Mercurial > repos > blastem
comparison debug.c @ 524:fb39534b6604
Move debugging code outside of main source file
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 11 Feb 2014 21:53:31 -0800 |
parents | |
children | 62860044337d |
comparison
equal
deleted
inserted
replaced
523:450c7745379a | 524:fb39534b6604 |
---|---|
1 #include "debug.h" | |
2 #include "blastem.h" | |
3 #include "68kinst.h" | |
4 #include <stdlib.h> | |
5 #include <string.h> | |
6 | |
7 bp_def * breakpoints = NULL; | |
8 bp_def * zbreakpoints = NULL; | |
9 uint32_t bp_index = 0; | |
10 uint32_t zbp_index = 0; | |
11 | |
12 bp_def ** find_breakpoint(bp_def ** cur, uint32_t address) | |
13 { | |
14 while (*cur) { | |
15 if ((*cur)->address == address) { | |
16 break; | |
17 } | |
18 cur = &((*cur)->next); | |
19 } | |
20 return cur; | |
21 } | |
22 | |
23 bp_def ** find_breakpoint_idx(bp_def ** cur, uint32_t index) | |
24 { | |
25 while (*cur) { | |
26 if ((*cur)->index == index) { | |
27 break; | |
28 } | |
29 cur = &((*cur)->next); | |
30 } | |
31 return cur; | |
32 } | |
33 | |
34 disp_def * displays = NULL; | |
35 disp_def * zdisplays = NULL; | |
36 uint32_t disp_index = 0; | |
37 uint32_t zdisp_index = 0; | |
38 | |
39 void add_display(disp_def ** head, uint32_t *index, char format_char, char * param) | |
40 { | |
41 disp_def * ndisp = malloc(sizeof(*ndisp)); | |
42 ndisp->format_char = format_char; | |
43 ndisp->param = strdup(param); | |
44 ndisp->next = *head; | |
45 ndisp->index = *index++; | |
46 *head = ndisp; | |
47 } | |
48 | |
49 void remove_display(disp_def ** head, uint32_t index) | |
50 { | |
51 while (*head) { | |
52 if ((*head)->index == index) { | |
53 disp_def * del_disp = *head; | |
54 *head = del_disp->next; | |
55 free(del_disp->param); | |
56 free(del_disp); | |
57 } else { | |
58 head = &(*head)->next; | |
59 } | |
60 } | |
61 } | |
62 | |
63 char * find_param(char * buf) | |
64 { | |
65 for (; *buf; buf++) { | |
66 if (*buf == ' ') { | |
67 if (*(buf+1)) { | |
68 return buf+1; | |
69 } | |
70 } | |
71 } | |
72 return NULL; | |
73 } | |
74 | |
75 void strip_nl(char * buf) | |
76 { | |
77 for(; *buf; buf++) { | |
78 if (*buf == '\n') { | |
79 *buf = 0; | |
80 return; | |
81 } | |
82 } | |
83 } | |
84 | |
85 void zdebugger_print(z80_context * context, char format_char, char * param) | |
86 { | |
87 uint32_t value; | |
88 char format[8]; | |
89 strcpy(format, "%s: %d\n"); | |
90 switch (format_char) | |
91 { | |
92 case 'x': | |
93 case 'X': | |
94 case 'd': | |
95 case 'c': | |
96 format[5] = format_char; | |
97 break; | |
98 case '\0': | |
99 break; | |
100 default: | |
101 fprintf(stderr, "Unrecognized format character: %c\n", format_char); | |
102 } | |
103 switch (param[0]) | |
104 { | |
105 case 'a': | |
106 if (param[1] == 'f') { | |
107 if(param[2] == '\'') { | |
108 value = context->alt_regs[Z80_A] << 8; | |
109 value |= context->alt_flags[ZF_S] << 7; | |
110 value |= context->alt_flags[ZF_Z] << 6; | |
111 value |= context->alt_flags[ZF_H] << 4; | |
112 value |= context->alt_flags[ZF_PV] << 2; | |
113 value |= context->alt_flags[ZF_N] << 1; | |
114 value |= context->alt_flags[ZF_C]; | |
115 } else { | |
116 value = context->regs[Z80_A] << 8; | |
117 value |= context->flags[ZF_S] << 7; | |
118 value |= context->flags[ZF_Z] << 6; | |
119 value |= context->flags[ZF_H] << 4; | |
120 value |= context->flags[ZF_PV] << 2; | |
121 value |= context->flags[ZF_N] << 1; | |
122 value |= context->flags[ZF_C]; | |
123 } | |
124 } else if(param[1] == '\'') { | |
125 value = context->alt_regs[Z80_A]; | |
126 } else { | |
127 value = context->regs[Z80_A]; | |
128 } | |
129 break; | |
130 case 'b': | |
131 if (param[1] == 'c') { | |
132 if(param[2] == '\'') { | |
133 value = context->alt_regs[Z80_B] << 8; | |
134 value |= context->alt_regs[Z80_C]; | |
135 } else { | |
136 value = context->regs[Z80_B] << 8; | |
137 value |= context->regs[Z80_C]; | |
138 } | |
139 } else if(param[1] == '\'') { | |
140 value = context->alt_regs[Z80_B]; | |
141 } else if(param[1] == 'a') { | |
142 value = context->bank_reg << 15; | |
143 } else { | |
144 value = context->regs[Z80_B]; | |
145 } | |
146 break; | |
147 case 'c': | |
148 if(param[1] == '\'') { | |
149 value = context->alt_regs[Z80_C]; | |
150 } else if(param[1] == 'y') { | |
151 value = context->current_cycle; | |
152 } else { | |
153 value = context->regs[Z80_C]; | |
154 } | |
155 break; | |
156 case 'd': | |
157 if (param[1] == 'e') { | |
158 if(param[2] == '\'') { | |
159 value = context->alt_regs[Z80_D] << 8; | |
160 value |= context->alt_regs[Z80_E]; | |
161 } else { | |
162 value = context->regs[Z80_D] << 8; | |
163 value |= context->regs[Z80_E]; | |
164 } | |
165 } else if(param[1] == '\'') { | |
166 value = context->alt_regs[Z80_D]; | |
167 } else { | |
168 value = context->regs[Z80_D]; | |
169 } | |
170 break; | |
171 case 'e': | |
172 if(param[1] == '\'') { | |
173 value = context->alt_regs[Z80_E]; | |
174 } else { | |
175 value = context->regs[Z80_E]; | |
176 } | |
177 break; | |
178 case 'f': | |
179 if(param[2] == '\'') { | |
180 value = context->alt_flags[ZF_S] << 7; | |
181 value |= context->alt_flags[ZF_Z] << 6; | |
182 value |= context->alt_flags[ZF_H] << 4; | |
183 value |= context->alt_flags[ZF_PV] << 2; | |
184 value |= context->alt_flags[ZF_N] << 1; | |
185 value |= context->alt_flags[ZF_C]; | |
186 } else { | |
187 value = context->flags[ZF_S] << 7; | |
188 value |= context->flags[ZF_Z] << 6; | |
189 value |= context->flags[ZF_H] << 4; | |
190 value |= context->flags[ZF_PV] << 2; | |
191 value |= context->flags[ZF_N] << 1; | |
192 value |= context->flags[ZF_C]; | |
193 } | |
194 break; | |
195 case 'h': | |
196 if (param[1] == 'l') { | |
197 if(param[2] == '\'') { | |
198 value = context->alt_regs[Z80_H] << 8; | |
199 value |= context->alt_regs[Z80_L]; | |
200 } else { | |
201 value = context->regs[Z80_H] << 8; | |
202 value |= context->regs[Z80_L]; | |
203 } | |
204 } else if(param[1] == '\'') { | |
205 value = context->alt_regs[Z80_H]; | |
206 } else { | |
207 value = context->regs[Z80_H]; | |
208 } | |
209 break; | |
210 case 'l': | |
211 if(param[1] == '\'') { | |
212 value = context->alt_regs[Z80_L]; | |
213 } else { | |
214 value = context->regs[Z80_L]; | |
215 } | |
216 break; | |
217 case 'i': | |
218 if(param[1] == 'x') { | |
219 if (param[2] == 'h') { | |
220 value = context->regs[Z80_IXH]; | |
221 } else if(param[2] == 'l') { | |
222 value = context->regs[Z80_IXL]; | |
223 } else { | |
224 value = context->regs[Z80_IXH] << 8; | |
225 value |= context->regs[Z80_IXL]; | |
226 } | |
227 } else if(param[1] == 'y') { | |
228 if (param[2] == 'h') { | |
229 value = context->regs[Z80_IYH]; | |
230 } else if(param[2] == 'l') { | |
231 value = context->regs[Z80_IYL]; | |
232 } else { | |
233 value = context->regs[Z80_IYH] << 8; | |
234 value |= context->regs[Z80_IYL]; | |
235 } | |
236 } else if(param[1] == 'n') { | |
237 value = context->int_cycle; | |
238 } else if(param[1] == 'f' && param[2] == 'f' && param[3] == '1') { | |
239 value = context->iff1; | |
240 } else if(param[1] == 'f' && param[2] == 'f' && param[3] == '2') { | |
241 value = context->iff2; | |
242 } else { | |
243 value = context->im; | |
244 } | |
245 break; | |
246 case 's': | |
247 if (param[1] == 'p') { | |
248 value = context->sp; | |
249 } | |
250 break; | |
251 case '0': | |
252 if (param[1] == 'x') { | |
253 uint16_t p_addr = strtol(param+2, NULL, 16); | |
254 if (p_addr < 0x4000) { | |
255 value = z80_ram[p_addr & 0x1FFF]; | |
256 } else if(p_addr >= 0x8000) { | |
257 uint32_t v_addr = context->bank_reg << 15; | |
258 v_addr += p_addr & 0x7FFF; | |
259 if (v_addr < 0x400000) { | |
260 value = cart[v_addr/2]; | |
261 } else if(v_addr > 0xE00000) { | |
262 value = ram[(v_addr & 0xFFFF)/2]; | |
263 } | |
264 if (v_addr & 1) { | |
265 value &= 0xFF; | |
266 } else { | |
267 value >>= 8; | |
268 } | |
269 } | |
270 } | |
271 break; | |
272 } | |
273 printf(format, param, value); | |
274 } | |
275 | |
276 z80_context * zdebugger(z80_context * context, uint16_t address) | |
277 { | |
278 static char last_cmd[1024]; | |
279 char input_buf[1024]; | |
280 static uint16_t branch_t; | |
281 static uint16_t branch_f; | |
282 z80inst inst; | |
283 //Check if this is a user set breakpoint, or just a temporary one | |
284 bp_def ** this_bp = find_breakpoint(&zbreakpoints, address); | |
285 if (*this_bp) { | |
286 printf("Z80 Breakpoint %d hit\n", (*this_bp)->index); | |
287 } else { | |
288 zremove_breakpoint(context, address); | |
289 } | |
290 uint8_t * pc; | |
291 if (address < 0x4000) { | |
292 pc = z80_ram + (address & 0x1FFF); | |
293 } else if (address >= 0x8000) { | |
294 if (context->bank_reg < (0x400000 >> 15)) { | |
295 fprintf(stderr, "Entered Z80 debugger in banked memory address %X, which is not yet supported\n", address); | |
296 exit(1); | |
297 } else { | |
298 fprintf(stderr, "Entered Z80 debugger in banked memory address %X, but the bank is not pointed to a cartridge address\n", address); | |
299 exit(1); | |
300 } | |
301 } else { | |
302 fprintf(stderr, "Entered Z80 debugger at address %X\n", address); | |
303 exit(1); | |
304 } | |
305 for (disp_def * cur = zdisplays; cur; cur = cur->next) { | |
306 zdebugger_print(context, cur->format_char, cur->param); | |
307 } | |
308 uint8_t * after_pc = z80_decode(pc, &inst); | |
309 z80_disasm(&inst, input_buf, address); | |
310 printf("%X:\t%s\n", address, input_buf); | |
311 uint16_t after = address + (after_pc-pc); | |
312 int debugging = 1; | |
313 while(debugging) { | |
314 fputs(">", stdout); | |
315 if (!fgets(input_buf, sizeof(input_buf), stdin)) { | |
316 fputs("fgets failed", stderr); | |
317 break; | |
318 } | |
319 strip_nl(input_buf); | |
320 //hitting enter repeats last command | |
321 if (input_buf[0]) { | |
322 strcpy(last_cmd, input_buf); | |
323 } else { | |
324 strcpy(input_buf, last_cmd); | |
325 } | |
326 char * param; | |
327 char format[8]; | |
328 uint32_t value; | |
329 bp_def * new_bp; | |
330 switch(input_buf[0]) | |
331 { | |
332 case 'a': | |
333 param = find_param(input_buf); | |
334 if (!param) { | |
335 fputs("a command requires a parameter\n", stderr); | |
336 break; | |
337 } | |
338 value = strtol(param, NULL, 16); | |
339 zinsert_breakpoint(context, value, (uint8_t *)zdebugger); | |
340 debugging = 0; | |
341 break; | |
342 case 'b': | |
343 param = find_param(input_buf); | |
344 if (!param) { | |
345 fputs("b command requires a parameter\n", stderr); | |
346 break; | |
347 } | |
348 value = strtol(param, NULL, 16); | |
349 zinsert_breakpoint(context, value, (uint8_t *)zdebugger); | |
350 new_bp = malloc(sizeof(bp_def)); | |
351 new_bp->next = zbreakpoints; | |
352 new_bp->address = value; | |
353 new_bp->index = zbp_index++; | |
354 zbreakpoints = new_bp; | |
355 printf("Z80 Breakpoint %d set at %X\n", new_bp->index, value); | |
356 break; | |
357 case 'c': | |
358 puts("Continuing"); | |
359 debugging = 0; | |
360 break; | |
361 case 'd': | |
362 if (input_buf[1] == 'i') { | |
363 char format_char = 0; | |
364 for(int i = 2; input_buf[i] != 0 && input_buf[i] != ' '; i++) { | |
365 if (input_buf[i] == '/') { | |
366 format_char = input_buf[i+1]; | |
367 break; | |
368 } | |
369 } | |
370 param = find_param(input_buf); | |
371 if (!param) { | |
372 fputs("display command requires a parameter\n", stderr); | |
373 break; | |
374 } | |
375 zdebugger_print(context, format_char, param); | |
376 add_display(&zdisplays, &zdisp_index, format_char, param); | |
377 } else if (input_buf[1] == 'e' || input_buf[1] == ' ') { | |
378 param = find_param(input_buf); | |
379 if (!param) { | |
380 fputs("delete command requires a parameter\n", stderr); | |
381 break; | |
382 } | |
383 if (param[0] >= '0' && param[0] <= '9') { | |
384 value = atoi(param); | |
385 this_bp = find_breakpoint_idx(&zbreakpoints, value); | |
386 if (!*this_bp) { | |
387 fprintf(stderr, "Breakpoint %d does not exist\n", value); | |
388 break; | |
389 } | |
390 new_bp = *this_bp; | |
391 zremove_breakpoint(context, new_bp->address); | |
392 *this_bp = new_bp->next; | |
393 free(new_bp); | |
394 } else if (param[0] == 'd') { | |
395 param = find_param(param); | |
396 if (!param) { | |
397 fputs("delete display command requires a parameter\n", stderr); | |
398 break; | |
399 } | |
400 remove_display(&zdisplays, atoi(param)); | |
401 } | |
402 } | |
403 break; | |
404 case 'n': | |
405 //TODO: Handle conditional branch instructions | |
406 if (inst.op == Z80_JP) { | |
407 if (inst.addr_mode == Z80_IMMED) { | |
408 after = inst.immed; | |
409 } else if (inst.ea_reg == Z80_HL) { | |
410 after = context->regs[Z80_H] << 8 | context->regs[Z80_L]; | |
411 } else if (inst.ea_reg == Z80_IX) { | |
412 after = context->regs[Z80_IXH] << 8 | context->regs[Z80_IXL]; | |
413 } else if (inst.ea_reg == Z80_IY) { | |
414 after = context->regs[Z80_IYH] << 8 | context->regs[Z80_IYL]; | |
415 } | |
416 } else if(inst.op == Z80_JR) { | |
417 after += inst.immed; | |
418 } else if(inst.op == Z80_RET) { | |
419 if (context->sp < 0x4000) { | |
420 after = z80_ram[context->sp & 0x1FFF] | z80_ram[(context->sp+1) & 0x1FFF] << 8; | |
421 } | |
422 } | |
423 zinsert_breakpoint(context, after, (uint8_t *)zdebugger); | |
424 debugging = 0; | |
425 break; | |
426 case 'p': | |
427 param = find_param(input_buf); | |
428 if (!param) { | |
429 fputs("p command requires a parameter\n", stderr); | |
430 break; | |
431 } | |
432 zdebugger_print(context, input_buf[1] == '/' ? input_buf[2] : 0, param); | |
433 break; | |
434 case 'q': | |
435 puts("Quitting"); | |
436 exit(0); | |
437 break; | |
438 case 's': { | |
439 param = find_param(input_buf); | |
440 if (!param) { | |
441 fputs("s command requires a file name\n", stderr); | |
442 break; | |
443 } | |
444 FILE * f = fopen(param, "wb"); | |
445 if (f) { | |
446 if(fwrite(z80_ram, 1, sizeof(z80_ram), f) != sizeof(z80_ram)) { | |
447 fputs("Error writing file\n", stderr); | |
448 } | |
449 fclose(f); | |
450 } else { | |
451 fprintf(stderr, "Could not open %s for writing\n", param); | |
452 } | |
453 break; | |
454 } | |
455 default: | |
456 fprintf(stderr, "Unrecognized debugger command %s\n", input_buf); | |
457 break; | |
458 } | |
459 } | |
460 return context; | |
461 } | |
462 | |
463 m68k_context * debugger(m68k_context * context, uint32_t address) | |
464 { | |
465 static char last_cmd[1024]; | |
466 char input_buf[1024]; | |
467 static uint32_t branch_t; | |
468 static uint32_t branch_f; | |
469 m68kinst inst; | |
470 //probably not necessary, but let's play it safe | |
471 address &= 0xFFFFFF; | |
472 if (address == branch_t) { | |
473 bp_def ** f_bp = find_breakpoint(&breakpoints, branch_f); | |
474 if (!*f_bp) { | |
475 remove_breakpoint(context, branch_f); | |
476 } | |
477 branch_t = branch_f = 0; | |
478 } else if(address == branch_f) { | |
479 bp_def ** t_bp = find_breakpoint(&breakpoints, branch_t); | |
480 if (!*t_bp) { | |
481 remove_breakpoint(context, branch_t); | |
482 } | |
483 branch_t = branch_f = 0; | |
484 } | |
485 //Check if this is a user set breakpoint, or just a temporary one | |
486 bp_def ** this_bp = find_breakpoint(&breakpoints, address); | |
487 if (*this_bp) { | |
488 printf("68K Breakpoint %d hit\n", (*this_bp)->index); | |
489 } else { | |
490 remove_breakpoint(context, address); | |
491 } | |
492 uint16_t * pc; | |
493 if (address < 0x400000) { | |
494 pc = cart + address/2; | |
495 } else if(address > 0xE00000) { | |
496 pc = ram + (address & 0xFFFF)/2; | |
497 } else { | |
498 fprintf(stderr, "Entered 68K debugger at address %X\n", address); | |
499 exit(1); | |
500 } | |
501 uint16_t * after_pc = m68k_decode(pc, &inst, address); | |
502 m68k_disasm(&inst, input_buf); | |
503 printf("%X: %s\n", address, input_buf); | |
504 uint32_t after = address + (after_pc-pc)*2; | |
505 int debugging = 1; | |
506 while (debugging) { | |
507 fputs(">", stdout); | |
508 if (!fgets(input_buf, sizeof(input_buf), stdin)) { | |
509 fputs("fgets failed", stderr); | |
510 break; | |
511 } | |
512 strip_nl(input_buf); | |
513 //hitting enter repeats last command | |
514 if (input_buf[0]) { | |
515 strcpy(last_cmd, input_buf); | |
516 } else { | |
517 strcpy(input_buf, last_cmd); | |
518 } | |
519 char * param; | |
520 char format[8]; | |
521 uint32_t value; | |
522 bp_def * new_bp; | |
523 switch(input_buf[0]) | |
524 { | |
525 case 'c': | |
526 puts("Continuing"); | |
527 debugging = 0; | |
528 break; | |
529 case 'b': | |
530 param = find_param(input_buf); | |
531 if (!param) { | |
532 fputs("b command requires a parameter\n", stderr); | |
533 break; | |
534 } | |
535 value = strtol(param, NULL, 16); | |
536 insert_breakpoint(context, value, (uint8_t *)debugger); | |
537 new_bp = malloc(sizeof(bp_def)); | |
538 new_bp->next = breakpoints; | |
539 new_bp->address = value; | |
540 new_bp->index = bp_index++; | |
541 breakpoints = new_bp; | |
542 printf("68K Breakpoint %d set at %X\n", new_bp->index, value); | |
543 break; | |
544 case 'a': | |
545 param = find_param(input_buf); | |
546 if (!param) { | |
547 fputs("a command requires a parameter\n", stderr); | |
548 break; | |
549 } | |
550 value = strtol(param, NULL, 16); | |
551 insert_breakpoint(context, value, (uint8_t *)debugger); | |
552 debugging = 0; | |
553 break; | |
554 case 'd': | |
555 param = find_param(input_buf); | |
556 if (!param) { | |
557 fputs("d command requires a parameter\n", stderr); | |
558 break; | |
559 } | |
560 value = atoi(param); | |
561 this_bp = find_breakpoint_idx(&breakpoints, value); | |
562 if (!*this_bp) { | |
563 fprintf(stderr, "Breakpoint %d does not exist\n", value); | |
564 break; | |
565 } | |
566 new_bp = *this_bp; | |
567 *this_bp = (*this_bp)->next; | |
568 free(new_bp); | |
569 break; | |
570 case 'p': | |
571 strcpy(format, "%s: %d\n"); | |
572 if (input_buf[1] == '/') { | |
573 switch (input_buf[2]) | |
574 { | |
575 case 'x': | |
576 case 'X': | |
577 case 'd': | |
578 case 'c': | |
579 format[5] = input_buf[2]; | |
580 break; | |
581 default: | |
582 fprintf(stderr, "Unrecognized format character: %c\n", input_buf[2]); | |
583 } | |
584 } | |
585 param = find_param(input_buf); | |
586 if (!param) { | |
587 fputs("p command requires a parameter\n", stderr); | |
588 break; | |
589 } | |
590 if (param[0] == 'd' && param[1] >= '0' && param[1] <= '7') { | |
591 value = context->dregs[param[1]-'0']; | |
592 } else if (param[0] == 'a' && param[1] >= '0' && param[1] <= '7') { | |
593 value = context->aregs[param[1]-'0']; | |
594 } else if (param[0] == 'S' && param[1] == 'R') { | |
595 value = (context->status << 8); | |
596 for (int flag = 0; flag < 5; flag++) { | |
597 value |= context->flags[flag] << (4-flag); | |
598 } | |
599 } else if(param[0] == 'c') { | |
600 value = context->current_cycle; | |
601 } else if (param[0] == '0' && param[1] == 'x') { | |
602 uint32_t p_addr = strtol(param+2, NULL, 16); | |
603 value = read_dma_value(p_addr/2); | |
604 } else { | |
605 fprintf(stderr, "Unrecognized parameter to p: %s\n", param); | |
606 break; | |
607 } | |
608 printf(format, param, value); | |
609 break; | |
610 case 'n': | |
611 if (inst.op == M68K_RTS) { | |
612 after = (read_dma_value(context->aregs[7]/2) << 16) | read_dma_value(context->aregs[7]/2 + 1); | |
613 } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) { | |
614 after = (read_dma_value((context->aregs[7]+2)/2) << 16) | read_dma_value((context->aregs[7]+2)/2 + 1); | |
615 } else if(m68k_is_noncall_branch(&inst)) { | |
616 if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) { | |
617 branch_f = after; | |
618 branch_t = m68k_branch_target(&inst, context->dregs, context->aregs); | |
619 insert_breakpoint(context, branch_t, (uint8_t *)debugger); | |
620 } else if(inst.op == M68K_DBCC) { | |
621 if ( inst.extra.cond == COND_FALSE) { | |
622 if (context->dregs[inst.dst.params.regs.pri] & 0xFFFF) { | |
623 after = m68k_branch_target(&inst, context->dregs, context->aregs); | |
624 } | |
625 } else { | |
626 branch_t = after; | |
627 branch_f = m68k_branch_target(&inst, context->dregs, context->aregs); | |
628 insert_breakpoint(context, branch_f, (uint8_t *)debugger); | |
629 } | |
630 } else { | |
631 after = m68k_branch_target(&inst, context->dregs, context->aregs); | |
632 } | |
633 } | |
634 insert_breakpoint(context, after, (uint8_t *)debugger); | |
635 debugging = 0; | |
636 break; | |
637 case 'o': | |
638 if (inst.op == M68K_RTS) { | |
639 after = (read_dma_value(context->aregs[7]/2) << 16) | read_dma_value(context->aregs[7]/2 + 1); | |
640 } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) { | |
641 after = (read_dma_value((context->aregs[7]+2)/2) << 16) | read_dma_value((context->aregs[7]+2)/2 + 1); | |
642 } else if(m68k_is_noncall_branch(&inst)) { | |
643 if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) { | |
644 branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; | |
645 if (branch_t < after) { | |
646 branch_t = 0; | |
647 } else { | |
648 branch_f = after; | |
649 insert_breakpoint(context, branch_t, (uint8_t *)debugger); | |
650 } | |
651 } else if(inst.op == M68K_DBCC) { | |
652 uint32_t target = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; | |
653 if (target > after) { | |
654 if (inst.extra.cond == COND_FALSE) { | |
655 after = target; | |
656 } else { | |
657 branch_f = target; | |
658 branch_t = after; | |
659 insert_breakpoint(context, branch_f, (uint8_t *)debugger); | |
660 } | |
661 } | |
662 } else { | |
663 after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; | |
664 } | |
665 } | |
666 insert_breakpoint(context, after, (uint8_t *)debugger); | |
667 debugging = 0; | |
668 break; | |
669 case 's': | |
670 if (inst.op == M68K_RTS) { | |
671 after = (read_dma_value(context->aregs[7]/2) << 16) | read_dma_value(context->aregs[7]/2 + 1); | |
672 } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) { | |
673 after = (read_dma_value((context->aregs[7]+2)/2) << 16) | read_dma_value((context->aregs[7]+2)/2 + 1); | |
674 } else if(m68k_is_branch(&inst)) { | |
675 if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) { | |
676 branch_f = after; | |
677 branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; | |
678 insert_breakpoint(context, branch_t, (uint8_t *)debugger); | |
679 } else if(inst.op == M68K_DBCC && inst.extra.cond != COND_FALSE) { | |
680 branch_t = after; | |
681 branch_f = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; | |
682 insert_breakpoint(context, branch_f, (uint8_t *)debugger); | |
683 } else { | |
684 after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; | |
685 } | |
686 } | |
687 insert_breakpoint(context, after, (uint8_t *)debugger); | |
688 debugging = 0; | |
689 break; | |
690 case 'v': { | |
691 genesis_context * gen = context->system; | |
692 //VDP debug commands | |
693 switch(input_buf[1]) | |
694 { | |
695 case 's': | |
696 vdp_print_sprite_table(gen->vdp); | |
697 break; | |
698 case 'r': | |
699 vdp_print_reg_explain(gen->vdp); | |
700 break; | |
701 } | |
702 break; | |
703 } | |
704 case 'z': { | |
705 genesis_context * gen = context->system; | |
706 //Z80 debug commands | |
707 switch(input_buf[1]) | |
708 { | |
709 case 'b': | |
710 param = find_param(input_buf); | |
711 if (!param) { | |
712 fputs("zb command requires a parameter\n", stderr); | |
713 break; | |
714 } | |
715 value = strtol(param, NULL, 16); | |
716 zinsert_breakpoint(gen->z80, value, (uint8_t *)zdebugger); | |
717 new_bp = malloc(sizeof(bp_def)); | |
718 new_bp->next = zbreakpoints; | |
719 new_bp->address = value; | |
720 new_bp->index = zbp_index++; | |
721 zbreakpoints = new_bp; | |
722 printf("Z80 Breakpoint %d set at %X\n", new_bp->index, value); | |
723 break; | |
724 case 'p': | |
725 param = find_param(input_buf); | |
726 if (!param) { | |
727 fputs("zp command requires a parameter\n", stderr); | |
728 break; | |
729 } | |
730 zdebugger_print(gen->z80, input_buf[2] == '/' ? input_buf[3] : 0, param); | |
731 } | |
732 break; | |
733 } | |
734 case 'q': | |
735 puts("Quitting"); | |
736 exit(0); | |
737 break; | |
738 default: | |
739 fprintf(stderr, "Unrecognized debugger command %s\n", input_buf); | |
740 break; | |
741 } | |
742 } | |
743 return context; | |
744 } |