diff --git a/source/cd_hw/cdd.c b/source/cd_hw/cdd.c index ab48442..e61b9f3 100644 --- a/source/cd_hw/cdd.c +++ b/source/cd_hw/cdd.c @@ -90,6 +90,26 @@ static const uint32 toc_shadow[15] = 11637, 2547, 2521, 3856, 900 }; +static const uint32 toc_dungeon[13] = +{ + 2250, 22950, 16350, 24900, 13875, 19950, 13800, 15375, 17400, 17100, + 3325, 6825, 25275 +}; + +static const uint32 toc_ffight[26] = +{ + 11994, 9742, 10136, 9685, 9553, 14588, 9430, 8721, 9975, 9764, + 9704, 12796, 585, 754, 951, 624, 9047, 1068, 817, 9191, 1024, + 14562, 10320, 8627, 3795, 3047 +}; + +static const uint32 toc_ffightj[29] = +{ + 11994, 9752, 10119, 9690, 9567, 14575, 9431, 8731, 9965, 9763, + 9716, 12791, 579, 751, 958, 630, 9050, 1052, 825, 9193, 1026, + 14553, 9834, 10542, 1699, 1792, 1781, 3783, 3052 +}; + /* supported WAVE file header (16-bit stereo samples @44.1kHz) */ static const unsigned char waveHeader[32] = { @@ -641,6 +661,45 @@ int cdd_load(char *filename, char *header) } while (cdd.toc.last < 15); } + else if (strstr(header + 0x180,"T-143025") != NULL) + { + /* Dungeon Explorer */ + 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_dungeon[cdd.toc.last]; + cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end; + cdd.toc.last++; + } + while (cdd.toc.last < 13); + } + else if (strstr(header + 0x180,"MK-4410") != NULL) + { + /* Final Fight CD (USA, Europe) */ + 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_ffight[cdd.toc.last]; + cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end; + cdd.toc.last++; + } + while (cdd.toc.last < 26); + } + else if (strstr(header + 0x180,"G-6013") != NULL) + { + /* Final Fight CD (Japan) */ + 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_ffightj[cdd.toc.last]; + cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end; + cdd.toc.last++; + } + while (cdd.toc.last < 29); + } else { /* default TOC (99 tracks & 2s per audio tracks) */ @@ -1081,11 +1140,24 @@ void cdd_process(void) if (!cdd.latency) { /* 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 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; + /* Wolf Team games (Anet Futatabi, Cobra Command, Road Avenger & Time Gal) need at least 6 interrupts delay */ + /* Space Adventure Cobra (2nd morgue scene) needs at least 13 interrupts delay (incl. seek time, so 6 here is OK) */ + /* Jeopardy & ESPN Sunday Night NFL are picky about this as well: 7 interrupts delay (+ seek time) seems OK */ + cdd.latency = 7; + } + + /* CD drive seek time */ + /* Some delay is especially needed when playing audio tracks located at the end of the disc (ex: Sonic CD intro) */ + /* max. seek time = 1.5s = 1.5 x 75 = 112.5 CDD interrupts (rounded to 120) for 270000 sectors max on disc */ + /* Note: this is only a rough approximation, on real hardware, drive seek time is much likely not linear */ + if (lba < cdd.lba) + { + cdd.latency += (((cdd.lba - lba) * 120) / 270000); + } + else + { + cdd.latency += (((lba - cdd.lba) * 120) / 270000); } /* update current track index */ @@ -1110,19 +1182,6 @@ void cdd_process(void) } else if (cdd.toc.tracks[index].fd) { - /* CD drive seek time */ - /* Some delay is also needed when playing AUDIO tracks located at the end of the disc (ex: Sonic CD intro) */ - /* max. seek time = 1.5s = 1.5 x 75 = 112.5 CDD interrupts (rounded to 120) for 270000 sectors max on disc */ - /* Note: this is only a rough approximation, on real hardware, drive seek time is much likely not linear */ - if (lba < cdd.lba) - { - cdd.latency += (((cdd.lba - lba) * 120) / 270000); - } - else - { - cdd.latency += (((lba - cdd.lba) * 120) / 270000); - } - /* seek AUDIO track */ if (lba < cdd.toc.tracks[index].start) { diff --git a/source/cd_hw/scd.c b/source/cd_hw/scd.c index 91d6085..47ed230 100644 --- a/source/cd_hw/scd.c +++ b/source/cd_hw/scd.c @@ -212,7 +212,7 @@ static void s68k_poll_detect(reg) } /* restart SUB-CPU polling detection */ - s68k.poll.cycle = s68k.cycles + 320; + s68k.poll.cycle = s68k.cycles + 392; s68k.poll.pc = s68k.pc; } @@ -412,7 +412,7 @@ static unsigned int scd_read_word(unsigned int address) /* relative MAIN-CPU cycle counter */ unsigned int cycles = (s68k.cycles * MCYCLES_PER_LINE) / SCYCLES_PER_LINE; - /* sync MAIN-CPU with SUB-CPU */ + /* sync MAIN-CPU with SUB-CPU (Mighty Morphin Power Rangers) */ if (!m68k.stopped && (m68k.cycles < cycles)) { m68k_run(cycles); @@ -1062,7 +1062,7 @@ void scd_init(void) { if (i & 2) { - /* PRG-RAM (first 128KB bank, mirrored) */ + /* $020000-$03FFFF (resp. $420000-$43FFFF): PRG-RAM (first 128KB bank, mirrored each 256KB) */ m68k.memory_map[i].base = scd.prg_ram + ((i & 1) << 16); m68k.memory_map[i].read8 = NULL; m68k.memory_map[i].read16 = NULL; @@ -1074,7 +1074,8 @@ void scd_init(void) } else { - /* internal ROM (128KB mirrored) (Flux expects it to be mapped at $440000-$45FFFF) */ + /* $000000-$01FFFF (resp. $400000-$41FFFF): internal ROM (128KB, mirrored each 256KB) */ + /* NB: Flux expects it to be mapped at $440000-$45FFFF */ m68k.memory_map[i].base = scd.bootrom + ((i & 1) << 16); m68k.memory_map[i].read8 = NULL; m68k.memory_map[i].read16 = NULL; @@ -1116,7 +1117,6 @@ void scd_init(void) /* $080000-$0BFFFF: Word-RAM in 2M mode (256KB)*/ for (i=0x08; i<0x0c; i++) { - /* allow Word-RAM access from both CPU in 2M mode (fixes sync issues in Mortal Kombat) */ s68k.memory_map[i].base = scd.word_ram_2M + ((i & 3) << 16); s68k.memory_map[i].read8 = NULL; s68k.memory_map[i].read16 = NULL; @@ -1167,6 +1167,8 @@ void scd_reset(int hard) /* TODO: figure what exactly is resetted when RESET bit is cleared by SUB-CPU */ if (hard) { + int i; + /* Clear all ASIC registers by default */ memset(scd.regs, 0, sizeof(scd.regs)); @@ -1183,6 +1185,14 @@ void scd_reset(int hard) /* 2M mode */ word_ram_switch(0); + + /* reset PRG-RAM banking on MAIN-CPU side */ + for (i=scd.cartridge.boot+0x02; i>16)&0xff].base, (address) & 0xffff); } @@ -238,6 +238,13 @@ static void m68k_poll_detect(reg) #endif m68k.cycles = m68k.cycle_end; m68k.stopped = 1 << reg; + + /* return to current instruction */ + do + { + m68k.pc -= 2; + } + while (m68k.ir != *(uint16 *)(m68k.memory_map[(m68k.pc>>16)&0xff].base + (m68k.pc & 0xffff))); } return; } @@ -249,7 +256,7 @@ static void m68k_poll_detect(reg) } /* restart MAIN-CPU polling detection */ - m68k.poll.cycle = m68k.cycles + 280; + m68k.poll.cycle = m68k.cycles + 840; m68k.poll.pc = m68k.pc; } @@ -335,6 +342,15 @@ unsigned int ctrl_io_read_byte(unsigned int address) /* SUB-CPU communication flags */ if (index == 0x0f) { + /* relative SUB-CPU cycle counter */ + unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; + + /* sync SUB-CPU with MAIN-CPU (Dracula Unleashed w/ Sega CD Model 2 OS ROM) */ + if (!s68k.stopped && (s68k.cycles < cycles)) + { + s68k_run(cycles); + } + m68k_poll_detect(0x0f); return scd.regs[0x0f>>1].byte.l; }