From: gameblabla Date: Sat, 2 Oct 2021 16:10:23 +0000 (+0200) Subject: Merge Icache emulation from PCSX Redux + Senquack changes from PCSX4ALL X-Git-Tag: r24l~555^2~5 X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7a8117168d6b9ad083757e013049c0e45734f3fb;p=pcsx_rearmed.git Merge Icache emulation from PCSX Redux + Senquack changes from PCSX4ALL 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 Co-authored-by: senquack --- diff --git a/Makefile b/Makefile index 80d129ec..1d70f643 100644 --- 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 diff --git a/Makefile.libretro b/Makefile.libretro index 1ecd3595..22336209 100644 --- a/Makefile.libretro +++ b/Makefile.libretro @@ -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 diff --git a/frontend/libretro.c b/frontend/libretro.c index 33f2a42d..8442a150 100644 --- a/frontend/libretro.c +++ b/frontend/libretro.c @@ -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"; diff --git a/frontend/libretro_core_options.h b/frontend/libretro_core_options.h index 1dbcefad..f3d68b68 100644 --- a/frontend/libretro_core_options.h +++ b/frontend/libretro_core_options.h @@ -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", diff --git a/frontend/libretro_core_options_intl.h b/frontend/libretro_core_options_intl.h index 174bb93e..e725c6b9 100644 --- a/frontend/libretro_core_options_intl.h +++ b/frontend/libretro_core_options_intl.h @@ -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", diff --git a/frontend/main.c b/frontend/main.c index a64e9bb8..da1f2f33 100644 --- a/frontend/main.c +++ b/frontend/main.c @@ -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; diff --git a/frontend/menu.c b/frontend/menu.c index 0f7933df..d8c3a31d 100644 --- a/frontend/menu.c +++ b/frontend/menu.c @@ -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), diff --git a/libpcsxcore/lightrec/plugin.c b/libpcsxcore/lightrec/plugin.c index 05d1735d..3e68a9ca 100644 --- a/libpcsxcore/lightrec/plugin.c +++ b/libpcsxcore/lightrec/plugin.c @@ -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, }; diff --git a/libpcsxcore/new_dynarec/backends/psx/emu_if.c b/libpcsxcore/new_dynarec/backends/psx/emu_if.c index 2a090a0b..e9fa6071 100644 --- a/libpcsxcore/new_dynarec/backends/psx/emu_if.c +++ b/libpcsxcore/new_dynarec/backends/psx/emu_if.c @@ -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 }; diff --git a/libpcsxcore/plugins.c b/libpcsxcore/plugins.c index a2f8fe27..34f24812 100644 --- a/libpcsxcore/plugins.c +++ b/libpcsxcore/plugins.c @@ -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: diff --git a/libpcsxcore/psxbios.c b/libpcsxcore/psxbios.c index cd627a05..46e1595e 100644 --- a/libpcsxcore/psxbios.c +++ b/libpcsxcore/psxbios.c @@ -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; } diff --git a/libpcsxcore/psxcommon.h b/libpcsxcore/psxcommon.h index 708d9843..7e105508 100644 --- a/libpcsxcore/psxcommon.h +++ b/libpcsxcore/psxcommon.h @@ -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 diff --git a/libpcsxcore/psxinterpreter.c b/libpcsxcore/psxinterpreter.c index 6c19f061..2e88fd5d 100644 --- a/libpcsxcore/psxinterpreter.c +++ b/libpcsxcore/psxinterpreter.c @@ -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 }; diff --git a/libpcsxcore/psxmem.c b/libpcsxcore/psxmem.c index 2f427acf..db3a2dbc 100644 --- a/libpcsxcore/psxmem.c +++ b/libpcsxcore/psxmem.c @@ -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 diff --git a/libpcsxcore/r3000a.c b/libpcsxcore/r3000a.c index 0a3e00b8..3288f5c3 100644 --- a/libpcsxcore/r3000a.c +++ b/libpcsxcore/r3000a.c @@ -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) diff --git a/libpcsxcore/r3000a.h b/libpcsxcore/r3000a.h index 32538e58..a5166459 100644 --- a/libpcsxcore/r3000a.h +++ b/libpcsxcore/r3000a.h @@ -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 */