void (*psxCP2[64])(struct psxCP2Regs *regs);
void (*psxCP2BSC[32])();
+#ifdef ICACHE_EMULATION
+/*
+Formula One 2001 :
+Use old CPU cache code when the RAM location is updated with new code (affects in-game racing)
+*/
+static u8* ICache_Addr;
+static u8* ICache_Code;
+uint32_t *Read_ICache(uint32_t pc)
+{
+ uint32_t pc_bank, pc_offset, pc_cache;
+ uint8_t *IAddr, *ICode;
+
+ pc_bank = pc >> 24;
+ pc_offset = pc & 0xffffff;
+ pc_cache = pc & 0xfff;
+
+ IAddr = ICache_Addr;
+ ICode = ICache_Code;
+
+ // cached - RAM
+ if (pc_bank == 0x80 || pc_bank == 0x00)
+ {
+ if (SWAP32(*(uint32_t *)(IAddr + pc_cache)) == pc_offset)
+ {
+ // Cache hit - return last opcode used
+ return (uint32_t *)(ICode + pc_cache);
+ }
+ else
+ {
+ // Cache miss - addresses don't match
+ // - default: 0xffffffff (not init)
+
+ // cache line is 4 bytes wide
+ pc_offset &= ~0xf;
+ pc_cache &= ~0xf;
+
+ // address line
+ *(uint32_t *)(IAddr + pc_cache + 0x0) = SWAP32(pc_offset + 0x0);
+ *(uint32_t *)(IAddr + pc_cache + 0x4) = SWAP32(pc_offset + 0x4);
+ *(uint32_t *)(IAddr + pc_cache + 0x8) = SWAP32(pc_offset + 0x8);
+ *(uint32_t *)(IAddr + pc_cache + 0xc) = SWAP32(pc_offset + 0xc);
+
+ // opcode line
+ pc_offset = pc & ~0xf;
+ *(uint32_t *)(ICode + pc_cache + 0x0) = psxMu32ref(pc_offset + 0x0);
+ *(uint32_t *)(ICode + pc_cache + 0x4) = psxMu32ref(pc_offset + 0x4);
+ *(uint32_t *)(ICode + pc_cache + 0x8) = psxMu32ref(pc_offset + 0x8);
+ *(uint32_t *)(ICode + pc_cache + 0xc) = psxMu32ref(pc_offset + 0xc);
+ }
+ }
+
+ /*
+ TODO: Probably should add cached BIOS
+ */
+ // default
+ return (uint32_t *)PSXM(pc);
+}
+#endif
+
static void delayRead(int reg, u32 bpc) {
u32 rold, rnew;
u32 *code;
u32 tmp;
- code = (u32 *)PSXM(bpc);
+ #ifdef ICACHE_EMULATION
+ if (Config.icache_emulation)
+ {
+ code = Read_ICache(psxRegs.pc);
+ }
+ else
+ #endif
+ {
+ code = (u32 *)PSXM(psxRegs.pc);
+ }
tmp = ((code == NULL) ? 0 : SWAP32(*code));
branch = 1;
u32 *code;
u32 temp;
- code = (u32 *)PSXM(psxRegs.pc);
+ #ifdef ICACHE_EMULATION
+ if (Config.icache_emulation)
+ {
+ code = Read_ICache(psxRegs.pc);
+ }
+ else
+ #endif
+ {
+ code = (u32 *)PSXM(psxRegs.pc);
+ }
psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code));
switch (_Op_) {
case 0x00: // SPECIAL
if (psxDelayBranchTest(tar))
return;
- code = (u32 *)PSXM(psxRegs.pc);
+ #ifdef ICACHE_EMULATION
+ if (Config.icache_emulation)
+ {
+ code = Read_ICache(psxRegs.pc);
+ }
+ else
+ #endif
+ {
+ code = (u32 *)PSXM(psxRegs.pc);
+ }
psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code));
debugI();
///////////////////////////////////////////
static int intInit() {
+#ifdef ICACHE_EMULATION
+ if (!ICache_Addr)
+ {
+ ICache_Addr = malloc(0x1000);
+ if (!ICache_Addr)
+ {
+ return -1;
+ }
+ }
+
+ if (!ICache_Code)
+ {
+ ICache_Code = malloc(0x1000);
+ if (!ICache_Code)
+ {
+ return -1;
+ }
+ }
+ memset(ICache_Addr, 0xff, 0x1000);
+ memset(ICache_Code, 0xff, 0x1000);
+#endif
return 0;
}
static void intReset() {
+#ifdef ICACHE_EMULATION
+ memset(ICache_Addr, 0xff, 0x1000);
+ memset(ICache_Code, 0xff, 0x1000);
+#endif
}
void intExecute() {
static void intClear(u32 Addr, u32 Size) {
}
+void intNotify (int note, void *data) {
+#ifdef ICACHE_EMULATION
+ /* Gameblabla - Only clear the icache if it's isolated */
+ if (note == R3000ACPU_NOTIFY_CACHE_ISOLATED)
+ {
+ memset(ICache_Addr, 0xff, 0x1000);
+ memset(ICache_Code, 0xff, 0x1000);
+ }
+#endif
+}
+
static void intShutdown() {
+#ifdef ICACHE_EMULATION
+ if (ICache_Addr)
+ {
+ free(ICache_Addr);
+ ICache_Addr = NULL;
+ }
+
+ if (ICache_Code)
+ {
+ free(ICache_Code);
+ ICache_Code = NULL;
+ }
+#endif
}
// interpreter execution
void execI() {
+#ifndef ICACHE_EMULATION
u32 *code = (u32 *)PSXM(psxRegs.pc);
+#else
+ u32 *code = Read_ICache(psxRegs.pc);
+#endif
+
psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code));
debugI();
intExecute,
intExecuteBlock,
intClear,
+#ifdef ICACHE_EMULATION
+ intNotify,
+#endif
intShutdown
};