Skip to content

Commit

Permalink
[Core/CD] improved robustness of CDD seeking delay emulation (fixes K…
Browse files Browse the repository at this point in the history
…rikzz's mcd-verificator CDC INIT endless loop following ekeeke@dd61951)
  • Loading branch information
ekeeke committed Sep 1, 2024
1 parent 7717557 commit a6002bb
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 66 deletions.
Binary file modified builds/genesis_plus_gx_libretro.dll
Binary file not shown.
Binary file modified builds/genplus_cube.dol
Binary file not shown.
Binary file modified builds/genplus_wii.dol
Binary file not shown.
155 changes: 89 additions & 66 deletions core/cd_hw/cdd.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@ void cdd_reset(void)
/* reset status */
cdd.status = cdd.loaded ? CD_TOC : NO_DISC;

/* reset pending flag */
cdd.pending = 0;

/* reset CD-DA fader (full volume) */
cdd.fader[0] = cdd.fader[1] = 0x400;

Expand All @@ -218,14 +221,18 @@ int cdd_context_save(uint8 *state)
{
int bufferptr = 0;
unsigned int offset = 0;
uint8 tmp8;

save_param(&cdd.cycles, sizeof(cdd.cycles));
save_param(&cdd.latency, sizeof(cdd.latency));
save_param(&cdd.index, sizeof(cdd.index));
save_param(&cdd.lba, sizeof(cdd.lba));
save_param(&cdd.scanOffset, sizeof(cdd.scanOffset));
save_param(&cdd.fader, sizeof(cdd.fader));
save_param(&cdd.status, sizeof(cdd.status));

/* 4-bit pending flag and 4-bit CDD status are saved together (to maintain backward savestate compatibility) */
tmp8 = cdd.status | (cdd.pending << 4);
save_param(&tmp8, sizeof(tmp8));

/* current track is an audio track ? */
if (cdd.toc.tracks[cdd.index].type == TYPE_AUDIO)
Expand Down Expand Up @@ -264,14 +271,19 @@ int cdd_context_load(uint8 *state, char *version)
{
unsigned int offset, lba, index;
int bufferptr = 0;
uint8 tmp8;

load_param(&cdd.cycles, sizeof(cdd.cycles));
load_param(&cdd.latency, sizeof(cdd.latency));
load_param(&index, sizeof(cdd.index));
load_param(&lba, sizeof(cdd.lba));
load_param(&cdd.scanOffset, sizeof(cdd.scanOffset));
load_param(&cdd.fader, sizeof(cdd.fader));
load_param(&cdd.status, sizeof(cdd.status));

/* 4-bit pending flag and 4-bit CDD status are saved together (to maintain backward savestate compatibility) */
load_param(&tmp8, sizeof(tmp8));
cdd.status = tmp8 & 0xf;
cdd.pending = tmp8 >> 4;

/* update current sector */
cdd.lba = lba;
Expand Down Expand Up @@ -1816,86 +1828,86 @@ void cdd_update(void)
{
/* CDC decoder is still running while disc is not being read (fixes MCD-verificator CDC Flags Test #30) */
cdc_decoder_update(0);
}

/* scanning disc */
if (cdd.status == CD_SCAN)
{
/* current track index */
int index = cdd.index;

/* fast-forward or fast-rewind */
cdd.lba += cdd.scanOffset;

/* check current track limits */
if (cdd.lba >= cdd.toc.tracks[index].end)
/* scanning disc */
if (cdd.status == CD_SCAN)
{
/* next track */
index++;
/* current track index */
int index = cdd.index;

/* fast-forward or fast-rewind */
cdd.lba += cdd.scanOffset;

/* check disc limits */
if (index < cdd.toc.last)
/* check current track limits */
if (cdd.lba >= cdd.toc.tracks[index].end)
{
/* skip directly to next track start position */
cdd.lba = cdd.toc.tracks[index].start;
/* next track */
index++;

/* check disc limits */
if (index < cdd.toc.last)
{
/* skip directly to next track start position */
cdd.lba = cdd.toc.tracks[index].start;
}
else
{
/* end of disc */
cdd.lba = cdd.toc.end;
cdd.index = cdd.toc.last;
cdd.status = CD_END;

/* no audio track playing */
scd.regs[0x36>>1].byte.h = 0x01;
return;
}
}
else
else if (cdd.lba < cdd.toc.tracks[index].start)
{
/* end of disc */
cdd.lba = cdd.toc.end;
cdd.index = cdd.toc.last;
cdd.status = CD_END;
/* check disc limits */
if (index > 0)
{
/* previous track */
index--;

/* no audio track playing */
scd.regs[0x36>>1].byte.h = 0x01;
return;
/* skip directly to previous track end position */
cdd.lba = cdd.toc.tracks[index].end;
}
else
{
/* start of first track */
cdd.lba = 0;
}
}
}
else if (cdd.lba < cdd.toc.tracks[index].start)
{
/* check disc limits */
if (index > 0)

/* seek to current subcode position */
if (cdd.toc.sub)
{
/* previous track */
index--;
cdStreamSeek(cdd.toc.sub, cdd.lba * 96, SEEK_SET);
}

/* current track is an audio track ? */
if (cdd.toc.tracks[index].type == TYPE_AUDIO)
{
/* seek to current track sector */
cdd_seek_audio(index, cdd.lba);

/* skip directly to previous track end position */
cdd.lba = cdd.toc.tracks[index].end;
/* audio track playing */
scd.regs[0x36>>1].byte.h = 0x00;
}
else
{
/* start of first track */
cdd.lba = 0;
/* no audio track playing */
scd.regs[0x36>>1].byte.h = 0x01;
}
}

/* seek to current subcode position */
if (cdd.toc.sub)
{
cdStreamSeek(cdd.toc.sub, cdd.lba * 96, SEEK_SET);
}

/* current track is an audio track ? */
if (cdd.toc.tracks[index].type == TYPE_AUDIO)
{
/* seek to current track sector */
cdd_seek_audio(index, cdd.lba);

/* audio track playing */
scd.regs[0x36>>1].byte.h = 0x00;
}
else
{
/* no audio track playing */
scd.regs[0x36>>1].byte.h = 0x01;
/* udpate current track index */
cdd.index = index;
}

/* udpate current track index */
cdd.index = index;
}

/* seeking should start with at least one interrupt delay (fixes Radical Rex incorrect PRG-RAM & Word-RAM initialization, causing missing sprites during intro) */
if (scd.regs[0x38>>1].byte.h == CD_SEEK)
/* check if seeking is pending */
if (cdd.pending)
{
/* reset track index */
int index = 0;
Expand Down Expand Up @@ -1963,8 +1975,11 @@ void cdd_update(void)
/* no audio track playing (yet) */
scd.regs[0x36>>1].byte.h = 0x01;

/* update CDD status to either PLAY or PAUSE depending on host command (will be reported to host once seeking has ended) */
cdd.status = scd.regs[0x42>>1].byte.h & 0x05;
/* update CDD status with pending end status (will be reported to host once seeking has ended) */
cdd.status = cdd.pending;

/* clear pending flag */
cdd.pending = 0;
}
}

Expand Down Expand Up @@ -2149,6 +2164,10 @@ void cdd_process(void)
scd.regs[0x3c>>1].w = 0x0000;
scd.regs[0x3e>>1].w = 0x0000;
scd.regs[0x40>>1].w = ~(CD_SEEK + 0x0f) & 0x0f;

/* seeking should start with at least one interrupt delay (fixes Radical Rex incorrect PRG-RAM & Word-RAM initialization, causing missing sprites during intro) */
/* so pending flag is set (with CDD end status) to indicate seeking is pending */
cdd.pending = CD_PLAY;
return;
}

Expand All @@ -2160,6 +2179,10 @@ void cdd_process(void)
scd.regs[0x3c>>1].w = 0x0000;
scd.regs[0x3e>>1].w = 0x0000;
scd.regs[0x40>>1].w = ~(CD_SEEK + 0x0f) & 0x0f;

/* seeking should start with at least one interrupt delay (same as 'Play' command) */
/* so pending flag is set (with CDD end status) to indicate seeking is pending */
cdd.pending = CD_PAUSE;
return;
}

Expand Down
1 change: 1 addition & 0 deletions core/cd_hw/cdd.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ typedef struct
int scanOffset;
uint16 fader[2];
uint8 status;
uint8 pending;
uint16 sectorSize;
toc_t toc;
#if defined(USE_LIBCHDR)
Expand Down

0 comments on commit a6002bb

Please sign in to comment.