diff --git a/HISTORY.txt b/HISTORY.txt index 518691629..78a938178 100644 --- a/HISTORY.txt +++ b/HISTORY.txt @@ -37,7 +37,8 @@ Genesis Plus GX 1.7.5 (xx/xx/xxxx) (Eke-Eke) * improved CDD status report accuracy (fixes track looping with Mode 1 patched games using MSU-MD driver) * improved Word-RAM byte access accuracy (verified on schematics) * improved GFX processing accuracy to halt it while Word RAM is allocated to Main CPU in 2M mode -* improved GFX timing accuracy (fixes "Night Striker" crashing after completing a game) +* improved GFX processing timing accuracy (fixes "Night Striker" crashing after completing a game) +* improved GFX processing robustness in case of word-RAM address overflow (fixes potential emulator crash in Flink level 20) * improved Sub-CPU BUSREQ status accuracy * disabled 68k and Z80 access to PRG-RAM when SUB-CPU is running (fixes "Dungeon Explorer") * disabled CD hardware reset on Soft-Reset (verified on real hardware) diff --git a/builds/genesis_plus_gx_libretro.dll b/builds/genesis_plus_gx_libretro.dll index 90e0dd412..32de916e2 100644 Binary files a/builds/genesis_plus_gx_libretro.dll and b/builds/genesis_plus_gx_libretro.dll differ diff --git a/builds/genplus_cube.dol b/builds/genplus_cube.dol index 12a21b17a..7e26b0329 100644 Binary files a/builds/genplus_cube.dol and b/builds/genplus_cube.dol differ diff --git a/builds/genplus_wii.dol b/builds/genplus_wii.dol index e0940a99e..d4a47526f 100644 Binary files a/builds/genplus_wii.dol and b/builds/genplus_wii.dol differ diff --git a/core/cart_hw/md_cart.c b/core/cart_hw/md_cart.c index a5fdb0f29..766289da1 100644 --- a/core/cart_hw/md_cart.c +++ b/core/cart_hw/md_cart.c @@ -224,7 +224,8 @@ static const md_entry_t rom_database[] = {0x0000,0x19ff,0x40,0x40,{{0x63,0x98,0xc9,0x18},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,m68k_unused_8_w,default_regs_r,NULL}}, /* Soul Blade */ {0x0000,0x0c5b,0x40,0x40,{{0x63,0x98,0xc9,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,m68k_unused_8_w,default_regs_r,NULL}}, - +/* Shi San Zhang Ma Jiang: Zhong Guo Mei Nv Pian (only $400004 is checked, other addresses/values are assumed) */ + {0xffff,0xd41d,0x40,0x40,{{0x63,0x98,0xc9,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,m68k_unused_8_w,default_regs_r,NULL}}, /* King of Fighter 98 */ {0x0000,0xd0a0,0x48,0x4f,{{0x00,0x00,0xaa,0xf0},{0xffffff,0xffffff,0xfc0000,0xfc0000},{0x000000,0x000000,0x480000,0x4c0000},0,0,NULL,m68k_unused_8_w,default_regs_r,NULL}}, diff --git a/core/cd_hw/cdd.c b/core/cd_hw/cdd.c index cc5e65dbf..73ead1a16 100644 --- a/core/cd_hw/cdd.c +++ b/core/cd_hw/cdd.c @@ -209,6 +209,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; @@ -220,6 +223,7 @@ 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)); @@ -227,7 +231,10 @@ int cdd_context_save(uint8 *state) 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) @@ -266,6 +273,7 @@ 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)); @@ -273,7 +281,11 @@ int cdd_context_load(uint8 *state, char *version) 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; @@ -1869,86 +1881,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; @@ -2016,8 +2028,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; } } @@ -2202,6 +2217,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; } @@ -2213,6 +2232,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; } diff --git a/core/cd_hw/cdd.h b/core/cd_hw/cdd.h index f2f780026..4c2ba5cc8 100644 --- a/core/cd_hw/cdd.h +++ b/core/cd_hw/cdd.h @@ -117,6 +117,7 @@ typedef struct int scanOffset; uint16 fader[2]; uint8 status; + uint8 pending; uint16 sectorSize; toc_t toc; #if defined(USE_LIBCHDR) diff --git a/core/cd_hw/gfx.c b/core/cd_hw/gfx.c index 85600e354..9221f508c 100644 --- a/core/cd_hw/gfx.c +++ b/core/cd_hw/gfx.c @@ -455,9 +455,11 @@ int gfx_context_load(uint8 *state) load_param(&gfx.bufferStart, sizeof(gfx.bufferStart)); load_param(&tmp32, 4); + tmp32 &= 0x3fff8; gfx.tracePtr = (uint16 *)(scd.word_ram_2M + tmp32); load_param(&tmp32, 4); + tmp32 &= ~((1 << ((2*gfx.mapShift) + 1)) - 1) & 0x3ffff; gfx.mapPtr = (uint16 *)(scd.word_ram_2M + tmp32); return bufferptr; @@ -480,6 +482,12 @@ INLINE void gfx_render(uint32 bufferIndex, uint32 width) uint32 xoffset = (int16) *gfx.tracePtr++; uint32 yoffset = (int16) *gfx.tracePtr++; + /* handle trace vector address overflow */ + if (gfx.tracePtr == (uint16 *)(scd.word_ram_2M + 0x40000)) + { + gfx.tracePtr = (uint16 *)(scd.word_ram_2M); + } + /* process all dots */ while (width--) { @@ -557,7 +565,7 @@ INLINE void gfx_render(uint32 bufferIndex, uint32 width) } /* read out paired pixel data */ - pixel_in = READ_BYTE(scd.word_ram_2M, bufferIndex >> 1); + pixel_in = READ_BYTE(scd.word_ram_2M, (bufferIndex >> 1) & 0x3ffff); /* update left or rigth pixel */ if (bufferIndex & 1) @@ -573,7 +581,7 @@ INLINE void gfx_render(uint32 bufferIndex, uint32 width) pixel_out = gfx.lut_prio[(scd.regs[0x02>>1].w >> 3) & 0x03][pixel_in][pixel_out]; /* write data to image buffer */ - WRITE_BYTE(scd.word_ram_2M, bufferIndex >> 1, pixel_out); + WRITE_BYTE(scd.word_ram_2M, (bufferIndex >> 1) & 0x3ffff, pixel_out); /* check current pixel position */ if ((bufferIndex & 7) != 7) @@ -657,7 +665,7 @@ void gfx_start(unsigned int base, int cycles) /* reference: https://github.com/MiSTer-devel/MegaCD_MiSTer/blob/master/docs/mcd%20logs/graphics_operations_and_68k_wordram_access.jpg */ /* TODO: figure what happen exactly when pixel offset is different from 0 */ /* for the moment, one additional read-modify-write access is assumed at the start if pixel offset is not aligned to 4 pixels */ - gfx.cyclesPerLine = 4 * 3 * (4 + 2 * scd.regs[0x62>>1].w + ((scd.regs[0x62>>1].w + (scd.regs[0x60>>1].byte.l & 0x03) + 3) >> 2)); + gfx.cyclesPerLine = 4 * 3 * (4 + 2 * (scd.regs[0x62>>1].w & 0x1ff) + (((scd.regs[0x62>>1].w & 0x1ff) + (scd.regs[0x60>>1].byte.l & 0x03) + 3) >> 2)); /* start graphics operation */ scd.regs[0x58>>1].byte.h = 0x80; @@ -731,7 +739,7 @@ void gfx_update(int cycles) while (lines--) { /* process dots to image buffer */ - gfx_render(gfx.bufferStart, scd.regs[0x62>>1].w); + gfx_render(gfx.bufferStart, scd.regs[0x62>>1].w & 0x1ff); /* increment image buffer start index for next line (8 pixels/line) */ gfx.bufferStart += 8;