changeset 18:3e7bfde7606e

M68K to x86 translation works for a limited subset of instructions and addressing modes
author Mike Pavone <pavone@retrodev.com>
date Tue, 04 Dec 2012 19:13:12 -0800
parents de0085d4ea40
children 4717146a7606
files 68kinst.c 68kinst.h Makefile dis.c gen_x86.c gen_x86.h m68k_to_x86.c m68k_to_x86.h mem.c notes.txt runtime.S trans.c
diffstat 12 files changed, 1256 insertions(+), 176 deletions(-) [+]
line wrap: on
line diff
--- a/68kinst.c	Tue Nov 27 22:54:38 2012 -0800
+++ b/68kinst.c	Tue Dec 04 19:13:12 2012 -0800
@@ -86,12 +86,12 @@
 	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 @@
 	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 @@
 				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 @@
 				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 @@
 	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 @@
 			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 @@
 				}
 				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 @@
 			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 @@
 		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 @@
 					//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 @@
 				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 @@
 				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 @@
 				//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 @@
 				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 @@
 				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 @@
 				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 @@
 					//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 @@
 				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 @@
 				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;
--- a/68kinst.h	Tue Nov 27 22:54:38 2012 -0800
+++ b/68kinst.h	Tue Dec 04 19:13:12 2012 -0800
@@ -169,13 +169,14 @@
 		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
 
--- a/Makefile	Tue Nov 27 22:54:38 2012 -0800
+++ b/Makefile	Tue Dec 04 19:13:12 2012 -0800
@@ -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 @@
 	$(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
--- a/dis.c	Tue Nov 27 22:54:38 2012 -0800
+++ b/dis.c	Tue Dec 04 19:13:12 2012 -0800
@@ -24,9 +24,9 @@
 	{
 		//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;
 }
--- a/gen_x86.c	Tue Nov 27 22:54:38 2012 -0800
+++ b/gen_x86.c	Tue Dec 04 19:13:12 2012 -0800
@@ -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 @@
 	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 @@
 	}
 	*(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 @@
 	}
 	*(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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 		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 @@
 	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 @@
 	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;
+		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;
-		disp >>= 8;
-		*(out++) = disp;
-		disp >>= 8;
-		*(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 @@
 		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;
--- a/gen_x86.h	Tue Nov 27 22:54:38 2012 -0800
+++ b/gen_x86.h	Tue Dec 04 19:13:12 2012 -0800
@@ -52,6 +52,19 @@
 	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 * 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);
 
--- a/m68k_to_x86.c	Tue Nov 27 22:54:38 2012 -0800
+++ b/m68k_to_x86.c	Tue Dec 04 19:13:12 2012 -0800
@@ -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 @@
 } 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 @@
 	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)
 {
-	int8_t reg = native_reg(op, opts);
+	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(&(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:
+		//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_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:
-		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;
+		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)
+{
+	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)
 {
-	int8_t reg_a, reg_b, flags_reg;
-	uint8_t dir = 0;
-	int32_t offset;
+	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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;
+}
+
--- a/m68k_to_x86.h	Tue Nov 27 22:54:38 2012 -0800
+++ b/m68k_to_x86.h	Tue Dec 04 19:13:12 2012 -0800
@@ -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 {
-	uint32_t flags;
-	int8_t   dregs[8];
-	int8_t   aregs[8];
+	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];
+	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);
--- a/mem.c	Tue Nov 27 22:54:38 2012 -0800
+++ b/mem.c	Tue Dec 04 19:13:12 2012 -0800
@@ -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;
+}
--- a/notes.txt	Tue Nov 27 22:54:38 2012 -0800
+++ b/notes.txt	Tue Dec 04 19:13:12 2012 -0800
@@ -36,16 +36,15 @@
 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:
--- a/runtime.S	Tue Nov 27 22:54:38 2012 -0800
+++ b/runtime.S	Tue Dec 04 19:13:12 2012 -0800
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/trans.c	Tue Dec 04 19:13:12 2012 -0800
@@ -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;
+}