summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pavone <pavone@retrodev.com>2013-01-13 13:01:13 -0800
committerMike Pavone <pavone@retrodev.com>2013-01-13 13:01:13 -0800
commite8f10d79de7c5c3cb59b73b2e0eb326fd4e1085e (patch)
treec4183d6e2f889159e32e735f6a70078b3503958d
parentc9f76989d03409e5323871979d34053fc771c86d (diff)
Fix a bunch of bugs in the CPU core, add a 68K debugger
-rw-r--r--68kinst.c34
-rw-r--r--blastem.c257
-rw-r--r--m68k_to_x86.c188
-rw-r--r--m68k_to_x86.h2
4 files changed, 417 insertions, 64 deletions
diff --git a/68kinst.c b/68kinst.c
index d0e8c20..580d8a5 100644
--- a/68kinst.c
+++ b/68kinst.c
@@ -479,13 +479,13 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
//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.addr_mode = decoded->src.addr_mode;
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;
+ }
}
} else {
if (size == OPSIZE_INVALID) {
@@ -1001,6 +1001,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
//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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
} 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.addr_mode = decoded->src.addr_mode;
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;
+ }
}
} else {
if (size == OPSIZE_INVALID) {
diff --git a/blastem.c b/blastem.c
index 7e653b2..742cf56 100644
--- a/blastem.c
+++ b/blastem.c
@@ -6,6 +6,7 @@
#include "blastem.h"
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#define CARTRIDGE_WORDS 0x200000
#define RAM_WORDS 32 * 1024
@@ -585,6 +586,232 @@ m68k_context * io_read_w(uint32_t location, m68k_context * context)
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 @@ int main(int argc, char ** argv)
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 @@ int main(int argc, char ** argv)
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 --git a/m68k_to_x86.c b/m68k_to_x86.c
index 98ace40..a3e71f4 100644
--- a/m68k_to_x86.c
+++ b/m68k_to_x86.c
@@ -38,6 +38,7 @@ void m68k_write_long_lowfirst();
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 @@ uint8_t * translate_m68k_src(m68kinst * inst, x86_ea * ea, uint8_t * out, x86_68
}
}
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 @@ uint8_t * translate_m68k_dst(m68kinst * inst, x86_ea * ea, uint8_t * out, x86_68
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 @@ uint8_t * translate_m68k_dst(m68kinst * inst, x86_ea * ea, uint8_t * out, x86_68
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 * translate_m68k_dst(m68kinst * inst, x86_ea * ea, uint8_t * out, x86_68
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 @@ uint8_t * translate_m68k_move(uint8_t * dst, m68kinst * inst, x86_68k_options *
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 @@ uint8_t * translate_m68k_move(uint8_t * dst, m68kinst * inst, x86_68k_options *
} 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 @@ uint8_t * translate_m68k_move(uint8_t * dst, m68kinst * inst, x86_68k_options *
} 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 @@ uint8_t * translate_m68k_move(uint8_t * dst, m68kinst * inst, x86_68k_options *
} 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 @@ uint8_t * translate_m68k_move(uint8_t * dst, m68kinst * inst, x86_68k_options *
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 @@ uint8_t * translate_m68k_move(uint8_t * dst, m68kinst * inst, x86_68k_options *
} 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 @@ uint8_t * translate_m68k_move(uint8_t * dst, m68kinst * inst, x86_68k_options *
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 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
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 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
}
}
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 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
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 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
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 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
}
}
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 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
}
}
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 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
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 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
}
}
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 @@ uint8_t * translate_m68k_stream(uint32_t address, m68k_context * context)
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 @@ uint8_t * get_native_address_trans(m68k_context * context, uint32_t address)
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 --git a/m68k_to_x86.h b/m68k_to_x86.h
index 24e6774..e558ee5 100644
--- a/m68k_to_x86.h
+++ b/m68k_to_x86.h
@@ -54,4 +54,6 @@ void start_68k_context(m68k_context * context, uint32_t address);
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);