Mercurial > repos > blastem
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) { |