mirror of https://github.com/inolen/redream.git
reenabled gdb-based debugger
This commit is contained in:
parent
32b1f75e37
commit
08b6b5de1d
|
@ -172,6 +172,7 @@ set(REDREAM_SOURCES
|
|||
src/hw/rom/flash.c
|
||||
src/hw/sh4/sh4.c
|
||||
src/hw/sh4/sh4_ccn.c
|
||||
src/hw/sh4/sh4_dbg.c
|
||||
src/hw/sh4/sh4_dmac.c
|
||||
src/hw/sh4/sh4_intc.c
|
||||
src/hw/sh4/sh4_tmu.c
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
#include "hw/scheduler.h"
|
||||
#include "hw/sh4/sh4.h"
|
||||
|
||||
DEFINE_OPTION_INT(gdb, 0, "Run gdb debug server");
|
||||
|
||||
void dc_poll_input(struct dreamcast *dc) {
|
||||
if (!dc->poll_input) {
|
||||
return;
|
||||
|
@ -198,6 +196,26 @@ struct execute_interface *dc_create_execute_interface(device_run_cb run,
|
|||
return execute;
|
||||
}
|
||||
|
||||
void dc_destroy_debug_interface(struct debug_interface *dbg) {
|
||||
free(dbg);
|
||||
}
|
||||
|
||||
struct debug_interface *dc_create_debug_interface(device_num_regs_cb num_regs,
|
||||
device_step_cb step,
|
||||
device_add_bp_cb add_bp,
|
||||
device_rem_bp_cb rem_bp,
|
||||
device_read_mem_cb read_mem,
|
||||
device_read_reg_cb read_reg) {
|
||||
struct debug_interface *dbg = calloc(1, sizeof(struct debug_interface));
|
||||
dbg->num_regs = num_regs;
|
||||
dbg->step = step;
|
||||
dbg->add_bp = add_bp;
|
||||
dbg->rem_bp = rem_bp;
|
||||
dbg->read_mem = read_mem;
|
||||
dbg->read_reg = read_reg;
|
||||
return dbg;
|
||||
}
|
||||
|
||||
void dc_destroy_device(struct device *dev) {
|
||||
list_remove(&dev->dc->devices, &dev->it);
|
||||
|
||||
|
@ -250,7 +268,9 @@ void dc_destroy(struct dreamcast *dc) {
|
|||
struct dreamcast *dc_create() {
|
||||
struct dreamcast *dc = calloc(1, sizeof(struct dreamcast));
|
||||
|
||||
dc->debugger = OPTION_gdb ? debugger_create(dc) : NULL;
|
||||
#ifndef NDEBUG
|
||||
dc->debugger = debugger_create(dc);
|
||||
#endif
|
||||
dc->memory = memory_create(dc);
|
||||
dc->scheduler = scheduler_create(dc);
|
||||
dc->sh4 = sh4_create(dc);
|
||||
|
|
|
@ -165,6 +165,14 @@ void *dc_create_device(struct dreamcast *dc, size_t size, const char *name,
|
|||
struct device *dc_get_device(struct dreamcast *dc, const char *name);
|
||||
void dc_destroy_device(struct device *dev);
|
||||
|
||||
struct debug_interface *dc_create_debug_interface(device_num_regs_cb num_regs,
|
||||
device_step_cb step,
|
||||
device_add_bp_cb add_bp,
|
||||
device_rem_bp_cb rem_bp,
|
||||
device_read_mem_cb read_mem,
|
||||
device_read_reg_cb read_reg);
|
||||
void dc_destroy_debug_interface(struct debug_interface *dbg);
|
||||
|
||||
struct execute_interface *dc_create_execute_interface(device_run_cb run,
|
||||
int running);
|
||||
void dc_destroy_execute_interface(struct execute_interface *execute);
|
||||
|
|
|
@ -540,7 +540,8 @@ static int gdrom_init(struct device *dev) {
|
|||
}
|
||||
|
||||
void gdrom_dma_end(struct gdrom *gd) {
|
||||
LOG_GDROM("gd_dma_end, %d / %d read from dma buffer", gd->dma_head, gd->dma_size);
|
||||
LOG_GDROM("gd_dma_end, %d / %d read from dma buffer", gd->dma_head,
|
||||
gd->dma_size);
|
||||
|
||||
if (gd->dma_head < gd->dma_size) {
|
||||
return;
|
||||
|
|
|
@ -41,19 +41,6 @@ static void sh4_swap_fpr_bank(struct sh4 *sh4) {
|
|||
}
|
||||
}
|
||||
|
||||
static void sh4_invalid_instr(void *data, uint32_t addr) {
|
||||
/*struct sh4 *self = reinterpret_cast<SH4 *>(ctx->sh4);
|
||||
|
||||
auto it = self->breakpoints.find(addr);
|
||||
CHECK_NE(it, self->breakpoints.end());
|
||||
|
||||
// force the main loop to break
|
||||
self->ctx.num_cycles = 0;
|
||||
|
||||
// let the debugger know execution has stopped
|
||||
self->dc->debugger->Trap();*/
|
||||
}
|
||||
|
||||
void sh4_sr_updated(void *data, uint32_t old_sr) {
|
||||
struct sh4 *sh4 = data;
|
||||
struct sh4_ctx *ctx = &sh4->ctx;
|
||||
|
@ -227,7 +214,7 @@ static int sh4_init(struct device *dev) {
|
|||
sh4->guest->ctx = &sh4->ctx;
|
||||
sh4->guest->mem = sh4->memory_if->space->base;
|
||||
sh4->guest->space = sh4->memory_if->space;
|
||||
sh4->guest->invalid_instr = &sh4_invalid_instr;
|
||||
sh4->guest->invalid_instr = &sh4_dbg_invalid_instr;
|
||||
sh4->guest->sq_prefetch = &sh4_ccn_sq_prefetch;
|
||||
sh4->guest->sr_updated = &sh4_sr_updated;
|
||||
sh4->guest->fpscr_updated = &sh4_fpscr_updated;
|
||||
|
@ -259,12 +246,16 @@ void sh4_destroy(struct sh4 *sh4) {
|
|||
|
||||
dc_destroy_memory_interface(sh4->memory_if);
|
||||
dc_destroy_execute_interface(sh4->execute_if);
|
||||
dc_destroy_debug_interface(sh4->debug_if);
|
||||
dc_destroy_device((struct device *)sh4);
|
||||
}
|
||||
|
||||
struct sh4 *sh4_create(struct dreamcast *dc) {
|
||||
struct sh4 *sh4 = dc_create_device(dc, sizeof(struct sh4), "sh", &sh4_init,
|
||||
&sh4_debug_menu);
|
||||
sh4->debug_if = dc_create_debug_interface(
|
||||
&sh4_dbg_num_registers, &sh4_dbg_step, &sh4_dbg_add_breakpoint,
|
||||
&sh4_dbg_remove_breakpoint, &sh4_dbg_read_memory, &sh4_dbg_read_register);
|
||||
sh4->execute_if = dc_create_execute_interface(&sh4_run, 0);
|
||||
sh4->memory_if = dc_create_memory_interface(dc, &sh4_data_map);
|
||||
|
||||
|
|
|
@ -51,6 +51,9 @@ struct sh4 {
|
|||
struct sh4_frontend *frontend;
|
||||
struct x64_backend *backend;
|
||||
|
||||
/* dbg */
|
||||
struct list breakpoints;
|
||||
|
||||
/* intc */
|
||||
enum sh4_interrupt sorted_interrupts[NUM_SH_INTERRUPTS];
|
||||
uint64_t sort_id[NUM_SH_INTERRUPTS];
|
||||
|
@ -76,6 +79,16 @@ uint32_t sh4_ccn_sq_read(struct sh4 *sh4, uint32_t addr, uint32_t data_mask);
|
|||
void sh4_ccn_sq_write(struct sh4 *sh4, uint32_t addr, uint32_t data,
|
||||
uint32_t data_mask);
|
||||
|
||||
int sh4_dbg_num_registers(struct device *dev);
|
||||
void sh4_dbg_step(struct device *dev);
|
||||
void sh4_dbg_add_breakpoint(struct device *dev, int type, uint32_t addr);
|
||||
void sh4_dbg_remove_breakpoint(struct device *dev, int type, uint32_t addr);
|
||||
void sh4_dbg_read_memory(struct device *dev, uint32_t addr, uint8_t *buffer,
|
||||
int size);
|
||||
void sh4_dbg_read_register(struct device *dev, int n, uint64_t *value,
|
||||
int *size);
|
||||
void sh4_dbg_invalid_instr(void *data, uint32_t addr);
|
||||
|
||||
void sh4_dmac_ddt(struct sh4 *sh, struct sh4_dtr *dtr);
|
||||
|
||||
void sh4_intc_update_pending(struct sh4 *sh4);
|
||||
|
|
|
@ -1,86 +1,143 @@
|
|||
// static int sh4_dbg_num_registers() {
|
||||
// return 59;
|
||||
// }
|
||||
#include "hw/debugger.h"
|
||||
#include "hw/sh4/sh4.h"
|
||||
#include "jit/frontend/sh4/sh4_disasm.h"
|
||||
#include "jit/frontend/sh4/sh4_fallback.h"
|
||||
|
||||
// static void sh4_dbg_step() {
|
||||
// // invalidate the block for the current pc
|
||||
// sh4->code_cache->RemoveBlocks(sh4->ctx.pc);
|
||||
struct breakpoint {
|
||||
uint32_t addr;
|
||||
uint16_t instr;
|
||||
struct list_node it;
|
||||
};
|
||||
|
||||
// // recompile it with only one instruction and run it
|
||||
// uint32_t guest_addr = sh4->ctx.pc;
|
||||
// uint8_t *host_addr = space->Translate(guest_addr);
|
||||
// int flags = GetCompileFlags() | SH4_SINGLE_INSTR;
|
||||
static struct breakpoint *lookup_breakpoint(struct sh4 *sh4, uint32_t addr) {
|
||||
list_for_each_entry(bp, &sh4->breakpoints, struct breakpoint, it) {
|
||||
if (bp->addr == addr) {
|
||||
return bp;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// code_pointer_t code = sh4->code_cache->CompileCode(guest_addr, host_addr,
|
||||
// flags);
|
||||
// sh4->ctx.pc = code();
|
||||
static void destroy_breakpoint(struct sh4 *sh4, struct breakpoint *bp) {
|
||||
list_remove(&sh4->breakpoints, &bp->it);
|
||||
free(bp);
|
||||
}
|
||||
|
||||
// // let the debugger know we've stopped
|
||||
// dc->debugger->Trap();
|
||||
// }
|
||||
static struct breakpoint *create_breakpoint(struct sh4 *sh4, uint32_t addr,
|
||||
uint16_t instr) {
|
||||
struct breakpoint *bp = calloc(1, sizeof(struct breakpoint));
|
||||
bp->addr = addr;
|
||||
bp->instr = instr;
|
||||
list_add(&sh4->breakpoints, &bp->it);
|
||||
return bp;
|
||||
}
|
||||
|
||||
// static void sh4_dbg_add_breakpoint(int type, uint32_t addr) {
|
||||
// // save off the original instruction
|
||||
// uint16_t instr = space->R16(addr);
|
||||
// breakpoints_.insert(std::make_pair(addr, instr));
|
||||
void sh4_dbg_invalid_instr(void *data, uint32_t addr) {
|
||||
struct sh4 *sh4 = data;
|
||||
|
||||
// // write out an invalid instruction
|
||||
// space->W16(addr, 0);
|
||||
/* ensure a breakpoint exists for this address */
|
||||
struct breakpoint *bp = lookup_breakpoint(sh4, addr);
|
||||
CHECK_NOTNULL(bp);
|
||||
|
||||
// sh4->code_cache->RemoveBlocks(addr);
|
||||
// }
|
||||
/* force a break from dispatch */
|
||||
sh4->ctx.run_cycles = 0;
|
||||
|
||||
// static void sh4_dbg_remove_breakpoint(int type, uint32_t addr) {
|
||||
// // recover the original instruction
|
||||
// auto it = breakpoints_.find(addr);
|
||||
// CHECK_NE(it, breakpoints_.end());
|
||||
// uint16_t instr = it->second;
|
||||
// breakpoints_.erase(it);
|
||||
/* let the debugger know execution has stopped */
|
||||
debugger_trap(sh4->dc->debugger);
|
||||
}
|
||||
|
||||
// // overwrite the invalid instruction with the original
|
||||
// space->W16(addr, instr);
|
||||
void sh4_dbg_read_register(struct device *dev, int n, uint64_t *value,
|
||||
int *size) {
|
||||
struct sh4 *sh4 = (struct sh4 *)dev;
|
||||
|
||||
// sh4->code_cache->RemoveBlocks(addr);
|
||||
// }
|
||||
if (n < 16) {
|
||||
*value = sh4->ctx.r[n];
|
||||
} else if (n == 16) {
|
||||
*value = sh4->ctx.pc;
|
||||
} else if (n == 17) {
|
||||
*value = sh4->ctx.pr;
|
||||
} else if (n == 18) {
|
||||
*value = sh4->ctx.gbr;
|
||||
} else if (n == 19) {
|
||||
*value = sh4->ctx.vbr;
|
||||
} else if (n == 20) {
|
||||
*value = sh4->ctx.mach;
|
||||
} else if (n == 21) {
|
||||
*value = sh4->ctx.macl;
|
||||
} else if (n == 22) {
|
||||
*value = sh4->ctx.sr;
|
||||
} else if (n == 23) {
|
||||
*value = sh4->ctx.fpul;
|
||||
} else if (n == 24) {
|
||||
*value = sh4->ctx.fpscr;
|
||||
} else if (n < 41) {
|
||||
*value = sh4->ctx.fr[n - 25];
|
||||
} else if (n == 41) {
|
||||
*value = sh4->ctx.ssr;
|
||||
} else if (n == 42) {
|
||||
*value = sh4->ctx.spc;
|
||||
} else if (n < 51) {
|
||||
uint32_t *b0 = (sh4->ctx.sr & RB_MASK) ? sh4->ctx.ralt : sh4->ctx.r;
|
||||
*value = b0[n - 43];
|
||||
} else if (n < 59) {
|
||||
uint32_t *b1 = (sh4->ctx.sr & RB_MASK) ? sh4->ctx.r : sh4->ctx.ralt;
|
||||
*value = b1[n - 51];
|
||||
}
|
||||
|
||||
// static void sh4_dbg_read_memory(uint32_t addr, uint8_t *buffer, int size) {
|
||||
// space->Memcpy(buffer, addr, size);
|
||||
// }
|
||||
*size = 4;
|
||||
}
|
||||
|
||||
// void sh4_dbg_read_register(int n, uint64_t *value, int *size) {
|
||||
// if (n < 16) {
|
||||
// *value = sh4->ctx.r[n];
|
||||
// } else if (n == 16) {
|
||||
// *value = sh4->ctx.pc;
|
||||
// } else if (n == 17) {
|
||||
// *value = sh4->ctx.pr;
|
||||
// } else if (n == 18) {
|
||||
// *value = sh4->ctx.gbr;
|
||||
// } else if (n == 19) {
|
||||
// *value = sh4->ctx.vbr;
|
||||
// } else if (n == 20) {
|
||||
// *value = sh4->ctx.mach;
|
||||
// } else if (n == 21) {
|
||||
// *value = sh4->ctx.macl;
|
||||
// } else if (n == 22) {
|
||||
// *value = sh4->ctx.sr;
|
||||
// } else if (n == 23) {
|
||||
// *value = sh4->ctx.fpul;
|
||||
// } else if (n == 24) {
|
||||
// *value = sh4->ctx.fpscr;
|
||||
// } else if (n < 41) {
|
||||
// *value = sh4->ctx.fr[n - 25];
|
||||
// } else if (n == 41) {
|
||||
// *value = sh4->ctx.ssr;
|
||||
// } else if (n == 42) {
|
||||
// *value = sh4->ctx.spc;
|
||||
// } else if (n < 51) {
|
||||
// uint32_t *b0 = (sh4->ctx.sr & RB) ? sh4->ctx.ralt : sh4->ctx.r;
|
||||
// *value = b0[n - 43];
|
||||
// } else if (n < 59) {
|
||||
// uint32_t *b1 = (sh4->ctx.sr & RB) ? sh4->ctx.r : sh4->ctx.ralt;
|
||||
// *value = b1[n - 51];
|
||||
// }
|
||||
void sh4_dbg_read_memory(struct device *dev, uint32_t addr, uint8_t *buffer,
|
||||
int size) {
|
||||
struct sh4 *sh4 = (struct sh4 *)dev;
|
||||
|
||||
// *size = 4;
|
||||
// }
|
||||
while (size--) {
|
||||
*(buffer++) = as_read8(sh4->memory_if->space, addr++);
|
||||
}
|
||||
}
|
||||
|
||||
void sh4_dbg_remove_breakpoint(struct device *dev, int type, uint32_t addr) {
|
||||
struct sh4 *sh4 = (struct sh4 *)dev;
|
||||
|
||||
struct breakpoint *bp = lookup_breakpoint(sh4, addr);
|
||||
CHECK_NOTNULL(bp);
|
||||
|
||||
/* restore the original instruction */
|
||||
as_write16(sh4->memory_if->space, addr, bp->instr);
|
||||
|
||||
/* free code cache to remove block containing the invalid instruction */
|
||||
jit_free_blocks(sh4->jit);
|
||||
|
||||
destroy_breakpoint(sh4, bp);
|
||||
}
|
||||
|
||||
void sh4_dbg_add_breakpoint(struct device *dev, int type, uint32_t addr) {
|
||||
struct sh4 *sh4 = (struct sh4 *)dev;
|
||||
|
||||
uint16_t instr = as_read16(sh4->memory_if->space, addr);
|
||||
struct breakpoint *bp = create_breakpoint(sh4, addr, instr);
|
||||
|
||||
/* write out an invalid instruction */
|
||||
as_write16(sh4->memory_if->space, addr, 0);
|
||||
|
||||
/* free code cache to remove block containing the original instruction */
|
||||
jit_free_blocks(sh4->jit);
|
||||
}
|
||||
|
||||
void sh4_dbg_step(struct device *dev) {
|
||||
struct sh4 *sh4 = (struct sh4 *)dev;
|
||||
|
||||
/* run the fallback handler for the current pc */
|
||||
uint16_t data = as_read16(sh4->memory_if->space, sh4->ctx.pc);
|
||||
union sh4_instr instr = {data};
|
||||
struct sh4_opdef *def = sh4_get_opdef(data);
|
||||
sh4_fallback_cb cb = sh4_get_fallback(data);
|
||||
cb(sh4->guest, sh4->ctx.pc, instr);
|
||||
|
||||
/* let the debugger know we've stopped */
|
||||
debugger_trap(sh4->dc->debugger);
|
||||
}
|
||||
|
||||
int sh4_dbg_num_registers(struct device *dev) {
|
||||
return 59;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue