# HG changeset patch # User Mike Pavone # Date 1358110873 28800 # Node ID ebcbdd1c4cc8cfc9285bf36f4ad21c1f8510e8e1 # Parent 2f08d9e90a4cab8cfd3f2cde903d22e36f3adb1f Fix a bunch of bugs in the CPU core, add a 68K debugger diff -r 2f08d9e90a4c -r ebcbdd1c4cc8 68kinst.c --- a/68kinst.c Wed Jan 09 22:31:07 2013 -0800 +++ b/68kinst.c Sun Jan 13 13:01:13 2013 -0800 @@ -479,13 +479,13 @@ break; #endif } + decoded->dst.addr_mode = MODE_REG; + decoded->dst.addr_mode = m68k_reg_quick_field(*istream); istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; return start+1; } - decoded->dst.addr_mode = MODE_REG; - decoded->dst.addr_mode = m68k_reg_quick_field(*istream); } else { opmode = (*istream >> 3) & 0x7; if ((*istream & 0xB80) == 0x880 && opmode != MODE_REG && opmode != MODE_AREG) { @@ -959,13 +959,13 @@ //SUBX decoded->op = M68K_SUBX; decoded->extra.size = size; - istream = m68k_decode_op(istream, size, &(decoded->src)); - if (!istream) { - decoded->op = M68K_INVALID; - return start+1; + decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream); + decoded->src.params.regs.pri = *istream & 0x7; + if (*istream & 0x8) { + decoded->dst.addr_mode = decoded->src.addr_mode = MODE_AREG_PREDEC; + } else { + decoded->dst.addr_mode = decoded->src.addr_mode = MODE_REG; } - decoded->dst.addr_mode = decoded->src.addr_mode; - decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream); } } else { if (size == OPSIZE_INVALID) { @@ -1001,6 +1001,7 @@ return start+1; } } else { + reg = m68k_reg_quick_field(*istream); istream = m68k_decode_op(istream, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; @@ -1011,12 +1012,12 @@ //CMPM decoded->src.addr_mode = decoded->dst.addr_mode = MODE_AREG_POSTINC; decoded->src.params.regs.pri = decoded->dst.params.regs.pri; - decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream); + decoded->dst.params.regs.pri = reg; } else { //EOR decoded->op = M68K_EOR; decoded->src.addr_mode = MODE_REG; - decoded->src.params.regs.pri = m68k_reg_quick_field(*istream); + decoded->src.params.regs.pri = reg; } } } else { @@ -1142,15 +1143,14 @@ } else { //ADDX decoded->op = M68K_ADDX; - //FIXME: Size is not technically correct decoded->extra.size = size; - istream = m68k_decode_op(istream, size, &(decoded->src)); - if (!istream) { - decoded->op = M68K_INVALID; - return start+1; + decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream); + decoded->src.params.regs.pri = *istream & 0x7; + if (*istream & 0x8) { + decoded->dst.addr_mode = decoded->src.addr_mode = MODE_AREG_PREDEC; + } else { + decoded->dst.addr_mode = decoded->src.addr_mode = MODE_REG; } - decoded->dst.addr_mode = decoded->src.addr_mode; - decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream); } } else { if (size == OPSIZE_INVALID) { diff -r 2f08d9e90a4c -r ebcbdd1c4cc8 blastem.c --- a/blastem.c Wed Jan 09 22:31:07 2013 -0800 +++ b/blastem.c Sun Jan 13 13:01:13 2013 -0800 @@ -6,6 +6,7 @@ #include "blastem.h" #include #include +#include #define CARTRIDGE_WORDS 0x200000 #define RAM_WORDS 32 * 1024 @@ -585,6 +586,232 @@ return context; } +typedef struct bp_def { + struct bp_def * next; + uint32_t address; + uint32_t index; +} bp_def; + +bp_def * breakpoints = NULL; +uint32_t bp_index = 0; + +bp_def ** find_breakpoint(bp_def ** cur, uint32_t address) +{ + while (*cur) { + if ((*cur)->address == address) { + break; + } + cur = &((*cur)->next); + } + return cur; +} + +bp_def ** find_breakpoint_idx(bp_def ** cur, uint32_t index) +{ + while (*cur) { + if ((*cur)->index == index) { + break; + } + cur = &((*cur)->next); + } + return cur; +} + +char * find_param(char * buf) +{ + for (; *buf; buf++) { + if (*buf == ' ') { + if (*(buf+1)) { + return buf+1; + } + } + } + return NULL; +} + +void strip_nl(char * buf) +{ + for(; *buf; buf++) { + if (*buf == '\n') { + *buf = 0; + return; + } + } +} + +m68k_context * debugger(m68k_context * context, uint32_t address) +{ + static char last_cmd[1024]; + char input_buf[1024]; + static uint32_t branch_t; + static uint32_t branch_f; + m68kinst inst; + //probably not necessary, but let's play it safe + address &= 0xFFFFFF; + if (address == branch_t) { + bp_def ** f_bp = find_breakpoint(&breakpoints, branch_f); + if (!*f_bp) { + remove_breakpoint(context, branch_f); + } + branch_t = branch_f = 0; + } else if(address == branch_f) { + bp_def ** t_bp = find_breakpoint(&breakpoints, branch_t); + if (!*t_bp) { + remove_breakpoint(context, branch_t); + } + branch_t = branch_f = 0; + } + //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); + } else { + remove_breakpoint(context, address); + } + uint16_t * pc; + if (address < 0x400000) { + pc = cart + address/2; + } else if(address > 0xE00000) { + pc = ram + (address & 0xFFFF)/2; + } else { + fprintf(stderr, "Entered debugger at address %X\n", address); + exit(1); + } + uint16_t * after_pc = m68k_decode(pc, &inst, address); + m68k_disasm(&inst, input_buf); + printf("%X: %s\n", address, input_buf); + uint32_t after = address + (after_pc-pc)*2; + 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 'c': + puts("Continuing"); + debugging = 0; + break; + case 'b': + param = find_param(input_buf); + if (!param) { + fputs("b command requires a parameter\n", stderr); + break; + } + value = strtol(param, NULL, 16); + insert_breakpoint(context, value, (uint8_t *)debugger); + new_bp = malloc(sizeof(bp_def)); + new_bp->next = breakpoints; + new_bp->address = value; + new_bp->index = bp_index++; + breakpoints = new_bp; + printf("Breakpoint %d set at %X\n", new_bp->index, value); + break; + case 'a': + param = find_param(input_buf); + if (!param) { + fputs("a command requires a parameter\n", stderr); + break; + } + value = strtol(param, NULL, 16); + insert_breakpoint(context, value, (uint8_t *)debugger); + debugging = 0; + break; + case 'd': + param = find_param(input_buf); + if (!param) { + fputs("b command requires a parameter\n", stderr); + break; + } + value = atoi(param); + this_bp = find_breakpoint_idx(&breakpoints, value); + if (!*this_bp) { + fprintf(stderr, "Breakpoint %d does not exist\n", value); + break; + } + new_bp = *this_bp; + *this_bp = (*this_bp)->next; + free(new_bp); + 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; + } + if (param[0] == 'd' && param[1] >= '0' && param[1] <= '7') { + value = context->dregs[param[1]-'0']; + } else if (param[0] == 'a' && param[1] >= '0' && param[1] <= '7') { + value = context->aregs[param[1]-'0']; + } else if (param[0] == 'S' && param[1] == 'R') { + value = (context->status << 8); + for (int flag = 0; flag < 5; flag++) { + value |= context->flags[flag] << (4-flag); + } + } else if (param[0] == '0' && param[1] == 'x') { + uint32_t p_addr = strtol(param+2, NULL, 16); + value = read_dma_value(p_addr/2); + } else { + fprintf(stderr, "Unrecognized parameter to p: %s\n", param); + break; + } + printf(format, param, value); + break; + case 'n': + //TODO: Deal with jmp, dbcc, rtr and rte + if (inst.op == M68K_RTS) { + after = (read_dma_value(context->aregs[7]/2) << 16) | read_dma_value(context->aregs[7]/2 + 1); + } else if(inst.op == M68K_BCC && inst.extra.cond != COND_FALSE) { + if (inst.extra.cond = COND_TRUE) { + after = inst.address + 2 + inst.src.params.immed; + } else { + branch_f = after; + branch_t = inst.address + 2 + inst.src.params.immed; + insert_breakpoint(context, branch_t, (uint8_t *)debugger); + } + } + insert_breakpoint(context, after, (uint8_t *)debugger); + debugging = 0; + break; + case 'q': + puts("Quitting"); + exit(0); + break; + default: + fprintf(stderr, "Unrecognized debugger command %s\n", input_buf); + break; + } + } + return context; +} + int main(int argc, char ** argv) { if (argc < 2) { @@ -595,16 +822,27 @@ fprintf(stderr, "Failed to open %s for reading\n", argv[1]); return 1; } - int width = 320; - int height = 240; - if (argc > 2) { - width = atoi(argv[2]); - if (argc > 3) { - height = atoi(argv[3]); - } else { - height = (width/320) * 240; + int width = -1; + int height = -1; + int debug = 0; + for (int i = 2; i < argc; i++) { + if (argv[i][0] == '-') { + switch(argv[i][1]) { + case 'd': + debug = 1; + break; + default: + fprintf(stderr, "Unrecognized switch %s\n", argv[i]); + return 1; + } + } else if (width < 0) { + width = atoi(argv[i]); + } else if (height < 0) { + height = atoi(argv[i]); } } + width = width < 320 ? 320 : width; + height = height < 240 ? (width/320) * 240 : height; render_init(width, height); x86_68k_options opts; @@ -629,6 +867,9 @@ translate_m68k_stream(address, &context);*/ address = cart[2] << 16 | cart[3]; translate_m68k_stream(address, &context); + if (debug) { + insert_breakpoint(&context, address, (uint8_t *)debugger); + } m68k_reset(&context); return 0; } diff -r 2f08d9e90a4c -r ebcbdd1c4cc8 m68k_to_x86.c --- a/m68k_to_x86.c Wed Jan 09 22:31:07 2013 -0800 +++ b/m68k_to_x86.c Sun Jan 13 13:01:13 2013 -0800 @@ -38,6 +38,7 @@ void m68k_write_long_highfirst(); void m68k_write_byte(); void m68k_save_context(); +void m68k_load_context(); void m68k_modified_ret_addr(); void m68k_native_addr(); void m68k_native_addr_and_sync(); @@ -175,7 +176,7 @@ } } ea->mode = MODE_REG_DIRECT; - ea->base = SCRATCH1; + ea->base = (inst->dst.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) ? SCRATCH2 : SCRATCH1; break; case MODE_AREG_DISPLACE: out = cycles(out, BUS); @@ -392,6 +393,9 @@ ea->disp = reg_offset(&(inst->dst)); break; case MODE_AREG_PREDEC: + if (inst->src.addr_mode == MODE_AREG_PREDEC) { + out = push_r(out, SCRATCH1); + } dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1)); if (opts->aregs[inst->dst.params.regs.pri] >= 0) { out = sub_ir(out, dec_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D); @@ -421,11 +425,16 @@ break; } } - //save reg value in SCRATCH2 so we can use it to save the result in memory later - if (opts->aregs[inst->dst.params.regs.pri] >= 0) { - out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D); + if (inst->src.addr_mode == MODE_AREG_PREDEC) { + //restore src operand to SCRATCH2 + out =pop_r(out, SCRATCH2); } else { - out = mov_rdisp8r(out, CONTEXT, reg_offset(&(inst->dst)), SCRATCH2, SZ_D); + //save reg value in SCRATCH2 so we can use it to save the result in memory later + if (opts->aregs[inst->dst.params.regs.pri] >= 0) { + out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D); + } else { + out = mov_rdisp8r(out, CONTEXT, reg_offset(&(inst->dst)), SCRATCH2, SZ_D); + } } if (inst->dst.addr_mode == MODE_AREG_POSTINC) { @@ -644,6 +653,13 @@ uint8_t * m68k_save_result(m68kinst * inst, uint8_t * out, x86_68k_options * opts) { if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG) { + if (inst->dst.addr_mode == MODE_AREG_PREDEC && inst->src.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) { + if (opts->aregs[inst->dst.params.regs.pri] >= 0) { + out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D); + } else { + out = mov_rdisp8r(out, CONTEXT, reg_offset(&(inst->dst)), SCRATCH2, SZ_D); + } + } switch (inst->extra.size) { case OPSIZE_BYTE: @@ -737,9 +753,11 @@ x86_ea src; dst = translate_m68k_src(inst, &src, dst, opts); reg = native_reg(&(inst->dst), opts); - //update statically set flags - dst = mov_ir(dst, 0, FLAG_V, SZ_B); - dst = mov_ir(dst, 0, FLAG_C, SZ_B); + if (inst->dst.addr_mode != MODE_AREG) { + //update statically set flags + dst = mov_ir(dst, 0, FLAG_V, SZ_B); + dst = mov_ir(dst, 0, FLAG_C, SZ_B); + } if (src.mode == MODE_REG_DIRECT) { flags_reg = src.base; @@ -775,9 +793,11 @@ } else { dst = mov_irdisp8(dst, src.disp, CONTEXT, reg_offset(&(inst->dst)), size); } - dst = cmp_ir(dst, 0, flags_reg, size); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); + if (inst->dst.addr_mode != MODE_AREG) { + dst = cmp_ir(dst, 0, flags_reg, size); + dst = setcc_r(dst, CC_Z, FLAG_Z); + dst = setcc_r(dst, CC_S, FLAG_N); + } break; case MODE_AREG_PREDEC: dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1)); @@ -802,9 +822,11 @@ } else { dst = mov_ir(dst, src.disp, SCRATCH1, inst->extra.size); } - dst = cmp_ir(dst, 0, flags_reg, inst->extra.size); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); + if (inst->dst.addr_mode != MODE_AREG) { + dst = cmp_ir(dst, 0, flags_reg, inst->extra.size); + dst = setcc_r(dst, CC_Z, FLAG_Z); + dst = setcc_r(dst, CC_S, FLAG_N); + } switch (inst->extra.size) { case OPSIZE_BYTE: @@ -843,9 +865,11 @@ } else { dst = mov_ir(dst, src.disp, SCRATCH1, inst->extra.size); } - dst = cmp_ir(dst, 0, flags_reg, inst->extra.size); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); + if (inst->dst.addr_mode != MODE_AREG) { + dst = cmp_ir(dst, 0, flags_reg, inst->extra.size); + dst = setcc_r(dst, CC_Z, FLAG_Z); + dst = setcc_r(dst, CC_S, FLAG_N); + } switch (inst->extra.size) { case OPSIZE_BYTE: @@ -906,9 +930,20 @@ if (inst->dst.params.regs.displacement) { dst = add_ir(dst, inst->dst.params.regs.displacement, SCRATCH2, SZ_D); } - dst = cmp_ir(dst, 0, flags_reg, inst->extra.size); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); + if (src.mode == MODE_REG_DIRECT) { + if (src.base != SCRATCH1) { + dst = mov_rr(dst, src.base, SCRATCH1, inst->extra.size); + } + } else if (src.mode == MODE_REG_DISPLACE8) { + dst = mov_rdisp8r(dst, src.base, src.disp, SCRATCH1, inst->extra.size); + } else { + dst = mov_ir(dst, src.disp, SCRATCH1, inst->extra.size); + } + if (inst->dst.addr_mode != MODE_AREG) { + dst = cmp_ir(dst, 0, flags_reg, inst->extra.size); + dst = setcc_r(dst, CC_Z, FLAG_Z); + dst = setcc_r(dst, CC_S, FLAG_N); + } switch (inst->extra.size) { case OPSIZE_BYTE: @@ -934,9 +969,11 @@ } else { dst = mov_ir(dst, src.disp, SCRATCH1, inst->extra.size); } - dst = cmp_ir(dst, 0, flags_reg, inst->extra.size); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); + if (inst->dst.addr_mode != MODE_AREG) { + dst = cmp_ir(dst, 0, flags_reg, inst->extra.size); + dst = setcc_r(dst, CC_Z, FLAG_Z); + dst = setcc_r(dst, CC_S, FLAG_N); + } switch (inst->extra.size) { case OPSIZE_BYTE: @@ -967,9 +1004,11 @@ dst = cycles(dst, BUS); } dst = mov_ir(dst, inst->dst.params.immed, SCRATCH2, SZ_D); - dst = cmp_ir(dst, 0, flags_reg, inst->extra.size); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); + if (inst->dst.addr_mode != MODE_AREG) { + dst = cmp_ir(dst, 0, flags_reg, inst->extra.size); + dst = setcc_r(dst, CC_Z, FLAG_Z); + dst = setcc_r(dst, CC_S, FLAG_N); + } switch (inst->extra.size) { case OPSIZE_BYTE: @@ -2621,11 +2660,13 @@ dst = add_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, size); } } - dst = setcc_r(dst, CC_C, FLAG_C); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - dst = setcc_r(dst, CC_O, FLAG_V); - dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); + if (inst->dst.addr_mode != MODE_AREG) { + dst = setcc_r(dst, CC_C, FLAG_C); + dst = setcc_r(dst, CC_Z, FLAG_Z); + dst = setcc_r(dst, CC_S, FLAG_N); + dst = setcc_r(dst, CC_O, FLAG_V); + dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); + } dst = m68k_save_result(inst, dst, opts); break; case M68K_ADDX: @@ -2647,7 +2688,8 @@ } } dst = setcc_r(dst, CC_C, FLAG_C); - dst = setcc_r(dst, CC_Z, FLAG_Z); + dst = jcc(dst, CC_Z, dst+4); + dst = mov_ir(dst, 0, FLAG_Z, SZ_B); dst = setcc_r(dst, CC_S, FLAG_N); dst = setcc_r(dst, CC_O, FLAG_V); dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); @@ -2710,6 +2752,7 @@ break; case M68K_ASL: case M68K_LSL: + //TODO: Check overflow flag behavior dst = translate_shift(dst, inst, &src_op, &dst_op, opts, shl_ir, shl_irdisp8, shl_clr, shl_clrdisp8, shr_ir, shr_irdisp8); break; case M68K_ASR: @@ -3294,6 +3337,7 @@ dst = cmp_ir(dst, 0, dst_op.base, inst->extra.size); dst = setcc_r(dst, CC_Z, FLAG_Z); dst = setcc_r(dst, CC_S, FLAG_N); + dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); dst = m68k_save_result(inst, dst, opts); } else { if (src_op.mode == MODE_IMMED) { @@ -3313,6 +3357,7 @@ } } dst = setcc_r(dst, CC_C, FLAG_C); + dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); } else { if (src_op.mode == MODE_REG_DIRECT) { if (src_op.base != SCRATCH1) { @@ -3364,10 +3409,12 @@ } } dst = setcc_r(dst, CC_C, FLAG_C); + dst = mov_rr(dst, FLAG_C, CONTEXT, SZ_B); end_off = dst + 1; dst = jmp(dst, dst+2); *zero_off = dst - (zero_off+1); - dst = mov_ir(dst, 0, FLAG_C, SZ_B); + //Carry flag is set to X flag when count is 0, this is different from ROR/ROL + dst = mov_rindr(dst, CONTEXT, FLAG_C, SZ_B); *end_off = dst - (end_off+1); } if (dst_op.mode == MODE_REG_DIRECT) { @@ -3437,11 +3484,13 @@ dst = sub_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, size); } } - dst = setcc_r(dst, CC_C, FLAG_C); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - dst = setcc_r(dst, CC_O, FLAG_V); - dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); + if (inst->dst.addr_mode != MODE_AREG) { + dst = setcc_r(dst, CC_C, FLAG_C); + dst = setcc_r(dst, CC_Z, FLAG_Z); + dst = setcc_r(dst, CC_S, FLAG_N); + dst = setcc_r(dst, CC_O, FLAG_V); + dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); + } dst = m68k_save_result(inst, dst, opts); break; case M68K_SUBX: @@ -3463,7 +3512,8 @@ } } dst = setcc_r(dst, CC_C, FLAG_C); - dst = setcc_r(dst, CC_Z, FLAG_Z); + dst = jcc(dst, CC_Z, dst+4); + dst = mov_ir(dst, 0, FLAG_Z, SZ_B); dst = setcc_r(dst, CC_S, FLAG_N); dst = setcc_r(dst, CC_O, FLAG_V); dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); @@ -3562,6 +3612,11 @@ dst = call(dst, (uint8_t *)exit); break; } + uint8_t * existing = get_native_address(opts->native_code_map, address); + if (existing) { + dst = jmp(dst, existing); + break; + } next = m68k_decode(encoded, &instbuf, address); address += (next-encoded)*2; encoded = next; @@ -3599,6 +3654,61 @@ return ret; } +void insert_breakpoint(m68k_context * context, uint32_t address, uint8_t * bp_handler) +{ + static uint8_t * bp_stub = NULL; + uint8_t * native = get_native_address_trans(context, address); + uint8_t * start_native = native; + native = mov_ir(native, address, SCRATCH1, SZ_D); + if (!bp_stub) { + x86_68k_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 = 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 *)m68k_save_context); + dst = push_r(dst, SCRATCH1); + dst = mov_rr(dst, CONTEXT, RDI, SZ_Q); + dst = mov_rr(dst, SCRATCH1, RSI, SZ_D); + dst = call(dst, bp_handler); + dst = mov_rr(dst, RAX, CONTEXT, SZ_Q); + //Restore context + dst = call(dst, (uint8_t *)m68k_load_context); + dst = pop_r(dst, SCRATCH1); + //do prologue stuff + dst = cmp_rr(dst, CYCLES, LIMIT, SZ_D); + uint8_t * jmp_off = dst+1; + dst = jcc(dst, CC_NC, dst + 7); + dst = call(dst, (uint8_t *)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 remove_breakpoint(m68k_context * context, uint32_t address) +{ + uint8_t * native = get_native_address(context->native_code_map, address); + check_cycles_int(native, address); +} + void start_68k_context(m68k_context * context, uint32_t address) { uint8_t * addr = get_native_address(context->native_code_map, address); diff -r 2f08d9e90a4c -r ebcbdd1c4cc8 m68k_to_x86.h --- a/m68k_to_x86.h Wed Jan 09 22:31:07 2013 -0800 +++ b/m68k_to_x86.h Sun Jan 13 13:01:13 2013 -0800 @@ -54,4 +54,6 @@ void init_x86_68k_opts(x86_68k_options * opts); void init_68k_context(m68k_context * context, native_map_slot * native_code_map, void * opts); void m68k_reset(m68k_context * context); +void insert_breakpoint(m68k_context * context, uint32_t address, uint8_t * bp_handler); +void remove_breakpoint(m68k_context * context, uint32_t address);