Implement debugging hooks into vr4300

This commit is contained in:
James Lambert 2021-01-10 17:07:21 -07:00
parent 13720b1e29
commit 2865d107e4
12 changed files with 197 additions and 9 deletions

View file

@ -365,6 +365,7 @@ 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

View file

@ -55,11 +55,5 @@ cen64_flatten cen64_hot int bus_read_word(const struct bus_controller *bus,
cen64_flatten cen64_hot int bus_write_word(struct bus_controller *bus,
uint32_t address, uint32_t word, uint32_t dqm);
// For asserting and deasserting RCP interrupts.
enum rcp_interrupt_mask;
int raise_rcp_interrupt(struct bus_controller *bus,
enum rcp_interrupt_mask mask);
#endif

View file

@ -349,3 +349,6 @@ 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) {
vr4300_connect_debugger(device->vr4300, break_handler_data, break_handler);
}

View file

@ -67,5 +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);
#endif

View file

@ -70,6 +70,8 @@ int vr4300_init(struct vr4300 *vr4300, struct bus_controller *bus, bool profilin
else
vr4300->profile_samples = NULL;
vr4300_debug_init(&vr4300->debug);
return 0;
}
@ -126,11 +128,23 @@ void vr4300_print_summary(struct vr4300_stats *stats) {
}
uint64_t vr4300_get_register(struct vr4300 *vr4300, size_t i) {
return vr4300->regs[i];
return vr4300->regs[i];
}
uint64_t vr4300_get_pc(struct vr4300 *vr4300) {
return vr4300->pipeline.dcwb_latch.common.pc;
return vr4300->pipeline.dcwb_latch.common.pc;
}
cen64_cold void vr4300_signal_break(struct vr4300 *vr4300) {
vr4300_debug_signal(&vr4300->debug, VR4300_DEBUG_SIGNALS_BREAK);
}
cen64_cold void vr4300_set_breakpoint(struct vr4300 *vr4300, uint64_t at) {
vr4300_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);
}
struct vr4300* vr4300_alloc() {
@ -140,6 +154,7 @@ struct vr4300* vr4300_alloc() {
}
cen64_cold void vr4300_free(struct vr4300* ptr) {
vr4300_debug_cleanup(&ptr->debug);
free(ptr);
}
@ -152,3 +167,8 @@ cen64_cold struct vr4300_stats* vr4300_stats_alloc() {
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) {
vr4300->debug.break_handler = break_handler;
vr4300->debug.break_handler_data = break_handler_data;
}

View file

@ -14,7 +14,9 @@
#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"
#include "vr4300/pipeline.h"
@ -23,6 +25,7 @@ struct bus_controller;
enum vr4300_signals {
VR4300_SIGNAL_FORCEEXIT = 0x000000001,
VR4300_SIGNAL_COLDRESET = 0x000000002,
VR4300_SIGNAL_BREAK = 0x000000004,
};
enum vr4300_register {
@ -103,6 +106,8 @@ struct vr4300 {
struct vr4300_icache icache;
uint64_t *profile_samples;
struct vr4300_debug debug;
};
struct vr4300_stats {
@ -112,7 +117,6 @@ struct vr4300_stats {
unsigned long opcode_counts[NUM_VR4300_OPCODES];
};
cen64_cold int vr4300_init(struct vr4300 *vr4300, struct bus_controller *bus, bool profiling);
cen64_cold void vr4300_print_summary(struct vr4300_stats *stats);
cen64_flatten cen64_hot void vr4300_cycle_(struct vr4300 *vr4300);

55
vr4300/debug.c Normal file
View file

@ -0,0 +1,55 @@
//
// 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;
}

38
vr4300/debug.h Normal file
View file

@ -0,0 +1,38 @@
//
// 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

View file

@ -483,6 +483,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);
}
// TRAP: Trap exception
@ -495,6 +496,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);
}
// RI: Reserved Instruction exception
@ -521,5 +523,6 @@ void VR4300_WAT(struct vr4300 *vr4300) {
status, epc, 0x180);
vr4300_dc_fault(vr4300, VR4300_FAULT_WAT);
vr4300_debug_exception(&vr4300->debug);
}

View file

@ -10,6 +10,7 @@
#include "common.h"
#include "bus/address.h"
#include "bus/controller.h"
#include "vr4300/cpu.h"
#include "vr4300/interface.h"
#ifdef _WIN32
@ -190,3 +191,52 @@ uint64_t get_profile_sample(struct vr4300 const *vr4300, size_t i)
return vr4300->profile_samples[i];
}
bool vr4300_read_word_vaddr(struct vr4300 *vr4300, uint64_t vaddr, uint32_t* result) {
if (vaddr & 0x3) {
// must be aligned
return false;
}
const struct segment* segment = get_segment(vaddr, vr4300->regs[VR4300_CP0_REGISTER_STATUS]);
if (!segment) {
return false;
}
uint32_t paddr;
bool cached;
if (segment->mapped) {
unsigned asid = vr4300->regs[VR4300_CP0_REGISTER_ENTRYHI] & 0xFF;
unsigned select, tlb_miss, index;
uint32_t page_mask;
tlb_miss = tlb_probe(&vr4300->cp0.tlb, vaddr, asid, &index);
page_mask = vr4300->cp0.page_mask[index];
select = ((page_mask + 1) & vaddr) != 0;
if (unlikely(tlb_miss || !(vr4300->cp0.state[index][select] & 2))) {
return false;
}
cached = ((vr4300->cp0.state[index][select] & 0x38) != 0x10);
paddr = (vr4300->cp0.pfn[index][select]) | (vaddr & page_mask);
} else {
paddr = vaddr - segment->offset;
cached = segment->cached;
}
if (cached) {
struct vr4300_dcache_line* line = vr4300_dcache_probe(&vr4300->dcache, vaddr, paddr);
if (line) {
memcpy(result, line->data + ((paddr & 0xf) ^ WORD_ADDR_XOR), sizeof(uint32_t));
} else {
bus_read_word(vr4300->bus, paddr, result);
}
} else {
bus_read_word(vr4300->bus, paddr, result);
}
return true;
}

View file

@ -24,6 +24,15 @@ 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*);
@ -39,6 +48,8 @@ cen64_cold void vr4300_cycle_extra(struct vr4300 *vr4300, struct vr4300_stats *s
uint64_t vr4300_get_register(struct vr4300 *vr4300, size_t i);
uint64_t vr4300_get_pc(struct vr4300 *vr4300);
bool vr4300_read_word_vaddr(struct vr4300 *vr4300, uint64_t vaddr, uint32_t* result);
int read_mi_regs(struct vr4300 *vr4300, uint32_t address, uint32_t *word);
int write_mi_regs(struct vr4300 *vr4300, uint32_t address, uint32_t word, uint32_t dqm);
@ -51,5 +62,10 @@ void signal_dd_interrupt(struct vr4300 *vr4300);
uint64_t get_profile_sample(struct vr4300 const *vr4300, size_t i);
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);
#endif

View file

@ -522,6 +522,8 @@ void vr4300_cycle_(struct vr4300 *vr4300) {
if (vr4300_wb_stage(vr4300))
return;
vr4300_debug_check_breakpoints(&vr4300->debug, vr4300_get_pc(vr4300));
if (vr4300_dc_stage(vr4300))
return;