mirror of
https://github.com/n64dev/cen64.git
synced 2024-06-15 10:37:48 -04:00
Implement debugging hooks into vr4300
This commit is contained in:
parent
13720b1e29
commit
2865d107e4
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
24
vr4300/cpu.c
24
vr4300/cpu.c
|
@ -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;
|
||||
}
|
|
@ -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
55
vr4300/debug.c
Normal 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
38
vr4300/debug.h
Normal 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
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue