Mercurial > repos > blastem
comparison debug.c @ 2178:f6d5bde4d07f
Finish debugger refactor started with expression parser changes
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 13 Aug 2022 19:16:30 -0700 |
parents | 44596610b2a0 |
children | 9a8dd4ba2753 |
comparison
equal
deleted
inserted
replaced
2177:44596610b2a0 | 2178:f6d5bde4d07f |
---|---|
18 #define Z80_OPTS opts | 18 #define Z80_OPTS opts |
19 #else | 19 #else |
20 #define Z80_OPTS options | 20 #define Z80_OPTS options |
21 #endif | 21 #endif |
22 | 22 |
23 | |
24 | |
25 static debug_root roots[5]; | 23 static debug_root roots[5]; |
26 static uint32_t num_roots; | 24 static uint32_t num_roots; |
27 #define MAX_DEBUG_ROOTS (sizeof(roots)/sizeof(*roots)) | 25 #define MAX_DEBUG_ROOTS (sizeof(roots)/sizeof(*roots)) |
28 | 26 |
29 debug_root *find_root(void *cpu) | 27 debug_root *find_root(void *cpu) |
62 } | 60 } |
63 cur = &((*cur)->next); | 61 cur = &((*cur)->next); |
64 } | 62 } |
65 return cur; | 63 return cur; |
66 } | 64 } |
67 | |
68 typedef enum { | |
69 TOKEN_NONE, | |
70 TOKEN_NUM, | |
71 TOKEN_NAME, | |
72 TOKEN_OPER, | |
73 TOKEN_SIZE, | |
74 TOKEN_LBRACKET, | |
75 TOKEN_RBRACKET, | |
76 TOKEN_LPAREN, | |
77 TOKEN_RPAREN | |
78 } token_type; | |
79 | 65 |
80 static const char *token_type_names[] = { | 66 static const char *token_type_names[] = { |
81 "TOKEN_NONE", | 67 "TOKEN_NONE", |
82 "TOKEN_NUM", | 68 "TOKEN_NUM", |
83 "TOKEN_NAME", | 69 "TOKEN_NAME", |
87 "TOKEN_RBRACKET", | 73 "TOKEN_RBRACKET", |
88 "TOKEN_LPAREN", | 74 "TOKEN_LPAREN", |
89 "TOKEN_RPAREN" | 75 "TOKEN_RPAREN" |
90 }; | 76 }; |
91 | 77 |
92 typedef struct { | |
93 token_type type; | |
94 union { | |
95 char *str; | |
96 char op[3]; | |
97 uint32_t num; | |
98 } v; | |
99 } token; | |
100 | |
101 static token parse_token(char *start, char **end) | 78 static token parse_token(char *start, char **end) |
102 { | 79 { |
103 while(*start && isblank(*start) && *start != '\n') | 80 while(*start && isblank(*start) && *start != '\n' && *start != '\r') |
104 { | 81 { |
105 ++start; | 82 ++start; |
106 } | 83 } |
107 if (!*start || *start == '\n') { | 84 if (!*start || *start == '\n' || *start == '\r') { |
108 return (token){ | 85 return (token){ |
109 .type = TOKEN_NONE | 86 .type = TOKEN_NONE |
110 }; | 87 }; |
111 *end = start; | 88 *end = start; |
112 } | 89 } |
182 return (token) { | 159 return (token) { |
183 .type = TOKEN_RPAREN | 160 .type = TOKEN_RPAREN |
184 }; | 161 }; |
185 } | 162 } |
186 *end = start + 1; | 163 *end = start + 1; |
187 while (**end && !isblank(**end)) | 164 while (**end && !isspace(**end)) |
188 { | 165 { |
189 uint8_t done = 0; | 166 uint8_t done = 0; |
190 switch (**end) | 167 switch (**end) |
191 { | 168 { |
192 case '+': | 169 case '+': |
217 .v = { | 194 .v = { |
218 .str = name | 195 .str = name |
219 } | 196 } |
220 }; | 197 }; |
221 } | 198 } |
222 | |
223 typedef enum { | |
224 EXPR_NONE, | |
225 EXPR_SCALAR, | |
226 EXPR_UNARY, | |
227 EXPR_BINARY, | |
228 EXPR_SIZE, | |
229 EXPR_MEM | |
230 } expr_type; | |
231 | |
232 typedef struct expr expr; | |
233 | |
234 struct expr { | |
235 expr_type type; | |
236 expr *left; | |
237 expr *right; | |
238 token op; | |
239 }; | |
240 | 199 |
241 static void free_expr(expr *e) | 200 static void free_expr(expr *e) |
242 { | 201 { |
243 if (!e) { | 202 if (!e) { |
244 return; | 203 return; |
617 value->left = calloc(1, sizeof(expr)); | 576 value->left = calloc(1, sizeof(expr)); |
618 value->left->type = EXPR_SCALAR; | 577 value->left->type = EXPR_SCALAR; |
619 value->left->op = first; | 578 value->left->op = first; |
620 return maybe_binary(value, after_second, end); | 579 return maybe_binary(value, after_second, end); |
621 } else { | 580 } else { |
581 if (second.type == TOKEN_NAME) { | |
582 free(second.v.str); | |
583 } | |
622 expr *ret = calloc(1, sizeof(expr)); | 584 expr *ret = calloc(1, sizeof(expr)); |
623 ret->type = EXPR_SCALAR; | 585 ret->type = EXPR_SCALAR; |
624 ret->op = first; | 586 ret->op = first; |
625 *end = after_first; | 587 *end = after_first; |
626 return ret; | 588 return ret; |
717 default: | 679 default: |
718 return 0; | 680 return 0; |
719 } | 681 } |
720 } | 682 } |
721 | 683 |
722 void add_display(disp_def ** head, uint32_t *index, char format_char, char * param) | |
723 { | |
724 disp_def * ndisp = malloc(sizeof(*ndisp)); | |
725 ndisp->format_char = format_char; | |
726 ndisp->param = strdup(param); | |
727 ndisp->next = *head; | |
728 ndisp->index = *index++; | |
729 *head = ndisp; | |
730 } | |
731 | |
732 void remove_display(disp_def ** head, uint32_t index) | |
733 { | |
734 while (*head) { | |
735 if ((*head)->index == index) { | |
736 disp_def * del_disp = *head; | |
737 *head = del_disp->next; | |
738 free(del_disp->param); | |
739 free(del_disp); | |
740 } else { | |
741 head = &(*head)->next; | |
742 } | |
743 } | |
744 } | |
745 | |
746 char * find_param(char * buf) | 684 char * find_param(char * buf) |
747 { | 685 { |
748 for (; *buf; buf++) { | 686 for (; *buf; buf++) { |
749 if (*buf == ' ') { | 687 if (*buf == ' ') { |
750 if (*(buf+1)) { | 688 if (*(buf+1)) { |
785 { | 723 { |
786 m68k_context *context = root->cpu_context; | 724 m68k_context *context = root->cpu_context; |
787 if (size == 'b') { | 725 if (size == 'b') { |
788 *out = m68k_read_byte(*out, context); | 726 *out = m68k_read_byte(*out, context); |
789 } else if (size == 'l') { | 727 } else if (size == 'l') { |
728 if (*out & 1) { | |
729 fprintf(stderr, "Longword access to odd addresses (%X) is not allowed\n", *out); | |
730 return 0; | |
731 } | |
790 *out = m68k_read_long(*out, context); | 732 *out = m68k_read_long(*out, context); |
791 } else { | 733 } else { |
734 if (*out & 1) { | |
735 fprintf(stderr, "Wword access to odd addresses (%X) is not allowed\n", *out); | |
736 return 0; | |
737 } | |
792 *out = m68k_read_word(*out, context); | 738 *out = m68k_read_word(*out, context); |
739 } | |
740 return 1; | |
741 } | |
742 | |
743 static uint8_t write_m68k(debug_root *root, uint32_t address, uint32_t value, char size) | |
744 { | |
745 m68k_context *context = root->cpu_context; | |
746 if (size == 'b') { | |
747 write_byte(address, value, (void **)context->mem_pointers, &context->options->gen, context); | |
748 } else if (size == 'l') { | |
749 if (address & 1) { | |
750 fprintf(stderr, "Longword access to odd addresses (%X) is not allowed\n", address); | |
751 return 0; | |
752 } | |
753 write_word(address, value >> 16, (void **)context->mem_pointers, &context->options->gen, context); | |
754 write_word(address + 2, value, (void **)context->mem_pointers, &context->options->gen, context); | |
755 } else { | |
756 if (address & 1) { | |
757 fprintf(stderr, "Wword access to odd addresses (%X) is not allowed\n", address); | |
758 return 0; | |
759 } | |
760 write_word(address, value, (void **)context->mem_pointers, &context->options->gen, context); | |
793 } | 761 } |
794 return 1; | 762 return 1; |
795 } | 763 } |
796 | 764 |
797 static uint8_t resolve_m68k(debug_root *root, const char *name, uint32_t *out) | 765 static uint8_t resolve_m68k(debug_root *root, const char *name, uint32_t *out) |
818 return 0; | 786 return 0; |
819 } | 787 } |
820 return 1; | 788 return 1; |
821 } | 789 } |
822 | 790 |
791 static uint8_t set_m68k(debug_root *root, const char *name, uint32_t value) | |
792 { | |
793 m68k_context *context = root->cpu_context; | |
794 if ((name[0] == 'd' || name[0] == 'D') && name[1] >= '0' && name[1] <= '7' && !name[2]) { | |
795 context->dregs[name[1]-'0'] = value; | |
796 } else if ((name[0] == 'a' || name[0] == 'A') && name[1] >= '0' && name[1] <= '7' && !name[2]) { | |
797 context->aregs[name[1]-'0'] = value; | |
798 } else if (!strcasecmp(name, "sr")) { | |
799 context->status = value >> 8; | |
800 for (int flag = 0; flag < 5; flag++) { | |
801 context->flags[flag] = (value & (1 << (4 - flag))) != 0; | |
802 } | |
803 } else if (!strcasecmp(name, "usp")) { | |
804 context->aregs[context->status & 0x20 ? 8 : 7] = value; | |
805 } else if (!strcasecmp(name, "ssp")) { | |
806 context->aregs[context->status & 0x20 ? 7 : 8] = value; | |
807 } else { | |
808 return 0; | |
809 } | |
810 return 1; | |
811 } | |
812 | |
823 static uint8_t resolve_genesis(debug_root *root, const char *name, uint32_t *out) | 813 static uint8_t resolve_genesis(debug_root *root, const char *name, uint32_t *out) |
824 { | 814 { |
825 if (resolve_m68k(root, name, out)) { | 815 if (resolve_m68k(root, name, out)) { |
826 return 1; | 816 return 1; |
827 } | 817 } |
832 return 1; | 822 return 1; |
833 } | 823 } |
834 return 0; | 824 return 0; |
835 } | 825 } |
836 | 826 |
837 void debugger_print(debug_root *root, char format_char, char *param) | 827 void ambiguous_iter(char *key, tern_val val, uint8_t valtype, void *data) |
838 { | 828 { |
839 uint32_t value; | 829 char *prefix = data; |
840 char format[8]; | 830 char * full = alloc_concat(prefix, key); |
841 strcpy(format, "%s: %d\n"); | 831 fprintf(stderr, "\t%s\n", full); |
842 switch (format_char) | 832 free(full); |
843 { | 833 } |
844 case 'x': | 834 |
845 case 'X': | 835 uint8_t parse_command(debug_root *root, char *text, parsed_command *out) |
846 case 'd': | 836 { |
847 case 'c': | 837 char *cur = text; |
848 case 's': | 838 while (*cur && *cur != '/' && !isspace(*cur)) |
849 format[5] = format_char; | 839 { |
850 break; | 840 ++cur; |
851 case '\0': | 841 } |
852 break; | 842 char *name = malloc(cur - text + 1); |
853 default: | 843 memcpy(name, text, cur - text); |
854 fprintf(stderr, "Unrecognized format character: %c\n", format_char); | 844 name[cur-text] = 0; |
855 } | 845 uint8_t ret = 0; |
856 char *after; | 846 tern_node *prefix_res = tern_find_prefix(root->commands, name); |
857 uint8_t at_least_one = 0; | 847 command_def *def = tern_find_ptr(prefix_res, ""); |
858 while (*param && *param != '\n') | 848 if (!def) { |
859 { | 849 tern_node *node = prefix_res; |
860 at_least_one = 1; | 850 while (node) |
861 expr *e = parse_expression(param, &after); | 851 { |
862 if (e) { | 852 if (node->left || node->right) { |
863 if (!eval_expr(root, e, &value)) { | 853 break; |
864 fprintf(stderr, "Failed to eval %s\n", param); | 854 } |
865 } | 855 if (node->el) { |
866 free_expr(e); | 856 node = node->straight.next; |
867 } else { | 857 } else { |
868 fprintf(stderr, "Failed to parse %s\n", param); | 858 def = node->straight.value.ptrval; |
869 } | 859 break; |
870 char *tmp_param = malloc(after-param+1); | 860 } |
871 memcpy(tmp_param, param, after-param); | 861 } |
872 tmp_param[after-param] = 0; | 862 if (!def && prefix_res) { |
873 param = after; | 863 fprintf(stderr, "%s is ambiguous. Matching commands:\n", name); |
874 if (format_char == 's') { | 864 tern_foreach(prefix_res, ambiguous_iter, name); |
865 goto cleanup_name; | |
866 } | |
867 } | |
868 if (!def) { | |
869 fprintf(stderr, "%s is not a recognized command\n", name); | |
870 goto cleanup_name; | |
871 } | |
872 char *format = NULL; | |
873 if (*cur == '/') { | |
874 ++cur; | |
875 text = cur; | |
876 while (*cur && !isspace(*cur)) | |
877 { | |
878 ++cur; | |
879 } | |
880 format = malloc(cur - text + 1); | |
881 memcpy(format, text, cur - text); | |
882 format[cur - text] = 0; | |
883 } | |
884 int num_args = 0; | |
885 command_arg *args = NULL; | |
886 if (*cur && *cur != '\n') { | |
887 ++cur; | |
888 } | |
889 text = cur; | |
890 if (def->raw_impl) { | |
891 while (*cur && *cur != '\n') | |
892 { | |
893 ++cur; | |
894 } | |
895 char *raw_param = NULL; | |
896 if (cur != text) { | |
897 raw_param = malloc(cur - text + 1); | |
898 memcpy(raw_param, text, cur - text); | |
899 raw_param[cur - text] = 0; | |
900 } | |
901 out->raw = raw_param; | |
902 out->args = NULL; | |
903 out->num_args = 0; | |
904 } else { | |
905 int arg_storage = 0; | |
906 if (def->max_args > 0) { | |
907 arg_storage = def->max_args; | |
908 } else if (def->max_args) { | |
909 arg_storage = def->min_args > 0 ? 2 * def->min_args : 2; | |
910 } | |
911 if (arg_storage) { | |
912 args = calloc(arg_storage, sizeof(command_arg)); | |
913 } | |
914 while (*text && *text != '\n') | |
915 { | |
916 char *after; | |
917 expr *e = parse_expression(text, &after); | |
918 if (e) { | |
919 if (num_args == arg_storage) { | |
920 if (def->max_args >= 0) { | |
921 free_expr(e); | |
922 fprintf(stderr, "Command %s takes a max of %d arguments, but at least %d provided\n", name, def->max_args, def->max_args+1); | |
923 goto cleanup_args; | |
924 } else { | |
925 arg_storage *= 2; | |
926 args = realloc(args, arg_storage * sizeof(command_arg)); | |
927 } | |
928 } | |
929 args[num_args].parsed = e; | |
930 args[num_args].raw = malloc(after - text + 1); | |
931 memcpy(args[num_args].raw, text, after - text); | |
932 args[num_args++].raw[after - text] = 0; | |
933 text = after; | |
934 } else { | |
935 goto cleanup_args; | |
936 } | |
937 } | |
938 if (num_args < def->min_args) { | |
939 fprintf(stderr, "Command %s requires at least %d arguments, but only %d provided\n", name, def->min_args, num_args); | |
940 goto cleanup_args; | |
941 } | |
942 out->raw = NULL; | |
943 out->args = args; | |
944 out->num_args = num_args; | |
945 } | |
946 out->def = def; | |
947 out->format = format; | |
948 | |
949 ret = 1; | |
950 cleanup_args: | |
951 if (!ret) { | |
952 for (int i = 0; i < num_args; i++) | |
953 { | |
954 free_expr(args[i].parsed); | |
955 free(args[i].raw); | |
956 } | |
957 free(args); | |
958 } | |
959 cleanup_name: | |
960 free(name); | |
961 return ret; | |
962 } | |
963 | |
964 static void free_parsed_command(parsed_command *cmd) | |
965 { | |
966 free(cmd->format); | |
967 free(cmd->raw); | |
968 for (int i = 0; i < cmd->num_args; i++) | |
969 { | |
970 free(cmd->args[i].raw); | |
971 free_expr(cmd->args[i].parsed); | |
972 } | |
973 free(cmd->args); | |
974 } | |
975 | |
976 static uint8_t cmd_quit(debug_root *root, char *format, int num_args, command_arg *args) | |
977 { | |
978 exit(0); | |
979 } | |
980 | |
981 typedef struct { | |
982 size_t num_commands; | |
983 size_t longest_command; | |
984 } help_state; | |
985 | |
986 static void help_first_pass(char *key, tern_val val, uint8_t valtype, void *data) | |
987 { | |
988 command_def *def = val.ptrval; | |
989 if (def->visited) { | |
990 return; | |
991 } | |
992 def->visited = 1; | |
993 help_state *state = data; | |
994 state->num_commands++; | |
995 size_t len = strlen(def->usage); | |
996 if (len > state->longest_command) { | |
997 state->longest_command = len; | |
998 } | |
999 } | |
1000 | |
1001 static void help_reset_visited(char *key, tern_val val, uint8_t valtype, void *data) | |
1002 { | |
1003 command_def *def = val.ptrval; | |
1004 def->visited = 0; | |
1005 } | |
1006 | |
1007 static void help_second_pass(char *key, tern_val val, uint8_t valtype, void *data) | |
1008 { | |
1009 command_def *def = val.ptrval; | |
1010 if (def->visited) { | |
1011 return; | |
1012 } | |
1013 def->visited = 1; | |
1014 help_state *state = data; | |
1015 size_t len = strlen(def->usage); | |
1016 printf(" %s", def->usage); | |
1017 while (len < state->longest_command) { | |
1018 putchar(' '); | |
1019 len++; | |
1020 } | |
1021 int remaining = 80 - state->longest_command - 5; | |
1022 const char *extra_desc = NULL; | |
1023 if (strlen(def->desc) <= remaining) { | |
1024 printf(" - %s\n", def->desc); | |
1025 } else { | |
1026 char split[76]; | |
1027 int split_point = remaining; | |
1028 while (split_point > 0 && !isspace(def->desc[split_point])) | |
1029 { | |
1030 --split_point; | |
1031 } | |
1032 if (!split_point) { | |
1033 split_point = remaining; | |
1034 } | |
1035 memcpy(split, def->desc, split_point); | |
1036 extra_desc = def->desc + split_point + 1; | |
1037 split[split_point] = 0; | |
1038 printf(" - %s\n", split); | |
1039 } | |
1040 if (def->names[1]) { | |
1041 fputs(" Aliases: ", stdout); | |
1042 len = strlen(" Aliases: "); | |
1043 const char **name = def->names + 1; | |
1044 uint8_t first = 1; | |
1045 while (*name) | |
1046 { | |
1047 if (first) { | |
1048 first = 0; | |
1049 } else { | |
1050 putchar(','); | |
1051 putchar(' '); | |
1052 len += 2; | |
1053 } | |
1054 fputs(*name, stdout); | |
1055 len += strlen(*name); | |
1056 ++name; | |
1057 } | |
1058 } else { | |
1059 len = 0; | |
1060 } | |
1061 if (extra_desc) { | |
1062 while (len < state->longest_command + 5) { | |
1063 putchar(' '); | |
1064 len++; | |
1065 } | |
1066 fputs(extra_desc, stdout); | |
1067 } | |
1068 putchar('\n'); | |
1069 } | |
1070 | |
1071 static uint8_t cmd_help(debug_root *root, char *format, char *param) | |
1072 { | |
1073 help_state state = {0,0}; | |
1074 tern_foreach(root->commands, help_first_pass, &state); | |
1075 tern_foreach(root->commands, help_reset_visited, &state); | |
1076 tern_foreach(root->commands, help_second_pass, &state); | |
1077 tern_foreach(root->commands, help_reset_visited, &state); | |
1078 return 1; | |
1079 } | |
1080 | |
1081 static uint8_t cmd_continue(debug_root *root, char *format, int num_args, command_arg *args) | |
1082 { | |
1083 return 0; | |
1084 } | |
1085 | |
1086 static uint8_t cmd_print(debug_root *root, char *format, int num_args, command_arg *args) | |
1087 { | |
1088 char format_str[8]; | |
1089 strcpy(format_str, "%s: %d\n"); | |
1090 if (format) { | |
1091 switch (format[0]) | |
1092 { | |
1093 case 'x': | |
1094 case 'X': | |
1095 case 'd': | |
1096 case 'c': | |
1097 case 's': | |
1098 format_str[5] = format[0]; | |
1099 break; | |
1100 default: | |
1101 fprintf(stderr, "Unrecognized format character: %c\n", format[0]); | |
1102 } | |
1103 } | |
1104 for (int i = 0; i < num_args; i++) | |
1105 { | |
1106 if (format && format[0] == 's') { | |
875 char tmp[128]; | 1107 char tmp[128]; |
876 int i; | 1108 int j; |
877 for (i = 0; i < sizeof(tmp)-1; i++, value++) | 1109 uint32_t addr = args[i].value; |
1110 for (j = 0; j < sizeof(tmp)-1; j++, addr++) | |
878 { | 1111 { |
879 uint32_t addr = value; | 1112 uint32_t tmp_addr = addr; |
880 root->read_mem(root, &addr, 'b'); | 1113 root->read_mem(root, &tmp_addr, 'b'); |
881 char c = addr; | 1114 char c = addr; |
882 if (c < 0x20 || c > 0x7F) { | 1115 if (c < 0x20 || c > 0x7F) { |
883 break; | 1116 break; |
884 } | 1117 } |
885 tmp[i] = c; | 1118 tmp[j] = c; |
886 } | 1119 } |
887 tmp[i] = 0; | 1120 tmp[j] = 0; |
888 printf(format, tmp_param, tmp); | 1121 printf(format_str, args[i].raw, tmp); |
889 } else { | 1122 } else { |
890 printf(format, tmp_param, value); | 1123 printf(format_str, args[i].raw, args[i].value); |
891 } | 1124 } |
892 free(tmp_param); | 1125 } |
893 while (*param && isblank(*param) && *param != '\n') | 1126 return 1; |
1127 } | |
1128 | |
1129 static uint8_t cmd_display(debug_root *root, char *format, int num_args, command_arg *args) | |
1130 { | |
1131 cmd_print(root, format, num_args, args); | |
1132 disp_def *ndisp = calloc(1, sizeof(*ndisp)); | |
1133 ndisp->next = root->displays; | |
1134 ndisp->index = root->disp_index++; | |
1135 ndisp->format = format ? strdup(format) : NULL; | |
1136 ndisp->num_args = num_args; | |
1137 ndisp->args = calloc(num_args, sizeof(command_arg)); | |
1138 memcpy(ndisp->args, args, num_args * sizeof(command_arg)); | |
1139 memset(args, 0, num_args * sizeof(command_arg)); | |
1140 root->displays = ndisp; | |
1141 printf("Added display %d\n", ndisp->index); | |
1142 return 1; | |
1143 } | |
1144 | |
1145 static uint8_t cmd_delete_display(debug_root *root, char *format, int num_args, command_arg *args) | |
1146 { | |
1147 disp_def **cur = &root->displays; | |
1148 while (*cur) | |
1149 { | |
1150 if ((*cur)->index == args[0].value) { | |
1151 disp_def *del_disp = *cur; | |
1152 *cur = del_disp->next; | |
1153 free(del_disp->format); | |
1154 for (int i = 0; i < del_disp->num_args; i++) | |
1155 { | |
1156 free(del_disp->args[i].raw); | |
1157 free_expr(del_disp->args[i].parsed); | |
1158 } | |
1159 free(del_disp->args); | |
1160 free(del_disp); | |
1161 break; | |
1162 } else { | |
1163 cur = &(*cur)->next; | |
1164 } | |
1165 } | |
1166 return 1; | |
1167 } | |
1168 | |
1169 static uint8_t cmd_softreset(debug_root *root, char *format, int num_args, command_arg *args) | |
1170 { | |
1171 if (current_system->soft_reset) { | |
1172 current_system->soft_reset(current_system); | |
1173 return 0; | |
1174 } else { | |
1175 fputs("Current system does not support soft reset", stderr); | |
1176 return 1; | |
1177 } | |
1178 } | |
1179 | |
1180 static uint8_t cmd_command(debug_root *root, char *format, int num_args, command_arg *args) | |
1181 { | |
1182 bp_def **target = find_breakpoint_idx(&root->breakpoints, args[0].value); | |
1183 if (!target) { | |
1184 fprintf(stderr, "Breakpoint %d does not exist!\n", args[0].value); | |
1185 return 1; | |
1186 } | |
1187 printf("Enter commands for breakpoing %d, type end when done\n", args[0].value); | |
1188 char cmd_buf[1024]; | |
1189 char *commands = NULL; | |
1190 uint32_t cmd_storage = 4; | |
1191 for (uint32_t i = 0; i < (*target)->num_commands; i++) | |
1192 { | |
1193 free_parsed_command((*target)->commands + i); | |
1194 } | |
1195 free((*target)->commands); | |
1196 (*target)->commands = calloc(cmd_storage, sizeof(parsed_command)); | |
1197 for (;;) | |
1198 { | |
1199 fputs(">>", stdout); | |
1200 fflush(stdout); | |
1201 fgets(cmd_buf, sizeof(cmd_buf), stdin); | |
1202 if (!strcmp(cmd_buf, "end\n")) { | |
1203 return 1; | |
1204 } else { | |
1205 if ((*target)->num_commands == cmd_storage) { | |
1206 cmd_storage *= 2; | |
1207 (*target)->commands = realloc((*target)->commands, cmd_storage * sizeof(parsed_command)); | |
1208 } | |
1209 if (parse_command(root, cmd_buf, (*target)->commands + (*target)->num_commands)) { | |
1210 ++(*target)->num_commands; | |
1211 } | |
1212 } | |
1213 } | |
1214 } | |
1215 | |
1216 const char *expr_type_names[] = { | |
1217 "EXPR_NONE", | |
1218 "EXPR_SCALAR", | |
1219 "EXPR_UNARY", | |
1220 "EXPR_BINARY", | |
1221 "EXPR_SIZE", | |
1222 "EXPR_MEM" | |
1223 }; | |
1224 | |
1225 static uint8_t run_command(debug_root *root, parsed_command *cmd) | |
1226 { | |
1227 if (cmd->def->raw_impl) { | |
1228 return cmd->def->raw_impl(root, cmd->format, cmd->raw); | |
1229 } else { | |
1230 for (int i = 0; i < cmd->num_args; i++) | |
894 { | 1231 { |
895 ++param; | 1232 if (!eval_expr(root, cmd->args[i].parsed, &cmd->args[i].value)) { |
896 } | 1233 fprintf(stderr, "Failed to eval %s\n", cmd->args[i].raw); |
897 } | 1234 return 1; |
898 if (!at_least_one) { | 1235 } |
899 fprintf(stderr, "Missing argument to print/%c\n", format_char); | 1236 } |
900 } | 1237 return cmd->def->impl(root, cmd->format, cmd->num_args, cmd->args); |
901 } | 1238 } |
902 | 1239 } |
903 #ifndef NO_Z80 | 1240 |
904 | 1241 static uint8_t cmd_set(debug_root *root, char *format, int num_args, command_arg *args) |
905 void zdebugger_print(z80_context * context, char format_char, char * param) | 1242 { |
906 { | 1243 char *name = NULL; |
907 uint32_t value; | 1244 char size = 0; |
908 char format[8]; | 1245 uint32_t address; |
909 strcpy(format, "%s: %d\n"); | 1246 switch (args[0].parsed->type) |
910 genesis_context *system = context->system; | 1247 { |
911 switch (format_char) | 1248 case EXPR_SCALAR: |
912 { | 1249 if (args[0].parsed->op.type == TOKEN_NAME) { |
913 case 'x': | 1250 name = args[0].parsed->op.v.str; |
914 case 'X': | 1251 } else { |
915 case 'd': | 1252 fputs("First argument to set must be a name or memory expression, not a number", stderr); |
916 case 'c': | 1253 return 1; |
917 format[5] = format_char; | 1254 } |
918 break; | 1255 break; |
919 case '\0': | 1256 case EXPR_SIZE: |
1257 size = args[0].parsed->op.v.op[0]; | |
1258 if (args[0].parsed->left->op.type == TOKEN_NAME) { | |
1259 name = args[0].parsed->left->op.v.str; | |
1260 } else { | |
1261 fputs("First argument to set must be a name or memory expression, not a number", stderr); | |
1262 return 1; | |
1263 } | |
1264 break; | |
1265 case EXPR_MEM: | |
1266 size = args[0].parsed->op.v.op[0]; | |
1267 if (!eval_expr(root, args[0].parsed->left, &address)) { | |
1268 fprintf(stderr, "Failed to eval %s\n", args[0].raw); | |
1269 return 1; | |
1270 } | |
920 break; | 1271 break; |
921 default: | 1272 default: |
922 fprintf(stderr, "Unrecognized format character: %c\n", format_char); | 1273 fprintf(stderr, "First argument to set must be a name or memory expression, got %s\n", expr_type_names[args[0].parsed->type]); |
923 } | 1274 return 1; |
924 switch (param[0]) | 1275 } |
925 { | 1276 if (!eval_expr(root, args[1].parsed, &args[1].value)) { |
1277 fprintf(stderr, "Failed to eval %s\n", args[1].raw); | |
1278 return 1; | |
1279 } | |
1280 uint32_t value = args[1].value; | |
1281 if (name && size && size != 'l') { | |
1282 uint32_t old; | |
1283 if (!root->resolve(root, name, &old)) { | |
1284 fprintf(stderr, "Failed to eval %s\n", name); | |
1285 return 1; | |
1286 } | |
1287 if (size == 'b') { | |
1288 old &= 0xFFFFFF00; | |
1289 value &= 0xFF; | |
1290 value |= old; | |
1291 } else { | |
1292 old &= 0xFFFF0000; | |
1293 value &= 0xFFFF; | |
1294 value |= old; | |
1295 } | |
1296 } | |
1297 if (name) { | |
1298 if (!root->set(root, name, value)) { | |
1299 fprintf(stderr, "Failed to set %s\n", name); | |
1300 } | |
1301 } else if (!root->write_mem(root, address, value, size)) { | |
1302 fprintf(stderr, "Failed to write to address %X\n", address); | |
1303 } | |
1304 return 1; | |
1305 } | |
1306 | |
1307 static uint8_t cmd_delete_m68k(debug_root *root, char *format, int num_args, command_arg *args) | |
1308 { | |
1309 bp_def **this_bp = find_breakpoint_idx(&root->breakpoints, args[0].value); | |
1310 if (!*this_bp) { | |
1311 fprintf(stderr, "Breakpoint %d does not exist\n", args[0].value); | |
1312 return 1; | |
1313 } | |
1314 bp_def *tmp = *this_bp; | |
1315 remove_breakpoint(root->cpu_context, tmp->address); | |
1316 *this_bp = (*this_bp)->next; | |
1317 if (tmp->commands) { | |
1318 for (uint32_t i = 0; i < tmp->num_commands; i++) | |
1319 { | |
1320 free_parsed_command(tmp->commands + i); | |
1321 } | |
1322 free(tmp->commands); | |
1323 } | |
1324 free(tmp); | |
1325 return 1; | |
1326 } | |
1327 | |
1328 static uint8_t cmd_breakpoint_m68k(debug_root *root, char *format, int num_args, command_arg *args) | |
1329 { | |
1330 insert_breakpoint(root->cpu_context, args[0].value, debugger); | |
1331 bp_def *new_bp = calloc(1, sizeof(bp_def)); | |
1332 new_bp->next = root->breakpoints; | |
1333 new_bp->address = args[0].value; | |
1334 new_bp->index = root->bp_index++; | |
1335 root->breakpoints = new_bp; | |
1336 printf("68K Breakpoint %d set at %X\n", new_bp->index, args[0].value); | |
1337 return 1; | |
1338 } | |
1339 | |
1340 static uint8_t cmd_advance_m68k(debug_root *root, char *format, int num_args, command_arg *args) | |
1341 { | |
1342 insert_breakpoint(root->cpu_context, args[0].value, debugger); | |
1343 return 0; | |
1344 } | |
1345 | |
1346 static uint8_t cmd_step_m68k(debug_root *root, char *format, int num_args, command_arg *args) | |
1347 { | |
1348 m68kinst *inst = root->inst; | |
1349 m68k_context *context = root->cpu_context; | |
1350 uint32_t after = root->after; | |
1351 if (inst->op == M68K_RTS) { | |
1352 after = m68k_read_long(context->aregs[7], context); | |
1353 } else if (inst->op == M68K_RTE || inst->op == M68K_RTR) { | |
1354 after = m68k_read_long(context->aregs[7] + 2, context); | |
1355 } else if(m68k_is_branch(inst)) { | |
1356 if (inst->op == M68K_BCC && inst->extra.cond != COND_TRUE) { | |
1357 root->branch_f = after; | |
1358 root->branch_t = m68k_branch_target(inst, context->dregs, context->aregs) & 0xFFFFFF; | |
1359 insert_breakpoint(context, root->branch_t, debugger); | |
1360 } else if(inst->op == M68K_DBCC) { | |
1361 if (inst->extra.cond == COND_FALSE) { | |
1362 if (context->dregs[inst->dst.params.regs.pri] & 0xFFFF) { | |
1363 after = m68k_branch_target(inst, context->dregs, context->aregs); | |
1364 } | |
1365 } else { | |
1366 root->branch_t = after; | |
1367 root->branch_f = m68k_branch_target(inst, context->dregs, context->aregs); | |
1368 insert_breakpoint(context, root->branch_f, debugger); | |
1369 } | |
1370 } else { | |
1371 after = m68k_branch_target(inst, context->dregs, context->aregs) & 0xFFFFFF; | |
1372 } | |
1373 } | |
1374 insert_breakpoint(root->cpu_context, after, debugger); | |
1375 return 0; | |
1376 } | |
1377 | |
1378 static uint8_t cmd_over_m68k(debug_root *root, char *format, int num_args, command_arg *args) | |
1379 { | |
1380 m68kinst *inst = root->inst; | |
1381 m68k_context *context = root->cpu_context; | |
1382 uint32_t after = root->after; | |
1383 if (inst->op == M68K_RTS) { | |
1384 after = m68k_read_long(context->aregs[7], context); | |
1385 } else if (inst->op == M68K_RTE || inst->op == M68K_RTR) { | |
1386 after = m68k_read_long(context->aregs[7] + 2, context); | |
1387 } else if(m68k_is_noncall_branch(inst)) { | |
1388 if (inst->op == M68K_BCC && inst->extra.cond != COND_TRUE) { | |
1389 root->branch_t = m68k_branch_target(inst, context->dregs, context->aregs) & 0xFFFFFF; | |
1390 if (root->branch_t < after) { | |
1391 root->branch_t = 0; | |
1392 } else { | |
1393 root->branch_f = after; | |
1394 insert_breakpoint(context, root->branch_t, debugger); | |
1395 } | |
1396 } else if(inst->op == M68K_DBCC) { | |
1397 uint32_t target = m68k_branch_target(inst, context->dregs, context->aregs) & 0xFFFFFF; | |
1398 if (target > after) { | |
1399 if (inst->extra.cond == COND_FALSE) { | |
1400 after = target; | |
1401 } else { | |
1402 root->branch_f = target; | |
1403 root->branch_t = after; | |
1404 insert_breakpoint(context, root->branch_f, debugger); | |
1405 } | |
1406 } | |
1407 } else { | |
1408 after = m68k_branch_target(inst, context->dregs, context->aregs) & 0xFFFFFF; | |
1409 } | |
1410 } | |
1411 insert_breakpoint(root->cpu_context, after, debugger); | |
1412 return 0; | |
1413 } | |
1414 | |
1415 static uint8_t cmd_next_m68k(debug_root *root, char *format, int num_args, command_arg *args) | |
1416 { | |
1417 m68kinst *inst = root->inst; | |
1418 m68k_context *context = root->cpu_context; | |
1419 uint32_t after = root->after; | |
1420 if (inst->op == M68K_RTS) { | |
1421 after = m68k_read_long(context->aregs[7], context); | |
1422 } else if (inst->op == M68K_RTE || inst->op == M68K_RTR) { | |
1423 after = m68k_read_long(context->aregs[7] + 2, context); | |
1424 } else if(m68k_is_noncall_branch(inst)) { | |
1425 if (inst->op == M68K_BCC && inst->extra.cond != COND_TRUE) { | |
1426 root->branch_f = after; | |
1427 root->branch_t = m68k_branch_target(inst, context->dregs, context->aregs); | |
1428 insert_breakpoint(context, root->branch_t, debugger); | |
1429 } else if(inst->op == M68K_DBCC) { | |
1430 if ( inst->extra.cond == COND_FALSE) { | |
1431 if (context->dregs[inst->dst.params.regs.pri] & 0xFFFF) { | |
1432 after = m68k_branch_target(inst, context->dregs, context->aregs); | |
1433 } | |
1434 } else { | |
1435 root->branch_t = after; | |
1436 root->branch_f = m68k_branch_target(inst, context->dregs, context->aregs); | |
1437 insert_breakpoint(context, root->branch_f, debugger); | |
1438 } | |
1439 } else { | |
1440 after = m68k_branch_target(inst, context->dregs, context->aregs) & 0xFFFFFF; | |
1441 } | |
1442 } | |
1443 insert_breakpoint(root->cpu_context, after, debugger); | |
1444 return 0; | |
1445 } | |
1446 | |
1447 static uint8_t cmd_backtrace_m68k(debug_root *root, char *format, int num_args, command_arg *args) | |
1448 { | |
1449 m68k_context *context = root->cpu_context; | |
1450 uint32_t stack = context->aregs[7]; | |
1451 uint8_t non_adr_count = 0; | |
1452 do { | |
1453 uint32_t bt_address = m68k_instruction_fetch(stack, context); | |
1454 bt_address = get_instruction_start(context->options, bt_address - 2); | |
1455 if (bt_address) { | |
1456 stack += 4; | |
1457 non_adr_count = 0; | |
1458 m68kinst inst; | |
1459 char buf[128]; | |
1460 m68k_decode(m68k_instruction_fetch, context, &inst, bt_address); | |
1461 m68k_disasm(&inst, buf); | |
1462 printf("%X: %s\n", bt_address, buf); | |
1463 } else { | |
1464 //non-return address value on stack can be word wide | |
1465 stack += 2; | |
1466 non_adr_count++; | |
1467 } | |
1468 //TODO: Make sure we don't wander into an invalid memory region | |
1469 } while (stack && non_adr_count < 6); | |
1470 return 1; | |
1471 } | |
1472 | |
1473 static uint8_t cmd_vdp_sprites(debug_root *root, char *format, int num_args, command_arg *args) | |
1474 { | |
1475 m68k_context *context = root->cpu_context; | |
1476 genesis_context * gen = context->system; | |
1477 vdp_print_sprite_table(gen->vdp); | |
1478 return 1; | |
1479 } | |
1480 | |
1481 static uint8_t cmd_vdp_regs(debug_root *root, char *format, int num_args, command_arg *args) | |
1482 { | |
1483 m68k_context *context = root->cpu_context; | |
1484 genesis_context * gen = context->system; | |
1485 vdp_print_reg_explain(gen->vdp); | |
1486 return 1; | |
1487 } | |
1488 | |
1489 static uint8_t cmd_ym_channel(debug_root *root, char *format, int num_args, command_arg *args) | |
1490 { | |
1491 m68k_context *context = root->cpu_context; | |
1492 genesis_context * gen = context->system; | |
1493 if (num_args) { | |
1494 ym_print_channel_info(gen->ym, args[0].value - 1); | |
1495 } else { | |
1496 for (int i = 0; i < 6; i++) { | |
1497 ym_print_channel_info(gen->ym, i); | |
1498 } | |
1499 } | |
1500 return 1; | |
1501 } | |
1502 | |
1503 static uint8_t cmd_ym_timer(debug_root *root, char *format, int num_args, command_arg *args) | |
1504 { | |
1505 m68k_context *context = root->cpu_context; | |
1506 genesis_context * gen = context->system; | |
1507 ym_print_timer_info(gen->ym); | |
1508 return 1; | |
1509 } | |
1510 | |
1511 static uint8_t cmd_sub(debug_root *root, char *format, char *param) | |
1512 { | |
1513 while (param && *param && isblank(*param)) | |
1514 { | |
1515 ++param; | |
1516 } | |
1517 m68k_context *m68k = root->cpu_context; | |
1518 genesis_context *gen = m68k->system; | |
1519 segacd_context *cd = gen->expansion; | |
1520 if (param && *param && !isspace(*param)) { | |
1521 parsed_command cmd; | |
1522 debug_root *sub_root = find_m68k_root(cd->m68k); | |
1523 if (!sub_root) { | |
1524 fputs("Failed to get debug root for Sub CPU\n", stderr); | |
1525 return 1; | |
1526 } | |
1527 if (!parse_command(sub_root, param, &cmd)) { | |
1528 return 1; | |
1529 } | |
1530 uint8_t ret = run_command(sub_root, &cmd); | |
1531 free_parsed_command(&cmd); | |
1532 return ret; | |
1533 } else { | |
1534 cd->enter_debugger = 1; | |
1535 return 0; | |
1536 } | |
1537 } | |
1538 | |
1539 static uint8_t cmd_main(debug_root *root, char *format, char *param) | |
1540 { | |
1541 while (param && *param && isblank(*param)) | |
1542 { | |
1543 ++param; | |
1544 } | |
1545 m68k_context *m68k = root->cpu_context; | |
1546 segacd_context *cd = m68k->system; | |
1547 | |
1548 if (param && *param && !isspace(*param)) { | |
1549 parsed_command cmd; | |
1550 debug_root *main_root = find_m68k_root(cd->genesis->m68k); | |
1551 if (!main_root) { | |
1552 fputs("Failed to get debug root for Main CPU\n", stderr); | |
1553 return 1; | |
1554 } | |
1555 if (!parse_command(main_root, param, &cmd)) { | |
1556 return 1; | |
1557 } | |
1558 uint8_t ret = run_command(main_root, &cmd); | |
1559 free_parsed_command(&cmd); | |
1560 return ret; | |
1561 } else { | |
1562 cd->genesis->header.enter_debugger = 1; | |
1563 return 0; | |
1564 } | |
1565 } | |
1566 | |
1567 static uint8_t cmd_gen_z80(debug_root *root, char *format, char *param) | |
1568 { | |
1569 while (param && *param && isblank(*param)) | |
1570 { | |
1571 ++param; | |
1572 } | |
1573 m68k_context *m68k = root->cpu_context; | |
1574 genesis_context *gen = m68k->system; | |
1575 | |
1576 if (param && *param && !isspace(*param)) { | |
1577 parsed_command cmd; | |
1578 debug_root *z80_root = find_z80_root(gen->z80); | |
1579 if (!z80_root) { | |
1580 fputs("Failed to get debug root for Z80\n", stderr); | |
1581 return 1; | |
1582 } | |
1583 if (!parse_command(z80_root, param, &cmd)) { | |
1584 return 1; | |
1585 } | |
1586 uint8_t ret = run_command(z80_root, &cmd); | |
1587 free_parsed_command(&cmd); | |
1588 return ret; | |
1589 } else { | |
1590 fputs("not implemented yet", stderr); | |
1591 return 0; | |
1592 } | |
1593 } | |
1594 | |
1595 command_def common_commands[] = { | |
1596 { | |
1597 .names = (const char *[]){ | |
1598 "quit", NULL | |
1599 }, | |
1600 .usage = "quit", | |
1601 .desc = "Quit BlastEm", | |
1602 .impl = cmd_quit, | |
1603 .min_args = 0, | |
1604 .max_args = 0, | |
1605 }, | |
1606 { | |
1607 .names = (const char *[]){ | |
1608 "help", "?", NULL | |
1609 }, | |
1610 .usage = "help", | |
1611 .desc = "Print a list of available commands for the current debug context", | |
1612 .raw_impl = cmd_help, | |
1613 .min_args = 0, | |
1614 .max_args = 1 | |
1615 }, | |
1616 { | |
1617 .names = (const char *[]){ | |
1618 "continue", "c", NULL | |
1619 }, | |
1620 .usage = "continue", | |
1621 .desc = "Resume execution", | |
1622 .impl = cmd_continue, | |
1623 .min_args = 0, | |
1624 .max_args = 0 | |
1625 }, | |
1626 { | |
1627 .names = (const char *[]){ | |
1628 "print", NULL | |
1629 }, | |
1630 .usage = "print[/FORMAT] EXPRESSION...", | |
1631 .desc = "Print one or more expressions using the optional format character", | |
1632 .impl = cmd_print, | |
1633 .min_args = 1, | |
1634 .max_args = -1 | |
1635 }, | |
1636 { | |
1637 .names = (const char *[]){ | |
1638 "softreset", "sr", NULL | |
1639 }, | |
1640 .usage = "softreset", | |
1641 .desc = "Perform a soft-reset for the current system", | |
1642 .impl = cmd_softreset, | |
1643 .min_args = 0, | |
1644 .max_args = 0, | |
1645 }, | |
1646 { | |
1647 .names = (const char *[]){ | |
1648 "display", NULL | |
1649 }, | |
1650 .usage = "display[/FORMAT] EXPRESSION...", | |
1651 .desc = "Print one or more expressions every time the debugger is entered", | |
1652 .impl = cmd_display, | |
1653 .min_args = 1, | |
1654 .max_args = -1 | |
1655 }, | |
1656 { | |
1657 .names = (const char *[]){ | |
1658 "deletedisplay", "dd", NULL | |
1659 }, | |
1660 .usage = "deletedisplay DISPLAYNUM", | |
1661 .desc = "Remove expressions added with the `display` command", | |
1662 .impl = cmd_delete_display, | |
1663 .min_args = 1, | |
1664 .max_args = 1 | |
1665 }, | |
1666 { | |
1667 .names = (const char *[]){ | |
1668 "commands", NULL | |
1669 }, | |
1670 .usage = "command BREAKPOINT", | |
1671 .desc = "Set a list of debugger commands to be executed when the given breakpoint is hit", | |
1672 .impl = cmd_command, | |
1673 .min_args = 1, | |
1674 .max_args = 1 | |
1675 }, | |
1676 { | |
1677 .names = (const char *[]){ | |
1678 "set", NULL | |
1679 }, | |
1680 .usage = "set MEM|NAME VALUE", | |
1681 .desc = "Set a register, symbol or memory location to the result of evaluating VALUE", | |
1682 .impl = cmd_set, | |
1683 .min_args = 2, | |
1684 .max_args = 2, | |
1685 .skip_eval = 1 | |
1686 } | |
1687 }; | |
1688 #define NUM_COMMON (sizeof(common_commands)/sizeof(*common_commands)) | |
1689 | |
1690 command_def m68k_commands[] = { | |
1691 { | |
1692 .names = (const char *[]){ | |
1693 "breakpoint", "b", NULL | |
1694 }, | |
1695 .usage = "breakpoint ADDRESSS", | |
1696 .desc = "Set a breakpoint at ADDRESS", | |
1697 .impl = cmd_breakpoint_m68k, | |
1698 .min_args = 1, | |
1699 .max_args = 1 | |
1700 }, | |
1701 { | |
1702 .names = (const char *[]){ | |
1703 "advance", NULL | |
1704 }, | |
1705 .usage = "advance ADDRESS", | |
1706 .desc = "Advance to ADDRESS", | |
1707 .impl = cmd_advance_m68k, | |
1708 .min_args = 1, | |
1709 .max_args = 1 | |
1710 }, | |
1711 { | |
1712 .names = (const char *[]){ | |
1713 "step", "s", NULL | |
1714 }, | |
1715 .usage = "step", | |
1716 .desc = "Advance to the next instruction, stepping into subroutines", | |
1717 .impl = cmd_step_m68k, | |
1718 .min_args = 0, | |
1719 .max_args = 0 | |
1720 }, | |
1721 { | |
1722 .names = (const char *[]){ | |
1723 "over", NULL | |
1724 }, | |
1725 .usage = "over", | |
1726 .desc = "Advance to the next instruction, ignoring branches to lower addresses", | |
1727 .impl = cmd_over_m68k, | |
1728 .min_args = 0, | |
1729 .max_args = 0 | |
1730 }, | |
1731 { | |
1732 .names = (const char *[]){ | |
1733 "next", NULL | |
1734 }, | |
1735 .usage = "next", | |
1736 .desc = "Advance to the next instruction", | |
1737 .impl = cmd_next_m68k, | |
1738 .min_args = 0, | |
1739 .max_args = 0 | |
1740 }, | |
1741 { | |
1742 .names = (const char *[]){ | |
1743 "backtrace", "bt", NULL | |
1744 }, | |
1745 .usage = "backtrace", | |
1746 .desc = "Print a backtrace", | |
1747 .impl = cmd_backtrace_m68k, | |
1748 .min_args = 0, | |
1749 .max_args = 0 | |
1750 }, | |
1751 { | |
1752 .names = (const char *[]){ | |
1753 "delete", "d", NULL | |
1754 }, | |
1755 .usage = "delete BREAKPOINT", | |
1756 .desc = "Remove breakpoint identified by BREAKPOINT", | |
1757 .impl = cmd_delete_m68k, | |
1758 .min_args = 1, | |
1759 .max_args = 1 | |
1760 } | |
1761 }; | |
1762 | |
1763 #define NUM_68K (sizeof(m68k_commands)/sizeof(*m68k_commands)) | |
1764 | |
1765 command_def genesis_commands[] = { | |
1766 { | |
1767 .names = (const char *[]){ | |
1768 "vdpsprites", "vs", NULL | |
1769 }, | |
1770 .usage = "vdpsprites", | |
1771 .desc = "Print the VDP sprite table", | |
1772 .impl = cmd_vdp_sprites, | |
1773 .min_args = 0, | |
1774 .max_args = 0 | |
1775 }, | |
1776 { | |
1777 .names = (const char *[]){ | |
1778 "vdpsregs", "vr", NULL | |
1779 }, | |
1780 .usage = "vdpregs", | |
1781 .desc = "Print VDP register values with a short description", | |
1782 .impl = cmd_vdp_regs, | |
1783 .min_args = 0, | |
1784 .max_args = 0 | |
1785 }, | |
1786 #ifndef NO_Z80 | |
1787 { | |
1788 .names = (const char *[]){ | |
1789 "z80", NULL | |
1790 }, | |
1791 .usage = "z80 [COMMAND]", | |
1792 .desc = "Run a Z80 debugger command or switch to Z80 context when no command is given", | |
1793 .raw_impl = cmd_gen_z80, | |
1794 .min_args = 0, | |
1795 .max_args = -1 | |
1796 }, | |
1797 #endif | |
1798 { | |
1799 .names = (const char *[]){ | |
1800 "ymchannel", "yc", NULL | |
1801 }, | |
1802 .usage = "ymchannel [CHANNEL]", | |
1803 .desc = "Print YM-2612 channel and operator params. Limited to CHANNEL if specified", | |
1804 .impl = cmd_ym_channel, | |
1805 .min_args = 0, | |
1806 .max_args = 1 | |
1807 }, | |
1808 { | |
1809 .names = (const char *[]){ | |
1810 "ymtimer", "yt", NULL | |
1811 }, | |
1812 .usage = "ymtimer", | |
1813 .desc = "Print YM-2612 timer info", | |
1814 .impl = cmd_ym_timer, | |
1815 .min_args = 0, | |
1816 .max_args = 0 | |
1817 } | |
1818 }; | |
1819 | |
1820 #define NUM_GENESIS (sizeof(genesis_commands)/sizeof(*genesis_commands)) | |
1821 | |
1822 command_def scd_main_commands[] = { | |
1823 { | |
1824 .names = (const char *[]){ | |
1825 "subcpu", NULL | |
1826 }, | |
1827 .usage = "subcpu [COMMAND]", | |
1828 .desc = "Run a Sub-CPU debugger command or switch to Sub-CPU context when no command is given", | |
1829 .raw_impl = cmd_sub, | |
1830 .min_args = 0, | |
1831 .max_args = -1 | |
1832 } | |
1833 }; | |
1834 | |
1835 #define NUM_SCD_MAIN (sizeof(scd_main_commands)/sizeof(*scd_main_commands)) | |
1836 | |
1837 command_def scd_sub_commands[] = { | |
1838 { | |
1839 .names = (const char *[]){ | |
1840 "maincpu", NULL | |
1841 }, | |
1842 .usage = "maincpu [COMMAND]", | |
1843 .desc = "Run a Main-CPU debugger command or switch to Main-CPU context when no command is given", | |
1844 .raw_impl = cmd_main, | |
1845 .min_args = 0, | |
1846 .max_args = -1 | |
1847 } | |
1848 }; | |
1849 | |
1850 #define NUM_SCD_SUB (sizeof(scd_main_commands)/sizeof(*scd_main_commands)) | |
1851 | |
1852 #ifndef NO_Z80 | |
1853 | |
1854 static uint8_t cmd_delete_z80(debug_root *root, char *format, int num_args, command_arg *args) | |
1855 { | |
1856 bp_def **this_bp = find_breakpoint_idx(&root->breakpoints, args[0].value); | |
1857 if (!*this_bp) { | |
1858 fprintf(stderr, "Breakpoint %d does not exist\n", args[0].value); | |
1859 return 1; | |
1860 } | |
1861 bp_def *tmp = *this_bp; | |
1862 zremove_breakpoint(root->cpu_context, tmp->address); | |
1863 *this_bp = (*this_bp)->next; | |
1864 if (tmp->commands) { | |
1865 for (uint32_t i = 0; i < tmp->num_commands; i++) | |
1866 { | |
1867 free_parsed_command(tmp->commands + i); | |
1868 } | |
1869 free(tmp->commands); | |
1870 } | |
1871 free(tmp); | |
1872 return 1; | |
1873 } | |
1874 | |
1875 static uint8_t cmd_breakpoint_z80(debug_root *root, char *format, int num_args, command_arg *args) | |
1876 { | |
1877 zinsert_breakpoint(root->cpu_context, args[0].value, (uint8_t *)zdebugger); | |
1878 bp_def *new_bp = calloc(1, sizeof(bp_def)); | |
1879 new_bp->next = root->breakpoints; | |
1880 new_bp->address = args[0].value; | |
1881 new_bp->index = root->bp_index++; | |
1882 root->breakpoints = new_bp; | |
1883 printf("Z80 Breakpoint %d set at %X\n", new_bp->index, args[0].value); | |
1884 return 1; | |
1885 } | |
1886 | |
1887 static uint8_t cmd_advance_z80(debug_root *root, char *format, int num_args, command_arg *args) | |
1888 { | |
1889 zinsert_breakpoint(root->cpu_context, args[0].value, (uint8_t *)zdebugger); | |
1890 return 0; | |
1891 } | |
1892 | |
1893 static uint8_t cmd_step_z80(debug_root *root, char *format, int num_args, command_arg *args) | |
1894 { | |
1895 z80inst *inst = root->inst; | |
1896 z80_context *context = root->cpu_context; | |
1897 uint32_t after = root->after; | |
1898 //TODO: handle conditional branches | |
1899 if (inst->op == Z80_JP || inst->op == Z80_CALL || inst->op == Z80_RST) { | |
1900 if (inst->addr_mode == Z80_IMMED) { | |
1901 after = inst->immed; | |
1902 } else if (inst->ea_reg == Z80_HL) { | |
926 #ifndef NEW_CORE | 1903 #ifndef NEW_CORE |
1904 after = context->regs[Z80_H] << 8 | context->regs[Z80_L]; | |
1905 } else if (inst->ea_reg == Z80_IX) { | |
1906 after = context->regs[Z80_IXH] << 8 | context->regs[Z80_IXL]; | |
1907 } else if (inst->ea_reg == Z80_IY) { | |
1908 after = context->regs[Z80_IYH] << 8 | context->regs[Z80_IYL]; | |
1909 #endif | |
1910 } | |
1911 } else if(inst->op == Z80_JR) { | |
1912 after += inst->immed; | |
1913 } else if(inst->op == Z80_RET) { | |
1914 uint8_t *sp = get_native_pointer(context->sp, (void **)context->mem_pointers, &context->Z80_OPTS->gen); | |
1915 if (sp) { | |
1916 after = *sp; | |
1917 sp = get_native_pointer((context->sp + 1) & 0xFFFF, (void **)context->mem_pointers, &context->Z80_OPTS->gen); | |
1918 if (sp) { | |
1919 after |= *sp << 8; | |
1920 } | |
1921 } | |
1922 } | |
1923 zinsert_breakpoint(context, after, (uint8_t *)zdebugger); | |
1924 return 0; | |
1925 } | |
1926 | |
1927 static uint8_t cmd_over_z80(debug_root *root, char *format, int num_args, command_arg *args) | |
1928 { | |
1929 fputs("not implemented yet\n", stderr); | |
1930 return 1; | |
1931 } | |
1932 | |
1933 static uint8_t cmd_next_z80(debug_root *root, char *format, int num_args, command_arg *args) | |
1934 { | |
1935 z80inst *inst = root->inst; | |
1936 z80_context *context = root->cpu_context; | |
1937 uint32_t after = root->after; | |
1938 //TODO: handle conditional branches | |
1939 if (inst->op == Z80_JP) { | |
1940 if (inst->addr_mode == Z80_IMMED) { | |
1941 after = inst->immed; | |
1942 } else if (inst->ea_reg == Z80_HL) { | |
1943 #ifndef NEW_CORE | |
1944 after = context->regs[Z80_H] << 8 | context->regs[Z80_L]; | |
1945 } else if (inst->ea_reg == Z80_IX) { | |
1946 after = context->regs[Z80_IXH] << 8 | context->regs[Z80_IXL]; | |
1947 } else if (inst->ea_reg == Z80_IY) { | |
1948 after = context->regs[Z80_IYH] << 8 | context->regs[Z80_IYL]; | |
1949 #endif | |
1950 } | |
1951 } else if(inst->op == Z80_JR) { | |
1952 after += inst->immed; | |
1953 } else if(inst->op == Z80_RET) { | |
1954 uint8_t *sp = get_native_pointer(context->sp, (void **)context->mem_pointers, &context->Z80_OPTS->gen); | |
1955 if (sp) { | |
1956 after = *sp; | |
1957 sp = get_native_pointer((context->sp + 1) & 0xFFFF, (void **)context->mem_pointers, &context->Z80_OPTS->gen); | |
1958 if (sp) { | |
1959 after |= *sp << 8; | |
1960 } | |
1961 } | |
1962 } | |
1963 zinsert_breakpoint(context, after, (uint8_t *)zdebugger); | |
1964 return 0; | |
1965 } | |
1966 | |
1967 static uint8_t cmd_backtrace_z80(debug_root *root, char *format, int num_args, command_arg *args) | |
1968 { | |
1969 z80_context *context = root->cpu_context; | |
1970 uint32_t stack = context->sp; | |
1971 uint8_t non_adr_count = 0; | |
1972 do { | |
1973 uint32_t bt_address = stack; | |
1974 if (!root->read_mem(root, &bt_address, 'w')) { | |
1975 break; | |
1976 } | |
1977 bt_address = z80_get_instruction_start(context, bt_address - 1); | |
1978 if (bt_address != 0xFEEDFEED) { | |
1979 stack += 4; | |
1980 non_adr_count = 0; | |
1981 z80inst inst; | |
1982 char buf[128]; | |
1983 uint8_t *pc = get_native_pointer(bt_address, (void **)context->mem_pointers, &context->Z80_OPTS->gen); | |
1984 z80_decode(pc, &inst); | |
1985 z80_disasm(&inst, buf, bt_address); | |
1986 printf("%X: %s\n", bt_address, buf); | |
1987 } else { | |
1988 //non-return address value on stack can be byte wide | |
1989 stack++; | |
1990 non_adr_count++; | |
1991 } | |
1992 //TODO: Make sure we don't wander into an invalid memory region | |
1993 } while (stack && non_adr_count < 6); | |
1994 return 1; | |
1995 } | |
1996 | |
1997 command_def z80_commands[] = { | |
1998 { | |
1999 .names = (const char *[]){ | |
2000 "breakpoint", "b", NULL | |
2001 }, | |
2002 .usage = "breakpoint ADDRESSS", | |
2003 .desc = "Set a breakpoint at ADDRESS", | |
2004 .impl = cmd_breakpoint_z80, | |
2005 .min_args = 1, | |
2006 .max_args = 1 | |
2007 }, | |
2008 { | |
2009 .names = (const char *[]){ | |
2010 "advance", NULL | |
2011 }, | |
2012 .usage = "advance ADDRESS", | |
2013 .desc = "Advance to ADDRESS", | |
2014 .impl = cmd_advance_z80, | |
2015 .min_args = 1, | |
2016 .max_args = 1 | |
2017 }, | |
2018 { | |
2019 .names = (const char *[]){ | |
2020 "step", "s", NULL | |
2021 }, | |
2022 .usage = "step", | |
2023 .desc = "Advance to the next instruction, stepping into subroutines", | |
2024 .impl = cmd_step_z80, | |
2025 .min_args = 0, | |
2026 .max_args = 0 | |
2027 }, | |
2028 { | |
2029 .names = (const char *[]){ | |
2030 "over", NULL | |
2031 }, | |
2032 .usage = "over", | |
2033 .desc = "Advance to the next instruction, ignoring branches to lower addresses", | |
2034 .impl = cmd_over_z80, | |
2035 .min_args = 0, | |
2036 .max_args = 0 | |
2037 }, | |
2038 { | |
2039 .names = (const char *[]){ | |
2040 "next", NULL | |
2041 }, | |
2042 .usage = "next", | |
2043 .desc = "Advance to the next instruction", | |
2044 .impl = cmd_next_z80, | |
2045 .min_args = 0, | |
2046 .max_args = 0 | |
2047 }, | |
2048 { | |
2049 .names = (const char *[]){ | |
2050 "backtrace", "bt", NULL | |
2051 }, | |
2052 .usage = "backtrace", | |
2053 .desc = "Print a backtrace", | |
2054 .impl = cmd_backtrace_z80, | |
2055 .min_args = 0, | |
2056 .max_args = 0 | |
2057 }, | |
2058 { | |
2059 .names = (const char *[]){ | |
2060 "delete", "d", NULL | |
2061 }, | |
2062 .usage = "delete BREAKPOINT", | |
2063 .desc = "Remove breakpoint identified by BREAKPOINT", | |
2064 .impl = cmd_delete_z80, | |
2065 .min_args = 1, | |
2066 .max_args = 1 | |
2067 } | |
2068 }; | |
2069 | |
2070 #define NUM_Z80 (sizeof(z80_commands)/sizeof(*z80_commands)) | |
2071 | |
2072 #endif | |
2073 | |
2074 void add_commands(debug_root *root, command_def *defs, uint32_t num_commands) | |
2075 { | |
2076 for (uint32_t i = 0; i < num_commands; i++) | |
2077 { | |
2078 for (int j = 0; defs[i].names[j]; j++) | |
2079 { | |
2080 root->commands = tern_insert_ptr(root->commands, defs[i].names[j], defs + i); | |
2081 } | |
2082 } | |
2083 } | |
2084 | |
2085 debug_root *find_m68k_root(m68k_context *context) | |
2086 { | |
2087 debug_root *root = find_root(context); | |
2088 if (root && !root->commands) { | |
2089 add_commands(root, common_commands, NUM_COMMON); | |
2090 add_commands(root, m68k_commands, NUM_68K); | |
2091 root->read_mem = read_m68k; | |
2092 root->write_mem = write_m68k; | |
2093 root->set = set_m68k; | |
2094 switch (current_system->type) | |
2095 { | |
2096 case SYSTEM_GENESIS: | |
2097 case SYSTEM_SEGACD: | |
2098 //check if this is the main CPU | |
2099 if (context->system == current_system) { | |
2100 root->resolve = resolve_genesis; | |
2101 add_commands(root, genesis_commands, NUM_GENESIS); | |
2102 if (current_system->type == SYSTEM_SEGACD) { | |
2103 add_commands(root, scd_main_commands, NUM_SCD_MAIN); | |
2104 } | |
2105 break; | |
2106 } else { | |
2107 add_commands(root, scd_sub_commands, NUM_SCD_SUB); | |
2108 } | |
2109 default: | |
2110 root->resolve = resolve_m68k; | |
2111 } | |
2112 } | |
2113 return root; | |
2114 } | |
2115 | |
2116 #ifndef NO_Z80 | |
2117 | |
2118 static uint8_t read_z80(debug_root *root, uint32_t *out, char size) | |
2119 { | |
2120 z80_context *context = root->cpu_context; | |
2121 uint32_t address = *out; | |
2122 *out = read_byte(address, (void **)context->mem_pointers, &context->options->gen, context); | |
2123 if (size == 'w') { | |
2124 *out |= read_byte(address + 1, (void **)context->mem_pointers, &context->options->gen, context) << 8; | |
2125 } | |
2126 return 1; | |
2127 } | |
2128 | |
2129 static uint8_t write_z80(debug_root *root, uint32_t address, uint32_t value, char size) | |
2130 { | |
2131 z80_context *context = root->cpu_context; | |
2132 write_byte(address, value, (void **)context->mem_pointers, &context->options->gen, context); | |
2133 if (size == 'w') { | |
2134 write_byte(address + 1, value >> 8, (void **)context->mem_pointers, &context->options->gen, context); | |
2135 } | |
2136 return 1; | |
2137 } | |
2138 | |
2139 static uint8_t resolve_z80(debug_root *root, const char *name, uint32_t *out) | |
2140 { | |
2141 z80_context *context = root->cpu_context; | |
2142 switch (tolower(name[0])) | |
2143 { | |
927 case 'a': | 2144 case 'a': |
928 if (param[1] == 'f') { | 2145 if (!name[1]) { |
929 if(param[2] == '\'') { | 2146 *out = context->regs[Z80_A]; |
930 value = context->alt_regs[Z80_A] << 8; | 2147 } else if (name[1] == '\'' && !name[2]) { |
931 value |= context->alt_flags[ZF_S] << 7; | 2148 *out = context->alt_regs[Z80_A]; |
932 value |= context->alt_flags[ZF_Z] << 6; | 2149 } else if (tolower(name[1]) == 'f') { |
933 value |= context->alt_flags[ZF_H] << 4; | 2150 if (!name[2]) { |
934 value |= context->alt_flags[ZF_PV] << 2; | 2151 *out = context->regs[Z80_A] << 8; |
935 value |= context->alt_flags[ZF_N] << 1; | 2152 *out |= context->flags[ZF_S] << 7; |
936 value |= context->alt_flags[ZF_C]; | 2153 *out |= context->flags[ZF_Z] << 6; |
2154 *out |= context->flags[ZF_H] << 4; | |
2155 *out |= context->flags[ZF_PV] << 2; | |
2156 *out |= context->flags[ZF_N] << 1; | |
2157 *out |= context->flags[ZF_C]; | |
2158 } else if (name[2] == '\'' && !name[3]) { | |
2159 *out = context->alt_regs[Z80_A] << 8; | |
2160 *out |= context->alt_flags[ZF_S] << 7; | |
2161 *out |= context->alt_flags[ZF_Z] << 6; | |
2162 *out |= context->alt_flags[ZF_H] << 4; | |
2163 *out |= context->alt_flags[ZF_PV] << 2; | |
2164 *out |= context->alt_flags[ZF_N] << 1; | |
2165 *out |= context->alt_flags[ZF_C]; | |
937 } else { | 2166 } else { |
938 value = context->regs[Z80_A] << 8; | 2167 return 0; |
939 value |= context->flags[ZF_S] << 7; | 2168 } |
940 value |= context->flags[ZF_Z] << 6; | |
941 value |= context->flags[ZF_H] << 4; | |
942 value |= context->flags[ZF_PV] << 2; | |
943 value |= context->flags[ZF_N] << 1; | |
944 value |= context->flags[ZF_C]; | |
945 } | |
946 } else if(param[1] == '\'') { | |
947 value = context->alt_regs[Z80_A]; | |
948 } else { | 2169 } else { |
949 value = context->regs[Z80_A]; | 2170 return 0; |
950 } | 2171 } |
951 break; | 2172 break; |
952 case 'b': | 2173 case 'b': |
953 if (param[1] == 'c') { | 2174 if (!name[1]) { |
954 if(param[2] == '\'') { | 2175 *out = context->regs[Z80_B]; |
955 value = context->alt_regs[Z80_B] << 8; | 2176 } else if (name[1] == '\'' && !name[2]) { |
956 value |= context->alt_regs[Z80_C]; | 2177 *out = context->alt_regs[Z80_B]; |
2178 } else if (tolower(name[1]) == 'c') { | |
2179 if (!name[2]) { | |
2180 *out = context->regs[Z80_B] << 8 | context->regs[Z80_C]; | |
2181 } else if (name[2] == '\'' && !name[3]) { | |
2182 *out = context->alt_regs[Z80_B] << 8 | context->alt_regs[Z80_C]; | |
957 } else { | 2183 } else { |
958 value = context->regs[Z80_B] << 8; | 2184 return 0; |
959 value |= context->regs[Z80_C]; | 2185 } |
960 } | |
961 } else if(param[1] == '\'') { | |
962 value = context->alt_regs[Z80_B]; | |
963 } else if(param[1] == 'a') { | |
964 value = context->bank_reg << 15; | |
965 } else { | |
966 value = context->regs[Z80_B]; | |
967 } | 2186 } |
968 break; | 2187 break; |
969 case 'c': | 2188 case 'c': |
970 if(param[1] == '\'') { | 2189 if (!name[1]) { |
971 value = context->alt_regs[Z80_C]; | 2190 *out = context->regs[Z80_C]; |
972 } else if(param[1] == 'y') { | 2191 } else if (name[1] == '\'' && !name[2]) { |
973 value = context->current_cycle; | 2192 *out = context->alt_regs[Z80_C]; |
974 } else { | 2193 } else { |
975 value = context->regs[Z80_C]; | 2194 return 0; |
976 } | 2195 } |
977 break; | 2196 break; |
978 case 'd': | 2197 case 'd': |
979 if (param[1] == 'e') { | 2198 if (!name[1]) { |
980 if(param[2] == '\'') { | 2199 *out = context->regs[Z80_D]; |
981 value = context->alt_regs[Z80_D] << 8; | 2200 } else if (name[1] == '\'' && !name[2]) { |
982 value |= context->alt_regs[Z80_E]; | 2201 *out = context->alt_regs[Z80_D]; |
2202 } else if (tolower(name[1]) == 'e') { | |
2203 if (!name[2]) { | |
2204 *out = context->regs[Z80_D] << 8 | context->regs[Z80_E]; | |
2205 } else if (name[2] == '\'' && !name[3]) { | |
2206 *out = context->alt_regs[Z80_D] << 8 | context->alt_regs[Z80_E]; | |
983 } else { | 2207 } else { |
984 value = context->regs[Z80_D] << 8; | 2208 return 0; |
985 value |= context->regs[Z80_E]; | 2209 } |
986 } | |
987 } else if(param[1] == '\'') { | |
988 value = context->alt_regs[Z80_D]; | |
989 } else { | |
990 value = context->regs[Z80_D]; | |
991 } | 2210 } |
992 break; | 2211 break; |
993 case 'e': | 2212 case 'e': |
994 if(param[1] == '\'') { | 2213 if (!name[1]) { |
995 value = context->alt_regs[Z80_E]; | 2214 *out = context->regs[Z80_E]; |
2215 } else if (name[1] == '\'' && !name[2]) { | |
2216 *out = context->alt_regs[Z80_E]; | |
996 } else { | 2217 } else { |
997 value = context->regs[Z80_E]; | 2218 return 0; |
998 } | 2219 } |
999 break; | 2220 break; |
1000 case 'f': | 2221 case 'f': |
1001 if(param[2] == '\'') { | 2222 if (!name[1]) { |
1002 value = context->alt_flags[ZF_S] << 7; | 2223 *out = context->flags[ZF_S] << 7; |
1003 value |= context->alt_flags[ZF_Z] << 6; | 2224 *out |= context->flags[ZF_Z] << 6; |
1004 value |= context->alt_flags[ZF_H] << 4; | 2225 *out |= context->flags[ZF_H] << 4; |
1005 value |= context->alt_flags[ZF_PV] << 2; | 2226 *out |= context->flags[ZF_PV] << 2; |
1006 value |= context->alt_flags[ZF_N] << 1; | 2227 *out |= context->flags[ZF_N] << 1; |
1007 value |= context->alt_flags[ZF_C]; | 2228 *out |= context->flags[ZF_C]; |
2229 } else if (name[1] == '\'' && !name[2]) { | |
2230 *out = context->alt_flags[ZF_S] << 7; | |
2231 *out |= context->alt_flags[ZF_Z] << 6; | |
2232 *out |= context->alt_flags[ZF_H] << 4; | |
2233 *out |= context->alt_flags[ZF_PV] << 2; | |
2234 *out |= context->alt_flags[ZF_N] << 1; | |
2235 *out |= context->alt_flags[ZF_C]; | |
1008 } else { | 2236 } else { |
1009 value = context->flags[ZF_S] << 7; | 2237 return 0; |
1010 value |= context->flags[ZF_Z] << 6; | |
1011 value |= context->flags[ZF_H] << 4; | |
1012 value |= context->flags[ZF_PV] << 2; | |
1013 value |= context->flags[ZF_N] << 1; | |
1014 value |= context->flags[ZF_C]; | |
1015 } | 2238 } |
1016 break; | 2239 break; |
1017 case 'h': | 2240 case 'h': |
1018 if (param[1] == 'l') { | 2241 if (!name[1]) { |
1019 if(param[2] == '\'') { | 2242 *out = context->regs[Z80_H]; |
1020 value = context->alt_regs[Z80_H] << 8; | 2243 } else if (name[1] == '\'' && !name[2]) { |
1021 value |= context->alt_regs[Z80_L]; | 2244 *out = context->alt_regs[Z80_H]; |
2245 } else if (tolower(name[1]) == 'e') { | |
2246 if (!name[2]) { | |
2247 *out = context->regs[Z80_H] << 8 | context->regs[Z80_L]; | |
2248 } else if (name[2] == '\'' && !name[3]) { | |
2249 *out = context->alt_regs[Z80_H] << 8 | context->alt_regs[Z80_L]; | |
1022 } else { | 2250 } else { |
1023 value = context->regs[Z80_H] << 8; | 2251 return 0; |
1024 value |= context->regs[Z80_L]; | 2252 } |
1025 } | 2253 } |
1026 } else if(param[1] == '\'') { | 2254 break; |
1027 value = context->alt_regs[Z80_H]; | 2255 case 'i': |
1028 } else { | 2256 switch (tolower(name[1])) |
1029 value = context->regs[Z80_H]; | 2257 { |
2258 case 0: | |
2259 *out = context->regs[Z80_I]; | |
2260 break; | |
2261 case 'f': | |
2262 if (name[2] != 'f' || name[3] < '1' || name[4]) { | |
2263 return 0; | |
2264 } | |
2265 if (name[3] == '1') { | |
2266 *out = context->iff1; | |
2267 } else if (name[3] == '2') { | |
2268 *out = context->iff2; | |
2269 } else { | |
2270 return 0; | |
2271 } | |
2272 break; | |
2273 case 'm': | |
2274 if (name[2]) { | |
2275 return 0; | |
2276 } | |
2277 *out = context->im; | |
2278 break; | |
2279 case 'n': | |
2280 if (strcasecmp(name +2, "t_cycle")) { | |
2281 return 0; | |
2282 } | |
2283 *out = context->int_cycle; | |
2284 break; | |
2285 case 'r': | |
2286 if (name[2]) { | |
2287 return 0; | |
2288 } | |
2289 *out = context->regs[Z80_I] << 8 | context->regs[Z80_R]; | |
2290 break; | |
2291 case 'x': | |
2292 switch (tolower(name[2])) | |
2293 { | |
2294 case 0: | |
2295 *out = context->regs[Z80_IXH] << 8 | context->regs[Z80_IXL]; | |
2296 break; | |
2297 case 'h': | |
2298 if (name[3]) { | |
2299 return 0; | |
2300 } | |
2301 *out = context->regs[Z80_IXH]; | |
2302 case 'l': | |
2303 if (name[3]) { | |
2304 return 0; | |
2305 } | |
2306 *out = context->regs[Z80_IXL]; | |
2307 default: | |
2308 return 0; | |
2309 } | |
2310 break; | |
2311 case 'y': | |
2312 switch (tolower(name[2])) | |
2313 { | |
2314 case 0: | |
2315 *out = context->regs[Z80_IYH] << 8 | context->regs[Z80_IYL]; | |
2316 break; | |
2317 case 'h': | |
2318 if (name[3]) { | |
2319 return 0; | |
2320 } | |
2321 *out = context->regs[Z80_IYH]; | |
2322 case 'l': | |
2323 if (name[3]) { | |
2324 return 0; | |
2325 } | |
2326 *out = context->regs[Z80_IYL]; | |
2327 default: | |
2328 return 0; | |
2329 } | |
2330 break; | |
2331 default: | |
2332 return 0; | |
1030 } | 2333 } |
1031 break; | 2334 break; |
1032 case 'l': | 2335 case 'l': |
1033 if(param[1] == '\'') { | 2336 if (!name[1]) { |
1034 value = context->alt_regs[Z80_L]; | 2337 *out = context->regs[Z80_L]; |
2338 } else if (name[1] == '\'' && !name[2]) { | |
2339 *out = context->alt_regs[Z80_L]; | |
1035 } else { | 2340 } else { |
1036 value = context->regs[Z80_L]; | 2341 return 0; |
2342 } | |
2343 break; | |
2344 case 'p': | |
2345 if (tolower(name[1]) != 'c' || name[2]) { | |
2346 return 0; | |
2347 } | |
2348 *out = root->address; | |
2349 break; | |
2350 case 'r': | |
2351 if (name[1]) { | |
2352 return 0; | |
2353 } | |
2354 *out = context->regs[Z80_R]; | |
2355 case 's': | |
2356 if (tolower(name[1]) != 'p' || name[2]) { | |
2357 return 0; | |
2358 } | |
2359 *out = context->sp; | |
2360 break; | |
2361 default: | |
2362 return 0; | |
2363 } | |
2364 return 1; | |
2365 } | |
2366 | |
2367 static uint8_t set_z80(debug_root *root, const char *name, uint32_t value) | |
2368 { | |
2369 z80_context *context = root->cpu_context; | |
2370 switch (tolower(name[0])) | |
2371 { | |
2372 case 'a': | |
2373 if (!name[1]) { | |
2374 context->regs[Z80_A] = value; | |
2375 } else if (name[1] == '\'' && !name[2]) { | |
2376 context->alt_regs[Z80_A] = value; | |
2377 } else if (tolower(name[1]) == 'f') { | |
2378 if (!name[2]) { | |
2379 context->regs[Z80_A] = value >> 8; | |
2380 context->flags[ZF_S] = value >> 7 & 1; | |
2381 context->flags[ZF_Z] = value >> 6 & 1; | |
2382 context->flags[ZF_H] = value >> 4 & 1; | |
2383 context->flags[ZF_PV] = value >> 2 & 1; | |
2384 context->flags[ZF_N] = value >> 1 & 1; | |
2385 context->flags[ZF_C] = value & 1; | |
2386 } else if (name[2] == '\'' && !name[3]) { | |
2387 context->alt_regs[Z80_A] = value >> 8; | |
2388 context->alt_flags[ZF_S] = value >> 7 & 1; | |
2389 context->alt_flags[ZF_Z] = value >> 6 & 1; | |
2390 context->alt_flags[ZF_H] = value >> 4 & 1; | |
2391 context->alt_flags[ZF_PV] = value >> 2 & 1; | |
2392 context->alt_flags[ZF_N] = value >> 1 & 1; | |
2393 context->alt_flags[ZF_C] = value & 1; | |
2394 } else { | |
2395 return 0; | |
2396 } | |
2397 } else { | |
2398 return 0; | |
2399 } | |
2400 break; | |
2401 case 'b': | |
2402 if (!name[1]) { | |
2403 context->regs[Z80_B] = value; | |
2404 } else if (name[1] == '\'' && !name[2]) { | |
2405 context->alt_regs[Z80_B] = value; | |
2406 } else if (tolower(name[1]) == 'c') { | |
2407 if (!name[2]) { | |
2408 context->regs[Z80_B] = value >> 8; | |
2409 context->regs[Z80_C] = value; | |
2410 } else if (name[2] == '\'' && !name[3]) { | |
2411 context->alt_regs[Z80_B] = value >> 8; | |
2412 context->alt_regs[Z80_C] = value; | |
2413 } else { | |
2414 return 0; | |
2415 } | |
2416 } | |
2417 break; | |
2418 case 'c': | |
2419 if (!name[1]) { | |
2420 context->regs[Z80_C] = value; | |
2421 } else if (name[1] == '\'' && !name[2]) { | |
2422 context->alt_regs[Z80_C] = value; | |
2423 } else { | |
2424 return 0; | |
2425 } | |
2426 break; | |
2427 case 'd': | |
2428 if (!name[1]) { | |
2429 context->regs[Z80_D] = value; | |
2430 } else if (name[1] == '\'' && !name[2]) { | |
2431 context->alt_regs[Z80_D] = value; | |
2432 } else if (tolower(name[1]) == 'e') { | |
2433 if (!name[2]) { | |
2434 context->regs[Z80_D] = value >> 8; | |
2435 context->regs[Z80_E] = value; | |
2436 } else if (name[2] == '\'' && !name[3]) { | |
2437 context->alt_regs[Z80_D] = value >> 8; | |
2438 context->alt_regs[Z80_E] = value; | |
2439 } else { | |
2440 return 0; | |
2441 } | |
2442 } | |
2443 break; | |
2444 case 'e': | |
2445 if (!name[1]) { | |
2446 context->regs[Z80_E] = value; | |
2447 } else if (name[1] == '\'' && !name[2]) { | |
2448 context->alt_regs[Z80_E] = value; | |
2449 } else { | |
2450 return 0; | |
2451 } | |
2452 break; | |
2453 case 'f': | |
2454 if (!name[1]) { | |
2455 context->flags[ZF_S] = value >> 7 & 1; | |
2456 context->flags[ZF_Z] = value >> 6 & 1; | |
2457 context->flags[ZF_H] = value >> 4 & 1; | |
2458 context->flags[ZF_PV] = value >> 2 & 1; | |
2459 context->flags[ZF_N] = value >> 1 & 1; | |
2460 context->flags[ZF_C] = value & 1; | |
2461 } else if (name[1] == '\'' && !name[2]) { | |
2462 context->alt_flags[ZF_S] = value >> 7 & 1; | |
2463 context->alt_flags[ZF_Z] = value >> 6 & 1; | |
2464 context->alt_flags[ZF_H] = value >> 4 & 1; | |
2465 context->alt_flags[ZF_PV] = value >> 2 & 1; | |
2466 context->alt_flags[ZF_N] = value >> 1 & 1; | |
2467 context->alt_flags[ZF_C] = value & 1; | |
2468 } else { | |
2469 return 0; | |
2470 } | |
2471 break; | |
2472 case 'h': | |
2473 if (!name[1]) { | |
2474 context->regs[Z80_H] = value; | |
2475 } else if (name[1] == '\'' && !name[2]) { | |
2476 context->alt_regs[Z80_H] = value; | |
2477 } else if (tolower(name[1]) == 'e') { | |
2478 if (!name[2]) { | |
2479 context->regs[Z80_H] = value >> 8; | |
2480 context->regs[Z80_L] = value; | |
2481 } else if (name[2] == '\'' && !name[3]) { | |
2482 context->alt_regs[Z80_H] = value >> 8; | |
2483 context->alt_regs[Z80_L] = value; | |
2484 } else { | |
2485 return 0; | |
2486 } | |
1037 } | 2487 } |
1038 break; | 2488 break; |
1039 case 'i': | 2489 case 'i': |
1040 if(param[1] == 'x') { | 2490 switch (tolower(name[1])) |
1041 if (param[2] == 'h') { | 2491 { |
1042 value = context->regs[Z80_IXH]; | 2492 case 0: |
1043 } else if(param[2] == 'l') { | 2493 context->regs[Z80_I] = value; |
1044 value = context->regs[Z80_IXL]; | 2494 break; |
2495 case 'f': | |
2496 if (name[2] != 'f' || name[3] < '1' || name[4]) { | |
2497 return 0; | |
2498 } | |
2499 if (name[3] == '1') { | |
2500 context->iff1 = value != 0; | |
2501 } else if (name[3] == '2') { | |
2502 context->iff2 = value != 0; | |
1045 } else { | 2503 } else { |
1046 value = context->regs[Z80_IXH] << 8; | 2504 return 0; |
1047 value |= context->regs[Z80_IXL]; | 2505 } |
1048 } | 2506 break; |
1049 } else if(param[1] == 'y') { | 2507 case 'm': |
1050 if (param[2] == 'h') { | 2508 if (name[2]) { |
1051 value = context->regs[Z80_IYH]; | 2509 return 0; |
1052 } else if(param[2] == 'l') { | 2510 } |
1053 value = context->regs[Z80_IYL]; | 2511 context->im = value & 3; |
1054 } else { | 2512 break; |
1055 value = context->regs[Z80_IYH] << 8; | 2513 case 'r': |
1056 value |= context->regs[Z80_IYL]; | 2514 if (name[2]) { |
1057 } | 2515 return 0; |
1058 } else if(param[1] == 'n') { | 2516 } |
1059 value = context->int_cycle; | 2517 context->regs[Z80_I] = value >> 8; |
1060 } else if(param[1] == 'f' && param[2] == 'f' && param[3] == '1') { | 2518 context->regs[Z80_R] = value; |
1061 value = context->iff1; | 2519 break; |
1062 } else if(param[1] == 'f' && param[2] == 'f' && param[3] == '2') { | 2520 case 'x': |
1063 value = context->iff2; | 2521 switch (tolower(name[2])) |
2522 { | |
2523 case 0: | |
2524 context->regs[Z80_IXH] = value >> 8; | |
2525 context->regs[Z80_IXL] = value; | |
2526 break; | |
2527 case 'h': | |
2528 if (name[3]) { | |
2529 return 0; | |
2530 } | |
2531 context->regs[Z80_IXH] = value; | |
2532 case 'l': | |
2533 if (name[3]) { | |
2534 return 0; | |
2535 } | |
2536 context->regs[Z80_IXL] = value; | |
2537 default: | |
2538 return 0; | |
2539 } | |
2540 break; | |
2541 case 'y': | |
2542 switch (tolower(name[2])) | |
2543 { | |
2544 case 0: | |
2545 context->regs[Z80_IYH] = value >> 8; | |
2546 context->regs[Z80_IYL] = value; | |
2547 break; | |
2548 case 'h': | |
2549 if (name[3]) { | |
2550 return 0; | |
2551 } | |
2552 context->regs[Z80_IYH] = value; | |
2553 case 'l': | |
2554 if (name[3]) { | |
2555 return 0; | |
2556 } | |
2557 context->regs[Z80_IYL] = value; | |
2558 default: | |
2559 return 0; | |
2560 } | |
2561 break; | |
2562 default: | |
2563 return 0; | |
2564 } | |
2565 break; | |
2566 case 'l': | |
2567 if (!name[1]) { | |
2568 context->regs[Z80_L] = value; | |
2569 } else if (name[1] == '\'' && !name[2]) { | |
2570 context->alt_regs[Z80_L] = value; | |
1064 } else { | 2571 } else { |
1065 value = context->im; | 2572 return 0; |
1066 } | 2573 } |
1067 break; | 2574 break; |
1068 #endif | 2575 case 'r': |
2576 if (name[1]) { | |
2577 return 0; | |
2578 } | |
2579 context->regs[Z80_R] = value; | |
1069 case 's': | 2580 case 's': |
1070 if (param[1] == 'p') { | 2581 if (tolower(name[1]) != 'p' || name[2]) { |
1071 value = context->sp; | 2582 return 0; |
1072 } | 2583 } |
2584 context->sp = value; | |
1073 break; | 2585 break; |
1074 case '0': | 2586 default: |
1075 if (param[1] == 'x') { | 2587 return 0; |
1076 uint16_t p_addr = strtol(param+2, NULL, 16); | 2588 } |
1077 value = read_byte(p_addr, (void **)context->mem_pointers, &context->options->gen, context); | 2589 return 1; |
1078 } | 2590 } |
1079 break; | 2591 |
1080 } | 2592 debug_root *find_z80_root(z80_context *context) |
1081 printf(format, param, value); | 2593 { |
2594 debug_root *root = find_root(context); | |
2595 if (root && !root->commands) { | |
2596 add_commands(root, common_commands, NUM_COMMON); | |
2597 add_commands(root, z80_commands, NUM_Z80); | |
2598 root->read_mem = read_z80; | |
2599 root->write_mem = write_z80; | |
2600 root->set = set_z80; | |
2601 root->resolve = resolve_z80; | |
2602 } | |
2603 return root; | |
1082 } | 2604 } |
1083 | 2605 |
1084 z80_context * zdebugger(z80_context * context, uint16_t address) | 2606 z80_context * zdebugger(z80_context * context, uint16_t address) |
1085 { | 2607 { |
1086 static char last_cmd[1024]; | 2608 static char last_cmd[1024]; |
1087 char input_buf[1024]; | 2609 char input_buf[1024]; |
1088 z80inst inst; | 2610 z80inst inst; |
1089 genesis_context *system = context->system; | 2611 genesis_context *system = context->system; |
1090 init_terminal(); | 2612 init_terminal(); |
1091 //Check if this is a user set breakpoint, or just a temporary one | |
1092 debug_root *root = find_root(context); | 2613 debug_root *root = find_root(context); |
1093 if (!root) { | 2614 if (!root) { |
1094 return context; | 2615 return context; |
1095 } | 2616 } |
2617 //Check if this is a user set breakpoint, or just a temporary one | |
1096 bp_def ** this_bp = find_breakpoint(&root->breakpoints, address); | 2618 bp_def ** this_bp = find_breakpoint(&root->breakpoints, address); |
1097 if (*this_bp) { | 2619 if (*this_bp) { |
1098 printf("Z80 Breakpoint %d hit\n", (*this_bp)->index); | 2620 printf("Z80 Breakpoint %d hit\n", (*this_bp)->index); |
1099 } else { | 2621 } else { |
1100 zremove_breakpoint(context, address); | 2622 zremove_breakpoint(context, address); |
1102 uint8_t * pc = get_native_pointer(address, (void **)context->mem_pointers, &context->Z80_OPTS->gen); | 2624 uint8_t * pc = get_native_pointer(address, (void **)context->mem_pointers, &context->Z80_OPTS->gen); |
1103 if (!pc) { | 2625 if (!pc) { |
1104 fatal_error("Failed to get native pointer on entering Z80 debugger at address %X\n", address); | 2626 fatal_error("Failed to get native pointer on entering Z80 debugger at address %X\n", address); |
1105 } | 2627 } |
1106 for (disp_def * cur = root->displays; cur; cur = cur->next) { | 2628 for (disp_def * cur = root->displays; cur; cur = cur->next) { |
1107 zdebugger_print(context, cur->format_char, cur->param); | 2629 cmd_print(root, cur->format, cur->num_args, cur->args); |
1108 } | 2630 } |
1109 uint8_t * after_pc = z80_decode(pc, &inst); | 2631 uint8_t * after_pc = z80_decode(pc, &inst); |
1110 z80_disasm(&inst, input_buf, address); | 2632 z80_disasm(&inst, input_buf, address); |
1111 printf("%X:\t%s\n", address, input_buf); | 2633 printf("%X:\t%s\n", address, input_buf); |
1112 uint16_t after = address + (after_pc-pc); | 2634 uint16_t after = address + (after_pc-pc); |
2635 root->address = address; | |
2636 root->after = after; | |
2637 root->inst = &inst; | |
1113 int debugging = 1; | 2638 int debugging = 1; |
1114 while(debugging) { | 2639 while(debugging) { |
1115 fputs(">", stdout); | 2640 fputs(">", stdout); |
1116 if (!fgets(input_buf, sizeof(input_buf), stdin)) { | 2641 if (!fgets(input_buf, sizeof(input_buf), stdin)) { |
1117 fputs("fgets failed", stderr); | 2642 fputs("fgets failed", stderr); |
1122 if (input_buf[0]) { | 2647 if (input_buf[0]) { |
1123 strcpy(last_cmd, input_buf); | 2648 strcpy(last_cmd, input_buf); |
1124 } else { | 2649 } else { |
1125 strcpy(input_buf, last_cmd); | 2650 strcpy(input_buf, last_cmd); |
1126 } | 2651 } |
1127 char * param; | 2652 parsed_command cmd; |
1128 char format[8]; | 2653 if (parse_command(root, input_buf, &cmd)) { |
1129 uint32_t value; | 2654 debugging = run_command(root, &cmd); |
1130 bp_def * new_bp; | 2655 free_parsed_command(&cmd); |
1131 switch(input_buf[0]) | 2656 } |
1132 { | 2657 } |
1133 case 'a': | 2658 return context; |
1134 param = find_param(input_buf); | 2659 } |
1135 if (!param) { | 2660 |
1136 fputs("a command requires a parameter\n", stderr); | |
1137 break; | |
1138 } | |
1139 value = strtol(param, NULL, 16); | |
1140 zinsert_breakpoint(context, value, (uint8_t *)zdebugger); | |
1141 debugging = 0; | |
1142 break; | |
1143 case 'b': | |
1144 param = find_param(input_buf); | |
1145 if (!param) { | |
1146 fputs("b command requires a parameter\n", stderr); | |
1147 break; | |
1148 } | |
1149 value = strtol(param, NULL, 16); | |
1150 zinsert_breakpoint(context, value, (uint8_t *)zdebugger); | |
1151 new_bp = malloc(sizeof(bp_def)); | |
1152 new_bp->next = root->breakpoints; | |
1153 new_bp->address = value; | |
1154 new_bp->index = root->bp_index++; | |
1155 new_bp->commands = NULL; | |
1156 root->breakpoints = new_bp; | |
1157 printf("Z80 Breakpoint %d set at %X\n", new_bp->index, value); | |
1158 break; | |
1159 case 'c': | |
1160 puts("Continuing"); | |
1161 debugging = 0; | |
1162 break; | |
1163 case 'd': | |
1164 if (input_buf[1] == 'i') { | |
1165 char format_char = 0; | |
1166 for(int i = 2; input_buf[i] != 0 && input_buf[i] != ' '; i++) { | |
1167 if (input_buf[i] == '/') { | |
1168 format_char = input_buf[i+1]; | |
1169 break; | |
1170 } | |
1171 } | |
1172 param = find_param(input_buf); | |
1173 if (!param) { | |
1174 fputs("display command requires a parameter\n", stderr); | |
1175 break; | |
1176 } | |
1177 zdebugger_print(context, format_char, param); | |
1178 add_display(&root->displays, &root->disp_index, format_char, param); | |
1179 } else if (input_buf[1] == 'e' || input_buf[1] == ' ') { | |
1180 param = find_param(input_buf); | |
1181 if (!param) { | |
1182 fputs("delete command requires a parameter\n", stderr); | |
1183 break; | |
1184 } | |
1185 if (param[0] >= '0' && param[0] <= '9') { | |
1186 value = atoi(param); | |
1187 this_bp = find_breakpoint_idx(&root->breakpoints, value); | |
1188 if (!*this_bp) { | |
1189 fprintf(stderr, "Breakpoint %d does not exist\n", value); | |
1190 break; | |
1191 } | |
1192 new_bp = *this_bp; | |
1193 zremove_breakpoint(context, new_bp->address); | |
1194 *this_bp = new_bp->next; | |
1195 free(new_bp); | |
1196 } else if (param[0] == 'd') { | |
1197 param = find_param(param); | |
1198 if (!param) { | |
1199 fputs("delete display command requires a parameter\n", stderr); | |
1200 break; | |
1201 } | |
1202 remove_display(&root->displays, atoi(param)); | |
1203 } | |
1204 } | |
1205 break; | |
1206 case 'n': | |
1207 //TODO: Handle conditional branch instructions | |
1208 if (inst.op == Z80_JP) { | |
1209 if (inst.addr_mode == Z80_IMMED) { | |
1210 after = inst.immed; | |
1211 } else if (inst.ea_reg == Z80_HL) { | |
1212 #ifndef NEW_CORE | |
1213 after = context->regs[Z80_H] << 8 | context->regs[Z80_L]; | |
1214 } else if (inst.ea_reg == Z80_IX) { | |
1215 after = context->regs[Z80_IXH] << 8 | context->regs[Z80_IXL]; | |
1216 } else if (inst.ea_reg == Z80_IY) { | |
1217 after = context->regs[Z80_IYH] << 8 | context->regs[Z80_IYL]; | |
1218 #endif | 2661 #endif |
1219 } | |
1220 } else if(inst.op == Z80_JR) { | |
1221 after += inst.immed; | |
1222 } else if(inst.op == Z80_RET) { | |
1223 uint8_t *sp = get_native_pointer(context->sp, (void **)context->mem_pointers, &context->Z80_OPTS->gen); | |
1224 if (sp) { | |
1225 after = *sp; | |
1226 sp = get_native_pointer((context->sp + 1) & 0xFFFF, (void **)context->mem_pointers, &context->Z80_OPTS->gen); | |
1227 if (sp) { | |
1228 after |= *sp << 8; | |
1229 } | |
1230 } | |
1231 } | |
1232 zinsert_breakpoint(context, after, (uint8_t *)zdebugger); | |
1233 debugging = 0; | |
1234 break; | |
1235 case 'p': | |
1236 param = find_param(input_buf); | |
1237 if (!param) { | |
1238 fputs("p command requires a parameter\n", stderr); | |
1239 break; | |
1240 } | |
1241 zdebugger_print(context, input_buf[1] == '/' ? input_buf[2] : 0, param); | |
1242 break; | |
1243 case 'q': | |
1244 puts("Quitting"); | |
1245 exit(0); | |
1246 break; | |
1247 case 's': { | |
1248 param = find_param(input_buf); | |
1249 if (!param) { | |
1250 fputs("s command requires a file name\n", stderr); | |
1251 break; | |
1252 } | |
1253 memmap_chunk const *ram_chunk = NULL; | |
1254 for (int i = 0; i < context->Z80_OPTS->gen.memmap_chunks; i++) | |
1255 { | |
1256 memmap_chunk const *cur = context->Z80_OPTS->gen.memmap + i; | |
1257 if (cur->flags & MMAP_WRITE) { | |
1258 ram_chunk = cur; | |
1259 break; | |
1260 } | |
1261 } | |
1262 if (ram_chunk) { | |
1263 uint32_t size = ram_chunk->end - ram_chunk->start; | |
1264 if (size > ram_chunk->mask) { | |
1265 size = ram_chunk->mask+1; | |
1266 } | |
1267 uint8_t *buf = get_native_pointer(ram_chunk->start, (void **)context->mem_pointers, &context->Z80_OPTS->gen); | |
1268 FILE * f = fopen(param, "wb"); | |
1269 if (f) { | |
1270 if(fwrite(buf, 1, size, f) != size) { | |
1271 fputs("Error writing file\n", stderr); | |
1272 } | |
1273 fclose(f); | |
1274 printf("Wrote %d bytes to %s\n", size, param); | |
1275 } else { | |
1276 fprintf(stderr, "Could not open %s for writing\n", param); | |
1277 } | |
1278 } else { | |
1279 fputs("Failed to find a RAM memory chunk\n", stderr); | |
1280 } | |
1281 break; | |
1282 } | |
1283 case '?': | |
1284 print_z80_help(); | |
1285 break; | |
1286 default: | |
1287 if ( | |
1288 !context->Z80_OPTS->gen.debug_cmd_handler | |
1289 || !context->Z80_OPTS->gen.debug_cmd_handler(&system->header, input_buf) | |
1290 ) { | |
1291 fprintf(stderr, "Unrecognized debugger command %s\nUse '?' for help.\n", input_buf); | |
1292 } | |
1293 break; | |
1294 } | |
1295 } | |
1296 return context; | |
1297 } | |
1298 | |
1299 #endif | |
1300 | |
1301 int run_debugger_command(m68k_context *context, uint32_t address, char *input_buf, m68kinst inst, uint32_t after); | |
1302 int run_genesis_debugger_command(m68k_context *context, uint32_t address, char *input_buf) | |
1303 { | |
1304 genesis_context * gen = context->system; | |
1305 char *param; | |
1306 uint32_t value; | |
1307 bp_def *new_bp; | |
1308 switch (input_buf[0]) | |
1309 { | |
1310 case 'v': | |
1311 //VDP debug commands | |
1312 switch(input_buf[1]) | |
1313 { | |
1314 case 's': | |
1315 vdp_print_sprite_table(gen->vdp); | |
1316 break; | |
1317 case 'r': | |
1318 vdp_print_reg_explain(gen->vdp); | |
1319 break; | |
1320 } | |
1321 break; | |
1322 case 'y': | |
1323 //YM-2612 debug commands | |
1324 switch(input_buf[1]) | |
1325 { | |
1326 case 'c': | |
1327 if (input_buf[2] == ' ') { | |
1328 int channel = atoi(input_buf+3)-1; | |
1329 ym_print_channel_info(gen->ym, channel); | |
1330 } else { | |
1331 for (int i = 0; i < 6; i++) { | |
1332 ym_print_channel_info(gen->ym, i); | |
1333 } | |
1334 } | |
1335 break; | |
1336 case 't': | |
1337 ym_print_timer_info(gen->ym); | |
1338 break; | |
1339 } | |
1340 break; | |
1341 case 'u': | |
1342 if (gen->expansion) { | |
1343 segacd_context *cd = gen->expansion; | |
1344 if (input_buf[1]) { | |
1345 //TODO: filter out commands that are unsafe to run when we don't have the current Sub CPU address | |
1346 run_debugger_command(cd->m68k, 0, input_buf + 1, (m68kinst){}, 0); | |
1347 } else { | |
1348 cd->enter_debugger = 1; | |
1349 return 0; | |
1350 } | |
1351 } else { | |
1352 fputs("u command only valid when Sega/Mega CD is active\n", stderr); | |
1353 } | |
1354 break; | |
1355 #ifndef NO_Z80 | |
1356 case 'z': | |
1357 //Z80 debug commands | |
1358 switch(input_buf[1]) | |
1359 { | |
1360 case 'b': { | |
1361 param = find_param(input_buf); | |
1362 if (!param) { | |
1363 fputs("zb command requires a parameter\n", stderr); | |
1364 break; | |
1365 } | |
1366 value = strtol(param, NULL, 16); | |
1367 debug_root *zroot = find_root(gen->z80); | |
1368 zinsert_breakpoint(gen->z80, value, (uint8_t *)zdebugger); | |
1369 new_bp = malloc(sizeof(bp_def)); | |
1370 new_bp->next = zroot->breakpoints; | |
1371 new_bp->address = value; | |
1372 new_bp->index = zroot->bp_index++; | |
1373 zroot->breakpoints = new_bp; | |
1374 printf("Z80 Breakpoint %d set at %X\n", new_bp->index, value); | |
1375 break; | |
1376 } | |
1377 case 'p': | |
1378 param = find_param(input_buf); | |
1379 if (!param) { | |
1380 fputs("zp command requires a parameter\n", stderr); | |
1381 break; | |
1382 } | |
1383 zdebugger_print(gen->z80, input_buf[2] == '/' ? input_buf[3] : 0, param); | |
1384 } | |
1385 break; | |
1386 #endif | |
1387 default: | |
1388 fprintf(stderr, "Unrecognized debugger command %s\nUse '?' for help.\n", input_buf); | |
1389 break; | |
1390 } | |
1391 return 1; | |
1392 } | |
1393 | |
1394 int run_subcpu_debugger_command(m68k_context *context, uint32_t address, char *input_buf) | |
1395 { | |
1396 segacd_context *cd = context->system; | |
1397 switch (input_buf[0]) | |
1398 { | |
1399 case 'm': | |
1400 if (input_buf[1]) { | |
1401 //TODO: filter out commands that are unsafe to run when we don't have the current Main CPU address | |
1402 return run_debugger_command(cd->genesis->m68k, 0, input_buf + 1, (m68kinst){}, 0); | |
1403 } else { | |
1404 cd->genesis->header.enter_debugger = 1; | |
1405 return 0; | |
1406 } | |
1407 break; | |
1408 default: | |
1409 fprintf(stderr, "Unrecognized debugger command %s\nUse '?' for help.\n", input_buf); | |
1410 break; | |
1411 } | |
1412 return 1; | |
1413 } | |
1414 | |
1415 int run_debugger_command(m68k_context *context, uint32_t address, char *input_buf, m68kinst inst, uint32_t after) | |
1416 { | |
1417 char * param; | |
1418 char format_char; | |
1419 genesis_context *system = context->system; | |
1420 uint32_t value; | |
1421 bp_def *new_bp, **this_bp; | |
1422 debug_root *root = find_root(context); | |
1423 if (!root) { | |
1424 return 0; | |
1425 } | |
1426 root->address = address; | |
1427 switch(input_buf[0]) | |
1428 { | |
1429 case 'c': | |
1430 if (input_buf[1] == 0 || input_buf[1] == 'o' && input_buf[2] == 'n') | |
1431 { | |
1432 puts("Continuing"); | |
1433 return 0; | |
1434 } else if (input_buf[1] == 'o' && input_buf[2] == 'm') { | |
1435 param = find_param(input_buf); | |
1436 if (!param) { | |
1437 fputs("com command requires a parameter\n", stderr); | |
1438 break; | |
1439 } | |
1440 bp_def **target = find_breakpoint_idx(&root->breakpoints, atoi(param)); | |
1441 if (!target) { | |
1442 fprintf(stderr, "Breakpoint %s does not exist!\n", param); | |
1443 break; | |
1444 } | |
1445 printf("Enter commands for breakpoing %d, type end when done\n", atoi(param)); | |
1446 char cmd_buf[1024]; | |
1447 char *commands = NULL; | |
1448 for (;;) | |
1449 { | |
1450 fputs(">>", stdout); | |
1451 fflush(stdout); | |
1452 fgets(cmd_buf, sizeof(cmd_buf), stdin); | |
1453 if (strcmp(cmd_buf, "end\n")) { | |
1454 if (commands) { | |
1455 char *tmp = commands; | |
1456 commands = alloc_concat(commands, cmd_buf); | |
1457 free(tmp); | |
1458 } else { | |
1459 commands = strdup(cmd_buf); | |
1460 } | |
1461 } else { | |
1462 break; | |
1463 } | |
1464 } | |
1465 (*target)->commands = commands; | |
1466 } else { | |
1467 } | |
1468 break; | |
1469 case 'b': | |
1470 if (input_buf[1] == 't') { | |
1471 uint32_t stack = context->aregs[7]; | |
1472 uint8_t non_adr_count = 0; | |
1473 do { | |
1474 uint32_t bt_address = m68k_instruction_fetch(stack, context); | |
1475 bt_address = get_instruction_start(context->options, bt_address - 2); | |
1476 if (bt_address) { | |
1477 stack += 4; | |
1478 non_adr_count = 0; | |
1479 m68k_decode(m68k_instruction_fetch, context, &inst, bt_address); | |
1480 m68k_disasm(&inst, input_buf); | |
1481 printf("%X: %s\n", bt_address, input_buf); | |
1482 } else { | |
1483 //non-return address value on stack can be word wide | |
1484 stack += 2; | |
1485 non_adr_count++; | |
1486 } | |
1487 //TODO: Make sure we don't wander into an invalid memory region | |
1488 } while (stack && non_adr_count < 6); | |
1489 } else { | |
1490 param = find_param(input_buf); | |
1491 if (!param) { | |
1492 fputs("b command requires a parameter\n", stderr); | |
1493 break; | |
1494 } | |
1495 value = strtol(param, NULL, 16); | |
1496 insert_breakpoint(context, value, debugger); | |
1497 new_bp = malloc(sizeof(bp_def)); | |
1498 new_bp->next = root->breakpoints; | |
1499 new_bp->address = value; | |
1500 new_bp->index = root->bp_index++; | |
1501 new_bp->commands = NULL; | |
1502 root->breakpoints = new_bp; | |
1503 printf("68K Breakpoint %d set at %X\n", new_bp->index, value); | |
1504 } | |
1505 break; | |
1506 case 'a': | |
1507 param = find_param(input_buf); | |
1508 if (!param) { | |
1509 fputs("a command requires a parameter\n", stderr); | |
1510 break; | |
1511 } | |
1512 value = strtol(param, NULL, 16); | |
1513 insert_breakpoint(context, value, debugger); | |
1514 return 0; | |
1515 case 'd': | |
1516 if (input_buf[1] == 'i') { | |
1517 format_char = 0; | |
1518 for(int i = 2; input_buf[i] != 0 && input_buf[i] != ' '; i++) { | |
1519 if (input_buf[i] == '/') { | |
1520 format_char = input_buf[i+1]; | |
1521 break; | |
1522 } | |
1523 } | |
1524 param = find_param(input_buf); | |
1525 if (!param) { | |
1526 fputs("display command requires a parameter\n", stderr); | |
1527 break; | |
1528 } | |
1529 debugger_print(root, format_char, param); | |
1530 add_display(&root->displays, &root->disp_index, format_char, param); | |
1531 } else { | |
1532 param = find_param(input_buf); | |
1533 if (!param) { | |
1534 fputs("d command requires a parameter\n", stderr); | |
1535 break; | |
1536 } | |
1537 value = atoi(param); | |
1538 this_bp = find_breakpoint_idx(&root->breakpoints, value); | |
1539 if (!*this_bp) { | |
1540 fprintf(stderr, "Breakpoint %d does not exist\n", value); | |
1541 break; | |
1542 } | |
1543 new_bp = *this_bp; | |
1544 *this_bp = (*this_bp)->next; | |
1545 if (new_bp->commands) { | |
1546 free(new_bp->commands); | |
1547 } | |
1548 free(new_bp); | |
1549 } | |
1550 break; | |
1551 case 'p': | |
1552 format_char = 0; | |
1553 for(int i = 1; input_buf[i] != 0 && input_buf[i] != ' '; i++) { | |
1554 if (input_buf[i] == '/') { | |
1555 format_char = input_buf[i+1]; | |
1556 break; | |
1557 } | |
1558 } | |
1559 param = find_param(input_buf); | |
1560 if (param) { | |
1561 debugger_print(root, format_char, param); | |
1562 } else { | |
1563 m68k_disasm(&inst, input_buf); | |
1564 printf("%X: %s\n", address, input_buf); | |
1565 } | |
1566 | |
1567 break; | |
1568 case 'n': | |
1569 if (inst.op == M68K_RTS) { | |
1570 after = m68k_read_long(context->aregs[7], context); | |
1571 } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) { | |
1572 after = m68k_read_long(context->aregs[7] + 2, context); | |
1573 } else if(m68k_is_noncall_branch(&inst)) { | |
1574 if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) { | |
1575 root->branch_f = after; | |
1576 root->branch_t = m68k_branch_target(&inst, context->dregs, context->aregs); | |
1577 insert_breakpoint(context, root->branch_t, debugger); | |
1578 } else if(inst.op == M68K_DBCC) { | |
1579 if ( inst.extra.cond == COND_FALSE) { | |
1580 if (context->dregs[inst.dst.params.regs.pri] & 0xFFFF) { | |
1581 after = m68k_branch_target(&inst, context->dregs, context->aregs); | |
1582 } | |
1583 } else { | |
1584 root->branch_t = after; | |
1585 root->branch_f = m68k_branch_target(&inst, context->dregs, context->aregs); | |
1586 insert_breakpoint(context, root->branch_f, debugger); | |
1587 } | |
1588 } else { | |
1589 after = m68k_branch_target(&inst, context->dregs, context->aregs); | |
1590 } | |
1591 } | |
1592 insert_breakpoint(context, after, debugger); | |
1593 return 0; | |
1594 case 'o': | |
1595 if (inst.op == M68K_RTS) { | |
1596 after = m68k_read_long(context->aregs[7], context); | |
1597 } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) { | |
1598 after = m68k_read_long(context->aregs[7] + 2, context); | |
1599 } else if(m68k_is_noncall_branch(&inst)) { | |
1600 if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) { | |
1601 root->branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; | |
1602 if (root->branch_t < after) { | |
1603 root->branch_t = 0; | |
1604 } else { | |
1605 root->branch_f = after; | |
1606 insert_breakpoint(context, root->branch_t, debugger); | |
1607 } | |
1608 } else if(inst.op == M68K_DBCC) { | |
1609 uint32_t target = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; | |
1610 if (target > after) { | |
1611 if (inst.extra.cond == COND_FALSE) { | |
1612 after = target; | |
1613 } else { | |
1614 root->branch_f = target; | |
1615 root->branch_t = after; | |
1616 insert_breakpoint(context, root->branch_f, debugger); | |
1617 } | |
1618 } | |
1619 } else { | |
1620 after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; | |
1621 } | |
1622 } | |
1623 insert_breakpoint(context, after, debugger); | |
1624 return 0; | |
1625 case 's': | |
1626 if (input_buf[1] == 'e') { | |
1627 param = find_param(input_buf); | |
1628 if (!param) { | |
1629 fputs("Missing destination parameter for set\n", stderr); | |
1630 return 1; | |
1631 } | |
1632 char *val = find_param(param); | |
1633 if (!val) { | |
1634 fputs("Missing value parameter for set\n", stderr); | |
1635 return 1; | |
1636 } | |
1637 long int_val; | |
1638 int reg_num; | |
1639 switch (val[0]) | |
1640 { | |
1641 case 'd': | |
1642 case 'a': | |
1643 reg_num = val[1] - '0'; | |
1644 if (reg_num < 0 || reg_num > 8) { | |
1645 fprintf(stderr, "Invalid register %s\n", val); | |
1646 return 1; | |
1647 } | |
1648 int_val = (val[0] == 'd' ? context->dregs : context->aregs)[reg_num]; | |
1649 break; | |
1650 case '$': | |
1651 int_val = strtol(val+1, NULL, 16); | |
1652 break; | |
1653 case '0': | |
1654 if (val[1] == 'x') { | |
1655 int_val = strtol(val+2, NULL, 16); | |
1656 break; | |
1657 } | |
1658 default: | |
1659 int_val = strtol(val, NULL, 10); | |
1660 } | |
1661 switch(param[0]) | |
1662 { | |
1663 case 'd': | |
1664 case 'a': | |
1665 reg_num = param[1] - '0'; | |
1666 if (reg_num < 0 || reg_num > 8) { | |
1667 fprintf(stderr, "Invalid register %s\n", param); | |
1668 return 1; | |
1669 } | |
1670 (param[0] == 'd' ? context->dregs : context->aregs)[reg_num] = int_val; | |
1671 break; | |
1672 default: | |
1673 fprintf(stderr, "Invalid destinatino %s\n", param); | |
1674 } | |
1675 break; | |
1676 } else if (input_buf[1] == 'r') { | |
1677 system->header.soft_reset(&system->header); | |
1678 return 0; | |
1679 } else { | |
1680 if (inst.op == M68K_RTS) { | |
1681 after = m68k_read_long(context->aregs[7], context); | |
1682 } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) { | |
1683 after = m68k_read_long(context->aregs[7] + 2, context); | |
1684 } else if(m68k_is_branch(&inst)) { | |
1685 if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) { | |
1686 root->branch_f = after; | |
1687 root->branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; | |
1688 insert_breakpoint(context, root->branch_t, debugger); | |
1689 } else if(inst.op == M68K_DBCC) { | |
1690 if (inst.extra.cond == COND_FALSE) { | |
1691 if (context->dregs[inst.dst.params.regs.pri] & 0xFFFF) { | |
1692 after = m68k_branch_target(&inst, context->dregs, context->aregs); | |
1693 } | |
1694 } else { | |
1695 root->branch_t = after; | |
1696 root->branch_f = m68k_branch_target(&inst, context->dregs, context->aregs); | |
1697 insert_breakpoint(context, root->branch_f, debugger); | |
1698 } | |
1699 } else { | |
1700 after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; | |
1701 } | |
1702 } | |
1703 insert_breakpoint(context, after, debugger); | |
1704 return 0; | |
1705 } | |
1706 case '?': | |
1707 print_m68k_help(); | |
1708 break; | |
1709 case 'q': | |
1710 puts("Quitting"); | |
1711 exit(0); | |
1712 break; | |
1713 default: { | |
1714 if (context->system == current_system) { | |
1715 //primary 68K for current system | |
1716 return run_genesis_debugger_command(context, address, input_buf); | |
1717 } else { | |
1718 //presumably Sega CD sub CPU | |
1719 //TODO: consider making this more generic | |
1720 return run_subcpu_debugger_command(context, address, input_buf); | |
1721 } | |
1722 break; | |
1723 } | |
1724 } | |
1725 return 1; | |
1726 } | |
1727 | |
1728 void print_m68k_help() | |
1729 { | |
1730 printf("M68k Debugger Commands\n"); | |
1731 printf(" b ADDRESS - Set a breakpoint at ADDRESS\n"); | |
1732 printf(" d BREAKPOINT - Delete a 68K breakpoint\n"); | |
1733 printf(" co BREAKPOINT - Run a list of debugger commands each time\n"); | |
1734 printf(" BREAKPOINT is hit\n"); | |
1735 printf(" a ADDRESS - Advance to address\n"); | |
1736 printf(" n - Advance to next instruction\n"); | |
1737 printf(" o - Advance to next instruction ignoring branches to\n"); | |
1738 printf(" lower addresses (good for breaking out of loops)\n"); | |
1739 printf(" s - Advance to next instruction (follows bsr/jsr)\n"); | |
1740 printf(" se REG|ADDRESS VALUE - Set value\n"); | |
1741 printf(" sr - Soft reset\n"); | |
1742 printf(" c - Continue\n"); | |
1743 printf(" bt - Print a backtrace\n"); | |
1744 printf(" p[/(x|X|d|c)] VALUE - Print a register or memory location\n"); | |
1745 printf(" di[/(x|X|d|c)] VALUE - Print a register or memory location each time\n"); | |
1746 printf(" a breakpoint is hit\n"); | |
1747 printf(" vs - Print VDP sprite list\n"); | |
1748 printf(" vr - Print VDP register info\n"); | |
1749 printf(" yc [CHANNEL NUM] - Print YM-2612 channel info\n"); | |
1750 printf(" yt - Print YM-2612 timer info\n"); | |
1751 printf(" zb ADDRESS - Set a Z80 breakpoint\n"); | |
1752 printf(" zp[/(x|X|d|c)] VALUE - Display a Z80 value\n"); | |
1753 printf(" ? - Display help\n"); | |
1754 printf(" q - Quit BlastEm\n"); | |
1755 } | |
1756 | |
1757 void print_z80_help() | |
1758 { | |
1759 printf("Z80 Debugger Commands\n"); | |
1760 printf(" b ADDRESS - Set a breakpoint at ADDRESS\n"); | |
1761 printf(" de BREAKPOINT - Delete a Z80 breakpoint\n"); | |
1762 printf(" a ADDRESS - Advance to address\n"); | |
1763 printf(" n - Advance to next instruction\n"); | |
1764 printf(" c - Continue\n"); | |
1765 printf(" p[/(x|X|d|c)] VALUE - Print a register or memory location\n"); | |
1766 printf(" di[/(x|X|d|c)] VALUE - Print a register or memory location each time\n"); | |
1767 printf(" a breakpoint is hit\n"); | |
1768 printf(" q - Quit BlastEm\n"); | |
1769 } | |
1770 | 2662 |
1771 void debugger(m68k_context * context, uint32_t address) | 2663 void debugger(m68k_context * context, uint32_t address) |
1772 { | 2664 { |
1773 static char last_cmd[1024]; | 2665 static char last_cmd[1024]; |
1774 char input_buf[1024]; | 2666 char input_buf[1024]; |
1779 context->options->sync_components(context, 0); | 2671 context->options->sync_components(context, 0); |
1780 if (context->system == current_system) { | 2672 if (context->system == current_system) { |
1781 genesis_context *gen = context->system; | 2673 genesis_context *gen = context->system; |
1782 vdp_force_update_framebuffer(gen->vdp); | 2674 vdp_force_update_framebuffer(gen->vdp); |
1783 } | 2675 } |
1784 debug_root *root = find_root(context); | 2676 debug_root *root = find_m68k_root(context); |
1785 if (!root) { | 2677 if (!root) { |
1786 return; | 2678 return; |
1787 } | 2679 } |
1788 //probably not necessary, but let's play it safe | 2680 //probably not necessary, but let's play it safe |
1789 address &= 0xFFFFFF; | 2681 address &= 0xFFFFFF; |
1800 } | 2692 } |
1801 root->branch_t = root->branch_f = 0; | 2693 root->branch_t = root->branch_f = 0; |
1802 } | 2694 } |
1803 | 2695 |
1804 uint32_t after = m68k_decode(m68k_instruction_fetch, context, &inst, address); | 2696 uint32_t after = m68k_decode(m68k_instruction_fetch, context, &inst, address); |
2697 root->address = address; | |
2698 root->after = after; | |
2699 root->inst = &inst; | |
1805 int debugging = 1; | 2700 int debugging = 1; |
1806 //Check if this is a user set breakpoint, or just a temporary one | 2701 //Check if this is a user set breakpoint, or just a temporary one |
1807 bp_def ** this_bp = find_breakpoint(&root->breakpoints, address); | 2702 bp_def ** this_bp = find_breakpoint(&root->breakpoints, address); |
1808 if (*this_bp) { | 2703 if (*this_bp) { |
1809 | 2704 for (uint32_t i = 0; debugging && i < (*this_bp)->num_commands; i++) |
1810 if ((*this_bp)->commands) | |
1811 { | 2705 { |
1812 char *commands = strdup((*this_bp)->commands); | 2706 debugging = run_command(root, (*this_bp)->commands + i); |
1813 char *copy = commands; | |
1814 | |
1815 while (debugging && *commands) | |
1816 { | |
1817 char *cmd = commands; | |
1818 strip_nl(cmd); | |
1819 commands += strlen(cmd) + 1; | |
1820 debugging = run_debugger_command(context, address, cmd, inst, after); | |
1821 } | |
1822 free(copy); | |
1823 } | 2707 } |
1824 if (debugging) { | 2708 if (debugging) { |
1825 printf("68K Breakpoint %d hit\n", (*this_bp)->index); | 2709 printf("68K Breakpoint %d hit\n", (*this_bp)->index); |
1826 } else { | 2710 } else { |
1827 return; | 2711 return; |
1828 } | 2712 } |
1829 } else { | 2713 } else { |
1830 remove_breakpoint(context, address); | 2714 remove_breakpoint(context, address); |
1831 } | 2715 } |
1832 for (disp_def * cur = root->displays; cur; cur = cur->next) { | 2716 for (disp_def * cur = root->displays; cur; cur = cur->next) { |
1833 debugger_print(root, cur->format_char, cur->param); | 2717 cmd_print(root, cur->format, cur->num_args, cur->args); |
1834 } | 2718 } |
1835 m68k_disasm(&inst, input_buf); | 2719 m68k_disasm(&inst, input_buf); |
1836 printf("%X: %s\n", address, input_buf); | 2720 printf("%X: %s\n", address, input_buf); |
1837 #ifdef _WIN32 | 2721 #ifdef _WIN32 |
1838 #define prompt 1 | 2722 #define prompt 1 |
1868 if (input_buf[0]) { | 2752 if (input_buf[0]) { |
1869 strcpy(last_cmd, input_buf); | 2753 strcpy(last_cmd, input_buf); |
1870 } else { | 2754 } else { |
1871 strcpy(input_buf, last_cmd); | 2755 strcpy(input_buf, last_cmd); |
1872 } | 2756 } |
1873 debugging = run_debugger_command(context, address, input_buf, inst, after); | 2757 parsed_command cmd; |
2758 if (parse_command(root, input_buf, &cmd)) { | |
2759 debugging = run_command(root, &cmd); | |
2760 free_parsed_command(&cmd); | |
2761 } | |
1874 } | 2762 } |
1875 return; | 2763 return; |
1876 } | 2764 } |