Mercurial > repos > blastem
comparison blastem.c @ 372:5dcf7551bb36
Bunch of Z80 debugger improvements
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 02 Jun 2013 20:14:27 -0700 |
parents | c9d2a2371f5e |
children | d42a8a3e4894 |
comparison
equal
deleted
inserted
replaced
371:0f8a759f1ff4 | 372:5dcf7551bb36 |
---|---|
997 cur = &((*cur)->next); | 997 cur = &((*cur)->next); |
998 } | 998 } |
999 return cur; | 999 return cur; |
1000 } | 1000 } |
1001 | 1001 |
1002 typedef struct disp_def { | |
1003 struct disp_def * next; | |
1004 char * param; | |
1005 uint32_t index; | |
1006 char format_char; | |
1007 } disp_def; | |
1008 | |
1009 disp_def * displays = NULL; | |
1010 disp_def * zdisplays = NULL; | |
1011 uint32_t disp_index = 0; | |
1012 uint32_t zdisp_index = 0; | |
1013 | |
1014 void add_display(disp_def ** head, uint32_t *index, char format_char, char * param) | |
1015 { | |
1016 disp_def * ndisp = malloc(sizeof(*ndisp)); | |
1017 ndisp->format_char = format_char; | |
1018 ndisp->param = strdup(param); | |
1019 ndisp->next = *head; | |
1020 ndisp->index = *index++; | |
1021 *head = ndisp; | |
1022 } | |
1023 | |
1024 void remove_display(disp_def ** head, uint32_t index) | |
1025 { | |
1026 while (*head) { | |
1027 if ((*head)->index == index) { | |
1028 disp_def * del_disp = *head; | |
1029 *head = del_disp->next; | |
1030 free(del_disp->param); | |
1031 free(del_disp); | |
1032 } else { | |
1033 head = &(*head)->next; | |
1034 } | |
1035 } | |
1036 } | |
1037 | |
1002 char * find_param(char * buf) | 1038 char * find_param(char * buf) |
1003 { | 1039 { |
1004 for (; *buf; buf++) { | 1040 for (; *buf; buf++) { |
1005 if (*buf == ' ') { | 1041 if (*buf == ' ') { |
1006 if (*(buf+1)) { | 1042 if (*(buf+1)) { |
1017 if (*buf == '\n') { | 1053 if (*buf == '\n') { |
1018 *buf = 0; | 1054 *buf = 0; |
1019 return; | 1055 return; |
1020 } | 1056 } |
1021 } | 1057 } |
1058 } | |
1059 | |
1060 void zdebugger_print(z80_context * context, char format_char, char * param) | |
1061 { | |
1062 uint32_t value; | |
1063 char format[8]; | |
1064 strcpy(format, "%s: %d\n"); | |
1065 switch (format_char) | |
1066 { | |
1067 case 'x': | |
1068 case 'X': | |
1069 case 'd': | |
1070 case 'c': | |
1071 format[5] = format_char; | |
1072 break; | |
1073 case '\0': | |
1074 break; | |
1075 default: | |
1076 fprintf(stderr, "Unrecognized format character: %c\n", format_char); | |
1077 } | |
1078 switch (param[0]) | |
1079 { | |
1080 case 'a': | |
1081 if (param[1] == 'f') { | |
1082 if(param[2] == '\'') { | |
1083 value = context->alt_regs[Z80_A] << 8; | |
1084 value |= context->alt_flags[ZF_S] << 7; | |
1085 value |= context->alt_flags[ZF_Z] << 6; | |
1086 value |= context->alt_flags[ZF_H] << 4; | |
1087 value |= context->alt_flags[ZF_PV] << 2; | |
1088 value |= context->alt_flags[ZF_N] << 1; | |
1089 value |= context->alt_flags[ZF_C]; | |
1090 } else { | |
1091 value = context->regs[Z80_A] << 8; | |
1092 value |= context->flags[ZF_S] << 7; | |
1093 value |= context->flags[ZF_Z] << 6; | |
1094 value |= context->flags[ZF_H] << 4; | |
1095 value |= context->flags[ZF_PV] << 2; | |
1096 value |= context->flags[ZF_N] << 1; | |
1097 value |= context->flags[ZF_C]; | |
1098 } | |
1099 } else if(param[1] == '\'') { | |
1100 value = context->alt_regs[Z80_A]; | |
1101 } else { | |
1102 value = context->regs[Z80_A]; | |
1103 } | |
1104 break; | |
1105 case 'b': | |
1106 if (param[1] == 'c') { | |
1107 if(param[2] == '\'') { | |
1108 value = context->alt_regs[Z80_B] << 8; | |
1109 value |= context->alt_regs[Z80_C]; | |
1110 } else { | |
1111 value = context->regs[Z80_B] << 8; | |
1112 value |= context->regs[Z80_C]; | |
1113 } | |
1114 } else if(param[1] == '\'') { | |
1115 value = context->alt_regs[Z80_B]; | |
1116 } else { | |
1117 value = context->regs[Z80_B]; | |
1118 } | |
1119 break; | |
1120 case 'c': | |
1121 if(param[1] == '\'') { | |
1122 value = context->alt_regs[Z80_C]; | |
1123 } else if(param[1] == 'y') { | |
1124 value = context->current_cycle; | |
1125 } else { | |
1126 value = context->regs[Z80_C]; | |
1127 } | |
1128 break; | |
1129 case 'd': | |
1130 if (param[1] == 'e') { | |
1131 if(param[2] == '\'') { | |
1132 value = context->alt_regs[Z80_D] << 8; | |
1133 value |= context->alt_regs[Z80_E]; | |
1134 } else { | |
1135 value = context->regs[Z80_D] << 8; | |
1136 value |= context->regs[Z80_E]; | |
1137 } | |
1138 } else if(param[1] == '\'') { | |
1139 value = context->alt_regs[Z80_D]; | |
1140 } else { | |
1141 value = context->regs[Z80_D]; | |
1142 } | |
1143 break; | |
1144 case 'e': | |
1145 if(param[1] == '\'') { | |
1146 value = context->alt_regs[Z80_E]; | |
1147 } else { | |
1148 value = context->regs[Z80_E]; | |
1149 } | |
1150 break; | |
1151 case 'f': | |
1152 if(param[2] == '\'') { | |
1153 value = context->alt_flags[ZF_S] << 7; | |
1154 value |= context->alt_flags[ZF_Z] << 6; | |
1155 value |= context->alt_flags[ZF_H] << 4; | |
1156 value |= context->alt_flags[ZF_PV] << 2; | |
1157 value |= context->alt_flags[ZF_N] << 1; | |
1158 value |= context->alt_flags[ZF_C]; | |
1159 } else { | |
1160 value = context->flags[ZF_S] << 7; | |
1161 value |= context->flags[ZF_Z] << 6; | |
1162 value |= context->flags[ZF_H] << 4; | |
1163 value |= context->flags[ZF_PV] << 2; | |
1164 value |= context->flags[ZF_N] << 1; | |
1165 value |= context->flags[ZF_C]; | |
1166 } | |
1167 break; | |
1168 case 'h': | |
1169 if (param[1] == 'l') { | |
1170 if(param[2] == '\'') { | |
1171 value = context->alt_regs[Z80_H] << 8; | |
1172 value |= context->alt_regs[Z80_L]; | |
1173 } else { | |
1174 value = context->regs[Z80_H] << 8; | |
1175 value |= context->regs[Z80_L]; | |
1176 } | |
1177 } else if(param[1] == '\'') { | |
1178 value = context->alt_regs[Z80_H]; | |
1179 } else { | |
1180 value = context->regs[Z80_H]; | |
1181 } | |
1182 break; | |
1183 case 'l': | |
1184 if(param[1] == '\'') { | |
1185 value = context->alt_regs[Z80_L]; | |
1186 } else { | |
1187 value = context->regs[Z80_L]; | |
1188 } | |
1189 break; | |
1190 case 'i': | |
1191 if(param[1] == 'x') { | |
1192 if (param[2] == 'h') { | |
1193 value = context->regs[Z80_IXH]; | |
1194 } else if(param[2] == 'l') { | |
1195 value = context->regs[Z80_IXL]; | |
1196 } else { | |
1197 value = context->regs[Z80_IXH] << 8; | |
1198 value |= context->regs[Z80_IXL]; | |
1199 } | |
1200 } else if(param[1] == 'y') { | |
1201 if (param[2] == 'h') { | |
1202 value = context->regs[Z80_IYH]; | |
1203 } else if(param[2] == 'l') { | |
1204 value = context->regs[Z80_IYL]; | |
1205 } else { | |
1206 value = context->regs[Z80_IYH] << 8; | |
1207 value |= context->regs[Z80_IYL]; | |
1208 } | |
1209 } else if(param[1] == 'n') { | |
1210 value = context->int_cycle; | |
1211 } else if(param[1] == 'f' && param[2] == 'f' && param[3] == '1') { | |
1212 value = context->iff1; | |
1213 } else if(param[1] == 'f' && param[2] == 'f' && param[3] == '2') { | |
1214 value = context->iff2; | |
1215 } else { | |
1216 value = context->im; | |
1217 } | |
1218 break; | |
1219 case 's': | |
1220 if (param[1] == 'p') { | |
1221 value = context->sp; | |
1222 } | |
1223 break; | |
1224 case '0': | |
1225 if (param[1] == 'x') { | |
1226 uint16_t p_addr = strtol(param+2, NULL, 16); | |
1227 if (p_addr < 0x4000) { | |
1228 value = z80_ram[p_addr & 0x1FFF]; | |
1229 } | |
1230 } | |
1231 break; | |
1232 } | |
1233 printf(format, param, value); | |
1022 } | 1234 } |
1023 | 1235 |
1024 z80_context * zdebugger(z80_context * context, uint16_t address) | 1236 z80_context * zdebugger(z80_context * context, uint16_t address) |
1025 { | 1237 { |
1026 static char last_cmd[1024]; | 1238 static char last_cmd[1024]; |
1048 } | 1260 } |
1049 } else { | 1261 } else { |
1050 fprintf(stderr, "Entered Z80 debugger at address %X\n", address); | 1262 fprintf(stderr, "Entered Z80 debugger at address %X\n", address); |
1051 exit(1); | 1263 exit(1); |
1052 } | 1264 } |
1265 for (disp_def * cur = zdisplays; cur; cur = cur->next) { | |
1266 zdebugger_print(context, cur->format_char, cur->param); | |
1267 } | |
1053 uint8_t * after_pc = z80_decode(pc, &inst); | 1268 uint8_t * after_pc = z80_decode(pc, &inst); |
1054 z80_disasm(&inst, input_buf, address); | 1269 z80_disasm(&inst, input_buf, address); |
1055 printf("%X:\t%s\n", address, input_buf); | 1270 printf("%X:\t%s\n", address, input_buf); |
1056 uint16_t after = address + (after_pc-pc); | 1271 uint16_t after = address + (after_pc-pc); |
1057 int debugging = 1; | 1272 int debugging = 1; |
1100 break; | 1315 break; |
1101 case 'c': | 1316 case 'c': |
1102 puts("Continuing"); | 1317 puts("Continuing"); |
1103 debugging = 0; | 1318 debugging = 0; |
1104 break; | 1319 break; |
1320 case 'd': | |
1321 if (input_buf[1] == 'i') { | |
1322 char format_char = 0; | |
1323 for(int i = 2; input_buf[i] != 0 && input_buf[i] != ' '; i++) { | |
1324 if (input_buf[i] == '/') { | |
1325 format_char = input_buf[i+1]; | |
1326 break; | |
1327 } | |
1328 } | |
1329 param = find_param(input_buf); | |
1330 if (!param) { | |
1331 fputs("display command requires a parameter\n", stderr); | |
1332 break; | |
1333 } | |
1334 zdebugger_print(context, format_char, param); | |
1335 add_display(&zdisplays, &zdisp_index, format_char, param); | |
1336 } else if (input_buf[1] == 'e' || input_buf[1] == ' ') { | |
1337 param = find_param(input_buf); | |
1338 if (!param) { | |
1339 fputs("delete command requires a parameter\n", stderr); | |
1340 break; | |
1341 } | |
1342 if (param[0] >= '0' && param[0] <= '9') { | |
1343 value = atoi(param); | |
1344 this_bp = find_breakpoint_idx(&zbreakpoints, value); | |
1345 if (!*this_bp) { | |
1346 fprintf(stderr, "Breakpoint %d does not exist\n", value); | |
1347 break; | |
1348 } | |
1349 new_bp = *this_bp; | |
1350 zremove_breakpoint(context, new_bp->address); | |
1351 *this_bp = new_bp->next; | |
1352 free(new_bp); | |
1353 } else if (param[0] == 'd') { | |
1354 param = find_param(param); | |
1355 if (!param) { | |
1356 fputs("delete display command requires a parameter\n", stderr); | |
1357 break; | |
1358 } | |
1359 remove_display(&zdisplays, atoi(param)); | |
1360 } | |
1361 } | |
1362 break; | |
1105 case 'n': | 1363 case 'n': |
1106 //TODO: Handle branch instructions | 1364 //TODO: Handle branch instructions |
1107 zinsert_breakpoint(context, after, (uint8_t *)zdebugger); | 1365 zinsert_breakpoint(context, after, (uint8_t *)zdebugger); |
1108 debugging = 0; | 1366 debugging = 0; |
1109 break; | 1367 break; |
1110 case 'p': | 1368 case 'p': |
1111 strcpy(format, "%s: %d\n"); | |
1112 if (input_buf[1] == '/') { | |
1113 switch (input_buf[2]) | |
1114 { | |
1115 case 'x': | |
1116 case 'X': | |
1117 case 'd': | |
1118 case 'c': | |
1119 format[5] = input_buf[2]; | |
1120 break; | |
1121 default: | |
1122 fprintf(stderr, "Unrecognized format character: %c\n", input_buf[2]); | |
1123 } | |
1124 } | |
1125 param = find_param(input_buf); | 1369 param = find_param(input_buf); |
1126 if (!param) { | 1370 if (!param) { |
1127 fputs("p command requires a parameter\n", stderr); | 1371 fputs("p command requires a parameter\n", stderr); |
1128 break; | 1372 break; |
1129 } | 1373 } |
1130 switch (param[0]) | 1374 zdebugger_print(context, input_buf[1] == '/' ? input_buf[2] : 0, param); |
1131 { | |
1132 case 'a': | |
1133 if (param[1] == 'f') { | |
1134 if(param[2] == '\'') { | |
1135 value = context->alt_regs[Z80_A] << 8; | |
1136 value |= context->alt_flags[ZF_S] << 7; | |
1137 value |= context->alt_flags[ZF_Z] << 6; | |
1138 value |= context->alt_flags[ZF_H] << 4; | |
1139 value |= context->alt_flags[ZF_PV] << 2; | |
1140 value |= context->alt_flags[ZF_N] << 1; | |
1141 value |= context->alt_flags[ZF_C]; | |
1142 } else { | |
1143 value = context->regs[Z80_A] << 8; | |
1144 value |= context->flags[ZF_S] << 7; | |
1145 value |= context->flags[ZF_Z] << 6; | |
1146 value |= context->flags[ZF_H] << 4; | |
1147 value |= context->flags[ZF_PV] << 2; | |
1148 value |= context->flags[ZF_N] << 1; | |
1149 value |= context->flags[ZF_C]; | |
1150 } | |
1151 } else if(param[1] == '\'') { | |
1152 value = context->alt_regs[Z80_A]; | |
1153 } else { | |
1154 value = context->regs[Z80_A]; | |
1155 } | |
1156 break; | |
1157 case 'b': | |
1158 if (param[1] == 'c') { | |
1159 if(param[2] == '\'') { | |
1160 value = context->alt_regs[Z80_B] << 8; | |
1161 value |= context->alt_regs[Z80_C]; | |
1162 } else { | |
1163 value = context->regs[Z80_B] << 8; | |
1164 value |= context->regs[Z80_C]; | |
1165 } | |
1166 } else if(param[1] == '\'') { | |
1167 value = context->alt_regs[Z80_B]; | |
1168 } else { | |
1169 value = context->regs[Z80_B]; | |
1170 } | |
1171 break; | |
1172 case 'c': | |
1173 if(param[1] == '\'') { | |
1174 value = context->alt_regs[Z80_C]; | |
1175 } else { | |
1176 value = context->regs[Z80_C]; | |
1177 } | |
1178 break; | |
1179 case 'd': | |
1180 if (param[1] == 'e') { | |
1181 if(param[2] == '\'') { | |
1182 value = context->alt_regs[Z80_D] << 8; | |
1183 value |= context->alt_regs[Z80_E]; | |
1184 } else { | |
1185 value = context->regs[Z80_D] << 8; | |
1186 value |= context->regs[Z80_E]; | |
1187 } | |
1188 } else if(param[1] == '\'') { | |
1189 value = context->alt_regs[Z80_D]; | |
1190 } else { | |
1191 value = context->regs[Z80_D]; | |
1192 } | |
1193 break; | |
1194 case 'e': | |
1195 if(param[1] == '\'') { | |
1196 value = context->alt_regs[Z80_E]; | |
1197 } else { | |
1198 value = context->regs[Z80_E]; | |
1199 } | |
1200 break; | |
1201 case 'f': | |
1202 if(param[2] == '\'') { | |
1203 value = context->alt_flags[ZF_S] << 7; | |
1204 value |= context->alt_flags[ZF_Z] << 6; | |
1205 value |= context->alt_flags[ZF_H] << 4; | |
1206 value |= context->alt_flags[ZF_PV] << 2; | |
1207 value |= context->alt_flags[ZF_N] << 1; | |
1208 value |= context->alt_flags[ZF_C]; | |
1209 } else { | |
1210 value = context->flags[ZF_S] << 7; | |
1211 value |= context->flags[ZF_Z] << 6; | |
1212 value |= context->flags[ZF_H] << 4; | |
1213 value |= context->flags[ZF_PV] << 2; | |
1214 value |= context->flags[ZF_N] << 1; | |
1215 value |= context->flags[ZF_C]; | |
1216 } | |
1217 break; | |
1218 case 'h': | |
1219 if (param[1] == 'l') { | |
1220 if(param[2] == '\'') { | |
1221 value = context->alt_regs[Z80_H] << 8; | |
1222 value |= context->alt_regs[Z80_L]; | |
1223 } else { | |
1224 value = context->regs[Z80_H] << 8; | |
1225 value |= context->regs[Z80_L]; | |
1226 } | |
1227 } else if(param[1] == '\'') { | |
1228 value = context->alt_regs[Z80_H]; | |
1229 } else { | |
1230 value = context->regs[Z80_H]; | |
1231 } | |
1232 break; | |
1233 case 'l': | |
1234 if(param[1] == '\'') { | |
1235 value = context->alt_regs[Z80_L]; | |
1236 } else { | |
1237 value = context->regs[Z80_L]; | |
1238 } | |
1239 break; | |
1240 case 'i': | |
1241 if(param[1] == 'x') { | |
1242 if (param[2] == 'h') { | |
1243 value = context->regs[Z80_IXH]; | |
1244 } else if(param[2] == 'l') { | |
1245 value = context->regs[Z80_IXL]; | |
1246 } else { | |
1247 value = context->regs[Z80_IXH] << 8; | |
1248 value |= context->regs[Z80_IXL]; | |
1249 } | |
1250 } else if(param[1] == 'y') { | |
1251 if (param[2] == 'h') { | |
1252 value = context->regs[Z80_IYH]; | |
1253 } else if(param[2] == 'l') { | |
1254 value = context->regs[Z80_IYL]; | |
1255 } else { | |
1256 value = context->regs[Z80_IYH] << 8; | |
1257 value |= context->regs[Z80_IYL]; | |
1258 } | |
1259 } else { | |
1260 value = context->im; | |
1261 } | |
1262 break; | |
1263 case '0': | |
1264 if (param[1] == 'x') { | |
1265 uint16_t p_addr = strtol(param+2, NULL, 16); | |
1266 if (p_addr < 0x4000) { | |
1267 value = z80_ram[p_addr & 0x1FFF]; | |
1268 } | |
1269 } | |
1270 break; | |
1271 } | |
1272 printf(format, param, value); | |
1273 break; | 1375 break; |
1274 case 'q': | 1376 case 'q': |
1275 puts("Quitting"); | 1377 puts("Quitting"); |
1276 exit(0); | 1378 exit(0); |
1277 break; | 1379 break; |