summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pavone <pavone@retrodev.com>2012-12-04 19:13:12 -0800
committerMike Pavone <pavone@retrodev.com>2012-12-04 19:13:12 -0800
commit854a8a9abf29e5cab28871f7a81d0fd1e7474b3d (patch)
tree54651ed6d72de7191718ba8e26e015e2ee2720ef
parente54fddc285255b26e7e0ca69db3efb009cfc9c15 (diff)
M68K to x86 translation works for a limited subset of instructions and addressing modes
-rw-r--r--68kinst.c53
-rw-r--r--68kinst.h5
-rw-r--r--Makefile12
-rw-r--r--dis.c4
-rw-r--r--gen_x86.c253
-rw-r--r--gen_x86.h35
-rw-r--r--m68k_to_x86.c774
-rw-r--r--m68k_to_x86.h46
-rw-r--r--mem.c25
-rw-r--r--notes.txt19
-rw-r--r--runtime.S163
-rw-r--r--trans.c39
12 files changed, 1254 insertions, 174 deletions
diff --git a/68kinst.c b/68kinst.c
index 1171aca..eddbde9 100644
--- a/68kinst.c
+++ b/68kinst.c
@@ -86,12 +86,12 @@ void m68k_decode_cond(uint16_t op, m68kinst * decoded)
decoded->extra.cond = (op >> 0x8) & 0xF;
}
-uint8_t m68K_reg_quick_field(uint16_t op)
+uint8_t m68k_reg_quick_field(uint16_t op)
{
return (op >> 9) & 0x7;
}
-uint16_t * m68K_decode(uint16_t * istream, m68kinst * decoded)
+uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
{
uint8_t optype = *istream >> 12;
uint8_t size;
@@ -101,6 +101,7 @@ uint16_t * m68K_decode(uint16_t * istream, m68kinst * decoded)
decoded->op = M68K_INVALID;
decoded->src.addr_mode = decoded->dst.addr_mode = MODE_UNUSED;
decoded->variant = VAR_NORMAL;
+ decoded->address = address;
switch(optype)
{
case BIT_MOVEP_IMMED:
@@ -122,7 +123,7 @@ uint16_t * m68K_decode(uint16_t * istream, m68kinst * decoded)
break;
}
decoded->src.addr_mode = MODE_REG;
- decoded->src.params.regs.pri = m68K_reg_quick_field(*istream);
+ decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
decoded->extra.size = OPSIZE_LONG;
istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->dst));
} else if ((*istream & 0xF00) == 0x800) {
@@ -353,13 +354,13 @@ uint16_t * m68K_decode(uint16_t * istream, m68kinst * decoded)
if (*istream & 0x80) {
//memory dest
decoded->src.addr_mode = MODE_REG;
- decoded->src.params.regs.pri = m68K_reg_quick_field(*istream);
+ decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
decoded->dst.addr_mode = MODE_AREG_DISPLACE;
decoded->dst.params.regs.pri = *istream & 0x7;
} else {
//memory source
decoded->dst.addr_mode = MODE_REG;
- decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream);
+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
decoded->src.addr_mode = MODE_AREG_DISPLACE;
decoded->src.params.regs.pri = *istream & 0x7;
}
@@ -374,8 +375,10 @@ uint16_t * m68K_decode(uint16_t * istream, m68kinst * decoded)
case MOVE_WORD:
decoded->op = M68K_MOVE;
decoded->extra.size = optype == MOVE_BYTE ? OPSIZE_BYTE : (optype == MOVE_WORD ? OPSIZE_WORD : OPSIZE_LONG);
+ opmode = (*istream >> 6) & 0x7;
+ reg = m68k_reg_quick_field(*istream);
istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
- istream = m68k_decode_op_ex(istream, (*istream >> 6) & 0x7, m68K_reg_quick_field(*istream), decoded->extra.size, &(decoded->dst));
+ istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst));
break;
case MISC:
@@ -383,7 +386,7 @@ uint16_t * m68K_decode(uint16_t * istream, m68kinst * decoded)
decoded->op = M68K_LEA;
decoded->extra.size = OPSIZE_LONG;
decoded->dst.addr_mode = MODE_AREG;
- decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream);
+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
} else {
if (*istream & 0x100) {
@@ -401,7 +404,7 @@ uint16_t * m68K_decode(uint16_t * istream, m68kinst * decoded)
}
istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
decoded->dst.addr_mode = MODE_REG;
- decoded->dst.addr_mode = m68K_reg_quick_field(*istream);
+ 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) {
@@ -684,7 +687,7 @@ uint16_t * m68K_decode(uint16_t * istream, m68kinst * decoded)
decoded->extra.size = size;
decoded->src.addr_mode = MODE_IMMEDIATE;
istream = m68k_decode_op(istream, size, &(decoded->dst));
- immed = m68K_reg_quick_field(*istream);
+ immed = m68k_reg_quick_field(*istream);
if (!immed) {
immed = 8;
}
@@ -722,7 +725,7 @@ uint16_t * m68K_decode(uint16_t * istream, m68kinst * decoded)
decoded->src.addr_mode = MODE_IMMEDIATE;
decoded->src.params.immed = sign_extend8(*istream & 0xFF);
decoded->dst.addr_mode = MODE_REG;
- decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream);
+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
immed = *istream & 0xFF;
break;
case OR_DIV_SBCD:
@@ -785,10 +788,12 @@ uint16_t * m68K_decode(uint16_t * istream, m68kinst * decoded)
//SUBA.l
decoded->extra.size = OPSIZE_LONG;
decoded->dst.addr_mode = MODE_AREG;
+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src));
} else {
decoded->extra.size = size;
decoded->src.addr_mode = MODE_REG;
+ decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
istream = m68k_decode_op(istream, size, &(decoded->dst));
}
} else {
@@ -797,7 +802,7 @@ uint16_t * m68K_decode(uint16_t * istream, m68kinst * decoded)
decoded->extra.size = size;
istream = m68k_decode_op(istream, size, &(decoded->src));
decoded->dst.addr_mode = decoded->src.addr_mode;
- decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream);
+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
}
} else {
if (size == OPSIZE_INVALID) {
@@ -808,7 +813,7 @@ uint16_t * m68K_decode(uint16_t * istream, m68kinst * decoded)
decoded->extra.size = size;
decoded->dst.addr_mode = MODE_REG;
}
- decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream);
+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
}
break;
@@ -824,19 +829,19 @@ uint16_t * m68K_decode(uint16_t * istream, m68kinst * decoded)
//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 = m68k_reg_quick_field(*istream);
} else {
//EOR
decoded->op = M68K_EOR;
decoded->extra.size = size;
decoded->src.addr_mode = MODE_REG;
- decoded->src.params.regs.pri = m68K_reg_quick_field(*istream);
+ decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
}
} else {
//CMP
decoded->extra.size = size;
decoded->dst.addr_mode = MODE_REG;
- decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream);
+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
istream = m68k_decode_op(istream, size, &(decoded->src));
}
break;
@@ -855,18 +860,18 @@ uint16_t * m68K_decode(uint16_t * istream, m68kinst * decoded)
decoded->op = M68K_MULS;
decoded->extra.size = OPSIZE_WORD;
decoded->dst.addr_mode = MODE_REG;
- decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream);
+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src));
} else if(!(*istream & 0xF0)) {
decoded->op = M68K_ABCD;
decoded->extra.size = OPSIZE_BYTE;
decoded->src.params.regs.pri = *istream & 0x7;
- decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream);
+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
decoded->dst.addr_mode = decoded->src.addr_mode = (*istream & 8) ? MODE_AREG_PREDEC : MODE_REG;
} else if(!(*istream & 0x30)) {
decoded->op = M68K_EXG;
decoded->extra.size = OPSIZE_LONG;
- decoded->src.params.regs.pri = m68K_reg_quick_field(*istream);
+ decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
decoded->dst.params.regs.pri = *istream & 0x7;
if (*istream & 0x8) {
if (*istream & 0x80) {
@@ -882,7 +887,7 @@ uint16_t * m68K_decode(uint16_t * istream, m68kinst * decoded)
decoded->op = M68K_AND;
decoded->extra.size = (*istream >> 6);
decoded->dst.addr_mode = MODE_REG;
- decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream);
+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
}
} else {
@@ -890,13 +895,13 @@ uint16_t * m68K_decode(uint16_t * istream, m68kinst * decoded)
decoded->op = M68K_MULU;
decoded->extra.size = OPSIZE_WORD;
decoded->dst.addr_mode = MODE_REG;
- decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream);
+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src));
} else {
decoded->op = M68K_AND;
decoded->extra.size = (*istream >> 6);
decoded->src.addr_mode = MODE_REG;
- decoded->src.params.regs.pri = m68K_reg_quick_field(*istream);
+ decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst));
}
}
@@ -911,10 +916,12 @@ uint16_t * m68K_decode(uint16_t * istream, m68kinst * decoded)
//ADDA.l
decoded->extra.size = OPSIZE_LONG;
decoded->dst.addr_mode = MODE_AREG;
+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src));
} else {
decoded->extra.size = size;
decoded->src.addr_mode = MODE_REG;
+ decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
istream = m68k_decode_op(istream, size, &(decoded->dst));
}
} else {
@@ -924,7 +931,7 @@ uint16_t * m68K_decode(uint16_t * istream, m68kinst * decoded)
decoded->extra.size = size;
istream = m68k_decode_op(istream, size, &(decoded->src));
decoded->dst.addr_mode = decoded->src.addr_mode;
- decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream);
+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
}
} else {
if (size == OPSIZE_INVALID) {
@@ -935,7 +942,7 @@ uint16_t * m68K_decode(uint16_t * istream, m68kinst * decoded)
decoded->extra.size = size;
decoded->dst.addr_mode = MODE_REG;
}
- decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream);
+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
}
break;
diff --git a/68kinst.h b/68kinst.h
index 842ab12..209ea29 100644
--- a/68kinst.h
+++ b/68kinst.h
@@ -169,13 +169,14 @@ typedef struct {
uint8_t size;
uint8_t cond;
} extra;
+ uint32_t address;
m68k_op_info src;
m68k_op_info dst;
} m68kinst;
-uint16_t * m68K_decode(uint16_t * istream, m68kinst * dst);
+uint16_t * m68k_decode(uint16_t * istream, m68kinst * dst, uint32_t address);
uint32_t m68k_cycles(m68kinst * inst);
-int m68K_disasm(m68kinst * decoded, char * dst);
+int m68k_disasm(m68kinst * decoded, char * dst);
#endif
diff --git a/Makefile b/Makefile
index 68fe8da..4275750 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,12 @@
+all : dis trans
+
dis : dis.o 68kinst.o
$(CC) -o dis dis.o 68kinst.o
+trans : trans.o 68kinst.o gen_x86.o m68k_to_x86.o runtime.o mem.o
+ $(CC) -o trans trans.o 68kinst.o gen_x86.o m68k_to_x86.o runtime.o mem.o
+
test_x86 : test_x86.o gen_x86.o
$(CC) -o test_x86 test_x86.o gen_x86.o
@@ -12,7 +17,10 @@ gen_fib : gen_fib.o gen_x86.o mem.o
$(CC) -c -o $@ $<
%.o : %.c
- $(CC) -ggdb -c -o $@ $<
+ $(CC) -ggdb -std=gnu99 -c -o $@ $<
+
+%.bin : %.s68
+ vasmm68k_mot -Fbin -m68000 -spaces -o $@ $<
clean :
- rm -rf dis test_x86 gen_fib *.o
+ rm -rf dis trans test_x86 gen_fib *.o
diff --git a/dis.c b/dis.c
index 38a3527..4aae55c 100644
--- a/dis.c
+++ b/dis.c
@@ -24,9 +24,9 @@ int main(int argc, char ** argv)
{
//printf("cur: %p: %x\n", cur, *cur);
unsigned short * start = cur;
- cur = m68K_decode(cur, &instbuf);
+ cur = m68k_decode(cur, &instbuf, (start - filebuf)*2);
m68k_disasm(&instbuf, disbuf);
- printf("%lX: %s\n", (start - filebuf)*2, disbuf);
+ printf("%X: %s\n", instbuf.address, disbuf);
}
return 0;
}
diff --git a/gen_x86.c b/gen_x86.c
index 1b0bed9..676debb 100644
--- a/gen_x86.c
+++ b/gen_x86.c
@@ -31,6 +31,8 @@
#define OP_RETN 0xC3
#define OP_MOV_IEA 0xC6
#define OP_CALL 0xE8
+#define OP_JMP 0xE9
+#define OP_JMP_BYTE 0xEB
#define OP_CALL_EA 0xFF
#define OP2_JCC 0x80
@@ -49,12 +51,6 @@
#define BIT_DIR 0x2
#define BIT_SIZE 0x1
-#define M68K_N_REG RBX
-#define M68K_V_REG BH
-#define M68K_Z_REG RDX
-#define M68K_C_REG DH
-
-#define M68K_SCRATCH RCX
enum {
X86_RAX = 0,
@@ -79,13 +75,6 @@ enum {
X86_R15
} x86_regs_enc;
-enum {
- MODE_REG_INDIRECT = 0,
- MODE_REG_DISPLACE8 = 0x40,
- MODE_REG_DIPSLACE32 = 0x80,
- MODE_REG_DIRECT = 0xC0
-} x86_modes;
-
uint8_t * x86_rr_sizedir(uint8_t * out, uint8_t opcode, uint8_t src, uint8_t dst, uint8_t size)
{
//TODO: Deal with the fact that AH, BH, CH and DH can only be in the R/M param when there's a REX prefix
@@ -160,6 +149,10 @@ uint8_t * x86_rrdisp8_sizedir(uint8_t * out, uint8_t opcode, uint8_t reg, uint8_
}
*(out++) = opcode | dir;
*(out++) = MODE_REG_DISPLACE8 | base | (reg << 3);
+ if (base == RSP) {
+ //add SIB byte, with no index and RSP as base
+ *(out++) = (RSP << 3) | RSP;
+ }
*(out++) = disp;
return out;
}
@@ -195,6 +188,10 @@ uint8_t * x86_rrind_sizedir(uint8_t * out, uint8_t opcode, uint8_t reg, uint8_t
}
*(out++) = opcode | dir;
*(out++) = MODE_REG_INDIRECT | base | (reg << 3);
+ if (base == RSP) {
+ //add SIB byte, with no index and RSP as base
+ *(out++) = (RSP << 3) | RSP;
+ }
return out;
}
@@ -251,6 +248,51 @@ uint8_t * x86_ir(uint8_t * out, uint8_t opcode, uint8_t op_ex, uint8_t al_opcode
return out;
}
+uint8_t * x86_irdisp8(uint8_t * out, uint8_t opcode, uint8_t op_ex, int32_t val, uint8_t dst, int8_t disp, uint8_t size)
+{
+ uint8_t sign_extend = 0;
+ if ((size == SZ_D || size == SZ_Q) && val <= 0x7F && val >= -0x80) {
+ sign_extend = 1;
+ opcode |= BIT_DIR;
+ }
+ if (size == SZ_W) {
+ *(out++) = PRE_SIZE;
+ }
+
+ if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) {
+ *out = PRE_REX;
+ if (size == SZ_Q) {
+ *out |= REX_QUAD;
+ }
+ if (dst >= R8) {
+ *out |= REX_RM_FIELD;
+ dst -= (R8 - X86_R8);
+ }
+ out++;
+ }
+ if (dst >= AH && dst <= BH) {
+ dst -= (AH-X86_AH);
+ }
+ if (size != SZ_B) {
+ opcode |= BIT_SIZE;
+ }
+ *(out++) = opcode;
+ *(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3);
+ *(out++) = disp;
+ *(out++) = val;
+ if (size != SZ_B && !sign_extend) {
+ val >>= 8;
+ *(out++) = val;
+ if (size != SZ_W) {
+ val >>= 8;
+ *(out++) = val;
+ val >>= 8;
+ *(out++) = val;
+ }
+ }
+ return out;
+}
+
uint8_t * add_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
{
@@ -262,6 +304,21 @@ uint8_t * add_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
return x86_ir(out, OP_IMMED_ARITH, OP_EX_ADDI, OP_ADD, val, dst, size);
}
+uint8_t * add_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_ADDI, val, dst_base, disp, size);
+}
+
+uint8_t * add_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_rrdisp8_sizedir(out, OP_ADD, src, dst_base, disp, size, 0);
+}
+
+uint8_t * add_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
+{
+ return x86_rrdisp8_sizedir(out, OP_ADD, dst, src_base, disp, size, BIT_DIR);
+}
+
uint8_t * or_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
{
return x86_rr_sizedir(out, OP_OR, src, dst, size);
@@ -271,6 +328,21 @@ uint8_t * or_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
return x86_ir(out, OP_IMMED_ARITH, OP_EX_ORI, OP_OR, val, dst, size);
}
+uint8_t * or_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_ORI, val, dst_base, disp, size);
+}
+
+uint8_t * or_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_rrdisp8_sizedir(out, OP_OR, src, dst_base, disp, size, 0);
+}
+
+uint8_t * or_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
+{
+ return x86_rrdisp8_sizedir(out, OP_OR, dst, src_base, disp, size, BIT_DIR);
+}
+
uint8_t * and_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
{
return x86_rr_sizedir(out, OP_AND, src, dst, size);
@@ -281,6 +353,21 @@ uint8_t * and_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
return x86_ir(out, OP_IMMED_ARITH, OP_EX_ANDI, OP_AND, val, dst, size);
}
+uint8_t * and_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_ANDI, val, dst_base, disp, size);
+}
+
+uint8_t * and_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_rrdisp8_sizedir(out, OP_AND, src, dst_base, disp, size, 0);
+}
+
+uint8_t * and_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
+{
+ return x86_rrdisp8_sizedir(out, OP_AND, dst, src_base, disp, size, BIT_DIR);
+}
+
uint8_t * xor_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
{
return x86_rr_sizedir(out, OP_XOR, src, dst, size);
@@ -291,6 +378,21 @@ uint8_t * xor_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
return x86_ir(out, OP_IMMED_ARITH, OP_EX_XORI, OP_XOR, val, dst, size);
}
+uint8_t * xor_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_XORI, val, dst_base, disp, size);
+}
+
+uint8_t * xor_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_rrdisp8_sizedir(out, OP_XOR, src, dst_base, disp, size, 0);
+}
+
+uint8_t * xor_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
+{
+ return x86_rrdisp8_sizedir(out, OP_XOR, dst, src_base, disp, size, BIT_DIR);
+}
+
uint8_t * sub_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
{
return x86_rr_sizedir(out, OP_SUB, src, dst, size);
@@ -301,6 +403,21 @@ uint8_t * sub_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
return x86_ir(out, OP_IMMED_ARITH, OP_EX_SUBI, OP_SUB, val, dst, size);
}
+uint8_t * sub_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_SUBI, val, dst_base, disp, size);
+}
+
+uint8_t * sub_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_rrdisp8_sizedir(out, OP_SUB, src, dst_base, disp, size, 0);
+}
+
+uint8_t * sub_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
+{
+ return x86_rrdisp8_sizedir(out, OP_SUB, dst, src_base, disp, size, BIT_DIR);
+}
+
uint8_t * cmp_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
{
return x86_rr_sizedir(out, OP_CMP, src, dst, size);
@@ -311,6 +428,21 @@ uint8_t * cmp_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
return x86_ir(out, OP_IMMED_ARITH, OP_EX_CMPI, OP_CMP, val, dst, size);
}
+uint8_t * cmp_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_CMPI, val, dst_base, disp, size);
+}
+
+uint8_t * cmp_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
+{
+ return x86_rrdisp8_sizedir(out, OP_CMP, src, dst_base, disp, size, 0);
+}
+
+uint8_t * cmp_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
+{
+ return x86_rrdisp8_sizedir(out, OP_CMP, dst, src_base, disp, size, BIT_DIR);
+}
+
uint8_t * mov_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
{
return x86_rr_sizedir(out, OP_MOV, src, dst, size);
@@ -360,12 +492,12 @@ uint8_t * mov_ir(uint8_t * out, int64_t val, uint8_t dst, uint8_t size)
dst -= (AH-X86_AH);
}
if (size == SZ_B) {
- *(out++) = OP_MOV_I8R;
+ *(out++) = OP_MOV_I8R | dst;
} else if (size == SZ_Q && sign_extend) {
*(out++) = OP_MOV_IEA | BIT_SIZE;
*(out++) = MODE_REG_DIRECT | dst;
} else {
- *(out++) = OP_MOV_IR;
+ *(out++) = OP_MOV_IR | dst;
}
*(out++) = val;
if (size != SZ_B) {
@@ -391,6 +523,43 @@ uint8_t * mov_ir(uint8_t * out, int64_t val, uint8_t dst, uint8_t size)
return out;
}
+uint8_t * mov_irdisp8(uint8_t * out, int32_t val, uint8_t dst, int8_t disp, uint8_t size)
+{
+ if (size == SZ_W) {
+ *(out++) = PRE_SIZE;
+ }
+ if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) {
+ *out = PRE_REX;
+ if (size == SZ_Q) {
+ *out |= REX_QUAD;
+ }
+ if (dst >= R8) {
+ *out |= REX_RM_FIELD;
+ dst -= (R8 - X86_R8);
+ }
+ out++;
+ }
+ if (dst >= AH && dst <= BH) {
+ dst -= (AH-X86_AH);
+ }
+ *(out++) = OP_MOV_IEA | (size == SZ_B ? 0 : BIT_SIZE);
+ *(out++) = MODE_REG_DISPLACE8 | dst;
+ *(out++) = disp;
+
+ *(out++) = val;
+ if (size != SZ_B) {
+ val >>= 8;
+ *(out++) = val;
+ if (size != SZ_W) {
+ val >>= 8;
+ *(out++) = val;
+ val >>= 8;
+ *(out++) = val;
+ }
+ }
+ return out;
+}
+
uint8_t * pushf(uint8_t * out)
{
*(out++) = OP_PUSHF;
@@ -451,21 +620,53 @@ uint8_t * setcc_rind(uint8_t * out, uint8_t cc, uint8_t dst)
return out;
}
-uint8_t * jcc(uint8_t * out, uint8_t cc, int32_t disp)
+uint8_t * jcc(uint8_t * out, uint8_t cc, uint8_t * dest)
{
+ ptrdiff_t disp = dest-(out+2);
if (disp <= 0x7F && disp >= -0x80) {
*(out++) = OP_JCC | cc;
*(out++) = disp;
} else {
- *(out++) = PRE_2BYTE;
- *(out++) = OP2_JCC | cc;
- *(out++) = disp;
- disp >>= 8;
- *(out++) = disp;
- disp >>= 8;
- *(out++) = disp;
- disp >>= 8;
+ disp = dest-(out+6);
+ if (disp <= 0x7FFFFFFF && disp >= -2147483648) {
+ *(out++) = PRE_2BYTE;
+ *(out++) = OP2_JCC | cc;
+ *(out++) = disp;
+ disp >>= 8;
+ *(out++) = disp;
+ disp >>= 8;
+ *(out++) = disp;
+ disp >>= 8;
+ *(out++) = disp;
+ } else {
+ printf("%p - %p = %lX\n", dest, out + 6, disp);
+ return NULL;
+ }
+ }
+ return out;
+}
+
+uint8_t * jmp(uint8_t * out, uint8_t * dest)
+{
+ ptrdiff_t disp = dest-(out+2);
+ if (disp <= 0x7F && disp >= -0x80) {
+ *(out++) = OP_JMP_BYTE;
*(out++) = disp;
+ } else {
+ disp = dest-(out+5);
+ if (disp <= 0x7FFFFFFF && disp >= -2147483648) {
+ *(out++) = OP_JMP;
+ *(out++) = disp;
+ disp >>= 8;
+ *(out++) = disp;
+ disp >>= 8;
+ *(out++) = disp;
+ disp >>= 8;
+ *(out++) = disp;
+ } else {
+ printf("%p - %p = %lX\n", dest, out + 6, disp);
+ return NULL;
+ }
}
return out;
}
@@ -483,8 +684,8 @@ uint8_t * call(uint8_t * out, uint8_t * fun)
disp >>= 8;
*(out++) = disp;
} else {
- //TODO: Implement far call
- printf("%p - %p = %ld, %d, %d, %d\n", fun, out + 5, disp, disp <= 0x7FFFFFFF, disp >= (-2147483648), -2147483648);
+ //TODO: Implement far call???
+ printf("%p - %p = %lX\n", fun, out + 5, disp);
return NULL;
}
return out;
diff --git a/gen_x86.h b/gen_x86.h
index b566508..f2dec17 100644
--- a/gen_x86.h
+++ b/gen_x86.h
@@ -52,6 +52,19 @@ enum {
SZ_Q
} x86_size;
+enum {
+ MODE_REG_INDIRECT = 0,
+ MODE_REG_INDEXED = 4,
+ MODE_REG_DISPLACE8 = 0x40,
+ MODE_REG_INDEXED_DISPLACE8 = 0x44,
+ MODE_REG_DIPSLACE32 = 0x80,
+ MODE_REG_INDEXED_DIPSLACE32 = 0x84,
+ MODE_REG_DIRECT = 0xC0,
+//"phony" mode
+ MODE_IMMED = 0xFF
+} x86_modes;
+
+
uint8_t * add_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size);
uint8_t * or_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size);
uint8_t * xor_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size);
@@ -64,19 +77,39 @@ uint8_t * xor_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size);
uint8_t * and_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size);
uint8_t * sub_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size);
uint8_t * cmp_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size);
+uint8_t * add_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size);
+uint8_t * or_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size);
+uint8_t * xor_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size);
+uint8_t * and_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size);
+uint8_t * sub_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size);
+uint8_t * cmp_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size);
+uint8_t * add_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size);
+uint8_t * add_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size);
+uint8_t * or_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size);
+uint8_t * or_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size);
+uint8_t * xor_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size);
+uint8_t * xor_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size);
+uint8_t * and_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size);
+uint8_t * and_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size);
+uint8_t * sub_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size);
+uint8_t * sub_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size);
+uint8_t * cmp_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size);
+uint8_t * cmp_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size);
uint8_t * mov_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size);
uint8_t * mov_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size);
uint8_t * mov_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size);
uint8_t * mov_rrind(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size);
uint8_t * mov_rindr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size);
uint8_t * mov_ir(uint8_t * out, int64_t val, uint8_t dst, uint8_t size);
+uint8_t * mov_irdisp8(uint8_t * out, int32_t val, uint8_t dst, int8_t disp, uint8_t size);
uint8_t * pushf(uint8_t * out);
uint8_t * popf(uint8_t * out);
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 * jcc(uint8_t * out, uint8_t cc, int32_t disp);
+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);
uint8_t * retn(uint8_t * out);
diff --git a/m68k_to_x86.c b/m68k_to_x86.c
index 6cdb16a..ab4d286 100644
--- a/m68k_to_x86.c
+++ b/m68k_to_x86.c
@@ -1,11 +1,16 @@
#include "gen_x86.h"
#include "m68k_to_x86.h"
-
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
#define BUS 4
+#define PREDEC_PENALTY 2
#define CYCLES RAX
#define LIMIT RBP
-#define SCRATCH RCX
+#define SCRATCH1 RCX
+#define SCRATCH2 RDI
#define CONTEXT RSI
#define FLAG_N RBX
@@ -22,16 +27,26 @@ typedef struct {
} x86_ea;
void handle_cycle_limit();
+void m68k_read_word_scratch1();
+void m68k_read_long_scratch1();
+void m68k_read_byte_scratch1();
+void m68k_write_word();
+void m68k_write_long_lowfirst();
+void m68k_write_long_highfirst();
+void m68k_write_byte();
+void m68k_save_context();
+void m68k_modified_ret_addr();
+void m68k_start_context(uint8_t * addr, m68k_context * context);
uint8_t * cycles(uint8_t * dst, uint32_t num)
{
- dst = add_i32r(dst, num, CYCLES);
+ dst = add_ir(dst, num, CYCLES, SZ_D);
}
-uint8_t * check_cycles(uint8_t * dst) Ivds
+uint8_t * check_cycles(uint8_t * dst)
{
dst = cmp_rr(dst, CYCLES, LIMIT, SZ_D);
- dst = jcc(dst, CC_G, 5);
+ dst = jcc(dst, CC_G, dst+7);
dst = call(dst, (char *)handle_cycle_limit);
}
@@ -46,37 +61,551 @@ int8_t native_reg(m68k_op_info * op, x86_68k_options * opts)
return -1;
}
-uint8_t * translate_m68k_ea(m68k_op_info * op, x86_ea * dst, uint8_t * out, x86_68k_options * opts)
+void print_regs_exit(m68k_context * context)
+{
+ for (int i = 0; i < 8; i++) {
+ printf("d%d: %X\n", i, context->dregs[i]);
+ }
+ for (int i = 0; i < 8; i++) {
+ printf("a%d: %X\n", i, context->aregs[i]);
+ }
+ exit(0);
+}
+
+uint8_t * translate_m68k_src(m68kinst * inst, x86_ea * ea, uint8_t * out, x86_68k_options * opts)
{
- int8_t reg = native_reg(op, opts);
+ int8_t reg = native_reg(&(inst->src), opts);
+ int32_t dec_amount,inc_amount;
if (reg >= 0) {
- dst->mode = MODE_REG_DIRECT;
- dst->base = reg;
- return;
+ ea->mode = MODE_REG_DIRECT;
+ ea->base = reg;
+ return out;
}
- switch (op->addr_mode)
+ switch (inst->src.addr_mode)
{
case MODE_REG:
case MODE_AREG:
- dst->mode = MODE_DISPLACE8;
- dst->base = CONTEXT;
- dst->disp = (op->addr_mode = MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * op->params.regs.pri;
+ //We only get one memory parameter, so if the dst operand is a register in memory,
+ //we need to copy this to a temp register first
+ reg = native_reg(&(inst->dst), opts);
+ if (reg >= 0 || inst->dst.addr_mode == MODE_UNUSED || (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode == MODE_AREG)
+ || inst->op == M68K_EXG) {
+
+ ea->mode = MODE_REG_DISPLACE8;
+ ea->base = CONTEXT;
+ ea->disp = (inst->src.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * inst->src.params.regs.pri;
+ } else {
+ out = mov_rdisp8r(out, CONTEXT, (inst->src.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * inst->src.params.regs.pri, SCRATCH1, inst->extra.size);
+ ea->mode = MODE_REG_DIRECT;
+ ea->base = SCRATCH1;
+ }
break;
+ case MODE_AREG_PREDEC:
+ dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1);
+ out = cycles(out, PREDEC_PENALTY);
+ if (opts->aregs[inst->src.params.regs.pri] >= 0) {
+ out = sub_ir(out, inc_amount, opts->aregs[inst->src.params.regs.pri], SZ_D);
+ } else {
+ out = sub_irdisp8(out, inc_amount, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SZ_D);
+ }
+ out = check_cycles(out);
case MODE_AREG_INDIRECT:
+ case MODE_AREG_POSTINC:
+ if (opts->aregs[inst->src.params.regs.pri] >= 0) {
+ out = mov_rr(out, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D);
+ } else {
+ out = mov_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SCRATCH1, SZ_D);
+ }
+ 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;
+ }
+ if (inst->src.addr_mode == MODE_AREG_POSTINC) {
+ inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1);
+ if (opts->aregs[inst->src.params.regs.pri] >= 0) {
+ out = add_ir(out, inc_amount, opts->aregs[inst->src.params.regs.pri], SZ_D);
+ } else {
+ out = add_irdisp8(out, inc_amount, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SZ_D);
+ }
+ }
+ ea->mode = MODE_REG_DIRECT;
+ ea->base = SCRATCH1;
break;
+ case MODE_IMMEDIATE:
+ if (inst->variant != VAR_QUICK) {
+ if (inst->extra.size == OPSIZE_LONG) {
+ out = cycles(out, BUS);
+ out = check_cycles(out);
+ }
+ out = cycles(out, BUS);
+ out = check_cycles(out);
+ }
+ ea->mode = MODE_IMMED;
+ ea->disp = inst->src.params.immed;
+ break;
+ default:
+ printf("address mode %d not implemented (src)\n", inst->src.addr_mode);
+ exit(1);
}
+ return out;
}
-uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
+uint8_t * translate_m68k_dst(m68kinst * inst, x86_ea * ea, uint8_t * out, x86_68k_options * opts)
+{
+ int8_t reg = native_reg(&(inst->dst), opts);
+ int32_t dec_amount, inc_amount;
+ if (reg >= 0) {
+ ea->mode = MODE_REG_DIRECT;
+ ea->base = reg;
+ return out;
+ }
+ switch (inst->dst.addr_mode)
+ {
+ case MODE_REG:
+ case MODE_AREG:
+ ea->mode = MODE_REG_DISPLACE8;
+ ea->base = CONTEXT;
+ ea->disp = (inst->dst.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * inst->dst.params.regs.pri;
+ break;
+ case MODE_AREG_PREDEC:
+ dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 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);
+ } else {
+ out = sub_irdisp8(out, dec_amount, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D);
+ }
+ case MODE_AREG_INDIRECT:
+ case MODE_AREG_POSTINC:
+ if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
+ out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], SCRATCH1, SZ_D);
+ } else {
+ out = mov_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SCRATCH1, SZ_D);
+ }
+ 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;
+ }
+ //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, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SCRATCH2, SZ_D);
+ }
+
+ if (inst->src.addr_mode == MODE_AREG_POSTINC) {
+ inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1);
+ if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
+ out = add_ir(out, inc_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D);
+ } else {
+ out = add_irdisp8(out, inc_amount, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D);
+ }
+ }
+ ea->mode = MODE_REG_DIRECT;
+ ea->base = SCRATCH1;
+ break;
+ default:
+ printf("address mode %d not implemented (dst)\n", inst->dst.addr_mode);
+ exit(1);
+ }
+ return out;
+}
+
+uint8_t * m68k_save_result(m68kinst * inst, uint8_t * out, x86_68k_options * opts)
{
- int8_t reg_a, reg_b, flags_reg;
+ if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG) {
+ switch (inst->extra.size)
+ {
+ case OPSIZE_BYTE:
+ out = call(out, (char *)m68k_write_byte);
+ break;
+ case OPSIZE_WORD:
+ out = call(out, (char *)m68k_write_word);
+ break;
+ case OPSIZE_LONG:
+ out = call(out, (char *)m68k_write_long_lowfirst);
+ break;
+ }
+ }
+ return out;
+}
+
+uint8_t * get_native_address(native_map_slot * native_code_map, uint32_t address)
+{
+ address &= 0xFFFFFF;
+ uint32_t chunk = address / NATIVE_CHUNK_SIZE;
+ if (!native_code_map[chunk].base) {
+ return NULL;
+ }
+ uint32_t offset = address % NATIVE_CHUNK_SIZE;
+ if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET) {
+ return NULL;
+ }
+ return native_code_map[chunk].base + native_code_map[chunk].offsets[offset];
+}
+
+deferred_addr * defer_address(deferred_addr * old_head, uint32_t address, uint8_t *dest)
+{
+ deferred_addr * new_head = malloc(sizeof(deferred_addr));
+ new_head->next = old_head;
+ new_head->address = address & 0xFFFFFF;
+ new_head->dest = dest;
+ return new_head;
+}
+
+void process_deferred(x86_68k_options * opts)
+{
+ deferred_addr * cur = opts->deferred;
+ deferred_addr **last_next = &(opts->deferred);
+ while(cur)
+ {
+ uint8_t * native = get_native_address(opts->native_code_map, cur->address);
+ if (native) {
+ int32_t disp = native - (cur->dest + 4);
+ printf("Native dest: %p, Offset address: %p, displacement: %X\n", native, cur->dest, disp);
+ uint8_t * out = cur->dest;
+ *(out++) = disp;
+ disp >>= 8;
+ *(out++) = disp;
+ disp >>= 8;
+ *(out++) = disp;
+ disp >>= 8;
+ *out = disp;
+ *last_next = cur->next;
+ free(cur);
+ cur = *last_next;
+ } else {
+ last_next = &(cur->next);
+ cur = cur->next;
+ }
+ }
+}
+
+void map_native_address(native_map_slot * native_code_map, uint32_t address, uint8_t * native_addr)
+{
+ //FIXME: This probably isn't going to work with real code in a lot of cases, no guarantee that
+ //all the code in 1KB block is going to be translated at the same time
+ address &= 0xFFFFFF;
+ uint32_t chunk = address / NATIVE_CHUNK_SIZE;
+ if (!native_code_map[chunk].base) {
+ native_code_map[chunk].base = native_addr;
+ native_code_map[chunk].offsets = malloc(sizeof(uint16_t) * NATIVE_CHUNK_SIZE);
+ memset(native_code_map[chunk].offsets, 0xFF, sizeof(uint16_t) * NATIVE_CHUNK_SIZE);
+ }
+ uint32_t offset = address % NATIVE_CHUNK_SIZE;
+ native_code_map[chunk].offsets[offset] = native_addr-native_code_map[chunk].base;
+}
+
+uint8_t * translate_m68k_move(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
+{
+ int8_t reg, flags_reg;
uint8_t dir = 0;
int32_t offset;
+ int32_t inc_amount, dec_amount;
+ x86_ea src;
+ dst = translate_m68k_src(inst, &src, dst, opts);
+ reg = native_reg(&(inst->dst), opts);
+ if (src.mode == MODE_REG_DIRECT) {
+ flags_reg = src.base;
+ } else {
+ if (reg >= 0) {
+ flags_reg = reg;
+ } else {
+ printf("moving %d to temp register %d\n", src.disp, SCRATCH1);
+ dst = mov_ir(dst, src.disp, SCRATCH1, SZ_D);
+ src.mode = MODE_REG_DIRECT;
+ flags_reg = src.base = SCRATCH1;
+ }
+ }
+ switch(inst->dst.addr_mode)
+ {
+ case MODE_REG:
+ case MODE_AREG:
+ if (reg >= 0) {
+ if (src.mode == MODE_REG_DIRECT) {
+ dst = mov_rr(dst, src.base, reg, inst->extra.size);
+ } else if (src.mode == MODE_REG_DISPLACE8) {
+ dst = mov_rdisp8r(dst, src.base, src.disp, reg, inst->extra.size);
+ } else {
+ dst = mov_ir(dst, src.disp, reg, inst->extra.size);
+ }
+ } else if(src.mode == MODE_REG_DIRECT) {
+ printf("mov_rrdisp8 from reg %d to offset %d from reg %d (%d)\n", src.base, (inst->dst.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * inst->dst.params.regs.pri, CONTEXT, inst->dst.params.regs.pri);
+ dst = mov_rrdisp8(dst, src.base, CONTEXT, (inst->dst.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * inst->dst.params.regs.pri, inst->extra.size);
+ } else {
+ dst = mov_irdisp8(dst, src.disp, CONTEXT, (inst->dst.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * inst->dst.params.regs.pri, inst->extra.size);
+ }
+ break;
+ case MODE_AREG_PREDEC:
+ dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1);
+ if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
+ dst = sub_ir(dst, dec_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D);
+ } else {
+ dst = sub_irdisp8(dst, dec_amount, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D);
+ }
+ case MODE_AREG_INDIRECT:
+ case MODE_AREG_POSTINC:
+ if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
+ dst = mov_rr(dst, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D);
+ } else {
+ dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SCRATCH2, SZ_D);
+ }
+ 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);
+ }
+ switch (inst->extra.size)
+ {
+ case OPSIZE_BYTE:
+ dst = call(dst, (char *)m68k_write_byte);
+ break;
+ case OPSIZE_WORD:
+ dst = call(dst, (char *)m68k_write_word);
+ break;
+ case OPSIZE_LONG:
+ dst = call(dst, (char *)m68k_write_long_highfirst);
+ break;
+ }
+ if (inst->dst.addr_mode == MODE_AREG_POSTINC) {
+ inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1);
+ if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
+ dst = add_ir(dst, inc_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D);
+ } else {
+ dst = add_irdisp8(dst, inc_amount, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D);
+ }
+ }
+ break;
+ default:
+ printf("address mode %d not implemented (move dst)\n", inst->dst.addr_mode);
+ exit(1);
+ }
+
+ //add cycles for prefetch
+ dst = cycles(dst, BUS);
+ //update flags
+ dst = mov_ir(dst, 0, FLAG_V, SZ_B);
+ dst = mov_ir(dst, 0, FLAG_C, SZ_B);
+ 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);
+ dst = check_cycles(dst);
+ return dst;
+}
+
+uint8_t * translate_m68k_lea(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
+{
+ int8_t dst_reg = native_reg(&(inst->dst), opts);
+ switch(inst->src.addr_mode)
+ {
+ case MODE_AREG_INDIRECT:
+ dst = cycles(dst, BUS);
+ if (opts->aregs[inst->src.params.regs.pri] >= 0) {
+ if (dst_reg >= 0) {
+ dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], dst_reg, SZ_D);
+ } else {
+ dst = mov_rrdisp8(dst, opts->aregs[inst->src.params.regs.pri], CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D);
+ }
+ } else {
+ if (dst_reg >= 0) {
+ dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, dst_reg, SZ_D);
+ } else {
+ dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SCRATCH1, SZ_D);
+ dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D);
+ }
+ }
+ dst = check_cycles(dst);
+ break;
+ case MODE_ABSOLUTE:
+ dst = cycles(dst, BUS);
+ dst = check_cycles(dst);
+ case MODE_ABSOLUTE_SHORT:
+ dst = cycles(dst, BUS);
+ dst = check_cycles(dst);
+ dst = cycles(dst, BUS);
+ if (dst_reg >= 0) {
+ dst = mov_ir(dst, inst->src.params.immed, dst_reg, SZ_D);
+ } else {
+ dst = mov_irdisp8(dst, inst->src.params.immed, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D);
+ }
+ dst = check_cycles(dst);
+ break;
+ }
+ return dst;
+}
+
+uint8_t * translate_m68k_bsr(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
+{
+ //TODO: Add cycles
+ int32_t disp = inst->src.params.immed;
+ uint32_t after = inst->address + (inst->variant == VAR_BYTE ? 2 : (inst->variant == VAR_WORD ? 4 : 6));
+ dst = mov_ir(dst, after, SCRATCH1, SZ_D);
+ dst = push_r(dst, SCRATCH1);
+ dst = sub_ir(dst, 4, opts->aregs[7], SZ_D);
+ dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D);
+ dst = call(dst, (char *)m68k_write_long_highfirst);
+ printf("bsr@%X: after=%X, disp=%X, dest=%X\n", inst->address, after, disp, after+disp);
+ uint8_t * dest_addr = get_native_address(opts->native_code_map, after + disp);
+ if (!dest_addr) {
+ opts->deferred = defer_address(opts->deferred, after + disp, dst + 1);
+ //dummy address to be replaced later
+ dest_addr = dst + 5;
+ }
+ dst = call(dst, (char *)dest_addr);
+ //would add_ir(dst, 8, RSP, SZ_Q) be faster here?
+ dst = pop_r(dst, SCRATCH1);
+ return dst;
+}
+
+uint8_t * translate_m68k_bcc(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
+{
+ //TODO: Add cycles
+ int32_t disp = inst->src.params.immed;
+ uint32_t after = inst->address + (inst->variant == VAR_BYTE ? 2 : (inst->variant == VAR_WORD ? 4 : 6));
+ printf("bcc@%X: after=%X, disp=%X, dest=%X\n", inst->address, after, disp, after+disp);
+ uint8_t * dest_addr = get_native_address(opts->native_code_map, after + disp);
+ if (inst->extra.cond == COND_TRUE) {
+ if (!dest_addr) {
+ opts->deferred = defer_address(opts->deferred, after + disp, dst + 1);
+ //dummy address to be replaced later, make sure it generates a 4-byte displacement
+ dest_addr = dst + 256;
+ }
+ dst = jmp(dst, dest_addr);
+ } else {
+ uint8_t cond = CC_NZ;
+ switch (inst->extra.cond)
+ {
+ case COND_HIGH:
+ cond = 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:
+ cond = CC_Z;
+ case COND_CARRY_SET:
+ dst = cmp_ir(dst, 0, FLAG_C, SZ_B);
+ break;
+ case COND_NOT_EQ:
+ cond = CC_Z;
+ case COND_EQ:
+ dst = cmp_ir(dst, 0, FLAG_Z, SZ_B);
+ break;
+ case COND_OVERF_CLR:
+ cond = CC_Z;
+ case COND_OVERF_SET:
+ dst = cmp_ir(dst, 0, FLAG_V, SZ_B);
+ break;
+ case COND_PLUS:
+ cond = CC_Z;
+ case COND_MINUS:
+ dst = cmp_ir(dst, 0, FLAG_N, SZ_B);
+ break;
+ case COND_GREATER_EQ:
+ cond = CC_Z;
+ case COND_LESS:
+ dst = cmp_rr(dst, FLAG_N, FLAG_V, SZ_B);
+ break;
+ case COND_GREATER:
+ cond = 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 (!dest_addr) {
+ opts->deferred = defer_address(opts->deferred, after + disp, dst + 2);
+ //dummy address to be replaced later, make sure it generates a 4-byte displacement
+ dest_addr = dst + 256;
+ }
+ dst = jcc(dst, cond, dest_addr);
+ }
+ return dst;
+}
+
+uint8_t * translate_m68k_rts(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
+{
+ //TODO: Add cycles
+ dst = mov_rr(dst, opts->aregs[7], SCRATCH1, SZ_D);
+ dst = add_ir(dst, 4, opts->aregs[7], SZ_D);
+ dst = call(dst, (char *)m68k_read_long_scratch1);
+ dst = cmp_rdisp8r(dst, RSP, 8, SCRATCH1, SZ_D);
+ dst = jcc(dst, CC_NZ, dst+3);
+ dst = retn(dst);
+ dst = jmp(dst, (char *)m68k_modified_ret_addr);
+ return dst;
+}
+
+uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
+{
+ map_native_address(opts->native_code_map, inst->address, dst);
+ if (inst->op == M68K_MOVE) {
+ return translate_m68k_move(dst, inst, opts);
+ } else if(inst->op == M68K_LEA) {
+ return translate_m68k_lea(dst, inst, opts);
+ } else if(inst->op == M68K_BSR) {
+ return translate_m68k_bsr(dst, inst, opts);
+ } else if(inst->op == M68K_BCC) {
+ return translate_m68k_bcc(dst, inst, opts);
+ } else if(inst->op == M68K_RTS) {
+ return translate_m68k_rts(dst, inst, opts);
+ }
+ x86_ea src_op, dst_op;
+ if (inst->src.addr_mode != MODE_UNUSED) {
+ dst = translate_m68k_src(inst, &src_op, dst, opts);
+ }
+ if (inst->dst.addr_mode != MODE_UNUSED) {
+ dst = translate_m68k_dst(inst, &dst_op, dst, opts);
+ }
switch(inst->op)
{
case M68K_ABCD:
+ break;
case M68K_ADD:
+ dst = cycles(dst, BUS);
+ if (src_op.mode == MODE_REG_DIRECT) {
+ if (dst_op.mode == MODE_REG_DIRECT) {
+ dst = add_rr(dst, src_op.base, dst_op.base, inst->extra.size);
+ } else {
+ dst = add_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, inst->extra.size);
+ }
+ } else if (src_op.mode == MODE_REG_DISPLACE8) {
+ dst = add_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, inst->extra.size);
+ } else {
+ if (dst_op.mode == MODE_REG_DIRECT) {
+ dst = add_ir(dst, src_op.disp, dst_op.base, inst->extra.size);
+ } else {
+ dst = add_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.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);
+ dst = check_cycles(dst);
+ break;
case M68K_ADDX:
case M68K_AND:
case M68K_ANDI_CCR:
@@ -92,6 +621,28 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
case M68K_CHK:
case M68K_CLR:
case M68K_CMP:
+ dst = cycles(dst, BUS);
+ if (src_op.mode == MODE_REG_DIRECT) {
+ if (dst_op.mode == MODE_REG_DIRECT) {
+ dst = cmp_rr(dst, src_op.base, dst_op.base, inst->extra.size);
+ } else {
+ dst = cmp_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, inst->extra.size);
+ }
+ } else if (src_op.mode == MODE_REG_DISPLACE8) {
+ dst = cmp_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, inst->extra.size);
+ } else {
+ if (dst_op.mode == MODE_REG_DIRECT) {
+ dst = cmp_ir(dst, src_op.disp, dst_op.base, inst->extra.size);
+ } else {
+ dst = cmp_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.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 = check_cycles(dst);
+ break;
case M68K_DBCC:
case M68K_DIVS:
case M68K_DIVU:
@@ -99,95 +650,41 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
case M68K_EORI_CCR:
case M68K_EORI_SR:
case M68K_EXG:
+ dst = cycles(dst, 6);
+ if (dst_op.mode == MODE_REG_DIRECT) {
+ dst = mov_rr(dst, dst_op.base, SCRATCH2, SZ_D);
+ if (src_op.mode == MODE_REG_DIRECT) {
+ dst = mov_rr(dst, src_op.base, dst_op.base, SZ_D);
+ dst = mov_rr(dst, SCRATCH2, src_op.base, SZ_D);
+ } else {
+ dst = mov_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, SZ_D);
+ dst = mov_rrdisp8(dst, SCRATCH2, src_op.base, src_op.disp, SZ_D);
+ }
+ } else {
+ dst = mov_rdisp8r(dst, dst_op.base, dst_op.disp, SCRATCH2, SZ_D);
+ if (src_op.mode == MODE_REG_DIRECT) {
+ dst = mov_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, SZ_D);
+ dst = mov_rr(dst, SCRATCH2, src_op.base, SZ_D);
+ } else {
+ dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_D);
+ dst = mov_rrdisp8(dst, SCRATCH1, dst_op.base, dst_op.disp, SZ_D);
+ dst = mov_rrdisp8(dst, SCRATCH2, src_op.base, src_op.disp, SZ_D);
+ }
+ }
+ dst = check_cycles(dst);
+ break;
case M68K_EXT:
case M68K_ILLEGAL:
+ dst = call(dst, (uint8_t *)m68k_save_context);
+ 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:
case M68K_LSL:
case M68K_LSR:
- case M68K_MOVE:
-
- if ((inst->src.addr_mode == MODE_REG || inst->src.addr_mode == MODE_AREG || (inst->src.addr_mode == MODE_IMMEDIATE && inst->src.variant == VAR_QUICK)) && (inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG)) {
- dst = cycles(dst, BUS);
- reg_a = native_reg(&(inst->src), opts);
- reg_b = native_reg(&(inst->dst), opts);
- dst = cycles(dst, BUS);
- if (reg_a >= 0 && reg_b >= 0) {
- dst = mov_rr(dst, reg_a, reg_b, inst->extra.size);
- flags_reg = reg_b;
- } else if(reg_a >= 0) {
- offset = inst->dst.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs);
- dst = mov_rrdisp8(dst, reg_a, CONTEXT, offset + 4 * inst->dst.params.regs.pri, inst->extra.size);
- flags_reg = reg_a;
- } else if(reg_b >= 0) {
- if (inst->src.addr_mode == MODE_REG) {
- dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + 4 * inst->src.params.regs.pri, reg_b, inst->extra.size);
- } else if(inst->src.addr_mode == MODE_AREG) {
- dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, reg_b, inst->extra.size);
- } else {
- dst = mov_i32r(dst, inst->src.params.u32, reg_b);
- }
- flags_reg = reg_b;
- } else {
-
- }
- dst = mov_i8r(dst, 0, FLAG_V);
- dst = mov_i8r(dst, 0, FLAG_C);
- switch (inst->extra.size)
- {
- case OPSIZE_BYTE:
- dst = cmp_i8r(dst, 0, reg_b, SZ_B);
- break;
- case OPSIZE_WORD:
- dst = cmp_i8r(dst, 0, reg_b, SZ_W);
- break;
- case OPSIZE_LONG:
- dst = cmp_i8r(dst, 0, reg_b, SZ_D);
- break;
- }
- dst = setcc_r(dst, CC_Z, FLAG_Z);
- dst = setcc_r(dst, CC_S, FLAG_N);
- dst = check_cycles(dst);
- }
-
- if (reg_a >= 0 && reg_b >= 0) {
- dst = cycles(dst, BUS);
- dst = mov_rr(dst, reg_a, reg_b, inst->extra.size);
- dst = mov_i8r(dst, 0, FLAG_V);
- dst = mov_i8r(dst, 0, FLAG_C);
- switch (inst->extra.size)
- {
- case OPSIZE_BYTE:
- dst = cmp_i8r(dst, 0, reg_b, SZ_B);
- break;
- case OPSIZE_WORD:
- dst = cmp_i8r(dst, 0, reg_b, SZ_W);
- break;
- case OPSIZE_LONG:
- dst = cmp_i8r(dst, 0, reg_b, SZ_D);
- break;
- }
- dst = setcc_r(dst, CC_Z, FLAG_Z);
- dst = setcc_r(dst, CC_S, FLAG_N);
- dst = check_cycles(dst);
- } else if(reg_a >= 0 || reg_b >= 0) {
- if (reg_a >= 0) {
- switch (inst->dst.addr_mode)
- {
- case MODE_REG:
- dst = cycles(dst, BUS);
- dst = mov_rr(dst, reg_a, reg_b, inst->extra.size);
- dst = check_cycles(dst);
- break;
- case MODE_AREG:
- break;
- }
- } else {
- }
- }
- break;
case M68K_MOVE_CCR:
case M68K_MOVE_FROM_SR:
case M68K_MOVE_SR:
@@ -217,6 +714,29 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
case M68K_SCC:
case M68K_STOP:
case M68K_SUB:
+ dst = cycles(dst, BUS);
+ if (src_op.mode == MODE_REG_DIRECT) {
+ if (dst_op.mode == MODE_REG_DIRECT) {
+ dst = sub_rr(dst, src_op.base, dst_op.base, inst->extra.size);
+ } else {
+ dst = sub_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, inst->extra.size);
+ }
+ } else if (src_op.mode == MODE_REG_DISPLACE8) {
+ dst = sub_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, inst->extra.size);
+ } else {
+ if (dst_op.mode == MODE_REG_DIRECT) {
+ dst = sub_ir(dst, src_op.disp, dst_op.base, inst->extra.size);
+ } else {
+ dst = sub_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.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);
+ dst = check_cycles(dst);
+ break;
case M68K_SUBX:
case M68K_SWAP:
case M68K_TAS:
@@ -227,5 +747,65 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
case M68K_INVALID:
break;
}
+ return dst;
+}
+
+uint8_t * translate_m68k_stream(uint8_t * dst, uint8_t * dst_end, uint32_t address, m68k_context * context)
+{
+ m68kinst instbuf;
+ x86_68k_options * opts = context->options;
+ char disbuf[1024];
+ uint16_t *encoded = context->mem_pointers[0] + address/2, *next;
+ do {
+ do {
+ if (dst_end-dst < 128) {
+ puts("out of code memory");
+ exit(1);
+ }
+ next = m68k_decode(encoded, &instbuf, address);
+ address += (next-encoded)*2;
+ encoded = next;
+ m68k_disasm(&instbuf, disbuf);
+ printf("%X: %s\n", instbuf.address, disbuf);
+ dst = translate_m68k(dst, &instbuf, opts);
+ } while(instbuf.op != M68K_ILLEGAL && instbuf.op != M68K_RTS && instbuf.op != M68K_RTE && !(instbuf.op == M68K_BCC && instbuf.extra.cond == COND_TRUE) && instbuf.op != M68K_JMP);
+ process_deferred(opts);
+ if (opts->deferred) {
+ address = opts->deferred->address;
+ encoded = context->mem_pointers[0] + address/2;
+ } else {
+ encoded = NULL;
+ }
+ } while(encoded != NULL);
+ return dst;
+}
+
+void start_68k_context(m68k_context * context, uint32_t address)
+{
+ uint8_t * addr = get_native_address(context->native_code_map, address);
+ m68k_start_context(addr, context);
+}
+
+void init_x86_68k_opts(x86_68k_options * opts)
+{
+ opts->flags = 0;
+ for (int i = 0; i < 8; i++)
+ opts->dregs[i] = opts->aregs[i] = -1;
+ opts->dregs[0] = R10;
+ opts->dregs[1] = R11;
+ opts->dregs[2] = R12;
+ opts->aregs[0] = R13;
+ opts->aregs[1] = R14;
+ opts->aregs[7] = R15;
+ opts->native_code_map = malloc(sizeof(native_map_slot) * NATIVE_MAP_CHUNKS);
+ memset(opts->native_code_map, 0, sizeof(native_map_slot) * NATIVE_MAP_CHUNKS);
+ opts->deferred = NULL;
+}
+
+void init_68k_context(m68k_context * context, native_map_slot * native_code_map, void * opts)
+{
+ memset(context, 0, sizeof(m68k_context));
+ context->native_code_map = native_code_map;
+ context->options = opts;
}
diff --git a/m68k_to_x86.h b/m68k_to_x86.h
index c287d6f..5dc04fd 100644
--- a/m68k_to_x86.h
+++ b/m68k_to_x86.h
@@ -1,16 +1,46 @@
#include <stdint.h>
+#include "68kinst.h"
+
+#define NUM_MEM_AREAS 4
+#define NATIVE_MAP_CHUNKS (32*1024)
+#define NATIVE_CHUNK_SIZE ((16 * 1024 * 1024 / NATIVE_MAP_CHUNKS)/2)
+#define INVALID_OFFSET 0xFFFF
+
+typedef struct {
+ uint8_t *base;
+ uint16_t *offsets;
+} native_map_slot;
+
+typedef struct deferred_addr {
+ struct deferred_addr *next;
+ uint8_t *dest;
+ uint32_t address;
+} deferred_addr;
typedef struct {
- uint32_t flags;
- int8_t dregs[8];
- int8_t aregs[8];
+ uint32_t flags;
+ int8_t dregs[8];
+ int8_t aregs[8];
+ native_map_slot *native_code_map;
+ deferred_addr *deferred;
+
} x86_68k_options;
typedef struct {
- uint8_t flags[5];
- uint8_t status;
- uint16_t reserved;
- uint32_t dregs[8];
- uint32_t aregs[8];
+ uint8_t flags[5];
+ uint8_t status;
+ uint16_t reserved;
+ uint32_t dregs[8];
+ uint32_t aregs[8];
+ uint32_t target_cycle;
+ uint32_t current_cycle;
+ uint16_t *mem_pointers[NUM_MEM_AREAS];
+ native_map_slot *native_code_map;
+ void *options;
} m68k_context;
+uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts);
+uint8_t * translate_m68k_stream(uint8_t * dst, uint8_t * dst_end, uint32_t address, m68k_context * context);
+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);
diff --git a/mem.c b/mem.c
index c3f03a4..cc07985 100644
--- a/mem.c
+++ b/mem.c
@@ -1,10 +1,35 @@
#include <sys/mman.h>
#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
#include "mem.h"
+/*
void * alloc_code(size_t *size)
{
*size += PAGE_SIZE - (*size & (PAGE_SIZE - 1));
return mmap(NULL, *size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
}
+*/
+/*
+void * alloc_code(size_t *size)
+{
+ char * ret = malloc(*size);
+ char * base = (char *)(((intptr_t)ret) & (~(PAGE_SIZE-1)));
+ mprotect(base, (ret + *size) - base, PROT_EXEC | PROT_READ | PROT_WRITE);
+ return ret;
+}
+*/
+
+void * alloc_code(size_t *size)
+{
+ *size += PAGE_SIZE - (*size & (PAGE_SIZE - 1));
+ void * ret = sbrk(*size);
+ if (ret == ((void *)-1)) {
+ return NULL;
+ }
+ mprotect(ret, *size, PROT_EXEC | PROT_READ | PROT_WRITE);
+ return ret;
+}
diff --git a/notes.txt b/notes.txt
index f3f54e7..f791327 100644
--- a/notes.txt
+++ b/notes.txt
@@ -36,16 +36,15 @@ dl = Z flag
dh = C flag
rbp = target cycle count
rsi = context pointer
-rdi = d0
-r8 = d1
-r9 = d2
-r10 = d3
-r11 = a0
-r12 = a1
-r13 = a6
-r14 = a7
-r15 = work ram address
-r16 = cartridge address
+rdi = scratch register
+r8 = cartridge address
+r9 = work ram address
+r10 = d0
+r11 = d1
+r12 = d2
+r13 = a0
+r14 = a1
+r15 = a7
rsp = native stack pointer
68K context:
diff --git a/runtime.S b/runtime.S
index 3800e7f..6e685a5 100644
--- a/runtime.S
+++ b/runtime.S
@@ -1,5 +1,162 @@
- .global _handle_cycle_limit
-_handle_cycle_limit:
- retn
+ .global handle_cycle_limit
+handle_cycle_limit:
+ ret
+
+ .global m68k_write_word
+m68k_write_word:
+ and $0xFFFFFF, %rdi
+ cmp $0x400000, %edi
+ jle cart_w
+ cmp $0xE00000, %edi
+ jge workram_w
+ jmp inccycles
+workram_w:
+ and $0xFFFF, %rdi
+ mov %cx, (%r9, %rdi)
+ jmp inccycles
+cart_w:
+ mov %cx, (%r8, %rdi)
+ jmp inccycles
+ .global m68k_write_byte
+m68k_write_byte:
+ and $0xFFFFFF, %rdi
+ /* deal with byte swapping */
+ xor $1, %edi
+ cmp $0x400000, %edi
+ jle cart_wb
+ cmp $0xE00000, %edi
+ jge workram_wb
+ jmp inccycles
+workram_wb:
+ and $0xFFFF, %rdi
+ mov %cl, (%r9, %rdi)
+ jmp inccycles
+cart_wb:
+ mov %cl, (%r8, %rdi)
+ jmp inccycles
+
+ .global m68k_write_long_lowfirst
+m68k_write_long_lowfirst:
+ push %rdi
+ add $2, %edi
+ call m68k_write_word
+ shr $16, %ecx
+ pop %rdi
+ jmp m68k_write_word
+
+ .global m68k_write_long_highfirst
+m68k_write_long_highfirst:
+ push %rdi
+ push %rcx
+ shr $16, %ecx
+ call m68k_write_word
+ pop %rcx
+ pop %rdi
+ add $2, %rdi
+ jmp m68k_write_word
+
+ .global m68k_read_word_scratch1
+m68k_read_word_scratch1:
+ and $0xFFFFFF, %rcx
+ cmp $0x400000, %ecx
+ jle cart
+ cmp $0xE00000, %ecx
+ jge workram
+ xor %cx, %cx
+ jmp inccycles
+workram:
+ and $0xFFFF, %rcx
+ mov (%r9, %rcx), %cx
+ jmp inccycles
+cart:
+ mov (%r8, %rcx), %cx
+inccycles:
+ add $4, %rax
+ cmp %rbp, %rax
+ jge sync
+ ret
+sync:
+ ret
+
+ .global m68k_read_long_scratch1
+m68k_read_long_scratch1:
+ push %rcx
+ call m68k_read_word_scratch1
+ mov %cx, %di
+ pop %rcx
+ add $2, %ecx
+ call m68k_read_word_scratch1
+ and $0xFFFF, %ecx
+ shl $16, %edi
+ or %edi, %ecx
+ ret
+
+ .global m68k_read_byte_scratch1
+m68k_read_byte_scratch1:
+ and $0xFFFFFF, %rcx
+ /* deal with byte swapping */
+ xor $1, %ecx
+ cmp $0x400000, %ecx
+ jle cart_b
+ cmp $0xE00000, %ecx
+ jge workram_b
+ xor %cl, %cl
+ jmp inccycles
+workram_b:
+ and $0xFFFF, %rcx
+ mov (%r9, %rcx), %cl
+ jmp inccycles
+cart_b:
+ mov (%r8, %rcx), %cl
+ jmp inccycles
+
+ret_addr_msg:
+ .asciz "Program modified return address on stack: found %X, expected %X\n"
+
+ .global m68k_modified_ret_addr
+m68k_modified_ret_addr:
+ lea ret_addr_msg(%rip), %rdi
+ mov %rcx, %rsi
+ mov 8(%rsp), %rdx
+ call printf
+ mov $1, %rdi
+ call exit
+
+ .global m68k_save_context
+m68k_save_context:
+ mov %bl, 1(%rsi) /* N Flag */
+ mov %bh, 2(%rsi) /* V flag */
+ mov %dl, 3(%rsi) /* Z flag */
+ mov %dh, 4(%rsi) /* C flag */
+ mov %r10d, 8(%rsi) /* d0 */
+ mov %r11d, 12(%rsi) /* d1 */
+ mov %r12d, 16(%rsi) /* d2 */
+ mov %r13d, 40(%rsi) /* a0 */
+ mov %r14d, 44(%rsi) /* a1 */
+ mov %r15d, 68(%rsi) /* a7 */
+ ret
+
+ .global m68k_load_context
+m68k_load_context:
+ mov 1(%rsi), %bl /* N Flag */
+ mov 2(%rsi), %bh /* V flag */
+ mov 3(%rsi), %dl /* Z flag */
+ mov 4(%rsi), %dh /* C flag */
+ mov 8(%rsi), %r10d /* d0 */
+ mov 12(%rsi), %r11d /* d1 */
+ mov 16(%rsi), %r12d /* d2 */
+ mov 40(%rsi), %r13d /* a0 */
+ mov 44(%rsi), %r14d /* a1 */
+ mov 68(%rsi), %r15d /* a7 */
+ mov 72(%rsi), %ebp /* target cycle count */
+ mov 76(%rsi), %eax /* current cycle count */
+ mov 80(%rsi), %r8d /* cartridge address */
+ mov 88(%rsi), %r9d /* work ram address */
+ ret
+
+ .global m68k_start_context
+m68k_start_context:
+ call m68k_load_context
+ jmp *%rdi
diff --git a/trans.c b/trans.c
new file mode 100644
index 0000000..0b6e25e
--- /dev/null
+++ b/trans.c
@@ -0,0 +1,39 @@
+#include "68kinst.h"
+#include "m68k_to_x86.h"
+#include "mem.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char ** argv)
+{
+ long filesize;
+ unsigned short *filebuf;
+ char disbuf[1024];
+ size_t size = 1024 * 1024;
+ uint8_t * transbuf = alloc_code(&size);
+ uint8_t *trans_cur, *end;
+ unsigned short * cur;
+ x86_68k_options opts;
+ m68k_context context;
+ FILE * f = fopen(argv[1], "rb");
+ fseek(f, 0, SEEK_END);
+ filesize = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ filebuf = malloc(filesize);
+ fread(filebuf, 2, filesize/2, f);
+ fclose(f);
+ for(cur = filebuf; cur - filebuf < (filesize/2); ++cur)
+ {
+ *cur = (*cur >> 8) | (*cur << 8);
+ }
+ init_x86_68k_opts(&opts);
+ init_68k_context(&context, opts.native_code_map, &opts);
+ //cartridge ROM
+ context.mem_pointers[0] = filebuf;
+ context.target_cycle = 0x7FFFFFFF;
+ //work RAM
+ context.mem_pointers[1] = malloc(64 * 1024);
+ translate_m68k_stream(transbuf, transbuf + size, 0, &context);
+ start_68k_context(&context, 0);
+ return 0;
+}