Sync with upstream https://github.com/ekeeke/Genesis-Plus-GX/commit/35ed78cc71f6b2c69b1377c9520416d0253b6633
This commit is contained in:
@@ -733,6 +733,7 @@
|
||||
OTHER_CFLAGS = (
|
||||
"-DLSB_FIRST",
|
||||
"-DUSE_32BPP_RENDERING",
|
||||
"-DMAXROMSIZE=33554432",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.openemu.${PRODUCT_NAME:identifier}";
|
||||
PRODUCT_NAME = GenesisPlus;
|
||||
@@ -753,6 +754,7 @@
|
||||
OTHER_CFLAGS = (
|
||||
"-DLSB_FIRST",
|
||||
"-DUSE_32BPP_RENDERING",
|
||||
"-DMAXROMSIZE=33554432",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.openemu.${PRODUCT_NAME:identifier}";
|
||||
PRODUCT_NAME = GenesisPlus;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus
|
||||
* Action Replay / Pro Action Replay emulation
|
||||
* Action Replay / Pro Action Replay hardware support
|
||||
*
|
||||
* Copyright (C) 2009-2014 Eke-Eke (Genesis Plus GX)
|
||||
* Copyright (C) 2009-2021 Eke-Eke (Genesis Plus GX)
|
||||
*
|
||||
* Redistribution and use of this code or any derivative works are permitted
|
||||
* provided that the following conditions are met:
|
||||
@@ -45,8 +45,7 @@ static struct
|
||||
{
|
||||
uint8 enabled;
|
||||
uint8 status;
|
||||
uint8 *rom;
|
||||
uint8 *ram;
|
||||
uint8 ram[0x10000];
|
||||
uint16 regs[13];
|
||||
uint16 old[4];
|
||||
uint16 data[4];
|
||||
@@ -54,64 +53,52 @@ static struct
|
||||
} action_replay;
|
||||
|
||||
static void ar_write_regs(uint32 address, uint32 data);
|
||||
static void ar_write_regs_2(uint32 address, uint32 data);
|
||||
static void ar2_write_reg(uint32 address, uint32 data);
|
||||
static void ar_write_ram_8(uint32 address, uint32 data);
|
||||
|
||||
void areplay_init(void)
|
||||
{
|
||||
int size;
|
||||
|
||||
memset(&action_replay,0,sizeof(action_replay));
|
||||
action_replay.enabled = action_replay.status = 0;
|
||||
|
||||
/* store Action replay ROM (max. 128k) & RAM (64k) above cartridge ROM + SRAM area */
|
||||
if (cart.romsize > 0x810000) return;
|
||||
action_replay.rom = cart.rom + 0x810000;
|
||||
action_replay.ram = cart.rom + 0x830000;
|
||||
|
||||
/* try to load Action Replay ROM file */
|
||||
size = load_archive(AR_ROM, action_replay.rom, 0x20000, NULL);
|
||||
|
||||
/* detect Action Replay board type */
|
||||
switch (size)
|
||||
/* try to load Action Replay ROM file (max. 64KB) */
|
||||
if (load_archive(AR_ROM, cart.lockrom, 0x10000, NULL) > 0)
|
||||
{
|
||||
case 0x8000:
|
||||
/* detect Action Replay board type */
|
||||
if (!memcmp(cart.lockrom + 0x120, "ACTION REPLAY ", 16))
|
||||
{
|
||||
if (!memcmp(action_replay.rom + 0x120, "ACTION REPLAY ", 16))
|
||||
{
|
||||
/* normal Action Replay (32K) */
|
||||
action_replay.enabled = TYPE_AR;
|
||||
|
||||
/* internal registers mapped at $010000-$01ffff */
|
||||
m68k.memory_map[0x01].write16 = ar_write_regs;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* normal Action Replay (32KB ROM) */
|
||||
action_replay.enabled = TYPE_AR;
|
||||
|
||||
case 0x10000:
|
||||
case 0x20000:
|
||||
/* $0000-$7fff mirrored into $8000-$ffff */
|
||||
memcpy(cart.lockrom + 0x8000, cart.lockrom, 0x8000);
|
||||
|
||||
/* internal registers mapped at $010000-$01ffff */
|
||||
m68k.memory_map[0x01].write16 = ar_write_regs;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Read stack pointer MSB */
|
||||
uint8 sp = READ_BYTE(action_replay.rom, 0x01);
|
||||
uint8 sp = cart.lockrom[0x01];
|
||||
|
||||
/* Detect board version */
|
||||
if ((sp == 0x42) && !memcmp(action_replay.rom + 0x120, "ACTION REPLAY 2 ", 16))
|
||||
if ((sp == 0x42) && !memcmp(cart.lockrom + 0x120, "ACTION REPLAY 2 ", 16))
|
||||
{
|
||||
/* PRO Action Replay 1 (64/128K) */
|
||||
/* PRO Action Replay (2x32KB ROM) */
|
||||
action_replay.enabled = TYPE_PRO1;
|
||||
|
||||
/* internal registers mapped at $010000-$01ffff */
|
||||
m68k.memory_map[0x01].write16 = ar_write_regs;
|
||||
}
|
||||
else if ((sp == 0x60) && !memcmp(action_replay.rom + 0x3c6, "ACTION REPLAY II", 16))
|
||||
else if ((sp == 0x60) && !memcmp(cart.lockrom + 0x3c6, "ACTION REPLAY II", 16))
|
||||
{
|
||||
/* PRO Action Replay 2 (64K) */
|
||||
/* PRO Action Replay 2 (2x32KB ROM) */
|
||||
action_replay.enabled = TYPE_PRO2;
|
||||
|
||||
/* internal registers mapped at $100000-$10ffff */
|
||||
m68k.memory_map[0x10].write16 = ar_write_regs_2;
|
||||
/* internal register mapped at $100000-$10ffff */
|
||||
m68k.memory_map[0x10].write16 = ar2_write_reg;
|
||||
}
|
||||
|
||||
/* internal RAM (64k), mapped at $420000-$42ffff or $600000-$60ffff */
|
||||
/* internal RAM (64KB), mapped at $420000-$42ffff or $600000-$60ffff */
|
||||
if (action_replay.enabled)
|
||||
{
|
||||
m68k.memory_map[sp].base = action_replay.ram;
|
||||
@@ -120,28 +107,22 @@ void areplay_init(void)
|
||||
m68k.memory_map[sp].write8 = ar_write_ram_8;
|
||||
m68k.memory_map[sp].write16 = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LSB_FIRST
|
||||
if (action_replay.enabled)
|
||||
{
|
||||
int i;
|
||||
for (i= 0; i<size; i+=2)
|
||||
if (action_replay.enabled)
|
||||
{
|
||||
/* Byteswap ROM */
|
||||
uint8 temp = action_replay.rom[i];
|
||||
action_replay.rom[i] = action_replay.rom[i+1];
|
||||
action_replay.rom[i+1] = temp;
|
||||
int i;
|
||||
for (i= 0; i<0x10000; i+=2)
|
||||
{
|
||||
/* Byteswap ROM */
|
||||
uint8 temp = cart.lockrom[i];
|
||||
cart.lockrom[i] = cart.lockrom[i+1];
|
||||
cart.lockrom[i+1] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void areplay_shutdown(void)
|
||||
@@ -166,7 +147,7 @@ void areplay_reset(int hard)
|
||||
memset(action_replay.addr, 0, sizeof(action_replay.addr));
|
||||
|
||||
/* by default, internal ROM is mapped at $000000-$00FFFF */
|
||||
m68k.memory_map[0].base = action_replay.rom;
|
||||
m68k.memory_map[0].base = cart.lockrom;
|
||||
|
||||
/* reset internal RAM on power-on */
|
||||
if (hard)
|
||||
@@ -287,7 +268,7 @@ static void ar_write_regs(uint32 address, uint32 data)
|
||||
}
|
||||
}
|
||||
|
||||
static void ar_write_regs_2(uint32 address, uint32 data)
|
||||
static void ar2_write_reg(uint32 address, uint32 data)
|
||||
{
|
||||
/* enable Cartridge ROM */
|
||||
if (((address & 0xff) == 0x78) && (data == 0xffff))
|
||||
@@ -301,4 +282,3 @@ static void ar_write_ram_8(uint32 address, uint32 data)
|
||||
/* byte writes are handled as word writes, with LSB duplicated in MSB (/LWR is not used) */
|
||||
*(uint16 *)(action_replay.ram + (address & 0xfffe)) = (data | (data << 8));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus
|
||||
* DATEL Action Replay / Pro Action Replay emulation
|
||||
* Action Replay / Pro Action Replay hardware support
|
||||
*
|
||||
* Copyright (C) 2009-2014 Eke-Eke (Genesis Plus GX)
|
||||
* Copyright (C) 2009-2021 Eke-Eke (Genesis Plus GX)
|
||||
*
|
||||
* Redistribution and use of this code or any derivative works are permitted
|
||||
* provided that the following conditions are met:
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus
|
||||
* Game Genie Hardware emulation
|
||||
* Game Genie hardware support
|
||||
*
|
||||
* Copyright (C) 2009-2014 Eke-Eke (Genesis Plus GX)
|
||||
* Copyright (C) 2009-2021 Eke-Eke (Genesis Plus GX)
|
||||
*
|
||||
* Based on documentation from Charles McDonald
|
||||
* (http://cgfm2.emuviews.com/txt/genie.txt)
|
||||
@@ -44,7 +44,6 @@
|
||||
static struct
|
||||
{
|
||||
uint8 enabled;
|
||||
uint8 *rom;
|
||||
uint16 regs[0x20];
|
||||
uint16 old[6];
|
||||
uint16 data[6];
|
||||
@@ -58,29 +57,25 @@ static void ggenie_write_word(unsigned int address, unsigned int data);
|
||||
static void ggenie_write_regs(unsigned int offset, unsigned int data);
|
||||
|
||||
void ggenie_init(void)
|
||||
{
|
||||
memset(&ggenie,0,sizeof(ggenie));
|
||||
{
|
||||
ggenie.enabled = 0;
|
||||
|
||||
/* Store Game Genie ROM (32k) above cartridge ROM + SRAM area */
|
||||
if (cart.romsize > 0x810000) return;
|
||||
ggenie.rom = cart.rom + 0x810000;
|
||||
|
||||
/* Try to load Game Genie ROM file */
|
||||
if (load_archive(GG_ROM, ggenie.rom, 0x8000, NULL) > 0)
|
||||
/* Try to load Game Genie ROM file (32KB) */
|
||||
if (load_archive(GG_ROM, cart.lockrom, 0x8000, NULL) > 0)
|
||||
{
|
||||
#ifdef LSB_FIRST
|
||||
int i;
|
||||
for (i=0; i<0x8000; i+=2)
|
||||
{
|
||||
/* Byteswap ROM */
|
||||
uint8 temp = ggenie.rom[i];
|
||||
ggenie.rom[i] = ggenie.rom[i+1];
|
||||
ggenie.rom[i+1] = temp;
|
||||
uint8 temp = cart.lockrom[i];
|
||||
cart.lockrom[i] = cart.lockrom[i+1];
|
||||
cart.lockrom[i+1] = temp;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* $0000-$7fff mirrored into $8000-$ffff */
|
||||
memcpy(ggenie.rom + 0x8000, ggenie.rom, 0x8000);
|
||||
memcpy(cart.lockrom + 0x8000, cart.lockrom, 0x8000);
|
||||
|
||||
/* Game Genie hardware is enabled */
|
||||
ggenie.enabled = 1;
|
||||
@@ -113,7 +108,7 @@ void ggenie_reset(int hard)
|
||||
}
|
||||
|
||||
/* Game Genie ROM is mapped at $000000-$007fff */
|
||||
m68k.memory_map[0].base = ggenie.rom;
|
||||
m68k.memory_map[0].base = cart.lockrom;
|
||||
|
||||
/* Internal registers are mapped at $000000-$00001f */
|
||||
m68k.memory_map[0].write8 = ggenie_write_byte;
|
||||
@@ -214,7 +209,7 @@ static void ggenie_write_regs(unsigned int offset, unsigned int data)
|
||||
else
|
||||
{
|
||||
/* $0000-$7ffff reads mapped to Game Genie ROM */
|
||||
m68k.memory_map[0].base = ggenie.rom;
|
||||
m68k.memory_map[0].base = cart.lockrom;
|
||||
m68k.memory_map[0].read8 = NULL;
|
||||
m68k.memory_map[0].read16 = NULL;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus
|
||||
* Game Genie Hardware emulation
|
||||
* Game Genie hardware support
|
||||
*
|
||||
* Copyright (C) 2009-2014 Eke-Eke (Genesis Plus GX)
|
||||
* Copyright (C) 2009-2021 Eke-Eke (Genesis Plus GX)
|
||||
*
|
||||
* Based on documentation from Charles McDonald
|
||||
* (http://cgfm2.emuviews.com/txt/genie.txt)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Genesis Plus
|
||||
* Mega Drive cartridge hardware support
|
||||
*
|
||||
* Copyright (C) 2007-2020 Eke-Eke (Genesis Plus GX)
|
||||
* Copyright (C) 2007-2021 Eke-Eke (Genesis Plus GX)
|
||||
*
|
||||
* Many cartridge protections were initially documented by Haze
|
||||
* (http://haze.mameworld.info/)
|
||||
@@ -79,6 +79,7 @@ static void mapper_256k_multi_w(uint32 address, uint32 data);
|
||||
static void mapper_wd1601_w(uint32 address, uint32 data);
|
||||
static uint32 mapper_64k_radica_r(uint32 address);
|
||||
static uint32 mapper_128k_radica_r(uint32 address);
|
||||
static void mapper_sr16v1_w(uint32 address, uint32 data);
|
||||
static void default_time_w(uint32 address, uint32 data);
|
||||
static void default_regs_w(uint32 address, uint32 data);
|
||||
static uint32 default_regs_r(uint32 address);
|
||||
@@ -227,6 +228,12 @@ static const md_entry_t rom_database[] =
|
||||
{0x0000,0xd0a0,0x48,0x4f,{{0x00,0x00,0xaa,0xf0},{0xffffff,0xffffff,0xfc0000,0xfc0000},{0x000000,0x000000,0x480000,0x4c0000},0,0,NULL,NULL,default_regs_r,NULL}},
|
||||
|
||||
|
||||
/* Rock Heaven */
|
||||
{0x6cca,0x2395,0x50,0x50,{{0x50,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x500008,0x000000,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,NULL}},
|
||||
/* Rock World */
|
||||
{0x3547,0xa3da,0x50,0x50,{{0x50,0xa0,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x500008,0x500208,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,NULL}},
|
||||
|
||||
|
||||
/* Rockman X3 (bootleg version ? two last register returned values are ignored, note that 0xaa/0x18 would work as well) */
|
||||
{0x0000,0x9d0e,0x40,0x40,{{0x0c,0x00,0xc9,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0x000000,0x400004,0x400006},0,0,default_regs_r,NULL,default_regs_r,NULL}},
|
||||
|
||||
@@ -441,84 +448,11 @@ void md_cart_init(void)
|
||||
SVP CHIP
|
||||
***********************************************/
|
||||
svp = NULL;
|
||||
if (strstr(rominfo.international,"Virtua Racing"))
|
||||
if ((READ_BYTE(cart.rom, 0x1c8) == 'S') && (READ_BYTE(cart.rom, 0x1c9) == 'V'))
|
||||
{
|
||||
svp_init();
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
LOCK-ON
|
||||
***********************************************/
|
||||
|
||||
/* clear existing patches */
|
||||
ggenie_shutdown();
|
||||
areplay_shutdown();
|
||||
|
||||
/* initialize extra hardware */
|
||||
switch (config.lock_on)
|
||||
{
|
||||
case TYPE_GG:
|
||||
{
|
||||
ggenie_init();
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_AR:
|
||||
{
|
||||
areplay_init();
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_SK:
|
||||
{
|
||||
/* store S&K ROM above cartridge ROM (and before backup memory) */
|
||||
if (cart.romsize > 0x600000) break;
|
||||
|
||||
/* try to load Sonic & Knuckles ROM file (2 MB) */
|
||||
if (load_archive(SK_ROM, cart.rom + 0x600000, 0x200000, NULL) == 0x200000)
|
||||
{
|
||||
/* check ROM header */
|
||||
if (!memcmp(cart.rom + 0x600000 + 0x120, "SONIC & KNUCKLES",16))
|
||||
{
|
||||
/* try to load Sonic 2 & Knuckles UPMEM ROM (256 KB) */
|
||||
if (load_archive(SK_UPMEM, cart.rom + 0x900000, 0x40000, NULL) == 0x40000)
|
||||
{
|
||||
/* $000000-$1FFFFF is mapped to S&K ROM */
|
||||
for (i=0x00; i<0x20; i++)
|
||||
{
|
||||
m68k.memory_map[i].base = cart.rom + 0x600000 + (i << 16);
|
||||
}
|
||||
|
||||
#ifdef LSB_FIRST
|
||||
for (i=0; i<0x200000; i+=2)
|
||||
{
|
||||
/* Byteswap ROM */
|
||||
uint8 temp = cart.rom[i + 0x600000];
|
||||
cart.rom[i + 0x600000] = cart.rom[i + 0x600000 + 1];
|
||||
cart.rom[i + 0x600000 + 1] = temp;
|
||||
}
|
||||
|
||||
for (i=0; i<0x40000; i+=2)
|
||||
{
|
||||
/* Byteswap ROM */
|
||||
uint8 temp = cart.rom[i + 0x900000];
|
||||
cart.rom[i + 0x900000] = cart.rom[i + 0x900000 + 1];
|
||||
cart.rom[i + 0x900000 + 1] = temp;
|
||||
}
|
||||
#endif
|
||||
cart.special |= HW_LOCK_ON;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
CARTRIDGE EXTRA HARDWARE
|
||||
***********************************************/
|
||||
@@ -562,16 +496,16 @@ void md_cart_init(void)
|
||||
/* Realtec mapper */
|
||||
if (cart.hw.realtec)
|
||||
{
|
||||
/* 8k BOOT ROM */
|
||||
/* copy 8KB Boot ROM after cartridge ROM area */
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
memcpy(cart.rom + 0x900000 + i*0x2000, cart.rom + 0x7e000, 0x2000);
|
||||
memcpy(cart.rom + 0x400000 + i*0x2000, cart.rom + 0x7e000, 0x2000);
|
||||
}
|
||||
|
||||
/* BOOT ROM is mapped to $000000-$3FFFFF */
|
||||
/* Boot ROM (8KB mirrored) is mapped to $000000-$3FFFFF */
|
||||
for (i=0x00; i<0x40; i++)
|
||||
{
|
||||
m68k.memory_map[i].base = cart.rom + 0x900000;
|
||||
m68k.memory_map[i].base = cart.rom + 0x400000;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -731,6 +665,11 @@ void md_cart_init(void)
|
||||
zbank_memory_map[i].write = mapper_smw_64_w;
|
||||
}
|
||||
}
|
||||
else if ((*(uint16 *)(cart.rom + 0x04) == 0x0000) && (*(uint16 *)(cart.rom + 0x06) == 0x0104) && (rominfo.checksum == 0x31fc))
|
||||
{
|
||||
/* Micro Machines (USA) custom TMSS bypass logic */
|
||||
m68k.memory_map[0xa1].write8 = mapper_sr16v1_w;
|
||||
}
|
||||
else if (cart.romsize > 0x400000)
|
||||
{
|
||||
/* assume linear ROM mapping by default (max. 10MB) */
|
||||
@@ -748,6 +687,79 @@ void md_cart_init(void)
|
||||
{
|
||||
cart.hw.time_w = default_time_w;
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
LOCK-ON
|
||||
***********************************************/
|
||||
|
||||
/* clear existing patches */
|
||||
ggenie_shutdown();
|
||||
areplay_shutdown();
|
||||
|
||||
/* initialize extra hardware */
|
||||
switch (config.lock_on)
|
||||
{
|
||||
case TYPE_GG:
|
||||
{
|
||||
ggenie_init();
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_AR:
|
||||
{
|
||||
areplay_init();
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_SK:
|
||||
{
|
||||
/* store Sonic & Knuckles ROM files after cartridge ROM area */
|
||||
if (cart.romsize > 0x400000) break;
|
||||
|
||||
/* try to load Sonic & Knuckles ROM file (2MB) */
|
||||
if (load_archive(SK_ROM, cart.rom + 0x400000, 0x200000, NULL) == 0x200000)
|
||||
{
|
||||
/* check ROM header */
|
||||
if (!memcmp(cart.rom + 0x400000 + 0x120, "SONIC & KNUCKLES",16))
|
||||
{
|
||||
/* try to load Sonic 2 & Knuckles upmem ROM file (256KB) */
|
||||
if (load_archive(SK_UPMEM, cart.rom + 0x600000, 0x40000, NULL) == 0x40000)
|
||||
{
|
||||
/* $000000-$1FFFFF is mapped to S&K ROM */
|
||||
for (i=0x00; i<0x20; i++)
|
||||
{
|
||||
m68k.memory_map[i].base = cart.rom + 0x400000 + (i << 16);
|
||||
}
|
||||
|
||||
#ifdef LSB_FIRST
|
||||
for (i=0; i<0x200000; i+=2)
|
||||
{
|
||||
/* Byteswap ROM */
|
||||
uint8 temp = cart.rom[i + 0x400000];
|
||||
cart.rom[i + 0x400000] = cart.rom[i + 0x400000 + 1];
|
||||
cart.rom[i + 0x400000 + 1] = temp;
|
||||
}
|
||||
|
||||
for (i=0; i<0x40000; i+=2)
|
||||
{
|
||||
/* Byteswap ROM */
|
||||
uint8 temp = cart.rom[i + 0x600000];
|
||||
cart.rom[i + 0x600000] = cart.rom[i + 0x600000 + 1];
|
||||
cart.rom[i + 0x600000 + 1] = temp;
|
||||
}
|
||||
#endif
|
||||
cart.special |= HW_LOCK_ON;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* hardware that need to be reseted on power on */
|
||||
@@ -941,12 +953,12 @@ static void mapper_sega_w(uint32 data)
|
||||
}
|
||||
|
||||
/* S&K lock-on chip */
|
||||
if ((cart.special & HW_LOCK_ON) && (config.lock_on == TYPE_SK))
|
||||
if (cart.special & HW_LOCK_ON)
|
||||
{
|
||||
/* S2K upmem chip mapped to $300000-$3fffff (256K mirrored) */
|
||||
/* S2K upmem chip mapped to $300000-$3fffff (256KB mirrored) */
|
||||
for (i=0x30; i<0x40; i++)
|
||||
{
|
||||
m68k.memory_map[i].base = (cart.rom + 0x900000) + ((i & 3) << 16);
|
||||
m68k.memory_map[i].base = (cart.rom + 0x600000) + ((i & 3) << 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1891,6 +1903,29 @@ static uint32 mapper_128k_radica_r(uint32 address)
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Custom logic (ST 16S25HB1 PAL) used in Micro Machines US cartridge (SR16V1.1 board)
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
/VRES is asserted after write access to 0xA14101 (TMSS bank-shift register)
|
||||
with D0=1 (cartridge ROM access enabled instead of TMSS Boot ROM) being detected
|
||||
*/
|
||||
static void mapper_sr16v1_w(uint32 address, uint32 data)
|
||||
{
|
||||
/* 0xA10000-0xA1FFFF address range is mapped to I/O and Control registers */
|
||||
ctrl_io_write_byte(address, data);
|
||||
|
||||
/* cartridge uses /LWR, /AS and VA1-VA18 (only VA8-VA17 required to decode access to TMSS bank-shift register) */
|
||||
if ((address & 0xff01) == 0x4101)
|
||||
{
|
||||
/* cartridge ROM is enabled when D0=1 */
|
||||
if (data & 0x01)
|
||||
{
|
||||
gen_reset(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************
|
||||
default !TIME signal handler
|
||||
*************************************************************/
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Genesis Plus
|
||||
* Mega Drive cartridge hardware support
|
||||
*
|
||||
* Copyright (C) 2007-2020 Eke-Eke (Genesis Plus GX)
|
||||
* Copyright (C) 2007-2021 Eke-Eke (Genesis Plus GX)
|
||||
*
|
||||
* Most cartridge protections were initially documented by Haze
|
||||
* (http://haze.mameworld.info/)
|
||||
@@ -81,10 +81,10 @@ typedef struct
|
||||
uint32 mask; /* ROM mask */
|
||||
uint8 special; /* custom external hardware (Lock-On, J-Cart, 3-D glasses, Terebi Oekaki,...) */
|
||||
cart_hw_t hw; /* cartridge internal hardware */
|
||||
uint8 rom[MAXROMSIZE]; /* ROM area */
|
||||
uint8 lockrom[0x10000]; /* Game Genie / (Pro) Action Replay Lock-On ROM area (max 64KB) */
|
||||
uint8 rom[MAXROMSIZE]; /* cartridge ROM area */
|
||||
} md_cart_t;
|
||||
|
||||
|
||||
/* Function prototypes */
|
||||
extern void md_cart_init(void);
|
||||
extern void md_cart_reset(int hard_reset);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Genesis Plus
|
||||
* SG-1000, Master System & Game Gear cartridge hardware support
|
||||
*
|
||||
* Copyright (C) 2007-2019 Eke-Eke (Genesis Plus GX)
|
||||
* Copyright (C) 2007-2020 Eke-Eke (Genesis Plus GX)
|
||||
*
|
||||
* Redistribution and use of this code or any derivative works are permitted
|
||||
* provided that the following conditions are met:
|
||||
@@ -134,9 +134,12 @@ static const rominfo_t game_list[] =
|
||||
{0x5E53C7F7, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* Ernie Els Golf */
|
||||
{0xD9A7F170, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* Man Overboard! */
|
||||
{0xF7C524F6, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* Micro Machines [GG] */
|
||||
{0xC21E6CD0, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* Micro Machines [GG] [Proto] */
|
||||
{0xDBE8895C, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* Micro Machines 2 - Turbo Tournament */
|
||||
{0xC1756BEE, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* Pete Sampras Tennis */
|
||||
{0x72981057, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* CJ Elephant Fugitive */
|
||||
{0x3ACE6335, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* CJ Elephant Fugitive [Proto] */
|
||||
{0x2306AAF4, 0, 0, 0, MAPPER_CODIES, SYSTEM_GG, REGION_USA}, /* Dinobasher - Starring Bignose the Caveman [GG] [Proto] */
|
||||
|
||||
/* games using serial EEPROM */
|
||||
{0x36EBCD6D, 0, 0, 0, MAPPER_93C46, SYSTEM_GG, REGION_USA}, /* Majors Pro Baseball */
|
||||
@@ -197,6 +200,7 @@ static const rominfo_t game_list[] =
|
||||
{0xC0E25D62, 0, 0, 0, MAPPER_SEGA, SYSTEM_SMS2, REGION_EUROPE}, /* California Games II */
|
||||
{0x45C50294, 0, 0, 0, MAPPER_SEGA, SYSTEM_SMS2, REGION_EUROPE}, /* Jogos de Verao II (BR) */
|
||||
{0xC9DBF936, 0, 0, 0, MAPPER_SEGA, SYSTEM_SMS2, REGION_EUROPE}, /* Home Alone */
|
||||
{0xA109A6FE, 0, 0, 0, MAPPER_SEGA, SYSTEM_SMS2, REGION_EUROPE}, /* Power Strike II */
|
||||
{0x0047B615, 0, 0, 0, MAPPER_SEGA, SYSTEM_SMS2, REGION_EUROPE}, /* Predator2 */
|
||||
{0xF42E145C, 0, 0, 0, MAPPER_SEGA, SYSTEM_SMS2, REGION_EUROPE}, /* Quest for the Shaven Yak Starring Ren Hoek & Stimpy (BR) */
|
||||
{0x9F951756, 0, 0, 0, MAPPER_SEGA, SYSTEM_SMS2, REGION_EUROPE}, /* RoboCop 3 */
|
||||
@@ -238,6 +242,7 @@ static const rominfo_t game_list[] =
|
||||
{0xA3EF13CB, 1, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Zaxxon 3-D */
|
||||
{0xBBA74147, 1, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Zaxxon 3-D [Proto] */
|
||||
{0xD6F43DDA, 1, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Out Run 3-D */
|
||||
{0x4E684EC0, 1, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Out Run 3-D [Proto] */
|
||||
{0x871562b0, 1, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Maze Walker */
|
||||
{0x156948f9, 1, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Space Harrier 3-D (J) */
|
||||
|
||||
@@ -245,6 +250,7 @@ static const rominfo_t game_list[] =
|
||||
{0xFBE5CFBB, 1, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Missile Defense 3D */
|
||||
{0xE79BB689, 1, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Missile Defense 3D [BIOS] */
|
||||
{0x43DEF05D, 1, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Missile Defense 3D [Proto] */
|
||||
{0x56DCB2D4, 1, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* 3D Gunner [Proto] */
|
||||
|
||||
/* games requiring Sega Light Phaser */
|
||||
{0x861B6E79, 0, 0, SYSTEM_LIGHTPHASER, MAPPER_SEGA, SYSTEM_SMS, REGION_USA}, /* Assault City [Light Phaser] */
|
||||
@@ -339,6 +345,8 @@ static const rominfo_t game_list[] =
|
||||
{0x56BD2455, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Doki Doki Penguin Land - Uchuu-Daibouken [Proto] */
|
||||
{0xC722FB42, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Fantasy Zone II (J) */
|
||||
{0x7ABC70E9, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Family Games (Party Games) */
|
||||
{0x9AFAB511, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Game De Check! Koutsuu Anzen [Proto] (JP) */
|
||||
{0x9E9DEB18, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Game De Check! Koutsuu Anzen [Proto] (JP) [T-Eng] */
|
||||
{0x6586BD1F, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Masters Golf */
|
||||
{0x4847BC91, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Masters Golf [Proto] */
|
||||
{0xB9FDF6D9, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Haja no Fuuin */
|
||||
@@ -351,6 +359,8 @@ static const rominfo_t game_list[] =
|
||||
{0x5B5F9106, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Nekyuu Kousien */
|
||||
{0xBEA27D5C, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Opa Opa */
|
||||
{0x6605D36A, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Phantasy Star (J) */
|
||||
{0x70E89681, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Phantasy Star (J) [T-Eng v1.02] */
|
||||
{0xA04CF71A, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Phantasy Star (J) [T-Eng v2.00] */
|
||||
{0xE1FFF1BB, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Shinobi (J) */
|
||||
{0x11645549, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Solomon no Kagi - Oujo Rihita no Namida */
|
||||
{0x7E0EF8CB, 0, 1, 0, MAPPER_SEGA, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Super Racing */
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Genesis Plus
|
||||
* SG-1000, Master System & Game Gear cartridge hardware support
|
||||
*
|
||||
* Copyright (C) 2007-2019 Eke-Eke (Genesis Plus GX)
|
||||
* Copyright (C) 2007-2020 Eke-Eke (Genesis Plus GX)
|
||||
*
|
||||
* Redistribution and use of this code or any derivative works are permitted
|
||||
* provided that the following conditions are met:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Genesis Plus
|
||||
* Backup RAM support
|
||||
*
|
||||
* Copyright (C) 2007-2020 Eke-Eke (Genesis Plus GX)
|
||||
* Copyright (C) 2007-2021 Eke-Eke (Genesis Plus GX)
|
||||
*
|
||||
* Redistribution and use of this code or any derivative works are permitted
|
||||
* provided that the following conditions are met:
|
||||
@@ -62,11 +62,8 @@ T_SRAM sram;
|
||||
****************************************************************************/
|
||||
void sram_init()
|
||||
{
|
||||
memset(&sram, 0, sizeof (T_SRAM));
|
||||
|
||||
/* backup RAM data is stored above cartridge ROM area, at $800000-$80FFFF (max. 64K) */
|
||||
if (cart.romsize > 0x800000) return;
|
||||
sram.sram = cart.rom + 0x800000;
|
||||
/* disable Backup RAM by default */
|
||||
sram.detected = sram.on = sram.custom = sram.start = sram.end = 0;
|
||||
|
||||
/* initialize Backup RAM */
|
||||
if (strstr(rominfo.international,"Sonic 1 Remastered"))
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Genesis Plus
|
||||
* Backup RAM support
|
||||
*
|
||||
* Copyright (C) 2007-2020 Eke-Eke (Genesis Plus GX)
|
||||
* Copyright (C) 2007-2021 Eke-Eke (Genesis Plus GX)
|
||||
*
|
||||
* Redistribution and use of this code or any derivative works are permitted
|
||||
* provided that the following conditions are met:
|
||||
@@ -47,7 +47,7 @@ typedef struct
|
||||
uint32 start;
|
||||
uint32 end;
|
||||
uint32 crc;
|
||||
uint8 *sram;
|
||||
uint8 sram[0x10000];
|
||||
} T_SRAM;
|
||||
|
||||
/* Function prototypes */
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Genesis Plus
|
||||
* CD compatible ROM/RAM cartridge support
|
||||
*
|
||||
* Copyright (C) 2012-2016 Eke-Eke (Genesis Plus GX)
|
||||
* Copyright (C) 2012-2021 Eke-Eke (Genesis Plus GX)
|
||||
*
|
||||
* Redistribution and use of this code or any derivative works are permitted
|
||||
* provided that the following conditions are met:
|
||||
@@ -38,7 +38,6 @@
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* backup RAM cartridge (max. 512KB) */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Genesis Plus
|
||||
* CD compatible ROM/RAM cartridge support
|
||||
*
|
||||
* Copyright (C) 2012-2016 Eke-Eke (Genesis Plus GX)
|
||||
* Copyright (C) 2012-2021 Eke-Eke (Genesis Plus GX)
|
||||
*
|
||||
* Redistribution and use of this code or any derivative works are permitted
|
||||
* provided that the following conditions are met:
|
||||
@@ -41,7 +41,7 @@
|
||||
typedef struct
|
||||
{
|
||||
uint8 reserved[0x80]; /* reserved for ROM cartridge infos (see md_cart.h) */
|
||||
uint8 area[0x840000]; /* cartridge ROM/RAM area (max. 8MB ROM + 64KB backup memory + Pro Action Replay 128KB ROM / 64KB RAM) */
|
||||
uint8 area[0x810000]; /* cartridge ROM/RAM area (max. 8MB ROM + Pro Action Replay 64KB ROM) */
|
||||
uint8 boot; /* cartridge boot mode (0x00: boot from CD with ROM/RAM cartridge enabled, 0x40: boot from ROM cartridge with CD enabled) */
|
||||
uint8 id; /* RAM cartridge ID (related to RAM size, 0 if disabled) */
|
||||
uint8 prot; /* RAM cartridge write protection */
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Genesis Plus
|
||||
* CD drive processor & CD-DA fader
|
||||
*
|
||||
* Copyright (C) 2012-2020 Eke-Eke (Genesis Plus GX)
|
||||
* Copyright (C) 2012-2021 Eke-Eke (Genesis Plus GX)
|
||||
*
|
||||
* Redistribution and use of this code or any derivative works are permitted
|
||||
* provided that the following conditions are met:
|
||||
@@ -315,7 +315,11 @@ int cdd_load(char *filename, char *header)
|
||||
/* open file */
|
||||
fd = cdStreamOpen(filename);
|
||||
if (!fd)
|
||||
return (-1);
|
||||
{
|
||||
/* do not return an error as this could be a ROM loaded in memory */
|
||||
/* which should be handled by load_archive function */
|
||||
return (0);
|
||||
}
|
||||
|
||||
#if defined(USE_LIBCHDR)
|
||||
if (!memcmp("chd", &filename[strlen(filename) - 3], 3) || !memcmp("CHD", &filename[strlen(filename) - 3], 3))
|
||||
@@ -1795,7 +1799,7 @@ void cdd_process(void)
|
||||
{
|
||||
case 0x00: /* Get Drive Status */
|
||||
{
|
||||
/* RS0-RS8 are normally unchanged unless reported drive status needs to be updated (i.e previous drive command has been processed) */
|
||||
/* RS0-RS1 are normally unchanged unless reported drive status needs to be updated (i.e previous drive command has been processed) */
|
||||
/* Note: this function is called one 75hz frame ahead of CDD update so latency counter is always one step ahead of upcoming status */
|
||||
/* Radical Rex and Annet Futatabi both need at least respectively 2 and 3 interrupts with 'playing' status returned before sectors start getting incremented */
|
||||
if (cdd.latency <= 3)
|
||||
@@ -1806,8 +1810,37 @@ void cdd_process(void)
|
||||
/* check if RS1 indicated invalid track infos (during seeking) */
|
||||
if (scd.regs[0x38>>1].byte.l == 0x0f)
|
||||
{
|
||||
/* seeking has ended so we return valid track infos, e.g current track number in RS2-RS3 (fixes Lunar - The Silver Star) */
|
||||
scd.regs[0x38>>1].byte.l = 0x02;
|
||||
/* seeking has ended so we return valid track infos, e.g current absolute time by default (fixes Lunar - The Silver Star) */
|
||||
int lba = cdd.lba + 150;
|
||||
scd.regs[0x38>>1].byte.l = 0x00;
|
||||
scd.regs[0x3a>>1].w = lut_BCD_16[(lba/75)/60];
|
||||
scd.regs[0x3c>>1].w = lut_BCD_16[(lba/75)%60];
|
||||
scd.regs[0x3e>>1].w = lut_BCD_16[(lba%75)];
|
||||
scd.regs[0x40>>1].byte.h = cdd.toc.tracks[cdd.index].type ? 0x04 : 0x00; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
|
||||
}
|
||||
|
||||
/* otherwise, check if RS2-RS8 need to be updated */
|
||||
else if (scd.regs[0x38>>1].byte.l == 0x00)
|
||||
{
|
||||
/* current absolute time */
|
||||
int lba = cdd.lba + 150;
|
||||
scd.regs[0x3a>>1].w = lut_BCD_16[(lba/75)/60];
|
||||
scd.regs[0x3c>>1].w = lut_BCD_16[(lba/75)%60];
|
||||
scd.regs[0x3e>>1].w = lut_BCD_16[(lba%75)];
|
||||
scd.regs[0x40>>1].byte.h = cdd.toc.tracks[cdd.index].type ? 0x04 : 0x00; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
|
||||
}
|
||||
else if (scd.regs[0x38>>1].byte.l == 0x01)
|
||||
{
|
||||
/* current track relative time */
|
||||
int lba = abs(cdd.lba - cdd.toc.tracks[cdd.index].start);
|
||||
scd.regs[0x3a>>1].w = lut_BCD_16[(lba/75)/60];
|
||||
scd.regs[0x3c>>1].w = lut_BCD_16[(lba/75)%60];
|
||||
scd.regs[0x3e>>1].w = lut_BCD_16[(lba%75)];
|
||||
scd.regs[0x40>>1].byte.h = cdd.toc.tracks[cdd.index].type ? 0x04 : 0x00; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
|
||||
}
|
||||
else if (scd.regs[0x38>>1].byte.l == 0x02)
|
||||
{
|
||||
/* current track number */
|
||||
scd.regs[0x3a>>1].w = (cdd.index < cdd.toc.last) ? lut_BCD_16[cdd.index + 1] : 0x0A0A;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,6 +201,7 @@ typedef struct _zlib_allocator zlib_allocator;
|
||||
struct _zlib_allocator
|
||||
{
|
||||
UINT32 * allocptr[MAX_ZLIB_ALLOCS];
|
||||
UINT32 * allocptr2[MAX_ZLIB_ALLOCS];
|
||||
};
|
||||
|
||||
typedef struct _zlib_codec_data zlib_codec_data;
|
||||
@@ -220,10 +221,11 @@ struct _lzma_allocator
|
||||
void (*Free)(void *p, void *address); /* address can be 0 */
|
||||
void (*FreeSz)(void *p, void *address, size_t size); /* address can be 0 */
|
||||
uint32_t* allocptr[MAX_LZMA_ALLOCS];
|
||||
uint32_t* allocptr2[MAX_LZMA_ALLOCS];
|
||||
};
|
||||
|
||||
typedef struct _lzma_codec_data lzma_codec_data;
|
||||
struct _lzma_codec_data
|
||||
struct _lzma_codec_data
|
||||
{
|
||||
CLzmaDec decoder;
|
||||
lzma_allocator allocator;
|
||||
@@ -375,6 +377,7 @@ void lzma_allocator_init(void* p)
|
||||
|
||||
/* reset pointer list */
|
||||
memset(codec->allocptr, 0, sizeof(codec->allocptr));
|
||||
memset(codec->allocptr2, 0, sizeof(codec->allocptr2));
|
||||
codec->Alloc = lzma_fast_alloc;
|
||||
codec->Free = lzma_fast_free;
|
||||
}
|
||||
@@ -403,11 +406,16 @@ void lzma_allocator_free(void* p )
|
||||
*-------------------------------------------------
|
||||
*/
|
||||
|
||||
/* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */
|
||||
#define LZMA_MIN_ALIGNMENT_BITS 512
|
||||
#define LZMA_MIN_ALIGNMENT_BYTES (LZMA_MIN_ALIGNMENT_BITS / 8)
|
||||
|
||||
void *lzma_fast_alloc(void *p, size_t size)
|
||||
{
|
||||
int scan;
|
||||
uint32_t *addr;
|
||||
uint32_t *addr = NULL;
|
||||
lzma_allocator *codec = (lzma_allocator *)(p);
|
||||
uintptr_t vaddr = 0;
|
||||
|
||||
/* compute the size, rounding to the nearest 1k */
|
||||
size = (size + 0x3ff) & ~0x3ff;
|
||||
@@ -420,28 +428,37 @@ void *lzma_fast_alloc(void *p, size_t size)
|
||||
{
|
||||
/* set the low bit of the size so we don't match next time */
|
||||
*ptr |= 1;
|
||||
return ptr + 1;
|
||||
|
||||
/* return aligned address of the block */
|
||||
return codec->allocptr2[scan];
|
||||
}
|
||||
}
|
||||
|
||||
/* alloc a new one and put it into the list */
|
||||
addr = (uint32_t *)malloc(sizeof(uint8_t) * (size + sizeof(uint32_t)));
|
||||
addr = (uint32_t *)malloc(size + sizeof(uint32_t) + LZMA_MIN_ALIGNMENT_BYTES);
|
||||
if (addr==NULL)
|
||||
return NULL;
|
||||
for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
|
||||
for (int scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
|
||||
{
|
||||
if (codec->allocptr[scan] == NULL)
|
||||
{
|
||||
/* store block address */
|
||||
codec->allocptr[scan] = addr;
|
||||
|
||||
/* compute aligned address, store it */
|
||||
vaddr = (uintptr_t)addr;
|
||||
vaddr = (vaddr + sizeof(uint32_t) + (LZMA_MIN_ALIGNMENT_BYTES-1)) & (~(LZMA_MIN_ALIGNMENT_BYTES-1));
|
||||
codec->allocptr2[scan] = (uint32_t*)vaddr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* set the low bit of the size so we don't match next time */
|
||||
*addr = size | 1;
|
||||
return addr + 1;
|
||||
}
|
||||
|
||||
/* return aligned address */
|
||||
return (void*)vaddr;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
* lzma_fast_free - fast free for lzma, which
|
||||
@@ -452,21 +469,22 @@ void *lzma_fast_alloc(void *p, size_t size)
|
||||
void lzma_fast_free(void *p, void *address)
|
||||
{
|
||||
int scan;
|
||||
uint32_t *ptr;
|
||||
lzma_allocator *codec;
|
||||
uint32_t *ptr = NULL;
|
||||
lzma_allocator *codec = NULL;
|
||||
|
||||
if (address == NULL)
|
||||
return;
|
||||
|
||||
codec = (lzma_allocator *)(p);
|
||||
|
||||
/* find the hunk */
|
||||
ptr = (uint32_t *)(address) - 1;
|
||||
ptr = (uint32_t *)address;
|
||||
for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
|
||||
{
|
||||
if (ptr == codec->allocptr[scan])
|
||||
if (ptr == codec->allocptr2[scan])
|
||||
{
|
||||
/* clear the low bit of the size to allow matches */
|
||||
*ptr &= ~1;
|
||||
*codec->allocptr[scan] &= ~1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -2458,9 +2476,14 @@ static chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t
|
||||
allocates and frees memory frequently
|
||||
-------------------------------------------------*/
|
||||
|
||||
/* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */
|
||||
#define ZLIB_MIN_ALIGNMENT_BITS 512
|
||||
#define ZLIB_MIN_ALIGNMENT_BYTES (ZLIB_MIN_ALIGNMENT_BITS / 8)
|
||||
|
||||
static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
|
||||
{
|
||||
zlib_allocator *alloc = (zlib_allocator *)opaque;
|
||||
uintptr_t paddr = 0;
|
||||
UINT32 *ptr;
|
||||
int i;
|
||||
|
||||
@@ -2475,12 +2498,14 @@ static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
|
||||
{
|
||||
/* set the low bit of the size so we don't match next time */
|
||||
*ptr |= 1;
|
||||
return ptr + 1;
|
||||
|
||||
/* return aligned block address */
|
||||
return (voidpf)(alloc->allocptr2[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* alloc a new one */
|
||||
ptr = (UINT32 *)malloc(size + sizeof(UINT32));
|
||||
ptr = (UINT32 *)malloc(size + sizeof(UINT32) + ZLIB_MIN_ALIGNMENT_BYTES);
|
||||
if (!ptr)
|
||||
return NULL;
|
||||
|
||||
@@ -2489,12 +2514,16 @@ static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
|
||||
if (!alloc->allocptr[i])
|
||||
{
|
||||
alloc->allocptr[i] = ptr;
|
||||
paddr = (((uintptr_t)ptr) + sizeof(UINT32) + (ZLIB_MIN_ALIGNMENT_BYTES-1)) & (~(ZLIB_MIN_ALIGNMENT_BYTES-1));
|
||||
alloc->allocptr2[i] = (uint32_t*)paddr;
|
||||
break;
|
||||
}
|
||||
|
||||
/* set the low bit of the size so we don't match next time */
|
||||
*ptr = size | 1;
|
||||
return ptr + 1;
|
||||
|
||||
/* return aligned block address */
|
||||
return (voidpf)paddr;
|
||||
}
|
||||
|
||||
|
||||
@@ -2506,15 +2535,15 @@ static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
|
||||
static void zlib_fast_free(voidpf opaque, voidpf address)
|
||||
{
|
||||
zlib_allocator *alloc = (zlib_allocator *)opaque;
|
||||
UINT32 *ptr = (UINT32 *)address - 1;
|
||||
UINT32 *ptr = (UINT32 *)address;
|
||||
int i;
|
||||
|
||||
/* find the hunk */
|
||||
for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
|
||||
if (ptr == alloc->allocptr[i])
|
||||
if (ptr == alloc->allocptr2[i])
|
||||
{
|
||||
/* clear the low bit of the size to allow matches */
|
||||
*ptr &= ~1;
|
||||
*(alloc->allocptr[i]) &= ~1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1306,6 +1306,13 @@ static void scd_write_word(unsigned int address, unsigned int data)
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x36: /* CDD control */
|
||||
{
|
||||
/* only bit 2 is writable (bits [1:0] forced to 0 by default) */
|
||||
scd.regs[0x37>>1].byte.l = data & 0x04;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4a: /* CDD command 9 (controlled by BIOS, word access only ?) */
|
||||
{
|
||||
scd.regs[0x4a>>1].w = 0;
|
||||
@@ -1557,7 +1564,6 @@ void scd_init(void)
|
||||
|
||||
void scd_reset(int hard)
|
||||
{
|
||||
/* TODO: figure what exactly is resetted when RESET bit is cleared by SUB-CPU */
|
||||
if (hard)
|
||||
{
|
||||
/* Clear all ASIC registers by default */
|
||||
@@ -1605,8 +1611,11 @@ void scd_reset(int hard)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Clear only SUB-CPU side registers */
|
||||
memset(&scd.regs[0x04>>1], 0, sizeof(scd.regs) - 4);
|
||||
/* TODO: figure what exactly is reset when RESET bit is cleared by SUB-CPU */
|
||||
/* Clear only SUB-CPU side registers (communication registers are not cleared, see msu-md-sample.bin) */
|
||||
scd.regs[0x04>>1].w = 0x0000;
|
||||
scd.regs[0x0c>>1].w = 0x0000;
|
||||
memset(&scd.regs[0x30>>1], 0, sizeof(scd.regs) - 0x30);
|
||||
}
|
||||
|
||||
/* SUB-CPU side default values */
|
||||
|
||||
+241
-133
@@ -25,7 +25,21 @@ to do:
|
||||
|
||||
*/
|
||||
|
||||
/** EkeEke (2011): removed multiple chips support, cleaned code & added FM board interface for Genesis Plus GX **/
|
||||
/************************************************/
|
||||
/** Modifications for Genesis Plus GX (EkeEke) **/
|
||||
/************************************************/
|
||||
/** 2011/xx/xx: removed multiple chips support, cleaned code & added FM board interface **/
|
||||
/** 2021/04/23: fixed synchronization of carrier/modulator phase reset after channel Key ON (fixes Japanese Master System BIOS music) **/
|
||||
/** 2021/04/24: fixed intruments ROM (verified on YM2413B die, cf. https://siliconpr0n.org/archive/doku.php?id=vendor:yamaha:opl2#ym2413_instrument_rom) **/
|
||||
/** 2021/04/24: fixed EG resolution bits (verified on YM2413B die, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2015-03-20) **/
|
||||
/** 2021/04/24: fixed EG dump rate (verified on YM2413 real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2015-12-31) **/
|
||||
/** 2021/04/25: fixed EG behavior for fastest attack rates (verified on YM2413 real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2017-01-26) **/
|
||||
/** 2021/04/25: fixed EG behavior when SL = 0 (verified on YM2413 real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2015-12-24) **/
|
||||
/** 2021/04/25: improved EG sustain phase transition comparator accuracy (verified on YM2413 real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2015-12-31) **/
|
||||
/** 2021/05/04: improved EG increment steps accuracy (verified on YM2413 real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2015-03-20) **/
|
||||
/** 2021/05/08: improved EG transitions accuracy (verified against https://github.com/nukeykt/Nuked-OPLL/blob/master/opll.c) **/
|
||||
/** 2021/05/11: improved EG attack phase algorithm accuracy (verified on YM2413 real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2017-01-26) **/
|
||||
/************************************************/
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
@@ -40,7 +54,7 @@ to do:
|
||||
#define ENV_LEN (1<<ENV_BITS)
|
||||
#define ENV_STEP (128.0/ENV_LEN)
|
||||
|
||||
#define MAX_ATT_INDEX ((1<<(ENV_BITS-2))-1) /*255*/
|
||||
#define MAX_ATT_INDEX ((1<<(ENV_BITS-3))-1) /*127*/
|
||||
#define MIN_ATT_INDEX (0)
|
||||
|
||||
/* sinwave entries */
|
||||
@@ -219,67 +233,100 @@ static const UINT32 sl_tab[16]={
|
||||
#undef SC
|
||||
|
||||
|
||||
#define RATE_STEPS (8)
|
||||
static const unsigned char eg_inc[15*RATE_STEPS]={
|
||||
#define RATE_STEPS (16)
|
||||
|
||||
/*cycle:0 1 2 3 4 5 6 7*/
|
||||
static const unsigned char eg_inc[14*RATE_STEPS]={
|
||||
|
||||
/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..12 0 (increment by 0 or 1) */
|
||||
/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..12 1 */
|
||||
/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..12 2 */
|
||||
/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..12 3 */
|
||||
/*cycle:0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15*/
|
||||
|
||||
/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 13 0 (increment by 1) */
|
||||
/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 13 1 */
|
||||
/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 13 2 */
|
||||
/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 13 3 */
|
||||
/* 0 */ 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, /* infinity rates for decay(s) */
|
||||
|
||||
/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 14 0 (increment by 2) */
|
||||
/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 14 1 */
|
||||
/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 14 2 */
|
||||
/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 14 3 */
|
||||
/* 1 */ 0,1, 0,1, 0,1, 0,1, 0,1, 0,1, 0,1, 0,1, /* rates 01..12 0 for decay(s) (increment by 0 or 1) */
|
||||
/* 2 */ 0,1, 1,1, 0,1, 0,1, 0,1, 1,1, 0,1, 0,1, /* rates 01..12 1 for decay(s) */
|
||||
/* 3 */ 0,1, 1,1, 0,1, 1,1, 0,1, 1,1, 0,1, 1,1, /* rates 01..12 2 for decay(s) */
|
||||
/* 4 */ 0,1, 1,1, 1,1, 1,1, 0,1, 1,1, 1,1, 1,1, /* rates 01..12 3 for decay(s) */
|
||||
|
||||
/* 5 */ 0,1, 0,1, 0,1, 0,1, 0,1, 0,1, 0,1, 0,1, /* rate 13 0 for decay(s) (increment by 0 or 1) */
|
||||
/* 6 */ 0,1, 0,1, 1,1, 1,1, 0,1, 0,1, 0,1, 0,1, /* rate 13 1 for decay(s) */
|
||||
/* 7 */ 0,1, 0,1, 1,1, 1,1, 0,1, 0,1, 1,1, 1,1, /* rate 13 2 for decay(s) */
|
||||
/* 8 */ 0,1, 0,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, /* rate 13 3 for decay(s) */
|
||||
|
||||
/* 9 */ 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, /* rate 14 0 for decay(s) (increment by 1) */
|
||||
/*10 */ 1,1, 1,1, 2,2, 2,2, 1,1, 1,1, 1,1, 1,1, /* rate 14 1 for decay(s) */
|
||||
/*11 */ 1,1, 1,1, 2,2, 2,2, 1,1, 1,1, 2,2, 2,2, /* rate 14 2 for decay(s) */
|
||||
/*12 */ 1,1, 1,1, 2,2, 2,2, 2,2, 2,2, 2,2, 2,2, /* rate 14 3 for decay(s) */
|
||||
|
||||
/*13 */ 2,2, 2,2, 2,2, 2,2, 2,2, 2,2, 2,2, 2,2, /* rates 15 0, 15 1, 15 2, 15 3 for decay(s) (increment by 2) */
|
||||
|
||||
/*12 */ 4,4, 4,4, 4,4, 4,4, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 4) */
|
||||
/*13 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 2, 15 3 for attack */
|
||||
/*14 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */
|
||||
};
|
||||
|
||||
static const unsigned char eg_mul[17*RATE_STEPS]={
|
||||
|
||||
/*cycle:0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15*/
|
||||
|
||||
/* 0 */ 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack */
|
||||
|
||||
/* 1 */ 0,1, 0,1, 0,1, 0,1, 0,1, 0,1, 0,1, 0,1, /* rates 01..11 0 for attack */
|
||||
/* 2 */ 0,1, 1,1, 0,1, 0,1, 0,1, 1,1, 0,1, 0,1, /* rates 01..11 1 for attack */
|
||||
/* 3 */ 0,1, 1,1, 0,1, 1,1, 0,1, 1,1, 0,1, 1,1, /* rates 01..11 2 for attack */
|
||||
/* 4 */ 0,1, 1,1, 1,1, 1,1, 0,1, 1,1, 1,1, 1,1, /* rates 01..11 3 for attack */
|
||||
|
||||
/* 5 */ 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, /* rate 12 0 for attack */
|
||||
/* 6 */ 1,1, 1,1, 2,2, 2,2, 1,1, 1,1, 1,1, 1,1, /* rate 12 1 for attack */
|
||||
/* 7 */ 1,1, 1,1, 2,2, 2,2, 1,1, 1,1, 2,2, 2,2, /* rate 12 2 for attack */
|
||||
/* 8 */ 1,1, 1,1, 2,2, 2,2, 2,2, 2,2, 2,2, 2,2, /* rate 12 3 for attack */
|
||||
|
||||
/* 9 */ 2,2, 2,2, 2,2, 2,2, 2,2, 2,2, 2,2, 2,2, /* rate 13 0 for attack */
|
||||
/*10 */ 2,2, 2,2, 4,4, 4,4, 2,2, 2,2, 2,2, 2,2, /* rate 13 1 for attack */
|
||||
/*11 */ 2,2, 2,2, 4,4, 4,4, 2,2, 2,2, 4,4, 4,4, /* rate 13 2 for attack */
|
||||
/*12 */ 2,2, 2,2, 4,4, 4,4, 4,4, 4,4, 4,4, 4,4, /* rate 13 3 for attack */
|
||||
|
||||
/*13 */ 4,4, 4,4, 4,4, 4,4, 4,4, 4,4, 4,4, 4,4, /* rate 14 0 for attack */
|
||||
/*14 */ 4,4, 4,4, 8,8, 8,8, 4,4, 4,4, 4,4, 4,4, /* rate 14 1 for attack */
|
||||
/*15 */ 4,4, 4,4, 8,8, 8,8, 4,4, 4,4, 8,8, 8,8, /* rate 14 2 for attack */
|
||||
/*16 */ 4,4, 4,4, 8,8, 8,8, 8,8, 8,8, 8,8, 8,8, /* rate 14 3 for attack */
|
||||
|
||||
};
|
||||
|
||||
#define O(a) (a*RATE_STEPS)
|
||||
|
||||
/*note that there is no O(13) in this table - it's directly in the code */
|
||||
static const unsigned char eg_rate_select[16+64+16]={ /* Envelope Generator rates (16 + 64 rates + 16 RKS) */
|
||||
|
||||
/* 16 infinite time rates */
|
||||
O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14),
|
||||
O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14),
|
||||
O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
|
||||
O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
|
||||
|
||||
/* rates 00-12 */
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
O( 0),O( 1),O( 2),O( 3),
|
||||
/* rate 00 */
|
||||
O( 0),O( 0),O( 0),O( 0), /* never used since infinite time rates are directly forced in the code for rate 00 */
|
||||
|
||||
/* rate 13 */
|
||||
O( 4),O( 5),O( 6),O( 7),
|
||||
/* rates 01-11 */
|
||||
O( 1),O( 2),O( 3),O( 4),
|
||||
O( 1),O( 2),O( 3),O( 4),
|
||||
O( 1),O( 2),O( 3),O( 4),
|
||||
O( 1),O( 2),O( 3),O( 4),
|
||||
O( 1),O( 2),O( 3),O( 4),
|
||||
O( 1),O( 2),O( 3),O( 4),
|
||||
O( 1),O( 2),O( 3),O( 4),
|
||||
O( 1),O( 2),O( 3),O( 4),
|
||||
O( 1),O( 2),O( 3),O( 4),
|
||||
O( 1),O( 2),O( 3),O( 4),
|
||||
O( 1),O( 2),O( 3),O( 4),
|
||||
|
||||
/* rate 14 */
|
||||
O( 8),O( 9),O(10),O(11),
|
||||
/* rate 12 */ /* only used for decay(s), handled directly in the code for attack */
|
||||
O( 1),O( 2),O( 3),O( 4),
|
||||
|
||||
/* rate 15 */
|
||||
O(12),O(12),O(12),O(12),
|
||||
/* rate 13 */ /* only used for decay(s), handled directly in the code for attack */
|
||||
O( 5),O( 6),O( 7),O( 8),
|
||||
|
||||
/* rate 14 */ /* only used for decay(s), handled directly in the code for attack */
|
||||
O( 9),O(10),O(11),O(12),
|
||||
|
||||
/* rate 15 */ /* only used for decay(s), handled directly in the code for attack */
|
||||
O(13),O(13),O(13),O(13),
|
||||
|
||||
/* 16 dummy rates (same as 15 3) */
|
||||
O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12),
|
||||
O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12),
|
||||
O(13),O(13),O(13),O(13),O(13),O(13),O(13),O(13),
|
||||
O(13),O(13),O(13),O(13),O(13),O(13),O(13),O(13),
|
||||
|
||||
};
|
||||
#undef O
|
||||
@@ -287,15 +334,19 @@ O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12),
|
||||
/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 */
|
||||
/*shift 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0 */
|
||||
/*mask 8191, 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0 */
|
||||
/*NB: for attack, above mask values lower 2 bits are cleared and rate 12 shift value is equal to 0 */
|
||||
|
||||
#define O(a) (a*1)
|
||||
static const unsigned char eg_rate_shift[16+64+16]={ /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */
|
||||
/* 16 infinite time rates */
|
||||
O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
|
||||
O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
|
||||
|
||||
/* rates 00-12 */
|
||||
O(13),O(13),O(13),O(13),
|
||||
/* 16 infinite time rates */
|
||||
O(13),O(13),O(13),O(13),O(13),O(13),O(13),O(13),
|
||||
O(13),O(13),O(13),O(13),O(13),O(13),O(13),O(13),
|
||||
|
||||
/* rate 00 */
|
||||
O(13),O(13),O(13),O(13), /* never used since infinite time rates are directly forced in the code for rate 00 */
|
||||
|
||||
/* rates 01-11 */
|
||||
O(12),O(12),O(12),O(12),
|
||||
O(11),O(11),O(11),O(11),
|
||||
O(10),O(10),O(10),O(10),
|
||||
@@ -307,15 +358,17 @@ O( 5),O( 5),O( 5),O( 5),
|
||||
O( 4),O( 4),O( 4),O( 4),
|
||||
O( 3),O( 3),O( 3),O( 3),
|
||||
O( 2),O( 2),O( 2),O( 2),
|
||||
|
||||
/* rate 12 */ /* only used for decay(s), handled directly in the code for attack */
|
||||
O( 1),O( 1),O( 1),O( 1),
|
||||
|
||||
/* rate 13 */
|
||||
/* rate 13 */ /* only used for decay(s), handled directly in the code for attack */
|
||||
O( 0),O( 0),O( 0),O( 0),
|
||||
|
||||
/* rate 14 */
|
||||
/* rate 14 */ /* only used for decay(s), handled directly in the code for attack */
|
||||
O( 0),O( 0),O( 0),O( 0),
|
||||
|
||||
/* rate 15 */
|
||||
/* rate 15 */ /* only used for decay(s), handled directly in the code for attack */
|
||||
O( 0),O( 0),O( 0),O( 0),
|
||||
|
||||
/* 16 dummy rates (same as 15 3) */
|
||||
@@ -455,45 +508,71 @@ static const INT8 lfo_pm_table[8*8] = {
|
||||
- LFO PM and AM enable are 100% correct
|
||||
- waveform DC and DM select are 100% correct
|
||||
*/
|
||||
/* 2021/04/23: corrected with values extracted from YM2413 instrument ROM, cf. https://siliconpr0n.org/archive/doku.php?id=vendor:yamaha:opl2#ym2413_instrument_rom */
|
||||
|
||||
static unsigned char table[19][8] = {
|
||||
/* MULT MULT modTL DcDmFb AR/DR AR/DR SL/RR SL/RR */
|
||||
/* 0 1 2 3 4 5 6 7 */
|
||||
{0x49, 0x4c, 0x4c, 0x12, 0x00, 0x00, 0x00, 0x00 }, /* 0 */
|
||||
/*{0x49, 0x4c, 0x4c, 0x12, 0x00, 0x00, 0x00, 0x00 }, */ /* 0 */
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 0 */
|
||||
|
||||
{0x61, 0x61, 0x1e, 0x17, 0xf0, 0x78, 0x00, 0x17 }, /* 1 */
|
||||
{0x13, 0x41, 0x1e, 0x0d, 0xd7, 0xf7, 0x13, 0x13 }, /* 2 */
|
||||
{0x13, 0x01, 0x99, 0x04, 0xf2, 0xf4, 0x11, 0x23 }, /* 3 */
|
||||
{0x21, 0x61, 0x1b, 0x07, 0xaf, 0x64, 0x40, 0x27 }, /* 4 */
|
||||
/*{0x61, 0x61, 0x1e, 0x17, 0xf0, 0x78, 0x00, 0x17 }, */ /* 1 */
|
||||
{0x71, 0x61, 0x1e, 0x17, 0xd0, 0x78, 0x00, 0x17 }, /* 1 */
|
||||
|
||||
/*{0x13, 0x41, 0x1e, 0x0d, 0xd7, 0xf7, 0x13, 0x13 }, */ /* 2 */
|
||||
{0x13, 0x41, 0x1a, 0x0d, 0xd8, 0xf7, 0x23, 0x13 }, /* 2 */
|
||||
|
||||
/*{0x13, 0x01, 0x99, 0x04, 0xf2, 0xf4, 0x11, 0x23 }, */ /* 3 */
|
||||
{0x13, 0x01, 0x99, 0x00, 0xf2, 0xc4, 0x11, 0x23 }, /* 3 */
|
||||
|
||||
/*{0x21, 0x61, 0x1b, 0x07, 0xaf, 0x64, 0x40, 0x27 }, */ /* 4 */
|
||||
{0x31, 0x61, 0x0e, 0x07, 0xa8, 0x64, 0x70, 0x27 }, /* 4 */
|
||||
|
||||
/*{0x22, 0x21, 0x1e, 0x09, 0xf0, 0x76, 0x08, 0x28 }, */ /* 5 */
|
||||
{0x22, 0x21, 0x1e, 0x06, 0xf0, 0x75, 0x08, 0x18 }, /* 5 */
|
||||
/*{0x22, 0x21, 0x1e, 0x06, 0xf0, 0x75, 0x08, 0x18 }, */ /* 5 */
|
||||
{0x32, 0x21, 0x1e, 0x06, 0xe0, 0x76, 0x00, 0x28 }, /* 5 */
|
||||
|
||||
/*{0x31, 0x22, 0x16, 0x09, 0x90, 0x7f, 0x00, 0x08 }, */ /* 6 */
|
||||
{0x31, 0x22, 0x16, 0x05, 0x90, 0x71, 0x00, 0x13 }, /* 6 */
|
||||
/*{0x31, 0x22, 0x16, 0x05, 0x90, 0x71, 0x00, 0x13 }, */ /* 6 */
|
||||
{0x31, 0x22, 0x16, 0x05, 0xe0, 0x71, 0x00, 0x18 }, /* 6 */
|
||||
|
||||
{0x21, 0x61, 0x1d, 0x07, 0x82, 0x80, 0x10, 0x17 }, /* 7 */
|
||||
{0x23, 0x21, 0x2d, 0x16, 0xc0, 0x70, 0x07, 0x07 }, /* 8 */
|
||||
{0x61, 0x61, 0x1b, 0x06, 0x64, 0x65, 0x10, 0x17 }, /* 9 */
|
||||
/*{0x21, 0x61, 0x1d, 0x07, 0x82, 0x80, 0x10, 0x17 }, */ /* 7 */
|
||||
{0x21, 0x61, 0x1d, 0x07, 0x82, 0x81, 0x10, 0x07 }, /* 7 */
|
||||
|
||||
/* {0x61, 0x61, 0x0c, 0x08, 0x85, 0xa0, 0x79, 0x07 }, */ /* A */
|
||||
{0x61, 0x61, 0x0c, 0x18, 0x85, 0xf0, 0x70, 0x07 }, /* A */
|
||||
/*{0x23, 0x21, 0x2d, 0x16, 0xc0, 0x70, 0x07, 0x07 }, */ /* 8 */
|
||||
{0x23, 0x21, 0x2d, 0x14, 0xa2, 0x72, 0x00, 0x07 }, /* 8 */
|
||||
|
||||
{0x23, 0x01, 0x07, 0x11, 0xf0, 0xa4, 0x00, 0x22 }, /* B */
|
||||
{0x97, 0xc1, 0x24, 0x07, 0xff, 0xf8, 0x22, 0x12 }, /* C */
|
||||
{0x61, 0x61, 0x1b, 0x06, 0x64, 0x65, 0x10, 0x17 }, /* 9 */
|
||||
|
||||
/* {0x61, 0x10, 0x0c, 0x08, 0xf2, 0xc4, 0x40, 0xc8 }, */ /* D */
|
||||
{0x61, 0x10, 0x0c, 0x05, 0xf2, 0xf4, 0x40, 0x44 }, /* D */
|
||||
/*{0x61, 0x61, 0x0c, 0x08, 0x85, 0xa0, 0x79, 0x07 }, */ /* A */
|
||||
/*{0x61, 0x61, 0x0c, 0x18, 0x85, 0xf0, 0x70, 0x07 }, */ /* A */
|
||||
{0x41, 0x61, 0x0b, 0x18, 0x85, 0xf7, 0x71, 0x07 }, /* A */
|
||||
|
||||
{0x01, 0x01, 0x55, 0x03, 0xf3, 0x92, 0xf3, 0xf3 }, /* E */
|
||||
{0x61, 0x41, 0x89, 0x03, 0xf1, 0xf4, 0xf0, 0x13 }, /* F */
|
||||
/*{0x23, 0x01, 0x07, 0x11, 0xf0, 0xa4, 0x00, 0x22 }, */ /* B */
|
||||
{0x13, 0x01, 0x83, 0x11, 0xfa, 0xe4, 0x10, 0x04 }, /* B */
|
||||
|
||||
/*{0x97, 0xc1, 0x24, 0x07, 0xff, 0xf8, 0x22, 0x12 }, */ /* C */
|
||||
{0x17, 0xc1, 0x24, 0x07, 0xf8, 0xf8, 0x22, 0x12 }, /* C */
|
||||
|
||||
/*{0x61, 0x10, 0x0c, 0x08, 0xf2, 0xc4, 0x40, 0xc8 }, */ /* D */
|
||||
/*{0x61, 0x10, 0x0c, 0x05, 0xf2, 0xf4, 0x40, 0x44 }, */ /* D */
|
||||
{0x61, 0x50, 0x0c, 0x05, 0xc2, 0xf5, 0x20, 0x42 }, /* D */
|
||||
|
||||
/*{0x01, 0x01, 0x55, 0x03, 0xf3, 0x92, 0xf3, 0xf3 }, */ /* E */
|
||||
{0x01, 0x01, 0x55, 0x03, 0xc9, 0x95, 0x03, 0x02 }, /* E */
|
||||
|
||||
/*{0x61, 0x41, 0x89, 0x03, 0xf1, 0xf4, 0xf0, 0x13 }, */ /* F */
|
||||
{0x61, 0x41, 0x89, 0x03, 0xf1, 0xe4, 0x40, 0x13 }, /* F */
|
||||
|
||||
/* drum instruments definitions */
|
||||
/* MULTI MULTI modTL xxx AR/DR AR/DR SL/RR SL/RR */
|
||||
/* 0 1 2 3 4 5 6 7 */
|
||||
{0x01, 0x01, 0x16, 0x00, 0xfd, 0xf8, 0x2f, 0x6d },/* BD(multi verified, modTL verified, mod env - verified(close), carr. env verifed) */
|
||||
{0x01, 0x01, 0x00, 0x00, 0xd8, 0xd8, 0xf9, 0xf8 },/* HH(multi verified), SD(multi not used) */
|
||||
{0x05, 0x01, 0x00, 0x00, 0xf8, 0xba, 0x49, 0x55 },/* TOM(multi,env verified), TOP CYM(multi verified, env verified) */
|
||||
/*{0x01, 0x01, 0x16, 0x00, 0xfd, 0xf8, 0x2f, 0x6d },*/ /* BD(multi verified, modTL verified, mod env - verified(close), carr. env verifed) */
|
||||
/*{0x01, 0x01, 0x00, 0x00, 0xd8, 0xd8, 0xf9, 0xf8 },*/ /* HH(multi verified), SD(multi not used) */
|
||||
/*{0x05, 0x01, 0x00, 0x00, 0xf8, 0xba, 0x49, 0x55 },*/ /* TOM(multi,env verified), TOP CYM(multi verified, env verified) */
|
||||
{0x01, 0x01, 0x18, 0x0f, 0xdf, 0xf8, 0x6a, 0x6d }, /* BD */
|
||||
{0x01, 0x01, 0x00, 0x00, 0xc8, 0xd8, 0xa7, 0x48 }, /* HH, SD */
|
||||
{0x05, 0x01, 0x00, 0x00, 0xf8, 0xaa, 0x59, 0x55 } /* TOM, TOP CYM */
|
||||
};
|
||||
|
||||
static signed int output[2];
|
||||
@@ -542,47 +621,55 @@ INLINE void advance(void)
|
||||
|
||||
switch(op->state)
|
||||
{
|
||||
case EG_DMP: /* dump phase */
|
||||
/*dump phase is performed by both operators in each channel*/
|
||||
/*when CARRIER envelope gets down to zero level,
|
||||
** phases in BOTH opearators are reset (at the same time ?)
|
||||
*/
|
||||
if ( !(ym2413.eg_cnt & ((1<<op->eg_sh_dp)-1) ) )
|
||||
case EG_DMP: /* dump phase */
|
||||
if ( (op->volume & ~3) == (MAX_ATT_INDEX & ~3) ) /* envelope level lowest 2 bits are ignored by the comparator */
|
||||
{
|
||||
op->volume += eg_inc[op->eg_sel_dp + ((ym2413.eg_cnt>>op->eg_sh_dp)&7)];
|
||||
op->state = EG_ATT;
|
||||
|
||||
if ( op->volume >= MAX_ATT_INDEX )
|
||||
/* force envelope to zero when attack rate is set to 15.0-15.3 */
|
||||
if ((op->ar + op->ksr) >= 16+60)
|
||||
{
|
||||
op->volume = MAX_ATT_INDEX;
|
||||
op->state = EG_ATT;
|
||||
/* restart Phase Generator */
|
||||
op->phase = 0;
|
||||
op->volume = MIN_ATT_INDEX;
|
||||
}
|
||||
|
||||
/*dump phase is performed by both operators in each channel*/
|
||||
/*when CARRIER envelope gets down to zero level,
|
||||
*phases in BOTH operators are reset (at the same time ?)
|
||||
*/
|
||||
if (i&1)
|
||||
{
|
||||
CH->SLOT[0].phase = CH->SLOT[1].phase = 0;
|
||||
}
|
||||
}
|
||||
else if ( !(ym2413.eg_cnt & ((1<<op->eg_sh_dp)-1) ) )
|
||||
{
|
||||
op->volume += eg_inc[op->eg_sel_dp + ((ym2413.eg_cnt>>op->eg_sh_dp)&15)];
|
||||
}
|
||||
break;
|
||||
|
||||
case EG_ATT: /* attack phase */
|
||||
if ( !(ym2413.eg_cnt & ((1<<op->eg_sh_ar)-1) ) )
|
||||
case EG_ATT: /* attack phase */
|
||||
if (op->volume == MIN_ATT_INDEX)
|
||||
{
|
||||
op->volume += (~op->volume *
|
||||
(eg_inc[op->eg_sel_ar + ((ym2413.eg_cnt>>op->eg_sh_ar)&7)])
|
||||
) >>2;
|
||||
|
||||
if (op->volume <= MIN_ATT_INDEX)
|
||||
{
|
||||
op->volume = MIN_ATT_INDEX;
|
||||
op->state = EG_DEC;
|
||||
}
|
||||
op->state = EG_DEC;
|
||||
}
|
||||
else if ( !(ym2413.eg_cnt & (((1<<op->eg_sh_ar)-1) & ~3)) )
|
||||
{
|
||||
op->volume += (~op->volume * (eg_mul[op->eg_sel_ar + ((ym2413.eg_cnt>>op->eg_sh_ar)&15)]))>>4;
|
||||
}
|
||||
break;
|
||||
|
||||
case EG_DEC: /* decay phase */
|
||||
if ( !(ym2413.eg_cnt & ((1<<op->eg_sh_dr)-1) ) )
|
||||
if ( (op->volume & ~7) == op->sl ) /* envelope level lowest 3 bits are ignored by the comparator */
|
||||
{
|
||||
op->volume += eg_inc[op->eg_sel_dr + ((ym2413.eg_cnt>>op->eg_sh_dr)&7)];
|
||||
|
||||
if ( op->volume >= op->sl )
|
||||
op->state = EG_SUS;
|
||||
op->state = EG_SUS;
|
||||
}
|
||||
else if ( !(ym2413.eg_cnt & ((1<<op->eg_sh_dr)-1) ) )
|
||||
{
|
||||
op->volume += eg_inc[op->eg_sel_dr + ((ym2413.eg_cnt>>op->eg_sh_dr)&15)];
|
||||
if ( (op->volume & ~3) == (MAX_ATT_INDEX & ~3) ) /* envelope level lowest 2 bits are ignored by the comparator */
|
||||
{
|
||||
op->state = EG_OFF;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -591,19 +678,20 @@ INLINE void advance(void)
|
||||
one can change percusive/non-percussive modes on the fly and
|
||||
the chip will remain in sustain phase - verified on real YM3812 */
|
||||
|
||||
if(op->eg_type) /* non-percussive mode (sustained tone) */
|
||||
if (op->eg_type) /* non-percussive mode (sustained tone) */
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
else /* percussive mode */
|
||||
else /* percussive mode */
|
||||
{
|
||||
/* during sustain phase chip adds Release Rate (in percussive mode) */
|
||||
if ( !(ym2413.eg_cnt & ((1<<op->eg_sh_rr)-1) ) )
|
||||
{
|
||||
op->volume += eg_inc[op->eg_sel_rr + ((ym2413.eg_cnt>>op->eg_sh_rr)&7)];
|
||||
|
||||
if ( op->volume >= MAX_ATT_INDEX )
|
||||
op->volume = MAX_ATT_INDEX;
|
||||
op->volume += eg_inc[op->eg_sel_rr + ((ym2413.eg_cnt>>op->eg_sh_rr)&15)];
|
||||
if ( (op->volume & ~3) == (MAX_ATT_INDEX & ~3) ) /* envelope level lowest 2 bits are ignored by the comparator */
|
||||
{
|
||||
op->state = EG_OFF;
|
||||
}
|
||||
}
|
||||
/* else do nothing in sustain phase */
|
||||
}
|
||||
@@ -629,7 +717,7 @@ INLINE void advance(void)
|
||||
*/
|
||||
if ( (i&1) || ((ym2413.rhythm&0x20) && (i>=12)) )/* exclude modulators */
|
||||
{
|
||||
if(op->eg_type) /* non-percussive mode (sustained tone) */
|
||||
if (op->eg_type) /* non-percussive mode (sustained tone) */
|
||||
/*this is correct: use RR when SUS = OFF*/
|
||||
/*and use RS when SUS = ON*/
|
||||
{
|
||||
@@ -637,10 +725,9 @@ INLINE void advance(void)
|
||||
{
|
||||
if ( !(ym2413.eg_cnt & ((1<<op->eg_sh_rs)-1) ) )
|
||||
{
|
||||
op->volume += eg_inc[op->eg_sel_rs + ((ym2413.eg_cnt>>op->eg_sh_rs)&7)];
|
||||
if ( op->volume >= MAX_ATT_INDEX )
|
||||
op->volume += eg_inc[op->eg_sel_rs + ((ym2413.eg_cnt>>op->eg_sh_rs)&15)];
|
||||
if ( (op->volume & ~3) == (MAX_ATT_INDEX & ~3) ) /* envelope level lowest 2 bits are ignored by the comparator */
|
||||
{
|
||||
op->volume = MAX_ATT_INDEX;
|
||||
op->state = EG_OFF;
|
||||
}
|
||||
}
|
||||
@@ -649,23 +736,21 @@ INLINE void advance(void)
|
||||
{
|
||||
if ( !(ym2413.eg_cnt & ((1<<op->eg_sh_rr)-1) ) )
|
||||
{
|
||||
op->volume += eg_inc[op->eg_sel_rr + ((ym2413.eg_cnt>>op->eg_sh_rr)&7)];
|
||||
if ( op->volume >= MAX_ATT_INDEX )
|
||||
op->volume += eg_inc[op->eg_sel_rr + ((ym2413.eg_cnt>>op->eg_sh_rr)&15)];
|
||||
if ( (op->volume & ~3) == (MAX_ATT_INDEX & ~3) ) /* envelope level lowest 2 bits are ignored by the comparator */
|
||||
{
|
||||
op->volume = MAX_ATT_INDEX;
|
||||
op->state = EG_OFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* percussive mode */
|
||||
else /* percussive mode */
|
||||
{
|
||||
if ( !(ym2413.eg_cnt & ((1<<op->eg_sh_rs)-1) ) )
|
||||
{
|
||||
op->volume += eg_inc[op->eg_sel_rs + ((ym2413.eg_cnt>>op->eg_sh_rs)&7)];
|
||||
if ( op->volume >= MAX_ATT_INDEX )
|
||||
op->volume += eg_inc[op->eg_sel_rs + ((ym2413.eg_cnt>>op->eg_sh_rs)&15)];
|
||||
if ( (op->volume & ~3) == (MAX_ATT_INDEX & ~3) ) /* envelope level lowest 2 bits are ignored by the comparator */
|
||||
{
|
||||
op->volume = MAX_ATT_INDEX;
|
||||
op->state = EG_OFF;
|
||||
}
|
||||
}
|
||||
@@ -673,8 +758,12 @@ INLINE void advance(void)
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
case EG_OFF: /* envelope off */
|
||||
op->volume = MAX_ATT_INDEX;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1142,21 +1231,30 @@ INLINE void CALC_FCSLOT(YM2413_OPLL_CH *CH,YM2413_OPLL_SLOT *SLOT)
|
||||
SLOT->ksr = ksr;
|
||||
|
||||
/* calculate envelope generator rates */
|
||||
if ((SLOT->ar + SLOT->ksr) < 16+62)
|
||||
if ((SLOT->ar + SLOT->ksr) >= 16+60)
|
||||
{
|
||||
SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ];
|
||||
SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ];
|
||||
/* attack phase is skipped in case attack rate is set to 15.0-15.3 before attack phase is started */
|
||||
/* during attack phase, in case attack rate is changed to 15.0-15.3, attack phase is blocked */
|
||||
/* (verified on real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2017-01-26) */
|
||||
SLOT->eg_sh_ar = 13;
|
||||
SLOT->eg_sel_ar = 0 * RATE_STEPS;
|
||||
}
|
||||
else
|
||||
else if ((SLOT->ar + SLOT->ksr) >= 16+48)
|
||||
{
|
||||
/* attack rates 12.0 to 14.3 have similar specific behavior */
|
||||
/* (verified on real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2017-01-26) */
|
||||
SLOT->eg_sh_ar = 0;
|
||||
SLOT->eg_sel_ar = 13*RATE_STEPS;
|
||||
SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr] + (4 * RATE_STEPS);
|
||||
}
|
||||
else
|
||||
{
|
||||
SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr];
|
||||
SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr];
|
||||
}
|
||||
SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ];
|
||||
SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ];
|
||||
SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ];
|
||||
SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ];
|
||||
|
||||
}
|
||||
|
||||
if (CH->sus)
|
||||
@@ -1167,7 +1265,7 @@ INLINE void CALC_FCSLOT(YM2413_OPLL_CH *CH,YM2413_OPLL_SLOT *SLOT)
|
||||
SLOT->eg_sh_rs = eg_rate_shift [SLOT_rs + SLOT->ksr ];
|
||||
SLOT->eg_sel_rs = eg_rate_select[SLOT_rs + SLOT->ksr ];
|
||||
|
||||
SLOT_dp = 16 + (13<<2);
|
||||
SLOT_dp = 16 + (12<<2);
|
||||
SLOT->eg_sh_dp = eg_rate_shift [SLOT_dp + SLOT->ksr ];
|
||||
SLOT->eg_sel_dp = eg_rate_select[SLOT_dp + SLOT->ksr ];
|
||||
}
|
||||
@@ -1225,15 +1323,25 @@ INLINE void set_ar_dr(int slot,int v)
|
||||
|
||||
SLOT->ar = (v>>4) ? 16 + ((v>>4) <<2) : 0;
|
||||
|
||||
if ((SLOT->ar + SLOT->ksr) < 16+62)
|
||||
if ((SLOT->ar + SLOT->ksr) >= 16+60)
|
||||
{
|
||||
SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ];
|
||||
SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ];
|
||||
/* attack phase is skipped in case attack rate is set to 15.0-15.3 before attack phase is started */
|
||||
/* during attack phase, in case attack rate is changed to 15.0-15.3, attack phase is blocked */
|
||||
/* (verified on real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2017-01-26) */
|
||||
SLOT->eg_sh_ar = 13;
|
||||
SLOT->eg_sel_ar = 0 * RATE_STEPS;
|
||||
}
|
||||
else
|
||||
else if ((SLOT->ar + SLOT->ksr) >= 16+48)
|
||||
{
|
||||
/* attack rates 12.0 to 14.3 have similar specific behavior */
|
||||
/* (verified on real hardware, cf. https://www.smspower.org/Development/YM2413ReverseEngineeringNotes2017-01-26) */
|
||||
SLOT->eg_sh_ar = 0;
|
||||
SLOT->eg_sel_ar = 13*RATE_STEPS;
|
||||
SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr] + (4 * RATE_STEPS);
|
||||
}
|
||||
else
|
||||
{
|
||||
SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr];
|
||||
SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr];
|
||||
}
|
||||
|
||||
SLOT->dr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0;
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
/*
|
||||
** CHANGELOG:
|
||||
**
|
||||
** 11-05-2021 Eke-Eke (Genesis Plus GX):
|
||||
** - fixed potential issue with SSG-EG inverted attenuation level on Key OFF
|
||||
**
|
||||
** 03-12-2017 Eke-Eke (Genesis Plus GX):
|
||||
** - improved 9-bit DAC emulation accuracy
|
||||
** - added discrete YM2612 DAC distortion emulation ("ladder effect")
|
||||
@@ -684,7 +687,7 @@ INLINE void FM_KEYOFF(FM_CH *CH , int s )
|
||||
{
|
||||
/* convert EG attenuation level */
|
||||
if (SLOT->ssgn ^ (SLOT->ssg&0x04))
|
||||
SLOT->volume = (0x200 - SLOT->volume);
|
||||
SLOT->volume = (0x200 - SLOT->volume) & MAX_ATT_INDEX;
|
||||
|
||||
/* force EG attenuation level */
|
||||
if (SLOT->volume >= 0x200)
|
||||
@@ -749,7 +752,7 @@ INLINE void FM_KEYOFF_CSM(FM_CH *CH , int s )
|
||||
{
|
||||
/* convert EG attenuation level */
|
||||
if (SLOT->ssgn ^ (SLOT->ssg&0x04))
|
||||
SLOT->volume = (0x200 - SLOT->volume);
|
||||
SLOT->volume = (0x200 - SLOT->volume) & MAX_ATT_INDEX;
|
||||
|
||||
/* force EG attenuation level */
|
||||
if (SLOT->volume >= 0x200)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#ifdef HAVE_YM3438_CORE
|
||||
/*
|
||||
* Copyright (C) 2017 Alexey Khokholov (Nuke.YKT)
|
||||
* Copyright (C) 2017-2018 Alexey Khokholov (Nuke.YKT)
|
||||
*
|
||||
* Redistribution and use of this code or any derivative works are permitted
|
||||
* provided that the following conditions are met:
|
||||
@@ -40,7 +40,7 @@
|
||||
* OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
|
||||
* OPL2 ROMs.
|
||||
*
|
||||
* version: 1.0.8
|
||||
* version: 1.0.10
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
@@ -235,7 +235,7 @@ static const Bit32u fm_algorithm[4][6][8] = {
|
||||
|
||||
static Bit32u chip_type = ym3438_mode_readmode;
|
||||
|
||||
void OPN2_DoIO(ym3438_t *chip)
|
||||
static void OPN2_DoIO(ym3438_t *chip)
|
||||
{
|
||||
/* Write signal check */
|
||||
chip->write_a_en = (chip->write_a & 0x03) == 0x01;
|
||||
@@ -249,10 +249,10 @@ void OPN2_DoIO(ym3438_t *chip)
|
||||
chip->write_busy_cnt &= 0x1f;
|
||||
}
|
||||
|
||||
void OPN2_DoRegWrite(ym3438_t *chip)
|
||||
static void OPN2_DoRegWrite(ym3438_t *chip)
|
||||
{
|
||||
Bit32u i;
|
||||
Bit32u slot = chip->slot % 12;
|
||||
Bit32u slot = chip->cycles % 12;
|
||||
Bit32u address;
|
||||
Bit32u channel = chip->channel;
|
||||
/* Update registers */
|
||||
@@ -379,7 +379,7 @@ void OPN2_DoRegWrite(ym3438_t *chip)
|
||||
/* Data */
|
||||
if (chip->write_d_en && (chip->write_data & 0x100) == 0)
|
||||
{
|
||||
switch (chip->address)
|
||||
switch (chip->write_fm_mode_a)
|
||||
{
|
||||
case 0x21: /* LSI test 1 */
|
||||
for (i = 0; i < 8; i++)
|
||||
@@ -458,7 +458,7 @@ void OPN2_DoRegWrite(ym3438_t *chip)
|
||||
/* Address */
|
||||
if (chip->write_a_en)
|
||||
{
|
||||
chip->write_fm_mode_a = chip->write_data & 0xff;
|
||||
chip->write_fm_mode_a = chip->write_data & 0x1ff;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,16 +468,18 @@ void OPN2_DoRegWrite(ym3438_t *chip)
|
||||
}
|
||||
}
|
||||
|
||||
void OPN2_PhaseCalcIncrement(ym3438_t *chip)
|
||||
static void OPN2_PhaseCalcIncrement(ym3438_t *chip)
|
||||
{
|
||||
Bit32u chan = chip->channel;
|
||||
Bit32u slot = chip->cycles;
|
||||
Bit32u fnum = chip->pg_fnum;
|
||||
Bit32u fnum_h = fnum >> 4;
|
||||
Bit32u fm;
|
||||
Bit32u basefreq;
|
||||
Bit8u lfo = chip->lfo_pm;
|
||||
Bit8u lfo_l = lfo & 0x0f;
|
||||
Bit8u pms = chip->pms[chip->channel];
|
||||
Bit8u dt = chip->dt[chip->slot];
|
||||
Bit8u pms = chip->pms[chan];
|
||||
Bit8u dt = chip->dt[slot];
|
||||
Bit8u dt_l = dt & 0x03;
|
||||
Bit8u detune = 0;
|
||||
Bit8u block, note;
|
||||
@@ -531,32 +533,32 @@ void OPN2_PhaseCalcIncrement(ym3438_t *chip)
|
||||
basefreq += detune;
|
||||
}
|
||||
basefreq &= 0x1ffff;
|
||||
chip->pg_inc[chip->slot] = (basefreq * chip->multi[chip->slot]) >> 1;
|
||||
chip->pg_inc[chip->slot] &= 0xfffff;
|
||||
chip->pg_inc[slot] = (basefreq * chip->multi[slot]) >> 1;
|
||||
chip->pg_inc[slot] &= 0xfffff;
|
||||
}
|
||||
|
||||
void OPN2_PhaseGenerate(ym3438_t *chip)
|
||||
static void OPN2_PhaseGenerate(ym3438_t *chip)
|
||||
{
|
||||
Bit32u slot;
|
||||
/* Mask increment */
|
||||
slot = (chip->slot + 20) % 24;
|
||||
slot = (chip->cycles + 20) % 24;
|
||||
if (chip->pg_reset[slot])
|
||||
{
|
||||
chip->pg_inc[slot] = 0;
|
||||
}
|
||||
/* Phase step */
|
||||
slot = (chip->slot + 19) % 24;
|
||||
chip->pg_phase[slot] += chip->pg_inc[slot];
|
||||
chip->pg_phase[slot] &= 0xfffff;
|
||||
slot = (chip->cycles + 19) % 24;
|
||||
if (chip->pg_reset[slot] || chip->mode_test_21[3])
|
||||
{
|
||||
chip->pg_phase[slot] = 0;
|
||||
}
|
||||
chip->pg_phase[slot] += chip->pg_inc[slot];
|
||||
chip->pg_phase[slot] &= 0xfffff;
|
||||
}
|
||||
|
||||
void OPN2_EnvelopeSSGEG(ym3438_t *chip)
|
||||
static void OPN2_EnvelopeSSGEG(ym3438_t *chip)
|
||||
{
|
||||
Bit32u slot = chip->slot;
|
||||
Bit32u slot = chip->cycles;
|
||||
Bit8u direction = 0;
|
||||
chip->eg_ssg_pgrst_latch[slot] = 0;
|
||||
chip->eg_ssg_repeat_latch[slot] = 0;
|
||||
@@ -601,9 +603,9 @@ void OPN2_EnvelopeSSGEG(ym3438_t *chip)
|
||||
chip->eg_ssg_enable[slot] = (chip->ssg_eg[slot] >> 3) & 0x01;
|
||||
}
|
||||
|
||||
void OPN2_EnvelopeADSR(ym3438_t *chip)
|
||||
static void OPN2_EnvelopeADSR(ym3438_t *chip)
|
||||
{
|
||||
Bit32u slot = (chip->slot + 22) % 24;
|
||||
Bit32u slot = (chip->cycles + 22) % 24;
|
||||
|
||||
Bit8u nkon = chip->eg_kon_latch[slot];
|
||||
Bit8u okon = chip->eg_kon[slot];
|
||||
@@ -725,12 +727,12 @@ void OPN2_EnvelopeADSR(ym3438_t *chip)
|
||||
chip->eg_state[slot] = nextstate;
|
||||
}
|
||||
|
||||
void OPN2_EnvelopePrepare(ym3438_t *chip)
|
||||
static void OPN2_EnvelopePrepare(ym3438_t *chip)
|
||||
{
|
||||
Bit8u rate;
|
||||
Bit8u sum;
|
||||
Bit8u inc = 0;
|
||||
Bit32u slot = chip->slot;
|
||||
Bit32u slot = chip->cycles;
|
||||
Bit8u rate_sel;
|
||||
|
||||
/* Prepare increment */
|
||||
@@ -813,9 +815,9 @@ void OPN2_EnvelopePrepare(ym3438_t *chip)
|
||||
chip->eg_sl[0] = chip->sl[slot];
|
||||
}
|
||||
|
||||
void OPN2_EnvelopeGenerate(ym3438_t *chip)
|
||||
static void OPN2_EnvelopeGenerate(ym3438_t *chip)
|
||||
{
|
||||
Bit32u slot = (chip->slot + 23) % 24;
|
||||
Bit32u slot = (chip->cycles + 23) % 24;
|
||||
Bit16u level;
|
||||
|
||||
level = chip->eg_level[slot];
|
||||
@@ -846,7 +848,7 @@ void OPN2_EnvelopeGenerate(ym3438_t *chip)
|
||||
chip->eg_out[slot] = level;
|
||||
}
|
||||
|
||||
void OPN2_UpdateLFO(ym3438_t *chip)
|
||||
static void OPN2_UpdateLFO(ym3438_t *chip)
|
||||
{
|
||||
if ((chip->lfo_quotient & lfo_cycles[chip->lfo_freq]) == lfo_cycles[chip->lfo_freq])
|
||||
{
|
||||
@@ -860,14 +862,14 @@ void OPN2_UpdateLFO(ym3438_t *chip)
|
||||
chip->lfo_cnt &= chip->lfo_en;
|
||||
}
|
||||
|
||||
void OPN2_FMPrepare(ym3438_t *chip)
|
||||
static void OPN2_FMPrepare(ym3438_t *chip)
|
||||
{
|
||||
Bit32u slot = (chip->slot + 6) % 24;
|
||||
Bit32u slot = (chip->cycles + 6) % 24;
|
||||
Bit32u channel = chip->channel;
|
||||
Bit16s mod, mod1, mod2;
|
||||
Bit32u op = slot / 6;
|
||||
Bit8u connect = chip->connect[channel];
|
||||
Bit32u prevslot = (chip->slot + 18) % 24;
|
||||
Bit32u prevslot = (chip->cycles + 18) % 24;
|
||||
|
||||
/* Calculate modulation */
|
||||
mod1 = mod2 = 0;
|
||||
@@ -908,7 +910,7 @@ void OPN2_FMPrepare(ym3438_t *chip)
|
||||
}
|
||||
chip->fm_mod[slot] = mod;
|
||||
|
||||
slot = (chip->slot + 18) % 24;
|
||||
slot = (chip->cycles + 18) % 24;
|
||||
/* OP1 */
|
||||
if (slot / 6 == 0)
|
||||
{
|
||||
@@ -922,9 +924,9 @@ void OPN2_FMPrepare(ym3438_t *chip)
|
||||
}
|
||||
}
|
||||
|
||||
void OPN2_ChGenerate(ym3438_t *chip)
|
||||
static void OPN2_ChGenerate(ym3438_t *chip)
|
||||
{
|
||||
Bit32u slot = (chip->slot + 18) % 24;
|
||||
Bit32u slot = (chip->cycles + 18) % 24;
|
||||
Bit32u channel = chip->channel;
|
||||
Bit32u op = slot / 6;
|
||||
Bit32u test_dac = chip->mode_test_2c[5];
|
||||
@@ -957,16 +959,17 @@ void OPN2_ChGenerate(ym3438_t *chip)
|
||||
chip->ch_acc[channel] = sum;
|
||||
}
|
||||
|
||||
void OPN2_ChOutput(ym3438_t *chip)
|
||||
static void OPN2_ChOutput(ym3438_t *chip)
|
||||
{
|
||||
Bit32u cycles = chip->cycles;
|
||||
Bit32u slot = chip->cycles;
|
||||
Bit32u channel = chip->channel;
|
||||
Bit32u test_dac = chip->mode_test_2c[5];
|
||||
Bit16s out;
|
||||
Bit16s sign;
|
||||
Bit32u out_en;
|
||||
chip->ch_read = chip->ch_lock;
|
||||
if (chip->slot < 12)
|
||||
if (slot < 12)
|
||||
{
|
||||
/* Ch 4,5,6 */
|
||||
channel++;
|
||||
@@ -1039,9 +1042,9 @@ void OPN2_ChOutput(ym3438_t *chip)
|
||||
}
|
||||
}
|
||||
|
||||
void OPN2_FMGenerate(ym3438_t *chip)
|
||||
static void OPN2_FMGenerate(ym3438_t *chip)
|
||||
{
|
||||
Bit32u slot = (chip->slot + 19) % 24;
|
||||
Bit32u slot = (chip->cycles + 19) % 24;
|
||||
/* Calculate phase */
|
||||
Bit16u phase = (chip->fm_mod[slot] + (chip->pg_phase[slot] >> 10)) & 0x3ff;
|
||||
Bit16u quarter;
|
||||
@@ -1077,7 +1080,7 @@ void OPN2_FMGenerate(ym3438_t *chip)
|
||||
chip->fm_out[slot] = output;
|
||||
}
|
||||
|
||||
void OPN2_DoTimerA(ym3438_t *chip)
|
||||
static void OPN2_DoTimerA(ym3438_t *chip)
|
||||
{
|
||||
Bit16u time;
|
||||
Bit8u load;
|
||||
@@ -1126,7 +1129,7 @@ void OPN2_DoTimerA(ym3438_t *chip)
|
||||
chip->timer_a_cnt = time & 0x3ff;
|
||||
}
|
||||
|
||||
void OPN2_DoTimerB(ym3438_t *chip)
|
||||
static void OPN2_DoTimerB(ym3438_t *chip)
|
||||
{
|
||||
Bit16u time;
|
||||
Bit8u load;
|
||||
@@ -1171,27 +1174,29 @@ void OPN2_DoTimerB(ym3438_t *chip)
|
||||
chip->timer_b_cnt = time & 0xff;
|
||||
}
|
||||
|
||||
void OPN2_KeyOn(ym3438_t*chip)
|
||||
static void OPN2_KeyOn(ym3438_t*chip)
|
||||
{
|
||||
Bit32u slot = chip->cycles;
|
||||
Bit32u chan = chip->channel;
|
||||
/* Key On */
|
||||
chip->eg_kon_latch[chip->slot] = chip->mode_kon[chip->slot];
|
||||
chip->eg_kon_csm[chip->slot] = 0;
|
||||
chip->eg_kon_latch[slot] = chip->mode_kon[slot];
|
||||
chip->eg_kon_csm[slot] = 0;
|
||||
if (chip->channel == 2 && chip->mode_kon_csm)
|
||||
{
|
||||
/* CSM Key On */
|
||||
chip->eg_kon_latch[chip->slot] = 1;
|
||||
chip->eg_kon_csm[chip->slot] = 1;
|
||||
chip->eg_kon_latch[slot] = 1;
|
||||
chip->eg_kon_csm[slot] = 1;
|
||||
}
|
||||
if (chip->cycles == chip->mode_kon_channel)
|
||||
{
|
||||
/* OP1 */
|
||||
chip->mode_kon[chip->channel] = chip->mode_kon_operator[0];
|
||||
chip->mode_kon[chan] = chip->mode_kon_operator[0];
|
||||
/* OP2 */
|
||||
chip->mode_kon[chip->channel + 12] = chip->mode_kon_operator[1];
|
||||
chip->mode_kon[chan + 12] = chip->mode_kon_operator[1];
|
||||
/* OP3 */
|
||||
chip->mode_kon[chip->channel + 6] = chip->mode_kon_operator[2];
|
||||
chip->mode_kon[chan + 6] = chip->mode_kon_operator[2];
|
||||
/* OP4 */
|
||||
chip->mode_kon[chip->channel + 18] = chip->mode_kon_operator[3];
|
||||
chip->mode_kon[chan + 18] = chip->mode_kon_operator[3];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1220,6 +1225,7 @@ void OPN2_SetChipType(Bit32u type)
|
||||
|
||||
void OPN2_Clock(ym3438_t *chip, Bit16s *buffer)
|
||||
{
|
||||
Bit32u slot = chip->cycles;
|
||||
chip->lfo_inc = chip->mode_test_21[1];
|
||||
chip->pg_read >>= 1;
|
||||
chip->eg_read[1] >>= 1;
|
||||
@@ -1310,7 +1316,7 @@ void OPN2_Clock(ym3438_t *chip, Bit16s *buffer)
|
||||
if (chip->mode_ch3)
|
||||
{
|
||||
/* Channel 3 special mode */
|
||||
switch (chip->slot)
|
||||
switch (slot)
|
||||
{
|
||||
case 1: /* OP1 */
|
||||
chip->pg_fnum = chip->fnum_3ch[1];
|
||||
@@ -1345,7 +1351,6 @@ void OPN2_Clock(ym3438_t *chip, Bit16s *buffer)
|
||||
OPN2_UpdateLFO(chip);
|
||||
OPN2_DoRegWrite(chip);
|
||||
chip->cycles = (chip->cycles + 1) % 24;
|
||||
chip->slot = chip->cycles;
|
||||
chip->channel = chip->cycles % 6;
|
||||
|
||||
buffer[0] = chip->mol;
|
||||
@@ -1397,6 +1402,7 @@ Bit8u OPN2_Read(ym3438_t *chip, Bit32u port)
|
||||
if (chip->mode_test_21[6])
|
||||
{
|
||||
/* Read test data */
|
||||
Bit32u slot = (chip->cycles + 18) % 24;
|
||||
Bit16u testdata = ((chip->pg_read & 0x01) << 15)
|
||||
| ((chip->eg_read[chip->mode_test_21[0]] & 0x01) << 14);
|
||||
if (chip->mode_test_2c[4])
|
||||
@@ -1405,7 +1411,7 @@ Bit8u OPN2_Read(ym3438_t *chip, Bit32u port)
|
||||
}
|
||||
else
|
||||
{
|
||||
testdata |= chip->fm_out[(chip->slot + 18) % 24] & 0x3fff;
|
||||
testdata |= chip->fm_out[slot] & 0x3fff;
|
||||
}
|
||||
if (chip->mode_test_21[7])
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Alexey Khokholov (Nuke.YKT)
|
||||
* Copyright (C) 2017-2018 Alexey Khokholov (Nuke.YKT)
|
||||
*
|
||||
* Redistribution and use of this code or any derivative works are permitted
|
||||
* provided that the following conditions are met:
|
||||
@@ -39,15 +39,19 @@
|
||||
* OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
|
||||
* OPL2 ROMs.
|
||||
*
|
||||
* version: 1.0.8
|
||||
* version: 1.0.9
|
||||
*/
|
||||
|
||||
#ifndef YM3438_H
|
||||
#define YM3438_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
ym3438_mode_ym2612 = 0x01, /* Enables YM2612 emulation (MD1, MD2 VA2) */
|
||||
ym3438_mode_readmode = 0x02, /* Enables status read on any port (TeraDrive, MD1 VA7, MD2, etc) */
|
||||
ym3438_mode_readmode = 0x02 /* Enables status read on any port (TeraDrive, MD1 VA7, MD2, etc) */
|
||||
};
|
||||
|
||||
#include <stdint.h>
|
||||
@@ -66,7 +70,6 @@ typedef int8_t Bit8s;
|
||||
typedef struct
|
||||
{
|
||||
Bit32u cycles;
|
||||
Bit32u slot;
|
||||
Bit32u channel;
|
||||
Bit16s mol, mor;
|
||||
/* IO */
|
||||
@@ -79,7 +82,7 @@ typedef struct
|
||||
Bit8u write_busy_cnt;
|
||||
Bit8u write_fm_address;
|
||||
Bit8u write_fm_data;
|
||||
Bit8u write_fm_mode_a;
|
||||
Bit16u write_fm_mode_a;
|
||||
Bit16u address;
|
||||
Bit8u data;
|
||||
Bit8u pin_test_in;
|
||||
@@ -155,7 +158,7 @@ typedef struct
|
||||
Bit8u timer_a_load_latch;
|
||||
Bit8u timer_a_overflow_flag;
|
||||
Bit8u timer_a_overflow;
|
||||
|
||||
|
||||
Bit16u timer_b_cnt;
|
||||
Bit8u timer_b_subcnt;
|
||||
Bit16u timer_b_reg;
|
||||
@@ -166,7 +169,7 @@ typedef struct
|
||||
Bit8u timer_b_load_latch;
|
||||
Bit8u timer_b_overflow_flag;
|
||||
Bit8u timer_b_overflow;
|
||||
|
||||
|
||||
/* Register set */
|
||||
Bit8u mode_test_21[8];
|
||||
Bit8u mode_test_2c[8];
|
||||
@@ -178,7 +181,7 @@ typedef struct
|
||||
Bit8u mode_kon_csm;
|
||||
Bit8u dacen;
|
||||
Bit16s dacdata;
|
||||
|
||||
|
||||
Bit8u ks[24];
|
||||
Bit8u ar[24];
|
||||
Bit8u sr[24];
|
||||
@@ -190,7 +193,7 @@ typedef struct
|
||||
Bit8u am[24];
|
||||
Bit8u tl[24];
|
||||
Bit8u ssg_eg[24];
|
||||
|
||||
|
||||
Bit16u fnum[6];
|
||||
Bit8u block[6];
|
||||
Bit8u kcode[6];
|
||||
@@ -216,4 +219,9 @@ void OPN2_SetTestPin(ym3438_t *chip, Bit32u value);
|
||||
Bit32u OPN2_ReadTestPin(ym3438_t *chip);
|
||||
Bit32u OPN2_ReadIRQPin(ym3438_t *chip);
|
||||
Bit8u OPN2_Read(ym3438_t *chip, Bit32u port);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user