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