Merge Icache emulation from PCSX Redux + Senquack changes from PCSX4ALL
authorgameblabla <gameblabla@protonmail.com>
Sat, 2 Oct 2021 16:10:23 +0000 (18:10 +0200)
committergameblabla <gameblabla@protonmail.com>
Sat, 2 Oct 2021 16:10:23 +0000 (18:10 +0200)
See (Redux) :
https://github.com/grumpycoders/pcsx-redux/commit/1923ce5

See original icache implementation (mirror of PCSX Reloaded):
https://github.com/gameblabla/pcsxr/commit/6916151

Without icache emulation, F1 2001 will greatly misbehave :
if you accelerate, the car will go around like crazy.
With icache emulation, it works as intended.

Note that our code is slightly different from theirs as i found out that
having the icache arrays in psxregs would cause crashes so instead
what i'm doing is to taking them out of there and only allocating them
on the heap (due to their great size).

Known issue(s) : Instruction cache emulation code fails to run
Spyro 2 PAL version. (or is it because of SBI?)

Co-authored-by: Nicolas Noble <nicolasnoble@users.noreply.github.com>
Co-authored-by: senquack <dansilsby@gmail.com>
16 files changed:
Makefile
Makefile.libretro
frontend/libretro.c
frontend/libretro_core_options.h
frontend/libretro_core_options_intl.h
frontend/main.c
frontend/menu.c
libpcsxcore/lightrec/plugin.c
libpcsxcore/new_dynarec/backends/psx/emu_if.c
libpcsxcore/plugins.c
libpcsxcore/psxbios.c
libpcsxcore/psxcommon.h
libpcsxcore/psxinterpreter.c
libpcsxcore/psxmem.c
libpcsxcore/r3000a.c
libpcsxcore/r3000a.h

index 80d129e..1d70f64 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -312,6 +312,9 @@ OBJS += libretro-common/time/rtime.o
 OBJS += libretro-common/vfs/vfs_implementation.o
 CFLAGS += -DUSE_LIBRETRO_VFS
 endif
+ifeq "$(ENABLE_ICACHE_EMULATION)" "1"
+CFLAGS += -DICACHE_EMULATION
+endif
 OBJS += frontend/libretro.o
 CFLAGS += -Ilibretro-common/include
 CFLAGS += -DFRONTEND_SUPPORTS_RGB565
index 1ecd359..2233620 100644 (file)
@@ -4,6 +4,7 @@ DEBUG ?= 0
 WANT_ZLIB ?= 1
 HAVE_CHD ?= 1
 USE_LIBRETRO_VFS ?= 0
+ENABLE_ICACHE_EMULATION ?= 1
 
 # Dynarec options: lightrec, ari64
 DYNAREC ?= lightrec
index 33f2a42..8442a15 100644 (file)
@@ -1699,6 +1699,19 @@ static void update_variables(bool in_flight)
       else if (strcmp(var.value, "enabled") == 0)
          Config.RCntFix = 1;
    }
+   
+#ifdef ICACHE_EMULATION
+   var.value = NULL;
+   var.key = "pcsx_rearmed_icache_emulation";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+         Config.icache_emulation = 0;
+      else if (strcmp(var.value, "enabled") == 0)
+         Config.icache_emulation = 1;
+   }
+#endif
 
    var.value = NULL;
    var.key = "pcsx_rearmed_inuyasha_fix";
index 1dbcefa..f3d68b6 100644 (file)
@@ -898,6 +898,17 @@ struct retro_core_option_definition option_defs_us[] = {
       },
       "disabled",
    },
+   {
+      "pcsx_rearmed_icache_emulation",
+      "Instruction Cache emulation",
+      "Enables or disables instruction cache emulation. Slower, but more accurate. Fails to run Spyro 2 PAL. This allows you to run F1 2001, Formula One Arcade, F1 99 and other games that may need instruction cache emulation. Interpreter/Lightrec only, does nothing on the ARMv7 backend.",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "disabled",
+   },
    {
       "pcsx_rearmed_inuyasha_fix",
       "InuYasha Sengoku Battle Fix",
index 174bb93..e725c6b 100644 (file)
@@ -380,6 +380,15 @@ struct retro_core_option_definition option_defs_tr[] = {
       },
       NULL
    },
+   {
+      "pcsx_rearmed_icache_emulation",
+      "ICache Düzeltmleri",
+      NULL,
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
    {
       "pcsx_rearmed_inuyasha_fix",
       "InuYasha Sengoku Battle Düzeltmesi",
index a64e9bb..da1f2f3 100644 (file)
@@ -122,7 +122,7 @@ void emu_set_default_config(void)
 {
        // try to set sane config on which most games work
        Config.Xa = Config.Cdda = Config.Sio =
-       Config.SpuIrq = Config.RCntFix = Config.VSyncWA = 0;
+       Config.icache_emulation = Config.SpuIrq = Config.RCntFix = Config.VSyncWA = 0;
        Config.PsxAuto = 1;
 
        pl_rearmed_cbs.thread_rendering = 0;
index 0f7933d..d8c3a31 100644 (file)
@@ -394,6 +394,7 @@ static const struct {
        CE_CONFIG_VAL(SpuIrq),
        CE_CONFIG_VAL(RCntFix),
        CE_CONFIG_VAL(VSyncWA),
+       CE_CONFIG_VAL(icache_emulation),
        CE_CONFIG_VAL(Cpu),
        CE_INTVAL(region),
        CE_INTVAL_V(g_scaler, 3),
@@ -1567,6 +1568,8 @@ static const char h_cfg_nodrc[]  = "Disable dynamic recompiler and use interpret
                                   "Might be useful to overcome some dynarec bugs";
 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
                                   "must reload game for any change to take effect";
+static const char h_cfg_icache[] = "Allows you to play the F1 games.\n"
+                                  "Note: This breaks the PAL version of Spyro 2.";
 
 static menu_entry e_menu_adv_options[] =
 {
@@ -1577,6 +1580,9 @@ static menu_entry e_menu_adv_options[] =
        mee_onoff_h   ("Disable CD Audio",       0, Config.Cdda, 1, h_cfg_cdda),
        //mee_onoff_h   ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
        mee_onoff_h   ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
+#ifdef ICACHE_EMULATION
+       mee_onoff_h   ("ICache emulation",       0, Config.icache_emulation, 1, h_cfg_icache),
+#endif
        //mee_onoff_h   ("Rootcounter hack",       0, Config.RCntFix, 1, h_cfg_rcnt1),
        mee_onoff_h   ("Rootcounter hack 2",     0, Config.VSyncWA, 1, h_cfg_rcnt2),
        mee_onoff_h   ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
index 05d1735..3e68a9c 100644 (file)
@@ -578,6 +578,25 @@ static void lightrec_plugin_clear(u32 addr, u32 size)
                lightrec_invalidate(lightrec_state, addr, size * 4);
 }
 
+#ifdef ICACHE_EMULATION
+static void lightrec_plugin_notify(int note, void *data)
+{
+       /*
+       To change once proper icache emulation is emulated
+       switch (note)
+       {
+               case R3000ACPU_NOTIFY_CACHE_UNISOLATED:
+                       lightrec_plugin_clear(0, 0x200000/4);
+                       break;
+               case R3000ACPU_NOTIFY_CACHE_ISOLATED:
+               // Sent from psxDma3().
+               case R3000ACPU_NOTIFY_DMA3_EXE_LOAD:
+               default:
+                       break;
+       }*/
+}
+#endif
+
 static void lightrec_plugin_shutdown(void)
 {
        lightrec_destroy(lightrec_state);
@@ -596,5 +615,8 @@ R3000Acpu psxRec =
        lightrec_plugin_execute,
        lightrec_plugin_execute_block,
        lightrec_plugin_clear,
+#ifdef ICACHE_EMULATION
+       lightrec_plugin_notify,
+#endif
        lightrec_plugin_shutdown,
 };
index 2a090a0..e9fa607 100644 (file)
@@ -398,6 +398,24 @@ static void ari64_clear(u32 addr, u32 size)
                        invalidate_block(start);
 }
 
+#ifdef ICACHE_EMULATION
+static void ari64_notify(int note, void *data) {
+       /*
+       To change once we have proper icache emulation
+       switch (note)
+       {
+               case R3000ACPU_NOTIFY_CACHE_UNISOLATED:
+                       ari64_clear(0, 0x200000/4);
+                       break;
+               case R3000ACPU_NOTIFY_CACHE_ISOLATED:
+               // Sent from psxDma3().
+               case R3000ACPU_NOTIFY_DMA3_EXE_LOAD:
+               default:
+                       break;
+       }*/
+}
+#endif
+
 static void ari64_shutdown()
 {
        new_dynarec_cleanup();
@@ -424,6 +442,9 @@ R3000Acpu psxRec = {
        intExecuteBlockT,
 #endif
        ari64_clear,
+#ifdef ICACHE_EMULATION
+       ari64_notify,
+#endif
        ari64_shutdown
 };
 
index a2f8fe2..34f2481 100644 (file)
@@ -776,7 +776,11 @@ unsigned char _PADpoll(int port, unsigned char value) {
        }
 
        //if no new request the pad return 0xff, for signaling connected
-       if (reqPos >= respSize) return 0xff;
+       if (reqPos >= respSize
+#ifdef ICACHE_EMULATION
+        && writeok
+#endif
+        ) return 0xff;
 
        switch(reqPos){
                case 2:
index cd627a0..46e1595 100644 (file)
@@ -1402,7 +1402,10 @@ void psxBios_FlushCache() { // 44
 #ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x44]);
 #endif
-
+#ifdef ICACHE_EMULATION
+    psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_ISOLATED, NULL);
+    psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_UNISOLATED, NULL);
+#endif
        pc0 = ra;
 }
 
index 708d984..7e10550 100644 (file)
@@ -130,6 +130,7 @@ typedef struct {
        boolean RCntFix;
        boolean UseNet;
        boolean VSyncWA;
+       boolean icache_emulation;
        u8 Cpu; // CPU_DYNAREC or CPU_INTERPRETER
        u8 PsxType; // PSX_TYPE_NTSC or PSX_TYPE_PAL
 #ifdef _WIN32
index 6c19f06..2e88fd5 100644 (file)
@@ -57,6 +57,65 @@ void (*psxCP0[32])();
 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;
 
@@ -274,7 +333,16 @@ void psxDelayTest(int reg, u32 bpc) {
        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;
 
@@ -298,7 +366,16 @@ static u32 psxBranchNoDelay(void) {
        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
@@ -427,7 +504,16 @@ static void doBranch(u32 tar) {
        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();
@@ -924,10 +1010,35 @@ void (*psxCP2BSC[32])() = {
 ///////////////////////////////////////////
 
 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() {
@@ -944,12 +1055,41 @@ void intExecuteBlock() {
 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();
@@ -968,5 +1108,8 @@ R3000Acpu psxInt = {
        intExecute,
        intExecuteBlock,
        intClear,
+#ifdef ICACHE_EMULATION
+       intNotify,
+#endif
        intShutdown
 };
index 2f427ac..db3a2db 100644 (file)
@@ -39,6 +39,8 @@
 #define MAP_ANONYMOUS MAP_ANON
 #endif
 
+boolean writeok = TRUE;
+
 #ifndef NDEBUG
 #include "debug.h"
 #else
@@ -254,8 +256,6 @@ void psxMemShutdown() {
        free(psxMemWLUT); psxMemWLUT = NULL;
 }
 
-static int writeok = 1;
-
 u8 psxMemRead8(u32 mem) {
        char *p;
        u32 t;
@@ -387,12 +387,36 @@ void psxMemWrite16(u32 mem, u16 value) {
 
 void psxMemWrite32(u32 mem, u32 value) {
        char *p;
+#if defined(ICACHE_EMULATION)
+       /*  Stores in PS1 code during cache isolation invalidate cachelines.
+        * It is assumed that cache-flush routines write to the lowest 4KB of
+        * address space for Icache, or 1KB for Dcache/scratchpad.
+        *  Originally, stores had to check 'writeok' in psxRegs struct before
+        * writing to RAM. To eliminate this necessity, we could simply patch the
+        * BIOS 0x44 FlushCache() A0 jumptable entry. Unfortunately, this won't
+        * work for some games that use less-buggy non-BIOS cache-flush routines
+        * like '007 Tomorrow Never Dies', often provided by SN-systems, the PS1
+        * toolchain provider.
+        *  Instead, we backup the lowest 64KB PS1 RAM when the cache is isolated.
+        * All stores write to RAM regardless of cache state. Thus, cache-flush
+        * routines temporarily trash the lowest 4KB of PS1 RAM. Fortunately, they
+        * ran in a 'critical section' with interrupts disabled, so there's little
+        * worry of PS1 code ever reading the trashed contents.
+        *  We point the relevant portions of psxMemRLUT[] to the 64KB backup while
+        * cache is isolated. This is in case the dynarec needs to recompile some
+        * code during isolation. As long as it reads code using psxMemRLUT[] ptrs,
+        * it should never see trashed RAM contents.
+        *
+        * -senquack, mips dynarec team, 2017
+        */
+       static u32 mem_bak[0x10000/4];
+#endif
        u32 t;
-
+       u32 m = mem & 0xffff;
 //     if ((mem&0x1fffff) == 0x71E18 || value == 0x48088800) SysPrintf("t2fix!!\n");
        t = mem >> 16;
        if (t == 0x1f80 || t == 0x9f80 || t == 0xbf80) {
-               if ((mem & 0xffff) < 0x400)
+               if (m < 0x400)
                        psxHu32ref(mem) = SWAPu32(value);
                else
                        psxHwWrite32(mem, value);
@@ -420,18 +444,39 @@ void psxMemWrite32(u32 mem, u32 value) {
 
                                switch (value) {
                                        case 0x800: case 0x804:
-                                               if (writeok == 0) break;
-                                               writeok = 0;
+                                               if (writeok == FALSE) break;
+                                               writeok = FALSE;
                                                memset(psxMemWLUT + 0x0000, 0, 0x80 * sizeof(void *));
                                                memset(psxMemWLUT + 0x8000, 0, 0x80 * sizeof(void *));
                                                memset(psxMemWLUT + 0xa000, 0, 0x80 * sizeof(void *));
+#ifdef ICACHE_EMULATION
+                                               /* Cache is now isolated, pending cache-flush sequence:
+                                               *  Backup lower 64KB of PS1 RAM, adjust psxMemRLUT[].
+                                               */
+                                               memcpy((void*)mem_bak, (void*)psxM, sizeof(mem_bak));
+                                               psxMemRLUT[0x0000] = psxMemRLUT[0x0020] = psxMemRLUT[0x0040] = psxMemRLUT[0x0060] = (u8 *)mem_bak;
+                                               psxMemRLUT[0x8000] = psxMemRLUT[0x8020] = psxMemRLUT[0x8040] = psxMemRLUT[0x8060] = (u8 *)mem_bak;
+                                               psxMemRLUT[0xa000] = psxMemRLUT[0xa020] = psxMemRLUT[0xa040] = psxMemRLUT[0xa060] = (u8 *)mem_bak;
+                                               psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_ISOLATED, NULL);
+#endif
                                                break;
                                        case 0x00: case 0x1e988:
-                                               if (writeok == 1) break;
-                                               writeok = 1;
+                                               if (writeok == TRUE) break;
+                                               writeok = TRUE;
                                                for (i = 0; i < 0x80; i++) psxMemWLUT[i + 0x0000] = (void *)&psxM[(i & 0x1f) << 16];
                                                memcpy(psxMemWLUT + 0x8000, psxMemWLUT, 0x80 * sizeof(void *));
                                                memcpy(psxMemWLUT + 0xa000, psxMemWLUT, 0x80 * sizeof(void *));
+#ifdef ICACHE_EMULATION
+                                               /* Cache is now unisolated:
+                                               * Restore lower 64KB RAM contents and psxMemRLUT[].
+                                               */
+                                               memcpy((void*)psxM, (void*)mem_bak, sizeof(mem_bak));
+                                               psxMemRLUT[0x0000] = psxMemRLUT[0x0020] = psxMemRLUT[0x0040] = psxMemRLUT[0x0060] = (u8 *)psxM;
+                                               psxMemRLUT[0x8000] = psxMemRLUT[0x8020] = psxMemRLUT[0x8040] = psxMemRLUT[0x8060] = (u8 *)psxM;
+                                               psxMemRLUT[0xa000] = psxMemRLUT[0xa020] = psxMemRLUT[0xa040] = psxMemRLUT[0xa060] = (u8 *)psxM;
+                                               /* Dynarecs might take this opportunity to flush their code cache */
+                                               psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_UNISOLATED, NULL);
+#endif
                                                break;
                                        default:
 #ifdef PSXMEM_LOG
index 0a3e00b..3288f5c 100644 (file)
@@ -53,7 +53,7 @@ void psxReset() {
        psxMemReset();
 
        memset(&psxRegs, 0x00, sizeof(psxRegs));
-
+       writeok = TRUE;
        psxRegs.pc = 0xbfc00000; // Start in bootstrap
 
        psxRegs.CP0.r[12] = 0x10900000; // COP0 enabled | BEV = 1 | TS = 1
@@ -81,7 +81,21 @@ void psxShutdown() {
 }
 
 void psxException(u32 code, u32 bd) {
-       if (!Config.HLE && ((((psxRegs.code = PSXMu32(psxRegs.pc)) >> 24) & 0xfe) == 0x4a)) {
+       #ifdef ICACHE_EMULATION
+       /* Without the CPU_INTERPRETER condition, this will make Lightrec crash.
+        * Hopefully a better solution than this mess is found. - Gameblabla
+       */
+       if (Config.icache_emulation && Config.Cpu == CPU_INTERPRETER)
+       {
+               psxRegs.code = SWAPu32(*Read_ICache(psxRegs.pc));
+       }
+       else
+       #endif
+       {
+               psxRegs.code = PSXMu32(psxRegs.pc);
+       }
+
+       if (!Config.HLE && ((((psxRegs.code) >> 24) & 0xfe) == 0x4a)) {
                // "hokuto no ken" / "Crash Bandicot 2" ...
                // BIOS does not allow to return to GTE instructions
                // (just skips it, supposedly because it's scheduled already)
index 32538e5..a516645 100644 (file)
@@ -29,12 +29,24 @@ extern "C" {
 #include "psxcounters.h"
 #include "psxbios.h"
 
+#ifdef ICACHE_EMULATION
+enum {
+       R3000ACPU_NOTIFY_CACHE_ISOLATED = 0,
+       R3000ACPU_NOTIFY_CACHE_UNISOLATED = 1,
+       R3000ACPU_NOTIFY_DMA3_EXE_LOAD = 2
+};
+extern uint32_t *Read_ICache(uint32_t pc);
+#endif
+
 typedef struct {
        int  (*Init)();
        void (*Reset)();
        void (*Execute)();              /* executes up to a break */
        void (*ExecuteBlock)(); /* executes up to a jump */
        void (*Clear)(u32 Addr, u32 Size);
+#ifdef ICACHE_EMULATION
+       void (*Notify)(int note, void *data);
+#endif
        void (*Shutdown)();
 } R3000Acpu;
 
@@ -184,6 +196,8 @@ typedef struct {
        struct { u32 sCycle, cycle; } intCycle[32];
 } psxRegisters;
 
+extern boolean writeok;
+
 extern psxRegisters psxRegs;
 
 /* new_dynarec stuff */