Mercurial > repos > blastem
comparison blastem.c @ 366:836585d389b8
Partial implementation of Z80 debugger
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Fri, 31 May 2013 19:43:13 -0700 |
parents | 62177cc39049 |
children | c9d2a2371f5e |
comparison
equal
deleted
inserted
replaced
365:3ba3b6656fff | 366:836585d389b8 |
---|---|
971 uint32_t address; | 971 uint32_t address; |
972 uint32_t index; | 972 uint32_t index; |
973 } bp_def; | 973 } bp_def; |
974 | 974 |
975 bp_def * breakpoints = NULL; | 975 bp_def * breakpoints = NULL; |
976 bp_def * zbreakpoints = NULL; | |
976 uint32_t bp_index = 0; | 977 uint32_t bp_index = 0; |
978 uint32_t zbp_index = 0; | |
977 | 979 |
978 bp_def ** find_breakpoint(bp_def ** cur, uint32_t address) | 980 bp_def ** find_breakpoint(bp_def ** cur, uint32_t address) |
979 { | 981 { |
980 while (*cur) { | 982 while (*cur) { |
981 if ((*cur)->address == address) { | 983 if ((*cur)->address == address) { |
1017 return; | 1019 return; |
1018 } | 1020 } |
1019 } | 1021 } |
1020 } | 1022 } |
1021 | 1023 |
1022 m68k_context * debugger(m68k_context * context, uint32_t address) | 1024 z80_context * zdebugger(z80_context * context, uint16_t address) |
1023 { | 1025 { |
1024 static char last_cmd[1024]; | 1026 static char last_cmd[1024]; |
1025 char input_buf[1024]; | 1027 char input_buf[1024]; |
1026 static uint32_t branch_t; | 1028 static uint16_t branch_t; |
1027 static uint32_t branch_f; | 1029 static uint16_t branch_f; |
1028 m68kinst inst; | 1030 z80inst inst; |
1029 //probably not necessary, but let's play it safe | |
1030 address &= 0xFFFFFF; | |
1031 if (address == branch_t) { | |
1032 bp_def ** f_bp = find_breakpoint(&breakpoints, branch_f); | |
1033 if (!*f_bp) { | |
1034 remove_breakpoint(context, branch_f); | |
1035 } | |
1036 branch_t = branch_f = 0; | |
1037 } else if(address == branch_f) { | |
1038 bp_def ** t_bp = find_breakpoint(&breakpoints, branch_t); | |
1039 if (!*t_bp) { | |
1040 remove_breakpoint(context, branch_t); | |
1041 } | |
1042 branch_t = branch_f = 0; | |
1043 } | |
1044 //Check if this is a user set breakpoint, or just a temporary one | 1031 //Check if this is a user set breakpoint, or just a temporary one |
1045 bp_def ** this_bp = find_breakpoint(&breakpoints, address); | 1032 bp_def ** this_bp = find_breakpoint(&zbreakpoints, address); |
1046 if (*this_bp) { | 1033 if (*this_bp) { |
1047 printf("Breakpoint %d hit\n", (*this_bp)->index); | 1034 printf("Z80 Breakpoint %d hit\n", (*this_bp)->index); |
1048 } else { | 1035 } else { |
1049 remove_breakpoint(context, address); | 1036 zremove_breakpoint(context, address); |
1050 } | 1037 } |
1051 uint16_t * pc; | 1038 uint8_t * pc; |
1052 if (address < 0x400000) { | 1039 if (address < 0x4000) { |
1053 pc = cart + address/2; | 1040 pc = z80_ram + (address & 0x1FFF); |
1054 } else if(address > 0xE00000) { | 1041 } else if (address >= 0x8000) { |
1055 pc = ram + (address & 0xFFFF)/2; | 1042 if (context->bank_reg < (0x400000 >> 15)) { |
1043 fprintf(stderr, "Entered Z80 debugger in banked memory address %X, which is not yet supported\n", address); | |
1044 exit(1); | |
1045 } else { | |
1046 fprintf(stderr, "Entered Z80 debugger in banked memory address %X, but the bank is not pointed to a cartridge address\n", address); | |
1047 exit(1); | |
1048 } | |
1056 } else { | 1049 } else { |
1057 fprintf(stderr, "Entered debugger at address %X\n", address); | 1050 fprintf(stderr, "Entered Z80 debugger at address %X\n", address); |
1058 exit(1); | 1051 exit(1); |
1059 } | 1052 } |
1060 uint16_t * after_pc = m68k_decode(pc, &inst, address); | 1053 uint8_t * after_pc = z80_decode(pc, &inst); |
1061 m68k_disasm(&inst, input_buf); | 1054 z80_disasm(&inst, input_buf, address); |
1062 printf("%X: %s\n", address, input_buf); | 1055 printf("%X:\t%s\n", address, input_buf); |
1063 uint32_t after = address + (after_pc-pc)*2; | 1056 uint16_t after = address + (after_pc-pc); |
1064 int debugging = 1; | 1057 int debugging = 1; |
1065 while (debugging) { | 1058 while(debugging) { |
1066 fputs(">", stdout); | 1059 fputs(">", stdout); |
1067 if (!fgets(input_buf, sizeof(input_buf), stdin)) { | 1060 if (!fgets(input_buf, sizeof(input_buf), stdin)) { |
1068 fputs("fgets failed", stderr); | 1061 fputs("fgets failed", stderr); |
1069 break; | 1062 break; |
1070 } | 1063 } |
1079 char format[8]; | 1072 char format[8]; |
1080 uint32_t value; | 1073 uint32_t value; |
1081 bp_def * new_bp; | 1074 bp_def * new_bp; |
1082 switch(input_buf[0]) | 1075 switch(input_buf[0]) |
1083 { | 1076 { |
1084 case 'c': | 1077 case 'a': |
1085 puts("Continuing"); | 1078 param = find_param(input_buf); |
1086 debugging = 0; | 1079 if (!param) { |
1080 fputs("a command requires a parameter\n", stderr); | |
1081 break; | |
1082 } | |
1083 value = strtol(param, NULL, 16); | |
1084 zinsert_breakpoint(context, value, (uint8_t *)zdebugger); | |
1087 break; | 1085 break; |
1088 case 'b': | 1086 case 'b': |
1089 param = find_param(input_buf); | 1087 param = find_param(input_buf); |
1090 if (!param) { | 1088 if (!param) { |
1091 fputs("b command requires a parameter\n", stderr); | 1089 fputs("b command requires a parameter\n", stderr); |
1092 break; | 1090 break; |
1093 } | 1091 } |
1094 value = strtol(param, NULL, 16); | 1092 value = strtol(param, NULL, 16); |
1095 insert_breakpoint(context, value, (uint8_t *)debugger); | 1093 zinsert_breakpoint(context, value, (uint8_t *)zdebugger); |
1096 new_bp = malloc(sizeof(bp_def)); | 1094 new_bp = malloc(sizeof(bp_def)); |
1097 new_bp->next = breakpoints; | 1095 new_bp->next = zbreakpoints; |
1098 new_bp->address = value; | 1096 new_bp->address = value; |
1099 new_bp->index = bp_index++; | 1097 new_bp->index = zbp_index++; |
1100 breakpoints = new_bp; | 1098 zbreakpoints = new_bp; |
1101 printf("Breakpoint %d set at %X\n", new_bp->index, value); | 1099 printf("Z80 Breakpoint %d set at %X\n", new_bp->index, value); |
1102 break; | 1100 break; |
1103 case 'a': | 1101 case 'c': |
1104 param = find_param(input_buf); | 1102 puts("Continuing"); |
1105 if (!param) { | |
1106 fputs("a command requires a parameter\n", stderr); | |
1107 break; | |
1108 } | |
1109 value = strtol(param, NULL, 16); | |
1110 insert_breakpoint(context, value, (uint8_t *)debugger); | |
1111 debugging = 0; | 1103 debugging = 0; |
1112 break; | 1104 break; |
1113 case 'd': | 1105 case 'n': |
1114 param = find_param(input_buf); | 1106 //TODO: Handle branch instructions |
1115 if (!param) { | 1107 zinsert_breakpoint(context, after, (uint8_t *)zdebugger); |
1116 fputs("b command requires a parameter\n", stderr); | |
1117 break; | |
1118 } | |
1119 value = atoi(param); | |
1120 this_bp = find_breakpoint_idx(&breakpoints, value); | |
1121 if (!*this_bp) { | |
1122 fprintf(stderr, "Breakpoint %d does not exist\n", value); | |
1123 break; | |
1124 } | |
1125 new_bp = *this_bp; | |
1126 *this_bp = (*this_bp)->next; | |
1127 free(new_bp); | |
1128 break; | 1108 break; |
1129 case 'p': | 1109 case 'p': |
1130 strcpy(format, "%s: %d\n"); | 1110 strcpy(format, "%s: %d\n"); |
1131 if (input_buf[1] == '/') { | 1111 if (input_buf[1] == '/') { |
1132 switch (input_buf[2]) | 1112 switch (input_buf[2]) |
1144 param = find_param(input_buf); | 1124 param = find_param(input_buf); |
1145 if (!param) { | 1125 if (!param) { |
1146 fputs("p command requires a parameter\n", stderr); | 1126 fputs("p command requires a parameter\n", stderr); |
1147 break; | 1127 break; |
1148 } | 1128 } |
1129 switch (param[0]) | |
1130 { | |
1131 case 'a': | |
1132 if (param[1] == 'f') { | |
1133 if(param[2] == '\'') { | |
1134 value = context->alt_regs[Z80_A] << 8; | |
1135 value |= context->alt_flags[ZF_S] << 7; | |
1136 value |= context->alt_flags[ZF_Z] << 6; | |
1137 value |= context->alt_flags[ZF_H] << 4; | |
1138 value |= context->alt_flags[ZF_PV] << 2; | |
1139 value |= context->alt_flags[ZF_N] << 1; | |
1140 value |= context->alt_flags[ZF_C]; | |
1141 } else { | |
1142 value = context->regs[Z80_A] << 8; | |
1143 value |= context->flags[ZF_S] << 7; | |
1144 value |= context->flags[ZF_Z] << 6; | |
1145 value |= context->flags[ZF_H] << 4; | |
1146 value |= context->flags[ZF_PV] << 2; | |
1147 value |= context->flags[ZF_N] << 1; | |
1148 value |= context->flags[ZF_C]; | |
1149 } | |
1150 } else if(param[1] == '\'') { | |
1151 value = context->alt_regs[Z80_A]; | |
1152 } else { | |
1153 value = context->regs[Z80_A]; | |
1154 } | |
1155 break; | |
1156 case 'b': | |
1157 if (param[1] == 'c') { | |
1158 if(param[2] == '\'') { | |
1159 value = context->alt_regs[Z80_B] << 8; | |
1160 value |= context->alt_regs[Z80_C]; | |
1161 } else { | |
1162 value = context->regs[Z80_B] << 8; | |
1163 value |= context->regs[Z80_C]; | |
1164 } | |
1165 } else if(param[1] == '\'') { | |
1166 value = context->alt_regs[Z80_B]; | |
1167 } else { | |
1168 value = context->regs[Z80_B]; | |
1169 } | |
1170 break; | |
1171 case 'c': | |
1172 if(param[1] == '\'') { | |
1173 value = context->alt_regs[Z80_C]; | |
1174 } else { | |
1175 value = context->regs[Z80_C]; | |
1176 } | |
1177 break; | |
1178 case 'd': | |
1179 if (param[1] == 'e') { | |
1180 if(param[2] == '\'') { | |
1181 value = context->alt_regs[Z80_D] << 8; | |
1182 value |= context->alt_regs[Z80_E]; | |
1183 } else { | |
1184 value = context->regs[Z80_D] << 8; | |
1185 value |= context->regs[Z80_E]; | |
1186 } | |
1187 } else if(param[1] == '\'') { | |
1188 value = context->alt_regs[Z80_D]; | |
1189 } else { | |
1190 value = context->regs[Z80_D]; | |
1191 } | |
1192 break; | |
1193 case 'e': | |
1194 if(param[1] == '\'') { | |
1195 value = context->alt_regs[Z80_E]; | |
1196 } else { | |
1197 value = context->regs[Z80_E]; | |
1198 } | |
1199 break; | |
1200 case 'f': | |
1201 if(param[2] == '\'') { | |
1202 value = context->alt_flags[ZF_S] << 7; | |
1203 value |= context->alt_flags[ZF_Z] << 6; | |
1204 value |= context->alt_flags[ZF_H] << 4; | |
1205 value |= context->alt_flags[ZF_PV] << 2; | |
1206 value |= context->alt_flags[ZF_N] << 1; | |
1207 value |= context->alt_flags[ZF_C]; | |
1208 } else { | |
1209 value = context->flags[ZF_S] << 7; | |
1210 value |= context->flags[ZF_Z] << 6; | |
1211 value |= context->flags[ZF_H] << 4; | |
1212 value |= context->flags[ZF_PV] << 2; | |
1213 value |= context->flags[ZF_N] << 1; | |
1214 value |= context->flags[ZF_C]; | |
1215 } | |
1216 break; | |
1217 case 'h': | |
1218 if (param[1] == 'l') { | |
1219 if(param[2] == '\'') { | |
1220 value = context->alt_regs[Z80_H] << 8; | |
1221 value |= context->alt_regs[Z80_L]; | |
1222 } else { | |
1223 value = context->regs[Z80_H] << 8; | |
1224 value |= context->regs[Z80_L]; | |
1225 } | |
1226 } else if(param[1] == '\'') { | |
1227 value = context->alt_regs[Z80_H]; | |
1228 } else { | |
1229 value = context->regs[Z80_H]; | |
1230 } | |
1231 break; | |
1232 case 'l': | |
1233 if(param[1] == '\'') { | |
1234 value = context->alt_regs[Z80_L]; | |
1235 } else { | |
1236 value = context->regs[Z80_L]; | |
1237 } | |
1238 break; | |
1239 case 'i': | |
1240 if(param[1] == 'x') { | |
1241 if (param[2] == 'h') { | |
1242 value = context->regs[Z80_IXH]; | |
1243 } else if(param[2] == 'l') { | |
1244 value = context->regs[Z80_IXL]; | |
1245 } else { | |
1246 value = context->regs[Z80_IXH] << 8; | |
1247 value |= context->regs[Z80_IXL]; | |
1248 } | |
1249 } else if(param[1] == 'y') { | |
1250 if (param[2] == 'h') { | |
1251 value = context->regs[Z80_IYH]; | |
1252 } else if(param[2] == 'l') { | |
1253 value = context->regs[Z80_IYL]; | |
1254 } else { | |
1255 value = context->regs[Z80_IYH] << 8; | |
1256 value |= context->regs[Z80_IYL]; | |
1257 } | |
1258 } else { | |
1259 value = context->im; | |
1260 } | |
1261 break; | |
1262 case '0': | |
1263 if (param[1] == 'x') { | |
1264 uint16_t p_addr = strtol(param+2, NULL, 16); | |
1265 if (p_addr < 0x4000) { | |
1266 value = z80_ram[p_addr & 0x1FFF]; | |
1267 } | |
1268 } | |
1269 break; | |
1270 } | |
1271 printf(format, param, value); | |
1272 break; | |
1273 case 'q': | |
1274 puts("Quitting"); | |
1275 exit(0); | |
1276 break; | |
1277 default: | |
1278 fprintf(stderr, "Unrecognized debugger command %s\n", input_buf); | |
1279 break; | |
1280 } | |
1281 } | |
1282 return context; | |
1283 } | |
1284 | |
1285 m68k_context * debugger(m68k_context * context, uint32_t address) | |
1286 { | |
1287 static char last_cmd[1024]; | |
1288 char input_buf[1024]; | |
1289 static uint32_t branch_t; | |
1290 static uint32_t branch_f; | |
1291 m68kinst inst; | |
1292 //probably not necessary, but let's play it safe | |
1293 address &= 0xFFFFFF; | |
1294 if (address == branch_t) { | |
1295 bp_def ** f_bp = find_breakpoint(&breakpoints, branch_f); | |
1296 if (!*f_bp) { | |
1297 remove_breakpoint(context, branch_f); | |
1298 } | |
1299 branch_t = branch_f = 0; | |
1300 } else if(address == branch_f) { | |
1301 bp_def ** t_bp = find_breakpoint(&breakpoints, branch_t); | |
1302 if (!*t_bp) { | |
1303 remove_breakpoint(context, branch_t); | |
1304 } | |
1305 branch_t = branch_f = 0; | |
1306 } | |
1307 //Check if this is a user set breakpoint, or just a temporary one | |
1308 bp_def ** this_bp = find_breakpoint(&breakpoints, address); | |
1309 if (*this_bp) { | |
1310 printf("68K Breakpoint %d hit\n", (*this_bp)->index); | |
1311 } else { | |
1312 remove_breakpoint(context, address); | |
1313 } | |
1314 uint16_t * pc; | |
1315 if (address < 0x400000) { | |
1316 pc = cart + address/2; | |
1317 } else if(address > 0xE00000) { | |
1318 pc = ram + (address & 0xFFFF)/2; | |
1319 } else { | |
1320 fprintf(stderr, "Entered 68K debugger at address %X\n", address); | |
1321 exit(1); | |
1322 } | |
1323 uint16_t * after_pc = m68k_decode(pc, &inst, address); | |
1324 m68k_disasm(&inst, input_buf); | |
1325 printf("%X: %s\n", address, input_buf); | |
1326 uint32_t after = address + (after_pc-pc)*2; | |
1327 int debugging = 1; | |
1328 while (debugging) { | |
1329 fputs(">", stdout); | |
1330 if (!fgets(input_buf, sizeof(input_buf), stdin)) { | |
1331 fputs("fgets failed", stderr); | |
1332 break; | |
1333 } | |
1334 strip_nl(input_buf); | |
1335 //hitting enter repeats last command | |
1336 if (input_buf[0]) { | |
1337 strcpy(last_cmd, input_buf); | |
1338 } else { | |
1339 strcpy(input_buf, last_cmd); | |
1340 } | |
1341 char * param; | |
1342 char format[8]; | |
1343 uint32_t value; | |
1344 bp_def * new_bp; | |
1345 switch(input_buf[0]) | |
1346 { | |
1347 case 'c': | |
1348 puts("Continuing"); | |
1349 debugging = 0; | |
1350 break; | |
1351 case 'b': | |
1352 param = find_param(input_buf); | |
1353 if (!param) { | |
1354 fputs("b command requires a parameter\n", stderr); | |
1355 break; | |
1356 } | |
1357 value = strtol(param, NULL, 16); | |
1358 insert_breakpoint(context, value, (uint8_t *)debugger); | |
1359 new_bp = malloc(sizeof(bp_def)); | |
1360 new_bp->next = breakpoints; | |
1361 new_bp->address = value; | |
1362 new_bp->index = bp_index++; | |
1363 breakpoints = new_bp; | |
1364 printf("68K Breakpoint %d set at %X\n", new_bp->index, value); | |
1365 break; | |
1366 case 'a': | |
1367 param = find_param(input_buf); | |
1368 if (!param) { | |
1369 fputs("a command requires a parameter\n", stderr); | |
1370 break; | |
1371 } | |
1372 value = strtol(param, NULL, 16); | |
1373 insert_breakpoint(context, value, (uint8_t *)debugger); | |
1374 debugging = 0; | |
1375 break; | |
1376 case 'd': | |
1377 param = find_param(input_buf); | |
1378 if (!param) { | |
1379 fputs("b command requires a parameter\n", stderr); | |
1380 break; | |
1381 } | |
1382 value = atoi(param); | |
1383 this_bp = find_breakpoint_idx(&breakpoints, value); | |
1384 if (!*this_bp) { | |
1385 fprintf(stderr, "Breakpoint %d does not exist\n", value); | |
1386 break; | |
1387 } | |
1388 new_bp = *this_bp; | |
1389 *this_bp = (*this_bp)->next; | |
1390 free(new_bp); | |
1391 break; | |
1392 case 'p': | |
1393 strcpy(format, "%s: %d\n"); | |
1394 if (input_buf[1] == '/') { | |
1395 switch (input_buf[2]) | |
1396 { | |
1397 case 'x': | |
1398 case 'X': | |
1399 case 'd': | |
1400 case 'c': | |
1401 format[5] = input_buf[2]; | |
1402 break; | |
1403 default: | |
1404 fprintf(stderr, "Unrecognized format character: %c\n", input_buf[2]); | |
1405 } | |
1406 } | |
1407 param = find_param(input_buf); | |
1408 if (!param) { | |
1409 fputs("p command requires a parameter\n", stderr); | |
1410 break; | |
1411 } | |
1149 if (param[0] == 'd' && param[1] >= '0' && param[1] <= '7') { | 1412 if (param[0] == 'd' && param[1] >= '0' && param[1] <= '7') { |
1150 value = context->dregs[param[1]-'0']; | 1413 value = context->dregs[param[1]-'0']; |
1151 } else if (param[0] == 'a' && param[1] >= '0' && param[1] <= '7') { | 1414 } else if (param[0] == 'a' && param[1] >= '0' && param[1] <= '7') { |
1152 value = context->aregs[param[1]-'0']; | 1415 value = context->aregs[param[1]-'0']; |
1153 } else if (param[0] == 'S' && param[1] == 'R') { | 1416 } else if (param[0] == 'S' && param[1] == 'R') { |
1190 case 's': | 1453 case 's': |
1191 vdp_print_sprite_table(gen->vdp); | 1454 vdp_print_sprite_table(gen->vdp); |
1192 break; | 1455 break; |
1193 case 'r': | 1456 case 'r': |
1194 vdp_print_reg_explain(gen->vdp); | 1457 vdp_print_reg_explain(gen->vdp); |
1458 break; | |
1459 } | |
1460 break; | |
1461 } | |
1462 case 'z': { | |
1463 genesis_context * gen = context->system; | |
1464 //Z80 debug commands | |
1465 switch(input_buf[1]) | |
1466 { | |
1467 case 'b': | |
1468 param = find_param(input_buf); | |
1469 if (!param) { | |
1470 fputs("zb command requires a parameter\n", stderr); | |
1471 break; | |
1472 } | |
1473 value = strtol(param, NULL, 16); | |
1474 zinsert_breakpoint(gen->z80, value, (uint8_t *)zdebugger); | |
1475 new_bp = malloc(sizeof(bp_def)); | |
1476 new_bp->next = zbreakpoints; | |
1477 new_bp->address = value; | |
1478 new_bp->index = zbp_index++; | |
1479 zbreakpoints = new_bp; | |
1480 printf("Z80 Breakpoint %d set at %X\n", new_bp->index, value); | |
1195 break; | 1481 break; |
1196 } | 1482 } |
1197 break; | 1483 break; |
1198 } | 1484 } |
1199 case 'q': | 1485 case 'q': |