From fe8f2d963e684a275a4a828fa0dfe65c39681799 Mon Sep 17 00:00:00 2001 From: kub Date: Tue, 20 Dec 2022 21:32:24 +0000 Subject: [PATCH] 32x, hacks for roms with caching related problems --- cpu/sh2/compiler.c | 12 ++---------- pico/32x/memory.c | 14 ++++++++++++-- pico/32x/sh2soc.c | 10 +--------- pico/cart.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ pico/carthw.cfg | 30 ++++++++++++++++++++++++------ pico/pico.h | 5 ++++- pico/pico_int.h | 1 + 7 files changed, 89 insertions(+), 28 deletions(-) diff --git a/cpu/sh2/compiler.c b/cpu/sh2/compiler.c index 360fcd03..76f6cd65 100644 --- a/cpu/sh2/compiler.c +++ b/cpu/sh2/compiler.c @@ -537,12 +537,6 @@ void REGPARM(1) (*sh2_drc_restore_sr)(SH2 *sh2); #define MF_POLLING 0x20 // include polling check in read // address space stuff -static int dr_is_rom(u32 a) -{ - // tweak for WWF Raw which writes data to some high ROM addresses - return (a & 0xc6000000) == 0x02000000 && (a & 0x3f0000) < 0x3e0000; -} - static int dr_ctx_get_mem_ptr(SH2 *sh2, u32 a, u32 *mask) { void *memptr; @@ -2698,7 +2692,7 @@ static int emit_get_rom_data(SH2 *sh2, sh2_reg_e r, s32 offs, int size, u32 *val if (gconst_get(r, &a)) { a += offs; // check if rom is memory mapped (not bank switched), and address is in rom - if (dr_is_rom(a) && p32x_sh2_get_mem_ptr(a, &mask, sh2) == sh2->p_rom) { + if (p32x_sh2_mem_is_rom(a, sh2) && p32x_sh2_get_mem_ptr(a, &mask, sh2) == sh2->p_rom) { switch (size & MF_SIZEMASK) { case 0: *val = (s8)p32x_sh2_read8(a, sh2s); break; // 8 case 1: *val = (s16)p32x_sh2_read16(a, sh2s); break; // 16 @@ -3830,14 +3824,12 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id) case OP_LOAD_POOL: #if PROPAGATE_CONSTANTS if ((opd->imm && opd->imm >= base_pc && opd->imm < end_literals) || - dr_is_rom(opd->imm)) + p32x_sh2_mem_is_rom(opd->imm, sh2)) { if (opd->size == 2) u = FETCH32(opd->imm); else u = (s16)FETCH_OP(opd->imm); - // tweak for Blackthorne: avoid stack overwriting - if (GET_Rn() == SHR_SP && u == 0x0603f800) u = 0x0603f900; gconst_new(GET_Rn(), u); } else diff --git a/pico/32x/memory.c b/pico/32x/memory.c index 7a61e89e..62c31227 100644 --- a/pico/32x/memory.c +++ b/pico/32x/memory.c @@ -816,7 +816,7 @@ static void p32x_sh2reg_write8(u32 a, u32 d, SH2 *sh2) Pico32x.sh2_regs[0] &= ~0x80; Pico32x.sh2_regs[0] |= d & 0x80; - if ((d ^ old) & 1) + if ((old ^ d) & 1) p32x_pwm_schedule_sh2(sh2); if ((old ^ d) & 2) p32x_update_cmd_irq(sh2, 0); @@ -1776,7 +1776,7 @@ static void REGPARM(3) sh2_write16_rom(u32 a, u32 d, SH2 *sh2) // Presumably the write goes to the CPU cache and is read back from there, // but it would be extremely costly to emulate cache behaviour. Just allow // writes to that region, hoping that the original ROM values are never used. - if ((a1 & 0x3e0000) == 0x3e0000) + if ((a1 & 0x3e0000) == 0x3e0000 && (PicoIn.quirks & PQUIRK_WWFRAW_HACK)) ((u16 *)sh2->p_rom)[a1 / 2] = d; else sh2_write16_unmapped(a, d, sh2); @@ -1951,6 +1951,16 @@ void *p32x_sh2_get_mem_ptr(u32 a, u32 *mask, SH2 *sh2) return ret; } +int p32x_sh2_mem_is_rom(u32 a, SH2 *sh2) +{ + if ((a & 0xc6000000) == 0x02000000) { + // ROM, but mind tweak for WWF Raw + return !(PicoIn.quirks & PQUIRK_WWFRAW_HACK) || (a & 0x3f0000) < 0x3e0000; + } + + return 0; +} + int p32x_sh2_memcpy(u32 dst, u32 src, int count, int size, SH2 *sh2) { u32 mask; diff --git a/pico/32x/sh2soc.c b/pico/32x/sh2soc.c index f8bb4e79..0336b872 100644 --- a/pico/32x/sh2soc.c +++ b/pico/32x/sh2soc.c @@ -137,15 +137,7 @@ static void dmac_memcpy(struct dma_chan *chan, SH2 *sh2) if (!up || chan->tcr < 4) return; -#if MARS_CHECK_HACK - // XXX Mars Check Program copies 32K longwords (128KB) from a 64KB buffer in - // ROM or DRAM to SDRAM in 4-longword mode, overwriting an SDRAM comm area in - // turn, which crashes the test on emulators without CPU cache emulation. - // This may be a bug in Mars Check. As a kludge limit the transfer to 64KB, - // which is what the check program test uses for checking the result. - // A better way would clearly be to have a mechanism to patch the ROM... - if (size == 3 && chan->tcr == 32768 && chan->dar == 0x06020000) size = 1; -#endif + if (size == 3) size = 2; // 4-word xfer mode still counts in words // XXX check TCR being a multiple of 4 in 4-word xfer mode? // XXX check alignment of sar/dar, generating a bus error if unaligned? diff --git a/pico/cart.c b/pico/cart.c index 8f9b6201..dad850b5 100644 --- a/pico/cart.c +++ b/pico/cart.c @@ -1201,6 +1201,12 @@ static void parse_carthw(const char *carthw_cfg, int *fill_sram, Pico.sv.flags &= ~SRF_EEPROM; else if (strcmp(p, "filled_sram") == 0) *fill_sram = 1; + else if (strcmp(p, "wwfraw_hack") == 0) + PicoIn.quirks |= PQUIRK_WWFRAW_HACK; + else if (strcmp(p, "blackthorne_hack") == 0) + PicoIn.quirks |= PQUIRK_BLACKTHORNE_HACK; + else if (strcmp(p, "marscheck_hack") == 0) + PicoIn.quirks |= PQUIRK_MARSCHECK_HACK; else if (strcmp(p, "force_6btn") == 0) PicoIn.quirks |= PQUIRK_FORCE_6BTN; else { @@ -1335,6 +1341,45 @@ static void PicoCartDetect(const char *carthw_cfg) // Unusual region 'code' if (rom_strcmp(0x1f0, "EUROPE") == 0 || rom_strcmp(0x1f0, "Europe") == 0) *(u32 *) (Pico.rom + 0x1f0) = CPU_LE4(0x20204520); + + // tweak for Blackthorne: master SH2 overwrites stack of slave SH2 being in PWM + // interrupt. On real hardware, nothing happens since slave fetches the values + // it has written from its cache, but picodrive doesn't emulate caching. + // move master memory area down by 0x100 bytes. + // XXX replace this abominable hack. It might cause other problems in the game! + if (PicoIn.quirks & PQUIRK_BLACKTHORNE_HACK) { + int i; + unsigned a = 0; + for (i = 0; i < Pico.romsize; i += 4) { + unsigned v = CPU_BE2(*(u32 *) (Pico.rom + i)); + if (a && v == a + 0x400) { // patch if 2 pointers with offset 0x400 are found + printf("auto-patching @%06x: %08x->%08x\n", i, v, v - 0x100); + *(u32 *) (Pico.rom + i) = CPU_BE2(v - 0x100); + } + // detect a pointer into the incriminating area + a = 0; + if (v >> 12 == 0x0603f000 >> 12 && !(v & 3)) + a = v; + } + } + + // tweak for Mars Check Program: copies 32K longwords (128KB) from a 64KB buffer + // in ROM or DRAM to SDRAM with DMA in 4-longword mode, overwriting an SDRAM comm + // area in turn. This crashes the test on emulators without CPU cache emulation. + // This may be a bug in Mars Check, since it's only checking for the 64KB result. + // Patch the DMA transfers so that they transfer only 64KB. + if (PicoIn.quirks & PQUIRK_MARSCHECK_HACK) { + int i; + unsigned a = 0; + for (i = 0; i < Pico.romsize; i += 4) { + unsigned v = CPU_BE2(*(u32 *) (Pico.rom + i)); + if (a == 0xffffff8c && v == 0x5ee1) { // patch if 4-long xfer written to CHCR + printf("auto-patching @%06x: %08x->%08x\n", i, v, v & ~0x800); + *(u32 *) (Pico.rom + i) = CPU_BE2(v & ~0x800); // change to half-sized xfer + } + a = v; + } + } } static void PicoCartDetectMS(void) diff --git a/pico/carthw.cfg b/pico/carthw.cfg index 964efb47..ef507949 100644 --- a/pico/carthw.cfg +++ b/pico/carthw.cfg @@ -52,6 +52,30 @@ hw = pico check_str = 0x100, "IMA IKUNO" hw = pico +# X-Men proto +[X-Men (prototype) - 32X] +check_str = 0x120, "32X SAMPLE PROGRAM" +check_str = 0x32b74c, "Bishop Level" +prop = force_6btn + +# WWF Raw +[WWF Raw - 32X] +check_str = 0x100, "SEGA 32X" +check_str = 0x150, "WWF RAW" +prop = wwfraw_hack # reads back data written to high ROM adresses from cache + +# Blackthorne +[Blackthorne - 32X] +check_str = 0x100, "SEGA 32X" +check_str = 0x120, "BLACKTHORNE" +prop = blackthorne_hack # reads back data overwritten by 2nd CPU from cache + +# Mars check program +[Mars Check - 32X] +check_str = 0x100, "SEGA" +check_str = 0x150, "MARS CHECK PROGRAM" +prop = marscheck_hack # reads back data overwritten by DMA from cache + # sram emulation triggers some protection for this one [Puggsy] check_str = 0x120, "PUGGSY" @@ -71,12 +95,6 @@ prop = filled_sram check_str = 0x150, " HardBall III" sram_range = 0x200000,0x20ffff -# X-Men proto -[X-Men (prototype)] -check_str = 0x150, "32X SAMPLE PROGRAM" -check_str = 0x32b74c, "Bishop Level" -prop = force_6btn - # The SSF2 mapper [Mega Everdrive] check_str = 0x100, "SEGA SSF" diff --git a/pico/pico.h b/pico/pico.h index cb4ebb54..6882faa5 100644 --- a/pico/pico.h +++ b/pico/pico.h @@ -89,7 +89,10 @@ extern void *p32x_bios_g, *p32x_bios_m, *p32x_bios_s; #define PHWS_SMS 2 #define PHWS_SG 3 -#define PQUIRK_FORCE_6BTN (1<<0) +#define PQUIRK_FORCE_6BTN (1<<0) +#define PQUIRK_BLACKTHORNE_HACK (1<<1) +#define PQUIRK_WWFRAW_HACK (1<<2) +#define PQUIRK_MARSCHECK_HACK (1<<3) // the emulator is configured and some status is reported // through this global state (not saved in savestates) diff --git a/pico/pico_int.h b/pico/pico_int.h index 0406dd50..55fb5ae6 100644 --- a/pico/pico_int.h +++ b/pico/pico_int.h @@ -1017,6 +1017,7 @@ u32 REGPARM(3) p32x_sh2_poll_memory8(u32 a, u32 d, SH2 *sh2); u32 REGPARM(3) p32x_sh2_poll_memory16(u32 a, u32 d, SH2 *sh2); u32 REGPARM(3) p32x_sh2_poll_memory32(u32 a, u32 d, SH2 *sh2); void *p32x_sh2_get_mem_ptr(u32 a, u32 *mask, SH2 *sh2); +int p32x_sh2_mem_is_rom(u32 a, SH2 *sh2); void p32x_sh2_poll_detect(u32 a, SH2 *sh2, u32 flags, int maxcnt); void p32x_sh2_poll_event(SH2 *sh2, u32 flags, u32 m68k_cycles); int p32x_sh2_memcpy(u32 dst, u32 src, int count, int size, SH2 *sh2); -- 2.39.2