gbdb: optimize breakpoints and add runto
This commit is contained in:
150
src/apps/gbdb.c
150
src/apps/gbdb.c
@@ -19,13 +19,14 @@
|
||||
#include "common/tri.h"
|
||||
|
||||
#define INPUT_MAX_LEN 512
|
||||
#define MAX_BREAKPTS 4 /* Should be plenty for anyone */
|
||||
#define MAX_BREAKPTS 2 /* Should be plenty for anyone */
|
||||
#define MAX_RAM_LEN (1 << 20) /* Up to 8Mb Cartridge */
|
||||
#define UNMAP_BOOTROM_ADDR 0xff50
|
||||
|
||||
typedef void (gbdb_cmd)(char *arg_string);
|
||||
|
||||
static bool cpu_at_breakpoint(void);
|
||||
static void breakpoint_addr_hit(uint16_t id);
|
||||
|
||||
static uint8_t ram[MAX_RAM_LEN];
|
||||
static const char prompt[] = "gbdb >";
|
||||
@@ -208,6 +209,7 @@ static void step(char *arg_list)
|
||||
if (init_steps + steps <= cpu.metrics.retired_instrs) {
|
||||
gb_log("CPU stopped after %" PRId64 " instructions\n", steps);
|
||||
} else if (cpu_at_breakpoint()) {
|
||||
breakpoint_addr_hit(cpu.pc);
|
||||
gb_log("Breakpoint hit\n");
|
||||
} else if (cpu.halted) {
|
||||
gb_log("CPU halted\n");
|
||||
@@ -438,8 +440,7 @@ static void quit(char *arg_list)
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void run(char *arg_list)
|
||||
{
|
||||
static void do_run(void) {
|
||||
paused = 0;
|
||||
signal(SIGINT, break_execution_handler);
|
||||
while(!cpu.halted && !cpu_at_breakpoint() && !paused) {
|
||||
@@ -451,43 +452,129 @@ static void run(char *arg_list)
|
||||
} else if (paused) {
|
||||
gb_log("Interrupted.\n");
|
||||
} else {
|
||||
gb_log("Breakpoint hit\n");
|
||||
breakpoint_addr_hit(cpu.pc);
|
||||
gb_log("Breakpoint hit\n");
|
||||
}
|
||||
}
|
||||
|
||||
static struct {
|
||||
uint16_t addr;
|
||||
bool active;
|
||||
static void run(char *arg_list)
|
||||
{
|
||||
do_run();
|
||||
}
|
||||
|
||||
static struct breakpoint {
|
||||
uint16_t addr;
|
||||
int id;
|
||||
bool temp;
|
||||
} breakpoints[MAX_BREAKPTS];
|
||||
|
||||
static int num_breakpoints = 0;
|
||||
|
||||
static struct breakpoint *get_breakpoint(int id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_breakpoints; i++) {
|
||||
if (breakpoints[i].id == id) {
|
||||
return &breakpoints[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int do_set_breakpoint(uint16_t addr, bool temp)
|
||||
{
|
||||
static int id = 0;
|
||||
if (num_breakpoints < ARRAY_SIZE(breakpoints)) {
|
||||
breakpoints[num_breakpoints].addr = addr;
|
||||
breakpoints[num_breakpoints].id = id++;
|
||||
breakpoints[num_breakpoints].temp = temp;
|
||||
num_breakpoints++;
|
||||
} else {
|
||||
printf("maximum number of breakpoints reached\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void set_breakpoint(char *arg_string)
|
||||
{
|
||||
uint16_t addr, i;
|
||||
char *token = strtok(arg_string, " ");
|
||||
|
||||
|
||||
if (token == NULL) {
|
||||
printf("usage: breakpoint add <addr>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
addr = parse_val(token);
|
||||
do_set_breakpoint(addr, false);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(breakpoints); i++) {
|
||||
if (breakpoints[i].active == false) {
|
||||
breakpoints[i].addr = addr;
|
||||
breakpoints[i].active = true;
|
||||
return;
|
||||
}
|
||||
static void runto(char *arg_string)
|
||||
{
|
||||
uint16_t addr, i, rc;
|
||||
char *token = strtok(arg_string, " ");
|
||||
|
||||
if (token == NULL) {
|
||||
printf("usage: runto <addr>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("maximum number of breakpoints reached\n");
|
||||
addr = parse_val(token);
|
||||
rc = do_set_breakpoint(addr, true);
|
||||
if (rc < 0) {
|
||||
printf("failed to set breakpoint\n");
|
||||
return;
|
||||
}
|
||||
|
||||
do_run();
|
||||
}
|
||||
|
||||
static int do_delete_breakpoint(int id)
|
||||
{
|
||||
struct breakpoint *bkpt = get_breakpoint(id);
|
||||
int index;
|
||||
|
||||
if (bkpt == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
index = bkpt - breakpoints;
|
||||
memmove(&breakpoints[index], &breakpoints[index + 1],
|
||||
num_breakpoints - index - 1);
|
||||
num_breakpoints--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void breakpoint_addr_hit(uint16_t addr)
|
||||
{
|
||||
struct breakpoint *bkpt = NULL;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_breakpoints; i++) {
|
||||
if (breakpoints[i].addr == addr) {
|
||||
bkpt= &breakpoints[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (bkpt == NULL) {
|
||||
printf("No breakpoint found at addr=%d\n", addr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bkpt->temp) {
|
||||
do_delete_breakpoint(bkpt->id);
|
||||
}
|
||||
}
|
||||
|
||||
static void delete_breakpoint(char *arg_string)
|
||||
{
|
||||
int bkpt;
|
||||
char *token = strtok(arg_string, " ");
|
||||
|
||||
int rc, bkpt;
|
||||
|
||||
if (token == NULL) {
|
||||
printf("usage: breakpoint rm <bkpt num>\n");
|
||||
return;
|
||||
@@ -495,27 +582,21 @@ static void delete_breakpoint(char *arg_string)
|
||||
|
||||
bkpt = parse_val(token);
|
||||
|
||||
if (bkpt < 0 || bkpt >= ARRAY_SIZE(breakpoints) || !breakpoints[bkpt].active) {
|
||||
printf("%d is not a valid breakpoint number\n", bkpt);
|
||||
return;
|
||||
rc = do_delete_breakpoint(bkpt);
|
||||
if (rc < 0) {
|
||||
printf("%d is not a valid breakpoint number\n", bkpt);
|
||||
}
|
||||
|
||||
breakpoints[bkpt].active = false;
|
||||
}
|
||||
|
||||
static void display_breakpoints(char *arg_string)
|
||||
{
|
||||
bool found1 = false;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(breakpoints); i++) {
|
||||
if (breakpoints[i].active) {
|
||||
printf("#%d: 0x%04x\n", i, breakpoints[i].addr);
|
||||
found1 = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found1) {
|
||||
if (num_breakpoints) {
|
||||
for (i = 0; i < num_breakpoints; i++) {
|
||||
printf("#%d: 0x%04x\n", breakpoints[i].id, breakpoints[i].addr);
|
||||
}
|
||||
} else {
|
||||
printf("No breakpoints set\n");
|
||||
}
|
||||
}
|
||||
@@ -565,8 +646,8 @@ static void breakpoint(char *arg_list)
|
||||
static bool breakpoint_is_at_addr(uint16_t addr) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(breakpoints); i++) {
|
||||
if (breakpoints[i].active && addr == breakpoints[i].addr) {
|
||||
for (i = 0; i < num_breakpoints; i++) {
|
||||
if (breakpoints[i].addr == addr) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -576,7 +657,7 @@ static bool breakpoint_is_at_addr(uint16_t addr) {
|
||||
|
||||
static bool cpu_at_breakpoint(void)
|
||||
{
|
||||
return breakpoint_is_at_addr(lr35902_get_reg_16(&cpu, LR35902_REG_PC));
|
||||
return breakpoint_is_at_addr(cpu.pc);
|
||||
}
|
||||
|
||||
static void process_cmd(const char *cmd_str, struct tri *commands)
|
||||
@@ -689,6 +770,7 @@ int main(int argc, char **argv)
|
||||
tri_add_string(&commands, "help", help);
|
||||
tri_add_string(&commands, "?", help);
|
||||
tri_add_string(&commands, "breakpoint", breakpoint);
|
||||
tri_add_string(&commands, "runto", runto);
|
||||
tri_add_string(&commands, "reset", init);
|
||||
tri_add_string(&commands, "assert", assert);
|
||||
tri_add_string(&commands, "set", set);
|
||||
|
||||
Reference in New Issue
Block a user