32x, hacks for roms with caching related problems

This commit is contained in:
kub 2022-12-20 21:32:24 +00:00
parent ebd9c86a6c
commit fe8f2d963e
7 changed files with 89 additions and 28 deletions

View file

@ -537,12 +537,6 @@ void REGPARM(1) (*sh2_drc_restore_sr)(SH2 *sh2);
#define MF_POLLING 0x20 // include polling check in read #define MF_POLLING 0x20 // include polling check in read
// address space stuff // 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) static int dr_ctx_get_mem_ptr(SH2 *sh2, u32 a, u32 *mask)
{ {
void *memptr; 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)) { if (gconst_get(r, &a)) {
a += offs; a += offs;
// check if rom is memory mapped (not bank switched), and address is in rom // 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) { switch (size & MF_SIZEMASK) {
case 0: *val = (s8)p32x_sh2_read8(a, sh2s); break; // 8 case 0: *val = (s8)p32x_sh2_read8(a, sh2s); break; // 8
case 1: *val = (s16)p32x_sh2_read16(a, sh2s); break; // 16 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: case OP_LOAD_POOL:
#if PROPAGATE_CONSTANTS #if PROPAGATE_CONSTANTS
if ((opd->imm && opd->imm >= base_pc && opd->imm < end_literals) || 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) if (opd->size == 2)
u = FETCH32(opd->imm); u = FETCH32(opd->imm);
else else
u = (s16)FETCH_OP(opd->imm); 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); gconst_new(GET_Rn(), u);
} }
else else

View file

@ -816,7 +816,7 @@ static void p32x_sh2reg_write8(u32 a, u32 d, SH2 *sh2)
Pico32x.sh2_regs[0] &= ~0x80; Pico32x.sh2_regs[0] &= ~0x80;
Pico32x.sh2_regs[0] |= d & 0x80; Pico32x.sh2_regs[0] |= d & 0x80;
if ((d ^ old) & 1) if ((old ^ d) & 1)
p32x_pwm_schedule_sh2(sh2); p32x_pwm_schedule_sh2(sh2);
if ((old ^ d) & 2) if ((old ^ d) & 2)
p32x_update_cmd_irq(sh2, 0); 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, // 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 // 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. // 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; ((u16 *)sh2->p_rom)[a1 / 2] = d;
else else
sh2_write16_unmapped(a, d, sh2); sh2_write16_unmapped(a, d, sh2);
@ -1951,6 +1951,16 @@ void *p32x_sh2_get_mem_ptr(u32 a, u32 *mask, SH2 *sh2)
return ret; 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) int p32x_sh2_memcpy(u32 dst, u32 src, int count, int size, SH2 *sh2)
{ {
u32 mask; u32 mask;

View file

@ -137,15 +137,7 @@ static void dmac_memcpy(struct dma_chan *chan, SH2 *sh2)
if (!up || chan->tcr < 4) if (!up || chan->tcr < 4)
return; 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 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 TCR being a multiple of 4 in 4-word xfer mode?
// XXX check alignment of sar/dar, generating a bus error if unaligned? // XXX check alignment of sar/dar, generating a bus error if unaligned?

View file

@ -1201,6 +1201,12 @@ static void parse_carthw(const char *carthw_cfg, int *fill_sram,
Pico.sv.flags &= ~SRF_EEPROM; Pico.sv.flags &= ~SRF_EEPROM;
else if (strcmp(p, "filled_sram") == 0) else if (strcmp(p, "filled_sram") == 0)
*fill_sram = 1; *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) else if (strcmp(p, "force_6btn") == 0)
PicoIn.quirks |= PQUIRK_FORCE_6BTN; PicoIn.quirks |= PQUIRK_FORCE_6BTN;
else { else {
@ -1335,6 +1341,45 @@ static void PicoCartDetect(const char *carthw_cfg)
// Unusual region 'code' // Unusual region 'code'
if (rom_strcmp(0x1f0, "EUROPE") == 0 || rom_strcmp(0x1f0, "Europe") == 0) if (rom_strcmp(0x1f0, "EUROPE") == 0 || rom_strcmp(0x1f0, "Europe") == 0)
*(u32 *) (Pico.rom + 0x1f0) = CPU_LE4(0x20204520); *(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) static void PicoCartDetectMS(void)

View file

@ -52,6 +52,30 @@ hw = pico
check_str = 0x100, "IMA IKUNO" check_str = 0x100, "IMA IKUNO"
hw = pico 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 # sram emulation triggers some protection for this one
[Puggsy] [Puggsy]
check_str = 0x120, "PUGGSY" check_str = 0x120, "PUGGSY"
@ -71,12 +95,6 @@ prop = filled_sram
check_str = 0x150, " HardBall III" check_str = 0x150, " HardBall III"
sram_range = 0x200000,0x20ffff 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 # The SSF2 mapper
[Mega Everdrive] [Mega Everdrive]
check_str = 0x100, "SEGA SSF" check_str = 0x100, "SEGA SSF"

View file

@ -89,7 +89,10 @@ extern void *p32x_bios_g, *p32x_bios_m, *p32x_bios_s;
#define PHWS_SMS 2 #define PHWS_SMS 2
#define PHWS_SG 3 #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 // the emulator is configured and some status is reported
// through this global state (not saved in savestates) // through this global state (not saved in savestates)

View file

@ -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_memory16(u32 a, u32 d, SH2 *sh2);
u32 REGPARM(3) p32x_sh2_poll_memory32(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); 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_detect(u32 a, SH2 *sh2, u32 flags, int maxcnt);
void p32x_sh2_poll_event(SH2 *sh2, u32 flags, u32 m68k_cycles); 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); int p32x_sh2_memcpy(u32 dst, u32 src, int count, int size, SH2 *sh2);