summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--68kinst.c18
-rw-r--r--68kinst.h1
-rw-r--r--gen_x86.c107
-rw-r--r--gen_x86.h4
-rw-r--r--m68k_to_x86.c69
5 files changed, 192 insertions, 7 deletions
diff --git a/68kinst.c b/68kinst.c
index a9033d7..a6ed994 100644
--- a/68kinst.c
+++ b/68kinst.c
@@ -124,8 +124,11 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
}
decoded->src.addr_mode = MODE_REG;
decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
- decoded->extra.size = OPSIZE_LONG;
- istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->dst));
+ decoded->extra.size = OPSIZE_BYTE;
+ istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst));
+ if (decoded->dst.addr_mode == MODE_REG) {
+ decoded->extra.size = OPSIZE_LONG;
+ }
} else if ((*istream & 0xF00) == 0x800) {
//BTST, BCHG, BCLR, BSET
switch ((*istream >> 6) & 0x3)
@@ -145,10 +148,13 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
}
opmode = (*istream >> 3) & 0x7;
reg = *istream & 0x7;
- decoded->src.addr_mode = MODE_IMMEDIATE;
+ decoded->src.addr_mode = MODE_IMMEDIATE_WORD;
decoded->src.params.immed = *(++istream) & 0xFF;
decoded->extra.size = OPSIZE_BYTE;
- istream = m68k_decode_op_ex(istream, opmode, reg, OPSIZE_BYTE, &(decoded->dst));
+ istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst));
+ if (decoded->dst.addr_mode == MODE_REG) {
+ decoded->extra.size = OPSIZE_LONG;
+ }
} else if ((*istream & 0xC0) == 0xC0) {
#ifdef M68020
//CMP2, CHK2, CAS, CAS2, RTM, CALLM
@@ -407,7 +413,8 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
decoded->dst.addr_mode = m68k_reg_quick_field(*istream);
} else {
opmode = (*istream >> 3) & 0x7;
- if ((*istream & 0xB80) == 0x880 && opmode != MODE_REG && opmode != MODE_AREG && opmode != MODE_AREG_POSTINC) {
+ if ((*istream & 0xB80) == 0x880 && opmode != MODE_REG && opmode != MODE_AREG) {
+ //TODO: Check for invalid modes that are dependent on direction
decoded->op = M68K_MOVEM;
decoded->extra.size = *istream & 0x40 ? OPSIZE_LONG : OPSIZE_WORD;
reg = *istream & 0x7;
@@ -1143,6 +1150,7 @@ int m68k_disasm_op(m68k_op_info *decoded, char *dst, int need_comma)
case MODE_AREG_DISPLACE:
return sprintf(dst, "%s (a%d, %d)", c, decoded->params.regs.pri, decoded->params.regs.displacement);
case MODE_IMMEDIATE:
+ case MODE_IMMEDIATE_WORD:
return sprintf(dst, "%s #%d", c, decoded->params.immed);
case MODE_ABSOLUTE_SHORT:
return sprintf(dst, "%s $%X.w", c, decoded->params.immed);
diff --git a/68kinst.h b/68kinst.h
index 209ea29..872bd2e 100644
--- a/68kinst.h
+++ b/68kinst.h
@@ -128,6 +128,7 @@ typedef enum {
MODE_PC_DISPLACE,
MODE_PC_INDEX,
MODE_IMMEDIATE,
+ MODE_IMMEDIATE_WORD,//used to indicate an immediate operand that only uses a single extension word even for a long operation
MODE_UNUSED
} m68k_addr_modes;
diff --git a/gen_x86.c b/gen_x86.c
index 9f10429..dbe58ca 100644
--- a/gen_x86.c
+++ b/gen_x86.c
@@ -40,6 +40,8 @@
#define OP2_JCC 0x80
#define OP2_SETCC 0x90
+#define OP2_BT 0xA3
+#define OP2_BTX_I 0xBA
#define OP_EX_ADDI 0x0
#define OP_EX_ORI 0x1
@@ -59,6 +61,11 @@
#define OP_EX_SAL 0x6 //identical to SHL
#define OP_EX_SAR 0x7
+#define OP_EX_BT 0x4
+#define OP_EX_BTS 0x5
+#define OP_EX_BTR 0x6
+#define OP_EX_BTC 0x7
+
#define BIT_IMMED_RAX 0x4
#define BIT_DIR 0x2
#define BIT_SIZE 0x1
@@ -880,6 +887,106 @@ uint8_t * setcc_rind(uint8_t * out, uint8_t cc, uint8_t dst)
return out;
}
+uint8_t * bt_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
+{
+ if (size == SZ_W) {
+ *(out++) = PRE_SIZE;
+ }
+ if (size == SZ_Q || src >= R8 || dst >= R8) {
+ *out = PRE_REX;
+ if (size == SZ_Q) {
+ *out |= REX_QUAD;
+ }
+ if (src >= R8) {
+ *out |= REX_REG_FIELD;
+ src -= (R8 - X86_R8);
+ }
+ if (dst >= R8) {
+ *out |= REX_RM_FIELD;
+ dst -= (R8 - X86_R8);
+ }
+ out++;
+ }
+ *(out++) = PRE_2BYTE;
+ *(out++) = OP2_BT;
+ *(out++) = MODE_REG_DIRECT | dst | (src << 3);
+ return out;
+}
+
+uint8_t * bt_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size)
+{
+ if (size == SZ_W) {
+ *(out++) = PRE_SIZE;
+ }
+ if (size == SZ_Q || src >= R8 || dst_base >= R8) {
+ *out = PRE_REX;
+ if (size == SZ_Q) {
+ *out |= REX_QUAD;
+ }
+ if (src >= R8) {
+ *out |= REX_REG_FIELD;
+ src -= (R8 - X86_R8);
+ }
+ if (dst_base >= R8) {
+ *out |= REX_RM_FIELD;
+ dst_base -= (R8 - X86_R8);
+ }
+ out++;
+ }
+ *(out++) = PRE_2BYTE;
+ *(out++) = OP2_BT;
+ *(out++) = MODE_REG_DISPLACE8 | dst_base | (src << 3);
+ *(out++) = dst_disp;
+ return out;
+}
+
+uint8_t * bt_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size)
+{
+ if (size == SZ_W) {
+ *(out++) = PRE_SIZE;
+ }
+ if (size == SZ_Q || dst >= R8) {
+ *out = PRE_REX;
+ if (size == SZ_Q) {
+ *out |= REX_QUAD;
+ }
+ if (dst >= R8) {
+ *out |= REX_RM_FIELD;
+ dst -= (R8 - X86_R8);
+ }
+ out++;
+ }
+ *(out++) = PRE_2BYTE;
+ *(out++) = OP2_BTX_I;
+ *(out++) = MODE_REG_DIRECT | dst | (OP_EX_BT << 3);
+ *(out++) = val;
+ return out;
+}
+
+uint8_t * bt_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size)
+{
+ if (size == SZ_W) {
+ *(out++) = PRE_SIZE;
+ }
+ if (size == SZ_Q || dst_base >= R8) {
+ *out = PRE_REX;
+ if (size == SZ_Q) {
+ *out |= REX_QUAD;
+ }
+ if (dst_base >= R8) {
+ *out |= REX_RM_FIELD;
+ dst_base -= (R8 - X86_R8);
+ }
+ out++;
+ }
+ *(out++) = PRE_2BYTE;
+ *(out++) = OP2_BTX_I;
+ *(out++) = MODE_REG_DISPLACE8 | dst_base | (OP_EX_BT << 3);
+ *(out++) = dst_disp;
+ *(out++) = val;
+ return out;
+}
+
uint8_t * jcc(uint8_t * out, uint8_t cc, uint8_t * dest)
{
ptrdiff_t disp = dest-(out+2);
diff --git a/gen_x86.h b/gen_x86.h
index b48f8ac..062fe1a 100644
--- a/gen_x86.h
+++ b/gen_x86.h
@@ -136,6 +136,10 @@ 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 * 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);
+uint8_t * bt_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size);
uint8_t * jcc(uint8_t * out, uint8_t cc, uint8_t *dest);
uint8_t * jmp(uint8_t * out, uint8_t *dest);
uint8_t * call(uint8_t * out, uint8_t * fun);
diff --git a/m68k_to_x86.c b/m68k_to_x86.c
index 2b6abba..262dfab 100644
--- a/m68k_to_x86.c
+++ b/m68k_to_x86.c
@@ -175,8 +175,9 @@ uint8_t * translate_m68k_src(m68kinst * inst, x86_ea * ea, uint8_t * out, x86_68
ea->base = SCRATCH1;
break;
case MODE_IMMEDIATE:
+ case MODE_IMMEDIATE_WORD:
if (inst->variant != VAR_QUICK) {
- if (inst->extra.size == OPSIZE_LONG) {
+ if (inst->extra.size == OPSIZE_LONG && inst->src.addr_mode == MODE_IMMEDIATE) {
out = cycles(out, BUS);
out = check_cycles(out);
}
@@ -254,6 +255,32 @@ uint8_t * translate_m68k_dst(m68kinst * inst, x86_ea * ea, uint8_t * out, x86_68
ea->mode = MODE_REG_DIRECT;
ea->base = SCRATCH1;
break;
+ case MODE_ABSOLUTE:
+ case MODE_ABSOLUTE_SHORT:
+ //Add cycles for reading address from instruction stream
+ if (inst->dst.addr_mode == MODE_ABSOLUTE) {
+ out = cycles(out, BUS*2);
+ } else {
+ out = cycles(out, BUS);
+ }
+ out = mov_ir(out, inst->dst.params.immed, SCRATCH1, SZ_D);
+ out = push_r(out, SCRATCH1);
+ switch (inst->extra.size)
+ {
+ case OPSIZE_BYTE:
+ out = call(out, (char *)m68k_read_byte_scratch1);
+ break;
+ case OPSIZE_WORD:
+ out = call(out, (char *)m68k_read_word_scratch1);
+ break;
+ case OPSIZE_LONG:
+ out = call(out, (char *)m68k_read_long_scratch1);
+ break;
+ }
+ out = pop_r(out, SCRATCH2);
+ ea->mode = MODE_REG_DIRECT;
+ ea->base = SCRATCH1;
+ break;
default:
printf("address mode %d not implemented (dst)\n", inst->dst.addr_mode);
exit(1);
@@ -1010,7 +1037,46 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
case M68K_BCHG:
case M68K_BCLR:
case M68K_BSET:
+ break;
case M68K_BTST:
+ dst = cycles(dst, inst->extra.size == OPSIZE_BYTE ? 4 : 6);
+ if (src_op.mode == MODE_IMMEDIATE) {
+ if (inst->extra.size == OPSIZE_BYTE) {
+ src_op.disp &= 0x7;
+ }
+ if (dst_op.mode == MODE_REG_DIRECT) {
+ dst = bt_ir(dst, src_op.disp, dst_op.base, SZ_D);
+ } else {
+ dst = bt_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, SZ_D);
+ }
+ } else {
+ if (src_op.mode == MODE_REG_DISPLACE8) {
+ if (dst_op.base == SCRATCH1) {
+ dst = push_r(dst, SCRATCH2);
+ dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH2, SZ_B);
+ src_op.base = SCRATCH1;
+ } else {
+ dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_B);
+ src_op.base = SCRATCH1;
+ }
+ }
+ if (inst->extra.size == OPSIZE_BYTE) {
+ dst = and_ir(dst, 0x7, src_op.base, SZ_B);
+ }
+ if (dst_op.mode == MODE_REG_DIRECT) {
+ dst = bt_rr(dst, src_op.base, dst_op.base, SZ_D);
+ } else {
+ dst = bt_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, SZ_D);
+ }
+ }
+ //x86 sets the carry flag to the value of the bit tested
+ //68K sets the zero flag to the complement of the bit tested
+ dst = setcc_r(dst, CC_NC, FLAG_Z);
+ if (src_op.base == SCRATCH2) {
+ dst = pop_r(dst, SCRATCH2);
+ }
+ dst = m68k_save_result(inst, dst, opts);
+ break;
case M68K_CHK:
break;
case M68K_CMP:
@@ -1096,7 +1162,6 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
dst = mov_rr(dst, CONTEXT, RDI, SZ_Q);
dst = call(dst, (uint8_t *)print_regs_exit);
break;
- case M68K_JMP:
case M68K_JSR:
case M68K_LEA:
case M68K_LINK: