From 9540bf1fe04ec76977862f60bdf6934146c4ad5a Mon Sep 17 00:00:00 2001 From: EkeEke Date: Tue, 6 Nov 2012 21:04:29 +0100 Subject: [PATCH 1/3] [SCD] incremented CD drive read latency: fixes Space Adventure Cobra (freeze when opening coffin at 2nd morgue scene) --- source/cd_hw/cdd.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/source/cd_hw/cdd.c b/source/cd_hw/cdd.c index 745a048..a73a75c 100644 --- a/source/cd_hw/cdd.c +++ b/source/cd_hw/cdd.c @@ -91,7 +91,7 @@ static const unsigned char waveHeader[32] = 0x44,0xac,0x00,0x00,0x10,0xb1,0x02,0x00,0x04,0x00,0x10,0x00,0x64,0x61,0x74,0x61 }; -/* supported file extensions */ +/* supported WAVE file extensions */ static const char extensions[10][16] = { "%02d.wav", @@ -1063,9 +1063,10 @@ void cdd_process(void) { /* Fixes a few games hanging during intro because they expect data to be read with some delay */ /* Wolf Team games (Anet Futatabi, Cobra Command, Road Avenger & Time Gal) need at least 6 interrupts delay */ - /* Radical Rex need at least one interrupt delay */ - /* Jeopardy need at least 9 interrupts delay (without counting seek time delay below )*/ - cdd.latency = 9; + /* Radical Rex needs at least one interrupt delay */ + /* Jeopardy needs at least 9 interrupts delay */ + /* Space Adventure Cobra (2nd morgue scene) needs at least 13 interrupts delay */ + cdd.latency = 13; } /* update current track index */ @@ -1161,7 +1162,7 @@ void cdd_process(void) /* no audio track playing */ scd.regs[0x36>>1].byte.h = 0x01; - /* update status (TODO: figure what is returned in RS1-RS8) */ + /* update status */ cdd.status = CD_READY; scd.regs[0x38>>1].w = CD_SEEK << 8; scd.regs[0x3a>>1].w = 0x0000; @@ -1176,7 +1177,7 @@ void cdd_process(void) /* no audio track playing */ scd.regs[0x36>>1].byte.h = 0x01; - /* update status (TODO: figure what is returned in RS1-RS8) */ + /* update status */ cdd.status = CD_READY; scd.regs[0x38>>1].w = CD_READY << 8; scd.regs[0x3a>>1].w = 0x0000; @@ -1203,7 +1204,7 @@ void cdd_process(void) cdd.scanOffset = CD_SCAN_SPEED; cdd.status = CD_SCAN; scd.regs[0x38>>1].w = (CD_SCAN << 8) | 0x02; - scd.regs[0x3a>>1].w = lut_BCD_16[cdd.index+1]; + scd.regs[0x3a>>1].w = (cdd.index < cdd.toc.last) ? lut_BCD_16[cdd.index + 1] : 0x0A0A; scd.regs[0x3c>>1].w = 0x0000; scd.regs[0x3e>>1].w = 0x0000; scd.regs[0x40>>1].byte.h = 0x00; @@ -1215,7 +1216,7 @@ void cdd_process(void) cdd.scanOffset = -CD_SCAN_SPEED; cdd.status = CD_SCAN; scd.regs[0x38>>1].w = (CD_SCAN << 8) | 0x02; - scd.regs[0x3a>>1].w = lut_BCD_16[cdd.index+1]; + scd.regs[0x3a>>1].w = (cdd.index < cdd.toc.last) ? lut_BCD_16[cdd.index + 1] : 0x0A0A; scd.regs[0x3c>>1].w = 0x0000; scd.regs[0x3e>>1].w = 0x0000; scd.regs[0x40>>1].byte.h = 0x00; From 5702eb2b8fe9c556c5c5e3d73e32fa4e62eadd9d Mon Sep 17 00:00:00 2001 From: EkeEke Date: Tue, 6 Nov 2012 21:29:13 +0100 Subject: [PATCH 2/3] [SCD] added default TOC for Shadow of the Beast II (prevent hangs when not using audio tracks) --- source/cd_hw/cdd.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/source/cd_hw/cdd.c b/source/cd_hw/cdd.c index a73a75c..da6025f 100644 --- a/source/cd_hw/cdd.c +++ b/source/cd_hw/cdd.c @@ -84,6 +84,12 @@ static const uint16 toc_lunar[52] = 685, 3167 }; +static const uint32 toc_shadow[15] = +{ + 10226, 70054, 11100, 12532, 12444, 11923, 10059, 10167, 10138, 13792, + 11637, 2547, 2521, 3856, 900 +}; + /* supported WAVE file header (16-bit stereo samples @44.1kHz) */ static const unsigned char waveHeader[32] = { @@ -595,7 +601,7 @@ int cdd_load(char *filename, char *header) /* Simulate audio tracks if none found */ if (cdd.toc.last == 1) { - /* Some games require specific TOC infos */ + /* Some games require exact TOC infos */ if (strstr(header + 0x180,"T-95035") != NULL) { /* Snatcher */ @@ -622,6 +628,19 @@ int cdd_load(char *filename, char *header) } while (cdd.toc.last < 52); } + else if (strstr(header + 0x180,"T-113045") != NULL) + { + /* Shadow of the Beast II */ + cdd.toc.last = cdd.toc.end = 0; + do + { + cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end; + cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_shadow[cdd.toc.last]; + cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end; + cdd.toc.last++; + } + while (cdd.toc.last < 15); + } else { /* default TOC (99 tracks & 2s per audio tracks) */ From 8d51460b1dc6f49bd4bad9bd53a22351d00b366f Mon Sep 17 00:00:00 2001 From: EkeEke Date: Tue, 6 Nov 2012 21:53:22 +0100 Subject: [PATCH 3/3] [MD] added Super Mario World 64 (unlicensed) cartridge hardware emulation --- source/cart_hw/md_cart.c | 201 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) diff --git a/source/cart_hw/md_cart.c b/source/cart_hw/md_cart.c index 8a2be24..eb9897d 100644 --- a/source/cart_hw/md_cart.c +++ b/source/cart_hw/md_cart.c @@ -67,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 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); static void mapper_seganet_w(uint32 address, uint32 data); static void mapper_32k_w(uint32 data); @@ -704,6 +706,38 @@ void md_cart_init(void) zbank_memory_map[i].write = zbank_unused_w; } } + else if ((*(uint16 *)(cart.rom + 0x08) == 0x6000) && (*(uint16 *)(cart.rom + 0x0a) == 0x01f6)) + { + /* Super Mario World 64 (unlicensed) mapper */ + for (i=0x08; i<0x10; i++) + { + /* lower 512KB mirrored */ + m68k.memory_map[i].base = cart.rom + ((i & 7) << 16); + } + + for (i=0x10; i<0x40; i++) + { + /* unused area */ + m68k.memory_map[i].read8 = m68k_read_bus_8; + m68k.memory_map[i].read16 = m68k_read_bus_16; + m68k.memory_map[i].write8 = m68k_unused_8_w; + m68k.memory_map[i].write16 = m68k_unused_16_w; + zbank_memory_map[i].read = m68k_read_bus_8; + zbank_memory_map[i].write = zbank_unused_w; + } + + for (i=0x60; i<0x70; i++) + { + /* custom hardware */ + m68k.memory_map[i].base = cart.rom + 0x0f0000; + m68k.memory_map[i].read8 = ((i & 0x07) < 0x04) ? NULL : mapper_smw_64_r; + m68k.memory_map[i].read16 = ((i & 0x07) < 0x04) ? NULL : mapper_smw_64_r; + m68k.memory_map[i].write8 = mapper_smw_64_w; + m68k.memory_map[i].write16 = mapper_smw_64_w; + zbank_memory_map[i].read = ((i & 0x07) < 0x04) ? NULL : mapper_smw_64_r; + zbank_memory_map[i].write = mapper_smw_64_w; + } + } else if (cart.romsize > 0x400000) { /* assume linear ROM mapper without bankswitching (max. 10MB) */ @@ -1271,6 +1305,173 @@ static uint32 mapper_t5740_r(uint32 address) return READ_BYTE(cart.rom, address); } +/* + Super Mario World 64 (unlicensed) mapper +*/ +static void mapper_smw_64_w(uint32 address, uint32 data) +{ + /* internal registers (saved to backup RAM) */ + switch ((address >> 16) & 0x07) + { + case 0x00: /* $60xxxx */ + { + if (address & 2) + { + /* $600003 data write mode ? */ + switch (sram.sram[0x00] & 0x07) + { + case 0x00: + { + /* update value returned at $660001-$660003 */ + sram.sram[0x06] = ((sram.sram[0x06] ^ sram.sram[0x01]) ^ data) & 0xFE; + break; + } + + case 0x01: + { + /* update value returned at $660005-$660007 */ + sram.sram[0x07] = data & 0xFE; + break; + } + + case 0x07: + { + /* update selected ROM bank (upper 512K) mapped at $610000-$61ffff */ + m68k.memory_map[0x61].base = m68k.memory_map[0x69].base = cart.rom + 0x080000 + ((data & 0x1c) << 14); + break; + } + + default: + { + /* unknown mode */ + break; + } + } + + /* $600003 data register */ + sram.sram[0x01] = data; + } + else + { + /* $600001 ctrl register */ + sram.sram[0x00] = data; + } + return; + } + + case 0x01: /* $61xxxx */ + { + if (address & 2) + { + /* $610003 ctrl register */ + sram.sram[0x02] = data; + } + return; + } + + case 0x04: /* $64xxxx */ + { + if (address & 2) + { + /* $640003 data register */ + sram.sram[0x04] = data; + } + else + { + /* $640001 data register */ + sram.sram[0x03] = data; + } + return; + } + + case 0x06: /* $66xxxx */ + { + /* unknown */ + return; + } + + case 0x07: /* $67xxxx */ + { + if (!(address & 2)) + { + /* $670001 ctrl register */ + sram.sram[0x05] = data; + + /* upper 512K ROM bank-switching enabled ? */ + if (sram.sram[0x02] & 0x80) + { + /* update selected ROM bank (upper 512K) mapped at $600000-$60ffff */ + m68k.memory_map[0x60].base = m68k.memory_map[0x68].base = cart.rom + 0x080000 + ((data & 0x1c) << 14); + } + } + return; + } + + default: /* not used */ + { + m68k_unused_8_w(address, data); + return; + } + } +} + +static uint32 mapper_smw_64_r(uint32 address) +{ + /* internal registers (saved to backup RAM) */ + switch ((address >> 16) & 0x03) + { + case 0x02: /* $66xxxx */ + { + switch ((address >> 1) & 7) + { + case 0x00: return sram.sram[0x06]; + case 0x01: return sram.sram[0x06] + 1; + case 0x02: return sram.sram[0x07]; + case 0x03: return sram.sram[0x07] + 1; + case 0x04: return sram.sram[0x08]; + case 0x05: return sram.sram[0x08] + 1; + case 0x06: return sram.sram[0x08] + 2; + case 0x07: return sram.sram[0x08] + 3; + } + } + + case 0x03: /* $67xxxx */ + { + uint8 data = (sram.sram[0x02] & 0x80) ? ((sram.sram[0x05] & 0x40) ? (sram.sram[0x03] & sram.sram[0x04]) : (sram.sram[0x03] ^ 0xFF)) : 0x00; + + if (address & 2) + { + /* $670003 */ + data &= 0x7f; + } + else + { + /* $66xxxx data registers update */ + if (sram.sram[0x05] & 0x80) + { + if (sram.sram[0x05] & 0x20) + { + /* update $660009-$66000f data register */ + sram.sram[0x08] = (sram.sram[0x04] << 2) & 0xFC; + } + else + { + /* update $660001-$660003 data register */ + sram.sram[0x06] = (sram.sram[0x01] ^ (sram.sram[0x03] << 1)) & 0xFE; + } + } + } + + return data; + } + + default: /* 64xxxx-$65xxxx */ + { + return 0x00; + } + } +} + /* Realtec ROM bankswitch (Earth Defend, Balloon Boy & Funny World, Whac-A-Critter) (Note: register usage is inverted in TascoDlx documentation)