Mercurial > repos > blastem
diff debug.c @ 2400:c97609fe8315
Implement watchpoints in Z80 debugger
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 23 Dec 2023 23:03:31 -0800 |
parents | bf4f1a8d1d48 |
children | 64cf80e683aa |
line wrap: on
line diff
--- a/debug.c Sat Dec 23 22:11:43 2023 -0800 +++ b/debug.c Sat Dec 23 23:03:31 2023 -0800 @@ -4339,7 +4339,11 @@ return 1; } bp_def *tmp = *this_bp; - zremove_breakpoint(root->cpu_context, tmp->address); + if (tmp->type == BP_TYPE_CPU) { + zremove_breakpoint(root->cpu_context, tmp->address); + } else if (tmp->type == BP_TYPE_CPU_WATCH) { + z80_remove_watchpoint(root->cpu_context, tmp->address, tmp->mask); + } *this_bp = (*this_bp)->next; if (tmp->commands) { for (uint32_t i = 0; i < tmp->num_commands; i++) @@ -4371,6 +4375,32 @@ return 1; } +static uint8_t cmd_watchpoint_z80(debug_root *root, parsed_command *cmd) +{ + uint32_t address; + if (!debug_cast_int(cmd->args[0].value, &address)) { + fprintf(stderr, "First argument to watchpoint must be an integer\n"); + return 1; + } + uint32_t size = 1; + if (cmd->num_args > 1) { + if (!debug_cast_int(cmd->args[1].value, &size)) { + fprintf(stderr, "Second argument to watchpoint must be an integer if provided\n"); + return 1; + } + } + z80_add_watchpoint(root->cpu_context, address, size); + bp_def *new_bp = calloc(1, sizeof(bp_def)); + new_bp->next = root->breakpoints; + new_bp->address = address; + new_bp->mask = size; + new_bp->index = root->bp_index++; + new_bp->type = BP_TYPE_CPU_WATCH; + root->breakpoints = new_bp; + printf("Z80 Watchpoint %d set for $%X\n", new_bp->index, address); + return 1; +} + static uint8_t cmd_advance_z80(debug_root *root, parsed_command *cmd) { uint32_t address; @@ -4572,6 +4602,16 @@ }, { .names = (const char *[]){ + "watchpoint", NULL + }, + .usage = "watchpoint ADDRESS [SIZE]", + .desc = "Set a watchpoint at ADDRESS with an optional SIZE in bytes. SIZE defaults to 1", + .impl = cmd_watchpoint_z80, + .min_args = 1, + .max_args = 2 + }, + { + .names = (const char *[]){ "advance", NULL }, .usage = "advance ADDRESS", @@ -5183,6 +5223,7 @@ } root->address = address; //Check if this is a user set breakpoint, or just a temporary one + int debugging; bp_def ** this_bp = find_breakpoint(&root->breakpoints, address, BP_TYPE_CPU); if (*this_bp) { if ((*this_bp)->condition) { @@ -5197,7 +5238,7 @@ (*this_bp)->condition = NULL; } } - int debugging = 1; + debugging = 1; for (uint32_t i = 0; debugging && i < (*this_bp)->num_commands; i++) { debugging = run_command(root, (*this_bp)->commands + i); @@ -5205,11 +5246,45 @@ if (debugging) { printf("Z80 Breakpoint %d hit\n", (*this_bp)->index); } else { + fflush(stdout); return context; } } else { zremove_breakpoint(context, address); } + if (context->wp_hit) { + context->wp_hit = 0; + this_bp = find_breakpoint(&root->breakpoints, context->wp_hit_address, BP_TYPE_CPU_WATCH); + if (*this_bp) { + if ((*this_bp)->condition) { + debug_val condres; + if (eval_expr(root, (*this_bp)->condition, &condres)) { + if (!condres.v.u32) { + return context; + } + } else { + fprintf(stderr, "Failed to eval condition for Z80 watchpoint %u\n", (*this_bp)->index); + free_expr((*this_bp)->condition); + (*this_bp)->condition = NULL; + } + } + debugging = 1; + for (uint32_t i = 0; debugging && i < (*this_bp)->num_commands; i++) + { + debugging = run_command(root, (*this_bp)->commands + i); + } + if (debugging) { + if (context->wp_old_value != context->wp_hit_value) { + printf("Z80 Watchpoint %d hit, old value: %X, new value %X\n", (*this_bp)->index, context->wp_old_value, context->wp_hit_value); + } else { + printf("Z80 Watchpoint %d hit\n", (*this_bp)->index); + } + } else { + fflush(stdout); + return context; + } + } + } uint8_t * pc = get_native_pointer(address, (void **)context->mem_pointers, &context->Z80_OPTS->gen); if (!pc) { fatal_error("Failed to get native pointer on entering Z80 debugger at address %X\n", address); @@ -5306,7 +5381,7 @@ return; } } else { - fprintf(stderr, "Failed to eval condition for M68K breakpoint %u\n", (*this_bp)->index); + fprintf(stderr, "Failed to eval condition for M68K watchpoint %u\n", (*this_bp)->index); free_expr((*this_bp)->condition); (*this_bp)->condition = NULL; }