#define _POSIX_C_SOURCE 199309 #include #include #include #include #include #include "intel_8080_emulator.h" #include "dis8080.h" #include "globals.h" uint8_t ram[0x10000]; struct watchpoint { uint16_t address; uint8_t value; bool enabled; }; static uint16_t breakpoints[16]; static struct watchpoint watchpoints[16]; static bool tracing = false; static bool singlestepping = true; static bool bdosbreak = false; static const char* delimiters = " \t\n\r"; uint8_t i8080_read(uint16_t addr) { return ram[addr]; } void i8080_write(uint16_t addr, uint8_t value) { ram[addr] = value; } uint8_t i8080_inport(uint8_t addr) { return 0; } void i8080_outport(uint8_t addr, uint8_t value) { biosbdos_entry(addr & 0xff); if (bdosbreak) singlestepping = true; } void showregs(void) { uint16_t af = i8080_read_reg16(AF); printf("%c%c.%c.%c%c%c sp=%04x af=%04x bc=%04x de=%04x hl=%04x\n", (af & 0x80) ? 'S' : 's', (af & 0x40) ? 'Z' : 'z', (af & 0x10) ? 'H' : 'h', (af & 0x04) ? 'P' : 'p', (af & 0x02) ? 'N' : 'n', (af & 0x01) ? 'C' : 'c', i8080_read_reg16(SP), af, i8080_read_reg16(BC), i8080_read_reg16(DE), i8080_read_reg16(HL)); char buffer[80]; int tstates; uint16_t pc = i8080_read_reg16(PC); i8080_disassemble(buffer, sizeof(buffer), pc); puts(buffer); } static void cmd_register(void) { char* w1 = strtok(NULL, delimiters); char* w2 = strtok(NULL, delimiters); if (w1 && w2) { int reg = -1; if (strcmp(w1, "sp") == 0) reg = SP; else if (strcmp(w1, "pc") == 0) reg = PC; else if (strcmp(w1, "af") == 0) reg = AF; else if (strcmp(w1, "bc") == 0) reg = BC; else if (strcmp(w1, "de") == 0) reg = DE; else if (strcmp(w1, "hl") == 0) reg = HL; else { printf("Bad register\n"); return; } i8080_write_reg16(reg, strtoul(w2, NULL, 16)); } showregs(); } static void cmd_break(void) { int i; char* w1 = strtok(NULL, delimiters); if (w1) { uint16_t breakpc = strtoul(w1, NULL, 16); for (i=0; ienabled) { w->address = watchaddr; w->enabled = true; w->value = ram[watchaddr]; return; } } printf("Too many breakpoints\n"); } else { for (i=0; ienabled) printf("%04x (current value: %02x)\n", w->address, w->value); } } } static void cmd_delete_breakpoint(void) { int i; char* w1 = strtok(NULL, delimiters); if (w1) { uint16_t breakpc = strtoul(w1, NULL, 16); for (i=0; ienabled && (w->address == address)) { w->enabled = false; return; } } printf("No such watchpoint\n"); } } static void cmd_memory(void) { int i; char* w1 = strtok(NULL, delimiters); char* w2 = strtok(NULL, delimiters); if (!w2) w2 = "100"; if (w1 && w2) { uint16_t startaddr = strtoul(w1, NULL, 16); uint16_t endaddr = startaddr + strtoul(w2, NULL, 16); uint16_t startrounded = startaddr & ~0xf; uint16_t endrounded = (endaddr + 0xf) & ~0xf; uint16_t p = startrounded; while (p < endrounded) { printf("%04x : ", p); for (i = 0; i < 16; i++) { uint16_t pp = p + i; if ((pp >= startaddr) && (pp < endaddr)) printf("%02x ", ram[pp]); else printf(" "); } printf(": "); for (i = 0; i < 16; i++) { uint16_t pp = p + i; if ((pp >= startaddr) && (pp < endaddr)) { uint8_t c = ram[pp]; if ((c < 32) || (c > 127)) c = '.'; putchar(c); } else putchar(' '); } p += 16; putchar('\n'); } } } static void cmd_unassemble(void) { char* w1 = strtok(NULL, delimiters); char* w2 = strtok(NULL, delimiters); uint16_t startaddr = i8080_read_reg16(PC); uint16_t endaddr; if (w1) startaddr = strtoul(w1, NULL, 16); endaddr = startaddr + 0x20; if (w2) endaddr = startaddr + strtoul(w2, NULL, 16); while (startaddr < endaddr) { char buffer[80]; startaddr = i8080_disassemble(buffer, sizeof(buffer), startaddr); puts(buffer); } } static void cmd_bdos(void) { char* w1 = strtok(NULL, delimiters); if (w1) bdosbreak = !!strtoul(w1, NULL, 16); else printf("break on bdos entry: %s\n", bdosbreak ? "on" : "off"); } static void cmd_tracing(void) { char* w1 = strtok(NULL, delimiters); if (w1) tracing = !!strtoul(w1, NULL, 16); else printf("tracing: %s\n", tracing ? "on" : "off"); } static void cmd_help(void) { printf("Sleazy debugger\n" " r show registers\n" " r set register\n" " b show breakpoints\n" " b set breakpoint\n" " db delete breakpoint\n" " w set watchpoint\n" " dw delete watchpoint\n" " m show memory\n" " u unassemble memory\n" " s single step\n" " g continue\n" " bdos 0|1 enable break on bdos entry\n" " tracing 0|1 enable tracing\n" ); } static void debug(void) { bool go = false; showregs(); while (!go) { char cmdline[80]; printf("debug> "); fflush(stdout); if (!fgets(cmdline, sizeof(cmdline), stdin)) exit(0); char* token = strtok(cmdline, delimiters); if (token != NULL) { if (strcmp(token, "?") == 0) cmd_help(); else if (strcmp(token, "r") == 0) cmd_register(); else if (strcmp(token, "b") == 0) cmd_break(); else if (strcmp(token, "w") == 0) cmd_watch(); else if (strcmp(token, "db") == 0) cmd_delete_breakpoint(); else if (strcmp(token, "dw") == 0) cmd_delete_watchpoint(); else if (strcmp(token, "m") == 0) cmd_memory(); else if (strcmp(token, "u") == 0) cmd_unassemble(); else if (strcmp(token, "s") == 0) { singlestepping = true; go = true; } else if (strcmp(token, "g") == 0) { singlestepping = false; go = true; } else if (strcmp(token, "bdos") == 0) cmd_bdos(); else if (strcmp(token, "tracing") == 0) cmd_tracing(); else printf("Bad command\n"); } } } static void sigusr1_cb(int number) { singlestepping = true; } void emulator_init(void) { int i; for (i=0; ienabled && (ram[w->address] != w->value)) { printf("\nWatchpoint hit: %04x has changed from %02x to %02x\n", w->address, w->value, ram[w->address]); w->value = ram[w->address]; singlestepping = true; } } if (singlestepping) debug(); else if (tracing) showregs(); i8080_exec(1); } }