lightrec: Add LIGHTREC_DEBUG functionality
authorPaul Cercueil <paul@crapouillou.net>
Fri, 17 Jan 2025 00:25:17 +0000 (01:25 +0100)
committernotaz <notasas@gmail.com>
Mon, 20 Jan 2025 20:08:27 +0000 (22:08 +0200)
When set, Lightrec will be built with the debug log level, the built-in
disassembler for PSX code and JIT code (requires binutils), and support
outputing data to the big-ass debugger (if the proper environment
variables are set).

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Makefile
frontend/main.c
include/lightrec/lightrec-config.h
jni/Android.mk
libpcsxcore/lightrec/plugin.c

index 7b9ac5f..ec07225 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -118,13 +118,22 @@ endif
 ifeq "$(DYNAREC)" "lightrec"
 CFLAGS += -Ideps/lightning/include -Ideps/lightrec -Iinclude/lightning -Iinclude/lightrec \
                  -DLIGHTREC -DLIGHTREC_STATIC
+ifeq ($(LIGHTREC_DEBUG),1)
+deps/lightrec/%.o: CFLAGS += -DLOG_LEVEL=DEBUG_L
+libpcsxcore/lightrec/plugin.o: CFLAGS += -DLIGHTREC_DEBUG=1
+frontend/main.o: CFLAGS += -DLIGHTREC_DEBUG=1
+deps/lightning/%.o: CFLAGS += -DDISASSEMBLER=1 -DBINUTILS_2_38=1 -DBINUTILS_2_29=1 \
+       -DHAVE_DISASSEMBLE_INIT_FOR_TARGET=1 -DPACKAGE_VERSION=1
+LDFLAGS += -lopcodes -lbfd
+endif
 LIGHTREC_CUSTOM_MAP ?= 0
 LIGHTREC_CUSTOM_MAP_OBJ ?= libpcsxcore/lightrec/mem.o
 LIGHTREC_THREADED_COMPILER ?= 0
 LIGHTREC_CODE_INV ?= 0
 CFLAGS += -DLIGHTREC_CUSTOM_MAP=$(LIGHTREC_CUSTOM_MAP) \
          -DLIGHTREC_CODE_INV=$(LIGHTREC_CODE_INV) \
-         -DLIGHTREC_ENABLE_THREADED_COMPILER=$(LIGHTREC_THREADED_COMPILER)
+         -DLIGHTREC_ENABLE_THREADED_COMPILER=$(LIGHTREC_THREADED_COMPILER) \
+         -DLIGHTREC_ENABLE_DISASSEMBLER=$(or $(LIGHTREC_DEBUG),0)
 ifeq ($(LIGHTREC_CUSTOM_MAP),1)
 LDLIBS += -lrt
 OBJS += $(LIGHTREC_CUSTOM_MAP_OBJ)
index 2dd5ca4..b2a4fea 100644 (file)
@@ -737,7 +737,9 @@ int main(int argc, char *argv[])
        else
                menu_loop();
 
+#ifndef LIGHTREC_DEBUG
        pl_start_watchdog();
+#endif
 
        while (!g_emu_want_quit)
        {
index 3d4b81e..8453fe4 100644 (file)
@@ -8,7 +8,7 @@
 
 #define ENABLE_THREADED_COMPILER LIGHTREC_ENABLE_THREADED_COMPILER
 #define ENABLE_FIRST_PASS 1
-#define ENABLE_DISASSEMBLER 0
+#define ENABLE_DISASSEMBLER LIGHTREC_ENABLE_DISASSEMBLER
 #define ENABLE_CODE_BUFFER 1
 
 #define HAS_DEFAULT_ELM 1
index 8439f3d..0fe5cb9 100644 (file)
@@ -134,6 +134,7 @@ HAVE_ARI64=0
 HAVE_LIGHTREC=0
 LIGHTREC_CUSTOM_MAP=0
 LIGHTREC_THREADED_COMPILER=0
+LIGHTREC_DEBUG=0
 HAVE_GPU_NEON=0
 ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
   HAVE_ARI64=1
@@ -154,6 +155,7 @@ else
 endif
   COREFLAGS   += -DLIGHTREC_CUSTOM_MAP=$(LIGHTREC_CUSTOM_MAP)
   COREFLAGS   += -DLIGHTREC_ENABLE_THREADED_COMPILER=$(LIGHTREC_THREADED_COMPILER)
+  COREFLAGS   += -DLIGHTREC_ENABLE_DISASSEMBLER=$(or $(LIGHTREC_DEBUG),0)
 
 ifeq ($(HAVE_ARI64),1)
   SOURCES_C   += $(DYNAREC_DIR)/new_dynarec.c \
index d62f35b..0ca44e4 100644 (file)
@@ -72,6 +72,9 @@ static bool use_lightrec_interpreter;
 static bool block_stepping;
 //static bool use_pcsx_interpreter;
 #define use_pcsx_interpreter 0
+static bool ram_disabled;
+static bool lightrec_debug, lightrec_very_debug;
+static u32 lightrec_begin_cycles;
 
 extern u32 lightrec_hacks;
 
@@ -340,6 +343,8 @@ static void lightrec_enable_ram(struct lightrec_state *state, bool enable)
                memcpy(psxM, cache_buf, sizeof(cache_buf));
        else
                memcpy(cache_buf, psxM, sizeof(cache_buf));
+
+       ram_disabled = !enable;
 }
 
 static bool lightrec_can_hw_direct(u32 kaddr, bool is_write, u8 size)
@@ -465,6 +470,16 @@ static int lightrec_plugin_init(void)
 
        use_lightrec_interpreter = !!getenv("LIGHTREC_INTERPRETER");
 
+#ifdef LIGHTREC_DEBUG
+       char *cycles = getenv("LIGHTREC_BEGIN_CYCLES");
+
+       lightrec_very_debug = !!getenv("LIGHTREC_VERY_DEBUG");
+       lightrec_debug = lightrec_very_debug || !!getenv("LIGHTREC_DEBUG");
+
+       if (cycles)
+               lightrec_begin_cycles = (unsigned int) strtol(cycles, NULL, 0);
+#endif
+
        lightrec_state = lightrec_init(LIGHTREC_PROG_NAME,
                        lightrec_map, ARRAY_SIZE(lightrec_map),
                        &lightrec_ops);
@@ -481,6 +496,104 @@ static int lightrec_plugin_init(void)
        return 0;
 }
 
+static u32 do_calculate_hash(const void *buffer, u32 count, u32 needle, bool le)
+{
+       unsigned int i;
+       const u32 *data = (const u32 *) buffer;
+       u32 hash = needle;
+
+       count /= 4;
+       for(i = 0; i < count; ++i) {
+               hash += le ? LE32TOH(data[i]) : data[i];
+               hash += (hash << 10);
+               hash ^= (hash >> 6);
+       }
+
+       hash += (hash << 3);
+       hash ^= (hash >> 11);
+       hash += (hash << 15);
+
+       return hash;
+}
+
+static u32 hash_calculate_le(const void *buffer, u32 count)
+{
+       return do_calculate_hash(buffer, count, 0xffffffff, true);
+}
+
+u32 hash_calculate(const void *buffer, u32 count)
+{
+       return do_calculate_hash(buffer, count, 0xffffffff, false);
+}
+
+static u32 hash_calculate_ram(const void *buffer, u32 ram_size)
+{
+       u32 hash;
+
+       if (ram_disabled)
+               hash = hash_calculate_le(cache_buf, sizeof(cache_buf));
+       else
+               hash = hash_calculate_le(buffer, sizeof(cache_buf));
+
+       return do_calculate_hash(buffer + sizeof(cache_buf),
+                                ram_size - sizeof(cache_buf),
+                                hash, true);
+}
+
+static const char * const mips_regs[] = {
+       "zero",
+       "at",
+       "v0", "v1",
+       "a0", "a1", "a2", "a3",
+       "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
+       "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+       "t8", "t9",
+       "k0", "k1",
+       "gp", "sp", "fp", "ra",
+       "lo", "hi",
+};
+
+static void print_for_big_ass_debugger(void)
+{
+       struct lightrec_registers *regs;
+       unsigned int i;
+
+       regs = lightrec_get_registers(lightrec_state);
+
+       printf("CYCLE 0x%08x PC 0x%08x", psxRegs.cycle, psxRegs.pc);
+
+       if (lightrec_very_debug)
+               printf(" RAM 0x%08x SCRATCH 0x%08x HW 0x%08x",
+                               hash_calculate_ram(psxM, 0x200000),
+                               hash_calculate_le(psxH, 0x400),
+                               hash_calculate_le(psxH + 0x1000, 0x2000));
+
+       printf(" CP0 0x%08x CP2D 0x%08x CP2C 0x%08x INT 0x%04x INTCYCLE 0x%08x GPU 0x%08x",
+                       hash_calculate(regs->cp0, sizeof(regs->cp0)),
+                       hash_calculate(regs->cp2d, sizeof(regs->cp2d)),
+                       hash_calculate(regs->cp2c, sizeof(regs->cp2c)),
+                       psxRegs.interrupt,
+                       hash_calculate(psxRegs.intCycle, sizeof(psxRegs.intCycle)),
+                       LE32TOH(HW_GPU_STATUS));
+
+       if (lightrec_very_debug) {
+               for (i = 0; i < 32; i++)
+                       printf(" CP2D%u 0x%08x", i, regs->cp2d[i]);
+               for (i = 0; i < 32; i++)
+                       printf(" CP2C%u 0x%08x", i, regs->cp2c[i]);
+       }
+
+       if (lightrec_very_debug)
+               for (i = 0; i < 34; i++)
+                       printf(" %s 0x%08x", mips_regs[i], regs->gpr[i]);
+       else
+               printf(" GPR 0x%08x",
+                      hash_calculate(regs->gpr, sizeof(regs->gpr)));
+       printf("\n");
+
+       fflush(stdout);
+}
+
 static void lightrec_plugin_sync_regs_to_pcsx(bool need_cp2);
 static void lightrec_plugin_sync_regs_from_pcsx(bool need_cp2);
 
@@ -488,6 +601,7 @@ static void lightrec_plugin_execute_internal(bool block_only)
 {
        struct lightrec_registers *regs;
        u32 flags, cycles_pcsx;
+       u32 old_pc = psxRegs.pc;
 
        regs = lightrec_get_registers(lightrec_state);
        gen_interupt((psxCP0Regs *)regs->cp0);
@@ -522,6 +636,8 @@ static void lightrec_plugin_execute_internal(bool block_only)
                if (flags & LIGHTREC_EXIT_SEGFAULT) {
                        fprintf(stderr, "Exiting at cycle 0x%08x\n",
                                psxRegs.cycle);
+                       if (lightrec_debug)
+                               print_for_big_ass_debugger();
                        exit(1);
                }
 
@@ -542,6 +658,10 @@ static void lightrec_plugin_execute_internal(bool block_only)
                }
        }
 
+       if (lightrec_debug && psxRegs.cycle >= lightrec_begin_cycles && psxRegs.pc != old_pc) {
+               print_for_big_ass_debugger();
+       }
+
        if ((regs->cp0[13] & regs->cp0[12] & 0x300) && (regs->cp0[12] & 0x1)) {
                /* Handle software interrupts */
                regs->cp0[13] &= ~0x7c;
@@ -552,7 +672,7 @@ static void lightrec_plugin_execute_internal(bool block_only)
 static void lightrec_plugin_execute(psxRegisters *regs)
 {
        while (!regs->stop)
-               lightrec_plugin_execute_internal(false);
+               lightrec_plugin_execute_internal(lightrec_very_debug);
 }
 
 static void lightrec_plugin_execute_block(psxRegisters *regs,