Mercurial > repos > blastem
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 } |