summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--blastem.c292
-rw-r--r--z80_to_x86.c57
-rw-r--r--z80_to_x86.h2
3 files changed, 348 insertions, 3 deletions
diff --git a/blastem.c b/blastem.c
index affb600..78181d4 100644
--- a/blastem.c
+++ b/blastem.c
@@ -973,7 +973,9 @@ typedef struct bp_def {
} bp_def;
bp_def * breakpoints = NULL;
+bp_def * zbreakpoints = NULL;
uint32_t bp_index = 0;
+uint32_t zbp_index = 0;
bp_def ** find_breakpoint(bp_def ** cur, uint32_t address)
{
@@ -1019,6 +1021,267 @@ void strip_nl(char * buf)
}
}
+z80_context * zdebugger(z80_context * context, uint16_t address)
+{
+ static char last_cmd[1024];
+ char input_buf[1024];
+ static uint16_t branch_t;
+ static uint16_t branch_f;
+ z80inst inst;
+ //Check if this is a user set breakpoint, or just a temporary one
+ bp_def ** this_bp = find_breakpoint(&zbreakpoints, address);
+ if (*this_bp) {
+ printf("Z80 Breakpoint %d hit\n", (*this_bp)->index);
+ } else {
+ zremove_breakpoint(context, address);
+ }
+ uint8_t * pc;
+ if (address < 0x4000) {
+ pc = z80_ram + (address & 0x1FFF);
+ } else if (address >= 0x8000) {
+ if (context->bank_reg < (0x400000 >> 15)) {
+ fprintf(stderr, "Entered Z80 debugger in banked memory address %X, which is not yet supported\n", address);
+ exit(1);
+ } else {
+ fprintf(stderr, "Entered Z80 debugger in banked memory address %X, but the bank is not pointed to a cartridge address\n", address);
+ exit(1);
+ }
+ } else {
+ fprintf(stderr, "Entered Z80 debugger at address %X\n", address);
+ exit(1);
+ }
+ uint8_t * after_pc = z80_decode(pc, &inst);
+ z80_disasm(&inst, input_buf, address);
+ printf("%X:\t%s\n", address, input_buf);
+ uint16_t after = address + (after_pc-pc);
+ int debugging = 1;
+ while(debugging) {
+ fputs(">", stdout);
+ if (!fgets(input_buf, sizeof(input_buf), stdin)) {
+ fputs("fgets failed", stderr);
+ break;
+ }
+ strip_nl(input_buf);
+ //hitting enter repeats last command
+ if (input_buf[0]) {
+ strcpy(last_cmd, input_buf);
+ } else {
+ strcpy(input_buf, last_cmd);
+ }
+ char * param;
+ char format[8];
+ uint32_t value;
+ bp_def * new_bp;
+ switch(input_buf[0])
+ {
+ case 'a':
+ param = find_param(input_buf);
+ if (!param) {
+ fputs("a command requires a parameter\n", stderr);
+ break;
+ }
+ value = strtol(param, NULL, 16);
+ zinsert_breakpoint(context, value, (uint8_t *)zdebugger);
+ break;
+ case 'b':
+ param = find_param(input_buf);
+ if (!param) {
+ fputs("b command requires a parameter\n", stderr);
+ break;
+ }
+ value = strtol(param, NULL, 16);
+ zinsert_breakpoint(context, value, (uint8_t *)zdebugger);
+ new_bp = malloc(sizeof(bp_def));
+ new_bp->next = zbreakpoints;
+ new_bp->address = value;
+ new_bp->index = zbp_index++;
+ zbreakpoints = new_bp;
+ printf("Z80 Breakpoint %d set at %X\n", new_bp->index, value);
+ break;
+ case 'c':
+ puts("Continuing");
+ debugging = 0;
+ break;
+ case 'n':
+ //TODO: Handle branch instructions
+ zinsert_breakpoint(context, after, (uint8_t *)zdebugger);
+ break;
+ case 'p':
+ strcpy(format, "%s: %d\n");
+ if (input_buf[1] == '/') {
+ switch (input_buf[2])
+ {
+ case 'x':
+ case 'X':
+ case 'd':
+ case 'c':
+ format[5] = input_buf[2];
+ break;
+ default:
+ fprintf(stderr, "Unrecognized format character: %c\n", input_buf[2]);
+ }
+ }
+ param = find_param(input_buf);
+ if (!param) {
+ fputs("p command requires a parameter\n", stderr);
+ break;
+ }
+ switch (param[0])
+ {
+ case 'a':
+ if (param[1] == 'f') {
+ if(param[2] == '\'') {
+ value = context->alt_regs[Z80_A] << 8;
+ value |= context->alt_flags[ZF_S] << 7;
+ value |= context->alt_flags[ZF_Z] << 6;
+ value |= context->alt_flags[ZF_H] << 4;
+ value |= context->alt_flags[ZF_PV] << 2;
+ value |= context->alt_flags[ZF_N] << 1;
+ value |= context->alt_flags[ZF_C];
+ } else {
+ value = context->regs[Z80_A] << 8;
+ value |= context->flags[ZF_S] << 7;
+ value |= context->flags[ZF_Z] << 6;
+ value |= context->flags[ZF_H] << 4;
+ value |= context->flags[ZF_PV] << 2;
+ value |= context->flags[ZF_N] << 1;
+ value |= context->flags[ZF_C];
+ }
+ } else if(param[1] == '\'') {
+ value = context->alt_regs[Z80_A];
+ } else {
+ value = context->regs[Z80_A];
+ }
+ break;
+ case 'b':
+ if (param[1] == 'c') {
+ if(param[2] == '\'') {
+ value = context->alt_regs[Z80_B] << 8;
+ value |= context->alt_regs[Z80_C];
+ } else {
+ value = context->regs[Z80_B] << 8;
+ value |= context->regs[Z80_C];
+ }
+ } else if(param[1] == '\'') {
+ value = context->alt_regs[Z80_B];
+ } else {
+ value = context->regs[Z80_B];
+ }
+ break;
+ case 'c':
+ if(param[1] == '\'') {
+ value = context->alt_regs[Z80_C];
+ } else {
+ value = context->regs[Z80_C];
+ }
+ break;
+ case 'd':
+ if (param[1] == 'e') {
+ if(param[2] == '\'') {
+ value = context->alt_regs[Z80_D] << 8;
+ value |= context->alt_regs[Z80_E];
+ } else {
+ value = context->regs[Z80_D] << 8;
+ value |= context->regs[Z80_E];
+ }
+ } else if(param[1] == '\'') {
+ value = context->alt_regs[Z80_D];
+ } else {
+ value = context->regs[Z80_D];
+ }
+ break;
+ case 'e':
+ if(param[1] == '\'') {
+ value = context->alt_regs[Z80_E];
+ } else {
+ value = context->regs[Z80_E];
+ }
+ break;
+ case 'f':
+ if(param[2] == '\'') {
+ value = context->alt_flags[ZF_S] << 7;
+ value |= context->alt_flags[ZF_Z] << 6;
+ value |= context->alt_flags[ZF_H] << 4;
+ value |= context->alt_flags[ZF_PV] << 2;
+ value |= context->alt_flags[ZF_N] << 1;
+ value |= context->alt_flags[ZF_C];
+ } else {
+ value = context->flags[ZF_S] << 7;
+ value |= context->flags[ZF_Z] << 6;
+ value |= context->flags[ZF_H] << 4;
+ value |= context->flags[ZF_PV] << 2;
+ value |= context->flags[ZF_N] << 1;
+ value |= context->flags[ZF_C];
+ }
+ break;
+ case 'h':
+ if (param[1] == 'l') {
+ if(param[2] == '\'') {
+ value = context->alt_regs[Z80_H] << 8;
+ value |= context->alt_regs[Z80_L];
+ } else {
+ value = context->regs[Z80_H] << 8;
+ value |= context->regs[Z80_L];
+ }
+ } else if(param[1] == '\'') {
+ value = context->alt_regs[Z80_H];
+ } else {
+ value = context->regs[Z80_H];
+ }
+ break;
+ case 'l':
+ if(param[1] == '\'') {
+ value = context->alt_regs[Z80_L];
+ } else {
+ value = context->regs[Z80_L];
+ }
+ break;
+ case 'i':
+ if(param[1] == 'x') {
+ if (param[2] == 'h') {
+ value = context->regs[Z80_IXH];
+ } else if(param[2] == 'l') {
+ value = context->regs[Z80_IXL];
+ } else {
+ value = context->regs[Z80_IXH] << 8;
+ value |= context->regs[Z80_IXL];
+ }
+ } else if(param[1] == 'y') {
+ if (param[2] == 'h') {
+ value = context->regs[Z80_IYH];
+ } else if(param[2] == 'l') {
+ value = context->regs[Z80_IYL];
+ } else {
+ value = context->regs[Z80_IYH] << 8;
+ value |= context->regs[Z80_IYL];
+ }
+ } else {
+ value = context->im;
+ }
+ break;
+ case '0':
+ if (param[1] == 'x') {
+ uint16_t p_addr = strtol(param+2, NULL, 16);
+ if (p_addr < 0x4000) {
+ value = z80_ram[p_addr & 0x1FFF];
+ }
+ }
+ break;
+ }
+ printf(format, param, value);
+ break;
+ case 'q':
+ puts("Quitting");
+ exit(0);
+ break;
+ default:
+ fprintf(stderr, "Unrecognized debugger command %s\n", input_buf);
+ break;
+ }
+ }
+ return context;
+}
+
m68k_context * debugger(m68k_context * context, uint32_t address)
{
static char last_cmd[1024];
@@ -1044,7 +1307,7 @@ m68k_context * debugger(m68k_context * context, uint32_t address)
//Check if this is a user set breakpoint, or just a temporary one
bp_def ** this_bp = find_breakpoint(&breakpoints, address);
if (*this_bp) {
- printf("Breakpoint %d hit\n", (*this_bp)->index);
+ printf("68K Breakpoint %d hit\n", (*this_bp)->index);
} else {
remove_breakpoint(context, address);
}
@@ -1054,7 +1317,7 @@ m68k_context * debugger(m68k_context * context, uint32_t address)
} else if(address > 0xE00000) {
pc = ram + (address & 0xFFFF)/2;
} else {
- fprintf(stderr, "Entered debugger at address %X\n", address);
+ fprintf(stderr, "Entered 68K debugger at address %X\n", address);
exit(1);
}
uint16_t * after_pc = m68k_decode(pc, &inst, address);
@@ -1098,7 +1361,7 @@ m68k_context * debugger(m68k_context * context, uint32_t address)
new_bp->address = value;
new_bp->index = bp_index++;
breakpoints = new_bp;
- printf("Breakpoint %d set at %X\n", new_bp->index, value);
+ printf("68K Breakpoint %d set at %X\n", new_bp->index, value);
break;
case 'a':
param = find_param(input_buf);
@@ -1196,6 +1459,29 @@ m68k_context * debugger(m68k_context * context, uint32_t address)
}
break;
}
+ case 'z': {
+ genesis_context * gen = context->system;
+ //Z80 debug commands
+ switch(input_buf[1])
+ {
+ case 'b':
+ param = find_param(input_buf);
+ if (!param) {
+ fputs("zb command requires a parameter\n", stderr);
+ break;
+ }
+ value = strtol(param, NULL, 16);
+ zinsert_breakpoint(gen->z80, value, (uint8_t *)zdebugger);
+ new_bp = malloc(sizeof(bp_def));
+ new_bp->next = zbreakpoints;
+ new_bp->address = value;
+ new_bp->index = zbp_index++;
+ zbreakpoints = new_bp;
+ printf("Z80 Breakpoint %d set at %X\n", new_bp->index, value);
+ break;
+ }
+ break;
+ }
case 'q':
puts("Quitting");
exit(0);
diff --git a/z80_to_x86.c b/z80_to_x86.c
index f2ead45..56b10ec 100644
--- a/z80_to_x86.c
+++ b/z80_to_x86.c
@@ -36,6 +36,8 @@ void z80_retrans_stub();
void z80_io_read();
void z80_io_write();
void z80_halt();
+void z80_save_context();
+void z80_load_context();
uint8_t z80_size(z80inst * inst)
{
@@ -1953,4 +1955,59 @@ void z80_reset(z80_context * context)
context->extra_pc = NULL;
}
+void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler)
+{
+ static uint8_t * bp_stub = NULL;
+ uint8_t * native = z80_get_native_address_trans(context, address);
+ uint8_t * start_native = native;
+ native = mov_ir(native, address, SCRATCH1, SZ_W);
+ if (!bp_stub) {
+ x86_z80_options * opts = context->options;
+ uint8_t * dst = opts->cur_code;
+ uint8_t * dst_end = opts->code_end;
+ if (dst_end - dst < 128) {
+ size_t size = 1024*1024;
+ dst = alloc_code(&size);
+ opts->code_end = dst_end = dst + size;
+ }
+ bp_stub = dst;
+ native = call(native, bp_stub);
+
+ //Calculate length of prologue
+ dst = z80_check_cycles_int(dst, address);
+ int check_int_size = dst-bp_stub;
+ dst = bp_stub;
+
+ //Save context and call breakpoint handler
+ dst = call(dst, (uint8_t *)z80_save_context);
+ dst = push_r(dst, SCRATCH1);
+ dst = mov_rr(dst, CONTEXT, RDI, SZ_Q);
+ dst = mov_rr(dst, SCRATCH1, RSI, SZ_W);
+ dst = call(dst, bp_handler);
+ dst = mov_rr(dst, RAX, CONTEXT, SZ_Q);
+ //Restore context
+ dst = call(dst, (uint8_t *)z80_load_context);
+ dst = pop_r(dst, SCRATCH1);
+ //do prologue stuff
+ dst = cmp_rr(dst, ZCYCLES, ZLIMIT, SZ_D);
+ uint8_t * jmp_off = dst+1;
+ dst = jcc(dst, CC_NC, dst + 7);
+ dst = call(dst, (uint8_t *)z80_handle_cycle_limit_int);
+ *jmp_off = dst - (jmp_off+1);
+ //jump back to body of translated instruction
+ dst = pop_r(dst, SCRATCH1);
+ dst = add_ir(dst, check_int_size - (native-start_native), SCRATCH1, SZ_Q);
+ dst = jmp_r(dst, SCRATCH1);
+ opts->cur_code = dst;
+ } else {
+ native = call(native, bp_stub);
+ }
+}
+
+void zremove_breakpoint(z80_context * context, uint16_t address)
+{
+ uint8_t * native = z80_get_native_address(context, address);
+ z80_check_cycles_int(native, address);
+}
+
diff --git a/z80_to_x86.h b/z80_to_x86.h
index 9c70516..5bcc3a8 100644
--- a/z80_to_x86.h
+++ b/z80_to_x86.h
@@ -59,6 +59,8 @@ uint8_t * z80_get_native_address(z80_context * context, uint32_t address);
z80_context * z80_handle_code_write(uint32_t address, z80_context * context);
void z80_run(z80_context * context);
void z80_reset(z80_context * context);
+void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler);
+void zremove_breakpoint(z80_context * context, uint16_t address);
#endif //Z80_TO_X86_H_