diff --git a/output/dll/gpgx.wbx.gz b/output/dll/gpgx.wbx.gz index d4cef8a5db..bd4bce54e1 100644 Binary files a/output/dll/gpgx.wbx.gz and b/output/dll/gpgx.wbx.gz differ diff --git a/src/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.cs b/src/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.cs index 5b9366ccad..ec06a10512 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.cs @@ -50,9 +50,9 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx Path = lp.Comm.CoreFileProvider.DllPath(), Filename = "gpgx.wbx", SbrkHeapSizeKB = 512, - SealedHeapSizeKB = 36 * 1024, + SealedHeapSizeKB = 4 * 1024, InvisibleHeapSizeKB = 4 * 1024, - PlainHeapSizeKB = 64 + 1024, + PlainHeapSizeKB = 34 * 1024, MmapHeapSizeKB = 1 * 1024, SkipCoreConsistencyCheck = lp.Comm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxCoreConsistencyCheck), SkipMemoryConsistencyCheck = lp.Comm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck), diff --git a/waterbox/gpgx/cinterface/cinterface.c b/waterbox/gpgx/cinterface/cinterface.c index 45a24e68e9..63b29217a0 100644 --- a/waterbox/gpgx/cinterface/cinterface.c +++ b/waterbox/gpgx/cinterface/cinterface.c @@ -527,7 +527,7 @@ GPGX_EX int gpgx_init(const char* feromextension, tempsram = alloc_invisible(24 * 1024); bg_pattern_cache = alloc_invisible(0x80000); - ext.md_cart.rom = alloc_sealed(32 * 1024 * 1024); + ext.md_cart.rom = alloc_plain(32 * 1024 * 1024); SZHVC_add = alloc_sealed(131072); SZHVC_sub = alloc_sealed(131072); ym2612_lfo_pm_table = alloc_sealed(131072); diff --git a/waterbox/gpgx/core/cart_hw/md_cart.c b/waterbox/gpgx/core/cart_hw/md_cart.c index 380c5ba218..16aefd6100 100644 --- a/waterbox/gpgx/core/cart_hw/md_cart.c +++ b/waterbox/gpgx/core/cart_hw/md_cart.c @@ -2,7 +2,7 @@ * Genesis Plus * Mega Drive cartridge hardware support * - * Copyright (C) 2007-2013 Eke-Eke (Genesis Plus GX) + * Copyright (C) 2007-2020 Eke-Eke (Genesis Plus GX) * * Many cartridge protections were initially documented by Haze * (http://haze.mameworld.info/) @@ -47,8 +47,6 @@ #include "gamepad.h" #include -#define CART_CNT (55) - /* Cart database entry */ typedef struct { @@ -61,6 +59,7 @@ typedef struct /* Function prototypes */ static void mapper_sega_w(uint32 data); +static void mapper_512k_w(uint32 address, uint32 data); static void mapper_ssf2_w(uint32 address, uint32 data); static void mapper_sf001_w(uint32 address, uint32 data); static void mapper_sf002_w(uint32 address, uint32 data); @@ -68,6 +67,8 @@ static void mapper_sf004_w(uint32 address, uint32 data); static uint32 mapper_sf004_r(uint32 address); static void mapper_t5740_w(uint32 address, uint32 data); static uint32 mapper_t5740_r(uint32 address); +static void mapper_flashkit_w(uint32 address, uint32 data); +static uint32 mapper_flashkit_r(uint32 address); static uint32 mapper_smw_64_r(uint32 address); static void mapper_smw_64_w(uint32 address, uint32 data); static void mapper_realtec_w(uint32 address, uint32 data); @@ -75,7 +76,11 @@ static void mapper_seganet_w(uint32 address, uint32 data); static void mapper_32k_w(uint32 data); static void mapper_64k_w(uint32 data); static void mapper_64k_multi_w(uint32 address); -static uint32 mapper_radica_r(uint32 address); +static uint32 mapper_128k_multi_r(uint32 address); +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 default_time_w(uint32 address, uint32 data); static void default_regs_w(uint32 address, uint32 data); static uint32 default_regs_r(uint32 address); @@ -92,7 +97,7 @@ static void tekken_regs_w(uint32 address, uint32 data); - copy protection device - custom ROM banking device */ -static const md_entry_t rom_database[CART_CNT] = +static const md_entry_t rom_database[] = { /* Funny World & Balloon Boy */ {0x0000,0x06ab,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},1,0,NULL,NULL,NULL,mapper_realtec_w}}, @@ -100,14 +105,29 @@ static const md_entry_t rom_database[CART_CNT] = {0xffff,0xf863,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},1,0,NULL,NULL,NULL,mapper_realtec_w}}, /* Earth Defense */ {0xffff,0x44fb,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},1,0,NULL,NULL,NULL,mapper_realtec_w}}, +/* Tom Clown */ + {0x0000,0xc0cd,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},1,0,NULL,NULL,NULL,mapper_realtec_w}}, +/* 1800-in-1 */ + {0x3296,0x2370,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,1,mapper_128k_multi_r,m68k_unused_8_w,NULL,NULL}}, + +/* Golden Mega 250-in-1 */ + {0xe43c,0x886f,0x08,0x08,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,1,NULL,m68k_unused_8_w,NULL,mapper_256k_multi_w}}, /* RADICA (Volume 1) (bad dump ?) */ - {0x0000,0x2326,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,1,mapper_radica_r,NULL,NULL,NULL}}, + {0x0000,0x2326,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,1,mapper_64k_radica_r,m68k_unused_8_w,NULL,NULL}}, /* RADICA (Volume 1) */ - {0x24f4,0xfc84,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,mapper_radica_r,NULL,NULL,NULL}}, + {0x24f4,0xfc84,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,mapper_64k_radica_r,m68k_unused_8_w,NULL,NULL}}, /* RADICA (Volume 2) */ - {0x104f,0x32e9,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,mapper_radica_r,NULL,NULL,NULL}}, + {0xd951,0x78d0,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,mapper_64k_radica_r,m68k_unused_8_w,NULL,NULL}}, +/* RADICA (Volume 3 - Super Sonic Gold edition) */ + {0x0000,0x1f25,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,mapper_64k_radica_r,m68k_unused_8_w,NULL,NULL}}, +/* RADICA (Street Fighter II CE edition) */ + {0x1add,0xa838,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,mapper_64k_radica_r,m68k_unused_8_w,NULL,NULL}}, +/* RADICA (Street Fighter II CE edition) (PAL) */ + {0x104f,0x32e9,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,mapper_64k_radica_r,m68k_unused_8_w,NULL,NULL}}, +/* RADICA (Sensible Soccer Plus edition) (PAL) */ + {0x0000,0x1f7f,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,mapper_128k_radica_r,m68k_unused_8_w,NULL,NULL}}, /* Tenchi wo Kurau III: Sangokushi Gaiden - Chinese Fighter */ @@ -127,7 +147,7 @@ static const md_entry_t rom_database[CART_CNT] = /* Super King Kong 99 */ {0x0000,0x7d6e,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,custom_regs_w}}, /* Gunfight 3-in-1 */ - {0x0000,0x6ff8,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,custom_regs_w}}, + {0x0000,0x6ff8,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,custom_regs_w}}, /* Pokemon Stadium */ {0x0000,0x843c,0x70,0x7f,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,1,NULL,NULL,NULL,custom_regs_w}}, @@ -181,6 +201,8 @@ static const md_entry_t rom_database[CART_CNT] = {0x0000,0x1585,0x40,0x40,{{0x55,0x0f,0xaa,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,NULL,default_regs_r_16,NULL}}, +/* Chaoji Puke - Super Poker (correct ROM dump, original release is an overdump) */ + {0xffff,0xd7b0,0x40,0x40,{{0x55,0x0f,0xaa,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,NULL,default_regs_r,NULL}}, /* Super Bubble Bobble */ {0x0000,0x16cd,0x40,0x40,{{0x55,0x0f,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,NULL}}, /* Tenchi wo Kurau II - The Battle of Red Cliffs (Unl) */ @@ -240,9 +262,6 @@ static const md_entry_t rom_database[CART_CNT] = }; -static uint8* mapper_32k_scratch = NULL; - - /************************************************************ Cart Hardware initialization *************************************************************/ @@ -322,6 +341,9 @@ void md_cart_init(void) /* ROM is mirrored each 2^k bytes */ cart.mask = size - 1; + /* no special external hardware required by default */ + cart.special = 0; + /********************************************** DEFAULT CARTRIDGE MAPPING ***********************************************/ @@ -373,13 +395,12 @@ void md_cart_init(void) sram_init(); eeprom_i2c_init(); - /* external SRAM */ + /* memory-mapped SRAM */ if (sram.on && !sram.custom) { - /* disabled on startup if ROM is mapped in same area */ - if (cart.romsize <= sram.start) + /* SRAM is mapped by default unless it overlaps with ROM area (Phantasy Star 4, Beyond Oasis/Legend of Thor, World Series Baseball 9x, Duke Nukem 3D,...) */ + if (sram.start >= cart.romsize) { - /* initialize m68k bus handlers */ m68k.memory_map[sram.start >> 16].base = sram.sram; m68k.memory_map[sram.start >> 16].read8 = sram_read_byte; m68k.memory_map[sram.start >> 16].read16 = sram_read_word; @@ -388,6 +409,34 @@ void md_cart_init(void) zbank_memory_map[sram.start >> 16].read = sram_read_byte; zbank_memory_map[sram.start >> 16].write = sram_write_byte; } + + /* support for Triple Play 96 & Triple Play - Gold Edition mapping */ + else if ((strstr(rominfo.product,"T-172026") != NULL) || (strstr(rominfo.product,"T-172116") != NULL)) + { + /* $000000-$1fffff: cartridge ROM (lower 2MB) */ + /* $200000-$2fffff: SRAM (32KB mirrored) */ + /* NB: existing 4MB ROM dumps include SRAM data at ROM offsets 0x200000-0x2fffff */ + for (i=0x20; i<0x30; i++) + { + m68k.memory_map[i].base = sram.sram; + m68k.memory_map[i].read8 = sram_read_byte; + m68k.memory_map[i].read16 = sram_read_word; + m68k.memory_map[i].write8 = sram_write_byte; + m68k.memory_map[i].write16 = sram_write_word; + zbank_memory_map[i].read = sram_read_byte; + zbank_memory_map[i].write = sram_write_byte; + } + + /* $300000-$3fffff: cartridge ROM (upper 1MB) */ + /* NB: only real (3MB) Mask ROM dumps need ROM offsets 0x200000-0x2fffff to be remapped to this area */ + if (READ_BYTE(cart.rom, 0x200000) != 0xFF) + { + for (i=0x30; i<0x40; i++) + { + m68k.memory_map[i].base = cart.rom + ((i - 0x10) << 16); + } + } + } } /********************************************** @@ -399,38 +448,6 @@ void md_cart_init(void) svp_init(); } - /********************************************** - J-CART - ***********************************************/ - cart.special = 0; - if ((strstr(rominfo.product,"00000000") && (rominfo.checksum == 0x168b)) || /* Super Skidmarks, Micro Machines Military */ - (strstr(rominfo.product,"00000000") && (rominfo.checksum == 0x165e)) || /* Pete Sampras Tennis (1991), Micro Machines 96 */ - (strstr(rominfo.product,"00000000") && (rominfo.checksum == 0xcee0)) || /* Micro Machines Military (bad) */ - (strstr(rominfo.product,"00000000") && (rominfo.checksum == 0x2c41)) || /* Micro Machines 96 (bad) */ - (strstr(rominfo.product,"XXXXXXXX") && (rominfo.checksum == 0xdf39)) || /* Sampras Tennis 96 */ - (strstr(rominfo.product,"T-123456") && (rominfo.checksum == 0x1eae)) || /* Sampras Tennis 96 */ - (strstr(rominfo.product,"T-120066") && (rominfo.checksum == 0x16a4)) || /* Pete Sampras Tennis (1994)*/ - strstr(rominfo.product,"T-120096")) /* Micro Machines 2 */ - { - if (cart.romsize <= 0x380000) /* just to be sure (checksum might not be enough) */ - { - cart.special |= HW_J_CART; - - /* force port 1 setting */ - if (input.system[1] != SYSTEM_WAYPLAY) - { - old_system[1] = input.system[1]; - input.system[1] = SYSTEM_MD_GAMEPAD; - } - - /* extra connectors mapped at $38xxxx or $3Fxxxx */ - m68k.memory_map[0x38].read16 = jcart_read; - m68k.memory_map[0x38].write16 = jcart_write; - m68k.memory_map[0x3f].read16 = jcart_read; - m68k.memory_map[0x3f].write16 = jcart_write; - } - } - /********************************************** LOCK-ON ***********************************************/ @@ -456,54 +473,45 @@ void md_cart_init(void) case TYPE_SK: { - FILE *f; - /* store S&K ROM above cartridge ROM (and before backup memory) */ if (cart.romsize > 0x600000) break; - /* load Sonic & Knuckles ROM (2 MB) */ - f = fopen(SK_ROM,"rb"); - if (!f) break; - for (i=0; i<0x200000; i+=0x1000) + /* try to load Sonic & Knuckles ROM file (2 MB) */ + if (load_archive(SK_ROM, cart.rom + 0x600000, 0x200000, NULL) == 0x200000) { - fread(cart.rom + 0x600000 + i, 0x1000, 1, f); - } - fclose(f); - - /* load Sonic 2 UPMEM ROM (256 KB) */ - f = fopen(SK_UPMEM,"rb"); - if (!f) break; - for (i=0; i<0x40000; i+=0x1000) - { - fread(cart.rom + 0x900000 + i, 0x1000, 1, f); - } - fclose(f); + /* 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<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; - } + 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 - - /* $000000-$1FFFFF is mapped to S&K ROM */ - for (i=0x00; i<0x20; i++) - { - m68k.memory_map[i].base = cart.rom + 0x600000 + (i << 16); + cart.special |= HW_LOCK_ON; + } + } } - - cart.special |= HW_LOCK_ON; break; } @@ -519,7 +527,7 @@ void md_cart_init(void) memset(&cart.hw, 0, sizeof(cart.hw)); /* search for game into database */ - for (i=0; i 0x400000) { - /* assume linear ROM mapper without bankswitching (max. 10MB) */ + /* assume linear ROM mapping by default (max. 10MB) */ for (i=0x40; i<0xA0; i++) { m68k.memory_map[i].base = cart.rom + (i<<16); @@ -835,25 +870,37 @@ static void mapper_sega_w(uint32 data) } } +/* + Everdrive extended SSF ROM bankswitch + documented by Krikzz (http://krikzz.com/pub/support/mega-ed/dev/extended_ssf.txt) +*/ +static void mapper_512k_w(uint32 address, uint32 data) +{ + uint32 i; + + /* 512K ROM paging */ + uint8 *src = cart.rom + ((data << 19) & cart.mask); + + /* cartridge area ($000000-$3FFFFF) is divided into 8 x 512K banks */ + address = (address << 2) & 0x38; + + /* remap selected ROM page to selected bank */ + for (i=0; i<8; i++) + { + m68k.memory_map[address++].base = src + (i<<16); + } +} + /* Super Street Fighter 2 ROM bankswitch - documented by Bart Trzynadlowski (http://www.trzy.org/files/ssf2.txt) + documented by Bart Trzynadlowski (http://emu-docs.org/Genesis/ssf2.txt) */ static void mapper_ssf2_w(uint32 address, uint32 data) { - /* 8 x 512k banks */ - address = (address << 2) & 0x38; - - /* bank 0 remains unchanged */ - if (address) + /* only banks 1-7 are remappable, bank 0 remains unchanged */ + if (address & 0x0E) { - uint32 i; - uint8 *src = cart.rom + (data << 19); - - for (i=0; i<8; i++) - { - m68k.memory_map[address++].base = src + (i<<16); - } + mapper_512k_w(address, data); } } @@ -958,59 +1005,23 @@ static void mapper_sf001_w(uint32 address, uint32 data) */ static void mapper_sf002_w(uint32 address, uint32 data) { - /* 8 x 512k banks */ - address = (address << 2) & 0x38; - - /* bank 0 remains unchanged */ - if (address) - { - uint32 i; - uint8 *src = cart.rom + (data << 19); - - for (i = 0; i<8; i++) - { - m68k.memory_map[address++].base = src + (i << 16); - } - } - else // emulate turning on SRAM - { - if (data & 1) - { - if (sram.on) - { - /* Backup RAM mapped to $200000-$20ffff (normally mirrored up to $3fffff but this breaks Sonic Megamix and no game need it) */ - cart.hw.bankshift = m68k.memory_map[0x20].base; - m68k.memory_map[0x20].base = sram.sram; - m68k.memory_map[0x20].read8 = sram_read_byte; - m68k.memory_map[0x20].read16 = sram_read_word; - zbank_memory_map[0x20].read = sram_read_byte; - - /* Backup RAM write protection */ - if (data & 2) - { - m68k.memory_map[0x20].write8 = m68k_unused_8_w; - m68k.memory_map[0x20].write16 = m68k_unused_16_w; - zbank_memory_map[0x20].write = zbank_unused_w; - } - else - { - m68k.memory_map[0x20].write8 = sram_write_byte; - m68k.memory_map[0x20].write16 = sram_write_word; - zbank_memory_map[0x20].write = sram_write_byte; - } - } - } - else - { - // automatically turn off writing to SRAM if SRAM is not visible - m68k.memory_map[0x20].write8 = m68k_unused_8_w; - m68k.memory_map[0x20].write16 = m68k_unused_16_w; - zbank_memory_map[0x20].write = zbank_unused_w; - - // put the ROM data back in the memory map - m68k.memory_map[0x20].base = cart.hw.bankshift; - } - } + int i; + if (data & 0x80) + { + /* $000000-$1BFFFF mapped to $200000-$3BFFFF */ + for (i=0x20; i<0x3C; i++) + { + m68k.memory_map[i].base = cart.rom + ((i & 0x1F) << 16); + } + } + else + { + /* $200000-$3BFFFF mapped to $200000-$3BFFFF */ + for (i=0x20; i<0x3C; i++) + { + m68k.memory_map[i].base = cart.rom + (i << 16); + } + } } /* @@ -1236,7 +1247,45 @@ static uint32 mapper_t5740_r(uint32 address) return READ_BYTE(cart.rom, address); } -/* +/* + FlashKit MD mapper (very limited M29W320xx Flash memory support -- enough for unlicensed games using device signature as protection) +*/ +static void mapper_flashkit_w(uint32 address, uint32 data) +{ + /* Increment Bus Write counter */ + cart.hw.regs[0]++; + + /* Wait for 3 consecutive bus writes */ + if (cart.hw.regs[0] == 3) + { + /* assume 'Auto Select' command */ + m68k.memory_map[0x0].read16 = mapper_flashkit_r; + } + else if (cart.hw.regs[0] == 4) + { + /* assume 'Read/Reset' command */ + m68k.memory_map[0x0].read16 = NULL; + + /* reset Bus Write counter */ + cart.hw.regs[0] = 0; + } +} + +static uint32 mapper_flashkit_r(uint32 address) +{ + /* hard-coded device signature */ + switch (address & 0x06) + { + case 0x00: /* Manufacturer Code (STMicroelectronics) */ + return 0x0020; + case 0x02: /* Device Code (M29W320EB) */ + return 0x2257; + default: /* not supported */ + return 0xffff; + } +} + +/* Super Mario World 64 (unlicensed) mapper */ static void mapper_smw_64_w(uint32 address, uint32 data) @@ -1489,8 +1538,8 @@ static void mapper_32k_w(uint32 data) { for (i=0; i<0x10; i++) { - /* Remap to extra scratch area */ - m68k.memory_map[i].base = &mapper_32k_scratch[i << 16]; + /* Remap to unused ROM area */ + m68k.memory_map[i].base = &cart.rom[0x400000 + (i << 16)]; /* address = address OR (value << 15) */ memcpy(m68k.memory_map[i].base, cart.rom + ((i << 16) | (data & 0x3f) << 15), 0x8000); @@ -1543,27 +1592,208 @@ static void mapper_64k_multi_w(uint32 address) /* 64 x 64k banks */ for (i=0; i<64; i++) { - m68k.memory_map[i].base = &cart.rom[((address++) & 0x3f) << 16]; + m68k.memory_map[i].base = &cart.rom[((address + i) & 0x3f) << 16]; + } +} + +/* + Custom ROM Bankswitch used in pirate "1800-in-1" cartridge + */ +static uint32 mapper_128k_multi_r(uint32 address) +{ + int i; + + /* 16 x 128k banks (2MB ROM) */ + /* Bank index (B3 B2 B1 B0) is encoded in address lower byte = {0 X B0 B1 X B2 B3 0} */ + /* Note: {0 B0 X B1 X B2 B3 0} also works, see below for the 9 unique values being used for all menu entries + read16 00A13000 (0002FBEE) => 0x000000-0x03ffff (2x128KB) + read16 00A13018 (00FF2056) => 0x040000-0x07ffff (2x128KB) + read16 00A13004 (00FF2120) => 0x080000-0x0bffff (2x128KB) + read16 00A1301C (00FF20A6) => 0x0c0000-0x0fffff (2x128KB) + read16 00A1300A (00FF20BA) => 0x100000-0x13ffff (2x128KB) + read16 00A1301A (00FF20CE) => 0x140000-0x17ffff (2x128KB) + read16 00A1300E (00FF20F4) => 0x180000-0x1bffff (2x128KB) + read16 00A1301E (00FF2136) => 0x1c0000-0x1dffff (1x128KB) + read16 00A1307E (00FF2142) => 0x1e0000-0x1fffff (1x128KB) + */ + int bank = ((address & 0x02) << 2) | (address & 0x04) | ((address & 0x10) >> 3) | ((address & 0x20) >> 5); + + /* remap cartridge area (64 x 64k banks) */ + address = bank << 1; + for (i=0x00; i<0x40; i++) + { + m68k.memory_map[i].base = &cart.rom[((address + i) & 0x3f) << 16]; + } + + /* returned value changes the menu title and number of entries in the 'game' list (the number of distinct games does not change though) */ + /* 0x00 => 9-in-1 */ + /* 0x01 => 190-in-1 */ + /* 0x02 => 888-in-1 */ + /* 0x03 => 1800-in-1 */ + /* real cartridge board has switches to select between the four different menus but here we force the largest menu selection (each other menus being a subset of the next larger menu) */ + return 0x03; +} + +/* + Custom ROM Bankswitch used in pirate "Golden Mega 250-in-1" cartridge + */ +static void mapper_256k_multi_w(uint32 address, uint32 data) +{ + int i; + + /* 8 x 256k banks (2MB ROM) */ + /* Bank index (B2 B1 B0) is encoded in data lower byte = {B1 B0 X X 0 0 0 B2} */ + /* Note: {X B0 B1 B2 0 0 0 X}, {B1 B0 X B2 0 0 0 X} or {X B0 B1 X 0 0 0 B2} also work, see below for the 4 unique values being used for all menu entries + write16 00089000 = 0000 (00FF0006) => 0x000000-0x03ffff (1x256KB) + write16 00089000 = 0040 (00FF0006) => 0x040000-0x07ffff (1x256KB) + write16 00089000 = 00A0 (00FF0006) => 0x080000-0x0fffff (2x256KB) + write16 00089000 = 0011 (00FF0006) => 0x100000-0x1fffff (4x256KB) + */ + int bank = ((data & 0x01) << 2) | ((data & 0xc0) >> 6); + + /* remap cartridge area (64 x 64k banks) */ + address = bank << 2; + for (i=0x00; i<0x40; i++) + { + m68k.memory_map[i].base = &cart.rom[((address + i) & 0x3f) << 16]; + } +} + +/* + Custom ROM Bankswitch used in "Canon - Legend of the New Gods" + (uses WD1601 QFPL V1.01 board also used in chinese X-in-1 pirates sold by mindkids) + */ +static void mapper_wd1601_w(uint32 address, uint32 data) +{ + int i; + + /* !TIME write16 0xA13002 = 0x3002 (00FFFE0C) */ + /* The board probably allows up to 256MB Flash ROM remapping but this game only has 4MB ROM chip */ + if ((address & 0xfe) == 0x02) + { + /* upper 2MB ROM mapped to $000000-$1fffff */ + for (i=0; i<0x20; i++) + { + m68k.memory_map[i].base = &cart.rom[(0x20 + i) << 16]; + } + + /* backup RAM (8KB) mapped to $2000000-$3fffff */ + for (i=0x20; i<0x40; i++) + { + m68k.memory_map[i].base = sram.sram; + m68k.memory_map[i].read8 = sram_read_byte; + m68k.memory_map[i].read16 = sram_read_word; + m68k.memory_map[i].write8 = sram_write_byte; + m68k.memory_map[i].write16 = sram_write_word; + zbank_memory_map[i].read = sram_read_byte; + zbank_memory_map[i].write = sram_write_byte; + } } } /* Custom ROM Bankswitch used in RADICA cartridges + +++++++++++++++++++++++++++++++++++++++++++++++ + Two different boards seem to exist (one with support for 64KB banks mapping and another one supporting 128KB banks + battery-RAM). + Radica Volume 1 requires 64KB banks mapping as the menu is located at a 64KB boundary. + Sensible Soccer Plus edition requires 128KB banks mapping with only VA6-VA2 being used to select bank index (VA1 is ignored). + Sensible Soccer Plus edition also requires 8KB backup RAM to be mapped in higher 2MB range. + Other games support both 64KB or 128KB mapping so it's not clear what exact board they are using but none require SRAM so we use 64KB mapper by default. + Note that Radica Volume 3 uses similar ROM mapping as Sensible Soccer Plus edition so it might be using same 128KB board, without any SRAM chip connected. */ -static uint32 mapper_radica_r(uint32 address) +static uint32 mapper_64k_radica_r(uint32 address) { int i = 0; - address = (address >> 1); /* 64 x 64k banks */ - for (i = 0; i < 64; i++) + /* + Volume 1 + -------- + 000000h-0fffffh: Kid Chameleon : !TIME read16 0xA13000 (00FF103A) + 100000h-1fffffh: Dr Robotnik's Mean Bean Machine : !TIME read16 0xA13020 (00FF101E) + 200000h-27ffffh: Sonic The Hedgehog : !TIME read16 0xA13040 (00FF101E) + 280000h-2fffffh: Golden Axe : !TIME read16 0xA13050 (00FF101E) + 300000h-37ffffh: Altered Beast : !TIME read16 0xA13060 (00FF101E) + 380000h-39ffffh: Flicky : !TIME read16 0xA13070 (00FF101E) + 3a0000h-3effffh: N/A : N/A + 3f0000h-3fffffh: Radica Menu (64 KB) : !TIME read16 0xA1307E (00FF1006) + + Volume 2 + -------- + 000000h-0fffffh: Sonic The Hedgehog 2 : !TIME read16 0xA13000 (00FF103A) + 100000h-1fffffh: The Ooze : !TIME read16 0xA13020 (00FF101E) + 200000h-2fffffh: Ecco The Dolphin : !TIME read16 0xA13040 (00FF101E) + 300000h-37ffffh: Gain Ground : !TIME read16 0xA13060 (00FF101E) + 380000h-3bffffh: Alex Kidd in Enchanted Castle : !TIME read16 0xA13070 (00FF101E) + 3c0000h-3dffffh: Columns : !TIME read16 0xA13078 (00FF101E) + 3e0000h-3fffffh: Radica Menu (128 KB) : !TIME read16 0xA1307C (00FF1006) + + Volume 3 - Super Sonic Gold edition + ----------------------------------- + 000000h-01ffffh: Radica Menu (128 KB) : N/A + 020000h-07ffffh: N/A : N/A + 080000h-0fffffh: Sonic The Hedgehog : !TIME read16 0xA13010 (00FF1012) + 100000h-1fffffh: Sonic The Hedgehog 2 : !TIME read16 0xA13020 (00FF1012) + 200000h-2fffffh: Sonic Spinball : !TIME read16 0xA13040 (00FF1012) + 300000h-3fffffh: Dr Robotnik's Mean Bean Machine : !TIME read16 0xA13060 (00FF1012) + + Street Fighter 2 CE edition + --------------------------- + 000000h-2fffffh: Street Fighter 2 CE : !TIME read16 0xA13000 (00FF103A) + 300000h-3bffffh: Ghouls'n Ghosts : !TIME read16 0xA13060 (00FF101E) + 3c0000h-3dffffh: Radica Menu (128 KB) : !TIME read16 0xA13078 (00FF1006) + 3e0000h-3fffffh: N/A : N/A + */ + int index = (address >> 1) & 0x3F; + + /* $000000-$3fffff area is mapped to selected banks (OR gates between VA21-VA16 and selected index) */ + for (i = 0x00; i < 0x40; i++) { - m68k.memory_map[i].base = &cart.rom[((address++)& 0x3f)<< 16]; + m68k.memory_map[i].base = &cart.rom[(index | i) << 16]; } return 0xffff; } +static uint32 mapper_128k_radica_r(uint32 address) +{ + int i = 0; + + /* 32 x 128k banks */ + /* + Sensible Soccer Plus edition + ---------------------------- + 000000h-01ffffh: Radica Menu (128 KB) : N/A + 020000h-07ffffh: N/A : N/A + 080000h-0fffffh: Sensible Soccer : !TIME read16 0xA13010 (00FF1012) + 100000h-1fffffh: Mega-Lo-Mania : !TIME read16 0xA13022 (00FF1012) + 200000h-37ffffh: Cannon Fodder : !TIME read16 0xA13042 (00FF1012) + 380000h-3fffffh: N/A : N/A + + Note: address bit 1 is ignored for bank selection but might be used to enable/disable SRAM mapping ? + */ + int index = (address >> 1) & 0x3E; + + /* $000000-$1fffff area is mapped to selected banks (OR gates between VA20-VA17 and selected index) */ + for (i = 0x00; i < 0x20; i++) + { + m68k.memory_map[i].base = &cart.rom[(index | i) << 16]; + } + + /* $200000-$3fffff area is mapped to 8KB SRAM (mirrored) */ + for (i = 0x20; i < 0x40; i++) + { + m68k.memory_map[i].base = sram.sram; + m68k.memory_map[i].read8 = sram_read_byte; + m68k.memory_map[i].read16 = sram_read_word; + m68k.memory_map[i].write8 = sram_write_byte; + m68k.memory_map[i].write16 = sram_write_word; + zbank_memory_map[i].read = sram_read_byte; + zbank_memory_map[i].write = sram_write_byte; + } + + return 0xffff; +} /************************************************************ default !TIME signal handler @@ -1571,15 +1801,22 @@ static uint32 mapper_radica_r(uint32 address) static void default_time_w(uint32 address, uint32 data) { - if (address < 0xa13040) + /* enable multi-game cartridge mapper by default */ + if (address < 0xa13060) { - /* unlicensed cartridges mapper (default) */ mapper_64k_multi_w(address); return; } - /* official cartridges mapper (default) */ - mapper_sega_w(data); + /* enable "official" cartridge mapper by default */ + if (address > 0xa130f1) + { + mapper_512k_w(address, data); + } + else + { + mapper_sega_w(data); + } }