libpcsxcore: Add database for Lightrec hacks
[pcsx_rearmed.git] / libpcsxcore / lightrec / plugin.c
index 2a46942..d3e4b33 100644 (file)
@@ -19,6 +19,7 @@
 #include "../psxmem.h"
 #include "../r3000a.h"
 #include "../psxinterpreter.h"
+#include "../psxhle.h"
 #include "../new_dynarec/events.h"
 
 #include "../frontend/main.h"
@@ -65,6 +66,8 @@ static bool use_lightrec_interpreter;
 static bool use_pcsx_interpreter;
 static bool block_stepping;
 
+extern u32 lightrec_hacks;
+
 enum my_cp2_opcodes {
        OP_CP2_RTPS             = 0x01,
        OP_CP2_NCLIP            = 0x06,
@@ -467,6 +470,8 @@ static int lightrec_plugin_init(void)
                        lightrec_map, ARRAY_SIZE(lightrec_map),
                        &lightrec_ops);
 
+       lightrec_set_unsafe_opt_flags(lightrec_state, lightrec_hacks);
+
        // fprintf(stderr, "M=0x%lx, P=0x%lx, R=0x%lx, H=0x%lx\n",
        //              (uintptr_t) psxM,
        //              (uintptr_t) psxP,
@@ -479,6 +484,9 @@ static int lightrec_plugin_init(void)
        return 0;
 }
 
+static void lightrec_plugin_sync_regs_to_pcsx(bool need_cp2);
+static void lightrec_plugin_sync_regs_from_pcsx(bool need_cp2);
+
 static void lightrec_plugin_execute_internal(bool block_only)
 {
        struct lightrec_registers *regs;
@@ -518,7 +526,18 @@ static void lightrec_plugin_execute_internal(bool block_only)
                }
 
                if (flags & LIGHTREC_EXIT_SYSCALL)
-                       psxException(0x20, 0, (psxCP0Regs *)regs->cp0);
+                       psxException(R3000E_Syscall << 2, 0, (psxCP0Regs *)regs->cp0);
+               else if (flags & LIGHTREC_EXIT_UNKNOWN_OP) {
+                       u32 op = intFakeFetch(psxRegs.pc);
+                       u32 hlec = op & 0x03ffffff;
+                       if ((op >> 26) == 0x3b && hlec < ARRAY_SIZE(psxHLEt) && Config.HLE) {
+                               lightrec_plugin_sync_regs_to_pcsx(0);
+                               psxHLEt[hlec]();
+                               lightrec_plugin_sync_regs_from_pcsx(0);
+                       }
+                       else
+                               psxException(R3000E_RI << 2, 0, (psxCP0Regs *)regs->cp0);
+               }
        }
 
        if ((regs->cp0[13] & regs->cp0[12] & 0x300) && (regs->cp0[12] & 0x1)) {
@@ -550,9 +569,6 @@ static void lightrec_plugin_clear(u32 addr, u32 size)
                lightrec_invalidate(lightrec_state, addr, size * 4);
 }
 
-static void lightrec_plugin_sync_regs_to_pcsx(void);
-static void lightrec_plugin_sync_regs_from_pcsx(void);
-
 static void lightrec_plugin_notify(enum R3000Anote note, void *data)
 {
        switch (note)
@@ -562,10 +578,13 @@ static void lightrec_plugin_notify(enum R3000Anote note, void *data)
                /* not used, lightrec calls lightrec_enable_ram() instead */
                break;
        case R3000ACPU_NOTIFY_BEFORE_SAVE:
-               lightrec_plugin_sync_regs_to_pcsx();
+               /* non-null 'data' means this is HLE related sync */
+               lightrec_plugin_sync_regs_to_pcsx(data == NULL);
                break;
        case R3000ACPU_NOTIFY_AFTER_LOAD:
-               lightrec_plugin_sync_regs_from_pcsx();
+               lightrec_plugin_sync_regs_from_pcsx(data == NULL);
+               if (data == NULL)
+                       lightrec_invalidate_all(lightrec_state);
                break;
        }
 }
@@ -608,26 +627,26 @@ static void lightrec_plugin_reset(void)
        regs->cp0[15] = 0x00000002; // PRevID = Revision ID, same as R3000A
 }
 
-static void lightrec_plugin_sync_regs_from_pcsx(void)
+static void lightrec_plugin_sync_regs_from_pcsx(bool need_cp2)
 {
        struct lightrec_registers *regs;
 
        regs = lightrec_get_registers(lightrec_state);
-       memcpy(regs->cp2d, &psxRegs.CP2, sizeof(regs->cp2d) + sizeof(regs->cp2c));
-       memcpy(regs->cp0, &psxRegs.CP0, sizeof(regs->cp0));
        memcpy(regs->gpr, &psxRegs.GPR, sizeof(regs->gpr));
-
-       lightrec_invalidate_all(lightrec_state);
+       memcpy(regs->cp0, &psxRegs.CP0, sizeof(regs->cp0));
+       if (need_cp2)
+               memcpy(regs->cp2d, &psxRegs.CP2, sizeof(regs->cp2d) + sizeof(regs->cp2c));
 }
 
-static void lightrec_plugin_sync_regs_to_pcsx(void)
+static void lightrec_plugin_sync_regs_to_pcsx(bool need_cp2)
 {
        struct lightrec_registers *regs;
 
        regs = lightrec_get_registers(lightrec_state);
-       memcpy(&psxRegs.CP2, regs->cp2d, sizeof(regs->cp2d) + sizeof(regs->cp2c));
-       memcpy(&psxRegs.CP0, regs->cp0, sizeof(regs->cp0));
        memcpy(&psxRegs.GPR, regs->gpr, sizeof(regs->gpr));
+       memcpy(&psxRegs.CP0, regs->cp0, sizeof(regs->cp0));
+       if (need_cp2)
+               memcpy(&psxRegs.CP2, regs->cp2d, sizeof(regs->cp2d) + sizeof(regs->cp2c));
 }
 
 R3000Acpu psxRec =