From 853ae0bbe2d9701e3b13a2ba97da1e064d2346aa Mon Sep 17 00:00:00 2001 From: James Lambert Date: Mon, 8 Mar 2021 09:19:35 -0700 Subject: [PATCH] Move debug hooks to a common location Add debug hooks to RSP Allow gdb stub to debug RSP --- CMakeLists.txt | 2 +- common/debug_hooks.c | 47 +++++++++++++++ common/debug_hooks.h | 45 +++++++++++++++ device/device.c | 4 +- device/device.h | 2 +- gdb/gdb.c | 6 +- gdb/gdb.h | 1 + gdb/protocol.c | 133 ++++++++++++++++++++++++++++++++++++++----- gdb/protocol.h | 3 +- rsp/cpu.c | 28 +++++++++ rsp/cpu.h | 3 + rsp/interface.h | 9 +++ rsp/pipeline.c | 4 ++ vr4300/cpu.c | 12 ++-- vr4300/cpu.h | 4 +- vr4300/debug.c | 55 ------------------ vr4300/debug.h | 38 ------------- vr4300/fault.c | 8 +-- vr4300/interface.c | 7 +-- vr4300/interface.h | 12 +--- vr4300/pipeline.c | 2 +- 21 files changed, 283 insertions(+), 142 deletions(-) create mode 100644 common/debug_hooks.c create mode 100644 common/debug_hooks.h delete mode 100644 vr4300/debug.c delete mode 100644 vr4300/debug.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ee1ba50c..e76047221 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -267,6 +267,7 @@ set(BUS_SOURCES set(COMMON_SOURCES ${PROJECT_SOURCE_DIR}/common/debug.c + ${PROJECT_SOURCE_DIR}/common/debug_hooks.c ${PROJECT_SOURCE_DIR}/common/hash_table.c ${PROJECT_SOURCE_DIR}/common/one_hot.c ${PROJECT_SOURCE_DIR}/common/reciprocal.c @@ -370,7 +371,6 @@ set(VR4300_SOURCES ${PROJECT_SOURCE_DIR}/vr4300/cpu.c ${PROJECT_SOURCE_DIR}/vr4300/dcache.c ${PROJECT_SOURCE_DIR}/vr4300/decoder.c - ${PROJECT_SOURCE_DIR}/vr4300/debug.c ${PROJECT_SOURCE_DIR}/vr4300/fault.c ${PROJECT_SOURCE_DIR}/vr4300/functions.c ${PROJECT_SOURCE_DIR}/vr4300/icache.c diff --git a/common/debug_hooks.c b/common/debug_hooks.c new file mode 100644 index 000000000..bfc60b02f --- /dev/null +++ b/common/debug_hooks.c @@ -0,0 +1,47 @@ + +#include "debug_hooks.h" + +cen64_cold void debug_init(struct debug_hooks* debug, enum debug_source source) { + hash_table_init(&debug->breakpoints, 0); + debug->break_handler = NULL; + debug->break_handler_data = NULL; + debug->source = source; +} + +cen64_cold void debug_cleanup(struct debug_hooks* debug) { + hash_table_free(&debug->breakpoints); +} + +cen64_cold void debug_check_breakpoints(struct debug_hooks* debug, uint64_t pc) { + if (debug->break_handler) { + enum debug_break_reason reason = DEBUG_BREAK_REASON_NONE; + if (hash_table_get(&debug->breakpoints, (unsigned long)pc, NULL)) { + reason = DEBUG_BREAK_REASON_BREAKPOINT; + } else if (debug->signals & DEBUG_SIGNALS_BREAK) { + reason = DEBUG_BREAK_REASON_PAUSE; + } + + if (reason != DEBUG_BREAK_REASON_NONE) { + debug->signals &= ~DEBUG_SIGNALS_BREAK; + debug->break_handler(debug->break_handler_data, reason, debug->source); + } + } +} + +cen64_cold void debug_exception(struct debug_hooks* debug) { + if (debug->break_handler) { + debug->break_handler(debug->break_handler_data, DEBUG_BREAK_REASON_EXCEPTION, debug->source); + } +} + +cen64_cold void debug_set_breakpoint(struct debug_hooks* debug, uint64_t pc) { + hash_table_set(&debug->breakpoints, (unsigned long)pc, 1); +} + +cen64_cold void debug_remove_breakpoint(struct debug_hooks* debug, uint64_t pc) { + hash_table_delete(&debug->breakpoints, (unsigned long)pc); +} + +cen64_cold void debug_signal(struct debug_hooks* debug, enum debug_signals signal) { + debug->signals |= signal; +} \ No newline at end of file diff --git a/common/debug_hooks.h b/common/debug_hooks.h new file mode 100644 index 000000000..c5a58d6c2 --- /dev/null +++ b/common/debug_hooks.h @@ -0,0 +1,45 @@ + +#ifndef __common_debug_hooks__ +#define __common_debug_hooks__ + +#include "common.h" +#include "common/hash_table.h" + +enum debug_break_reason { + DEBUG_BREAK_REASON_NONE, + DEBUG_BREAK_REASON_BREAKPOINT, + DEBUG_BREAK_REASON_EXCEPTION, + DEBUG_BREAK_REASON_PAUSE, +}; + +enum debug_source { + DEBUG_SOURCE_VR4300, + DEBUG_SOURCE_RSP, +}; + +typedef void (*debug_break_handler)(void* data, enum debug_break_reason reason, enum debug_source source); + +enum debug_signals { + DEBUG_SIGNALS_BREAK = 0x000000001, +}; + +struct debug_hooks { + struct hash_table breakpoints; + debug_break_handler break_handler; + void* break_handler_data; + unsigned signals; + enum debug_source source; +}; + +void debug_init(struct debug_hooks* debug, enum debug_source source); + +void debug_cleanup(struct debug_hooks* debug); +void debug_check_breakpoints(struct debug_hooks* debug, uint64_t pc); +void debug_exception(struct debug_hooks* debug); +void debug_set_breakpoint(struct debug_hooks* debug, uint64_t pc); +void debug_remove_breakpoint(struct debug_hooks* debug, uint64_t pc); + +void debug_signal(struct debug_hooks* debug, enum debug_signals signal); + + +#endif \ No newline at end of file diff --git a/device/device.c b/device/device.c index cd5a046c6..96d855980 100644 --- a/device/device.c +++ b/device/device.c @@ -23,6 +23,7 @@ #include "ri/controller.h" #include "si/controller.h" #include "rsp/cpu.h" +#include "rsp/interface.h" #include "thread.h" #include "vi/controller.h" #include "vr4300/interface.h" @@ -349,6 +350,7 @@ int device_debug_spin(struct cen64_device *device) { return 0; } -cen64_cold void device_connect_debugger(struct cen64_device *device, void* break_handler_data, vr4300_debug_break_handler break_handler) { +cen64_cold void device_connect_debugger(struct cen64_device *device, void* break_handler_data, debug_break_handler break_handler) { vr4300_connect_debugger(device->vr4300, break_handler_data, break_handler); + rsp_connect_debugger(&device->rsp, break_handler_data, break_handler); } \ No newline at end of file diff --git a/device/device.h b/device/device.h index 81709c25a..62aa336f4 100644 --- a/device/device.h +++ b/device/device.h @@ -67,7 +67,7 @@ cen64_cold struct cen64_device *device_create(struct cen64_device *device, cen64_cold void device_exit(struct bus_controller *bus); cen64_cold void device_run(struct cen64_device *device); -cen64_cold void device_connect_debugger(struct cen64_device *device, void* break_handler_data, vr4300_debug_break_handler break_handler); +cen64_cold void device_connect_debugger(struct cen64_device *device, void* break_handler_data, debug_break_handler break_handler); #endif diff --git a/gdb/gdb.c b/gdb/gdb.c index 021784d58..617ecf101 100644 --- a/gdb/gdb.c +++ b/gdb/gdb.c @@ -22,7 +22,7 @@ #include #endif -cen64_cold void gdb_handle_breakpoint(void* data, enum vr4300_debug_break_reason reason); +cen64_cold void gdb_handle_breakpoint(void* data, enum debug_break_reason reason, enum debug_source source); int gdb_read(struct gdb* gdb) { if (gdb->pending_data >= MAX_GDB_PACKET_SIZE) { @@ -142,7 +142,7 @@ CEN64_THREAD_RETURN_TYPE gdb_thread(void *opaque) { return CEN64_THREAD_RETURN_VAL; } -cen64_cold void gdb_handle_breakpoint(void* data, enum vr4300_debug_break_reason reason) { +cen64_cold void gdb_handle_breakpoint(void* data, enum debug_break_reason reason, enum debug_source source) { struct gdb* gdb = (struct gdb*)data; debug("Stopping at 0x%08x\n", (uint32_t)vr4300_get_pc(gdb->device->vr4300)); @@ -154,7 +154,7 @@ cen64_cold void gdb_handle_breakpoint(void* data, enum vr4300_debug_break_reason vr4300_remove_breakpoint(gdb->device->vr4300, 0xFFFFFFFF80000000ULL); cen64_cv_signal(&gdb->client_semaphore); } else { - gdb_send_stop_reply(gdb, reason == VR4300_DEBUG_BREAK_REASON_BREAKPOINT); + gdb_send_stop_reply(gdb, reason == DEBUG_BREAK_REASON_BREAKPOINT, source); } cen64_mutex_lock(&gdb->client_mutex); diff --git a/gdb/gdb.h b/gdb/gdb.h index cd71630c7..112f9c43a 100644 --- a/gdb/gdb.h +++ b/gdb/gdb.h @@ -20,6 +20,7 @@ enum gdb_flags { GDB_FLAGS_INITIAL = 0x1, GDB_FLAGS_CONNECTED = 0x2, GDB_FLAGS_PAUSED = 0x4, + GDB_FLAGS_RSP_SELECTED = 0x8, }; struct gdb { diff --git a/gdb/protocol.c b/gdb/protocol.c index 18a778690..e1b529954 100644 --- a/gdb/protocol.c +++ b/gdb/protocol.c @@ -11,6 +11,7 @@ #include "gdb/protocol.h" #include "gdb/gdb.h" #include "vr4300/cpu.h" +#include "rsp/interface.h" #include @@ -25,11 +26,22 @@ #include #endif +#define GDB_GLOBAL_THREAD_ID 1 +#define GDB_RSP_THEAD_ID 2 + #define GDB_GET_EXC_CODE(cause) (((cause) >> 2) & 0x1f) #define GDB_TRANSLATE_PC(pc) ((uint64_t)(pc) | 0xFFFFFFFF00000000ULL) -#define GDB_GLOBAL_THREAD_ID 1 #define GDB_STR_STARTS_WITH(str, const_str) (strncmp(str, const_str, sizeof const_str - 1) == 0) +#define GDB_RSP_MEMORY_BASE 0x04000000 +#define GDB_RSP_INSTRUCTION_BASE 0x04001000 +#define GDB_RSP_INSTRUCTION_END 0x04002000 +#define GDB_RSP_INSTRUCTION_SIZE 0x1000 + +// not standard just used to allow GDB to access vector registers +#define GDB_RSP_VREG_BASE 0x04020000 +#define GDB_RSP_VREG_LEN 512 + static int gdb_signals[32] = { 2, // SIGINT 11, // SIGSEGV @@ -65,6 +77,34 @@ static int gdb_signals[32] = { 0, // reserved }; +bool gdb_is_rsp_addr(uint64_t addr) { + return addr >= GDB_RSP_MEMORY_BASE && addr < GDB_RSP_INSTRUCTION_END; +} + +bool gdb_is_rsp_instruction(uint64_t addr) { + return (addr & 0xFFFFFFFF) < GDB_RSP_INSTRUCTION_SIZE; +} + +bool gdb_is_rsp_register(uint64_t addr) { + return addr >= GDB_RSP_VREG_BASE && addr < GDB_RSP_VREG_BASE + GDB_RSP_VREG_LEN; +} + +void gdb_set_breakpoint(struct cen64_device* device, uint64_t addr) { + if (gdb_is_rsp_instruction(addr)) { + rsp_set_breakpoint(&device->rsp, addr & 0xFFF); + } else { + vr4300_set_breakpoint(device->vr4300, addr); + } +} + +void gdb_remove_breakpoint(struct cen64_device* device, uint64_t addr) { + if (gdb_is_rsp_instruction(addr)) { + rsp_remove_breakpoint(&device->rsp, addr & 0xFFF); + } else { + vr4300_remove_breakpoint(device->vr4300, addr); + } +} + int gdb_read_hex_digit(char character) { if (character >= 'a' && character <= 'f') { return 10 + character - 'a'; @@ -110,6 +150,17 @@ char* gdb_write_hex64(char* target, uint64_t data, int data_size) { return target; } +char* gdb_write_hexstring(char* target, const char* src) { + while (*src) { + *target++ = gdb_hex_letters[(*src >> 4) & 0xF]; + *target++ = gdb_hex_letters[(*src >> 0) & 0xF]; + src++; + } + + return target; + +} + int gdb_apply_checksum(char* message) { char* message_start = message; if (*message == '$') { @@ -207,7 +258,7 @@ void gdb_handle_v(struct gdb* gdb, const char* command_start, const char *comman } } -void gdb_reply_registers(struct gdb* gdb) { +void gdb_reply_vr4300_registers(struct gdb* gdb) { char* current = gdb->output_buffer; *current++ = '$'; @@ -236,6 +287,43 @@ void gdb_reply_registers(struct gdb* gdb) { gdb_send(gdb); } +void gdb_reply_rsp_registers(struct gdb* gdb) { + char* current = gdb->output_buffer; + *current++ = '$'; + + // R0 + current = gdb_write_hex64(current, 0, sizeof(uint64_t)); + for (int i = RSP_REGISTER_AT; i <= RSP_REGISTER_RA; i++) { + current = gdb_write_hex64(current, rsp_get_register(&gdb->device->rsp, i), sizeof(uint64_t)); + } + + current = gdb_write_hex64(current, 0, sizeof(uint64_t)); // VR4300_CP0_REGISTER_STATUS + current = gdb_write_hex64(current, 0, sizeof(uint64_t)); // VR4300_REGISTER_LO + current = gdb_write_hex64(current, 0, sizeof(uint64_t)); // VR4300_REGISTER_HI + current = gdb_write_hex64(current, 0, sizeof(uint64_t)); // VR4300_CP0_REGISTER_BADVADDR + current = gdb_write_hex64(current, 0, sizeof(uint64_t)); // VR4300_CP0_REGISTER_CAUSE + current = gdb_write_hex64(current, rsp_get_pc(&gdb->device->rsp), sizeof(uint64_t)); + + for (int i = VR4300_REGISTER_CP1_0; i <= VR4300_REGISTER_CP1_31; i++) { + current = gdb_write_hex64(current, vr4300_get_register(gdb->device->vr4300, i), sizeof(uint64_t)); + } + + current = gdb_write_hex64(current, vr4300_get_register(gdb->device->vr4300, VR4300_CP1_FCR31), sizeof(uint64_t)); + + *current++ = '#'; + *current++ = '\0'; + + gdb_send(gdb); +} + +void gdb_reply_registers(struct gdb* gdb) { + if (gdb->flags & GDB_FLAGS_RSP_SELECTED) { + gdb_reply_rsp_registers(gdb); + } else { + gdb_reply_vr4300_registers(gdb); + } +} + void gdb_reply_memory(struct gdb* gdb, const char* command_start, const char *command_end) { char* current = gdb->output_buffer; *current++ = '$'; @@ -255,14 +343,21 @@ void gdb_reply_memory(struct gdb* gdb, const char* command_start, const char *co for (int curr = 0; curr < len + byteShift; curr += 4) { uint32_t word = 0; int32_t vaddr = alignedAddr + curr; - - if (!vr4300_read_word_vaddr(gdb->device->vr4300, vaddr, &word)) { - debug("Bad vaddr %08x\n", vaddr); - } - // if (curr > 0x20) { - // word = curr; - // } + if ((gdb->flags & GDB_FLAGS_RSP_SELECTED) && gdb_is_rsp_instruction(vaddr)) { + bus_read_word(&gdb->device->bus, vaddr + GDB_RSP_INSTRUCTION_BASE, &word); + } else if (gdb_is_rsp_register(vaddr)) { + int32_t relative = (vaddr - GDB_RSP_VREG_BASE) / sizeof(uint16_t); + int32_t registerIndex = relative / 8; + int32_t elementIndex = relative % 8; + + word = ((int32_t)gdb->device->rsp.cp2.regs[registerIndex].e[elementIndex] << 16) | + (int32_t)gdb->device->rsp.cp2.regs[registerIndex].e[elementIndex + 1]; + } else if (gdb_is_rsp_addr(vaddr)) { + bus_read_word(&gdb->device->bus, vaddr, &word); + } else { + vr4300_read_word_vaddr(gdb->device->vr4300, vaddr, &word); + } current = gdb_write_hex64(current, word, sizeof(uint32_t)); } @@ -296,7 +391,7 @@ void gdb_handle_packet(struct gdb* gdb, const char* command_start, const char* c gdb_send_literal(gdb, "$#00"); break; case '?': - gdb_send_stop_reply(gdb, false); + gdb_send_stop_reply(gdb, false, DEBUG_SOURCE_VR4300); break; case 'g': gdb_reply_registers(gdb); @@ -315,9 +410,9 @@ void gdb_handle_packet(struct gdb* gdb, const char* command_start, const char* c uint64_t addr = GDB_TRANSLATE_PC(gdb_parse_hex(&command_start[3], 4)); if (*command_start == 'z') { - vr4300_remove_breakpoint(gdb->device->vr4300, addr); + gdb_remove_breakpoint(gdb->device, addr); } else { - vr4300_set_breakpoint(gdb->device->vr4300, addr); + gdb_set_breakpoint(gdb->device, addr); } return gdb_send_literal(gdb, "$OK#9a"); @@ -331,15 +426,22 @@ void gdb_handle_packet(struct gdb* gdb, const char* command_start, const char* c } } -cen64_cold void gdb_send_stop_reply(struct gdb* gdb, bool is_breakpoint) { +cen64_cold void gdb_send_stop_reply(struct gdb* gdb, bool is_breakpoint, enum debug_source source) { char* current = gdb->output_buffer; int exc_code; - if (is_breakpoint) { + if (source == DEBUG_SOURCE_RSP) { + gdb->flags |= GDB_FLAGS_RSP_SELECTED; exc_code = 9; } else { - exc_code = GDB_GET_EXC_CODE(vr4300_get_register(gdb->device->vr4300, VR4300_CP0_REGISTER_CAUSE)); + gdb->flags &= ~GDB_FLAGS_RSP_SELECTED; + if (is_breakpoint) { + exc_code = 9; + } else { + exc_code = GDB_GET_EXC_CODE(vr4300_get_register(gdb->device->vr4300, VR4300_CP0_REGISTER_CAUSE)); + } } + current += sprintf(current, "$T%02x", gdb_signals[exc_code]); if (is_breakpoint) { current += sprintf(current, "swbreak:"); @@ -347,5 +449,6 @@ cen64_cold void gdb_send_stop_reply(struct gdb* gdb, bool is_breakpoint) { current += sprintf(current, "thread:%d;", GDB_GLOBAL_THREAD_ID); *current++ = '#'; *current++ = '\0'; + gdb_send(gdb); } \ No newline at end of file diff --git a/gdb/protocol.h b/gdb/protocol.h index c6c6075d7..6e2cc3eb4 100644 --- a/gdb/protocol.h +++ b/gdb/protocol.h @@ -11,10 +11,11 @@ #ifndef _gdb_protocol_h__ #define _gdb_protocol_h__ #include "common.h" +#include "common/debug_hooks.h" struct gdb; -cen64_cold void gdb_send_stop_reply(struct gdb* gdb, bool is_breakpoint); +cen64_cold void gdb_send_stop_reply(struct gdb* gdb, bool is_breakpoint, enum debug_source source); cen64_cold void gdb_handle_packet(struct gdb* gdb, const char* command_start, const char* command_end); diff --git a/rsp/cpu.c b/rsp/cpu.c index 04fd6db18..e9b51cec8 100644 --- a/rsp/cpu.c +++ b/rsp/cpu.c @@ -28,6 +28,7 @@ static void rsp_connect_bus(struct rsp *rsp, struct bus_controller *bus) { // Releases memory acquired for the RSP component. void rsp_destroy(struct rsp *rsp) { arch_rsp_destroy(rsp); + debug_cleanup(&rsp->debug); } // Initializes the RSP component. @@ -37,6 +38,8 @@ int rsp_init(struct rsp *rsp, struct bus_controller *bus) { rsp_cp0_init(rsp); rsp_pipeline_init(&rsp->pipeline); + debug_init(&rsp->debug, DEBUG_SOURCE_RSP); + return arch_rsp_init(rsp); } @@ -52,3 +55,28 @@ void rsp_late_init(struct rsp *rsp) { write_vco_hi(rsp->cp2.flags[RSP_VCO].e, rsp_vzero()); write_vce (rsp->cp2.flags[RSP_VCE].e, rsp_vzero()); } + +void rsp_signal_break(struct rsp *rsp) { + debug_signal(&rsp->debug, DEBUG_SIGNALS_BREAK); +} + +void rsp_set_breakpoint(struct rsp *rsp, uint64_t at) { + debug_set_breakpoint(&rsp->debug, at); +} + +void rsp_remove_breakpoint(struct rsp *rsp, uint64_t at) { + debug_remove_breakpoint(&rsp->debug, at); +} + +uint32_t rsp_get_register(struct rsp *rsp, size_t i) { + return rsp->regs[i]; +} + +uint32_t rsp_get_pc(struct rsp *rsp) { + return rsp->pipeline.dfwb_latch.common.pc; +} + +void rsp_connect_debugger(struct rsp *rsp, void* break_handler_data, debug_break_handler break_handler) { + rsp->debug.break_handler = break_handler; + rsp->debug.break_handler_data = break_handler_data; +} \ No newline at end of file diff --git a/rsp/cpu.h b/rsp/cpu.h index d6517d652..aa3a5c366 100644 --- a/rsp/cpu.h +++ b/rsp/cpu.h @@ -11,6 +11,7 @@ #ifndef __rsp_cpu_h__ #define __rsp_cpu_h__ #include "common.h" +#include "common/debug_hooks.h" #include "os/dynarec.h" #include "rsp/cp0.h" #include "rsp/cp2.h" @@ -65,6 +66,8 @@ struct rsp { // TODO: Only for IA32/x86_64 SSE2; sloppy? struct dynarec_slab vload_dynarec; struct dynarec_slab vstore_dynarec; + + struct debug_hooks debug; }; cen64_cold int rsp_init(struct rsp *rsp, struct bus_controller *bus); diff --git a/rsp/interface.h b/rsp/interface.h index 48ea9073a..26d36b797 100644 --- a/rsp/interface.h +++ b/rsp/interface.h @@ -11,6 +11,7 @@ #ifndef __rsp_interface_h__ #define __rsp_interface_h__ #include "common.h" +#include "common/debug_hooks.h" void rsp_dma_read(struct rsp *rsp); void rsp_dma_write(struct rsp *rsp); @@ -22,5 +23,13 @@ int write_sp_mem(void *opaque, uint32_t address, uint32_t word, uint32_t dqm); int write_sp_regs(void *opaque, uint32_t address, uint32_t word, uint32_t dqm); int write_sp_regs2(void *opaque, uint32_t address, uint32_t word, uint32_t dqm); +uint32_t rsp_get_register(struct rsp *rsp, size_t i); +uint32_t rsp_get_pc(struct rsp *rsp); + +void rsp_signal_break(struct rsp *rsp); +void rsp_set_breakpoint(struct rsp *rsp, uint64_t at); +void rsp_remove_breakpoint(struct rsp *rsp, uint64_t at); +void rsp_connect_debugger(struct rsp *rsp, void* break_handler_data, debug_break_handler break_handler); + #endif diff --git a/rsp/pipeline.c b/rsp/pipeline.c index 808c23e48..a0e40e424 100644 --- a/rsp/pipeline.c +++ b/rsp/pipeline.c @@ -13,6 +13,7 @@ #include "rsp/cp2.h" #include "rsp/cpu.h" #include "rsp/decoder.h" +#include "rsp/interface.h" #include "rsp/opcodes.h" #include "rsp/pipeline.h" #include "rsp/rsp.h" @@ -215,11 +216,14 @@ static inline void rsp_wb_stage(struct rsp *rsp) { // Advances the processor pipeline by one clock. void rsp_cycle_(struct rsp *rsp) { rsp_wb_stage(rsp); + rsp_df_stage(rsp); rsp->pipeline.exdf_latch.result.dest = RSP_REGISTER_R0; rsp->pipeline.exdf_latch.request.type = RSP_MEM_REQUEST_NONE; + debug_check_breakpoints(&rsp->debug, rsp_get_pc(rsp)); + rsp_v_ex_stage(rsp); rsp_ex_stage(rsp); diff --git a/vr4300/cpu.c b/vr4300/cpu.c index c238ec14a..55ff1ed6d 100644 --- a/vr4300/cpu.c +++ b/vr4300/cpu.c @@ -70,7 +70,7 @@ int vr4300_init(struct vr4300 *vr4300, struct bus_controller *bus, bool profilin else vr4300->profile_samples = NULL; - vr4300_debug_init(&vr4300->debug); + debug_init(&vr4300->debug, DEBUG_SOURCE_VR4300); return 0; } @@ -136,15 +136,15 @@ uint64_t vr4300_get_pc(struct vr4300 *vr4300) { } cen64_cold void vr4300_signal_break(struct vr4300 *vr4300) { - vr4300_debug_signal(&vr4300->debug, VR4300_DEBUG_SIGNALS_BREAK); + debug_signal(&vr4300->debug, DEBUG_SIGNALS_BREAK); } cen64_cold void vr4300_set_breakpoint(struct vr4300 *vr4300, uint64_t at) { - vr4300_debug_set_breakpoint(&vr4300->debug, at); + debug_set_breakpoint(&vr4300->debug, at); } cen64_cold void vr4300_remove_breakpoint(struct vr4300 *vr4300, uint64_t at) { - vr4300_debug_remove_breakpoint(&vr4300->debug, at); + debug_remove_breakpoint(&vr4300->debug, at); } struct vr4300* vr4300_alloc() { @@ -154,7 +154,7 @@ struct vr4300* vr4300_alloc() { } cen64_cold void vr4300_free(struct vr4300* ptr) { - vr4300_debug_cleanup(&ptr->debug); + debug_cleanup(&ptr->debug); free(ptr); } @@ -168,7 +168,7 @@ cen64_cold void vr4300_stats_free(struct vr4300_stats* ptr) { free(ptr); } -cen64_cold void vr4300_connect_debugger(struct vr4300 *vr4300, void* break_handler_data, vr4300_debug_break_handler break_handler) { +cen64_cold void vr4300_connect_debugger(struct vr4300 *vr4300, void* break_handler_data, debug_break_handler break_handler) { vr4300->debug.break_handler = break_handler; vr4300->debug.break_handler_data = break_handler_data; } \ No newline at end of file diff --git a/vr4300/cpu.h b/vr4300/cpu.h index 423a29a94..6351fc625 100644 --- a/vr4300/cpu.h +++ b/vr4300/cpu.h @@ -11,10 +11,10 @@ #ifndef __vr4300_cpu_h__ #define __vr4300_cpu_h__ #include "common.h" +#include "common/debug_hooks.h" #include "vr4300/cp0.h" #include "vr4300/cp1.h" #include "vr4300/dcache.h" -#include "vr4300/debug.h" #include "vr4300/icache.h" #include "vr4300/interface.h" #include "vr4300/opcodes.h" @@ -107,7 +107,7 @@ struct vr4300 { uint64_t *profile_samples; - struct vr4300_debug debug; + struct debug_hooks debug; }; struct vr4300_stats { diff --git a/vr4300/debug.c b/vr4300/debug.c deleted file mode 100644 index 19f2ace15..000000000 --- a/vr4300/debug.c +++ /dev/null @@ -1,55 +0,0 @@ -// -// vr4300/debug.c: VR4300 debug hooks. -// -// CEN64: Cycle-Accurate Nintendo 64 Emulator. -// Copyright (C) 2015, Tyler J. Stachecki. -// -// This file is subject to the terms and conditions defined in -// 'LICENSE', which is part of this source code package. -// - -#include "debug.h" - -cen64_cold void vr4300_debug_init(struct vr4300_debug* debug) { - hash_table_init(&debug->breakpoints, 0); - debug->break_handler = NULL; - debug->break_handler_data = NULL; -} - -cen64_cold void vr4300_debug_cleanup(struct vr4300_debug* debug) { - hash_table_free(&debug->breakpoints); -} - -cen64_cold void vr4300_debug_check_breakpoints(struct vr4300_debug* debug, uint64_t pc) { - if (debug->break_handler) { - enum vr4300_debug_break_reason reason = VR4300_DEBUG_BREAK_REASON_NONE; - if (hash_table_get(&debug->breakpoints, (unsigned long)pc, NULL)) { - reason = VR4300_DEBUG_BREAK_REASON_BREAKPOINT; - } else if (debug->signals & VR4300_DEBUG_SIGNALS_BREAK) { - reason = VR4300_DEBUG_BREAK_REASON_PAUSE; - } - - if (reason != VR4300_DEBUG_BREAK_REASON_NONE) { - debug->signals &= ~VR4300_DEBUG_SIGNALS_BREAK; - debug->break_handler(debug->break_handler_data, reason); - } - } -} - -cen64_cold void vr4300_debug_exception(struct vr4300_debug* debug) { - if (debug->break_handler) { - debug->break_handler(debug->break_handler_data, VR4300_DEBUG_BREAK_REASON_EXCEPTION); - } -} - -cen64_cold void vr4300_debug_set_breakpoint(struct vr4300_debug* debug, uint64_t pc) { - hash_table_set(&debug->breakpoints, (unsigned long)pc, 1); -} - -cen64_cold void vr4300_debug_remove_breakpoint(struct vr4300_debug* debug, uint64_t pc) { - hash_table_delete(&debug->breakpoints, (unsigned long)pc); -} - -cen64_cold void vr4300_debug_signal(struct vr4300_debug* debug, enum vr4300_debug_signals signal) { - debug->signals |= signal; -} \ No newline at end of file diff --git a/vr4300/debug.h b/vr4300/debug.h deleted file mode 100644 index f4a613c12..000000000 --- a/vr4300/debug.h +++ /dev/null @@ -1,38 +0,0 @@ -// -// vr4300/debug.h: VR4300 debug hooks. -// -// CEN64: Cycle-Accurate Nintendo 64 Emulator. -// Copyright (C) 2015, Tyler J. Stachecki. -// -// This file is subject to the terms and conditions defined in -// 'LICENSE', which is part of this source code package. -// - -#ifndef __vr4300_debug_h__ -#define __vr4300_debug_h__ -#include "common.h" -#include "common/hash_table.h" -#include "vr4300/interface.h" - -enum vr4300_debug_signals { - VR4300_DEBUG_SIGNALS_BREAK = 0x000000001, -}; - -struct vr4300_debug { - struct hash_table breakpoints; - vr4300_debug_break_handler break_handler; - void* break_handler_data; - unsigned signals; -}; - -cen64_cold void vr4300_debug_init(struct vr4300_debug* debug); - -cen64_cold void vr4300_debug_cleanup(struct vr4300_debug* debug); -cen64_cold void vr4300_debug_check_breakpoints(struct vr4300_debug* debug, uint64_t pc); -cen64_cold void vr4300_debug_exception(struct vr4300_debug* debug); -cen64_cold void vr4300_debug_set_breakpoint(struct vr4300_debug* debug, uint64_t pc); -cen64_cold void vr4300_debug_remove_breakpoint(struct vr4300_debug* debug, uint64_t pc); - -cen64_cold void vr4300_debug_signal(struct vr4300_debug* debug, enum vr4300_debug_signals signal); - -#endif \ No newline at end of file diff --git a/vr4300/fault.c b/vr4300/fault.c index 7fc8f653b..ddac86ca7 100644 --- a/vr4300/fault.c +++ b/vr4300/fault.c @@ -345,7 +345,7 @@ void VR4300_DTLB(struct vr4300 *vr4300, unsigned miss, unsigned inv, unsigned mo vr4300_exception_epilogue(vr4300, (cause & ~0xFF) | (type << 2), status, epc, offs); - vr4300_debug_exception(&vr4300->debug); + debug_exception(&vr4300->debug); } // IADE: Instruction address error exception. @@ -484,7 +484,7 @@ void VR4300_BRPT(struct vr4300 *vr4300) { vr4300_exception_prolog(vr4300, common, &cause, &status, &epc); vr4300_exception_epilogue(vr4300, (cause & ~0xFF) | (9 << 2), status, epc, 0x180); - vr4300_debug_exception(&vr4300->debug); + debug_exception(&vr4300->debug); } // TRAP: Trap exception @@ -497,7 +497,7 @@ void VR4300_TRAP(struct vr4300* vr4300) { vr4300_exception_prolog(vr4300, common, &cause, &status, &epc); vr4300_exception_epilogue(vr4300, (cause & ~0xFF) | (13 << 2), status, epc, 0x180); - vr4300_debug_exception(&vr4300->debug); + debug_exception(&vr4300->debug); } // RI: Reserved Instruction exception @@ -524,6 +524,6 @@ void VR4300_WAT(struct vr4300 *vr4300) { status, epc, 0x180); vr4300_dc_fault(vr4300, VR4300_FAULT_WAT); - vr4300_debug_exception(&vr4300->debug); + debug_exception(&vr4300->debug); } diff --git a/vr4300/interface.c b/vr4300/interface.c index 9250d2aa5..6e17bd5eb 100644 --- a/vr4300/interface.c +++ b/vr4300/interface.c @@ -231,12 +231,11 @@ bool vr4300_read_word_vaddr(struct vr4300 *vr4300, uint64_t vaddr, uint32_t* res if (line) { memcpy(result, line->data + ((paddr & 0xf) ^ WORD_ADDR_XOR), sizeof(uint32_t)); + return true; } else { - bus_read_word(vr4300->bus, paddr, result); + return bus_read_word(vr4300->bus, paddr, result) != 0; } } else { - bus_read_word(vr4300->bus, paddr, result); + return bus_read_word(vr4300->bus, paddr, result) != 0; } - - return true; } \ No newline at end of file diff --git a/vr4300/interface.h b/vr4300/interface.h index e77a4a09c..928136f3a 100644 --- a/vr4300/interface.h +++ b/vr4300/interface.h @@ -11,6 +11,7 @@ #ifndef __vr4300_interface_h__ #define __vr4300_interface_h__ #include "common.h" +#include "common/debug_hooks.h" enum rcp_interrupt_mask { MI_INTR_SP = 0x01, @@ -24,15 +25,6 @@ enum rcp_interrupt_mask { struct vr4300; struct vr4300_stats; -enum vr4300_debug_break_reason { - VR4300_DEBUG_BREAK_REASON_NONE, - VR4300_DEBUG_BREAK_REASON_BREAKPOINT, - VR4300_DEBUG_BREAK_REASON_EXCEPTION, - VR4300_DEBUG_BREAK_REASON_PAUSE, -}; - -typedef void (*vr4300_debug_break_handler)(void* data, enum vr4300_debug_break_reason reason); - cen64_cold struct vr4300* vr4300_alloc(); cen64_cold void vr4300_free(struct vr4300*); @@ -65,7 +57,7 @@ int has_profile_samples(struct vr4300 const *vr4300); cen64_cold void vr4300_signal_break(struct vr4300 *vr4300); cen64_cold void vr4300_set_breakpoint(struct vr4300 *vr4300, uint64_t at); cen64_cold void vr4300_remove_breakpoint(struct vr4300 *vr4300, uint64_t at); -cen64_cold void vr4300_connect_debugger(struct vr4300 *vr4300, void* break_handler_data, vr4300_debug_break_handler break_handler); +cen64_cold void vr4300_connect_debugger(struct vr4300 *vr4300, void* break_handler_data, debug_break_handler break_handler); #endif diff --git a/vr4300/pipeline.c b/vr4300/pipeline.c index 46204004e..c6c16195a 100644 --- a/vr4300/pipeline.c +++ b/vr4300/pipeline.c @@ -522,7 +522,7 @@ void vr4300_cycle_(struct vr4300 *vr4300) { if (vr4300_wb_stage(vr4300)) return; - vr4300_debug_check_breakpoints(&vr4300->debug, vr4300_get_pc(vr4300)); + debug_check_breakpoints(&vr4300->debug, vr4300_get_pc(vr4300)); if (vr4300_dc_stage(vr4300)) return;