[Core/CD]

.added build-in TOC support for a few games that hang if no audio tracks are
found or used
.modified CD access/seek time emulation
.improved CPU polling detection
.improved SUB & MAIN-CPU synchronization (fixes Dracula Unleashed when using
Model 2 US BIOS)
.added missing reinitialization of MAIN-CPU PRG-RAM bank on reset
This commit is contained in:
EkeEke 2013-04-19 16:55:52 +02:00
parent c9fb127730
commit 325f6dd5a7
3 changed files with 109 additions and 24 deletions

View File

@ -90,6 +90,26 @@ static const uint32 toc_shadow[15] =
11637, 2547, 2521, 3856, 900 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) */ /* supported WAVE file header (16-bit stereo samples @44.1kHz) */
static const unsigned char waveHeader[32] = static const unsigned char waveHeader[32] =
{ {
@ -641,6 +661,45 @@ int cdd_load(char *filename, char *header)
} }
while (cdd.toc.last < 15); 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 else
{ {
/* default TOC (99 tracks & 2s per audio tracks) */ /* default TOC (99 tracks & 2s per audio tracks) */
@ -1081,11 +1140,24 @@ void cdd_process(void)
if (!cdd.latency) if (!cdd.latency)
{ {
/* Fixes a few games hanging during intro because they expect data to be read with some delay */ /* 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 */ /* Radical Rex needs at least one interrupt delay */
/* Jeopardy needs at least 9 interrupts delay */ /* 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 */ /* Space Adventure Cobra (2nd morgue scene) needs at least 13 interrupts delay (incl. seek time, so 6 here is OK) */
cdd.latency = 13; /* 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 */ /* update current track index */
@ -1110,19 +1182,6 @@ void cdd_process(void)
} }
else if (cdd.toc.tracks[index].fd) 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 */ /* seek AUDIO track */
if (lba < cdd.toc.tracks[index].start) if (lba < cdd.toc.tracks[index].start)
{ {

View File

@ -212,7 +212,7 @@ static void s68k_poll_detect(reg)
} }
/* restart SUB-CPU polling detection */ /* restart SUB-CPU polling detection */
s68k.poll.cycle = s68k.cycles + 320; s68k.poll.cycle = s68k.cycles + 392;
s68k.poll.pc = s68k.pc; s68k.poll.pc = s68k.pc;
} }
@ -412,7 +412,7 @@ static unsigned int scd_read_word(unsigned int address)
/* relative MAIN-CPU cycle counter */ /* relative MAIN-CPU cycle counter */
unsigned int cycles = (s68k.cycles * MCYCLES_PER_LINE) / SCYCLES_PER_LINE; 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)) if (!m68k.stopped && (m68k.cycles < cycles))
{ {
m68k_run(cycles); m68k_run(cycles);
@ -1062,7 +1062,7 @@ void scd_init(void)
{ {
if (i & 2) 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].base = scd.prg_ram + ((i & 1) << 16);
m68k.memory_map[i].read8 = NULL; m68k.memory_map[i].read8 = NULL;
m68k.memory_map[i].read16 = NULL; m68k.memory_map[i].read16 = NULL;
@ -1074,7 +1074,8 @@ void scd_init(void)
} }
else 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].base = scd.bootrom + ((i & 1) << 16);
m68k.memory_map[i].read8 = NULL; m68k.memory_map[i].read8 = NULL;
m68k.memory_map[i].read16 = NULL; m68k.memory_map[i].read16 = NULL;
@ -1116,7 +1117,6 @@ void scd_init(void)
/* $080000-$0BFFFF: Word-RAM in 2M mode (256KB)*/ /* $080000-$0BFFFF: Word-RAM in 2M mode (256KB)*/
for (i=0x08; i<0x0c; i++) 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].base = scd.word_ram_2M + ((i & 3) << 16);
s68k.memory_map[i].read8 = NULL; s68k.memory_map[i].read8 = NULL;
s68k.memory_map[i].read16 = 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 */ /* TODO: figure what exactly is resetted when RESET bit is cleared by SUB-CPU */
if (hard) if (hard)
{ {
int i;
/* Clear all ASIC registers by default */ /* Clear all ASIC registers by default */
memset(scd.regs, 0, sizeof(scd.regs)); memset(scd.regs, 0, sizeof(scd.regs));
@ -1183,6 +1185,14 @@ void scd_reset(int hard)
/* 2M mode */ /* 2M mode */
word_ram_switch(0); word_ram_switch(0);
/* reset PRG-RAM banking on MAIN-CPU side */
for (i=scd.cartridge.boot+0x02; i<scd.cartridge.boot+0x20; i+=4)
{
/* MAIN-CPU: $020000-$03FFFF (resp. $420000-$43FFFF) mapped to first 128KB PRG-RAM bank (mirrored each 256KB) */
m68k.memory_map[i].base = scd.prg_ram;
m68k.memory_map[i+1].base = scd.prg_ram + 0x10000;
}
} }
else else
{ {

View File

@ -238,6 +238,13 @@ static void m68k_poll_detect(reg)
#endif #endif
m68k.cycles = m68k.cycle_end; m68k.cycles = m68k.cycle_end;
m68k.stopped = 1 << reg; 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; return;
} }
@ -249,7 +256,7 @@ static void m68k_poll_detect(reg)
} }
/* restart MAIN-CPU polling detection */ /* restart MAIN-CPU polling detection */
m68k.poll.cycle = m68k.cycles + 280; m68k.poll.cycle = m68k.cycles + 840;
m68k.poll.pc = m68k.pc; m68k.poll.pc = m68k.pc;
} }
@ -335,6 +342,15 @@ unsigned int ctrl_io_read_byte(unsigned int address)
/* SUB-CPU communication flags */ /* SUB-CPU communication flags */
if (index == 0x0f) 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); m68k_poll_detect(0x0f);
return scd.regs[0x0f>>1].byte.l; return scd.regs[0x0f>>1].byte.l;
} }