changeset 574:1594525e2157

More 68K core refactoring to both reduce the amount of code and better split the host-cpu specific parts from the generic parts
author Michael Pavone <pavone@retrodev.com>
date Mon, 03 Mar 2014 22:17:20 -0800
parents 29d99db6f55d
children f90da1c2ba86
files gen.h m68k_core.c m68k_core_x86.c m68k_internal.h
diffstat 4 files changed, 545 insertions(+), 1021 deletions(-) [+]
line wrap: on
line diff
--- a/gen.h	Mon Mar 03 22:16:41 2014 -0800
+++ b/gen.h	Mon Mar 03 22:17:20 2014 -0800
@@ -20,5 +20,6 @@
 void init_code_info(code_info *code);
 void call(code_info *code, code_ptr fun);
 void jmp(code_info *code, code_ptr dest);
+void jmp_r(code_info *code, uint8_t dst);
 
 #endif //GEN_H_
--- a/m68k_core.c	Mon Mar 03 22:16:41 2014 -0800
+++ b/m68k_core.c	Mon Mar 03 22:17:20 2014 -0800
@@ -13,6 +13,8 @@
 #include <stdlib.h>
 #include <string.h>
 
+char disasm_buf[1024];
+
 int8_t native_reg(m68k_op_info * op, m68k_options * opts)
 {
 	if (op->addr_mode == MODE_REG) {
@@ -24,13 +26,20 @@
 	return -1;
 }
 
+size_t dreg_offset(uint8_t reg)
+{
+	return offsetof(m68k_context, dregs) + sizeof(uint32_t) * reg;
+}
+
+size_t areg_offset(uint8_t reg)
+{
+	return offsetof(m68k_context, aregs) + sizeof(uint32_t) * reg;
+}
+
 //must be called with an m68k_op_info that uses a register
 size_t reg_offset(m68k_op_info *op)
 {
-	if (op->addr_mode == MODE_REG) {
-		return offsetof(m68k_context, dregs) + sizeof(uint32_t) * op->params.regs.pri;
-	}
-	return offsetof(m68k_context, aregs) + sizeof(uint32_t) * op->params.regs.pri;
+	return op->addr_mode == MODE_REG ? dreg_offset(op->params.regs.pri) : areg_offset(op->params.regs.pri);
 }
 
 void print_regs_exit(m68k_context * context)
@@ -77,6 +86,281 @@
 	}
 }
 
+void translate_m68k_lea(m68k_options * opts, m68kinst * inst)
+{
+	code_info *code = &opts->gen.code;
+	int8_t dst_reg = native_reg(&(inst->dst), opts);
+	switch(inst->src.addr_mode)
+	{
+	case MODE_AREG_INDIRECT:
+		cycles(&opts->gen, BUS);
+		if (dst_reg >= 0) {
+			areg_to_native(opts, inst->src.params.regs.pri, dst_reg);
+		} else {
+			if (opts->aregs[inst->src.params.regs.pri] >= 0) {
+				native_to_areg(opts, opts->aregs[inst->src.params.regs.pri], inst->dst.params.regs.pri);
+			} else {
+				areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1);
+				native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
+			}
+		}
+		break;
+	case MODE_AREG_DISPLACE:
+		cycles(&opts->gen, 8);
+		calc_areg_displace(opts, &inst->src, dst_reg >= 0 ? dst_reg : opts->gen.scratch1);
+		if (dst_reg < 0) {
+			native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
+		}
+		break;
+	case MODE_AREG_INDEX_DISP8:
+		cycles(&opts->gen, 12);
+		if (dst_reg < 0 || inst->dst.params.regs.pri == inst->src.params.regs.pri || inst->dst.params.regs.pri == (inst->src.params.regs.sec >> 1 & 0x7)) {
+			dst_reg = opts->gen.scratch1;
+		}
+		calc_areg_index_disp8(opts, &inst->src, dst_reg);
+		if (dst_reg == opts->gen.scratch1) {
+			native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
+		}
+		break;
+	case MODE_PC_DISPLACE:
+		cycles(&opts->gen, 8);
+		ldi_areg(opts, inst->src.params.regs.displacement + inst->address+2, inst->dst.params.regs.pri);
+		break;
+	case MODE_PC_INDEX_DISP8:
+		cycles(&opts->gen, BUS*3);
+		if (dst_reg < 0 || inst->dst.params.regs.pri == (inst->src.params.regs.sec >> 1 & 0x7)) {
+			dst_reg = opts->gen.scratch1;
+		}
+		ldi_native(opts, inst->address+2, dst_reg);
+		calc_index_disp8(opts, &inst->src, dst_reg);
+		if (dst_reg == opts->gen.scratch1) {
+			native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
+		}
+		break;
+	case MODE_ABSOLUTE:
+	case MODE_ABSOLUTE_SHORT:
+		cycles(&opts->gen, (inst->src.addr_mode == MODE_ABSOLUTE) ? BUS * 3 : BUS * 2);
+		ldi_areg(opts, inst->src.params.immed, inst->dst.params.regs.pri);
+		break;
+	default:
+		m68k_disasm(inst, disasm_buf);
+		printf("%X: %s\naddress mode %d not implemented (lea src)\n", inst->address, disasm_buf, inst->src.addr_mode);
+		exit(1);
+	}
+}
+
+void translate_m68k_pea(m68k_options * opts, m68kinst * inst)
+{
+	code_info *code = &opts->gen.code;
+	switch(inst->src.addr_mode)
+	{
+	case MODE_AREG_INDIRECT:
+		cycles(&opts->gen, BUS);
+		areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1);
+		break;
+	case MODE_AREG_DISPLACE:
+		cycles(&opts->gen, 8);
+		calc_areg_displace(opts, &inst->src, opts->gen.scratch1);
+		break;
+	case MODE_AREG_INDEX_DISP8:
+		cycles(&opts->gen, 6);//TODO: Check to make sure this is correct
+		calc_areg_index_disp8(opts, &inst->src, opts->gen.scratch1);
+		break;
+	case MODE_PC_DISPLACE:
+		cycles(&opts->gen, 8);
+		ldi_native(opts, inst->src.params.regs.displacement + inst->address+2, opts->gen.scratch1);
+		break;
+	case MODE_PC_INDEX_DISP8:
+		cycles(&opts->gen, BUS*3);//TODO: Check to make sure this is correct
+		ldi_native(opts, inst->address+2, opts->gen.scratch1);
+		calc_index_disp8(opts, &inst->src, opts->gen.scratch1);
+		break;
+	case MODE_ABSOLUTE:
+	case MODE_ABSOLUTE_SHORT:
+		cycles(&opts->gen, (inst->src.addr_mode == MODE_ABSOLUTE) ? BUS * 3 : BUS * 2);
+		ldi_native(opts, inst->src.params.immed, opts->gen.scratch1);
+		break;
+	default:
+		m68k_disasm(inst, disasm_buf);
+		printf("%X: %s\naddress mode %d not implemented (lea src)\n", inst->address, disasm_buf, inst->src.addr_mode);
+		exit(1);
+	}
+	subi_areg(opts, 4, 7);
+	areg_to_native(opts, 7, opts->gen.scratch2);
+	call(code, opts->write_32_lowfirst);
+}
+
+void push_const(m68k_options *opts, int32_t value)
+{
+	ldi_native(opts, value, opts->gen.scratch1);
+	subi_areg(opts, 4, 7);
+	areg_to_native(opts, 7, opts->gen.scratch2);
+	call(&opts->gen.code, opts->write_32_highfirst);
+}
+
+void jump_m68k_abs(m68k_options * opts, uint32_t address)
+{
+	code_info *code = &opts->gen.code;
+	code_ptr dest_addr = get_native_address(opts->gen.native_code_map, address);
+	if (!dest_addr) {
+		opts->gen.deferred = defer_address(opts->gen.deferred, address, code->cur + 1);
+		//dummy address to be replaced later, make sure it generates a 4-byte displacement
+		dest_addr = code->cur + 256;
+	}
+	jmp(code, dest_addr);
+	//this used to call opts->native_addr for destinations in RAM, but that shouldn't be needed
+	//since instruction retranslation patches the original native instruction location
+}
+
+void translate_m68k_bsr(m68k_options * opts, m68kinst * inst)
+{
+	code_info *code = &opts->gen.code;
+	int32_t disp = inst->src.params.immed;
+	uint32_t after = inst->address + (inst->variant == VAR_BYTE ? 2 : 4);
+	//TODO: Add cycles in the right place relative to pushing the return address on the stack
+	cycles(&opts->gen, 10);
+	push_const(opts, after);
+	jump_m68k_abs(opts, inst->address + 2 + disp);
+}
+
+void translate_m68k_jmp_jsr(m68k_options * opts, m68kinst * inst)
+{
+	uint8_t is_jsr = inst->op == M68K_JSR;
+	code_info *code = &opts->gen.code;
+	code_ptr dest_addr;
+	uint8_t sec_reg;
+	uint32_t after;
+	uint32_t m68k_addr;
+	switch(inst->src.addr_mode)
+	{
+	case MODE_AREG_INDIRECT:
+		cycles(&opts->gen, BUS*2);
+		if (is_jsr) {
+			push_const(opts, inst->address+2);
+		}
+		areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1);
+		call(code, opts->native_addr);
+		jmp_r(code, opts->gen.scratch1);
+		break;
+	case MODE_AREG_DISPLACE:
+		cycles(&opts->gen, BUS*2);
+		if (is_jsr) {
+			push_const(opts, inst->address+4);
+		}
+		calc_areg_displace(opts, &inst->src, opts->gen.scratch1);
+		call(code, opts->native_addr);
+		jmp_r(code, opts->gen.scratch1);
+		break;
+	case MODE_AREG_INDEX_DISP8:
+		cycles(&opts->gen, BUS*3);//TODO: CHeck that this is correct
+		if (is_jsr) {
+			push_const(opts, inst->address+4);
+		}
+		calc_areg_index_disp8(opts, &inst->src, opts->gen.scratch1);
+		call(code, opts->native_addr);
+		jmp_r(code, opts->gen.scratch1);
+		break;
+	case MODE_PC_DISPLACE:
+		//TODO: Add cycles in the right place relative to pushing the return address on the stack
+		cycles(&opts->gen, 10);
+		if (is_jsr) {
+			push_const(opts, inst->address+4);
+		}
+		jump_m68k_abs(opts, inst->src.params.regs.displacement + inst->address + 2);
+		break;
+	case MODE_PC_INDEX_DISP8:
+		cycles(&opts->gen, BUS*3);//TODO: CHeck that this is correct
+		if (is_jsr) {
+			push_const(opts, inst->address+4);
+		}
+		ldi_native(opts, inst->address+2, opts->gen.scratch1);
+		calc_index_disp8(opts, &inst->src, opts->gen.scratch1);
+		call(code, opts->native_addr);
+		jmp_r(code, opts->gen.scratch1);
+		break;
+	case MODE_ABSOLUTE:
+	case MODE_ABSOLUTE_SHORT:
+		//TODO: Add cycles in the right place relative to pushing the return address on the stack
+		cycles(&opts->gen, inst->src.addr_mode == MODE_ABSOLUTE ? 12 : 10);
+		if (is_jsr) {
+			push_const(opts, inst->address + (inst->src.addr_mode == MODE_ABSOLUTE ? 6 : 4));
+		}
+		jump_m68k_abs(opts, inst->src.params.immed);
+		break;
+	default:
+		m68k_disasm(inst, disasm_buf);
+		printf("%s\naddress mode %d not yet supported (%s)\n", disasm_buf, inst->src.addr_mode, is_jsr ? "jsr" : "jmp");
+		exit(1);
+	}
+}
+
+void translate_m68k_unlk(m68k_options * opts, m68kinst * inst)
+{
+	cycles(&opts->gen, BUS);
+	areg_to_native(opts, inst->dst.params.regs.pri, opts->aregs[7]);
+	areg_to_native(opts, 7, opts->gen.scratch1);
+	call(&opts->gen.code, opts->read_32);
+	native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
+	addi_areg(opts, 4, 7);
+}
+
+void translate_m68k_link(m68k_options * opts, m68kinst * inst)
+{
+	//compensate for displacement word
+	cycles(&opts->gen, BUS);
+	subi_areg(opts, 4, 7);
+	areg_to_native(opts, 7, opts->gen.scratch2);
+	areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1);
+	call(&opts->gen.code, opts->write_32_highfirst);
+	native_to_areg(opts, opts->aregs[7], inst->src.params.regs.pri);
+	addi_areg(opts, inst->dst.params.immed, 7);
+	//prefetch
+	cycles(&opts->gen, BUS);
+}
+
+void translate_m68k_rts(m68k_options * opts, m68kinst * inst)
+{
+	code_info *code = &opts->gen.code;
+	//TODO: Add cycles
+	areg_to_native(opts, 7, opts->gen.scratch1);
+	addi_areg(opts, 4, 7);
+	call(code, opts->read_32);
+	call(code, opts->native_addr);
+	jmp_r(code, opts->gen.scratch1);
+}
+
+void translate_m68k_rtr(m68k_options *opts, m68kinst * inst)
+{
+	code_info *code = &opts->gen.code;
+	//Read saved CCR
+	areg_to_native(opts, 7, opts->gen.scratch1);
+	call(code, opts->read_16);
+	addi_areg(opts, 2, 7);
+	call(code, opts->set_ccr);
+	//Read saved PC
+	areg_to_native(opts, 7, opts->gen.scratch1);
+	call(code, opts->read_32);
+	addi_areg(opts, 4, 7);
+	//Get native address and jump to it
+	call(code, opts->native_addr);
+	jmp_r(code, opts->gen.scratch1);
+}
+
+void translate_m68k_trap(m68k_options *opts, m68kinst *inst)
+{
+	code_info *code = &opts->gen.code;
+	ldi_native(opts, inst->src.params.immed + VECTOR_TRAP_0, opts->gen.scratch2);
+	ldi_native(opts, inst->address+2, opts->gen.scratch1);
+	jmp(code, opts->trap);
+}
+
+void swap_ssp_usp(m68k_options * opts)
+{
+	areg_to_native(opts, 7, opts->gen.scratch2);
+	areg_to_native(opts, 8, opts->aregs[7]);
+	native_to_areg(opts, opts->gen.scratch2, 8);
+}
+
 code_ptr get_native_address(native_map_slot * native_code_map, uint32_t address)
 {
 	address &= 0xFFFFFF;
@@ -278,3 +562,12 @@
 	start_68k_context(context, address);
 }
 
+
+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;
+	context->int_cycle = 0xFFFFFFFF;
+	context->status = 0x27;
+}
--- a/m68k_core_x86.c	Mon Mar 03 22:16:41 2014 -0800
+++ b/m68k_core_x86.c	Mon Mar 03 22:17:20 2014 -0800
@@ -14,9 +14,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#define BUS 4
-#define PREDEC_PENALTY 2
-
 #define CYCLES RAX
 #define LIMIT RBP
 #define CONTEXT RSI
@@ -36,15 +33,6 @@
 	FLAG_C
 };
 
-char disasm_buf[1024];
-
-m68k_context * sync_components(m68k_context * context, uint32_t address);
-
-void m68k_invalid();
-void bcd_add();
-void bcd_sub();
-
-
 void set_flag(m68k_options * opts, uint8_t val, uint8_t flag)
 {
 	if (opts->flag_regs[flag] >= 0) {
@@ -181,6 +169,145 @@
 	}
 }
 
+void areg_to_native(m68k_options *opts, uint8_t reg, uint8_t native_reg)
+{
+	if (opts->aregs[reg] >= 0) {
+		mov_rr(&opts->gen.code, opts->aregs[reg], native_reg, SZ_D);
+	} else {
+		mov_rdispr(&opts->gen.code, opts->gen.context_reg,  areg_offset(reg), native_reg, SZ_D);
+	}
+}
+
+void dreg_to_native(m68k_options *opts, uint8_t reg, uint8_t native_reg)
+{
+	if (opts->dregs[reg] >= 0) {
+		mov_rr(&opts->gen.code, opts->dregs[reg], native_reg, SZ_D);
+	} else {
+		mov_rdispr(&opts->gen.code, opts->gen.context_reg,  dreg_offset(reg), native_reg, SZ_D);
+	}
+}
+
+void areg_to_native_sx(m68k_options *opts, uint8_t reg, uint8_t native_reg)
+{
+	if (opts->aregs[reg] >= 0) {
+		movsx_rr(&opts->gen.code, opts->aregs[reg], native_reg, SZ_W, SZ_D);
+	} else {
+		movsx_rdispr(&opts->gen.code, opts->gen.context_reg,  areg_offset(reg), native_reg, SZ_W, SZ_D);
+	}
+}
+
+void dreg_to_native_sx(m68k_options *opts, uint8_t reg, uint8_t native_reg)
+{
+	if (opts->dregs[reg] >= 0) {
+		movsx_rr(&opts->gen.code, opts->dregs[reg], native_reg, SZ_W, SZ_D);
+	} else {
+		movsx_rdispr(&opts->gen.code, opts->gen.context_reg,  dreg_offset(reg), native_reg, SZ_W, SZ_D);
+	}
+}
+
+void native_to_areg(m68k_options *opts, uint8_t native_reg, uint8_t reg)
+{
+	if (opts->aregs[reg] >= 0) {
+		mov_rr(&opts->gen.code, native_reg, opts->aregs[reg], SZ_D);
+	} else {
+		mov_rrdisp(&opts->gen.code, native_reg, opts->gen.context_reg, areg_offset(reg), SZ_D);
+	}
+}
+
+void native_to_dreg(m68k_options *opts, uint8_t native_reg, uint8_t reg)
+{
+	if (opts->dregs[reg] >= 0) {
+		mov_rr(&opts->gen.code, native_reg, opts->dregs[reg], SZ_D);
+	} else {
+		mov_rrdisp(&opts->gen.code, native_reg, opts->gen.context_reg, dreg_offset(reg), SZ_D);
+	}
+}
+
+void ldi_areg(m68k_options *opts, int32_t value, uint8_t reg)
+{
+	if (opts->aregs[reg] >= 0) {
+		mov_ir(&opts->gen.code, value, opts->aregs[reg], SZ_D);
+	} else {
+		mov_irdisp(&opts->gen.code, value, opts->gen.context_reg, areg_offset(reg), SZ_D);
+	}
+}
+
+void ldi_native(m68k_options *opts, int32_t value, uint8_t reg)
+{
+	mov_ir(&opts->gen.code, value, reg, SZ_D);
+}
+
+void addi_areg(m68k_options *opts, int32_t val, uint8_t reg)
+{
+	if (opts->aregs[reg] >= 0) {
+		add_ir(&opts->gen.code, val, opts->aregs[reg], SZ_D);
+	} else {
+		add_irdisp(&opts->gen.code, val, opts->gen.context_reg, areg_offset(reg), SZ_D);
+	}
+}
+
+void subi_areg(m68k_options *opts, int32_t val, uint8_t reg)
+{
+	if (opts->aregs[reg] >= 0) {
+		sub_ir(&opts->gen.code, val, opts->aregs[reg], SZ_D);
+	} else {
+		sub_irdisp(&opts->gen.code, val, opts->gen.context_reg, areg_offset(reg), SZ_D);
+	}
+}
+
+void add_areg_native(m68k_options *opts, uint8_t reg, uint8_t native_reg)
+{
+	if (opts->aregs[reg] >= 0) {
+		add_rr(&opts->gen.code, opts->aregs[reg], native_reg, SZ_D);
+	} else {
+		add_rdispr(&opts->gen.code, opts->gen.context_reg, areg_offset(reg), native_reg, SZ_D);
+	}
+}
+
+void add_dreg_native(m68k_options *opts, uint8_t reg, uint8_t native_reg)
+{
+	if (opts->dregs[reg] >= 0) {
+		add_rr(&opts->gen.code, opts->dregs[reg], native_reg, SZ_D);
+	} else {
+		add_rdispr(&opts->gen.code, opts->gen.context_reg, dreg_offset(reg), native_reg, SZ_D);
+	}
+}
+
+void calc_areg_displace(m68k_options *opts, m68k_op_info *op, uint8_t native_reg)
+{
+	areg_to_native(opts, op->params.regs.pri, native_reg);
+	add_ir(&opts->gen.code, op->params.regs.displacement, native_reg, SZ_D);
+}
+
+void calc_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_reg)
+{
+	uint8_t sec_reg = (op->params.regs.sec >> 1) & 0x7;
+	if (op->params.regs.sec & 1) {
+		if (op->params.regs.sec & 0x10) {
+			add_areg_native(opts, sec_reg, native_reg);
+		} else {
+			add_dreg_native(opts, sec_reg, native_reg);
+		}
+	} else {
+		uint8_t other_reg = native_reg == opts->gen.scratch1 ? opts->gen.scratch2 : opts->gen.scratch1;
+		if (op->params.regs.sec & 0x10) {
+			areg_to_native_sx(opts, sec_reg, other_reg);
+		} else {
+			dreg_to_native_sx(opts, sec_reg, other_reg);
+		}
+		add_rr(&opts->gen.code, other_reg, native_reg, SZ_D);
+	}
+	if (op->params.regs.displacement) {
+		add_ir(&opts->gen.code, op->params.regs.displacement, native_reg, SZ_D);
+	}
+}
+
+void calc_areg_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_reg)
+{
+	areg_to_native(opts, op->params.regs.pri, native_reg);
+	calc_index_disp8(opts, op, native_reg);
+}
+
 void translate_m68k_op(m68kinst * inst, x86_ea * ea, m68k_options * opts, uint8_t dst)
 {
 	code_info *code = &opts->gen.code;
@@ -230,18 +357,10 @@
 		if (!dst) {
 			cycles(&opts->gen, PREDEC_PENALTY);
 		}
-		if (opts->aregs[op->params.regs.pri] >= 0) {
-			sub_ir(code, dec_amount, opts->aregs[op->params.regs.pri], SZ_D);
-		} else {
-			sub_irdisp(code, dec_amount, opts->gen.context_reg, reg_offset(op), SZ_D);
-		}
+		subi_areg(opts, dec_amount, op->params.regs.pri);
 	case MODE_AREG_INDIRECT:
 	case MODE_AREG_POSTINC:
-		if (opts->aregs[op->params.regs.pri] >= 0) {
-			mov_rr(code, opts->aregs[op->params.regs.pri], opts->gen.scratch1, SZ_D);
-		} else {
-			mov_rdispr(code, opts->gen.context_reg,  reg_offset(op), opts->gen.scratch1, SZ_D);
-		}
+		areg_to_native(opts, op->params.regs.pri, opts->gen.scratch1);
 		m68k_read_size(opts, inst->extra.size);
 
 		if (dst) {
@@ -250,33 +369,20 @@
 				pop_r(code, opts->gen.scratch2);
 			} else {
 				//save reg value in opts->gen.scratch2 so we can use it to save the result in memory later
-				if (opts->aregs[op->params.regs.pri] >= 0) {
-					mov_rr(code, opts->aregs[op->params.regs.pri], opts->gen.scratch2, SZ_D);
-				} else {
-					mov_rdispr(code, opts->gen.context_reg, reg_offset(op), opts->gen.scratch2, SZ_D);
-				}
+				areg_to_native(opts, op->params.regs.pri, opts->gen.scratch2);
 			}
 		}
 
 		if (op->addr_mode == MODE_AREG_POSTINC) {
 			inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (op->params.regs.pri == 7 ? 2 : 1));
-			if (opts->aregs[op->params.regs.pri] >= 0) {
-				add_ir(code, inc_amount, opts->aregs[op->params.regs.pri], SZ_D);
-			} else {
-				add_irdisp(code, inc_amount, opts->gen.context_reg, reg_offset(op), SZ_D);
-			}
+			addi_areg(opts, inc_amount, op->params.regs.pri);
 		}
 		ea->mode = MODE_REG_DIRECT;
 		ea->base = (!dst && inst->dst.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) ? opts->gen.scratch2 : opts->gen.scratch1;
 		break;
 	case MODE_AREG_DISPLACE:
 		cycles(&opts->gen, BUS);
-		if (opts->aregs[op->params.regs.pri] >= 0) {
-			mov_rr(code, opts->aregs[op->params.regs.pri], opts->gen.scratch1, SZ_D);
-		} else {
-			mov_rdispr(code, opts->gen.context_reg,  reg_offset(op), opts->gen.scratch1, SZ_D);
-		}
-		add_ir(code, op->params.regs.displacement, opts->gen.scratch1, SZ_D);
+		calc_areg_displace(opts, op, opts->gen.scratch1);
 		if (dst) {
 			push_r(code, opts->gen.scratch1);
 		}
@@ -290,45 +396,7 @@
 		break;
 	case MODE_AREG_INDEX_DISP8:
 		cycles(&opts->gen, 6);
-		if (opts->aregs[op->params.regs.pri] >= 0) {
-			mov_rr(code, opts->aregs[op->params.regs.pri], opts->gen.scratch1, SZ_D);
-		} else {
-			mov_rdispr(code, opts->gen.context_reg,  reg_offset(op), opts->gen.scratch1, SZ_D);
-		}
-		sec_reg = (op->params.regs.sec >> 1) & 0x7;
-		if (op->params.regs.sec & 1) {
-			if (op->params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					add_rr(code, opts->aregs[sec_reg], opts->gen.scratch1, SZ_D);
-				} else {
-					add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					add_rr(code, opts->dregs[sec_reg], opts->gen.scratch1, SZ_D);
-				} else {
-					add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D);
-				}
-			}
-		} else {
-			if (op->params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					movsx_rr(code, opts->aregs[sec_reg], opts->gen.scratch2, SZ_W, SZ_D);
-				} else {
-					movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					movsx_rr(code, opts->dregs[sec_reg], opts->gen.scratch2, SZ_W, SZ_D);
-				} else {
-					movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D);
-				}
-			}
-			add_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_D);
-		}
-		if (op->params.regs.displacement) {
-			add_ir(code, op->params.regs.displacement, opts->gen.scratch1, SZ_D);
-		}
+		calc_areg_index_disp8(opts, op, opts->gen.scratch1);
 		if (dst) {
 			push_r(code, opts->gen.scratch1);
 		}
@@ -357,40 +425,7 @@
 	case MODE_PC_INDEX_DISP8:
 		cycles(&opts->gen, 6);
 		mov_ir(code, inst->address+2, opts->gen.scratch1, SZ_D);
-		sec_reg = (op->params.regs.sec >> 1) & 0x7;
-		if (op->params.regs.sec & 1) {
-			if (op->params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					add_rr(code, opts->aregs[sec_reg], opts->gen.scratch1, SZ_D);
-				} else {
-					add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					add_rr(code, opts->dregs[sec_reg], opts->gen.scratch1, SZ_D);
-				} else {
-					add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D);
-				}
-			}
-		} else {
-			if (op->params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					movsx_rr(code, opts->aregs[sec_reg], opts->gen.scratch2, SZ_W, SZ_D);
-				} else {
-					movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					movsx_rr(code, opts->dregs[sec_reg], opts->gen.scratch2, SZ_W, SZ_D);
-				} else {
-					movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D);
-				}
-			}
-			add_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_D);
-		}
-		if (op->params.regs.displacement) {
-			add_ir(code, op->params.regs.displacement, opts->gen.scratch1, SZ_D);
-		}
+		calc_index_disp8(opts, op, opts->gen.scratch1);
 		if (dst) {
 			push_r(code, opts->gen.scratch1);
 		}
@@ -450,11 +485,7 @@
 	code_info *code = &opts->gen.code;
 	if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG) {
 		if (inst->dst.addr_mode == MODE_AREG_PREDEC && inst->src.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) {
-			if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
-				mov_rr(code, opts->aregs[inst->dst.params.regs.pri], opts->gen.scratch2, SZ_D);
-			} else {
-				mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->dst)), opts->gen.scratch2, SZ_D);
-			}
+			areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2);
 		}
 		switch (inst->extra.size)
 		{
@@ -531,18 +562,10 @@
 		break;
 	case MODE_AREG_PREDEC:
 		dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1));
-		if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
-			sub_ir(code, dec_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D);
-		} else {
-			sub_irdisp(code, dec_amount, opts->gen.context_reg, reg_offset(&(inst->dst)), SZ_D);
-		}
+		subi_areg(opts, dec_amount, inst->dst.params.regs.pri);
 	case MODE_AREG_INDIRECT:
 	case MODE_AREG_POSTINC:
-		if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
-			mov_rr(code, opts->aregs[inst->dst.params.regs.pri], opts->gen.scratch2, SZ_D);
-		} else {
-			mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->dst)), opts->gen.scratch2, SZ_D);
-		}
+		areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2);
 		if (src.mode == MODE_REG_DIRECT) {
 			if (src.base != opts->gen.scratch1) {
 				mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
@@ -561,21 +584,12 @@
 
 		if (inst->dst.addr_mode == MODE_AREG_POSTINC) {
 			inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1));
-			if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
-				add_ir(code, inc_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D);
-			} else {
-				add_irdisp(code, inc_amount, opts->gen.context_reg, reg_offset(&(inst->dst)), SZ_D);
-			}
+			addi_areg(opts, inc_amount, inst->dst.params.regs.pri);
 		}
 		break;
 	case MODE_AREG_DISPLACE:
 		cycles(&opts->gen, BUS);
-		if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
-			mov_rr(code, opts->aregs[inst->dst.params.regs.pri], opts->gen.scratch2, SZ_D);
-		} else {
-			mov_rdispr(code, opts->gen.context_reg,  reg_offset(&(inst->dst)), opts->gen.scratch2, SZ_D);
-		}
-		add_ir(code, inst->dst.params.regs.displacement, opts->gen.scratch2, SZ_D);
+		calc_areg_displace(opts, &inst->dst, opts->gen.scratch2);
 		if (src.mode == MODE_REG_DIRECT) {
 			if (src.base != opts->gen.scratch1) {
 				mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
@@ -594,50 +608,13 @@
 		break;
 	case MODE_AREG_INDEX_DISP8:
 		cycles(&opts->gen, 6);//TODO: Check to make sure this is correct
-		if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
-			mov_rr(code, opts->aregs[inst->dst.params.regs.pri], opts->gen.scratch2, SZ_D);
-		} else {
-			mov_rdispr(code, opts->gen.context_reg,  reg_offset(&(inst->dst)), opts->gen.scratch2, SZ_D);
+		//calc_areg_index_disp8 will clober scratch1 when a 16-bit index is used
+		if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) {
+			push_r(code, opts->gen.scratch1);
 		}
-		sec_reg = (inst->dst.params.regs.sec >> 1) & 0x7;
-		if (inst->dst.params.regs.sec & 1) {
-			if (inst->dst.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					add_rr(code, opts->aregs[sec_reg], opts->gen.scratch2, SZ_D);
-				} else {
-					add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					add_rr(code, opts->dregs[sec_reg], opts->gen.scratch2, SZ_D);
-				} else {
-					add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_D);
-				}
-			}
-		} else {
-			if (src.base == opts->gen.scratch1) {
-				push_r(code, opts->gen.scratch1);
-			}
-			if (inst->dst.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					movsx_rr(code, opts->aregs[sec_reg], opts->gen.scratch1, SZ_W, SZ_D);
-				} else {
-					movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_W, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					movsx_rr(code, opts->dregs[sec_reg], opts->gen.scratch1, SZ_W, SZ_D);
-				} else {
-					movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_W, SZ_D);
-				}
-			}
-			add_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_D);
-			if (src.base == opts->gen.scratch1) {
-				pop_r(code, opts->gen.scratch1);
-			}
-		}
-		if (inst->dst.params.regs.displacement) {
-			add_ir(code, inst->dst.params.regs.displacement, opts->gen.scratch2, SZ_D);
+		calc_areg_index_disp8(opts, &inst->dst, opts->gen.scratch2);
+		if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) {
+			pop_r(code, opts->gen.scratch1);
 		}
 		if (src.mode == MODE_REG_DIRECT) {
 			if (src.base != opts->gen.scratch1) {
@@ -677,45 +654,12 @@
 	case MODE_PC_INDEX_DISP8:
 		cycles(&opts->gen, 6);//TODO: Check to make sure this is correct
 		mov_ir(code, inst->address, opts->gen.scratch2, SZ_D);
-		sec_reg = (inst->dst.params.regs.sec >> 1) & 0x7;
-		if (inst->dst.params.regs.sec & 1) {
-			if (inst->dst.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					add_rr(code, opts->aregs[sec_reg], opts->gen.scratch2, SZ_D);
-				} else {
-					add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					add_rr(code, opts->dregs[sec_reg], opts->gen.scratch2, SZ_D);
-				} else {
-					add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_D);
-				}
-			}
-		} else {
-			if (src.base == opts->gen.scratch1) {
-				push_r(code, opts->gen.scratch1);
-			}
-			if (inst->dst.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					movsx_rr(code, opts->aregs[sec_reg], opts->gen.scratch1, SZ_W, SZ_D);
-				} else {
-					movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_W, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					movsx_rr(code, opts->dregs[sec_reg], opts->gen.scratch1, SZ_W, SZ_D);
-				} else {
-					movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_W, SZ_D);
-				}
-			}
-			add_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_D);
-			if (src.base == opts->gen.scratch1) {
-				pop_r(code, opts->gen.scratch1);
-			}
+		if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) {
+			push_r(code, opts->gen.scratch1);
 		}
-		if (inst->dst.params.regs.displacement) {
-			add_ir(code, inst->dst.params.regs.displacement, opts->gen.scratch2, SZ_D);
+		calc_index_disp8(opts, &inst->dst, opts->gen.scratch2);
+		if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) {
+			pop_r(code, opts->gen.scratch1);
 		}
 		if (src.mode == MODE_REG_DIRECT) {
 			if (src.base != opts->gen.scratch1) {
@@ -780,63 +724,15 @@
 		{
 		case MODE_AREG_INDIRECT:
 		case MODE_AREG_PREDEC:
-			if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
-				mov_rr(code, opts->aregs[inst->dst.params.regs.pri], opts->gen.scratch2, SZ_D);
-			} else {
-				mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->dst)), opts->gen.scratch2, SZ_D);
-			}
+			areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2);
 			break;
 		case MODE_AREG_DISPLACE:
 			early_cycles += BUS;
-			reg = opts->gen.scratch2;
-			if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
-				mov_rr(code, opts->aregs[inst->dst.params.regs.pri], opts->gen.scratch2, SZ_D);
-			} else {
-				mov_rdispr(code, opts->gen.context_reg,  reg_offset(&(inst->dst)), opts->gen.scratch2, SZ_D);
-			}
-			add_ir(code, inst->dst.params.regs.displacement, opts->gen.scratch2, SZ_D);
+			calc_areg_displace(opts, &inst->dst, opts->gen.scratch2);
 			break;
 		case MODE_AREG_INDEX_DISP8:
 			early_cycles += 6;
-			if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
-				mov_rr(code, opts->aregs[inst->dst.params.regs.pri], opts->gen.scratch2, SZ_D);
-			} else {
-				mov_rdispr(code, opts->gen.context_reg,  reg_offset(&(inst->dst)), opts->gen.scratch2, SZ_D);
-			}
-			sec_reg = (inst->dst.params.regs.sec >> 1) & 0x7;
-			if (inst->dst.params.regs.sec & 1) {
-				if (inst->dst.params.regs.sec & 0x10) {
-					if (opts->aregs[sec_reg] >= 0) {
-						add_rr(code, opts->aregs[sec_reg], opts->gen.scratch2, SZ_D);
-					} else {
-						add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_D);
-					}
-				} else {
-					if (opts->dregs[sec_reg] >= 0) {
-						add_rr(code, opts->dregs[sec_reg], opts->gen.scratch2, SZ_D);
-					} else {
-						add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_D);
-					}
-				}
-			} else {
-				if (inst->dst.params.regs.sec & 0x10) {
-					if (opts->aregs[sec_reg] >= 0) {
-						movsx_rr(code, opts->aregs[sec_reg], opts->gen.scratch1, SZ_W, SZ_D);
-					} else {
-						movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_W, SZ_D);
-					}
-				} else {
-					if (opts->dregs[sec_reg] >= 0) {
-						movsx_rr(code, opts->dregs[sec_reg], opts->gen.scratch1, SZ_W, SZ_D);
-					} else {
-						movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_W, SZ_D);
-					}
-				}
-				add_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_D);
-			}
-			if (inst->dst.params.regs.displacement) {
-				add_ir(code, inst->dst.params.regs.displacement, opts->gen.scratch2, SZ_D);
-			}
+			calc_areg_index_disp8(opts, &inst->dst, opts->gen.scratch2);
 			break;
 		case MODE_PC_DISPLACE:
 			early_cycles += BUS;
@@ -845,41 +741,7 @@
 		case MODE_PC_INDEX_DISP8:
 			early_cycles += 6;
 			mov_ir(code, inst->address+2, opts->gen.scratch2, SZ_D);
-			sec_reg = (inst->dst.params.regs.sec >> 1) & 0x7;
-			if (inst->dst.params.regs.sec & 1) {
-				if (inst->dst.params.regs.sec & 0x10) {
-					if (opts->aregs[sec_reg] >= 0) {
-						add_rr(code, opts->aregs[sec_reg], opts->gen.scratch2, SZ_D);
-					} else {
-						add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_D);
-					}
-				} else {
-					if (opts->dregs[sec_reg] >= 0) {
-						add_rr(code, opts->dregs[sec_reg], opts->gen.scratch2, SZ_D);
-					} else {
-						add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_D);
-					}
-				}
-			} else {
-				if (inst->dst.params.regs.sec & 0x10) {
-					if (opts->aregs[sec_reg] >= 0) {
-						movsx_rr(code, opts->aregs[sec_reg], opts->gen.scratch1, SZ_W, SZ_D);
-					} else {
-						movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_W, SZ_D);
-					}
-				} else {
-					if (opts->dregs[sec_reg] >= 0) {
-						movsx_rr(code, opts->dregs[sec_reg], opts->gen.scratch1, SZ_W, SZ_D);
-					} else {
-						movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_W, SZ_D);
-					}
-				}
-				add_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_D);
-			}
-			if (inst->dst.params.regs.displacement) {
-				add_ir(code, inst->dst.params.regs.displacement, opts->gen.scratch2, SZ_D);
-			}
-			break;
+			calc_index_disp8(opts, &inst->dst, opts->gen.scratch2);
 		case MODE_ABSOLUTE:
 			early_cycles += 4;
 		case MODE_ABSOLUTE_SHORT:
@@ -906,17 +768,9 @@
 				}
 				push_r(code, opts->gen.scratch2);
 				if (reg > 7) {
-					if (opts->aregs[reg-8] >= 0) {
-						mov_rr(code, opts->aregs[reg-8], opts->gen.scratch1, inst->extra.size);
-					} else {
-						mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * (reg-8), opts->gen.scratch1, inst->extra.size);
-					}
+					areg_to_native(opts, reg-8, opts->gen.scratch1);
 				} else {
-					if (opts->dregs[reg] >= 0) {
-						mov_rr(code, opts->dregs[reg], opts->gen.scratch1, inst->extra.size);
-					} else {
-						mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t) * (reg), opts->gen.scratch1, inst->extra.size);
-					}
+					dreg_to_native(opts, reg, opts->gen.scratch1);
 				}
 				if (inst->extra.size == OPSIZE_LONG) {
 					call(code, opts->write_32_lowfirst);
@@ -930,11 +784,7 @@
 			}
 		}
 		if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
-			if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
-				mov_rr(code, opts->gen.scratch2, opts->aregs[inst->dst.params.regs.pri], SZ_D);
-			} else {
-				mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, reg_offset(&(inst->dst)), SZ_D);
-			}
+			native_to_areg(opts, opts->gen.scratch2, inst->dst.params.regs.pri);
 		}
 	} else {
 		//mem to reg
@@ -943,63 +793,16 @@
 		{
 		case MODE_AREG_INDIRECT:
 		case MODE_AREG_POSTINC:
-			if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-				mov_rr(code, opts->aregs[inst->src.params.regs.pri], opts->gen.scratch1, SZ_D);
-			} else {
-				mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src)), opts->gen.scratch1, SZ_D);
-			}
+			areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1);
 			break;
 		case MODE_AREG_DISPLACE:
 			early_cycles += BUS;
 			reg = opts->gen.scratch2;
-			if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-				mov_rr(code, opts->aregs[inst->src.params.regs.pri], opts->gen.scratch1, SZ_D);
-			} else {
-				mov_rdispr(code, opts->gen.context_reg,  reg_offset(&(inst->src)), opts->gen.scratch1, SZ_D);
-			}
-			add_ir(code, inst->src.params.regs.displacement, opts->gen.scratch1, SZ_D);
+			calc_areg_displace(opts, &inst->src, opts->gen.scratch1);
 			break;
 		case MODE_AREG_INDEX_DISP8:
 			early_cycles += 6;
-			if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-				mov_rr(code, opts->aregs[inst->src.params.regs.pri], opts->gen.scratch1, SZ_D);
-			} else {
-				mov_rdispr(code, opts->gen.context_reg,  reg_offset(&(inst->src)), opts->gen.scratch1, SZ_D);
-			}
-			sec_reg = (inst->src.params.regs.sec >> 1) & 0x7;
-			if (inst->src.params.regs.sec & 1) {
-				if (inst->src.params.regs.sec & 0x10) {
-					if (opts->aregs[sec_reg] >= 0) {
-						add_rr(code, opts->aregs[sec_reg], opts->gen.scratch1, SZ_D);
-					} else {
-						add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D);
-					}
-				} else {
-					if (opts->dregs[sec_reg] >= 0) {
-						add_rr(code, opts->dregs[sec_reg], opts->gen.scratch1, SZ_D);
-					} else {
-						add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D);
-					}
-				}
-			} else {
-				if (inst->src.params.regs.sec & 0x10) {
-					if (opts->aregs[sec_reg] >= 0) {
-						movsx_rr(code, opts->aregs[sec_reg], opts->gen.scratch2, SZ_W, SZ_D);
-					} else {
-						movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D);
-					}
-				} else {
-					if (opts->dregs[sec_reg] >= 0) {
-						movsx_rr(code, opts->dregs[sec_reg], opts->gen.scratch2, SZ_W, SZ_D);
-					} else {
-						movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D);
-					}
-				}
-				add_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_D);
-			}
-			if (inst->src.params.regs.displacement) {
-				add_ir(code, inst->src.params.regs.displacement, opts->gen.scratch1, SZ_D);
-			}
+			calc_areg_index_disp8(opts, &inst->src, opts->gen.scratch1);
 			break;
 		case MODE_PC_DISPLACE:
 			early_cycles += BUS;
@@ -1008,40 +811,7 @@
 		case MODE_PC_INDEX_DISP8:
 			early_cycles += 6;
 			mov_ir(code, inst->address+2, opts->gen.scratch1, SZ_D);
-			sec_reg = (inst->src.params.regs.sec >> 1) & 0x7;
-			if (inst->src.params.regs.sec & 1) {
-				if (inst->src.params.regs.sec & 0x10) {
-					if (opts->aregs[sec_reg] >= 0) {
-						add_rr(code, opts->aregs[sec_reg], opts->gen.scratch1, SZ_D);
-					} else {
-						add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D);
-					}
-				} else {
-					if (opts->dregs[sec_reg] >= 0) {
-						add_rr(code, opts->dregs[sec_reg], opts->gen.scratch1, SZ_D);
-					} else {
-						add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D);
-					}
-				}
-			} else {
-				if (inst->src.params.regs.sec & 0x10) {
-					if (opts->aregs[sec_reg] >= 0) {
-						movsx_rr(code, opts->aregs[sec_reg], opts->gen.scratch2, SZ_W, SZ_D);
-					} else {
-						movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D);
-					}
-				} else {
-					if (opts->dregs[sec_reg] >= 0) {
-						movsx_rr(code, opts->dregs[sec_reg], opts->gen.scratch2, SZ_W, SZ_D);
-					} else {
-						movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D);
-					}
-				}
-				add_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_D);
-			}
-			if (inst->src.params.regs.displacement) {
-				add_ir(code, inst->src.params.regs.displacement, opts->gen.scratch1, SZ_D);
-			}
+			calc_index_disp8(opts, &inst->src, opts->gen.scratch1);
 			break;
 		case MODE_ABSOLUTE:
 			early_cycles += 4;
@@ -1067,28 +837,16 @@
 					movsx_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_W, SZ_D);
 				}
 				if (reg > 7) {
-					if (opts->aregs[reg-8] >= 0) {
-						mov_rr(code, opts->gen.scratch1, opts->aregs[reg-8], SZ_D);
-					} else {
-						mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * (reg-8), SZ_D);
-					}
+					native_to_areg(opts, opts->gen.scratch1, reg-8);
 				} else {
-					if (opts->dregs[reg] >= 0) {
-						mov_rr(code, opts->gen.scratch1, opts->dregs[reg], SZ_D);
-					} else {
-						mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t) * (reg), SZ_D);
-					}
+					native_to_dreg(opts, opts->gen.scratch1, reg);
 				}
 				pop_r(code, opts->gen.scratch1);
 				add_ir(code, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch1, SZ_D);
 			}
 		}
 		if (inst->src.addr_mode == MODE_AREG_POSTINC) {
-			if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-				mov_rr(code, opts->gen.scratch1, opts->aregs[inst->src.params.regs.pri], SZ_D);
-			} else {
-				mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->src)), SZ_D);
-			}
+			native_to_areg(opts, opts->gen.scratch1, inst->src.params.regs.pri);
 		}
 	}
 	//prefetch
@@ -1141,270 +899,6 @@
 	//M68K EXT only operates on registers so no need for a call to save result here
 }
 
-void translate_m68k_lea(m68k_options * opts, m68kinst * inst)
-{
-	code_info *code = &opts->gen.code;
-	int8_t dst_reg = native_reg(&(inst->dst), opts), sec_reg;
-	switch(inst->src.addr_mode)
-	{
-	case MODE_AREG_INDIRECT:
-		cycles(&opts->gen, BUS);
-		if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-			if (dst_reg >= 0) {
-				mov_rr(code, opts->aregs[inst->src.params.regs.pri], dst_reg, SZ_D);
-			} else {
-				mov_rrdisp(code, opts->aregs[inst->src.params.regs.pri], opts->gen.context_reg, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D);
-			}
-		} else {
-			if (dst_reg >= 0) {
-				mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, dst_reg, SZ_D);
-			} else {
-				mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, opts->gen.scratch1, SZ_D);
-				mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D);
-			}
-		}
-		break;
-	case MODE_AREG_DISPLACE:
-		cycles(&opts->gen, 8);
-		if (dst_reg >= 0) {
-			if (inst->src.params.regs.pri != inst->dst.params.regs.pri) {
-				if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-					mov_rr(code, opts->aregs[inst->src.params.regs.pri], dst_reg, SZ_D);
-				} else {
-					mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src)), dst_reg, SZ_D);
-				}
-			}
-			add_ir(code, inst->src.params.regs.displacement, dst_reg, SZ_D);
-		} else {
-			if (inst->src.params.regs.pri != inst->dst.params.regs.pri) {
-				if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-					mov_rrdisp(code, opts->aregs[inst->src.params.regs.pri], opts->gen.context_reg, reg_offset(&(inst->dst)), SZ_D);
-				} else {
-					mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src)), opts->gen.scratch1, SZ_D);
-					mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst)), SZ_D);
-				}
-			}
-			add_irdisp(code, inst->src.params.regs.displacement, opts->gen.context_reg, reg_offset(&(inst->dst)), SZ_D);
-		}
-		break;
-	case MODE_AREG_INDEX_DISP8:
-		cycles(&opts->gen, 12);
-		if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-			mov_rr(code, opts->aregs[inst->src.params.regs.pri], opts->gen.scratch2, SZ_D);
-		} else {
-			mov_rdispr(code, opts->gen.context_reg,  reg_offset(&(inst->src)), opts->gen.scratch2, SZ_D);
-		}
-		sec_reg = (inst->src.params.regs.sec >> 1) & 0x7;
-		if (inst->src.params.regs.sec & 1) {
-			if (inst->src.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					add_rr(code, opts->aregs[sec_reg], opts->gen.scratch2, SZ_D);
-				} else {
-					add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					add_rr(code, opts->dregs[sec_reg], opts->gen.scratch2, SZ_D);
-				} else {
-					add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_D);
-				}
-			}
-		} else {
-			if (inst->src.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					movsx_rr(code, opts->aregs[sec_reg], opts->gen.scratch1, SZ_W, SZ_D);
-				} else {
-					movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_W, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					movsx_rr(code, opts->dregs[sec_reg], opts->gen.scratch1, SZ_W, SZ_D);
-				} else {
-					movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_W, SZ_D);
-				}
-			}
-			add_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_D);
-		}
-		if (inst->src.params.regs.displacement) {
-			add_ir(code, inst->src.params.regs.displacement, opts->gen.scratch2, SZ_D);
-		}
-		if (dst_reg >= 0) {
-			mov_rr(code, opts->gen.scratch2, dst_reg, SZ_D);
-		} else {
-			mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, reg_offset(&(inst->dst)), SZ_D);
-		}
-		break;
-	case MODE_PC_DISPLACE:
-		cycles(&opts->gen, 8);
-		if (dst_reg >= 0) {
-			mov_ir(code, inst->src.params.regs.displacement + inst->address+2, dst_reg, SZ_D);
-		} else {
-			mov_irdisp(code, inst->src.params.regs.displacement + inst->address+2, opts->gen.context_reg, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D);
-		}
-		break;
-	case MODE_PC_INDEX_DISP8:
-		cycles(&opts->gen, BUS*3);
-		mov_ir(code, inst->address+2, opts->gen.scratch1, SZ_D);
-		sec_reg = (inst->src.params.regs.sec >> 1) & 0x7;
-		if (inst->src.params.regs.sec & 1) {
-			if (inst->src.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					add_rr(code, opts->aregs[sec_reg], opts->gen.scratch1, SZ_D);
-				} else {
-					add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					add_rr(code, opts->dregs[sec_reg], opts->gen.scratch1, SZ_D);
-				} else {
-					add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D);
-				}
-			}
-		} else {
-			if (inst->src.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					movsx_rr(code, opts->aregs[sec_reg], opts->gen.scratch2, SZ_W, SZ_D);
-				} else {
-					movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					movsx_rr(code, opts->dregs[sec_reg], opts->gen.scratch2, SZ_W, SZ_D);
-				} else {
-					movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D);
-				}
-			}
-			add_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_D);
-		}
-		if (inst->src.params.regs.displacement) {
-			add_ir(code, inst->src.params.regs.displacement, opts->gen.scratch1, SZ_D);
-		}
-		if (dst_reg >= 0) {
-			mov_rr(code, opts->gen.scratch1, dst_reg, SZ_D);
-		} else {
-			mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst)), SZ_D);
-		}
-		break;
-	case MODE_ABSOLUTE:
-	case MODE_ABSOLUTE_SHORT:
-		cycles(&opts->gen, (inst->src.addr_mode == MODE_ABSOLUTE) ? BUS * 3 : BUS * 2);
-		if (dst_reg >= 0) {
-			mov_ir(code, inst->src.params.immed, dst_reg, SZ_D);
-		} else {
-			mov_irdisp(code, inst->src.params.immed, opts->gen.context_reg, reg_offset(&(inst->dst)), SZ_D);
-		}
-		break;
-	default:
-		m68k_disasm(inst, disasm_buf);
-		printf("%X: %s\naddress mode %d not implemented (lea src)\n", inst->address, disasm_buf, inst->src.addr_mode);
-		exit(1);
-	}
-}
-
-void translate_m68k_pea(m68k_options * opts, m68kinst * inst)
-{
-	code_info *code = &opts->gen.code;
-	uint8_t sec_reg;
-	switch(inst->src.addr_mode)
-	{
-	case MODE_AREG_INDIRECT:
-		cycles(&opts->gen, BUS);
-		if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-			mov_rr(code, opts->aregs[inst->src.params.regs.pri], opts->gen.scratch1, SZ_D);
-		} else {
-			mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, opts->gen.scratch1, SZ_D);
-		}
-		break;
-	case MODE_AREG_DISPLACE:
-		cycles(&opts->gen, 8);
-		if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-			mov_rr(code, opts->aregs[inst->src.params.regs.pri], opts->gen.scratch1, SZ_D);
-		} else {
-			mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src)), opts->gen.scratch1, SZ_D);
-		}
-		add_ir(code, inst->src.params.regs.displacement, opts->gen.scratch1, SZ_D);
-		break;
-	case MODE_AREG_INDEX_DISP8:
-		cycles(&opts->gen, 6);//TODO: Check to make sure this is correct
-		if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-			mov_rr(code, opts->aregs[inst->src.params.regs.pri], opts->gen.scratch1, SZ_D);
-		} else {
-			mov_rdispr(code, opts->gen.context_reg,  reg_offset(&(inst->src)), opts->gen.scratch1, SZ_D);
-		}
-		sec_reg = (inst->src.params.regs.sec >> 1) & 0x7;
-		if (inst->src.params.regs.sec & 1) {
-			if (inst->src.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					add_rr(code, opts->aregs[sec_reg], opts->gen.scratch1, SZ_D);
-				} else {
-					add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					add_rr(code, opts->dregs[sec_reg], opts->gen.scratch1, SZ_D);
-				} else {
-					add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D);
-				}
-			}
-		} else {
-			if (inst->src.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					movsx_rr(code, opts->aregs[sec_reg], opts->gen.scratch2, SZ_W, SZ_D);
-				} else {
-					movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					movsx_rr(code, opts->dregs[sec_reg], opts->gen.scratch2, SZ_W, SZ_D);
-				} else {
-					movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D);
-				}
-			}
-			add_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_D);
-		}
-		if (inst->src.params.regs.displacement) {
-			add_ir(code, inst->src.params.regs.displacement, opts->gen.scratch1, SZ_D);
-		}
-		break;
-	case MODE_PC_DISPLACE:
-		cycles(&opts->gen, 8);
-		mov_ir(code, inst->src.params.regs.displacement + inst->address+2, opts->gen.scratch1, SZ_D);
-		break;
-	case MODE_ABSOLUTE:
-	case MODE_ABSOLUTE_SHORT:
-		cycles(&opts->gen, (inst->src.addr_mode == MODE_ABSOLUTE) ? BUS * 3 : BUS * 2);
-		mov_ir(code, inst->src.params.immed, opts->gen.scratch1, SZ_D);
-		break;
-	default:
-		m68k_disasm(inst, disasm_buf);
-		printf("%X: %s\naddress mode %d not implemented (lea src)\n", inst->address, disasm_buf, inst->src.addr_mode);
-		exit(1);
-	}
-	sub_ir(code, 4, opts->aregs[7], SZ_D);
-	mov_rr(code, opts->aregs[7], opts->gen.scratch2, SZ_D);
-	call(code, opts->write_32_lowfirst);
-}
-
-void translate_m68k_bsr(m68k_options * opts, m68kinst * inst)
-{
-	code_info *code = &opts->gen.code;
-	int32_t disp = inst->src.params.immed;
-	uint32_t after = inst->address + (inst->variant == VAR_BYTE ? 2 : 4);
-	//TODO: Add cycles in the right place relative to pushing the return address on the stack
-	cycles(&opts->gen, 10);
-	mov_ir(code, after, opts->gen.scratch1, SZ_D);
-	sub_ir(code, 4, opts->aregs[7], SZ_D);
-	mov_rr(code, opts->aregs[7], opts->gen.scratch2, SZ_D);
-	call(code, opts->write_32_highfirst);
-	code_ptr dest_addr = get_native_address(opts->gen.native_code_map, (inst->address+2) + disp);
-	if (!dest_addr) {
-		opts->gen.deferred = defer_address(opts->gen.deferred, (inst->address+2) + disp, code->cur + 1);
-		//dummy address to be replaced later
-		dest_addr = code->cur + 256;
-	}
-	jmp(code, dest_addr);
-}
-
 uint8_t m68k_eval_cond(m68k_options * opts, uint8_t cc)
 {
 	uint8_t cond = CC_NZ;
@@ -1458,15 +952,10 @@
 	cycles(&opts->gen, 10);//TODO: Adjust this for branch not taken case
 	int32_t disp = inst->src.params.immed;
 	uint32_t after = inst->address + 2;
-	code_ptr dest_addr = get_native_address(opts->gen.native_code_map, after + disp);
 	if (inst->extra.cond == COND_TRUE) {
-		if (!dest_addr) {
-			opts->gen.deferred = defer_address(opts->gen.deferred, after + disp, code->cur + 1);
-			//dummy address to be replaced later, make sure it generates a 4-byte displacement
-			dest_addr = code->cur + 256;
-		}
-		jmp(code, dest_addr);
+		jump_m68k_abs(opts, after + disp);
 	} else {
+		code_ptr dest_addr = get_native_address(opts->gen.native_code_map, after + disp);
 		uint8_t cond = m68k_eval_cond(opts, inst->extra.cond);
 		if (!dest_addr) {
 			opts->gen.deferred = defer_address(opts->gen.deferred, after + disp, code->cur + 2);
@@ -1520,214 +1009,6 @@
 	m68k_save_result(inst, opts);
 }
 
-void translate_m68k_jmp_jsr(m68k_options * opts, m68kinst * inst)
-{
-	uint8_t is_jsr = inst->op == M68K_JSR;
-	code_info *code = &opts->gen.code;
-	code_ptr dest_addr;
-	uint8_t sec_reg;
-	uint32_t after;
-	uint32_t m68k_addr;
-	switch(inst->src.addr_mode)
-	{
-	case MODE_AREG_INDIRECT:
-		cycles(&opts->gen, BUS*2);
-		if (is_jsr) {
-			mov_ir(code, inst->address + 2, opts->gen.scratch1, SZ_D);
-			sub_ir(code, 4, opts->aregs[7], SZ_D);
-			mov_rr(code, opts->aregs[7], opts->gen.scratch2, SZ_D);
-			call(code, opts->write_32_highfirst);
-		}
-		if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-			mov_rr(code, opts->aregs[inst->src.params.regs.pri], opts->gen.scratch1, SZ_D);
-		} else {
-			mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, opts->gen.scratch1, SZ_D);
-		}
-		call(code, opts->native_addr);
-		jmp_r(code, opts->gen.scratch1);
-		break;
-	case MODE_AREG_DISPLACE:
-		cycles(&opts->gen, BUS*2);
-		if (is_jsr) {
-			mov_ir(code, inst->address + 4, opts->gen.scratch1, SZ_D);
-			sub_ir(code, 4, opts->aregs[7], SZ_D);
-			mov_rr(code, opts->aregs[7], opts->gen.scratch2, SZ_D);
-			call(code, opts->write_32_highfirst);
-		}
-		if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-			mov_rr(code, opts->aregs[inst->src.params.regs.pri], opts->gen.scratch1, SZ_D);
-		} else {
-			mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, opts->gen.scratch1, SZ_D);
-		}
-		add_ir(code, inst->src.params.regs.displacement, opts->gen.scratch1, SZ_D);
-		call(code, opts->native_addr);
-		jmp_r(code, opts->gen.scratch1);
-		break;
-	case MODE_AREG_INDEX_DISP8:
-		cycles(&opts->gen, BUS*3);//TODO: CHeck that this is correct
-		if (is_jsr) {
-			mov_ir(code, inst->address + 4, opts->gen.scratch1, SZ_D);
-			sub_ir(code, 4, opts->aregs[7], SZ_D);
-			mov_rr(code, opts->aregs[7], opts->gen.scratch2, SZ_D);
-			call(code, opts->write_32_highfirst);
-		}
-		if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-			mov_rr(code, opts->aregs[inst->src.params.regs.pri], opts->gen.scratch1, SZ_D);
-		} else {
-			mov_rdispr(code, opts->gen.context_reg,  reg_offset(&(inst->src)), opts->gen.scratch1, SZ_D);
-		}
-		sec_reg = (inst->src.params.regs.sec >> 1) & 0x7;
-		if (inst->src.params.regs.sec & 1) {
-			//32-bit index register
-			if (inst->src.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					add_rr(code, opts->aregs[sec_reg], opts->gen.scratch1, SZ_D);
-				} else {
-					add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					add_rr(code, opts->dregs[sec_reg], opts->gen.scratch1, SZ_D);
-				} else {
-					add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D);
-				}
-			}
-		} else {
-			//16-bit index register
-			if (inst->src.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					movsx_rr(code, opts->aregs[sec_reg], opts->gen.scratch2, SZ_W, SZ_D);
-				} else {
-					movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					movsx_rr(code, opts->dregs[sec_reg], opts->gen.scratch2, SZ_W, SZ_D);
-				} else {
-					movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D);
-				}
-			}
-			add_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_D);
-		}
-		if (inst->src.params.regs.displacement) {
-			add_ir(code, inst->src.params.regs.displacement, opts->gen.scratch1, SZ_D);
-		}
-		call(code, opts->native_addr);
-		jmp_r(code, opts->gen.scratch1);
-		break;
-	case MODE_PC_DISPLACE:
-		//TODO: Add cycles in the right place relative to pushing the return address on the stack
-		cycles(&opts->gen, 10);
-		if (is_jsr) {
-			mov_ir(code, inst->address + 4, opts->gen.scratch1, SZ_D);
-			sub_ir(code, 4, opts->aregs[7], SZ_D);
-			mov_rr(code, opts->aregs[7], opts->gen.scratch2, SZ_D);
-			call(code, opts->write_32_highfirst);
-		}
-		m68k_addr = inst->src.params.regs.displacement + inst->address + 2;
-		if ((m68k_addr & 0xFFFFFF) < 0x400000) {
-			dest_addr = get_native_address(opts->gen.native_code_map, m68k_addr);
-			if (!dest_addr) {
-				opts->gen.deferred = defer_address(opts->gen.deferred, m68k_addr, code->cur + 1);
-				//dummy address to be replaced later, make sure it generates a 4-byte displacement
-				dest_addr = code->cur + 256;
-			}
-			jmp(code, dest_addr);
-		} else {
-			mov_ir(code, m68k_addr, opts->gen.scratch1, SZ_D);
-			call(code, opts->native_addr);
-			jmp_r(code, opts->gen.scratch1);
-		}
-		break;
-	case MODE_PC_INDEX_DISP8:
-		cycles(&opts->gen, BUS*3);//TODO: CHeck that this is correct
-		if (is_jsr) {
-			mov_ir(code, inst->address + 4, opts->gen.scratch1, SZ_D);
-			sub_ir(code, 4, opts->aregs[7], SZ_D);
-			mov_rr(code, opts->aregs[7], opts->gen.scratch2, SZ_D);
-			call(code, opts->write_32_highfirst);
-		}
-		mov_ir(code, inst->address+2, opts->gen.scratch1, SZ_D);
-		sec_reg = (inst->src.params.regs.sec >> 1) & 0x7;
-		if (inst->src.params.regs.sec & 1) {
-			if (inst->src.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					add_rr(code, opts->aregs[sec_reg], opts->gen.scratch1, SZ_D);
-				} else {
-					add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					add_rr(code, opts->dregs[sec_reg], opts->gen.scratch1, SZ_D);
-				} else {
-					add_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch1, SZ_D);
-				}
-			}
-		} else {
-			if (inst->src.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					movsx_rr(code, opts->aregs[sec_reg], opts->gen.scratch2, SZ_W, SZ_D);
-				} else {
-					movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					movsx_rr(code, opts->dregs[sec_reg], opts->gen.scratch2, SZ_W, SZ_D);
-				} else {
-					movsx_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, opts->gen.scratch2, SZ_W, SZ_D);
-				}
-			}
-			add_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_D);
-		}
-		if (inst->src.params.regs.displacement) {
-			add_ir(code, inst->src.params.regs.displacement, opts->gen.scratch1, SZ_D);
-		}
-		call(code, opts->native_addr);
-		jmp_r(code, opts->gen.scratch1);
-		break;
-	case MODE_ABSOLUTE:
-	case MODE_ABSOLUTE_SHORT:
-		//TODO: Add cycles in the right place relative to pushing the return address on the stack
-		cycles(&opts->gen, inst->src.addr_mode == MODE_ABSOLUTE ? 12 : 10);
-		if (is_jsr) {
-			mov_ir(code, inst->address + (inst->src.addr_mode == MODE_ABSOLUTE ? 6 : 4), opts->gen.scratch1, SZ_D);
-			sub_ir(code, 4, opts->aregs[7], SZ_D);
-			mov_rr(code, opts->aregs[7], opts->gen.scratch2, SZ_D);
-			call(code, opts->write_32_highfirst);
-		}
-		m68k_addr = inst->src.params.immed;
-		if ((m68k_addr & 0xFFFFFF) < 0x400000) {
-			dest_addr = get_native_address(opts->gen.native_code_map, m68k_addr);
-			if (!dest_addr) {
-				opts->gen.deferred = defer_address(opts->gen.deferred, m68k_addr, code->cur + 1);
-				//dummy address to be replaced later, make sure it generates a 4-byte displacement
-				dest_addr = code->cur + 256;
-			}
-			jmp(code, dest_addr);
-		} else {
-			mov_ir(code, m68k_addr, opts->gen.scratch1, SZ_D);
-			call(code, opts->native_addr);
-			jmp_r(code, opts->gen.scratch1);
-		}
-		break;
-	default:
-		m68k_disasm(inst, disasm_buf);
-		printf("%s\naddress mode %d not yet supported (%s)\n", disasm_buf, inst->src.addr_mode, is_jsr ? "jsr" : "jmp");
-		exit(1);
-	}
-}
-
-void translate_m68k_rts(m68k_options * opts, m68kinst * inst)
-{
-	code_info *code = &opts->gen.code;
-	//TODO: Add cycles
-	mov_rr(code, opts->aregs[7], opts->gen.scratch1, SZ_D);
-	add_ir(code, 4, opts->aregs[7], SZ_D);
-	call(code, opts->read_32);
-	call(code, opts->native_addr);
-	jmp_r(code, opts->gen.scratch1);
-}
-
 void translate_m68k_dbcc(m68k_options * opts, m68kinst * inst)
 {
 	code_info *code = &opts->gen.code;
@@ -1752,13 +1033,7 @@
 	code_ptr loop_end_loc = code->cur + 1;
 	jcc(code, CC_Z, code->cur + 2);
 	uint32_t after = inst->address + 2;
-	code_ptr dest_addr = get_native_address(opts->gen.native_code_map, after + inst->src.params.immed);
-	if (!dest_addr) {
-		opts->gen.deferred = defer_address(opts->gen.deferred, after + inst->src.params.immed, code->cur + 1);
-		//dummy address to be replaced later, make sure it generates a 4-byte displacement
-		dest_addr = code->cur + 256;
-	}
-	jmp(code, dest_addr);
+	jump_m68k_abs(opts, after + inst->src.params.immed);
 	*loop_end_loc = code->cur - (loop_end_loc+1);
 	if (skip_loc) {
 		cycles(&opts->gen, 2);
@@ -1769,44 +1044,13 @@
 	}
 }
 
-void translate_m68k_link(m68k_options * opts, m68kinst * inst)
-{
-	code_info *code = &opts->gen.code;
-	int8_t reg = native_reg(&(inst->src), opts);
-	//compensate for displacement word
-	cycles(&opts->gen, BUS);
-	sub_ir(code, 4, opts->aregs[7], SZ_D);
-	mov_rr(code, opts->aregs[7], opts->gen.scratch2, SZ_D);
-	if (reg >= 0) {
-		mov_rr(code, reg, opts->gen.scratch1, SZ_D);
-	} else {
-		mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src)), opts->gen.scratch1, SZ_D);
-	}
-	call(code, opts->write_32_highfirst);
-	if (reg >= 0) {
-		mov_rr(code, opts->aregs[7], reg, SZ_D);
-	} else {
-		mov_rrdisp(code, opts->aregs[7], opts->gen.context_reg, reg_offset(&(inst->src)), SZ_D);
-	}
-	add_ir(code, inst->dst.params.immed, opts->aregs[7], SZ_D);
-	//prefetch
-	cycles(&opts->gen, BUS);
-}
-
 void translate_m68k_movep(m68k_options * opts, m68kinst * inst)
 {
 	code_info *code = &opts->gen.code;
 	int8_t reg;
 	cycles(&opts->gen, BUS*2);
 	if (inst->src.addr_mode == MODE_REG) {
-		if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
-			mov_rr(code, opts->aregs[inst->dst.params.regs.pri], opts->gen.scratch2, SZ_D);
-		} else {
-			mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->dst)), opts->gen.scratch2, SZ_D);
-		}
-		if (inst->dst.params.regs.displacement) {
-			add_ir(code, inst->dst.params.regs.displacement, opts->gen.scratch2, SZ_D);
-		}
+		calc_areg_displace(opts, &inst->dst, opts->gen.scratch2);
 		reg = native_reg(&(inst->src), opts);
 		if (inst->extra.size == OPSIZE_LONG) {
 			if (reg >= 0) {
@@ -1848,14 +1092,7 @@
 		add_ir(code, 2, opts->gen.scratch2, SZ_D);
 		call(code, opts->write_8);
 	} else {
-		if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-			mov_rr(code, opts->aregs[inst->src.params.regs.pri], opts->gen.scratch1, SZ_D);
-		} else {
-			mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src)), opts->gen.scratch1, SZ_D);
-		}
-		if (inst->src.params.regs.displacement) {
-			add_ir(code, inst->src.params.regs.displacement, opts->gen.scratch1, SZ_D);
-		}
+		calc_areg_displace(opts, &inst->src, opts->gen.scratch1);
 		reg = native_reg(&(inst->dst), opts);
 		if (inst->extra.size == OPSIZE_LONG) {
 			if (reg >= 0) {
@@ -2144,6 +1381,8 @@
 		return translate_m68k_movem(opts, inst);
 	} else if(inst->op == M68K_LINK) {
 		return translate_m68k_link(opts, inst);
+	} else if(inst->op == M68K_UNLK) {
+		return translate_m68k_unlk(opts, inst);
 	} else if(inst->op == M68K_EXT) {
 		return translate_m68k_ext(opts, inst);
 	} else if(inst->op == M68K_SCC) {
@@ -2723,19 +1962,16 @@
 		//TODO: Trap if not in supervisor mode
 		//bt_irdisp(code, BIT_SUPERVISOR, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
 		if (inst->src.addr_mode == MODE_UNUSED) {
-			if (dst_op.mode == MODE_REG_DIRECT) {
-				mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, dst_op.base, SZ_D);
-			} else {
-				mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, opts->gen.scratch1, SZ_D);
+			areg_to_native(opts, 8, dst_op.mode == MODE_REG_DIRECT ? dst_op.base : opts->gen.scratch1);
+			if (dst_op.mode != MODE_REG_DIRECT) {
 				mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_D);
 			}
 		} else {
-			if (src_op.mode == MODE_REG_DIRECT) {
-				mov_rrdisp(code, src_op.base, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D);
-			} else {
+			if (src_op.mode != MODE_REG_DIRECT) {
 				mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_D);
-				mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D);
+				src_op.base = opts->gen.scratch1;
 			}
+			native_to_areg(opts, src_op.base, 8);
 		}
 		break;
 	//case M68K_MOVEP:
@@ -3133,39 +2369,26 @@
 	case M68K_RTE:
 		//TODO: Trap if not in system mode
 		//Read saved SR
-		mov_rr(code, opts->aregs[7], opts->gen.scratch1, SZ_D);
+		areg_to_native(opts, 7, opts->gen.scratch1);
 		call(code, opts->read_16);
-		add_ir(code, 2, opts->aregs[7], SZ_D);
+		addi_areg(opts, 2, 7);
 		call(code, opts->set_sr);
 		//Read saved PC
-		mov_rr(code, opts->aregs[7], opts->gen.scratch1, SZ_D);
+		areg_to_native(opts, 7, opts->gen.scratch1);
 		call(code, opts->read_32);
-		add_ir(code, 4, opts->aregs[7], SZ_D);
+		addi_areg(opts, 4, 7);
 		//Check if we've switched to user mode and swap stack pointers if needed
 		bt_irdisp(code, 5, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
 		end_off = code->cur + 1;
 		jcc(code, CC_C, code->cur + 2);
-		mov_rr(code, opts->aregs[7], opts->gen.scratch2, SZ_D);
-		mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, opts->aregs[7], SZ_D);
-		mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D);
+		swap_ssp_usp(opts);
 		*end_off = code->cur - (end_off+1);
 		//Get native address, sync components, recalculate integer points and jump to returned address
 		call(code, opts->native_addr_and_sync);
 		jmp_r(code, opts->gen.scratch1);
 		break;
 	case M68K_RTR:
-		//Read saved CCR
-		mov_rr(code, opts->aregs[7], opts->gen.scratch1, SZ_D);
-		call(code, opts->read_16);
-		add_ir(code, 2, opts->aregs[7], SZ_D);
-		call(code, opts->set_ccr);
-		//Read saved PC
-		mov_rr(code, opts->aregs[7], opts->gen.scratch1, SZ_D);
-		call(code, opts->read_32);
-		add_ir(code, 4, opts->aregs[7], SZ_D);
-		//Get native address and jump to it
-		call(code, opts->native_addr);
-		jmp_r(code, opts->gen.scratch1);
+		translate_m68k_rtr(opts, inst);
 		break;
 	case M68K_SBCD: {
 		if (src_op.base != opts->gen.scratch2) {
@@ -3216,9 +2439,7 @@
 		mov_irdisp(code, (src_op.disp >> 8), opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
 		if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) {
 			//leave supervisor mode
-			mov_rr(code, opts->aregs[7], opts->gen.scratch1, SZ_D);
-			mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, opts->aregs[7], SZ_D);
-			mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D);
+			swap_ssp_usp(opts);
 		}
 		code_ptr loop_top = code->cur;
 		call(code, opts->do_sync);
@@ -3317,9 +2538,7 @@
 		break;
 	//case M68K_TAS:
 	case M68K_TRAP:
-		mov_ir(code, src_op.disp + VECTOR_TRAP_0, opts->gen.scratch2, SZ_D);
-		mov_ir(code, inst->address+2, opts->gen.scratch1, SZ_D);
-		jmp(code, opts->trap);
+		translate_m68k_trap(opts, inst);
 		break;
 	//case M68K_TRAPV:
 	case M68K_TST:
@@ -3334,22 +2553,6 @@
 		set_flag_cond(opts, CC_S, FLAG_N);
 		set_flag(opts, 0, FLAG_V);
 		break;
-	case M68K_UNLK:
-		cycles(&opts->gen, BUS);
-		if (dst_op.mode == MODE_REG_DIRECT) {
-			mov_rr(code, dst_op.base, opts->aregs[7], SZ_D);
-		} else {
-			mov_rdispr(code, dst_op.base, dst_op.disp, opts->aregs[7], SZ_D);
-		}
-		mov_rr(code, opts->aregs[7], opts->gen.scratch1, SZ_D);
-		call(code, opts->read_32);
-		if (dst_op.mode == MODE_REG_DIRECT) {
-			mov_rr(code, opts->gen.scratch1, dst_op.base, SZ_D);
-		} else {
-			mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_D);
-		}
-		add_ir(code, 4, opts->aregs[7], SZ_D);
-		break;
 	default:
 		m68k_disasm(inst, disasm_buf);
 		printf("%X: %s\ninstruction %d not yet implemented\n", inst->address, disasm_buf, inst->op);
@@ -4141,18 +3344,16 @@
 	bt_irdisp(code, 5, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
 	code_ptr already_supervisor = code->cur + 1;
 	jcc(code, CC_C, code->cur + 2);
-	mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, opts->gen.scratch2, SZ_D);
-	mov_rrdisp(code, opts->aregs[7], opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D);
-	mov_rr(code, opts->gen.scratch2, opts->aregs[7], SZ_D);
+	swap_ssp_usp(opts);
 	*already_supervisor = code->cur - (already_supervisor+1);
 	//save PC
-	sub_ir(code, 4, opts->aregs[7], SZ_D);
-	mov_rr(code, opts->aregs[7], opts->gen.scratch2, SZ_D);
+	subi_areg(opts, 4, 7);
+	areg_to_native(opts, 7, opts->gen.scratch2);
 	call(code, opts->write_32_lowfirst);
 	//save status register
-	sub_ir(code, 2, opts->aregs[7], SZ_D);
+	subi_areg(opts, 2, 7);
 	call(code, opts->get_sr);
-	mov_rr(code, opts->aregs[7], opts->gen.scratch2, SZ_D);
+	areg_to_native(opts, 7, opts->gen.scratch2);
 	call(code, opts->write_16);
 	//update status register
 	and_irdisp(code, 0xF8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
@@ -4177,18 +3378,16 @@
 	bt_irdisp(code, 5, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
 	already_supervisor = code->cur + 1;
 	jcc(code, CC_C, code->cur + 2);
-	mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, opts->gen.scratch2, SZ_D);
-	mov_rrdisp(code, opts->aregs[7], opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D);
-	mov_rr(code, opts->gen.scratch2, opts->aregs[7], SZ_D);
+	swap_ssp_usp(opts);
 	*already_supervisor = code->cur - (already_supervisor+1);
 	//save PC
-	sub_ir(code, 4, opts->aregs[7], SZ_D);
-	mov_rr(code, opts->aregs[7], opts->gen.scratch2, SZ_D);
+	subi_areg(opts, 4, 7);
+	areg_to_native(opts, 7, opts->gen.scratch2);
 	call(code, opts->write_32_lowfirst);
 	//save status register
-	sub_ir(code, 2, opts->aregs[7], SZ_D);
+	subi_areg(opts, 2, 7);
 	call(code, opts->get_sr);
-	mov_rr(code, opts->aregs[7], opts->gen.scratch2, SZ_D);
+	areg_to_native(opts, 7, opts->gen.scratch2);
 	call(code, opts->write_16);
 	//set supervisor bit
 	or_irdisp(code, 0x20, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
@@ -4200,13 +3399,3 @@
 	cycles(&opts->gen, 18);
 	jmp_r(code, opts->gen.scratch1);
 }
-
-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;
-	context->int_cycle = 0xFFFFFFFF;
-	context->status = 0x27;
-}
-
--- a/m68k_internal.h	Mon Mar 03 22:16:41 2014 -0800
+++ b/m68k_internal.h	Mon Mar 03 22:17:20 2014 -0800
@@ -11,13 +11,33 @@
 //functions implemented in host CPU specfic file
 void translate_out_of_bounds(code_info *code);
 void check_code_prologue(code_info *code);
+void areg_to_native(m68k_options *opts, uint8_t reg, uint8_t native_reg);
+void dreg_to_native(m68k_options *opts, uint8_t reg, uint8_t native_reg);
+void areg_to_native_sx(m68k_options *opts, uint8_t reg, uint8_t native_reg);
+void dreg_to_native_sx(m68k_options *opts, uint8_t reg, uint8_t native_reg);
+void native_to_areg(m68k_options *opts, uint8_t native_reg, uint8_t reg);
+void native_to_dreg(m68k_options *opts, uint8_t native_reg, uint8_t reg);
+void ldi_areg(m68k_options *opts, int32_t value, uint8_t reg);
+void ldi_native(m68k_options *opts, int32_t value, uint8_t reg);
+void addi_areg(m68k_options *opts, int32_t val, uint8_t reg);
+void subi_areg(m68k_options *opts, int32_t val, uint8_t reg);
+void add_areg_native(m68k_options *opts, uint8_t reg, uint8_t native_reg);
+void add_dreg_native(m68k_options *opts, uint8_t reg, uint8_t native_reg);
+void calc_areg_displace(m68k_options *opts, m68k_op_info *op, uint8_t native_reg);
+void calc_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_reg);
+void calc_areg_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_reg);
 
 //functions implemented in m68k_core.c
 int8_t native_reg(m68k_op_info * op, m68k_options * opts);
+size_t dreg_offset(uint8_t reg);
+size_t areg_offset(uint8_t reg);
 size_t reg_offset(m68k_op_info *op);
 void print_regs_exit(m68k_context * context);
 void m68k_read_size(m68k_options *opts, uint8_t size);
 void m68k_write_size(m68k_options *opts, uint8_t size);
+void push_const(m68k_options *opts, int32_t value);
+void jump_m68k_abs(m68k_options * opts, uint32_t address);
+void swap_ssp_usp(m68k_options * opts);
 code_ptr get_native_address(native_map_slot * native_code_map, uint32_t address);
 void map_native_address(m68k_context * context, uint32_t address, code_ptr native_addr, uint8_t size, uint8_t native_size);
 uint8_t get_native_inst_size(m68k_options * opts, uint32_t address);
@@ -25,4 +45,25 @@
 void m68k_handle_deferred(m68k_context * context);
 code_ptr get_native_address_trans(m68k_context * context, uint32_t address);
 
+//individual instructions
+void translate_m68k_lea(m68k_options * opts, m68kinst * inst);
+void translate_m68k_pea(m68k_options * opts, m68kinst * inst);
+void translate_m68k_bsr(m68k_options * opts, m68kinst * inst);
+void translate_m68k_jmp_jsr(m68k_options * opts, m68kinst * inst);
+void translate_m68k_unlk(m68k_options * opts, m68kinst * inst);
+void translate_m68k_link(m68k_options * opts, m68kinst * inst);
+void translate_m68k_rts(m68k_options * opts, m68kinst * inst);
+void translate_m68k_rtr(m68k_options *opts, m68kinst * inst);
+void translate_m68k_trap(m68k_options *opts, m68kinst *inst);
+
+#define BUS 4
+#define PREDEC_PENALTY 2
+extern char disasm_buf[1024];
+
+m68k_context * sync_components(m68k_context * context, uint32_t address);
+
+void m68k_invalid();
+void bcd_add();
+void bcd_sub();
+
 #endif //M68K_INTERNAL_H_