summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pavone <pavone@retrodev.com>2012-12-28 17:57:43 -0800
committerMike Pavone <pavone@retrodev.com>2012-12-28 17:57:43 -0800
commitc7827141fecf66bc83c5cbb1cd0a38fd925e2689 (patch)
tree6e75a422071112c0350c13f9304857fe47435ac2
parentbd5260222653289a71a49fa5093e33204112b3e0 (diff)
Implement scc (untested)
-rw-r--r--gen_x86.c13
-rw-r--r--gen_x86.h1
-rw-r--r--m68k_to_x86.c94
3 files changed, 108 insertions, 0 deletions
diff --git a/gen_x86.c b/gen_x86.c
index 2708c13..23dbba5 100644
--- a/gen_x86.c
+++ b/gen_x86.c
@@ -1069,6 +1069,19 @@ uint8_t * setcc_rind(uint8_t * out, uint8_t cc, uint8_t dst)
return out;
}
+uint8_t * setcc_rdisp8(uint8_t * out, uint8_t cc, uint8_t dst, int8_t disp)
+{
+ if (dst >= R8) {
+ *(out++) = PRE_REX | REX_RM_FIELD;
+ dst -= R8 - X86_R8;
+ }
+ *(out++) = PRE_2BYTE;
+ *(out++) = OP2_SETCC | cc;
+ *(out++) = MODE_REG_DISPLACE8 | dst;
+ *(out++) = disp;
+ return out;
+}
+
uint8_t * bt_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
{
if (size == SZ_W) {
diff --git a/gen_x86.h b/gen_x86.h
index ebc1f97..ff58a2b 100644
--- a/gen_x86.h
+++ b/gen_x86.h
@@ -143,6 +143,7 @@ uint8_t * push_r(uint8_t * out, uint8_t reg);
uint8_t * pop_r(uint8_t * out, uint8_t reg);
uint8_t * setcc_r(uint8_t * out, uint8_t cc, uint8_t dst);
uint8_t * setcc_rind(uint8_t * out, uint8_t cc, uint8_t dst);
+uint8_t * setcc_rdisp8(uint8_t * out, uint8_t cc, uint8_t dst, int8_t disp);
uint8_t * bt_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size);
uint8_t * bt_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size);
uint8_t * bt_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size);
diff --git a/m68k_to_x86.c b/m68k_to_x86.c
index 5b0c8a1..06d0e63 100644
--- a/m68k_to_x86.c
+++ b/m68k_to_x86.c
@@ -1338,6 +1338,98 @@ uint8_t * translate_m68k_bcc(uint8_t * dst, m68kinst * inst, x86_68k_options * o
return dst;
}
+uint8_t * translate_m68k_scc(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
+{
+ uint8_t cond = inst->extra.cond;
+ x86_ea dst_op;
+ inst->extra.size = OPSIZE_BYTE;
+ dst = translate_m68k_dst(inst, &dst_op, dst, opts, 1);
+ if (cond == COND_TRUE || cond == COND_FALSE) {
+ if ((inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG) && inst->extra.cond == COND_TRUE) {
+ dst = cycles(dst, 6);
+ } else {
+ dst = cycles(dst, BUS);
+ }
+ if (dst_op.mode == MODE_REG_DIRECT) {
+ dst = mov_ir(dst, cond == COND_TRUE, dst_op.base, SZ_B);
+ } else {
+ dst = mov_irdisp8(dst, cond == COND_TRUE, dst_op.base, dst_op.disp, SZ_B);
+ }
+ } else {
+ uint8_t cc = CC_NZ;
+ switch (cond)
+ {
+ case COND_HIGH:
+ cc = CC_Z;
+ case COND_LOW_SAME:
+ dst = mov_rr(dst, FLAG_Z, SCRATCH1, SZ_B);
+ dst = or_rr(dst, FLAG_C, SCRATCH1, SZ_B);
+ break;
+ case COND_CARRY_CLR:
+ cc = CC_Z;
+ case COND_CARRY_SET:
+ dst = cmp_ir(dst, 0, FLAG_C, SZ_B);
+ break;
+ case COND_NOT_EQ:
+ cc = CC_Z;
+ case COND_EQ:
+ dst = cmp_ir(dst, 0, FLAG_Z, SZ_B);
+ break;
+ case COND_OVERF_CLR:
+ cc = CC_Z;
+ case COND_OVERF_SET:
+ dst = cmp_ir(dst, 0, FLAG_V, SZ_B);
+ break;
+ case COND_PLUS:
+ cc = CC_Z;
+ case COND_MINUS:
+ dst = cmp_ir(dst, 0, FLAG_N, SZ_B);
+ break;
+ case COND_GREATER_EQ:
+ cc = CC_Z;
+ case COND_LESS:
+ dst = cmp_rr(dst, FLAG_N, FLAG_V, SZ_B);
+ break;
+ case COND_GREATER:
+ cc = CC_Z;
+ case COND_LESS_EQ:
+ dst = mov_rr(dst, FLAG_V, SCRATCH1, SZ_B);
+ dst = xor_rr(dst, FLAG_N, SCRATCH1, SZ_B);
+ dst = or_rr(dst, FLAG_Z, SCRATCH1, SZ_B);
+ break;
+ }
+ if ((inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG)) {
+ uint8_t *true_off = dst + 1;
+ dst = jcc(dst, cc, dst+2);
+ dst = cycles(dst, BUS);
+ if (dst_op.mode == MODE_REG_DIRECT) {
+ dst = mov_ir(dst, 0, dst_op.base, SZ_B);
+ } else {
+ dst = mov_irdisp8(dst, 0, dst_op.base, dst_op.disp, SZ_B);
+ }
+ uint8_t *end_off = dst+1;
+ dst = jmp(dst, dst+2);
+ *true_off = dst - (true_off+1);
+ dst = cycles(dst, 6);
+ if (dst_op.mode == MODE_REG_DIRECT) {
+ dst = mov_ir(dst, 1, dst_op.base, SZ_B);
+ } else {
+ dst = mov_irdisp8(dst, 1, dst_op.base, dst_op.disp, SZ_B);
+ }
+ *end_off = dst - (end_off+1);
+ } else {
+ dst = cycles(dst, BUS);
+ if (dst_op.mode == MODE_REG_DIRECT) {
+ dst = setcc_r(dst, cc, dst_op.base);
+ } else {
+ dst = setcc_rdisp8(dst, cc, dst_op.base, dst_op.disp);
+ }
+ }
+ }
+ dst = m68k_save_result(inst, dst, opts);
+ return dst;
+}
+
uint8_t * translate_m68k_jmp(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
{
uint8_t * dest_addr;
@@ -1795,6 +1887,8 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
return translate_m68k_link(dst, inst, opts);
} else if(inst->op == M68K_EXT) {
return translate_m68k_ext(dst, inst, opts);
+ } else if(inst->op == M68K_SCC) {
+ return translate_m68k_scc(dst, inst, opts);
}
x86_ea src_op, dst_op;
if (inst->src.addr_mode != MODE_UNUSED) {