From 109c5c1302691f013b65b38012180c47d5952a83 Mon Sep 17 00:00:00 2001 From: xjsxjs197 <31617363+xjsxjs197@users.noreply.github.com> Date: Sun, 16 Oct 2022 18:16:29 +0800 Subject: [PATCH] add ICache Xenogears: fixes memory card access. Need more test determine whether it has an impact on other games --- misc.c | 2 ++ ppc/pR3000A.c | 13 ++++++-- psxbios.c | 1 + psxinterpreter.c | 15 ++++++---- psxmem.c | 2 ++ r3000a.c | 9 +++++- r3000a.h | 77 ++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 111 insertions(+), 8 deletions(-) diff --git a/misc.c b/misc.c index 22c989f5..f5484763 100644 --- a/misc.c +++ b/misc.c @@ -290,6 +290,8 @@ int LoadCdromFile(char *filename, EXE_HEADER *head) { psxCpu->Clear(addr, size / 4); + psxRegs.ICache_valid = FALSE; + while (size & ~2047) { incTime(); READTRACK(); diff --git a/ppc/pR3000A.c b/ppc/pR3000A.c index 506ea976..f4e9c443 100644 --- a/ppc/pR3000A.c +++ b/ppc/pR3000A.c @@ -1090,12 +1090,21 @@ __inline static void execute() { char *p; p = (char*)PC_REC(psxRegs.pc); - /*if (p != NULL)*/ recFunc = (void (**)()) (u32)p; + /*if (p != NULL)*/ /*else { recError(); return; }*/ - if (*recFunc == 0) { + if (*p == 0) { recRecompile(); } + else if (psxRegs.ICache_valid == FALSE) { // Xenogears: fixes memory card access with original BIOS (0a_44_FlushCache issue) + //psxCpu->Clear(0x0, 0x20000); + memset(recRAM, 0, 0x200000); + recRecompile(); + p = (char*)PC_REC(psxRegs.pc); + psxRegs.ICache_valid = TRUE; + } + recFunc = (void (**)()) (u32)p; + recRun(*recFunc, (u32)&psxRegs, (u32)&psxM); } diff --git a/psxbios.c b/psxbios.c index 84f4deb0..57a1b767 100644 --- a/psxbios.c +++ b/psxbios.c @@ -1322,6 +1322,7 @@ void psxBios_FlushCache() { // 44 #ifdef PSXBIOS_LOG PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x44]); #endif + psxRegs.ICache_valid = FALSE; pc0 = ra; } diff --git a/psxinterpreter.c b/psxinterpreter.c index 7ed8016b..4523d4c7 100644 --- a/psxinterpreter.c +++ b/psxinterpreter.c @@ -267,7 +267,9 @@ void psxDelayTest(int reg, u32 bpc) { u32 *code; u32 tmp; - code = (u32 *)PSXM(bpc); + // Don't execute yet - just peek + code = Read_ICache(bpc, TRUE); + tmp = ((code == NULL) ? 0 : SWAP32(*code)); branch = 1; @@ -291,7 +293,7 @@ __inline u32 psxBranchNoDelay(void) { u32 *code; u32 temp; - code = (u32 *)PSXM(psxRegs.pc); + code = Read_ICache(psxRegs.pc, TRUE); psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code)); switch (_Op_) { case 0x00: // SPECIAL @@ -416,11 +418,13 @@ __inline void doBranch(u32 tar) { branch2 = branch = 1; branchPC = tar; - // check for branch in delay slot + // notaz: check for branch in delay slot if (psxDelayBranchTest(tar)) return; - code = (u32 *)PSXM(psxRegs.pc); + // branch delay slot + code = Read_ICache(psxRegs.pc, TRUE); + psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code)); debugI(); @@ -920,6 +924,7 @@ static int intInit() { } static void intReset() { + psxRegs.ICache_valid = FALSE; } static void intExecute() { @@ -950,7 +955,7 @@ static void intShutdown() { // interpreter execution inline void execI() { - u32 *code = (u32 *)PSXM(psxRegs.pc); + u32 *code = Read_ICache(psxRegs.pc, FALSE); psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code)); debugI(); diff --git a/psxmem.c b/psxmem.c index dc0b424b..19c3fb2b 100644 --- a/psxmem.c +++ b/psxmem.c @@ -363,6 +363,8 @@ void psxMemWrite32(u32 mem, u32 value) { memset(psxMemWLUT + 0x0000, 0, 0x80 * sizeof(void *)); memset(psxMemWLUT + 0x8000, 0, 0x80 * sizeof(void *)); memset(psxMemWLUT + 0xa000, 0, 0x80 * sizeof(void *)); + + psxRegs.ICache_valid = FALSE; break; case 0x00: case 0x1e988: if (writeok == 1) break; diff --git a/r3000a.c b/r3000a.c index 721ad49c..16d8964d 100644 --- a/r3000a.c +++ b/r3000a.c @@ -253,11 +253,18 @@ inline void psxTestHWInts() { if (*((u32*)psxHAddr(0x1070)) & *((u32*)psxHAddr(0x1074))) { // upd xjsxjs197 end if ((psxRegs.CP0.n.Status & 0x401) == 0x401) { + u32 opcode; + + // Crash Bandicoot 2: Don't run exceptions when GTE in pipeline + opcode = SWAP32(*Read_ICache(psxRegs.pc, TRUE)); + if( ((opcode >> 24) & 0xfe) != 0x4a ) { + psxException(0x400, 0); + } #ifdef PSXCPU_LOG PSXCPU_LOG("Interrupt: %x %x\n", psxHu32(0x1070), psxHu32(0x1074)); #endif // SysPrintf("Interrupt (%x): %x %x\n", psxRegs.cycle, psxHu32(0x1070), psxHu32(0x1074)); - psxException(0x400, 0); + //psxException(0x400, 0); } } } diff --git a/r3000a.h b/r3000a.h index 0f4429f9..9741a7a3 100644 --- a/r3000a.h +++ b/r3000a.h @@ -135,10 +135,87 @@ typedef struct { u32 interrupt; //u32 intCycle[32]; struct { u32 sCycle, cycle; } intCycle[32]; + u8 ICache_Addr[0x1000]; + u8 ICache_Code[0x1000]; + bool ICache_valid; } psxRegisters; extern psxRegisters psxRegs; +/* +Formula One 2001 +- Use old CPU cache code when the RAM location is + updated with new code (affects in-game racing) + +TODO: +- I-cache / D-cache swapping +- Isolate D-cache from RAM +*/ + +static inline u32 *Read_ICache(u32 pc, bool isolate) { + u32 pc_bank, pc_offset, pc_cache; + u8 *IAddr, *ICode; + + pc_bank = pc >> 24; + pc_offset = pc & 0xffffff; + pc_cache = pc & 0xfff; + + IAddr = psxRegs.ICache_Addr; + ICode = psxRegs.ICache_Code; + + // clear I-cache + if (!psxRegs.ICache_valid) { + memset(psxRegs.ICache_Addr, 0xff, sizeof(psxRegs.ICache_Addr)); + memset(psxRegs.ICache_Code, 0xff, sizeof(psxRegs.ICache_Code)); + + psxRegs.ICache_valid = TRUE; + } + + // uncached + if (pc_bank >= 0xa0) + return (u32 *)PSXM(pc); + + // cached - RAM + if (pc_bank == 0x80 || pc_bank == 0x00) { + if (SWAP32(*(u32 *)(IAddr + pc_cache)) == pc_offset) { + // Cache hit - return last opcode used + return (u32 *)(ICode + pc_cache); + } else { + // Cache miss - addresses don't match + // - default: 0xffffffff (not init) + + if (!isolate) { + // cache line is 4 bytes wide + pc_offset &= ~0xf; + pc_cache &= ~0xf; + + // address line + *(u32 *)(IAddr + pc_cache + 0x0) = SWAP32(pc_offset + 0x0); + *(u32 *)(IAddr + pc_cache + 0x4) = SWAP32(pc_offset + 0x4); + *(u32 *)(IAddr + pc_cache + 0x8) = SWAP32(pc_offset + 0x8); + *(u32 *)(IAddr + pc_cache + 0xc) = SWAP32(pc_offset + 0xc); + + // opcode line + pc_offset = pc & ~0xf; + *(u32 *)(ICode + pc_cache + 0x0) = psxMu32ref(pc_offset + 0x0); + *(u32 *)(ICode + pc_cache + 0x4) = psxMu32ref(pc_offset + 0x4); + *(u32 *)(ICode + pc_cache + 0x8) = psxMu32ref(pc_offset + 0x8); + *(u32 *)(ICode + pc_cache + 0xc) = psxMu32ref(pc_offset + 0xc); + } + + // normal code + return (u32 *)PSXM(pc); + } + } + + /* + TODO: Probably should add cached BIOS + */ + + // default + return (u32 *)PSXM(pc); +} + enum { PSXINT_SIO = 0, PSXINT_CDR,