comparison debug.c @ 2396:bf4f1a8d1d48

Implement 68K watchpoints in internal debugger
author Michael Pavone <pavone@retrodev.com>
date Sat, 23 Dec 2023 17:37:57 -0800
parents ebca8ab02701
children c97609fe8315
comparison
equal deleted inserted replaced
2395:ebca8ab02701 2396:bf4f1a8d1d48
378 return root; 378 return root;
379 } 379 }
380 380
381 bp_def ** find_breakpoint(bp_def ** cur, uint32_t address, uint8_t type) 381 bp_def ** find_breakpoint(bp_def ** cur, uint32_t address, uint8_t type)
382 { 382 {
383 while (*cur) { 383 if (type == BP_TYPE_CPU_WATCH) {
384 if ((*cur)->type == type && (*cur)->address == (((*cur)->mask) & address)) { 384 while (*cur) {
385 break; 385 if ((*cur)->type == type && address >= (*cur)->address && address < ((*cur)->address + (*cur)->mask)) {
386 } 386 break;
387 cur = &((*cur)->next); 387 }
388 cur = &((*cur)->next);
389 }
390 } else {
391 while (*cur) {
392 if ((*cur)->type == type && (*cur)->address == (((*cur)->mask) & address)) {
393 break;
394 }
395 cur = &((*cur)->next);
396 }
388 } 397 }
389 return cur; 398 return cur;
390 } 399 }
391 400
392 bp_def ** find_breakpoint_idx(bp_def ** cur, uint32_t index) 401 bp_def ** find_breakpoint_idx(bp_def ** cur, uint32_t index)
3112 } 3121 }
3113 uint32_t start = 0; 3122 uint32_t start = 0;
3114 debug_val val; 3123 debug_val val;
3115 debug_array * arr = NULL; 3124 debug_array * arr = NULL;
3116 if (cmd->args[1].parsed->type == EXPR_MEM) { 3125 if (cmd->args[1].parsed->type == EXPR_MEM) {
3117 3126
3118 if (!eval_expr(root, cmd->args[1].parsed->left, &val)) { 3127 if (!eval_expr(root, cmd->args[1].parsed->left, &val)) {
3119 fprintf(stderr, "Failed to eval start index\n"); 3128 fprintf(stderr, "Failed to eval start index\n");
3120 goto cleanup; 3129 goto cleanup;
3121 } 3130 }
3122 if (!debug_cast_int(val, &start)) { 3131 if (!debug_cast_int(val, &start)) {
3275 } 3284 }
3276 uint32_t start = 0; 3285 uint32_t start = 0;
3277 debug_val val; 3286 debug_val val;
3278 debug_array * arr = NULL; 3287 debug_array * arr = NULL;
3279 if (cmd->args[1].parsed->type == EXPR_MEM) { 3288 if (cmd->args[1].parsed->type == EXPR_MEM) {
3280 3289
3281 if (!eval_expr(root, cmd->args[1].parsed->left, &val)) { 3290 if (!eval_expr(root, cmd->args[1].parsed->left, &val)) {
3282 fprintf(stderr, "Failed to eval start index\n"); 3291 fprintf(stderr, "Failed to eval start index\n");
3283 goto cleanup; 3292 goto cleanup;
3284 } 3293 }
3285 if (!debug_cast_int(val, &start)) { 3294 if (!debug_cast_int(val, &start)) {
3438 return 1; 3447 return 1;
3439 } 3448 }
3440 bp_def *tmp = *this_bp; 3449 bp_def *tmp = *this_bp;
3441 if (tmp->type == BP_TYPE_CPU) { 3450 if (tmp->type == BP_TYPE_CPU) {
3442 remove_breakpoint(root->cpu_context, tmp->address); 3451 remove_breakpoint(root->cpu_context, tmp->address);
3452 } else if (tmp->type == BP_TYPE_CPU_WATCH) {
3453 m68k_remove_watchpoint(root->cpu_context, tmp->address, tmp->mask);
3443 } 3454 }
3444 *this_bp = (*this_bp)->next; 3455 *this_bp = (*this_bp)->next;
3445 if (tmp->commands) { 3456 if (tmp->commands) {
3446 for (uint32_t i = 0; i < tmp->num_commands; i++) 3457 for (uint32_t i = 0; i < tmp->num_commands; i++)
3447 { 3458 {
3467 new_bp->mask = 0xFFFFFF; 3478 new_bp->mask = 0xFFFFFF;
3468 new_bp->index = root->bp_index++; 3479 new_bp->index = root->bp_index++;
3469 new_bp->type = BP_TYPE_CPU; 3480 new_bp->type = BP_TYPE_CPU;
3470 root->breakpoints = new_bp; 3481 root->breakpoints = new_bp;
3471 printf("68K Breakpoint %d set at $%X\n", new_bp->index, address); 3482 printf("68K Breakpoint %d set at $%X\n", new_bp->index, address);
3483 return 1;
3484 }
3485
3486 static uint8_t cmd_watchpoint_m68k(debug_root *root, parsed_command *cmd)
3487 {
3488 uint32_t address;
3489 if (!debug_cast_int(cmd->args[0].value, &address)) {
3490 fprintf(stderr, "First argument to watchpoint must be an integer\n");
3491 return 1;
3492 }
3493 uint32_t size;
3494 if (cmd->num_args > 1) {
3495 if (!debug_cast_int(cmd->args[1].value, &size)) {
3496 fprintf(stderr, "Second argument to watchpoint must be an integer if provided\n");
3497 return 1;
3498 }
3499 } else {
3500 //default to byte for odd addresses, word for even
3501 size = (address & 1) ? 1 : 2;
3502 }
3503 m68k_add_watchpoint(root->cpu_context, address, size);
3504 bp_def *new_bp = calloc(1, sizeof(bp_def));
3505 new_bp->next = root->breakpoints;
3506 new_bp->address = address;
3507 new_bp->mask = size;
3508 new_bp->index = root->bp_index++;
3509 new_bp->type = BP_TYPE_CPU_WATCH;
3510 root->breakpoints = new_bp;
3511 printf("68K Watchpoint %d set for $%X\n", new_bp->index, address);
3472 return 1; 3512 return 1;
3473 } 3513 }
3474 3514
3475 static void on_vdp_reg_write(vdp_context *context, uint16_t reg, uint16_t value) 3515 static void on_vdp_reg_write(vdp_context *context, uint16_t reg, uint16_t value)
3476 { 3516 {
4097 .usage = "breakpoint ADDRESSS", 4137 .usage = "breakpoint ADDRESSS",
4098 .desc = "Set a breakpoint at ADDRESS", 4138 .desc = "Set a breakpoint at ADDRESS",
4099 .impl = cmd_breakpoint_m68k, 4139 .impl = cmd_breakpoint_m68k,
4100 .min_args = 1, 4140 .min_args = 1,
4101 .max_args = 1 4141 .max_args = 1
4142 },
4143 {
4144 .names = (const char *[]){
4145 "watchpoint", NULL
4146 },
4147 .usage = "watchpoint ADDRESS [SIZE]",
4148 .desc = "Set a watchpoint at ADDRESS with an optional SIZE in bytes. SIZE defaults to 2 for even address and 1 for odd",
4149 .impl = cmd_watchpoint_m68k,
4150 .min_args = 1,
4151 .max_args = 2
4102 }, 4152 },
4103 { 4153 {
4104 .names = (const char *[]){ 4154 .names = (const char *[]){
4105 "advance", NULL 4155 "advance", NULL
4106 }, 4156 },
5193 m68kinst inst; 5243 m68kinst inst;
5194 5244
5195 init_terminal(); 5245 init_terminal();
5196 5246
5197 context->options->sync_components(context, 0); 5247 context->options->sync_components(context, 0);
5198 if (context->system == current_system) {
5199 genesis_context *gen = context->system;
5200 vdp_force_update_framebuffer(gen->vdp);
5201 }
5202 debug_root *root = find_m68k_root(context); 5248 debug_root *root = find_m68k_root(context);
5203 if (!root) { 5249 if (!root) {
5204 return; 5250 return;
5205 } 5251 }
5206 //probably not necessary, but let's play it safe 5252 //probably not necessary, but let's play it safe
5241 debugging = run_command(root, (*this_bp)->commands + i); 5287 debugging = run_command(root, (*this_bp)->commands + i);
5242 } 5288 }
5243 if (debugging) { 5289 if (debugging) {
5244 printf("68K Breakpoint %d hit\n", (*this_bp)->index); 5290 printf("68K Breakpoint %d hit\n", (*this_bp)->index);
5245 } else { 5291 } else {
5292 fflush(stdout);
5246 return; 5293 return;
5247 } 5294 }
5248 } else { 5295 } else {
5249 remove_breakpoint(context, address); 5296 remove_breakpoint(context, address);
5297 }
5298 if (context->wp_hit) {
5299 context->wp_hit = 0;
5300 this_bp = find_breakpoint(&root->breakpoints, context->wp_hit_address, BP_TYPE_CPU_WATCH);
5301 if (*this_bp) {
5302 if ((*this_bp)->condition) {
5303 debug_val condres;
5304 if (eval_expr(root, (*this_bp)->condition, &condres)) {
5305 if (!condres.v.u32) {
5306 return;
5307 }
5308 } else {
5309 fprintf(stderr, "Failed to eval condition for M68K breakpoint %u\n", (*this_bp)->index);
5310 free_expr((*this_bp)->condition);
5311 (*this_bp)->condition = NULL;
5312 }
5313 }
5314 for (uint32_t i = 0; debugging && i < (*this_bp)->num_commands; i++)
5315 {
5316 debugging = run_command(root, (*this_bp)->commands + i);
5317 }
5318 if (debugging) {
5319 if (context->wp_old_value != context->wp_hit_value) {
5320 printf("68K Watchpoint %d hit, old value: %X, new value %X\n", (*this_bp)->index, context->wp_old_value, context->wp_hit_value);
5321 } else {
5322 printf("68K Watchpoint %d hit\n", (*this_bp)->index);
5323 }
5324 } else {
5325 fflush(stdout);
5326 return;
5327 }
5328 }
5329 }
5330 if (context->system == current_system) {
5331 genesis_context *gen = context->system;
5332 vdp_force_update_framebuffer(gen->vdp);
5250 } 5333 }
5251 uint32_t after = m68k_decode(m68k_instruction_fetch, context, &inst, address); 5334 uint32_t after = m68k_decode(m68k_instruction_fetch, context, &inst, address);
5252 root->after = after; 5335 root->after = after;
5253 root->inst = &inst; 5336 root->inst = &inst;
5254 for (disp_def * cur = root->displays; cur; cur = cur->next) { 5337 for (disp_def * cur = root->displays; cur; cur = cur->next) {