comparison debug.c @ 2045:b119e0de9a70 proprietary

Strip out mega wifi support and debugger
author Michael Pavone <pavone@retrodev.com>
date Tue, 21 Sep 2021 23:17:34 -0700
parents a7b753e260a2
children
comparison
equal deleted inserted replaced
2043:804954731e3f 2045:b119e0de9a70
111 return m68k_read_word(address, context) << 16 | m68k_read_word(address + 2, context); 111 return m68k_read_word(address, context) << 16 | m68k_read_word(address + 2, context);
112 } 112 }
113 113
114 void debugger_print(m68k_context *context, char format_char, char *param, uint32_t address) 114 void debugger_print(m68k_context *context, char format_char, char *param, uint32_t address)
115 { 115 {
116 uint32_t value;
117 char format[8];
118 strcpy(format, "%s: %d\n");
119 switch (format_char)
120 {
121 case 'x':
122 case 'X':
123 case 'd':
124 case 'c':
125 format[5] = format_char;
126 break;
127 case '\0':
128 break;
129 default:
130 fprintf(stderr, "Unrecognized format character: %c\n", format_char);
131 }
132 if (param[0] == 'd' && param[1] >= '0' && param[1] <= '7') {
133 value = context->dregs[param[1]-'0'];
134 if (param[2] == '.') {
135 if (param[3] == 'w') {
136 value &= 0xFFFF;
137 } else if (param[3] == 'b') {
138 value &= 0xFF;
139 }
140 }
141 } else if (param[0] == 'a' && param[1] >= '0' && param[1] <= '7') {
142 value = context->aregs[param[1]-'0'];
143 if (param[2] == '.') {
144 if (param[3] == 'w') {
145 value &= 0xFFFF;
146 } else if (param[3] == 'b') {
147 value &= 0xFF;
148 }
149 }
150 } else if (param[0] == 's' && param[1] == 'r') {
151 value = (context->status << 8);
152 for (int flag = 0; flag < 5; flag++) {
153 value |= context->flags[flag] << (4-flag);
154 }
155 } else if(param[0] == 'c') {
156 value = context->current_cycle;
157 } else if(param[0] == 'f') {
158 genesis_context *gen = context->system;
159 value = gen->vdp->frame;
160 } else if (param[0] == 'p' && param[1] == 'c') {
161 value = address;
162 } else if ((param[0] == '0' && param[1] == 'x') || param[0] == '$') {
163 char *after;
164 uint32_t p_addr = strtol(param+(param[0] == '0' ? 2 : 1), &after, 16);
165 if (after[0] == '.' && after[1] == 'l') {
166 value = m68k_read_long(p_addr, context);
167 } else if (after[0] == '.' && after[1] == 'b') {
168 value = m68k_read_byte(p_addr, context);
169 } else {
170 value = m68k_read_word(p_addr, context);
171 }
172 } else if(param[0] == '(' && (param[1] == 'a' || param[1] == 'd') && param[2] >= '0' && param[2] <= '7' && param[3] == ')') {
173 uint8_t reg = param[2] - '0';
174 uint32_t p_addr = param[1] == 'a' ? context->aregs[reg] : context->dregs[reg];
175 if (param[4] == '.' && param[5] == 'l') {
176 value = m68k_read_long(p_addr, context);
177 } else if (param[4] == '.' && param[5] == 'b') {
178 value = m68k_read_byte(p_addr, context);
179 } else {
180 value = m68k_read_word(p_addr, context);
181 }
182 } else {
183 fprintf(stderr, "Unrecognized parameter to p: %s\n", param);
184 return;
185 }
186 printf(format, param, value);
187 } 116 }
188 117
189 #ifndef NO_Z80 118 #ifndef NO_Z80
190 119
191 void zdebugger_print(z80_context * context, char format_char, char * param) 120 void zdebugger_print(z80_context * context, char format_char, char * param)
192 { 121 {
193 uint32_t value;
194 char format[8];
195 strcpy(format, "%s: %d\n");
196 genesis_context *system = context->system;
197 switch (format_char)
198 {
199 case 'x':
200 case 'X':
201 case 'd':
202 case 'c':
203 format[5] = format_char;
204 break;
205 case '\0':
206 break;
207 default:
208 fprintf(stderr, "Unrecognized format character: %c\n", format_char);
209 }
210 switch (param[0])
211 {
212 #ifndef NEW_CORE
213 case 'a':
214 if (param[1] == 'f') {
215 if(param[2] == '\'') {
216 value = context->alt_regs[Z80_A] << 8;
217 value |= context->alt_flags[ZF_S] << 7;
218 value |= context->alt_flags[ZF_Z] << 6;
219 value |= context->alt_flags[ZF_H] << 4;
220 value |= context->alt_flags[ZF_PV] << 2;
221 value |= context->alt_flags[ZF_N] << 1;
222 value |= context->alt_flags[ZF_C];
223 } else {
224 value = context->regs[Z80_A] << 8;
225 value |= context->flags[ZF_S] << 7;
226 value |= context->flags[ZF_Z] << 6;
227 value |= context->flags[ZF_H] << 4;
228 value |= context->flags[ZF_PV] << 2;
229 value |= context->flags[ZF_N] << 1;
230 value |= context->flags[ZF_C];
231 }
232 } else if(param[1] == '\'') {
233 value = context->alt_regs[Z80_A];
234 } else {
235 value = context->regs[Z80_A];
236 }
237 break;
238 case 'b':
239 if (param[1] == 'c') {
240 if(param[2] == '\'') {
241 value = context->alt_regs[Z80_B] << 8;
242 value |= context->alt_regs[Z80_C];
243 } else {
244 value = context->regs[Z80_B] << 8;
245 value |= context->regs[Z80_C];
246 }
247 } else if(param[1] == '\'') {
248 value = context->alt_regs[Z80_B];
249 } else if(param[1] == 'a') {
250 value = context->bank_reg << 15;
251 } else {
252 value = context->regs[Z80_B];
253 }
254 break;
255 case 'c':
256 if(param[1] == '\'') {
257 value = context->alt_regs[Z80_C];
258 } else if(param[1] == 'y') {
259 value = context->current_cycle;
260 } else {
261 value = context->regs[Z80_C];
262 }
263 break;
264 case 'd':
265 if (param[1] == 'e') {
266 if(param[2] == '\'') {
267 value = context->alt_regs[Z80_D] << 8;
268 value |= context->alt_regs[Z80_E];
269 } else {
270 value = context->regs[Z80_D] << 8;
271 value |= context->regs[Z80_E];
272 }
273 } else if(param[1] == '\'') {
274 value = context->alt_regs[Z80_D];
275 } else {
276 value = context->regs[Z80_D];
277 }
278 break;
279 case 'e':
280 if(param[1] == '\'') {
281 value = context->alt_regs[Z80_E];
282 } else {
283 value = context->regs[Z80_E];
284 }
285 break;
286 case 'f':
287 if(param[2] == '\'') {
288 value = context->alt_flags[ZF_S] << 7;
289 value |= context->alt_flags[ZF_Z] << 6;
290 value |= context->alt_flags[ZF_H] << 4;
291 value |= context->alt_flags[ZF_PV] << 2;
292 value |= context->alt_flags[ZF_N] << 1;
293 value |= context->alt_flags[ZF_C];
294 } else {
295 value = context->flags[ZF_S] << 7;
296 value |= context->flags[ZF_Z] << 6;
297 value |= context->flags[ZF_H] << 4;
298 value |= context->flags[ZF_PV] << 2;
299 value |= context->flags[ZF_N] << 1;
300 value |= context->flags[ZF_C];
301 }
302 break;
303 case 'h':
304 if (param[1] == 'l') {
305 if(param[2] == '\'') {
306 value = context->alt_regs[Z80_H] << 8;
307 value |= context->alt_regs[Z80_L];
308 } else {
309 value = context->regs[Z80_H] << 8;
310 value |= context->regs[Z80_L];
311 }
312 } else if(param[1] == '\'') {
313 value = context->alt_regs[Z80_H];
314 } else {
315 value = context->regs[Z80_H];
316 }
317 break;
318 case 'l':
319 if(param[1] == '\'') {
320 value = context->alt_regs[Z80_L];
321 } else {
322 value = context->regs[Z80_L];
323 }
324 break;
325 case 'i':
326 if(param[1] == 'x') {
327 if (param[2] == 'h') {
328 value = context->regs[Z80_IXH];
329 } else if(param[2] == 'l') {
330 value = context->regs[Z80_IXL];
331 } else {
332 value = context->regs[Z80_IXH] << 8;
333 value |= context->regs[Z80_IXL];
334 }
335 } else if(param[1] == 'y') {
336 if (param[2] == 'h') {
337 value = context->regs[Z80_IYH];
338 } else if(param[2] == 'l') {
339 value = context->regs[Z80_IYL];
340 } else {
341 value = context->regs[Z80_IYH] << 8;
342 value |= context->regs[Z80_IYL];
343 }
344 } else if(param[1] == 'n') {
345 value = context->int_cycle;
346 } else if(param[1] == 'f' && param[2] == 'f' && param[3] == '1') {
347 value = context->iff1;
348 } else if(param[1] == 'f' && param[2] == 'f' && param[3] == '2') {
349 value = context->iff2;
350 } else {
351 value = context->im;
352 }
353 break;
354 #endif
355 case 's':
356 if (param[1] == 'p') {
357 value = context->sp;
358 }
359 break;
360 case '0':
361 if (param[1] == 'x') {
362 uint16_t p_addr = strtol(param+2, NULL, 16);
363 value = read_byte(p_addr, (void **)context->mem_pointers, &context->options->gen, context);
364 }
365 break;
366 }
367 printf(format, param, value);
368 } 122 }
369 123
370 z80_context * zdebugger(z80_context * context, uint16_t address) 124 z80_context * zdebugger(z80_context * context, uint16_t address)
371 { 125 {
372 static char last_cmd[1024];
373 char input_buf[1024];
374 static uint16_t branch_t;
375 static uint16_t branch_f;
376 z80inst inst;
377 genesis_context *system = context->system;
378 init_terminal();
379 //Check if this is a user set breakpoint, or just a temporary one
380 bp_def ** this_bp = find_breakpoint(&zbreakpoints, address);
381 if (*this_bp) {
382 printf("Z80 Breakpoint %d hit\n", (*this_bp)->index);
383 } else {
384 zremove_breakpoint(context, address);
385 }
386 uint8_t * pc = get_native_pointer(address, (void **)context->mem_pointers, &context->Z80_OPTS->gen);
387 if (!pc) {
388 fatal_error("Failed to get native pointer on entering Z80 debugger at address %X\n", address);
389 }
390 for (disp_def * cur = zdisplays; cur; cur = cur->next) {
391 zdebugger_print(context, cur->format_char, cur->param);
392 }
393 uint8_t * after_pc = z80_decode(pc, &inst);
394 z80_disasm(&inst, input_buf, address);
395 printf("%X:\t%s\n", address, input_buf);
396 uint16_t after = address + (after_pc-pc);
397 int debugging = 1;
398 while(debugging) {
399 fputs(">", stdout);
400 if (!fgets(input_buf, sizeof(input_buf), stdin)) {
401 fputs("fgets failed", stderr);
402 break;
403 }
404 strip_nl(input_buf);
405 //hitting enter repeats last command
406 if (input_buf[0]) {
407 strcpy(last_cmd, input_buf);
408 } else {
409 strcpy(input_buf, last_cmd);
410 }
411 char * param;
412 char format[8];
413 uint32_t value;
414 bp_def * new_bp;
415 switch(input_buf[0])
416 {
417 case 'a':
418 param = find_param(input_buf);
419 if (!param) {
420 fputs("a command requires a parameter\n", stderr);
421 break;
422 }
423 value = strtol(param, NULL, 16);
424 zinsert_breakpoint(context, value, (uint8_t *)zdebugger);
425 debugging = 0;
426 break;
427 case 'b':
428 param = find_param(input_buf);
429 if (!param) {
430 fputs("b command requires a parameter\n", stderr);
431 break;
432 }
433 value = strtol(param, NULL, 16);
434 zinsert_breakpoint(context, value, (uint8_t *)zdebugger);
435 new_bp = malloc(sizeof(bp_def));
436 new_bp->next = zbreakpoints;
437 new_bp->address = value;
438 new_bp->index = zbp_index++;
439 new_bp->commands = NULL;
440 zbreakpoints = new_bp;
441 printf("Z80 Breakpoint %d set at %X\n", new_bp->index, value);
442 break;
443 case 'c':
444 puts("Continuing");
445 debugging = 0;
446 break;
447 case 'd':
448 if (input_buf[1] == 'i') {
449 char format_char = 0;
450 for(int i = 2; input_buf[i] != 0 && input_buf[i] != ' '; i++) {
451 if (input_buf[i] == '/') {
452 format_char = input_buf[i+1];
453 break;
454 }
455 }
456 param = find_param(input_buf);
457 if (!param) {
458 fputs("display command requires a parameter\n", stderr);
459 break;
460 }
461 zdebugger_print(context, format_char, param);
462 add_display(&zdisplays, &zdisp_index, format_char, param);
463 } else if (input_buf[1] == 'e' || input_buf[1] == ' ') {
464 param = find_param(input_buf);
465 if (!param) {
466 fputs("delete command requires a parameter\n", stderr);
467 break;
468 }
469 if (param[0] >= '0' && param[0] <= '9') {
470 value = atoi(param);
471 this_bp = find_breakpoint_idx(&zbreakpoints, value);
472 if (!*this_bp) {
473 fprintf(stderr, "Breakpoint %d does not exist\n", value);
474 break;
475 }
476 new_bp = *this_bp;
477 zremove_breakpoint(context, new_bp->address);
478 *this_bp = new_bp->next;
479 free(new_bp);
480 } else if (param[0] == 'd') {
481 param = find_param(param);
482 if (!param) {
483 fputs("delete display command requires a parameter\n", stderr);
484 break;
485 }
486 remove_display(&zdisplays, atoi(param));
487 }
488 }
489 break;
490 case 'n':
491 //TODO: Handle conditional branch instructions
492 if (inst.op == Z80_JP) {
493 if (inst.addr_mode == Z80_IMMED) {
494 after = inst.immed;
495 } else if (inst.ea_reg == Z80_HL) {
496 #ifndef NEW_CORE
497 after = context->regs[Z80_H] << 8 | context->regs[Z80_L];
498 } else if (inst.ea_reg == Z80_IX) {
499 after = context->regs[Z80_IXH] << 8 | context->regs[Z80_IXL];
500 } else if (inst.ea_reg == Z80_IY) {
501 after = context->regs[Z80_IYH] << 8 | context->regs[Z80_IYL];
502 #endif
503 }
504 } else if(inst.op == Z80_JR) {
505 after += inst.immed;
506 } else if(inst.op == Z80_RET) {
507 uint8_t *sp = get_native_pointer(context->sp, (void **)context->mem_pointers, &context->Z80_OPTS->gen);
508 if (sp) {
509 after = *sp;
510 sp = get_native_pointer((context->sp + 1) & 0xFFFF, (void **)context->mem_pointers, &context->Z80_OPTS->gen);
511 if (sp) {
512 after |= *sp << 8;
513 }
514 }
515 }
516 zinsert_breakpoint(context, after, (uint8_t *)zdebugger);
517 debugging = 0;
518 break;
519 case 'p':
520 param = find_param(input_buf);
521 if (!param) {
522 fputs("p command requires a parameter\n", stderr);
523 break;
524 }
525 zdebugger_print(context, input_buf[1] == '/' ? input_buf[2] : 0, param);
526 break;
527 case 'q':
528 puts("Quitting");
529 exit(0);
530 break;
531 case 's': {
532 param = find_param(input_buf);
533 if (!param) {
534 fputs("s command requires a file name\n", stderr);
535 break;
536 }
537 memmap_chunk const *ram_chunk = NULL;
538 for (int i = 0; i < context->Z80_OPTS->gen.memmap_chunks; i++)
539 {
540 memmap_chunk const *cur = context->Z80_OPTS->gen.memmap + i;
541 if (cur->flags & MMAP_WRITE) {
542 ram_chunk = cur;
543 break;
544 }
545 }
546 if (ram_chunk) {
547 uint32_t size = ram_chunk->end - ram_chunk->start;
548 if (size > ram_chunk->mask) {
549 size = ram_chunk->mask+1;
550 }
551 uint8_t *buf = get_native_pointer(ram_chunk->start, (void **)context->mem_pointers, &context->Z80_OPTS->gen);
552 FILE * f = fopen(param, "wb");
553 if (f) {
554 if(fwrite(buf, 1, size, f) != size) {
555 fputs("Error writing file\n", stderr);
556 }
557 fclose(f);
558 printf("Wrote %d bytes to %s\n", size, param);
559 } else {
560 fprintf(stderr, "Could not open %s for writing\n", param);
561 }
562 } else {
563 fputs("Failed to find a RAM memory chunk\n", stderr);
564 }
565 break;
566 }
567 case '?':
568 print_z80_help();
569 break;
570 default:
571 if (
572 !context->Z80_OPTS->gen.debug_cmd_handler
573 || !context->Z80_OPTS->gen.debug_cmd_handler(&system->header, input_buf)
574 ) {
575 fprintf(stderr, "Unrecognized debugger command %s\nUse '?' for help.\n", input_buf);
576 }
577 break;
578 }
579 }
580 return context; 126 return context;
581 } 127 }
582 128
583 #endif 129 #endif
584 130
585 static uint32_t branch_t;
586 static uint32_t branch_f;
587
588 int run_debugger_command(m68k_context *context, uint32_t address, char *input_buf, m68kinst inst, uint32_t after)
589 {
590 char * param;
591 char format_char;
592 genesis_context *system = context->system;
593 uint32_t value;
594 bp_def *new_bp, **this_bp;
595 switch(input_buf[0])
596 {
597 case 'c':
598 if (input_buf[1] == 0 || input_buf[1] == 'o' && input_buf[2] == 'n')
599 {
600 puts("Continuing");
601 return 0;
602 } else if (input_buf[1] == 'o' && input_buf[2] == 'm') {
603 param = find_param(input_buf);
604 if (!param) {
605 fputs("com command requires a parameter\n", stderr);
606 break;
607 }
608 bp_def **target = find_breakpoint_idx(&breakpoints, atoi(param));
609 if (!target) {
610 fprintf(stderr, "Breakpoint %s does not exist!\n", param);
611 break;
612 }
613 printf("Enter commands for breakpoing %d, type end when done\n", atoi(param));
614 char cmd_buf[1024];
615 char *commands = NULL;
616 for (;;)
617 {
618 fputs(">>", stdout);
619 fflush(stdout);
620 fgets(cmd_buf, sizeof(cmd_buf), stdin);
621 if (strcmp(cmd_buf, "end\n")) {
622 if (commands) {
623 char *tmp = commands;
624 commands = alloc_concat(commands, cmd_buf);
625 free(tmp);
626 } else {
627 commands = strdup(cmd_buf);
628 }
629 } else {
630 break;
631 }
632 }
633 (*target)->commands = commands;
634 } else {
635 }
636 break;
637 case 'b':
638 if (input_buf[1] == 't') {
639 uint32_t stack = context->aregs[7];
640 if (stack >= 0xE00000) {
641 stack &= 0xFFFF;
642 uint8_t non_adr_count = 0;
643 do {
644 uint32_t bt_address = system->work_ram[stack/2] << 16 | system->work_ram[stack/2+1];
645 bt_address = get_instruction_start(context->options, bt_address - 2);
646 if (bt_address) {
647 stack += 4;
648 non_adr_count = 0;
649 uint16_t *bt_pc = NULL;
650 if (bt_address < 0x400000) {
651 bt_pc = system->cart + bt_address/2;
652 } else if(bt_address > 0xE00000) {
653 bt_pc = system->work_ram + (bt_address & 0xFFFF)/2;
654 }
655 m68k_decode(bt_pc, &inst, bt_address);
656 m68k_disasm(&inst, input_buf);
657 printf("%X: %s\n", bt_address, input_buf);
658 } else {
659 //non-return address value on stack can be word wide
660 stack += 2;
661 non_adr_count++;
662 }
663 stack &= 0xFFFF;
664 } while (stack && non_adr_count < 6);
665 }
666 } else {
667 param = find_param(input_buf);
668 if (!param) {
669 fputs("b command requires a parameter\n", stderr);
670 break;
671 }
672 value = strtol(param, NULL, 16);
673 insert_breakpoint(context, value, debugger);
674 new_bp = malloc(sizeof(bp_def));
675 new_bp->next = breakpoints;
676 new_bp->address = value;
677 new_bp->index = bp_index++;
678 new_bp->commands = NULL;
679 breakpoints = new_bp;
680 printf("68K Breakpoint %d set at %X\n", new_bp->index, value);
681 }
682 break;
683 case 'a':
684 param = find_param(input_buf);
685 if (!param) {
686 fputs("a command requires a parameter\n", stderr);
687 break;
688 }
689 value = strtol(param, NULL, 16);
690 insert_breakpoint(context, value, debugger);
691 return 0;
692 case 'd':
693 if (input_buf[1] == 'i') {
694 format_char = 0;
695 for(int i = 2; input_buf[i] != 0 && input_buf[i] != ' '; i++) {
696 if (input_buf[i] == '/') {
697 format_char = input_buf[i+1];
698 break;
699 }
700 }
701 param = find_param(input_buf);
702 if (!param) {
703 fputs("display command requires a parameter\n", stderr);
704 break;
705 }
706 debugger_print(context, format_char, param, address);
707 add_display(&displays, &disp_index, format_char, param);
708 } else {
709 param = find_param(input_buf);
710 if (!param) {
711 fputs("d command requires a parameter\n", stderr);
712 break;
713 }
714 value = atoi(param);
715 this_bp = find_breakpoint_idx(&breakpoints, value);
716 if (!*this_bp) {
717 fprintf(stderr, "Breakpoint %d does not exist\n", value);
718 break;
719 }
720 new_bp = *this_bp;
721 *this_bp = (*this_bp)->next;
722 if (new_bp->commands) {
723 free(new_bp->commands);
724 }
725 free(new_bp);
726 }
727 break;
728 case 'p':
729 format_char = 0;
730 for(int i = 1; input_buf[i] != 0 && input_buf[i] != ' '; i++) {
731 if (input_buf[i] == '/') {
732 format_char = input_buf[i+1];
733 break;
734 }
735 }
736 param = find_param(input_buf);
737 if (param) {
738 debugger_print(context, format_char, param, address);
739 } else {
740 m68k_disasm(&inst, input_buf);
741 printf("%X: %s\n", address, input_buf);
742 }
743
744 break;
745 case 'n':
746 if (inst.op == M68K_RTS) {
747 after = m68k_read_long(context->aregs[7], context);
748 } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) {
749 after = m68k_read_long(context->aregs[7] + 2, context);
750 } else if(m68k_is_noncall_branch(&inst)) {
751 if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
752 branch_f = after;
753 branch_t = m68k_branch_target(&inst, context->dregs, context->aregs);
754 insert_breakpoint(context, branch_t, debugger);
755 } else if(inst.op == M68K_DBCC) {
756 if ( inst.extra.cond == COND_FALSE) {
757 if (context->dregs[inst.dst.params.regs.pri] & 0xFFFF) {
758 after = m68k_branch_target(&inst, context->dregs, context->aregs);
759 }
760 } else {
761 branch_t = after;
762 branch_f = m68k_branch_target(&inst, context->dregs, context->aregs);
763 insert_breakpoint(context, branch_f, debugger);
764 }
765 } else {
766 after = m68k_branch_target(&inst, context->dregs, context->aregs);
767 }
768 }
769 insert_breakpoint(context, after, debugger);
770 return 0;
771 case 'o':
772 if (inst.op == M68K_RTS) {
773 after = m68k_read_long(context->aregs[7], context);
774 } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) {
775 after = m68k_read_long(context->aregs[7] + 2, context);
776 } else if(m68k_is_noncall_branch(&inst)) {
777 if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
778 branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
779 if (branch_t < after) {
780 branch_t = 0;
781 } else {
782 branch_f = after;
783 insert_breakpoint(context, branch_t, debugger);
784 }
785 } else if(inst.op == M68K_DBCC) {
786 uint32_t target = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
787 if (target > after) {
788 if (inst.extra.cond == COND_FALSE) {
789 after = target;
790 } else {
791 branch_f = target;
792 branch_t = after;
793 insert_breakpoint(context, branch_f, debugger);
794 }
795 }
796 } else {
797 after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
798 }
799 }
800 insert_breakpoint(context, after, debugger);
801 return 0;
802 case 's':
803 if (input_buf[1] == 'e') {
804 param = find_param(input_buf);
805 if (!param) {
806 fputs("Missing destination parameter for set\n", stderr);
807 return 1;
808 }
809 char *val = find_param(param);
810 if (!val) {
811 fputs("Missing value parameter for set\n", stderr);
812 return 1;
813 }
814 long int_val;
815 int reg_num;
816 switch (val[0])
817 {
818 case 'd':
819 case 'a':
820 reg_num = val[1] - '0';
821 if (reg_num < 0 || reg_num > 8) {
822 fprintf(stderr, "Invalid register %s\n", val);
823 return 1;
824 }
825 int_val = (val[0] == 'd' ? context->dregs : context->aregs)[reg_num];
826 break;
827 case '$':
828 int_val = strtol(val+1, NULL, 16);
829 break;
830 case '0':
831 if (val[1] == 'x') {
832 int_val = strtol(val+2, NULL, 16);
833 break;
834 }
835 default:
836 int_val = strtol(val, NULL, 10);
837 }
838 switch(param[0])
839 {
840 case 'd':
841 case 'a':
842 reg_num = param[1] - '0';
843 if (reg_num < 0 || reg_num > 8) {
844 fprintf(stderr, "Invalid register %s\n", param);
845 return 1;
846 }
847 (param[0] == 'd' ? context->dregs : context->aregs)[reg_num] = int_val;
848 break;
849 default:
850 fprintf(stderr, "Invalid destinatino %s\n", param);
851 }
852 break;
853 } else if (input_buf[1] == 'r') {
854 system->header.soft_reset(&system->header);
855 return 0;
856 } else {
857 if (inst.op == M68K_RTS) {
858 after = m68k_read_long(context->aregs[7], context);
859 } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) {
860 after = m68k_read_long(context->aregs[7] + 2, context);
861 } else if(m68k_is_branch(&inst)) {
862 if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
863 branch_f = after;
864 branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
865 insert_breakpoint(context, branch_t, debugger);
866 } else if(inst.op == M68K_DBCC) {
867 if (inst.extra.cond == COND_FALSE) {
868 if (context->dregs[inst.dst.params.regs.pri] & 0xFFFF) {
869 after = m68k_branch_target(&inst, context->dregs, context->aregs);
870 }
871 } else {
872 branch_t = after;
873 branch_f = m68k_branch_target(&inst, context->dregs, context->aregs);
874 insert_breakpoint(context, branch_f, debugger);
875 }
876 } else {
877 after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
878 }
879 }
880 insert_breakpoint(context, after, debugger);
881 return 0;
882 }
883 case 'v': {
884 genesis_context * gen = context->system;
885 //VDP debug commands
886 switch(input_buf[1])
887 {
888 case 's':
889 vdp_print_sprite_table(gen->vdp);
890 break;
891 case 'r':
892 vdp_print_reg_explain(gen->vdp);
893 break;
894 }
895 break;
896 }
897 case 'y': {
898 genesis_context * gen = context->system;
899 //YM-2612 debug commands
900 switch(input_buf[1])
901 {
902 case 'c':
903 if (input_buf[2] == ' ') {
904 int channel = atoi(input_buf+3)-1;
905 ym_print_channel_info(gen->ym, channel);
906 } else {
907 for (int i = 0; i < 6; i++) {
908 ym_print_channel_info(gen->ym, i);
909 }
910 }
911 break;
912 case 't':
913 ym_print_timer_info(gen->ym);
914 break;
915 }
916 break;
917 }
918 #ifndef NO_Z80
919 case 'z': {
920 genesis_context * gen = context->system;
921 //Z80 debug commands
922 switch(input_buf[1])
923 {
924 case 'b':
925 param = find_param(input_buf);
926 if (!param) {
927 fputs("zb command requires a parameter\n", stderr);
928 break;
929 }
930 value = strtol(param, NULL, 16);
931 zinsert_breakpoint(gen->z80, value, (uint8_t *)zdebugger);
932 new_bp = malloc(sizeof(bp_def));
933 new_bp->next = zbreakpoints;
934 new_bp->address = value;
935 new_bp->index = zbp_index++;
936 zbreakpoints = new_bp;
937 printf("Z80 Breakpoint %d set at %X\n", new_bp->index, value);
938 break;
939 case 'p':
940 param = find_param(input_buf);
941 if (!param) {
942 fputs("zp command requires a parameter\n", stderr);
943 break;
944 }
945 zdebugger_print(gen->z80, input_buf[2] == '/' ? input_buf[3] : 0, param);
946 }
947 break;
948 }
949 #endif
950 case '?':
951 print_m68k_help();
952 break;
953 case 'q':
954 puts("Quitting");
955 exit(0);
956 break;
957 default:
958 fprintf(stderr, "Unrecognized debugger command %s\nUse '?' for help.\n", input_buf);
959 break;
960 }
961 return 1;
962 }
963
964 void print_m68k_help()
965 {
966 printf("M68k Debugger Commands\n");
967 printf(" b ADDRESS - Set a breakpoint at ADDRESS\n");
968 printf(" d BREAKPOINT - Delete a 68K breakpoint\n");
969 printf(" co BREAKPOINT - Run a list of debugger commands each time\n");
970 printf(" BREAKPOINT is hit\n");
971 printf(" a ADDRESS - Advance to address\n");
972 printf(" n - Advance to next instruction\n");
973 printf(" o - Advance to next instruction ignoring branches to\n");
974 printf(" lower addresses (good for breaking out of loops)\n");
975 printf(" s - Advance to next instruction (follows bsr/jsr)\n");
976 printf(" se REG|ADDRESS VALUE - Set value\n");
977 printf(" sr - Soft reset\n");
978 printf(" c - Continue\n");
979 printf(" bt - Print a backtrace\n");
980 printf(" p[/(x|X|d|c)] VALUE - Print a register or memory location\n");
981 printf(" di[/(x|X|d|c)] VALUE - Print a register or memory location each time\n");
982 printf(" a breakpoint is hit\n");
983 printf(" vs - Print VDP sprite list\n");
984 printf(" vr - Print VDP register info\n");
985 printf(" yc [CHANNEL NUM] - Print YM-2612 channel info\n");
986 printf(" yt - Print YM-2612 timer info\n");
987 printf(" zb ADDRESS - Set a Z80 breakpoint\n");
988 printf(" zp[/(x|X|d|c)] VALUE - Display a Z80 value\n");
989 printf(" ? - Display help\n");
990 printf(" q - Quit BlastEm\n");
991 }
992
993 void print_z80_help()
994 {
995 printf("Z80 Debugger Commands\n");
996 printf(" b ADDRESS - Set a breakpoint at ADDRESS\n");
997 printf(" de BREAKPOINT - Delete a Z80 breakpoint\n");
998 printf(" a ADDRESS - Advance to address\n");
999 printf(" n - Advance to next instruction\n");
1000 printf(" c - Continue\n");
1001 printf(" p[/(x|X|d|c)] VALUE - Print a register or memory location\n");
1002 printf(" di[/(x|X|d|c)] VALUE - Print a register or memory location each time\n");
1003 printf(" a breakpoint is hit\n");
1004 printf(" q - Quit BlastEm\n");
1005 }
1006
1007 void debugger(m68k_context * context, uint32_t address) 131 void debugger(m68k_context * context, uint32_t address)
1008 { 132 {
1009 static char last_cmd[1024];
1010 char input_buf[1024];
1011 m68kinst inst;
1012
1013 init_terminal();
1014
1015 sync_components(context, 0);
1016 genesis_context *gen = context->system;
1017 vdp_force_update_framebuffer(gen->vdp);
1018 //probably not necessary, but let's play it safe
1019 address &= 0xFFFFFF;
1020 if (address == branch_t) {
1021 bp_def ** f_bp = find_breakpoint(&breakpoints, branch_f);
1022 if (!*f_bp) {
1023 remove_breakpoint(context, branch_f);
1024 }
1025 branch_t = branch_f = 0;
1026 } else if(address == branch_f) {
1027 bp_def ** t_bp = find_breakpoint(&breakpoints, branch_t);
1028 if (!*t_bp) {
1029 remove_breakpoint(context, branch_t);
1030 }
1031 branch_t = branch_f = 0;
1032 }
1033
1034 uint16_t * pc = get_native_pointer(address, (void **)context->mem_pointers, &context->options->gen);
1035 if (!pc) {
1036 fatal_error("Entered 68K debugger at address %X\n", address);
1037 }
1038 uint16_t * after_pc = m68k_decode(pc, &inst, address);
1039 uint32_t after = address + (after_pc-pc)*2;
1040 int debugging = 1;
1041 //Check if this is a user set breakpoint, or just a temporary one
1042 bp_def ** this_bp = find_breakpoint(&breakpoints, address);
1043 if (*this_bp) {
1044
1045 if ((*this_bp)->commands)
1046 {
1047 char *commands = strdup((*this_bp)->commands);
1048 char *copy = commands;
1049
1050 while (debugging && *commands)
1051 {
1052 char *cmd = commands;
1053 strip_nl(cmd);
1054 commands += strlen(cmd) + 1;
1055 debugging = run_debugger_command(context, address, cmd, inst, after);
1056 }
1057 free(copy);
1058 }
1059 if (debugging) {
1060 printf("68K Breakpoint %d hit\n", (*this_bp)->index);
1061 } else {
1062 return;
1063 }
1064 } else {
1065 remove_breakpoint(context, address);
1066 }
1067 for (disp_def * cur = displays; cur; cur = cur->next) {
1068 debugger_print(context, cur->format_char, cur->param, address);
1069 }
1070 m68k_disasm(&inst, input_buf);
1071 printf("%X: %s\n", address, input_buf);
1072 #ifdef _WIN32
1073 #define prompt 1
1074 #else
1075 int prompt = 1;
1076 fd_set read_fds;
1077 FD_ZERO(&read_fds);
1078 struct timeval timeout;
1079 #endif
1080 while (debugging) {
1081 if (prompt) {
1082 fputs(">", stdout);
1083 fflush(stdout);
1084 }
1085 process_events();
1086 #ifndef _WIN32
1087 timeout.tv_sec = 0;
1088 timeout.tv_usec = 16667;
1089 FD_SET(fileno(stdin), &read_fds);
1090 if(select(fileno(stdin) + 1, &read_fds, NULL, NULL, &timeout) < 1) {
1091 prompt = 0;
1092 continue;
1093 } else {
1094 prompt = 1;
1095 }
1096 #endif
1097 if (!fgets(input_buf, sizeof(input_buf), stdin)) {
1098 fputs("fgets failed", stderr);
1099 break;
1100 }
1101 strip_nl(input_buf);
1102 //hitting enter repeats last command
1103 if (input_buf[0]) {
1104 strcpy(last_cmd, input_buf);
1105 } else {
1106 strcpy(input_buf, last_cmd);
1107 }
1108 debugging = run_debugger_command(context, address, input_buf, inst, after);
1109 }
1110 return; 133 return;
1111 } 134 }