comparison blastem.c @ 184:ebcbdd1c4cc8

Fix a bunch of bugs in the CPU core, add a 68K debugger
author Mike Pavone <pavone@retrodev.com>
date Sun, 13 Jan 2013 13:01:13 -0800
parents 97aa449706c2
children b204fbed4efe
comparison
equal deleted inserted replaced
183:2f08d9e90a4c 184:ebcbdd1c4cc8
4 #include "vdp.h" 4 #include "vdp.h"
5 #include "render.h" 5 #include "render.h"
6 #include "blastem.h" 6 #include "blastem.h"
7 #include <stdio.h> 7 #include <stdio.h>
8 #include <stdlib.h> 8 #include <stdlib.h>
9 #include <string.h>
9 10
10 #define CARTRIDGE_WORDS 0x200000 11 #define CARTRIDGE_WORDS 0x200000
11 #define RAM_WORDS 32 * 1024 12 #define RAM_WORDS 32 * 1024
12 #define Z80_RAM_BYTES 8 * 1024 13 #define Z80_RAM_BYTES 8 * 1024
13 #define MCLKS_PER_68K 7 14 #define MCLKS_PER_68K 7
583 } 584 }
584 } 585 }
585 return context; 586 return context;
586 } 587 }
587 588
589 typedef struct bp_def {
590 struct bp_def * next;
591 uint32_t address;
592 uint32_t index;
593 } bp_def;
594
595 bp_def * breakpoints = NULL;
596 uint32_t bp_index = 0;
597
598 bp_def ** find_breakpoint(bp_def ** cur, uint32_t address)
599 {
600 while (*cur) {
601 if ((*cur)->address == address) {
602 break;
603 }
604 cur = &((*cur)->next);
605 }
606 return cur;
607 }
608
609 bp_def ** find_breakpoint_idx(bp_def ** cur, uint32_t index)
610 {
611 while (*cur) {
612 if ((*cur)->index == index) {
613 break;
614 }
615 cur = &((*cur)->next);
616 }
617 return cur;
618 }
619
620 char * find_param(char * buf)
621 {
622 for (; *buf; buf++) {
623 if (*buf == ' ') {
624 if (*(buf+1)) {
625 return buf+1;
626 }
627 }
628 }
629 return NULL;
630 }
631
632 void strip_nl(char * buf)
633 {
634 for(; *buf; buf++) {
635 if (*buf == '\n') {
636 *buf = 0;
637 return;
638 }
639 }
640 }
641
642 m68k_context * debugger(m68k_context * context, uint32_t address)
643 {
644 static char last_cmd[1024];
645 char input_buf[1024];
646 static uint32_t branch_t;
647 static uint32_t branch_f;
648 m68kinst inst;
649 //probably not necessary, but let's play it safe
650 address &= 0xFFFFFF;
651 if (address == branch_t) {
652 bp_def ** f_bp = find_breakpoint(&breakpoints, branch_f);
653 if (!*f_bp) {
654 remove_breakpoint(context, branch_f);
655 }
656 branch_t = branch_f = 0;
657 } else if(address == branch_f) {
658 bp_def ** t_bp = find_breakpoint(&breakpoints, branch_t);
659 if (!*t_bp) {
660 remove_breakpoint(context, branch_t);
661 }
662 branch_t = branch_f = 0;
663 }
664 //Check if this is a user set breakpoint, or just a temporary one
665 bp_def ** this_bp = find_breakpoint(&breakpoints, address);
666 if (*this_bp) {
667 printf("Breakpoint %d hit\n", (*this_bp)->index);
668 } else {
669 remove_breakpoint(context, address);
670 }
671 uint16_t * pc;
672 if (address < 0x400000) {
673 pc = cart + address/2;
674 } else if(address > 0xE00000) {
675 pc = ram + (address & 0xFFFF)/2;
676 } else {
677 fprintf(stderr, "Entered debugger at address %X\n", address);
678 exit(1);
679 }
680 uint16_t * after_pc = m68k_decode(pc, &inst, address);
681 m68k_disasm(&inst, input_buf);
682 printf("%X: %s\n", address, input_buf);
683 uint32_t after = address + (after_pc-pc)*2;
684 int debugging = 1;
685 while (debugging) {
686 fputs(">", stdout);
687 if (!fgets(input_buf, sizeof(input_buf), stdin)) {
688 fputs("fgets failed", stderr);
689 break;
690 }
691 strip_nl(input_buf);
692 //hitting enter repeats last command
693 if (input_buf[0]) {
694 strcpy(last_cmd, input_buf);
695 } else {
696 strcpy(input_buf, last_cmd);
697 }
698 char * param;
699 char format[8];
700 uint32_t value;
701 bp_def * new_bp;
702 switch(input_buf[0])
703 {
704 case 'c':
705 puts("Continuing");
706 debugging = 0;
707 break;
708 case 'b':
709 param = find_param(input_buf);
710 if (!param) {
711 fputs("b command requires a parameter\n", stderr);
712 break;
713 }
714 value = strtol(param, NULL, 16);
715 insert_breakpoint(context, value, (uint8_t *)debugger);
716 new_bp = malloc(sizeof(bp_def));
717 new_bp->next = breakpoints;
718 new_bp->address = value;
719 new_bp->index = bp_index++;
720 breakpoints = new_bp;
721 printf("Breakpoint %d set at %X\n", new_bp->index, value);
722 break;
723 case 'a':
724 param = find_param(input_buf);
725 if (!param) {
726 fputs("a command requires a parameter\n", stderr);
727 break;
728 }
729 value = strtol(param, NULL, 16);
730 insert_breakpoint(context, value, (uint8_t *)debugger);
731 debugging = 0;
732 break;
733 case 'd':
734 param = find_param(input_buf);
735 if (!param) {
736 fputs("b command requires a parameter\n", stderr);
737 break;
738 }
739 value = atoi(param);
740 this_bp = find_breakpoint_idx(&breakpoints, value);
741 if (!*this_bp) {
742 fprintf(stderr, "Breakpoint %d does not exist\n", value);
743 break;
744 }
745 new_bp = *this_bp;
746 *this_bp = (*this_bp)->next;
747 free(new_bp);
748 break;
749 case 'p':
750 strcpy(format, "%s: %d\n");
751 if (input_buf[1] == '/') {
752 switch (input_buf[2])
753 {
754 case 'x':
755 case 'X':
756 case 'd':
757 case 'c':
758 format[5] = input_buf[2];
759 break;
760 default:
761 fprintf(stderr, "Unrecognized format character: %c\n", input_buf[2]);
762 }
763 }
764 param = find_param(input_buf);
765 if (!param) {
766 fputs("p command requires a parameter\n", stderr);
767 break;
768 }
769 if (param[0] == 'd' && param[1] >= '0' && param[1] <= '7') {
770 value = context->dregs[param[1]-'0'];
771 } else if (param[0] == 'a' && param[1] >= '0' && param[1] <= '7') {
772 value = context->aregs[param[1]-'0'];
773 } else if (param[0] == 'S' && param[1] == 'R') {
774 value = (context->status << 8);
775 for (int flag = 0; flag < 5; flag++) {
776 value |= context->flags[flag] << (4-flag);
777 }
778 } else if (param[0] == '0' && param[1] == 'x') {
779 uint32_t p_addr = strtol(param+2, NULL, 16);
780 value = read_dma_value(p_addr/2);
781 } else {
782 fprintf(stderr, "Unrecognized parameter to p: %s\n", param);
783 break;
784 }
785 printf(format, param, value);
786 break;
787 case 'n':
788 //TODO: Deal with jmp, dbcc, rtr and rte
789 if (inst.op == M68K_RTS) {
790 after = (read_dma_value(context->aregs[7]/2) << 16) | read_dma_value(context->aregs[7]/2 + 1);
791 } else if(inst.op == M68K_BCC && inst.extra.cond != COND_FALSE) {
792 if (inst.extra.cond = COND_TRUE) {
793 after = inst.address + 2 + inst.src.params.immed;
794 } else {
795 branch_f = after;
796 branch_t = inst.address + 2 + inst.src.params.immed;
797 insert_breakpoint(context, branch_t, (uint8_t *)debugger);
798 }
799 }
800 insert_breakpoint(context, after, (uint8_t *)debugger);
801 debugging = 0;
802 break;
803 case 'q':
804 puts("Quitting");
805 exit(0);
806 break;
807 default:
808 fprintf(stderr, "Unrecognized debugger command %s\n", input_buf);
809 break;
810 }
811 }
812 return context;
813 }
814
588 int main(int argc, char ** argv) 815 int main(int argc, char ** argv)
589 { 816 {
590 if (argc < 2) { 817 if (argc < 2) {
591 fputs("Usage: blastem FILENAME\n", stderr); 818 fputs("Usage: blastem FILENAME\n", stderr);
592 return 1; 819 return 1;
593 } 820 }
594 if(!load_rom(argv[1])) { 821 if(!load_rom(argv[1])) {
595 fprintf(stderr, "Failed to open %s for reading\n", argv[1]); 822 fprintf(stderr, "Failed to open %s for reading\n", argv[1]);
596 return 1; 823 return 1;
597 } 824 }
598 int width = 320; 825 int width = -1;
599 int height = 240; 826 int height = -1;
600 if (argc > 2) { 827 int debug = 0;
601 width = atoi(argv[2]); 828 for (int i = 2; i < argc; i++) {
602 if (argc > 3) { 829 if (argv[i][0] == '-') {
603 height = atoi(argv[3]); 830 switch(argv[i][1]) {
604 } else { 831 case 'd':
605 height = (width/320) * 240; 832 debug = 1;
606 } 833 break;
607 } 834 default:
835 fprintf(stderr, "Unrecognized switch %s\n", argv[i]);
836 return 1;
837 }
838 } else if (width < 0) {
839 width = atoi(argv[i]);
840 } else if (height < 0) {
841 height = atoi(argv[i]);
842 }
843 }
844 width = width < 320 ? 320 : width;
845 height = height < 240 ? (width/320) * 240 : height;
608 render_init(width, height); 846 render_init(width, height);
609 847
610 x86_68k_options opts; 848 x86_68k_options opts;
611 m68k_context context; 849 m68k_context context;
612 vdp_context v_context; 850 vdp_context v_context;
627 translate_m68k_stream(address, &context); 865 translate_m68k_stream(address, &context);
628 address = cart[0x78/2] << 16 | cart[0x7A/2]; 866 address = cart[0x78/2] << 16 | cart[0x7A/2];
629 translate_m68k_stream(address, &context);*/ 867 translate_m68k_stream(address, &context);*/
630 address = cart[2] << 16 | cart[3]; 868 address = cart[2] << 16 | cart[3];
631 translate_m68k_stream(address, &context); 869 translate_m68k_stream(address, &context);
870 if (debug) {
871 insert_breakpoint(&context, address, (uint8_t *)debugger);
872 }
632 m68k_reset(&context); 873 m68k_reset(&context);
633 return 0; 874 return 0;
634 } 875 }