annotate debug.c @ 989:d70000fdff0b

Implemented IR and undefined bits of info word for address error exception frames
author Michael Pavone <pavone@retrodev.com>
date Wed, 27 Apr 2016 21:39:17 -0700
parents 751280fb4494
children 22e87b739ad6
rev   line source
pavone@524 1 #include "debug.h"
pavone@524 2 #include "blastem.h"
pavone@524 3 #include "68kinst.h"
pavone@524 4 #include <stdlib.h>
pavone@524 5 #include <string.h>
pavone@745 6 #ifndef _WIN32
pavone@723 7 #include <sys/select.h>
pavone@745 8 #endif
pavone@723 9 #include "render.h"
pavone@792 10 #include "util.h"
pavone@794 11 #include "terminal.h"
pavone@524 12
pavone@525 13 static bp_def * breakpoints = NULL;
pavone@525 14 static bp_def * zbreakpoints = NULL;
pavone@525 15 static uint32_t bp_index = 0;
pavone@525 16 static uint32_t zbp_index = 0;
pavone@524 17
pavone@524 18 bp_def ** find_breakpoint(bp_def ** cur, uint32_t address)
pavone@524 19 {
pavone@524 20 while (*cur) {
pavone@524 21 if ((*cur)->address == address) {
pavone@524 22 break;
pavone@524 23 }
pavone@524 24 cur = &((*cur)->next);
pavone@524 25 }
pavone@524 26 return cur;
pavone@524 27 }
pavone@524 28
pavone@524 29 bp_def ** find_breakpoint_idx(bp_def ** cur, uint32_t index)
pavone@524 30 {
pavone@524 31 while (*cur) {
pavone@524 32 if ((*cur)->index == index) {
pavone@524 33 break;
pavone@524 34 }
pavone@524 35 cur = &((*cur)->next);
pavone@524 36 }
pavone@524 37 return cur;
pavone@524 38 }
pavone@524 39
pavone@524 40 disp_def * displays = NULL;
pavone@524 41 disp_def * zdisplays = NULL;
pavone@524 42 uint32_t disp_index = 0;
pavone@524 43 uint32_t zdisp_index = 0;
pavone@524 44
pavone@524 45 void add_display(disp_def ** head, uint32_t *index, char format_char, char * param)
pavone@524 46 {
pavone@524 47 disp_def * ndisp = malloc(sizeof(*ndisp));
pavone@524 48 ndisp->format_char = format_char;
pavone@524 49 ndisp->param = strdup(param);
pavone@524 50 ndisp->next = *head;
pavone@524 51 ndisp->index = *index++;
pavone@524 52 *head = ndisp;
pavone@524 53 }
pavone@524 54
pavone@524 55 void remove_display(disp_def ** head, uint32_t index)
pavone@524 56 {
pavone@524 57 while (*head) {
pavone@524 58 if ((*head)->index == index) {
pavone@524 59 disp_def * del_disp = *head;
pavone@524 60 *head = del_disp->next;
pavone@524 61 free(del_disp->param);
pavone@524 62 free(del_disp);
pavone@524 63 } else {
pavone@524 64 head = &(*head)->next;
pavone@524 65 }
pavone@524 66 }
pavone@524 67 }
pavone@524 68
pavone@524 69 char * find_param(char * buf)
pavone@524 70 {
pavone@524 71 for (; *buf; buf++) {
pavone@524 72 if (*buf == ' ') {
pavone@524 73 if (*(buf+1)) {
pavone@524 74 return buf+1;
pavone@524 75 }
pavone@524 76 }
pavone@524 77 }
pavone@524 78 return NULL;
pavone@524 79 }
pavone@524 80
pavone@524 81 void strip_nl(char * buf)
pavone@524 82 {
pavone@524 83 for(; *buf; buf++) {
pavone@524 84 if (*buf == '\n') {
pavone@524 85 *buf = 0;
pavone@524 86 return;
pavone@524 87 }
pavone@524 88 }
pavone@524 89 }
pavone@524 90
pavone@829 91 void debugger_print(m68k_context *context, char format_char, char *param)
pavone@829 92 {
pavone@829 93 uint32_t value;
pavone@829 94 char format[8];
pavone@829 95 strcpy(format, "%s: %d\n");
pavone@829 96 switch (format_char)
pavone@829 97 {
pavone@829 98 case 'x':
pavone@829 99 case 'X':
pavone@829 100 case 'd':
pavone@829 101 case 'c':
pavone@829 102 format[5] = format_char;
pavone@829 103 break;
pavone@829 104 case '\0':
pavone@829 105 break;
pavone@829 106 default:
pavone@829 107 fprintf(stderr, "Unrecognized format character: %c\n", format_char);
pavone@829 108 }
pavone@829 109 if (param[0] == 'd' && param[1] >= '0' && param[1] <= '7') {
pavone@829 110 value = context->dregs[param[1]-'0'];
pavone@829 111 } else if (param[0] == 'a' && param[1] >= '0' && param[1] <= '7') {
pavone@829 112 value = context->aregs[param[1]-'0'];
pavone@829 113 } else if (param[0] == 'S' && param[1] == 'R') {
pavone@829 114 value = (context->status << 8);
pavone@829 115 for (int flag = 0; flag < 5; flag++) {
pavone@829 116 value |= context->flags[flag] << (4-flag);
pavone@829 117 }
pavone@829 118 } else if(param[0] == 'c') {
pavone@829 119 value = context->current_cycle;
pavone@829 120 } else if ((param[0] == '0' && param[1] == 'x') || param[0] == '$') {
pavone@829 121 uint32_t p_addr = strtol(param+(param[0] == '0' ? 2 : 1), NULL, 16);
pavone@829 122 if ((p_addr & 0xFFFFFF) == 0xC00004) {
pavone@829 123 genesis_context * gen = context->system;
pavone@829 124 value = vdp_hv_counter_read(gen->vdp);
pavone@829 125 } else {
pavone@865 126 uint16_t *word = get_native_pointer(p_addr & 0xFFFFFE, (void **)context->mem_pointers, &context->options->gen);
pavone@865 127 value = *word;
pavone@829 128 }
pavone@829 129 } else {
pavone@829 130 fprintf(stderr, "Unrecognized parameter to p: %s\n", param);
pavone@829 131 return;
pavone@829 132 }
pavone@829 133 printf(format, param, value);
pavone@829 134 }
pavone@829 135
pavone@565 136 #ifndef NO_Z80
pavone@548 137
pavone@524 138 void zdebugger_print(z80_context * context, char format_char, char * param)
pavone@524 139 {
pavone@524 140 uint32_t value;
pavone@524 141 char format[8];
pavone@524 142 strcpy(format, "%s: %d\n");
pavone@524 143 switch (format_char)
pavone@524 144 {
pavone@524 145 case 'x':
pavone@524 146 case 'X':
pavone@524 147 case 'd':
pavone@524 148 case 'c':
pavone@524 149 format[5] = format_char;
pavone@524 150 break;
pavone@524 151 case '\0':
pavone@524 152 break;
pavone@524 153 default:
pavone@524 154 fprintf(stderr, "Unrecognized format character: %c\n", format_char);
pavone@524 155 }
pavone@524 156 switch (param[0])
pavone@524 157 {
pavone@524 158 case 'a':
pavone@524 159 if (param[1] == 'f') {
pavone@524 160 if(param[2] == '\'') {
pavone@524 161 value = context->alt_regs[Z80_A] << 8;
pavone@524 162 value |= context->alt_flags[ZF_S] << 7;
pavone@524 163 value |= context->alt_flags[ZF_Z] << 6;
pavone@524 164 value |= context->alt_flags[ZF_H] << 4;
pavone@524 165 value |= context->alt_flags[ZF_PV] << 2;
pavone@524 166 value |= context->alt_flags[ZF_N] << 1;
pavone@524 167 value |= context->alt_flags[ZF_C];
pavone@524 168 } else {
pavone@524 169 value = context->regs[Z80_A] << 8;
pavone@524 170 value |= context->flags[ZF_S] << 7;
pavone@524 171 value |= context->flags[ZF_Z] << 6;
pavone@524 172 value |= context->flags[ZF_H] << 4;
pavone@524 173 value |= context->flags[ZF_PV] << 2;
pavone@524 174 value |= context->flags[ZF_N] << 1;
pavone@524 175 value |= context->flags[ZF_C];
pavone@524 176 }
pavone@524 177 } else if(param[1] == '\'') {
pavone@524 178 value = context->alt_regs[Z80_A];
pavone@524 179 } else {
pavone@524 180 value = context->regs[Z80_A];
pavone@524 181 }
pavone@524 182 break;
pavone@524 183 case 'b':
pavone@524 184 if (param[1] == 'c') {
pavone@524 185 if(param[2] == '\'') {
pavone@524 186 value = context->alt_regs[Z80_B] << 8;
pavone@524 187 value |= context->alt_regs[Z80_C];
pavone@524 188 } else {
pavone@524 189 value = context->regs[Z80_B] << 8;
pavone@524 190 value |= context->regs[Z80_C];
pavone@524 191 }
pavone@524 192 } else if(param[1] == '\'') {
pavone@524 193 value = context->alt_regs[Z80_B];
pavone@524 194 } else if(param[1] == 'a') {
pavone@524 195 value = context->bank_reg << 15;
pavone@524 196 } else {
pavone@524 197 value = context->regs[Z80_B];
pavone@524 198 }
pavone@524 199 break;
pavone@524 200 case 'c':
pavone@524 201 if(param[1] == '\'') {
pavone@524 202 value = context->alt_regs[Z80_C];
pavone@524 203 } else if(param[1] == 'y') {
pavone@524 204 value = context->current_cycle;
pavone@524 205 } else {
pavone@524 206 value = context->regs[Z80_C];
pavone@524 207 }
pavone@524 208 break;
pavone@524 209 case 'd':
pavone@524 210 if (param[1] == 'e') {
pavone@524 211 if(param[2] == '\'') {
pavone@524 212 value = context->alt_regs[Z80_D] << 8;
pavone@524 213 value |= context->alt_regs[Z80_E];
pavone@524 214 } else {
pavone@524 215 value = context->regs[Z80_D] << 8;
pavone@524 216 value |= context->regs[Z80_E];
pavone@524 217 }
pavone@524 218 } else if(param[1] == '\'') {
pavone@524 219 value = context->alt_regs[Z80_D];
pavone@524 220 } else {
pavone@524 221 value = context->regs[Z80_D];
pavone@524 222 }
pavone@524 223 break;
pavone@524 224 case 'e':
pavone@524 225 if(param[1] == '\'') {
pavone@524 226 value = context->alt_regs[Z80_E];
pavone@524 227 } else {
pavone@524 228 value = context->regs[Z80_E];
pavone@524 229 }
pavone@524 230 break;
pavone@524 231 case 'f':
pavone@524 232 if(param[2] == '\'') {
pavone@524 233 value = context->alt_flags[ZF_S] << 7;
pavone@524 234 value |= context->alt_flags[ZF_Z] << 6;
pavone@524 235 value |= context->alt_flags[ZF_H] << 4;
pavone@524 236 value |= context->alt_flags[ZF_PV] << 2;
pavone@524 237 value |= context->alt_flags[ZF_N] << 1;
pavone@524 238 value |= context->alt_flags[ZF_C];
pavone@524 239 } else {
pavone@524 240 value = context->flags[ZF_S] << 7;
pavone@524 241 value |= context->flags[ZF_Z] << 6;
pavone@524 242 value |= context->flags[ZF_H] << 4;
pavone@524 243 value |= context->flags[ZF_PV] << 2;
pavone@524 244 value |= context->flags[ZF_N] << 1;
pavone@524 245 value |= context->flags[ZF_C];
pavone@524 246 }
pavone@524 247 break;
pavone@524 248 case 'h':
pavone@524 249 if (param[1] == 'l') {
pavone@524 250 if(param[2] == '\'') {
pavone@524 251 value = context->alt_regs[Z80_H] << 8;
pavone@524 252 value |= context->alt_regs[Z80_L];
pavone@524 253 } else {
pavone@524 254 value = context->regs[Z80_H] << 8;
pavone@524 255 value |= context->regs[Z80_L];
pavone@524 256 }
pavone@524 257 } else if(param[1] == '\'') {
pavone@524 258 value = context->alt_regs[Z80_H];
pavone@524 259 } else {
pavone@524 260 value = context->regs[Z80_H];
pavone@524 261 }
pavone@524 262 break;
pavone@524 263 case 'l':
pavone@524 264 if(param[1] == '\'') {
pavone@524 265 value = context->alt_regs[Z80_L];
pavone@524 266 } else {
pavone@524 267 value = context->regs[Z80_L];
pavone@524 268 }
pavone@524 269 break;
pavone@524 270 case 'i':
pavone@524 271 if(param[1] == 'x') {
pavone@524 272 if (param[2] == 'h') {
pavone@524 273 value = context->regs[Z80_IXH];
pavone@524 274 } else if(param[2] == 'l') {
pavone@524 275 value = context->regs[Z80_IXL];
pavone@524 276 } else {
pavone@524 277 value = context->regs[Z80_IXH] << 8;
pavone@524 278 value |= context->regs[Z80_IXL];
pavone@524 279 }
pavone@524 280 } else if(param[1] == 'y') {
pavone@524 281 if (param[2] == 'h') {
pavone@524 282 value = context->regs[Z80_IYH];
pavone@524 283 } else if(param[2] == 'l') {
pavone@524 284 value = context->regs[Z80_IYL];
pavone@524 285 } else {
pavone@524 286 value = context->regs[Z80_IYH] << 8;
pavone@524 287 value |= context->regs[Z80_IYL];
pavone@524 288 }
pavone@524 289 } else if(param[1] == 'n') {
pavone@524 290 value = context->int_cycle;
pavone@524 291 } else if(param[1] == 'f' && param[2] == 'f' && param[3] == '1') {
pavone@524 292 value = context->iff1;
pavone@524 293 } else if(param[1] == 'f' && param[2] == 'f' && param[3] == '2') {
pavone@524 294 value = context->iff2;
pavone@524 295 } else {
pavone@524 296 value = context->im;
pavone@524 297 }
pavone@524 298 break;
pavone@524 299 case 's':
pavone@524 300 if (param[1] == 'p') {
pavone@524 301 value = context->sp;
pavone@524 302 }
pavone@524 303 break;
pavone@524 304 case '0':
pavone@524 305 if (param[1] == 'x') {
pavone@524 306 uint16_t p_addr = strtol(param+2, NULL, 16);
pavone@524 307 if (p_addr < 0x4000) {
pavone@524 308 value = z80_ram[p_addr & 0x1FFF];
pavone@524 309 } else if(p_addr >= 0x8000) {
pavone@524 310 uint32_t v_addr = context->bank_reg << 15;
pavone@524 311 v_addr += p_addr & 0x7FFF;
pavone@524 312 if (v_addr < 0x400000) {
pavone@524 313 value = cart[v_addr/2];
pavone@524 314 } else if(v_addr > 0xE00000) {
pavone@524 315 value = ram[(v_addr & 0xFFFF)/2];
pavone@524 316 }
pavone@524 317 if (v_addr & 1) {
pavone@524 318 value &= 0xFF;
pavone@524 319 } else {
pavone@524 320 value >>= 8;
pavone@524 321 }
pavone@524 322 }
pavone@524 323 }
pavone@524 324 break;
pavone@524 325 }
pavone@524 326 printf(format, param, value);
pavone@524 327 }
pavone@524 328
pavone@524 329 z80_context * zdebugger(z80_context * context, uint16_t address)
pavone@524 330 {
pavone@524 331 static char last_cmd[1024];
pavone@524 332 char input_buf[1024];
pavone@524 333 static uint16_t branch_t;
pavone@524 334 static uint16_t branch_f;
pavone@524 335 z80inst inst;
pavone@794 336 init_terminal();
pavone@524 337 //Check if this is a user set breakpoint, or just a temporary one
pavone@524 338 bp_def ** this_bp = find_breakpoint(&zbreakpoints, address);
pavone@524 339 if (*this_bp) {
pavone@524 340 printf("Z80 Breakpoint %d hit\n", (*this_bp)->index);
pavone@524 341 } else {
pavone@524 342 zremove_breakpoint(context, address);
pavone@524 343 }
pavone@524 344 uint8_t * pc;
pavone@524 345 if (address < 0x4000) {
pavone@524 346 pc = z80_ram + (address & 0x1FFF);
pavone@524 347 } else if (address >= 0x8000) {
pavone@524 348 if (context->bank_reg < (0x400000 >> 15)) {
pavone@792 349 fatal_error("Entered Z80 debugger in banked memory address %X, which is not yet supported\n", address);
pavone@524 350 } else {
pavone@792 351 fatal_error("Entered Z80 debugger in banked memory address %X, but the bank is not pointed to a cartridge address\n", address);
pavone@524 352 }
pavone@524 353 } else {
pavone@792 354 fatal_error("Entered Z80 debugger at address %X\n", address);
pavone@524 355 }
pavone@524 356 for (disp_def * cur = zdisplays; cur; cur = cur->next) {
pavone@524 357 zdebugger_print(context, cur->format_char, cur->param);
pavone@524 358 }
pavone@524 359 uint8_t * after_pc = z80_decode(pc, &inst);
pavone@524 360 z80_disasm(&inst, input_buf, address);
pavone@524 361 printf("%X:\t%s\n", address, input_buf);
pavone@524 362 uint16_t after = address + (after_pc-pc);
pavone@524 363 int debugging = 1;
pavone@524 364 while(debugging) {
pavone@524 365 fputs(">", stdout);
pavone@524 366 if (!fgets(input_buf, sizeof(input_buf), stdin)) {
pavone@524 367 fputs("fgets failed", stderr);
pavone@524 368 break;
pavone@524 369 }
pavone@524 370 strip_nl(input_buf);
pavone@524 371 //hitting enter repeats last command
pavone@524 372 if (input_buf[0]) {
pavone@524 373 strcpy(last_cmd, input_buf);
pavone@524 374 } else {
pavone@524 375 strcpy(input_buf, last_cmd);
pavone@524 376 }
pavone@524 377 char * param;
pavone@524 378 char format[8];
pavone@524 379 uint32_t value;
pavone@524 380 bp_def * new_bp;
pavone@524 381 switch(input_buf[0])
pavone@524 382 {
pavone@524 383 case 'a':
pavone@524 384 param = find_param(input_buf);
pavone@524 385 if (!param) {
pavone@524 386 fputs("a command requires a parameter\n", stderr);
pavone@524 387 break;
pavone@524 388 }
pavone@524 389 value = strtol(param, NULL, 16);
pavone@524 390 zinsert_breakpoint(context, value, (uint8_t *)zdebugger);
pavone@524 391 debugging = 0;
pavone@524 392 break;
pavone@524 393 case 'b':
pavone@524 394 param = find_param(input_buf);
pavone@524 395 if (!param) {
pavone@524 396 fputs("b command requires a parameter\n", stderr);
pavone@524 397 break;
pavone@524 398 }
pavone@524 399 value = strtol(param, NULL, 16);
pavone@524 400 zinsert_breakpoint(context, value, (uint8_t *)zdebugger);
pavone@524 401 new_bp = malloc(sizeof(bp_def));
pavone@524 402 new_bp->next = zbreakpoints;
pavone@524 403 new_bp->address = value;
pavone@524 404 new_bp->index = zbp_index++;
pavone@867 405 new_bp->commands = NULL;
pavone@524 406 zbreakpoints = new_bp;
pavone@524 407 printf("Z80 Breakpoint %d set at %X\n", new_bp->index, value);
pavone@524 408 break;
pavone@524 409 case 'c':
pavone@524 410 puts("Continuing");
pavone@524 411 debugging = 0;
pavone@524 412 break;
pavone@524 413 case 'd':
pavone@524 414 if (input_buf[1] == 'i') {
pavone@524 415 char format_char = 0;
pavone@524 416 for(int i = 2; input_buf[i] != 0 && input_buf[i] != ' '; i++) {
pavone@524 417 if (input_buf[i] == '/') {
pavone@524 418 format_char = input_buf[i+1];
pavone@524 419 break;
pavone@524 420 }
pavone@524 421 }
pavone@524 422 param = find_param(input_buf);
pavone@524 423 if (!param) {
pavone@524 424 fputs("display command requires a parameter\n", stderr);
pavone@524 425 break;
pavone@524 426 }
pavone@524 427 zdebugger_print(context, format_char, param);
pavone@524 428 add_display(&zdisplays, &zdisp_index, format_char, param);
pavone@524 429 } else if (input_buf[1] == 'e' || input_buf[1] == ' ') {
pavone@524 430 param = find_param(input_buf);
pavone@524 431 if (!param) {
pavone@524 432 fputs("delete command requires a parameter\n", stderr);
pavone@524 433 break;
pavone@524 434 }
pavone@524 435 if (param[0] >= '0' && param[0] <= '9') {
pavone@524 436 value = atoi(param);
pavone@524 437 this_bp = find_breakpoint_idx(&zbreakpoints, value);
pavone@524 438 if (!*this_bp) {
pavone@524 439 fprintf(stderr, "Breakpoint %d does not exist\n", value);
pavone@524 440 break;
pavone@524 441 }
pavone@524 442 new_bp = *this_bp;
pavone@524 443 zremove_breakpoint(context, new_bp->address);
pavone@524 444 *this_bp = new_bp->next;
pavone@524 445 free(new_bp);
pavone@524 446 } else if (param[0] == 'd') {
pavone@524 447 param = find_param(param);
pavone@524 448 if (!param) {
pavone@524 449 fputs("delete display command requires a parameter\n", stderr);
pavone@524 450 break;
pavone@524 451 }
pavone@524 452 remove_display(&zdisplays, atoi(param));
pavone@524 453 }
pavone@524 454 }
pavone@524 455 break;
pavone@524 456 case 'n':
pavone@524 457 //TODO: Handle conditional branch instructions
pavone@524 458 if (inst.op == Z80_JP) {
pavone@524 459 if (inst.addr_mode == Z80_IMMED) {
pavone@524 460 after = inst.immed;
pavone@524 461 } else if (inst.ea_reg == Z80_HL) {
pavone@524 462 after = context->regs[Z80_H] << 8 | context->regs[Z80_L];
pavone@524 463 } else if (inst.ea_reg == Z80_IX) {
pavone@524 464 after = context->regs[Z80_IXH] << 8 | context->regs[Z80_IXL];
pavone@524 465 } else if (inst.ea_reg == Z80_IY) {
pavone@524 466 after = context->regs[Z80_IYH] << 8 | context->regs[Z80_IYL];
pavone@524 467 }
pavone@524 468 } else if(inst.op == Z80_JR) {
pavone@524 469 after += inst.immed;
pavone@524 470 } else if(inst.op == Z80_RET) {
pavone@524 471 if (context->sp < 0x4000) {
pavone@524 472 after = z80_ram[context->sp & 0x1FFF] | z80_ram[(context->sp+1) & 0x1FFF] << 8;
pavone@524 473 }
pavone@524 474 }
pavone@524 475 zinsert_breakpoint(context, after, (uint8_t *)zdebugger);
pavone@524 476 debugging = 0;
pavone@524 477 break;
pavone@524 478 case 'p':
pavone@524 479 param = find_param(input_buf);
pavone@524 480 if (!param) {
pavone@524 481 fputs("p command requires a parameter\n", stderr);
pavone@524 482 break;
pavone@524 483 }
pavone@524 484 zdebugger_print(context, input_buf[1] == '/' ? input_buf[2] : 0, param);
pavone@524 485 break;
pavone@524 486 case 'q':
pavone@524 487 puts("Quitting");
pavone@524 488 exit(0);
pavone@524 489 break;
pavone@524 490 case 's': {
pavone@524 491 param = find_param(input_buf);
pavone@524 492 if (!param) {
pavone@524 493 fputs("s command requires a file name\n", stderr);
pavone@524 494 break;
pavone@524 495 }
pavone@524 496 FILE * f = fopen(param, "wb");
pavone@524 497 if (f) {
pavone@524 498 if(fwrite(z80_ram, 1, sizeof(z80_ram), f) != sizeof(z80_ram)) {
pavone@524 499 fputs("Error writing file\n", stderr);
pavone@524 500 }
pavone@524 501 fclose(f);
pavone@524 502 } else {
pavone@524 503 fprintf(stderr, "Could not open %s for writing\n", param);
pavone@524 504 }
pavone@524 505 break;
pavone@524 506 }
pavone@524 507 default:
pavone@524 508 fprintf(stderr, "Unrecognized debugger command %s\n", input_buf);
pavone@524 509 break;
pavone@524 510 }
pavone@524 511 }
pavone@524 512 return context;
pavone@524 513 }
pavone@524 514
pavone@548 515 #endif
pavone@548 516
pavone@829 517 static uint32_t branch_t;
pavone@829 518 static uint32_t branch_f;
pavone@829 519
pavone@849 520 int run_debugger_command(m68k_context *context, char *input_buf, m68kinst inst, uint32_t after)
pavone@829 521 {
pavone@829 522 char * param;
pavone@829 523 char format_char;
pavone@849 524 uint32_t value;
pavone@829 525 bp_def *new_bp, **this_bp;
pavone@829 526 switch(input_buf[0])
pavone@829 527 {
pavone@829 528 case 'c':
pavone@830 529 if (input_buf[1] == 0 || input_buf[1] == 'o' && input_buf[2] == 'n')
pavone@830 530 {
pavone@830 531 puts("Continuing");
pavone@830 532 return 0;
pavone@830 533 } else if (input_buf[1] == 'o' && input_buf[2] == 'm') {
pavone@830 534 param = find_param(input_buf);
pavone@830 535 if (!param) {
pavone@830 536 fputs("com command requires a parameter\n", stderr);
pavone@830 537 break;
pavone@830 538 }
pavone@830 539 bp_def **target = find_breakpoint_idx(&breakpoints, atoi(param));
pavone@830 540 if (!target) {
pavone@830 541 fprintf(stderr, "Breakpoint %s does not exist!\n", param);
pavone@830 542 break;
pavone@830 543 }
pavone@830 544 printf("Enter commands for breakpoing %d, type end when done\n", atoi(param));
pavone@830 545 char cmd_buf[1024];
pavone@830 546 char *commands = NULL;
pavone@830 547 for (;;)
pavone@830 548 {
pavone@830 549 fputs(">>", stdout);
pavone@830 550 fflush(stdout);
pavone@830 551 fgets(cmd_buf, sizeof(cmd_buf), stdin);
pavone@830 552 if (strcmp(cmd_buf, "end\n")) {
pavone@830 553 if (commands) {
pavone@830 554 char *tmp = commands;
pavone@830 555 commands = alloc_concat(commands, cmd_buf);
pavone@830 556 free(tmp);
pavone@830 557 } else {
pavone@830 558 commands = strdup(cmd_buf);
pavone@830 559 }
pavone@830 560 } else {
pavone@830 561 break;
pavone@830 562 }
pavone@830 563 }
pavone@830 564 (*target)->commands = commands;
pavone@830 565 } else {
pavone@830 566 }
pavone@829 567 case 'b':
pavone@829 568 if (input_buf[1] == 't') {
pavone@829 569 uint32_t stack = context->aregs[7];
pavone@829 570 if (stack >= 0xE00000) {
pavone@829 571 stack &= 0xFFFF;
pavone@829 572 uint8_t non_adr_count = 0;
pavone@829 573 do {
pavone@829 574 uint32_t bt_address = ram[stack/2] << 16 | ram[stack/2+1];
pavone@985 575 bt_address = get_instruction_start(context->options, context->native_code_map, bt_address - 2);
pavone@829 576 if (bt_address) {
pavone@829 577 stack += 4;
pavone@829 578 non_adr_count = 0;
pavone@829 579 uint16_t *bt_pc = NULL;
pavone@829 580 if (bt_address < 0x400000) {
pavone@829 581 bt_pc = cart + bt_address/2;
pavone@829 582 } else if(bt_address > 0xE00000) {
pavone@829 583 bt_pc = ram + (bt_address & 0xFFFF)/2;
pavone@829 584 }
pavone@829 585 m68k_decode(bt_pc, &inst, bt_address);
pavone@829 586 m68k_disasm(&inst, input_buf);
pavone@829 587 printf("%X: %s\n", bt_address, input_buf);
pavone@829 588 } else {
pavone@829 589 //non-return address value on stack can be word wide
pavone@829 590 stack += 2;
pavone@829 591 non_adr_count++;
pavone@829 592 }
pavone@829 593 stack &= 0xFFFF;
pavone@829 594 } while (stack && non_adr_count < 6);
pavone@829 595 }
pavone@829 596 } else {
pavone@829 597 param = find_param(input_buf);
pavone@829 598 if (!param) {
pavone@829 599 fputs("b command requires a parameter\n", stderr);
pavone@829 600 break;
pavone@829 601 }
pavone@829 602 value = strtol(param, NULL, 16);
pavone@829 603 insert_breakpoint(context, value, (uint8_t *)debugger);
pavone@829 604 new_bp = malloc(sizeof(bp_def));
pavone@829 605 new_bp->next = breakpoints;
pavone@829 606 new_bp->address = value;
pavone@829 607 new_bp->index = bp_index++;
pavone@919 608 new_bp->commands = NULL;
pavone@829 609 breakpoints = new_bp;
pavone@829 610 printf("68K Breakpoint %d set at %X\n", new_bp->index, value);
pavone@829 611 }
pavone@829 612 break;
pavone@829 613 case 'a':
pavone@829 614 param = find_param(input_buf);
pavone@829 615 if (!param) {
pavone@829 616 fputs("a command requires a parameter\n", stderr);
pavone@829 617 break;
pavone@829 618 }
pavone@829 619 value = strtol(param, NULL, 16);
pavone@829 620 insert_breakpoint(context, value, (uint8_t *)debugger);
pavone@829 621 return 0;
pavone@829 622 case 'd':
pavone@829 623 if (input_buf[1] == 'i') {
pavone@829 624 format_char = 0;
pavone@829 625 for(int i = 2; input_buf[i] != 0 && input_buf[i] != ' '; i++) {
pavone@829 626 if (input_buf[i] == '/') {
pavone@829 627 format_char = input_buf[i+1];
pavone@829 628 break;
pavone@829 629 }
pavone@829 630 }
pavone@829 631 param = find_param(input_buf);
pavone@829 632 if (!param) {
pavone@829 633 fputs("display command requires a parameter\n", stderr);
pavone@829 634 break;
pavone@829 635 }
pavone@829 636 debugger_print(context, format_char, param);
pavone@829 637 add_display(&displays, &disp_index, format_char, param);
pavone@829 638 } else {
pavone@829 639 param = find_param(input_buf);
pavone@829 640 if (!param) {
pavone@829 641 fputs("d command requires a parameter\n", stderr);
pavone@829 642 break;
pavone@829 643 }
pavone@829 644 value = atoi(param);
pavone@829 645 this_bp = find_breakpoint_idx(&breakpoints, value);
pavone@829 646 if (!*this_bp) {
pavone@829 647 fprintf(stderr, "Breakpoint %d does not exist\n", value);
pavone@829 648 break;
pavone@829 649 }
pavone@829 650 new_bp = *this_bp;
pavone@829 651 *this_bp = (*this_bp)->next;
pavone@830 652 if (new_bp->commands) {
pavone@830 653 free(new_bp->commands);
pavone@830 654 }
pavone@829 655 free(new_bp);
pavone@829 656 }
pavone@829 657 break;
pavone@829 658 case 'p':
pavone@829 659 format_char = 0;
pavone@831 660 for(int i = 1; input_buf[i] != 0 && input_buf[i] != ' '; i++) {
pavone@829 661 if (input_buf[i] == '/') {
pavone@829 662 format_char = input_buf[i+1];
pavone@829 663 break;
pavone@829 664 }
pavone@829 665 }
pavone@829 666 param = find_param(input_buf);
pavone@829 667 if (!param) {
pavone@829 668 fputs("p command requires a parameter\n", stderr);
pavone@829 669 break;
pavone@829 670 }
pavone@829 671 debugger_print(context, format_char, param);
pavone@829 672 break;
pavone@829 673 case 'n':
pavone@829 674 if (inst.op == M68K_RTS) {
pavone@829 675 after = (read_dma_value(context->aregs[7]/2) << 16) | read_dma_value(context->aregs[7]/2 + 1);
pavone@829 676 } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) {
pavone@829 677 after = (read_dma_value((context->aregs[7]+2)/2) << 16) | read_dma_value((context->aregs[7]+2)/2 + 1);
pavone@829 678 } else if(m68k_is_noncall_branch(&inst)) {
pavone@829 679 if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
pavone@829 680 branch_f = after;
pavone@829 681 branch_t = m68k_branch_target(&inst, context->dregs, context->aregs);
pavone@829 682 insert_breakpoint(context, branch_t, (uint8_t *)debugger);
pavone@829 683 } else if(inst.op == M68K_DBCC) {
pavone@829 684 if ( inst.extra.cond == COND_FALSE) {
pavone@829 685 if (context->dregs[inst.dst.params.regs.pri] & 0xFFFF) {
pavone@829 686 after = m68k_branch_target(&inst, context->dregs, context->aregs);
pavone@829 687 }
pavone@829 688 } else {
pavone@829 689 branch_t = after;
pavone@829 690 branch_f = m68k_branch_target(&inst, context->dregs, context->aregs);
pavone@829 691 insert_breakpoint(context, branch_f, (uint8_t *)debugger);
pavone@829 692 }
pavone@829 693 } else {
pavone@829 694 after = m68k_branch_target(&inst, context->dregs, context->aregs);
pavone@829 695 }
pavone@829 696 }
pavone@829 697 insert_breakpoint(context, after, (uint8_t *)debugger);
pavone@829 698 return 0;
pavone@829 699 case 'o':
pavone@829 700 if (inst.op == M68K_RTS) {
pavone@829 701 after = (read_dma_value(context->aregs[7]/2) << 16) | read_dma_value(context->aregs[7]/2 + 1);
pavone@829 702 } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) {
pavone@829 703 after = (read_dma_value((context->aregs[7]+2)/2) << 16) | read_dma_value((context->aregs[7]+2)/2 + 1);
pavone@829 704 } else if(m68k_is_noncall_branch(&inst)) {
pavone@829 705 if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
pavone@829 706 branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
pavone@829 707 if (branch_t < after) {
pavone@829 708 branch_t = 0;
pavone@829 709 } else {
pavone@829 710 branch_f = after;
pavone@829 711 insert_breakpoint(context, branch_t, (uint8_t *)debugger);
pavone@829 712 }
pavone@829 713 } else if(inst.op == M68K_DBCC) {
pavone@829 714 uint32_t target = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
pavone@829 715 if (target > after) {
pavone@829 716 if (inst.extra.cond == COND_FALSE) {
pavone@829 717 after = target;
pavone@829 718 } else {
pavone@829 719 branch_f = target;
pavone@829 720 branch_t = after;
pavone@829 721 insert_breakpoint(context, branch_f, (uint8_t *)debugger);
pavone@829 722 }
pavone@829 723 }
pavone@829 724 } else {
pavone@829 725 after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
pavone@829 726 }
pavone@829 727 }
pavone@829 728 insert_breakpoint(context, after, (uint8_t *)debugger);
pavone@829 729 return 0;
pavone@829 730 case 's':
pavone@829 731 if (inst.op == M68K_RTS) {
pavone@829 732 after = (read_dma_value(context->aregs[7]/2) << 16) | read_dma_value(context->aregs[7]/2 + 1);
pavone@829 733 } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) {
pavone@829 734 after = (read_dma_value((context->aregs[7]+2)/2) << 16) | read_dma_value((context->aregs[7]+2)/2 + 1);
pavone@829 735 } else if(m68k_is_branch(&inst)) {
pavone@829 736 if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
pavone@829 737 branch_f = after;
pavone@829 738 branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
pavone@829 739 insert_breakpoint(context, branch_t, (uint8_t *)debugger);
pavone@829 740 } else if(inst.op == M68K_DBCC && inst.extra.cond != COND_FALSE) {
pavone@829 741 branch_t = after;
pavone@829 742 branch_f = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
pavone@829 743 insert_breakpoint(context, branch_f, (uint8_t *)debugger);
pavone@829 744 } else {
pavone@829 745 after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
pavone@829 746 }
pavone@829 747 }
pavone@829 748 insert_breakpoint(context, after, (uint8_t *)debugger);
pavone@829 749 return 0;
pavone@829 750 case 'v': {
pavone@829 751 genesis_context * gen = context->system;
pavone@829 752 //VDP debug commands
pavone@829 753 switch(input_buf[1])
pavone@829 754 {
pavone@829 755 case 's':
pavone@829 756 vdp_print_sprite_table(gen->vdp);
pavone@829 757 break;
pavone@829 758 case 'r':
pavone@829 759 vdp_print_reg_explain(gen->vdp);
pavone@829 760 break;
pavone@829 761 }
pavone@829 762 break;
pavone@829 763 }
pavone@829 764 case 'y': {
pavone@829 765 genesis_context * gen = context->system;
pavone@829 766 //YM-2612 debug commands
pavone@829 767 switch(input_buf[1])
pavone@829 768 {
pavone@829 769 case 'c':
pavone@829 770 if (input_buf[2] == ' ') {
pavone@829 771 int channel = atoi(input_buf+3)-1;
pavone@829 772 ym_print_channel_info(gen->ym, channel);
pavone@829 773 } else {
pavone@829 774 for (int i = 0; i < 6; i++) {
pavone@829 775 ym_print_channel_info(gen->ym, i);
pavone@829 776 }
pavone@829 777 }
pavone@930 778 break;
pavone@930 779 case 't':
pavone@930 780 ym_print_timer_info(gen->ym);
pavone@930 781 break;
pavone@829 782 }
pavone@829 783 break;
pavone@829 784 }
pavone@829 785 #ifndef NO_Z80
pavone@829 786 case 'z': {
pavone@829 787 genesis_context * gen = context->system;
pavone@829 788 //Z80 debug commands
pavone@829 789 switch(input_buf[1])
pavone@829 790 {
pavone@829 791 case 'b':
pavone@829 792 param = find_param(input_buf);
pavone@829 793 if (!param) {
pavone@829 794 fputs("zb command requires a parameter\n", stderr);
pavone@829 795 break;
pavone@829 796 }
pavone@829 797 value = strtol(param, NULL, 16);
pavone@829 798 zinsert_breakpoint(gen->z80, value, (uint8_t *)zdebugger);
pavone@829 799 new_bp = malloc(sizeof(bp_def));
pavone@829 800 new_bp->next = zbreakpoints;
pavone@829 801 new_bp->address = value;
pavone@829 802 new_bp->index = zbp_index++;
pavone@829 803 zbreakpoints = new_bp;
pavone@829 804 printf("Z80 Breakpoint %d set at %X\n", new_bp->index, value);
pavone@829 805 break;
pavone@829 806 case 'p':
pavone@829 807 param = find_param(input_buf);
pavone@829 808 if (!param) {
pavone@829 809 fputs("zp command requires a parameter\n", stderr);
pavone@829 810 break;
pavone@829 811 }
pavone@829 812 zdebugger_print(gen->z80, input_buf[2] == '/' ? input_buf[3] : 0, param);
pavone@829 813 }
pavone@829 814 break;
pavone@829 815 }
pavone@829 816 #endif
pavone@829 817 case 'q':
pavone@829 818 puts("Quitting");
pavone@829 819 exit(0);
pavone@829 820 break;
pavone@829 821 default:
pavone@829 822 fprintf(stderr, "Unrecognized debugger command %s\n", input_buf);
pavone@829 823 break;
pavone@829 824 }
pavone@829 825 return 1;
pavone@829 826 }
pavone@829 827
pavone@829 828
pavone@524 829 m68k_context * debugger(m68k_context * context, uint32_t address)
pavone@524 830 {
pavone@524 831 static char last_cmd[1024];
pavone@524 832 char input_buf[1024];
pavone@524 833 m68kinst inst;
pavone@830 834
pavone@794 835 init_terminal();
pavone@830 836
pavone@707 837 sync_components(context, 0);
pavone@524 838 //probably not necessary, but let's play it safe
pavone@524 839 address &= 0xFFFFFF;
pavone@524 840 if (address == branch_t) {
pavone@524 841 bp_def ** f_bp = find_breakpoint(&breakpoints, branch_f);
pavone@524 842 if (!*f_bp) {
pavone@524 843 remove_breakpoint(context, branch_f);
pavone@524 844 }
pavone@524 845 branch_t = branch_f = 0;
pavone@524 846 } else if(address == branch_f) {
pavone@524 847 bp_def ** t_bp = find_breakpoint(&breakpoints, branch_t);
pavone@524 848 if (!*t_bp) {
pavone@524 849 remove_breakpoint(context, branch_t);
pavone@524 850 }
pavone@524 851 branch_t = branch_f = 0;
pavone@524 852 }
pavone@849 853
pavone@849 854 uint16_t * pc;
pavone@849 855 if (address < 0x400000) {
pavone@849 856 pc = cart + address/2;
pavone@849 857 } else if(address > 0xE00000) {
pavone@849 858 pc = ram + (address & 0xFFFF)/2;
pavone@849 859 } else {
pavone@849 860 fatal_error("Entered 68K debugger at address %X\n", address);
pavone@849 861 }
pavone@849 862 uint16_t * after_pc = m68k_decode(pc, &inst, address);
pavone@849 863 uint32_t after = address + (after_pc-pc)*2;
pavone@830 864 int debugging = 1;
pavone@524 865 //Check if this is a user set breakpoint, or just a temporary one
pavone@524 866 bp_def ** this_bp = find_breakpoint(&breakpoints, address);
pavone@524 867 if (*this_bp) {
pavone@830 868
pavone@830 869 if ((*this_bp)->commands)
pavone@830 870 {
pavone@830 871 char *commands = strdup((*this_bp)->commands);
pavone@830 872 char *copy = commands;
pavone@830 873
pavone@830 874 while (debugging && *commands)
pavone@830 875 {
pavone@830 876 char *cmd = commands;
pavone@830 877 strip_nl(cmd);
pavone@830 878 commands += strlen(cmd) + 1;
pavone@849 879 debugging = run_debugger_command(context, cmd, inst, after);
pavone@830 880 }
pavone@830 881 free(copy);
pavone@830 882 }
pavone@830 883 if (debugging) {
pavone@830 884 printf("68K Breakpoint %d hit\n", (*this_bp)->index);
pavone@830 885 } else {
pavone@830 886 return context;
pavone@830 887 }
pavone@524 888 } else {
pavone@524 889 remove_breakpoint(context, address);
pavone@524 890 }
pavone@829 891 for (disp_def * cur = displays; cur; cur = cur->next) {
pavone@829 892 debugger_print(context, cur->format_char, cur->param);
pavone@829 893 }
pavone@524 894 m68k_disasm(&inst, input_buf);
pavone@524 895 printf("%X: %s\n", address, input_buf);
pavone@745 896 #ifdef _WIN32
pavone@745 897 #define prompt 1
pavone@745 898 #else
pavone@723 899 int prompt = 1;
pavone@723 900 fd_set read_fds;
pavone@723 901 FD_ZERO(&read_fds);
pavone@723 902 struct timeval timeout;
pavone@745 903 #endif
pavone@524 904 while (debugging) {
pavone@723 905 if (prompt) {
pavone@723 906 fputs(">", stdout);
pavone@723 907 fflush(stdout);
pavone@723 908 }
pavone@723 909 process_events();
pavone@745 910 #ifndef _WIN32
pavone@723 911 timeout.tv_sec = 0;
pavone@723 912 timeout.tv_usec = 16667;
pavone@723 913 FD_SET(fileno(stdin), &read_fds);
pavone@723 914 if(select(fileno(stdin) + 1, &read_fds, NULL, NULL, &timeout) < 1) {
pavone@723 915 prompt = 0;
pavone@723 916 continue;
pavone@723 917 } else {
pavone@723 918 prompt = 1;
pavone@723 919 }
pavone@745 920 #endif
pavone@524 921 if (!fgets(input_buf, sizeof(input_buf), stdin)) {
pavone@524 922 fputs("fgets failed", stderr);
pavone@524 923 break;
pavone@524 924 }
pavone@524 925 strip_nl(input_buf);
pavone@524 926 //hitting enter repeats last command
pavone@524 927 if (input_buf[0]) {
pavone@524 928 strcpy(last_cmd, input_buf);
pavone@524 929 } else {
pavone@524 930 strcpy(input_buf, last_cmd);
pavone@524 931 }
pavone@849 932 debugging = run_debugger_command(context, input_buf, inst, after);
pavone@524 933 }
pavone@524 934 return context;
pavone@524 935 }