changeset 652:f822d9216968

Merge
author Michael Pavone <pavone@retrodev.com>
date Tue, 30 Dec 2014 19:11:34 -0800
parents 9d6fed6501ba (diff) 103d5cabbe14 (current diff)
children a18e3923481e
files .hgignore 68kinst.c Makefile blastem.c debug.c dis.c z80_to_x86.c z80_to_x86.h
diffstat 42 files changed, 7515 insertions(+), 6787 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Tue Dec 16 01:10:54 2014 -0800
+++ b/.hgignore	Tue Dec 30 19:11:34 2014 -0800
@@ -6,15 +6,22 @@
 *.jpg
 *.pdf
 *.tar.gz
+*.list
 *~
 starscream/*
+gxz80/*
+musashi/*
 vdpreverse/*
 nemesis/*
 html/*
+generated_tests/*
+ztests/*
 *.o
 *.list
 blastem
 dis
 stateview
 trans
-
+zdis
+ztestrun
+address.log
--- a/.hgtags	Tue Dec 16 01:10:54 2014 -0800
+++ b/.hgtags	Tue Dec 30 19:11:34 2014 -0800
@@ -1,1 +1,2 @@
 949c7d8756931ca19d93d6de5cc507405a007937 v0.1.0
+6b7a96d0eda8ed9f1a1436c3ac590a1c4db94f27 v0.2.0
--- a/68kinst.c	Tue Dec 16 01:10:54 2014 -0800
+++ b/68kinst.c	Tue Dec 30 19:11:34 2014 -0800
@@ -1097,6 +1097,7 @@
 				break;
 			case 4:
 				decoded->op = M68K_SBCD;
+				decoded->extra.size = OPSIZE_BYTE;
 				decoded->dst.addr_mode = decoded->src.addr_mode = *istream & 0x8 ? MODE_AREG_PREDEC : MODE_REG;
 				decoded->src.params.regs.pri = *istream & 0x7;
 				decoded->dst.params.regs.pri = (*istream >> 9) & 0x7;
--- a/Makefile	Tue Dec 16 01:10:54 2014 -0800
+++ b/Makefile	Tue Dec 30 19:11:34 2014 -0800
@@ -3,11 +3,12 @@
 else
 LIBS=sdl glew gl
 endif
-LDFLAGS=-lm `pkg-config --libs $(LIBS)`
 ifdef DEBUG
-CFLAGS=-ggdb -std=gnu99 `pkg-config --cflags-only-I $(LIBS)` -Wreturn-type -Werror=return-type
+CFLAGS:=-ggdb -std=gnu99 $(shell pkg-config --cflags-only-I $(LIBS)) -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration
+LDFLAGS:=-ggdb -lm $(shell pkg-config --libs $(LIBS))
 else
-CFLAGS=-O2 -std=gnu99 `pkg-config --cflags-only-I $(LIBS)` -Wreturn-type -Werror=return-type
+CFLAGS:=-O2 -flto -std=gnu99 $(shell pkg-config  --cflags-only-I $(LIBS)) -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration
+LDFLAGS:=-O2 -flto -lm $(shell pkg-config --libs $(LIBS))
 endif
 
 ifdef PROFILE
@@ -28,16 +29,50 @@
 CFLAGS+= -DM68010
 endif
 
-TRANSOBJS=gen_x86.o x86_backend.o mem.o
-M68KOBJS=68kinst.o m68k_to_x86.o runtime.o
-Z80OBJS=z80inst.o z80_to_x86.o zruntime.o
+ifndef CPU
+CPU:=$(shell uname -m)
+endif
+
+
+
+TRANSOBJS=gen.o backend.o mem.o
+M68KOBJS=68kinst.o m68k_core.o
+ifeq ($(CPU),x86_64)
+M68KOBJS+= runtime.o m68k_core_x86.o
+TRANSOBJS+= gen_x86.o backend_x86.o
+else
+ifeq ($(CPU),i686)
+M68KOBJS+= runtime_32.o m68k_core_x86.o
+TRANSOBJS+= gen_x86.o backend_x86.o
+NOZ80:=1
+endif
+endif
+
+Z80OBJS=z80inst.o z80_to_x86.o
 AUDIOOBJS=ym2612.o psg.o wave.o
 CONFIGOBJS=config.o tern.o util.o
 
+MAINOBJS=blastem.o debug.o gdb_remote.o vdp.o render_sdl.o io.o $(CONFIGOBJS) gst.o $(M68KOBJS) $(TRANSOBJS) $(AUDIOOBJS)
+
+ifeq ($(CPU),x86_64)
+CFLAGS+=-DX86_64
+else
+ifeq ($(CPU),i686)
+CFLAGS+=-DX86_32
+endif
+endif
+
+ifdef NOZ80
+CFLAGS+=-DNO_Z80
+else
+MAINOBJS+= $(Z80OBJS)
+endif
+
+
 all : dis zdis stateview vgmplay blastem
 
-blastem : blastem.o debug.o gdb_remote.o vdp.o render_sdl.o io.o $(CONFIGOBJS) gst.o $(M68KOBJS) $(Z80OBJS) $(TRANSOBJS) $(AUDIOOBJS)
-	$(CC) -ggdb -o blastem blastem.o debug.o gdb_remote.o vdp.o render_sdl.o io.o $(CONFIGOBJS) gst.o $(M68KOBJS) $(Z80OBJS) $(TRANSOBJS) $(AUDIOOBJS) $(LDFLAGS)
+blastem : $(MAINOBJS)
+	$(CC) -o blastem $(MAINOBJS) $(LDFLAGS)
 
 dis : dis.o 68kinst.o tern.o vos_program_module.o
 	$(CC) -o dis dis.o 68kinst.o tern.o vos_program_module.o
@@ -69,13 +104,16 @@
 testgst : testgst.o gst.o
 	$(CC) -o testgst testgst.o gst.o
 
-test_x86 : test_x86.o gen_x86.o
-	$(CC) -o test_x86 test_x86.o gen_x86.o
+test_x86 : test_x86.o gen_x86.o gen.o
+	$(CC) -o test_x86 test_x86.o gen_x86.o gen.o
+
+test_arm : test_arm.o gen_arm.o mem.o gen.o
+	$(CC) -o test_arm test_arm.o gen_arm.o mem.o gen.o
 
 gen_fib : gen_fib.o gen_x86.o mem.o
 	$(CC) -o gen_fib gen_fib.o gen_x86.o mem.o
 
-offsets : offsets.c z80_to_x86.h m68k_to_x86.h
+offsets : offsets.c z80_to_x86.h m68k_core.h
 	$(CC) -o offsets offsets.c
 
 vos_prog_info : vos_prog_info.o vos_program_module.o
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/backend.c	Tue Dec 30 19:11:34 2014 -0800
@@ -0,0 +1,53 @@
+/*
+ Copyright 2013 Michael Pavone
+ This file is part of BlastEm.
+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
+*/
+#include "backend.h"
+#include <stdlib.h>
+
+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 remove_deferred_until(deferred_addr **head_ptr, deferred_addr * remove_to)
+{
+	for(deferred_addr *cur = *head_ptr; cur && cur != remove_to; cur = *head_ptr)
+	{
+		*head_ptr = cur->next;
+		free(cur);
+	}
+}
+
+void process_deferred(deferred_addr ** head_ptr, void * context, native_addr_func get_native)
+{
+	deferred_addr * cur = *head_ptr;
+	deferred_addr **last_next = head_ptr;
+	while(cur)
+	{
+		code_ptr native = get_native(context, cur->address);//get_native_address(opts->native_code_map, cur->address);
+		if (native) {
+			int32_t disp = native - (cur->dest + 4);
+			code_ptr 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;
+		}
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/backend.h	Tue Dec 30 19:11:34 2014 -0800
@@ -0,0 +1,117 @@
+/*
+ Copyright 2013 Michael Pavone
+ This file is part of BlastEm.
+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
+*/
+#ifndef BACKEND_H_
+#define BACKEND_H_
+
+#include <stdint.h>
+#include <stdio.h>
+#include "gen.h"
+
+#define INVALID_OFFSET 0xFFFFFFFF
+#define EXTENSION_WORD 0xFFFFFFFE
+
+#if defined(X86_32) || defined(X86_64)
+typedef struct {
+	int32_t disp;
+	uint8_t mode;
+	uint8_t base;
+	uint8_t index;
+} host_ea;
+#else
+typedef struct {
+	int32_t disp;
+	uint8_t mode;
+	uint8_t base;
+} host_ea;
+#endif
+
+typedef struct {
+	uint8_t  *base;
+	int32_t  *offsets;
+} native_map_slot;
+
+typedef struct deferred_addr {
+	struct deferred_addr *next;
+	code_ptr             dest;
+	uint32_t             address;
+} deferred_addr;
+
+typedef enum {
+	READ_16,
+	READ_8,
+	WRITE_16,
+	WRITE_8
+} ftype;
+
+typedef struct {
+	uint32_t flags;
+	native_map_slot *native_code_map;
+	deferred_addr   *deferred;
+	code_info       code;
+	uint8_t         **ram_inst_sizes;
+	code_ptr        save_context;
+	code_ptr        load_context;
+	code_ptr        handle_cycle_limit;
+	code_ptr        handle_cycle_limit_int;
+	code_ptr        handle_code_write;
+	uint32_t        address_mask;
+	uint32_t        max_address;
+	uint32_t        bus_cycles;
+	int32_t         mem_ptr_off;
+	int32_t         ram_flags_off;
+	uint8_t         ram_flags_shift;
+	uint8_t         address_size;
+	uint8_t         byte_swap;
+	uint8_t         context_reg;
+	uint8_t         cycles;
+	uint8_t         limit;
+	uint8_t			scratch1;
+	uint8_t			scratch2;
+} cpu_options;
+
+
+#define MMAP_READ      0x01
+#define MMAP_WRITE     0x02
+#define MMAP_CODE      0x04
+#define MMAP_PTR_IDX   0x08
+#define MMAP_ONLY_ODD  0x10
+#define MMAP_ONLY_EVEN 0x20
+#define MMAP_FUNC_NULL 0x40
+#define MMAP_BYTESWAP  0x80
+
+typedef uint16_t (*read_16_fun)(uint32_t address, void * context);
+typedef uint8_t (*read_8_fun)(uint32_t address, void * context);
+typedef void * (*write_16_fun)(uint32_t address, void * context, uint16_t value);
+typedef void * (*write_8_fun)(uint32_t address, void * context, uint8_t value);
+
+typedef struct {
+	uint32_t     start;
+	uint32_t     end;
+	uint32_t     mask;
+	uint16_t     ptr_index;
+	uint16_t     flags;
+	void *       buffer;
+	read_16_fun  read_16;
+	write_16_fun write_16;
+	read_8_fun   read_8;
+	write_8_fun  write_8;
+} memmap_chunk;
+
+typedef uint8_t * (*native_addr_func)(void * context, uint32_t address);
+
+deferred_addr * defer_address(deferred_addr * old_head, uint32_t address, uint8_t *dest);
+void remove_deferred_until(deferred_addr **head_ptr, deferred_addr * remove_to);
+void process_deferred(deferred_addr ** head_ptr, void * context, native_addr_func get_native);
+
+void cycles(cpu_options *opts, uint32_t num);
+void check_cycles_int(cpu_options *opts, uint32_t address);
+void check_cycles(cpu_options * opts);
+void check_code_prologue(code_info *code);
+
+code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t num_chunks, ftype fun_type, code_ptr *after_inc);
+
+#endif //BACKEND_H_
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/backend_x86.c	Tue Dec 30 19:11:34 2014 -0800
@@ -0,0 +1,288 @@
+#include "backend.h"
+#include "gen_x86.h"
+
+void cycles(cpu_options *opts, uint32_t num)
+{
+	add_ir(&opts->code, num, opts->cycles, SZ_D);
+}
+
+void check_cycles_int(cpu_options *opts, uint32_t address)
+{
+	code_info *code = &opts->code;
+	cmp_rr(code, opts->cycles, opts->limit, SZ_D);
+	code_ptr jmp_off = code->cur+1;
+	jcc(code, CC_NC, jmp_off+1);
+	mov_ir(code, address, opts->scratch1, SZ_D);
+	call(code, opts->handle_cycle_limit_int);
+	*jmp_off = code->cur - (jmp_off+1);
+}
+
+void check_cycles(cpu_options * opts)
+{
+	code_info *code = &opts->code;
+	cmp_rr(code, opts->cycles, opts->limit, SZ_D);
+	check_alloc_code(code, MAX_INST_LEN*2);
+	code_ptr jmp_off = code->cur+1;
+	jcc(code, CC_NC, jmp_off+1);
+	call(code, opts->handle_cycle_limit);
+	*jmp_off = code->cur - (jmp_off+1);
+}
+
+void check_code_prologue(code_info *code)
+{
+	check_alloc_code(code, MAX_INST_LEN*4);
+}
+
+code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t num_chunks, ftype fun_type, code_ptr *after_inc)
+{
+	code_info *code = &opts->code;
+	code_ptr start = code->cur;
+	check_cycles(opts);
+	cycles(opts, opts->bus_cycles);
+	if (after_inc) {
+		*after_inc = code->cur;
+	}
+	if (opts->address_size == SZ_D && opts->address_mask < 0xFFFFFFFF) {
+		and_ir(code, opts->address_mask, opts->scratch1, SZ_D);
+	}
+	code_ptr lb_jcc = NULL, ub_jcc = NULL;
+	uint8_t is_write = fun_type == WRITE_16 || fun_type == WRITE_8;
+	uint8_t adr_reg = is_write ? opts->scratch2 : opts->scratch1;
+	uint16_t access_flag = is_write ? MMAP_WRITE : MMAP_READ;
+	uint8_t size =  (fun_type == READ_16 || fun_type == WRITE_16) ? SZ_W : SZ_B;
+	for (uint32_t chunk = 0; chunk < num_chunks; chunk++)
+	{
+		if (memmap[chunk].start > 0) {
+			cmp_ir(code, memmap[chunk].start, adr_reg, opts->address_size);
+			lb_jcc = code->cur + 1;
+			jcc(code, CC_C, code->cur + 2);
+		}
+		if (memmap[chunk].end < opts->max_address) {
+			cmp_ir(code, memmap[chunk].end, adr_reg, opts->address_size);
+			ub_jcc = code->cur + 1;
+			jcc(code, CC_NC, code->cur + 2);
+		}
+
+		if (memmap[chunk].mask != opts->address_mask) {
+			and_ir(code, memmap[chunk].mask, adr_reg, opts->address_size);
+		}
+		void * cfun;
+		switch (fun_type)
+		{
+		case READ_16:
+			cfun = memmap[chunk].read_16;
+			break;
+		case READ_8:
+			cfun = memmap[chunk].read_8;
+			break;
+		case WRITE_16:
+			cfun = memmap[chunk].write_16;
+			break;
+		case WRITE_8:
+			cfun = memmap[chunk].write_8;
+			break;
+		default:
+			cfun = NULL;
+		}
+		if(memmap[chunk].flags & access_flag) {
+			if (memmap[chunk].flags & MMAP_PTR_IDX) {
+				if (memmap[chunk].flags & MMAP_FUNC_NULL) {
+					cmp_irdisp(code, 0, opts->context_reg, opts->mem_ptr_off + sizeof(void*) * memmap[chunk].ptr_index, SZ_PTR);
+					code_ptr not_null = code->cur + 1;
+					jcc(code, CC_NZ, code->cur + 2);
+					call(code, opts->save_context);
+#ifdef X86_64
+					if (is_write) {
+						if (opts->scratch2 != RDI) {
+							mov_rr(code, opts->scratch2, RDI, opts->address_size);
+						}
+						mov_rr(code, opts->scratch1, RDX, size);
+					} else {
+						push_r(code, opts->context_reg);
+						mov_rr(code, opts->scratch1, RDI, opts->address_size);
+					}
+					test_ir(code, 8, RSP, opts->address_size);
+					code_ptr adjust_rsp = code->cur + 1;
+					jcc(code, CC_NZ, code->cur + 2);
+					call(code, cfun);
+					code_ptr no_adjust = code->cur + 1;
+					jmp(code, code->cur + 2);
+					*adjust_rsp = code->cur - (adjust_rsp + 1);
+					sub_ir(code, 8, RSP, SZ_PTR);
+					call(code, cfun);
+					add_ir(code, 8, RSP, SZ_PTR);
+					*no_adjust = code->cur - (no_adjust + 1);
+#else
+					if (is_write) {
+						push_r(code, opts->scratch1);
+					} else {
+						push_r(code, opts->context_reg);//save opts->context_reg for later
+					}
+					push_r(code, opts->context_reg);
+					push_r(code, is_write ? opts->scratch2 : opts->scratch1);
+					call(code, cfun);
+					add_ir(code, is_write ? 12 : 8, RSP, opts->address_size);
+#endif
+					if (is_write) {
+						mov_rr(code, RAX, opts->context_reg, SZ_PTR);
+					} else {
+						pop_r(code, opts->context_reg);
+						mov_rr(code, RAX, opts->scratch1, size);
+					}
+					jmp(code, opts->load_context);
+
+					*not_null = code->cur - (not_null + 1);
+				}
+				if ((opts->byte_swap || memmap[chunk].flags & MMAP_BYTESWAP) && size == SZ_B) {
+					xor_ir(code, 1, adr_reg, opts->address_size);
+				}
+				if (opts->address_size != SZ_D) {
+					movzx_rr(code, adr_reg, adr_reg, opts->address_size, SZ_D);
+				}
+				add_rdispr(code, opts->context_reg, opts->mem_ptr_off + sizeof(void*) * memmap[chunk].ptr_index, adr_reg, SZ_PTR);
+				if (is_write) {
+					mov_rrind(code, opts->scratch1, opts->scratch2, size);
+
+				} else {
+					mov_rindr(code, opts->scratch1, opts->scratch1, size);
+				}
+			} else {
+				uint8_t tmp_size = size;
+				if (size == SZ_B) {
+					if ((memmap[chunk].flags & MMAP_ONLY_ODD) || (memmap[chunk].flags & MMAP_ONLY_EVEN)) {
+						bt_ir(code, 0, adr_reg, opts->address_size);
+						code_ptr good_addr = code->cur + 1;
+						jcc(code, (memmap[chunk].flags & MMAP_ONLY_ODD) ? CC_C : CC_NC, code->cur + 2);
+						if (!is_write) {
+							mov_ir(code, 0xFF, opts->scratch1, SZ_B);
+						}
+						retn(code);
+						*good_addr = code->cur - (good_addr + 1);
+						shr_ir(code, 1, adr_reg, opts->address_size);
+					} else if (opts->byte_swap || memmap[chunk].flags & MMAP_BYTESWAP) {
+						xor_ir(code, 1, adr_reg, opts->address_size);
+					}
+				} else if ((memmap[chunk].flags & MMAP_ONLY_ODD) || (memmap[chunk].flags & MMAP_ONLY_EVEN)) {
+					tmp_size = SZ_B;
+					shr_ir(code, 1, adr_reg, opts->address_size);
+					if ((memmap[chunk].flags & MMAP_ONLY_EVEN) && is_write) {
+						shr_ir(code, 8, opts->scratch1, SZ_W);
+					}
+				}
+				if (opts->address_size != SZ_D) {
+					movzx_rr(code, adr_reg, adr_reg, opts->address_size, SZ_D);
+				}
+				if ((intptr_t)memmap[chunk].buffer <= 0x7FFFFFFF && (intptr_t)memmap[chunk].buffer >= -2147483648) {
+					if (is_write) {
+						mov_rrdisp(code, opts->scratch1, opts->scratch2, (intptr_t)memmap[chunk].buffer, tmp_size);
+					} else {
+						mov_rdispr(code, opts->scratch1, (intptr_t)memmap[chunk].buffer, opts->scratch1, tmp_size);
+					}
+				} else {
+					if (is_write) {
+						push_r(code, opts->scratch1);
+						mov_ir(code, (intptr_t)memmap[chunk].buffer, opts->scratch1, SZ_PTR);
+						add_rr(code, opts->scratch1, opts->scratch2, SZ_PTR);
+						pop_r(code, opts->scratch1);
+						mov_rrind(code, opts->scratch1, opts->scratch2, tmp_size);
+					} else {
+						mov_ir(code, (intptr_t)memmap[chunk].buffer, opts->scratch2, SZ_PTR);
+						mov_rindexr(code, opts->scratch2, opts->scratch1, 1, opts->scratch1, tmp_size);
+					}
+				}
+				if (size != tmp_size && !is_write) {
+					if (memmap[chunk].flags & MMAP_ONLY_EVEN) {
+						shl_ir(code, 8, opts->scratch1, SZ_W);
+						mov_ir(code, 0xFF, opts->scratch1, SZ_B);
+					} else {
+						or_ir(code, 0xFF00, opts->scratch1, SZ_W);
+					}
+				}
+			}
+			if (is_write && (memmap[chunk].flags & MMAP_CODE)) {
+				mov_rr(code, opts->scratch2, opts->scratch1, opts->address_size);
+				shr_ir(code, opts->ram_flags_shift, opts->scratch1, opts->address_size);
+				bt_rrdisp(code, opts->scratch1, opts->context_reg, opts->ram_flags_off, opts->address_size);
+				code_ptr not_code = code->cur + 1;
+				jcc(code, CC_NC, code->cur + 2);
+				call(code, opts->save_context);
+#ifdef X86_32
+				push_r(code, opts->context_reg);
+				push_r(code, opts->scratch2);
+#else
+				if (opts->scratch2 != RDI) {
+					mov_rr(code, opts->scratch2, RDI, opts->address_size);
+				}
+#endif
+				call(code, opts->handle_code_write);
+#ifdef X86_32
+				add_ir(code, 8, RSP, SZ_D);
+#endif
+				mov_rr(code, RAX, opts->context_reg, SZ_PTR);
+				call(code, opts->load_context);
+				*not_code = code->cur - (not_code+1);
+			}
+			retn(code);
+		} else if (cfun) {
+			call(code, opts->save_context);
+#ifdef X86_64
+			if (is_write) {
+				if (opts->scratch2 != RDI) {
+					mov_rr(code, opts->scratch2, RDI, opts->address_size);
+				}
+				mov_rr(code, opts->scratch1, RDX, size);
+			} else {
+				push_r(code, opts->context_reg);
+				mov_rr(code, opts->scratch1, RDI, opts->address_size);
+			}
+			test_ir(code, 8, RSP, SZ_D);
+			code_ptr adjust_rsp = code->cur + 1;
+			jcc(code, CC_NZ, code->cur + 2);
+			call(code, cfun);
+			code_ptr no_adjust = code->cur + 1;
+			jmp(code, code->cur + 2);
+			*adjust_rsp = code->cur - (adjust_rsp + 1);
+			sub_ir(code, 8, RSP, SZ_PTR);
+			call(code, cfun);
+			add_ir(code, 8, RSP, SZ_PTR);
+			*no_adjust = code->cur - (no_adjust+1);
+#else
+			if (is_write) {
+				push_r(code, opts->scratch1);
+			} else {
+				push_r(code, opts->context_reg);//save opts->context_reg for later
+			}
+			push_r(code, opts->context_reg);
+			push_r(code, is_write ? opts->scratch2 : opts->scratch1);
+			call(code, cfun);
+			add_ir(code, is_write ? 12 : 8, RSP, SZ_D);
+#endif
+			if (is_write) {
+				mov_rr(code, RAX, opts->context_reg, SZ_PTR);
+			} else {
+				pop_r(code, opts->context_reg);
+				mov_rr(code, RAX, opts->scratch1, size);
+			}
+			jmp(code, opts->load_context);
+		} else {
+			//Not sure the best course of action here
+			if (!is_write) {
+				mov_ir(code, size == SZ_B ? 0xFF : 0xFFFF, opts->scratch1, size);
+			}
+			retn(code);
+		}
+		if (lb_jcc) {
+			*lb_jcc = code->cur - (lb_jcc+1);
+			lb_jcc = NULL;
+		}
+		if (ub_jcc) {
+			*ub_jcc = code->cur - (ub_jcc+1);
+			ub_jcc = NULL;
+		}
+	}
+	if (!is_write) {
+		mov_ir(code, size == SZ_B ? 0xFF : 0xFFFF, opts->scratch1, size);
+	}
+	retn(code);
+	return start;
+}
--- a/blastem.c	Tue Dec 16 01:10:54 2014 -0800
+++ b/blastem.c	Tue Dec 30 19:11:34 2014 -0800
@@ -4,7 +4,7 @@
  BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
 */
 #include "68kinst.h"
-#include "m68k_to_x86.h"
+#include "m68k_core.h"
 #include "z80_to_x86.h"
 #include "mem.h"
 #include "vdp.h"
@@ -182,6 +182,7 @@
 
 void sync_z80(z80_context * z_context, uint32_t mclks)
 {
+#ifndef NO_Z80
 	if (z80_enabled && !reset && !busreq) {
 		genesis_context * gen = z_context->system;
 		z_context->sync_cycle = mclks / MCLKS_PER_Z80;
@@ -198,14 +199,18 @@
 				}
 				if (z_context->iff1) {
 					z_context->int_cycle = z_context->int_pulse_start < z_context->int_enable_cycle ? z_context->int_enable_cycle : z_context->int_pulse_start;
+				} else {
+					z_context->int_cycle = CYCLE_NEVER;
 				}
 				z_context->target_cycle = z_context->sync_cycle < z_context->int_cycle ? z_context->sync_cycle : z_context->int_cycle;
 				dprintf("Running Z80 from cycle %d to cycle %d. Int cycle: %d\n", z_context->current_cycle, z_context->sync_cycle, z_context->int_cycle);
-				z80_run(z_context);
+				z_context->run(z_context);
 				dprintf("Z80 ran to cycle %d\n", z_context->current_cycle);
 			}
 		}
-	} else {
+	} else
+#endif
+	{
 		z_context->current_cycle = mclks / MCLKS_PER_Z80;
 	}
 }
@@ -410,8 +415,9 @@
 	return vdp_port_write(vdp_port, context, vdp_port < 0x10 ? value | value << 8 : ((vdp_port & 1) ? value : 0));
 }
 
-z80_context * z80_vdp_port_write(uint16_t vdp_port, z80_context * context, uint8_t value)
+void * z80_vdp_port_write(uint32_t vdp_port, void * vcontext, uint8_t value)
 {
+	z80_context * context = vcontext;
 	genesis_context * gen = context->system;
 	if (vdp_port & 0xE0) {
 		printf("machine freeze due to write to Z80 address %X\n", 0x7F00 | vdp_port);
@@ -480,6 +486,34 @@
 	}
 }
 
+uint8_t z80_vdp_port_read(uint32_t vdp_port, void * vcontext)
+{
+	z80_context * context = vcontext;
+	if (vdp_port & 0xE0) {
+		printf("machine freeze due to read from Z80 address %X\n", 0x7F00 | vdp_port);
+		exit(1);
+	}
+	genesis_context * gen = context->system;
+	vdp_port &= 0x1F;
+	uint16_t ret;
+	if (vdp_port < 0x10) {
+		//These probably won't currently interact well with the 68K accessing the VDP
+		vdp_run_context(gen->vdp, context->current_cycle * MCLKS_PER_Z80);
+		if (vdp_port < 4) {
+			ret = vdp_data_port_read(gen->vdp);
+		} else if (vdp_port < 8) {
+			ret = vdp_control_port_read(gen->vdp);
+		} else {
+			printf("Illegal write to HV Counter port %X\n", vdp_port);
+			exit(1);
+		}
+	} else {
+		//TODO: Figure out the correct value today
+		ret = 0xFFFF;
+	}
+	return vdp_port & 1 ? ret : ret >> 8;
+}
+
 uint32_t zram_counter = 0;
 #define Z80_ACK_DELAY 3
 #define Z80_BUSY_DELAY 1//TODO: Find the actual value for this
@@ -499,7 +533,9 @@
 			location &= 0x7FFF;
 			if (location < 0x4000) {
 				z80_ram[location & 0x1FFF] = value;
+#ifndef NO_Z80
 				z80_handle_code_write(location & 0x1FFF, gen->z80);
+#endif
 			} else if (location < 0x6000) {
 				sync_sound(gen, context->current_cycle * MCLKS_PER_68K);
 				if (location & 1) {
@@ -699,8 +735,9 @@
 	return value;
 }
 
-z80_context * z80_write_ym(uint16_t location, z80_context * context, uint8_t value)
+void * z80_write_ym(uint32_t location, void * vcontext, uint8_t value)
 {
+	z80_context * context = vcontext;
 	genesis_context * gen = context->system;
 	sync_sound(gen, context->current_cycle * MCLKS_PER_Z80);
 	if (location & 1) {
@@ -713,13 +750,55 @@
 	return context;
 }
 
-uint8_t z80_read_ym(uint16_t location, z80_context * context)
+uint8_t z80_read_ym(uint32_t location, void * vcontext)
 {
+	z80_context * context = vcontext;
 	genesis_context * gen = context->system;
 	sync_sound(gen, context->current_cycle * MCLKS_PER_Z80);
 	return ym_read_status(gen->ym);
 }
 
+uint8_t z80_read_bank(uint32_t location, void * vcontext)
+{
+	z80_context * context = vcontext;
+	uint32_t address = context->bank_reg << 15 | location;
+	if (address >= 0xC00000 && address < 0xE00000) {
+		return z80_vdp_port_read(location & 0xFF, context);
+	} else {
+		fprintf(stderr, "Unhandled read by Z80 from address %X through banked memory area\n", address);
+	}
+	return 0;
+}
+
+void *z80_write_bank(uint32_t location, void * vcontext, uint8_t value)
+{
+	z80_context * context = vcontext;
+	uint32_t address = context->bank_reg << 15 | location;
+	if (address >= 0xE00000) {
+		address &= 0xFFFF;
+		((uint8_t *)ram)[address ^ 1] = value;
+	} else if (address >= 0xC00000) {
+		z80_vdp_port_write(location & 0xFF, context, value);
+	} else {
+		fprintf(stderr, "Unhandled write by Z80 to address %X through banked memory area\n", address);
+	}
+	return context;
+}
+
+void *z80_write_bank_reg(uint32_t location, void * vcontext, uint8_t value)
+{
+	z80_context * context = vcontext;
+	
+	context->bank_reg = (context->bank_reg >> 1 | value << 8) & 0x1FF;
+	if (context->bank_reg < 0x80) {
+		context->mem_pointers[1] = context->mem_pointers[2] + (context->bank_reg << 15);
+	} else {
+		context->mem_pointers[1] = NULL;
+	}
+	
+	return context;
+}
+
 uint16_t read_sram_w(uint32_t address, m68k_context * context)
 {
 	genesis_context * gen = context->system;
@@ -894,7 +973,7 @@
 void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, uint8_t * debugger)
 {
 	m68k_context context;
-	x86_68k_options opts;
+	m68k_options opts;
 	gen->m68k = &context;
 	memmap_chunk memmap[MAX_MAP_CHUNKS];
 	uint32_t num_chunks;
@@ -988,9 +1067,9 @@
 		}
 		atexit(save_sram);
 	}
-	init_x86_68k_opts(&opts, memmap, num_chunks);
+	init_m68k_opts(&opts, memmap, num_chunks);
 	opts.address_log = address_log;
-	init_68k_context(&context, opts.native_code_map, &opts);
+	init_68k_context(&context, opts.gen.native_code_map, &opts);
 
 	context.video_context = gen->vdp;
 	context.system = gen;
@@ -1016,7 +1095,9 @@
 			insert_breakpoint(&context, pc, debugger);
 		}
 		adjust_int_cycle(gen->m68k, gen->vdp);
+#ifndef NO_Z80
 		gen->z80->native_pc =  z80_get_native_address_trans(gen->z80, gen->z80->pc);
+#endif
 		start_68k_context(&context, pc);
 	} else {
 		if (debugger) {
@@ -1095,6 +1176,15 @@
 		}
 	}
 }
+#ifndef NO_Z80
+const memmap_chunk z80_map[] = {
+	{ 0x0000, 0x4000,  0x1FFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE,                         z80_ram, NULL, NULL, NULL,              NULL },
+	{ 0x8000, 0x10000, 0x7FFF, 1, MMAP_READ | MMAP_PTR_IDX | MMAP_FUNC_NULL | MMAP_BYTESWAP,  NULL,    NULL, NULL, z80_read_bank,     z80_write_bank},
+	{ 0x4000, 0x6000,  0x0003, 0, 0,                                                          NULL,    NULL, NULL, z80_read_ym,       z80_write_ym},
+	{ 0x6000, 0x6100,  0xFFFF, 0, 0,                                                          NULL,    NULL, NULL, NULL,              z80_write_bank_reg},
+	{ 0x7F00, 0x8000,  0x00FF, 0, 0,                                                          NULL,    NULL, NULL, z80_vdp_port_read, z80_vdp_port_write}
+};
+#endif
 
 int main(int argc, char ** argv)
 {
@@ -1260,9 +1350,11 @@
 	psg_init(&p_context, render_sample_rate(), gen.master_clock, MCLKS_PER_PSG, render_audio_buffer());
 
 	z80_context z_context;
-	x86_z80_options z_opts;
-	init_x86_z80_opts(&z_opts);
+#ifndef NO_Z80
+	z80_options z_opts;
+	init_x86_z80_opts(&z_opts, z80_map, 5);
 	init_z80_context(&z_context, &z_opts);
+#endif
 
 	z_context.system = &gen;
 	z_context.mem_pointers[0] = z80_ram;
--- a/blastem.h	Tue Dec 16 01:10:54 2014 -0800
+++ b/blastem.h	Tue Dec 30 19:11:34 2014 -0800
@@ -7,7 +7,7 @@
 #define BLASTEM_H_
 
 #include <stdint.h>
-#include "m68k_to_x86.h"
+#include "m68k_core.h"
 #include "z80_to_x86.h"
 #include "ym2612.h"
 #include "vdp.h"
--- a/comparetests.py	Tue Dec 16 01:10:54 2014 -0800
+++ b/comparetests.py	Tue Dec 30 19:11:34 2014 -0800
@@ -18,6 +18,49 @@
 	else:
 		prefixes.append(argv[i])
 
+def print_mismatch(path, b, m):
+	blines = b.split('\n')
+	mlines = m.split('\n')
+	if len(blines) != len(mlines):
+		print '-----------------------------'
+		print 'Unknown mismatch in', path
+		print 'blastem output:'
+		print b
+		print 'musashi output:'
+		print m
+		print '-----------------------------'
+		return
+	prevline = ''
+	differences = []
+	flagmismatch = False
+	regmismatch = False
+	for i in xrange(0, len(blines)):
+		if blines[i] != mlines[i]:
+			if prevline == 'XNZVC':
+				differences.append((prevline, prevline))
+				flagmismatch = True
+			else:
+				regmismatch = True
+			differences.append((blines[i], mlines[i]))
+		prevline = blines[i]
+	if flagmismatch and regmismatch:
+		mtype = 'General'
+	elif flagmismatch:
+		mtype = 'Flag'
+	elif regmismatch:
+		mtype = 'Register'
+	else:
+		mtype = 'Unknown'
+	print '-----------------------------'
+	print mtype, 'mismatch in', path
+	for i in xrange(0, 2):
+		print 'musashi' if i else 'blastem', 'output:'
+		for diff in differences:
+			print diff[i]
+	print '-----------------------------'
+
+
+
 for path in glob('generated_tests/*/*.bin'):
 	if path in skip:
 		continue
@@ -36,13 +79,8 @@
 			m = subprocess.check_output(['musashi/mustrans', path])
 			#_,_,b = b.partition('\n')
 			if b != m:
-				print '-----------------------------'
-				print 'Mismatch in ' + path
-				print 'blastem output:'
-				print b
-				print 'musashi output:'
-				print m
-				print '-----------------------------'
+				print_mismatch(path, b, m)
+
 			else:
 				print path, 'passed'
 		except subprocess.CalledProcessError as e:
--- a/debug.c	Tue Dec 16 01:10:54 2014 -0800
+++ b/debug.c	Tue Dec 30 19:11:34 2014 -0800
@@ -82,6 +82,8 @@
 	}
 }
 
+#ifndef NO_Z80
+
 void zdebugger_print(z80_context * context, char format_char, char * param)
 {
 	uint32_t value;
@@ -460,6 +462,8 @@
 	return context;
 }
 
+#endif
+
 m68k_context * debugger(m68k_context * context, uint32_t address)
 {
 	static char last_cmd[1024];
@@ -527,19 +531,49 @@
 				debugging = 0;
 				break;
 			case 'b':
-				param = find_param(input_buf);
-				if (!param) {
-					fputs("b command requires a parameter\n", stderr);
-					break;
+				if (input_buf[1] == 't') {
+					uint32_t stack = context->aregs[7];
+					if (stack >= 0xE00000) {
+						stack &= 0xFFFF;
+						uint8_t non_adr_count = 0;
+						do {
+							uint32_t bt_address = ram[stack/2] << 16 | ram[stack/2+1];
+							bt_address = get_instruction_start(context->native_code_map, bt_address - 2);
+							if (bt_address) {
+								stack += 4;
+								non_adr_count = 0;
+								uint16_t *bt_pc = NULL;
+								if (bt_address < 0x400000) {
+									bt_pc = cart + bt_address/2;
+								} else if(bt_address > 0xE00000) {
+									bt_pc = ram + (bt_address & 0xFFFF)/2;
+								}
+								m68k_decode(bt_pc, &inst, bt_address);
+								m68k_disasm(&inst, input_buf);
+								printf("%X: %s\n", bt_address, input_buf);
+							} else {
+								//non-return address value on stack can be word wide
+								stack += 2;
+								non_adr_count++;
+							}
+							stack &= 0xFFFF;
+						} while (stack && non_adr_count < 6);
+					}
+				} else {
+					param = find_param(input_buf);
+					if (!param) {
+						fputs("b command requires a parameter\n", stderr);
+						break;
+					}
+					value = strtol(param, NULL, 16);
+					insert_breakpoint(context, value, (uint8_t *)debugger);
+					new_bp = malloc(sizeof(bp_def));
+					new_bp->next = breakpoints;
+					new_bp->address = value;
+					new_bp->index = bp_index++;
+					breakpoints = new_bp;
+					printf("68K Breakpoint %d set at %X\n", new_bp->index, value);
 				}
-				value = strtol(param, NULL, 16);
-				insert_breakpoint(context, value, (uint8_t *)debugger);
-				new_bp = malloc(sizeof(bp_def));
-				new_bp->next = breakpoints;
-				new_bp->address = value;
-				new_bp->index = bp_index++;
-				breakpoints = new_bp;
-				printf("68K Breakpoint %d set at %X\n", new_bp->index, value);
 				break;
 			case 'a':
 				param = find_param(input_buf);
@@ -706,6 +740,7 @@
 				}
 				break;
 			}
+#ifndef NO_Z80
 			case 'z': {
 				genesis_context * gen = context->system;
 				//Z80 debug commands
@@ -736,6 +771,7 @@
 				}
 				break;
 			}
+#endif
 			case 'q':
 				puts("Quitting");
 				exit(0);
--- a/debug.h	Tue Dec 16 01:10:54 2014 -0800
+++ b/debug.h	Tue Dec 30 19:11:34 2014 -0800
@@ -2,7 +2,7 @@
 #define DEBUG_H_
 
 #include <stdint.h>
-#include "m68k_to_x86.h"
+#include "m68k_core.h"
 
 typedef struct disp_def {
 	struct disp_def * next;
--- a/dis.c	Tue Dec 16 01:10:54 2014 -0800
+++ b/dis.c	Tue Dec 30 19:11:34 2014 -0800
@@ -292,7 +292,7 @@
 					if (is_visited(address)) {
 						break;
 					}
-				} else if (instbuf.src.addr_mode = MODE_PC_DISPLACE) {
+				} else if (instbuf.src.addr_mode == MODE_PC_DISPLACE) {
 					address = instbuf.src.params.regs.displacement + instbuf.address + 2;
 					encoded = filebuf + (address - address_off)/2;
 					if (is_visited(address)) {
--- a/gdb_remote.c	Tue Dec 16 01:10:54 2014 -0800
+++ b/gdb_remote.c	Tue Dec 30 19:11:34 2014 -0800
@@ -145,7 +145,9 @@
 	} else if (address >= 0xA00000 && address < 0xA04000) {
 		z80_ram[address & 0x1FFF] = value;
 		genesis_context * gen = context->system;
+#ifndef NO_Z80
 		z80_handle_code_write(address & 0x1FFF, gen->z80);
+#endif
 		return;
 	} else {
 		return;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen.c	Tue Dec 30 19:11:34 2014 -0800
@@ -0,0 +1,15 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "gen.h"
+#include "mem.h"
+
+void init_code_info(code_info *code)
+{
+	size_t size = CODE_ALLOC_SIZE;
+	code->cur = alloc_code(&size);
+	if (!code->cur) {
+		fputs("Failed to allocate memory for generated code\n", stderr);
+		exit(1);
+	}
+	code->last = code->cur + size/sizeof(code_word) - RESERVE_WORDS;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen.h	Tue Dec 30 19:11:34 2014 -0800
@@ -0,0 +1,25 @@
+#ifndef GEN_H_
+#define GEN_H_
+#include <stdint.h>
+
+#if defined(X86_64) || defined(X86_32)
+typedef uint8_t code_word;
+#define RESERVE_WORDS 5 //opcode + 4-byte displacement
+#else
+typedef uint32_t code_word;
+#define RESERVE_WORDS 4 //1 push + 1 ldr + 1bx + 1 constant
+#endif
+typedef code_word * code_ptr;
+#define CODE_ALLOC_SIZE (1024*1024)
+
+typedef struct {
+	code_ptr cur;
+	code_ptr last;
+} code_info;
+
+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_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen_arm.c	Tue Dec 30 19:11:34 2014 -0800
@@ -0,0 +1,550 @@
+/*
+ Copyright 2014 Michael Pavone
+ This file is part of BlastEm.
+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
+*/
+#include "gen_arm.h"
+#include "mem.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+#define OP_FIELD_SHIFT 21u
+
+//Data processing format instructions
+#define OP_AND 0x0u
+#define OP_EOR (0x1u << OP_FIELD_SHIFT)
+#define OP_SUB (0x2u << OP_FIELD_SHIFT)
+#define OP_RSB (0x3u << OP_FIELD_SHIFT)
+#define OP_ADD (0x4u << OP_FIELD_SHIFT)
+#define OP_ADC (0x5u << OP_FIELD_SHIFT)
+#define OP_SBC (0x6u << OP_FIELD_SHIFT)
+#define OP_RSC (0x7u << OP_FIELD_SHIFT)
+#define OP_TST (0x8u << OP_FIELD_SHIFT)
+#define OP_TEQ (0x9u << OP_FIELD_SHIFT)
+#define OP_CMP (0xAu << OP_FIELD_SHIFT)
+#define OP_CMN (0xBu << OP_FIELD_SHIFT)
+#define OP_ORR (0xCu << OP_FIELD_SHIFT)
+#define OP_MOV (0xDu << OP_FIELD_SHIFT)
+#define OP_BIC (0xEu << OP_FIELD_SHIFT)
+#define OP_MVN (0xFu << OP_FIELD_SHIFT)
+
+//branch instructions
+#define OP_B  0xA000000u
+#define OP_BL 0xB000000u
+#define OP_BX 0x12FFF10u
+
+//load/store
+#define OP_STR   0x4000000u
+#define OP_LDR   0x4100000u
+#define OP_STM   0x8000000u
+#define OP_LDM   0x8100000u
+#define POST_IND 0u
+#define PRE_IND  0x1000000u
+#define DIR_DOWN 0u
+#define DIR_UP   0x0800000u
+#define SZ_W     0u
+#define SZ_B     0x0400000u
+#define WRITE_B  0x0200000u
+#define OFF_IMM  0u
+#define OFF_REG  0x2000000u
+
+#define PUSH     (OP_STR | PRE_IND | OFF_IMM | SZ_W | WRITE_B | DIR_DOWN | sizeof(uint32_t) | (sp << 16))
+#define POP      (OP_LDR | POST_IND | OFF_IMM | SZ_W | DIR_UP | sizeof(uint32_t) | (sp << 16))
+#define PUSHM     (OP_STM | PRE_IND | SZ_W | WRITE_B | DIR_DOWN | (sp << 16))
+#define POPM      (OP_LDM | POST_IND | SZ_W | WRITE_B | DIR_UP | (sp << 16))
+
+#define IMMED    0x2000000u
+#define REG      0u
+
+
+uint32_t make_immed(uint32_t val)
+{
+	uint32_t rot_amount = 0;
+	for (; rot_amount < 0x20; rot_amount += 2)
+	{
+		uint32_t test_mask = ~(0xFF << rot_amount | 0xFF >> (32-rot_amount));
+		if (!(test_mask & val)) {
+			return val << rot_amount | val >> (32-rot_amount) | rot_amount << 7;
+		}
+	}
+	return INVALID_IMMED;
+}
+
+void check_alloc_code(code_info *code)
+{
+	if (code->cur == code->last) {
+		size_t size = CODE_ALLOC_SIZE;
+		uint32_t *next_code = alloc_code(&size);
+		if (!next_code) {
+			fputs("Failed to allocate memory for generated code\n", stderr);
+			exit(1);
+		}
+		if (next_code = code->last + RESERVE_WORDS) {
+			//new chunk is contiguous with the current one
+			code->last = next_code + size/sizeof(code_word) - RESERVE_WORDS;
+		} else {
+			uint32_t * from = code->cur + 2;
+			if (next_code - from < 0x400000 || from - next_code <= 0x400000) {
+				*from = CC_AL | OP_B | ((next_code - from) & 0xFFFFFF);
+			} else {
+				//push r0 onto the stack
+				*(from++) = CC_AL | PUSH;
+				uint32_t immed = make_immed((uint32_t)next_code);
+				if (immed == INVALID_IMMED) {
+					//Load target into r0 from word after next instruction into register 0
+					*(from++) = CC_AL | OP_LDR | OFF_IMM | DIR_DOWN | PRE_IND | SZ_W | (pc << 16) | 4;
+					from[1] = (uint32_t)next_code;
+				} else {
+					//Load target into r0
+					*(from++) = CC_AL | OP_MOV | IMMED | NO_COND | immed;
+				}
+				//branch to address in r0
+				*from = CC_AL | OP_BX;
+				code->last = next_code + size/sizeof(code_word) - RESERVE_WORDS;
+				//pop r0
+				*(next_code++) = CC_AL | POP;
+				code->cur = next_code;
+			}
+		}
+	}
+}
+
+uint32_t data_proc(code_info *code, uint32_t cond, uint32_t op, uint32_t set_cond, uint32_t dst, uint32_t src1, uint32_t src2)
+{
+	check_alloc_code(code);
+	*(code->cur++) = cond | op | set_cond | (src1 << 16) | (dst << 12) | src2;
+
+	return CODE_OK;
+}
+
+uint32_t data_proci(code_info *code, uint32_t cond, uint32_t op, uint32_t set_cond, uint32_t dst, uint32_t src1, uint32_t immed)
+{
+	immed = make_immed(immed);
+	if (immed == INVALID_IMMED) {
+		return immed;
+	}
+	return data_proc(code, cond, op | IMMED, set_cond, dst, src1, immed);
+}
+
+//TODO: support shifted register for op2
+
+uint32_t and(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
+{
+	return data_proc(code, CC_AL, OP_AND, set_cond, dst, src1, src2);
+}
+
+uint32_t andi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
+{
+	return data_proci(code, CC_AL, OP_AND, set_cond, dst, src1, immed);
+}
+
+uint32_t and_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
+{
+	return data_proc(code, cc, OP_AND, set_cond, dst, src1, src2);
+}
+
+uint32_t andi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
+{
+	return data_proci(code, cc, OP_AND, set_cond, dst, src1, immed);
+}
+
+uint32_t eor(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
+{
+	return data_proc(code, CC_AL, OP_EOR, set_cond, dst, src1, src2);
+}
+
+uint32_t eori(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
+{
+	return data_proci(code, CC_AL, OP_EOR, set_cond, dst, src1, immed);
+}
+
+uint32_t eor_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
+{
+	return data_proc(code, cc, OP_EOR, set_cond, dst, src1, src2);
+}
+
+uint32_t eori_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
+{
+	return data_proci(code, cc, OP_EOR, set_cond, dst, src1, immed);
+}
+
+uint32_t sub(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
+{
+	return data_proc(code, CC_AL, OP_SUB, set_cond, dst, src1, src2);
+}
+
+uint32_t subi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
+{
+	return data_proci(code, CC_AL, OP_SUB, set_cond, dst, src1, immed);
+}
+
+uint32_t sub_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
+{
+	return data_proc(code, cc, OP_SUB, set_cond, dst, src1, src2);
+}
+
+uint32_t subi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
+{
+	return data_proci(code, cc, OP_SUB, set_cond, dst, src1, immed);
+}
+
+uint32_t rsb(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
+{
+	return data_proc(code, CC_AL, OP_RSB, set_cond, dst, src1, src2);
+}
+
+uint32_t rsbi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
+{
+	return data_proci(code, CC_AL, OP_RSB, set_cond, dst, src1, immed);
+}
+
+uint32_t rsb_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
+{
+	return data_proc(code, cc, OP_RSB, set_cond, dst, src1, src2);
+}
+
+uint32_t rsbi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
+{
+	return data_proci(code, cc, OP_RSB, set_cond, dst, src1, immed);
+}
+
+uint32_t add(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
+{
+	return data_proc(code, CC_AL, OP_ADD, set_cond, dst, src1, src2);
+}
+
+uint32_t addi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
+{
+	return data_proci(code, CC_AL, OP_ADD, set_cond, dst, src1, immed);
+}
+
+uint32_t add_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
+{
+	return data_proc(code, cc, OP_ADD, set_cond, dst, src1, src2);
+}
+
+uint32_t addi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
+{
+	return data_proci(code, cc, OP_ADD, set_cond, dst, src1, immed);
+}
+
+uint32_t adc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
+{
+	return data_proc(code, CC_AL, OP_ADC, set_cond, dst, src1, src2);
+}
+
+uint32_t adci(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
+{
+	return data_proci(code, CC_AL, OP_ADC, set_cond, dst, src1, immed);
+}
+
+uint32_t adc_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
+{
+	return data_proc(code, cc, OP_ADC, set_cond, dst, src1, src2);
+}
+
+uint32_t adci_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
+{
+	return data_proci(code, cc, OP_ADC, set_cond, dst, src1, immed);
+}
+
+uint32_t sbc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
+{
+	return data_proc(code, CC_AL, OP_SBC, set_cond, dst, src1, src2);
+}
+
+uint32_t sbci(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
+{
+	return data_proci(code, CC_AL, OP_SBC, set_cond, dst, src1, immed);
+}
+
+uint32_t sbc_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
+{
+	return data_proc(code, cc, OP_SBC, set_cond, dst, src1, src2);
+}
+
+uint32_t sbci_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
+{
+	return data_proci(code, cc, OP_SBC, set_cond, dst, src1, immed);
+}
+
+uint32_t rsc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
+{
+	return data_proc(code, CC_AL, OP_RSC, set_cond, dst, src1, src2);
+}
+
+uint32_t rsci(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
+{
+	return data_proci(code, CC_AL, OP_RSC, set_cond, dst, src1, immed);
+}
+
+uint32_t rsc_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
+{
+	return data_proc(code, cc, OP_RSC, set_cond, dst, src1, src2);
+}
+
+uint32_t rsci_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
+{
+	return data_proci(code, cc, OP_RSC, set_cond, dst, src1, immed);
+}
+
+uint32_t tst(code_info *code, uint32_t src1, uint32_t src2)
+{
+	return data_proc(code, CC_AL, OP_TST, SET_COND, r0, src1, src2);
+}
+
+uint32_t tsti(code_info *code, uint32_t src1, uint32_t immed)
+{
+	return data_proci(code, CC_AL, OP_TST, SET_COND, r0, src1, immed);
+}
+
+uint32_t tst_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc)
+{
+	return data_proc(code, cc, OP_TST, SET_COND, r0, src1, src2);
+}
+
+uint32_t tsti_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc)
+{
+	return data_proci(code, cc, OP_TST, SET_COND, r0, src1, immed);
+}
+
+uint32_t teq(code_info *code, uint32_t src1, uint32_t src2)
+{
+	return data_proc(code, CC_AL, OP_TEQ, SET_COND, r0, src1, src2);
+}
+
+uint32_t teqi(code_info *code, uint32_t src1, uint32_t immed)
+{
+	return data_proci(code, CC_AL, OP_TEQ, SET_COND, r0, src1, immed);
+}
+
+uint32_t teq_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc)
+{
+	return data_proc(code, cc, OP_TEQ, SET_COND, r0, src1, src2);
+}
+
+uint32_t teqi_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc)
+{
+	return data_proci(code, cc, OP_TEQ, SET_COND, r0, src1, immed);
+}
+
+uint32_t cmp(code_info *code, uint32_t src1, uint32_t src2)
+{
+	return data_proc(code, CC_AL, OP_CMP, SET_COND, r0, src1, src2);
+}
+
+uint32_t cmpi(code_info *code, uint32_t src1, uint32_t immed)
+{
+	return data_proci(code, CC_AL, OP_CMP, SET_COND, r0, src1, immed);
+}
+
+uint32_t cmp_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc)
+{
+	return data_proc(code, cc, OP_CMP, SET_COND, r0, src1, src2);
+}
+
+uint32_t cmpi_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc)
+{
+	return data_proci(code, cc, OP_CMP, SET_COND, r0, src1, immed);
+}
+
+uint32_t cmn(code_info *code, uint32_t src1, uint32_t src2)
+{
+	return data_proc(code, CC_AL, OP_CMN, SET_COND, r0, src1, src2);
+}
+
+uint32_t cmni(code_info *code, uint32_t src1, uint32_t immed)
+{
+	return data_proci(code, CC_AL, OP_CMN, SET_COND, r0, src1, immed);
+}
+
+uint32_t cmn_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc)
+{
+	return data_proc(code, cc, OP_CMN, SET_COND, r0, src1, src2);
+}
+
+uint32_t cmni_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc)
+{
+	return data_proci(code, cc, OP_CMN, SET_COND, r0, src1, immed);
+}
+
+uint32_t orr(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
+{
+	return data_proc(code, CC_AL, OP_ORR, set_cond, dst, src1, src2);
+}
+
+uint32_t orri(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
+{
+	return data_proci(code, CC_AL, OP_ORR, set_cond, dst, src1, immed);
+}
+
+uint32_t orr_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
+{
+	return data_proc(code, cc, OP_ORR, set_cond, dst, src1, src2);
+}
+
+uint32_t orri_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
+{
+	return data_proci(code, cc, OP_ORR, set_cond, dst, src1, immed);
+}
+
+uint32_t mov(code_info *code, uint32_t dst, uint32_t src2, uint32_t set_cond)
+{
+	return data_proc(code, CC_AL, OP_MOV, set_cond, dst, 0, src2);
+}
+
+uint32_t movi(code_info *code, uint32_t dst, uint32_t immed, uint32_t set_cond)
+{
+	return data_proci(code, CC_AL, OP_MOV, set_cond, dst, 0, immed);
+}
+
+uint32_t mov_cc(code_info *code, uint32_t dst, uint32_t src2, uint32_t cc, uint32_t set_cond)
+{
+	return data_proc(code, cc, OP_MOV, set_cond, dst, 0, src2);
+}
+
+uint32_t movi_cc(code_info *code, uint32_t dst, uint32_t immed, uint32_t cc, uint32_t set_cond)
+{
+	return data_proci(code, cc, OP_MOV, set_cond, dst, 0, immed);
+}
+
+uint32_t bic(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
+{
+	return data_proc(code, CC_AL, OP_BIC, set_cond, dst, src1, src2);
+}
+
+uint32_t bici(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
+{
+	return data_proci(code, CC_AL, OP_BIC, set_cond, dst, src1, immed);
+}
+
+uint32_t bic_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
+{
+	return data_proc(code, cc, OP_BIC, set_cond, dst, src1, src2);
+}
+
+uint32_t bici_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
+{
+	return data_proci(code, cc, OP_BIC, set_cond, dst, src1, immed);
+}
+
+uint32_t mvn(code_info *code, uint32_t dst, uint32_t src2, uint32_t set_cond)
+{
+	return data_proc(code, CC_AL, OP_MVN, set_cond, dst, 0, src2);
+}
+
+uint32_t mvni(code_info *code, uint32_t dst, uint32_t immed, uint32_t set_cond)
+{
+	return data_proci(code, CC_AL, OP_MVN, set_cond, dst, 0, immed);
+}
+
+uint32_t mvn_cc(code_info *code, uint32_t dst, uint32_t src2, uint32_t cc, uint32_t set_cond)
+{
+	return data_proc(code, cc, OP_MVN, set_cond, dst, 0, src2);
+}
+
+uint32_t mvni_cc(code_info *code, uint32_t dst, uint32_t immed, uint32_t cc, uint32_t set_cond)
+{
+	return data_proci(code, cc, OP_MVN, set_cond, dst, 0, immed);
+}
+
+uint32_t branchi(code_info *code, uint32_t cc, uint32_t op, uint32_t *dst)
+{
+	uint32_t * from = code->cur + 2;
+	if (dst - from >= 0x400000 && from - dst > 0x400000) {
+		return INVALID_IMMED;
+	}
+	check_alloc_code(code);
+	*(code->cur++) = cc | op | ((dst - from) & 0xFFFFFF);
+	return CODE_OK;
+}
+
+uint32_t b(code_info *code, uint32_t *dst)
+{
+	return branchi(code, CC_AL, OP_B, dst);
+}
+
+uint32_t b_cc(code_info *code, uint32_t *dst, uint32_t cc)
+{
+	return branchi(code, cc, OP_B, dst);
+}
+
+uint32_t bl(code_info *code, uint32_t *dst)
+{
+	return branchi(code, CC_AL, OP_BL, dst);
+}
+
+uint32_t bl_cc(code_info *code, uint32_t *dst, uint32_t cc)
+{
+	return branchi(code, cc, OP_BL, dst);
+}
+
+uint32_t bx(code_info *code, uint32_t dst)
+{
+	check_alloc_code(code);
+	*(code->cur++) = CC_AL | OP_BX | dst;
+	return CODE_OK;
+}
+
+uint32_t bx_cc(code_info *code, uint32_t dst, uint32_t cc)
+{
+	check_alloc_code(code);
+	*(code->cur++) = cc | OP_BX | dst;
+	return CODE_OK;
+}
+
+uint32_t push(code_info *code, uint32_t reg)
+{
+	check_alloc_code(code);
+	*(code->cur++) = CC_AL | PUSH | reg << 12;
+	return CODE_OK;
+}
+
+uint32_t push_cc(code_info *code, uint32_t reg, uint32_t cc)
+{
+	check_alloc_code(code);
+	*(code->cur++) = cc | PUSH | reg << 12;
+	return CODE_OK;
+}
+
+uint32_t pushm(code_info *code, uint32_t reglist)
+{
+	check_alloc_code(code);
+	*(code->cur++) = CC_AL | PUSHM | reglist;
+	return CODE_OK;
+}
+
+uint32_t pushm_cc(code_info *code, uint32_t reglist, uint32_t cc)
+{
+	check_alloc_code(code);
+	*(code->cur++) = cc | PUSHM | reglist;
+	return CODE_OK;
+}
+
+uint32_t pop(code_info *code, uint32_t reg)
+{
+	check_alloc_code(code);
+	*(code->cur++) = CC_AL | POP | reg << 12;
+	return CODE_OK;
+}
+
+uint32_t pop_cc(code_info *code, uint32_t reg, uint32_t cc)
+{
+	check_alloc_code(code);
+	*(code->cur++) = cc | POP | reg << 12;
+	return CODE_OK;
+}
+
+uint32_t popm(code_info *code, uint32_t reglist)
+{
+	check_alloc_code(code);
+	*(code->cur++) = CC_AL | POPM | reglist;
+	return CODE_OK;
+}
+
+uint32_t popm_cc(code_info *code, uint32_t reglist, uint32_t cc)
+{
+	check_alloc_code(code);
+	*(code->cur++) = cc | POPM | reglist;
+	return CODE_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen_arm.h	Tue Dec 30 19:11:34 2014 -0800
@@ -0,0 +1,153 @@
+/*
+ Copyright 2014 Michael Pavone
+ This file is part of BlastEm.
+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
+*/
+#ifndef GEN_ARM_H_
+#define GEN_ARM_H_
+
+#include <stdint.h>
+#include "gen.h"
+
+#define SET_COND 0x100000u
+#define NO_COND  0u
+
+#define CC_FIELD_SHIFT 28
+
+#define CC_EQ 0x0u
+#define CC_NE (0x1u << CC_FIELD_SHIFT)
+#define CC_CS (0x2u << CC_FIELD_SHIFT)
+#define CC_CC (0x3u << CC_FIELD_SHIFT)
+#define CC_MI (0x4u << CC_FIELD_SHIFT)
+#define CC_PL (0x5u << CC_FIELD_SHIFT)
+#define CC_VS (0x6u << CC_FIELD_SHIFT)
+#define CC_VC (0x7u << CC_FIELD_SHIFT)
+#define CC_HI (0x8u << CC_FIELD_SHIFT)
+#define CC_LS (0x9u << CC_FIELD_SHIFT)
+#define CC_GE (0xAu << CC_FIELD_SHIFT)
+#define CC_LT (0xBu << CC_FIELD_SHIFT)
+#define CC_GT (0xCu << CC_FIELD_SHIFT)
+#define CC_LE (0xDu << CC_FIELD_SHIFT)
+#define CC_AL (0xEu << CC_FIELD_SHIFT)
+
+#define INVALID_IMMED 0xFFFFFFFFu
+#define CODE_OK 0u
+
+enum {
+	r0,
+	r1,
+	r2,
+	r3,
+	r4,
+	r5,
+	r6,
+	r7,
+	r8,
+	r9,
+	r10,
+	r11,
+	r12,
+	sp,
+	lr,
+	pc
+};
+
+#define R0  0x1
+#define R1  0x2
+#define R2  0x4
+#define R3  0x8
+#define R4  0x10
+#define R5  0x20
+#define R6  0x40
+#define R7  0x80
+#define R8  0x100
+#define R9  0x200
+#define R10 0x400
+#define R11 0x800
+#define R12 0x1000
+#define SP  0x2000
+#define LR  0x4000
+#define PC  0x8000
+
+uint32_t and(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond);
+uint32_t andi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond);
+uint32_t and_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond);
+uint32_t andi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond);
+uint32_t eor(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond);
+uint32_t eori(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond);
+uint32_t eor_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond);
+uint32_t eori_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond);
+uint32_t sub(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond);
+uint32_t subi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond);
+uint32_t sub_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond);
+uint32_t subi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond);
+uint32_t rsb(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond);
+uint32_t rsbi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond);
+uint32_t rsb_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond);
+uint32_t rsbi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond);
+uint32_t add(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond);
+uint32_t addi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond);
+uint32_t add_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond);
+uint32_t addi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond);
+uint32_t adc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond);
+uint32_t adci(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond);
+uint32_t adc_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond);
+uint32_t adci_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond);
+uint32_t sbc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond);
+uint32_t sbci(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond);
+uint32_t sbc_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond);
+uint32_t sbci_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond);
+uint32_t rsc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond);
+uint32_t rsci(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond);
+uint32_t rsc_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond);
+uint32_t rsci_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond);
+uint32_t tst(code_info *code, uint32_t src1, uint32_t src2);
+uint32_t tsti(code_info *code, uint32_t src1, uint32_t immed);
+uint32_t tst_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc);
+uint32_t tsti_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc);
+uint32_t teq(code_info *code, uint32_t src1, uint32_t src2);
+uint32_t teqi(code_info *code, uint32_t src1, uint32_t immed);
+uint32_t teq_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc);
+uint32_t teqi_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc);
+uint32_t cmp(code_info *code, uint32_t src1, uint32_t src2);
+uint32_t cmpi(code_info *code, uint32_t src1, uint32_t immed);
+uint32_t cmp_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc);
+uint32_t cmpi_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc);
+uint32_t cmn(code_info *code, uint32_t src1, uint32_t src2);
+uint32_t cmni(code_info *code, uint32_t src1, uint32_t immed);
+uint32_t cmn_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc);
+uint32_t cmni_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc);
+uint32_t orr(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond);
+uint32_t orri(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond);
+uint32_t orr_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond);
+uint32_t orri_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond);
+uint32_t mov(code_info *code, uint32_t dst, uint32_t src2, uint32_t set_cond);
+uint32_t movi(code_info *code, uint32_t dst, uint32_t immed, uint32_t set_cond);
+uint32_t mov_cc(code_info *code, uint32_t dst, uint32_t src2, uint32_t cc, uint32_t set_cond);
+uint32_t movi_cc(code_info *code, uint32_t dst, uint32_t immed, uint32_t cc, uint32_t set_cond);
+uint32_t bic(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond);
+uint32_t bici(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond);
+uint32_t bic_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond);
+uint32_t bici_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond);
+uint32_t mvn(code_info *code, uint32_t dst, uint32_t src2, uint32_t set_cond);
+uint32_t mvni(code_info *code, uint32_t dst, uint32_t immed, uint32_t set_cond);
+uint32_t mvn_cc(code_info *code, uint32_t dst, uint32_t src2, uint32_t cc, uint32_t set_cond);
+uint32_t mvni_cc(code_info *code, uint32_t dst, uint32_t immed, uint32_t cc, uint32_t set_cond);
+
+uint32_t b(code_info *code, uint32_t *dst);
+uint32_t b_cc(code_info *code, uint32_t *dst, uint32_t cc);
+uint32_t bl(code_info *code, uint32_t *dst);
+uint32_t bl_cc(code_info *code, uint32_t *dst, uint32_t cc);
+uint32_t bx(code_info *code, uint32_t dst);
+uint32_t bx_cc(code_info *code, uint32_t dst, uint32_t cc);
+
+uint32_t push(code_info *code, uint32_t reg);
+uint32_t push_cc(code_info *code, uint32_t reg, uint32_t cc);
+uint32_t pushm(code_info *code, uint32_t reglist);
+uint32_t pushm_cc(code_info *code, uint32_t reglist, uint32_t cc);
+uint32_t pop(code_info *code, uint32_t reg);
+uint32_t pop_cc(code_info *code, uint32_t reg, uint32_t cc);
+uint32_t popm(code_info *code, uint32_t reglist);
+uint32_t popm_cc(code_info *code, uint32_t reglist, uint32_t cc);
+
+#endif //GEN_ARM_H_
--- a/gen_x86.c	Tue Dec 16 01:10:54 2014 -0800
+++ b/gen_x86.c	Tue Dec 30 19:11:34 2014 -0800
@@ -4,7 +4,7 @@
  BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
 */
 #include "gen_x86.h"
-#include "68kinst.h"
+#include "mem.h"
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -33,6 +33,7 @@
 #define OP_TEST 0x84
 #define OP_XCHG 0x86
 #define OP_MOV 0x88
+#define PRE_XOP 0x8F
 #define OP_XCHG_AX 0x90
 #define OP_CDQ 0x99
 #define OP_PUSHF 0x9C
@@ -127,8 +128,55 @@
 	X86_R15
 } x86_regs_enc;
 
-uint8_t * x86_rr_sizedir(uint8_t * out, uint16_t opcode, uint8_t src, uint8_t dst, uint8_t size)
+void jmp_nocheck(code_info *code, code_ptr dest)
 {
+	code_ptr out = code->cur;
+	ptrdiff_t disp = dest-(out+2);
+	if (disp <= 0x7F && disp >= -0x80) {
+		*(out++) = OP_JMP_BYTE;
+		*(out++) = disp;
+	} else {
+		disp = dest-(out+5);
+		if (disp <= 0x7FFFFFFF && disp >= -2147483648) {
+			*(out++) = OP_JMP;
+			*(out++) = disp;
+			disp >>= 8;
+			*(out++) = disp;
+			disp >>= 8;
+			*(out++) = disp;
+			disp >>= 8;
+			*(out++) = disp;
+		} else {
+			fprintf(stderr, "jmp: %p - %p = %lX\n", dest, out + 6, (long)disp);
+			exit(1);
+		}
+	}
+	code->cur = out;
+}
+
+void check_alloc_code(code_info *code, uint32_t inst_size)
+{
+	if (code->cur + inst_size > code->last) {
+		size_t size = CODE_ALLOC_SIZE;
+		code_ptr next_code = alloc_code(&size);
+		if (!next_code) {
+			fputs("Failed to allocate memory for generated code\n", stderr);
+			exit(1);
+		}
+		if (next_code != code->last + RESERVE_WORDS) {
+			//new chunk is not contiguous with the current one
+			jmp_nocheck(code, next_code);
+			code->cur = next_code;
+			code->last = next_code + size/sizeof(RESERVE_WORDS);
+		}
+		code->last = next_code + size/sizeof(code_word) - RESERVE_WORDS;
+	}
+}
+
+void x86_rr_sizedir(code_info *code, uint16_t opcode, uint8_t src, uint8_t dst, uint8_t size)
+{
+	check_alloc_code(code, 5);
+	code_ptr out = code->cur;
 	uint8_t tmp;
 	if (size == SZ_W) {
 		*(out++) = PRE_SIZE;
@@ -175,60 +223,13 @@
 		*(out++) = opcode;
 	}
 	*(out++) = MODE_REG_DIRECT | dst | (src << 3);
-	return out;
+	code->cur = out;
 }
 
-uint8_t * x86_rrdisp8_sizedir(uint8_t * out, uint16_t opcode, uint8_t reg, uint8_t base, int8_t disp, uint8_t size, uint8_t dir)
+void x86_rrdisp_sizedir(code_info *code, uint16_t opcode, uint8_t reg, uint8_t base, int32_t disp, uint8_t size, uint8_t dir)
 {
-	//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
-	uint8_t tmp;
-	if (size == SZ_W) {
-		*(out++) = PRE_SIZE;
-	}
-	if (size == SZ_Q || reg >= R8 || base >= R8 || (size == SZ_B && reg >= RSP && reg <= RDI)) {
-		*out = PRE_REX;
-		if (reg >= AH && reg <= BH) {
-			fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
-			exit(1);
-		}
-		if (size == SZ_Q) {
-			*out |= REX_QUAD;
-		}
-		if (reg >= R8) {
-			*out |= REX_REG_FIELD;
-			reg -= (R8 - X86_R8);
-		}
-		if (base >= R8) {
-			*out |= REX_RM_FIELD;
-			base -= (R8 - X86_R8);
-		}
-		out++;
-	}
-	if (size == SZ_B) {
-		if (reg >= AH && reg <= BH) {
-			reg -= (AH-X86_AH);
-		}
-	} else {
-		opcode |= BIT_SIZE;
-	}
-	opcode |= dir;
-	if (opcode >= 0x100) {
-		*(out++) = opcode >> 8;
-		*(out++) = opcode;
-	} else {
-		*(out++) = opcode;
-	}
-	*(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;
-}
-
-uint8_t * x86_rrdisp32_sizedir(uint8_t * out, uint16_t opcode, uint8_t reg, uint8_t base, int32_t disp, uint8_t size, uint8_t dir)
-{
+	check_alloc_code(code, 10);
+	code_ptr out = code->cur;
 	//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
 	uint8_t tmp;
 	if (size == SZ_W) {
@@ -267,20 +268,28 @@
 	} else {
 		*(out++) = opcode;
 	}
-	*(out++) = MODE_REG_DISPLACE32 | base | (reg << 3);
+	if (disp < 128 && disp >= -128) {
+		*(out++) = MODE_REG_DISPLACE8 | base | (reg << 3);
+	} else {
+		*(out++) = MODE_REG_DISPLACE32 | base | (reg << 3);
+	}
 	if (base == RSP) {
 		//add SIB byte, with no index and RSP as base
 		*(out++) = (RSP << 3) | RSP;
 	}
 	*(out++) = disp;
-	*(out++) = disp >> 8;
-	*(out++) = disp >> 16;
-	*(out++) = disp >> 24;
-	return out;
+	if (disp >= 128 || disp < -128) {
+		*(out++) = disp >> 8;
+		*(out++) = disp >> 16;
+		*(out++) = disp >> 24;
+	}
+	code->cur = out;
 }
 
-uint8_t * x86_rrind_sizedir(uint8_t * out, uint8_t opcode, uint8_t reg, uint8_t base, uint8_t size, uint8_t dir)
+void x86_rrind_sizedir(code_info *code, uint8_t opcode, uint8_t reg, uint8_t base, uint8_t size, uint8_t dir)
 {
+	check_alloc_code(code, 5);
+	code_ptr out = code->cur;
 	//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
 	uint8_t tmp;
 	if (size == SZ_W) {
@@ -313,16 +322,25 @@
 		opcode |= BIT_SIZE;
 	}
 	*(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;
+	if (base == RBP) {
+		//add a dummy 8-bit displacement since MODE_REG_INDIRECT with
+		//an R/M field of RBP selects RIP, relative addressing
+		*(out++) = MODE_REG_DISPLACE8 | base | (reg << 3);
+		*(out++) = 0;
+	} else {
+		*(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;
+	code->cur = out;
 }
 
-uint8_t * x86_rrindex_sizedir(uint8_t * out, uint8_t opcode, uint8_t reg, uint8_t base, uint8_t index, uint8_t scale, uint8_t size, uint8_t dir)
+void x86_rrindex_sizedir(code_info *code, uint8_t opcode, uint8_t reg, uint8_t base, uint8_t index, uint8_t scale, uint8_t size, uint8_t dir)
 {
+	check_alloc_code(code, 5);
+	code_ptr out = code->cur;
 	//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
 	uint8_t tmp;
 	if (size == SZ_W) {
@@ -359,18 +377,22 @@
 		opcode |= BIT_SIZE;
 	}
 	*(out++) = opcode | dir;
-	*(out++) = MODE_REG_INDIRECT | base | (RSP << 3);
-	if (base == RSP) {
-		if (scale == 4) {
-			scale = 3;
-		}
-		*(out++) = scale << 6 | (index << 3) | base;
+	*(out++) = MODE_REG_INDIRECT | RSP | (reg << 3);
+	if (scale == 4) {
+		scale = 2;
+	} else if(scale == 8) {
+		scale = 3;
+	} else {
+		scale--;
 	}
-	return out;
+	*(out++) = scale << 6 | (index << 3) | base;
+	code->cur = out;
 }
 
-uint8_t * x86_r_size(uint8_t * out, uint8_t opcode, uint8_t opex, uint8_t dst, uint8_t size)
+void x86_r_size(code_info *code, uint8_t opcode, uint8_t opex, uint8_t dst, uint8_t size)
 {
+	check_alloc_code(code, 4);
+	code_ptr out = code->cur;
 	uint8_t tmp;
 	if (size == SZ_W) {
 		*(out++) = PRE_SIZE;
@@ -399,11 +421,13 @@
 	}
 	*(out++) = opcode;
 	*(out++) = MODE_REG_DIRECT | dst | (opex << 3);
-	return out;
+	code->cur = out;
 }
 
-uint8_t * x86_rdisp8_size(uint8_t * out, uint8_t opcode, uint8_t opex, uint8_t dst, int8_t disp, uint8_t size)
+void x86_rdisp_size(code_info *code, uint8_t opcode, uint8_t opex, uint8_t dst, int32_t disp, uint8_t size)
 {
+	check_alloc_code(code, 7);
+	code_ptr out = code->cur;
 	uint8_t tmp;
 	if (size == SZ_W) {
 		*(out++) = PRE_SIZE;
@@ -423,13 +447,23 @@
 		opcode |= BIT_SIZE;
 	}
 	*(out++) = opcode;
-	*(out++) = MODE_REG_DISPLACE8 | dst | (opex << 3);
-	*(out++) = disp;
-	return out;
+	if (disp < 128 && disp >= -128) {
+		*(out++) = MODE_REG_DISPLACE8 | dst | (opex << 3);
+		*(out++) = disp;
+	} else {
+		*(out++) = MODE_REG_DISPLACE32 | dst | (opex << 3);
+		*(out++) = disp;
+		*(out++) = disp >> 8;
+		*(out++) = disp >> 16;
+		*(out++) = disp >> 24;
+	}
+	code->cur = out;
 }
 
-uint8_t * x86_ir(uint8_t * out, uint8_t opcode, uint8_t op_ex, uint8_t al_opcode, int32_t val, uint8_t dst, uint8_t size)
+void x86_ir(code_info *code, uint8_t opcode, uint8_t op_ex, uint8_t al_opcode, int32_t val, uint8_t dst, uint8_t size)
 {
+	check_alloc_code(code, 8);
+	code_ptr out = code->cur;
 	uint8_t sign_extend = 0;
 	if (opcode != OP_NOT_NEG && (size == SZ_D || size == SZ_Q) && val <= 0x7F && val >= -0x80) {
 		sign_extend = 1;
@@ -478,53 +512,13 @@
 			*(out++) = val;
 		}
 	}
-	return out;
+	code->cur = 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)
+void x86_irdisp(code_info *code, uint8_t opcode, uint8_t op_ex, int32_t val, uint8_t dst, int32_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) {
-		*out = PRE_REX;
-		if (size == SZ_Q) {
-			*out |= REX_QUAD;
-		}
-		if (dst >= R8) {
-			*out |= REX_RM_FIELD;
-			dst -= (R8 - X86_R8);
-		}
-		out++;
-	}
-	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 * x86_irdisp32(uint8_t * out, uint8_t opcode, uint8_t op_ex, int32_t val, uint8_t dst, int32_t disp, uint8_t size)
-{
+	check_alloc_code(code, 12);
+	code_ptr out = code->cur;
 	uint8_t sign_extend = 0;
 	if ((size == SZ_D || size == SZ_Q) && val <= 0x7F && val >= -0x80) {
 		sign_extend = 1;
@@ -549,14 +543,19 @@
 		opcode |= BIT_SIZE;
 	}
 	*(out++) = opcode;
-	*(out++) = MODE_REG_DISPLACE32 | dst | (op_ex << 3);
-	*(out++) = disp;
-	disp >>= 8;
-	*(out++) = disp;
-	disp >>= 8;
-	*(out++) = disp;
-	disp >>= 8;
-	*(out++) = disp;
+	if (disp < 128 && disp >= -128) {
+		*(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3);
+		*(out++) = disp;
+	} else {
+		*(out++) = MODE_REG_DISPLACE32 | dst | (op_ex << 3);
+		*(out++) = disp;
+		disp >>= 8;
+		*(out++) = disp;
+		disp >>= 8;
+		*(out++) = disp;
+		disp >>= 8;
+		*(out++) = disp;
+	}
 	*(out++) = val;
 	if (size != SZ_B && !sign_extend) {
 		val >>= 8;
@@ -568,12 +567,13 @@
 			*(out++) = val;
 		}
 	}
-	return out;
+	code->cur = out;
 }
 
-
-uint8_t * x86_shiftrot_ir(uint8_t * out, uint8_t op_ex, uint8_t val, uint8_t dst, uint8_t size)
+void x86_shiftrot_ir(code_info *code, uint8_t op_ex, uint8_t val, uint8_t dst, uint8_t size)
 {
+	check_alloc_code(code, 5);
+	code_ptr out = code->cur;
 	if (size == SZ_W) {
 		*(out++) = PRE_SIZE;
 	}
@@ -597,11 +597,13 @@
 	if (val != 1) {
 		*(out++) = val;
 	}
-	return out;
+	code->cur = out;
 }
 
-uint8_t * x86_shiftrot_irdisp8(uint8_t * out, uint8_t op_ex, uint8_t val, uint8_t dst, int8_t disp, uint8_t size)
+void x86_shiftrot_irdisp(code_info *code, uint8_t op_ex, uint8_t val, uint8_t dst, int32_t disp, uint8_t size)
 {
+	check_alloc_code(code, 9);
+	code_ptr out = code->cur;
 	if (size == SZ_W) {
 		*(out++) = PRE_SIZE;
 	}
@@ -621,16 +623,26 @@
 	}
 
 	*(out++) = (val == 1 ? OP_SHIFTROT_1: OP_SHIFTROT_IR) | (size == SZ_B ? 0 : BIT_SIZE);
-	*(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3);
-	*(out++) = disp;
+	if (disp < 128 && disp >= -128) {
+		*(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3);
+		*(out++) = disp;
+	} else {
+		*(out++) = MODE_REG_DISPLACE32 | dst | (op_ex << 3);
+		*(out++) = disp;
+		*(out++) = disp >> 8;
+		*(out++) = disp >> 16;
+		*(out++) = disp >> 24;
+	}
 	if (val != 1) {
 		*(out++) = val;
 	}
-	return out;
+	code->cur = out;
 }
 
-uint8_t * x86_shiftrot_clr(uint8_t * out, uint8_t op_ex, uint8_t dst, uint8_t size)
+void x86_shiftrot_clr(code_info *code, uint8_t op_ex, uint8_t dst, uint8_t size)
 {
+	check_alloc_code(code, 4);
+	code_ptr out = code->cur;
 	if (size == SZ_W) {
 		*(out++) = PRE_SIZE;
 	}
@@ -651,11 +663,13 @@
 
 	*(out++) = OP_SHIFTROT_CL | (size == SZ_B ? 0 : BIT_SIZE);
 	*(out++) = MODE_REG_DIRECT | dst | (op_ex << 3);
-	return out;
+	code->cur = out;
 }
 
-uint8_t * x86_shiftrot_clrdisp8(uint8_t * out, uint8_t op_ex, uint8_t dst, int8_t disp, uint8_t size)
+void x86_shiftrot_clrdisp(code_info *code, uint8_t op_ex, uint8_t dst, int32_t disp, uint8_t size)
 {
+	check_alloc_code(code, 8);
+	code_ptr out = code->cur;
 	if (size == SZ_W) {
 		*(out++) = PRE_SIZE;
 	}
@@ -675,497 +689,492 @@
 	}
 
 	*(out++) = OP_SHIFTROT_CL | (size == SZ_B ? 0 : BIT_SIZE);
-	*(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3);
-	*(out++) = disp;
-	return out;
-}
-
-uint8_t * rol_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size)
-{
-	return x86_shiftrot_ir(out, OP_EX_ROL, val, dst, size);
+	if (disp < 128 && disp >= -128) {
+		*(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3);
+		*(out++) = disp;
+	} else {
+		*(out++) = MODE_REG_DISPLACE32 | dst | (op_ex << 3);
+		*(out++) = disp;
+		*(out++) = disp >> 8;
+		*(out++) = disp >> 16;
+		*(out++) = disp >> 24;
+	}
+	code->cur = out;
 }
 
-uint8_t * ror_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size)
+void rol_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
 {
-	return x86_shiftrot_ir(out, OP_EX_ROR, val, dst, size);
+	x86_shiftrot_ir(code, OP_EX_ROL, val, dst, size);
 }
 
-uint8_t * rcl_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size)
+void ror_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
 {
-	return x86_shiftrot_ir(out, OP_EX_RCL, val, dst, size);
+	x86_shiftrot_ir(code, OP_EX_ROR, val, dst, size);
 }
 
-uint8_t * rcr_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size)
+void rcl_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
 {
-	return x86_shiftrot_ir(out, OP_EX_RCR, val, dst, size);
+	x86_shiftrot_ir(code, OP_EX_RCL, val, dst, size);
 }
 
-uint8_t * shl_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size)
+void rcr_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
 {
-	return x86_shiftrot_ir(out, OP_EX_SHL, val, dst, size);
+	x86_shiftrot_ir(code, OP_EX_RCR, val, dst, size);
 }
 
-uint8_t * shr_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size)
+void shl_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
 {
-	return x86_shiftrot_ir(out, OP_EX_SHR, val, dst, size);
+	x86_shiftrot_ir(code, OP_EX_SHL, val, dst, size);
 }
 
-uint8_t * sar_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size)
+void shr_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
 {
-	return x86_shiftrot_ir(out, OP_EX_SAR, val, dst, size);
+	x86_shiftrot_ir(code, OP_EX_SHR, val, dst, size);
 }
 
-uint8_t * rol_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+void sar_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
 {
-	return x86_shiftrot_irdisp8(out, OP_EX_ROL, val, dst_base, disp, size);
+	x86_shiftrot_ir(code, OP_EX_SAR, val, dst, size);
 }
 
-uint8_t * ror_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+void rol_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_shiftrot_irdisp8(out, OP_EX_ROR, val, dst_base, disp, size);
+	x86_shiftrot_irdisp(code, OP_EX_ROL, val, dst_base, disp, size);
 }
 
-uint8_t * rcl_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+void ror_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_shiftrot_irdisp8(out, OP_EX_RCL, val, dst_base, disp, size);
+	x86_shiftrot_irdisp(code, OP_EX_ROR, val, dst_base, disp, size);
 }
 
-uint8_t * rcr_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+void rcl_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_shiftrot_irdisp8(out, OP_EX_RCR, val, dst_base, disp, size);
+	x86_shiftrot_irdisp(code, OP_EX_RCL, val, dst_base, disp, size);
 }
 
-uint8_t * shl_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+void rcr_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_shiftrot_irdisp8(out, OP_EX_SHL, val, dst_base, disp, size);
+	x86_shiftrot_irdisp(code, OP_EX_RCR, val, dst_base, disp, size);
 }
 
-uint8_t * shr_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+void shl_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_shiftrot_irdisp8(out, OP_EX_SHR, val, dst_base, disp, size);
+	x86_shiftrot_irdisp(code, OP_EX_SHL, val, dst_base, disp, size);
 }
 
-uint8_t * sar_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+void shr_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_shiftrot_irdisp8(out, OP_EX_SAR, val, dst_base, disp, size);
+	x86_shiftrot_irdisp(code, OP_EX_SHR, val, dst_base, disp, size);
 }
 
-uint8_t * rol_clr(uint8_t * out, uint8_t dst, uint8_t size)
+void sar_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_shiftrot_clr(out, OP_EX_ROL, dst, size);
-}
-
-uint8_t * ror_clr(uint8_t * out, uint8_t dst, uint8_t size)
-{
-	return x86_shiftrot_clr(out, OP_EX_ROR, dst, size);
+	x86_shiftrot_irdisp(code, OP_EX_SAR, val, dst_base, disp, size);
 }
 
-uint8_t * rcl_clr(uint8_t * out, uint8_t dst, uint8_t size)
+void rol_clr(code_info *code, uint8_t dst, uint8_t size)
 {
-	return x86_shiftrot_clr(out, OP_EX_RCL, dst, size);
+	x86_shiftrot_clr(code, OP_EX_ROL, dst, size);
 }
 
-uint8_t * rcr_clr(uint8_t * out, uint8_t dst, uint8_t size)
+void ror_clr(code_info *code, uint8_t dst, uint8_t size)
 {
-	return x86_shiftrot_clr(out, OP_EX_RCR, dst, size);
+	x86_shiftrot_clr(code, OP_EX_ROR, dst, size);
 }
 
-uint8_t * shl_clr(uint8_t * out, uint8_t dst, uint8_t size)
+void rcl_clr(code_info *code, uint8_t dst, uint8_t size)
 {
-	return x86_shiftrot_clr(out, OP_EX_SHL, dst, size);
+	x86_shiftrot_clr(code, OP_EX_RCL, dst, size);
 }
 
-uint8_t * shr_clr(uint8_t * out, uint8_t dst, uint8_t size)
+void rcr_clr(code_info *code, uint8_t dst, uint8_t size)
 {
-	return x86_shiftrot_clr(out, OP_EX_SHR, dst, size);
+	x86_shiftrot_clr(code, OP_EX_RCR, dst, size);
 }
 
-uint8_t * sar_clr(uint8_t * out, uint8_t dst, uint8_t size)
+void shl_clr(code_info *code, uint8_t dst, uint8_t size)
 {
-	return x86_shiftrot_clr(out, OP_EX_SAR, dst, size);
+	x86_shiftrot_clr(code, OP_EX_SHL, dst, size);
 }
 
-uint8_t * rol_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size)
+void shr_clr(code_info *code, uint8_t dst, uint8_t size)
 {
-	return x86_shiftrot_clrdisp8(out, OP_EX_ROL, dst_base, disp, size);
+	x86_shiftrot_clr(code, OP_EX_SHR, dst, size);
 }
 
-uint8_t * ror_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size)
+void sar_clr(code_info *code, uint8_t dst, uint8_t size)
 {
-	return x86_shiftrot_clrdisp8(out, OP_EX_ROR, dst_base, disp, size);
+	x86_shiftrot_clr(code, OP_EX_SAR, dst, size);
 }
 
-uint8_t * rcl_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size)
+void rol_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_shiftrot_clrdisp8(out, OP_EX_RCL, dst_base, disp, size);
+	x86_shiftrot_clrdisp(code, OP_EX_ROL, dst_base, disp, size);
 }
 
-uint8_t * rcr_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size)
+void ror_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_shiftrot_clrdisp8(out, OP_EX_RCR, dst_base, disp, size);
+	x86_shiftrot_clrdisp(code, OP_EX_ROR, dst_base, disp, size);
 }
 
-uint8_t * shl_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size)
+void rcl_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_shiftrot_clrdisp8(out, OP_EX_SHL, dst_base, disp, size);
+	x86_shiftrot_clrdisp(code, OP_EX_RCL, dst_base, disp, size);
 }
 
-uint8_t * shr_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size)
+void rcr_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_shiftrot_clrdisp8(out, OP_EX_SHR, dst_base, disp, size);
+	x86_shiftrot_clrdisp(code, OP_EX_RCR, dst_base, disp, size);
 }
 
-uint8_t * sar_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size)
+void shl_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_shiftrot_clrdisp8(out, OP_EX_SAR, dst_base, disp, size);
+	x86_shiftrot_clrdisp(code, OP_EX_SHL, dst_base, disp, size);
 }
 
-uint8_t * add_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
+void shr_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rr_sizedir(out, OP_ADD, src, dst, size);
+	x86_shiftrot_clrdisp(code, OP_EX_SHR, dst_base, disp, size);
 }
 
-uint8_t * add_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
+void sar_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_ir(out, OP_IMMED_ARITH, OP_EX_ADDI, OP_ADD, val, dst, size);
+	x86_shiftrot_clrdisp(code, OP_EX_SAR, dst_base, disp, size);
 }
 
-uint8_t * add_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+void add_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
 {
-	return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_ADDI, val, dst_base, disp, size);
+	x86_rr_sizedir(code, OP_ADD, src, dst, size);
 }
 
-uint8_t * add_irdisp32(uint8_t * out, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
+void add_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
 {
-	return x86_irdisp32(out, OP_IMMED_ARITH, OP_EX_ADDI, val, dst_base, disp, size);
+	x86_ir(code, OP_IMMED_ARITH, OP_EX_ADDI, OP_ADD, val, dst, size);
 }
 
-uint8_t * add_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
+void add_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rrdisp8_sizedir(out, OP_ADD, src, dst_base, disp, size, 0);
+	x86_irdisp(code, OP_IMMED_ARITH, OP_EX_ADDI, val, dst_base, disp, size);
 }
 
-uint8_t * add_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
+void add_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rrdisp8_sizedir(out, OP_ADD, dst, src_base, disp, size, BIT_DIR);
+	x86_rrdisp_sizedir(code, OP_ADD, src, dst_base, disp, size, 0);
 }
 
-uint8_t * adc_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
+void add_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
 {
-	return x86_rr_sizedir(out, OP_ADC, src, dst, size);
+	x86_rrdisp_sizedir(code, OP_ADD, dst, src_base, disp, size, BIT_DIR);
 }
 
-uint8_t * adc_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
+void adc_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
 {
-	return x86_ir(out, OP_IMMED_ARITH, OP_EX_ADCI, OP_ADC, val, dst, size);
+	x86_rr_sizedir(code, OP_ADC, src, dst, size);
 }
 
-uint8_t * adc_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+void adc_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
 {
-	return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_ADCI, val, dst_base, disp, size);
+	x86_ir(code, OP_IMMED_ARITH, OP_EX_ADCI, OP_ADC, val, dst, size);
 }
 
-uint8_t * adc_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
+void adc_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rrdisp8_sizedir(out, OP_ADC, src, dst_base, disp, size, 0);
+	x86_irdisp(code, OP_IMMED_ARITH, OP_EX_ADCI, val, dst_base, disp, size);
 }
 
-uint8_t * adc_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
+void adc_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rrdisp8_sizedir(out, OP_ADC, dst, src_base, disp, size, BIT_DIR);
+	x86_rrdisp_sizedir(code, OP_ADC, src, dst_base, disp, size, 0);
 }
 
-uint8_t * or_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
+void adc_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
 {
-	return x86_rr_sizedir(out, OP_OR, src, dst, size);
-}
-uint8_t * or_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
-{
-	return x86_ir(out, OP_IMMED_ARITH, OP_EX_ORI, OP_OR, val, dst, size);
+	x86_rrdisp_sizedir(code, OP_ADC, dst, src_base, disp, size, BIT_DIR);
 }
 
-uint8_t * or_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+void or_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
 {
-	return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_ORI, val, dst_base, disp, size);
+	x86_rr_sizedir(code, OP_OR, src, dst, size);
+}
+void or_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
+{
+	x86_ir(code, OP_IMMED_ARITH, OP_EX_ORI, OP_OR, val, dst, size);
 }
 
-uint8_t * or_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
+void or_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rrdisp8_sizedir(out, OP_OR, src, dst_base, disp, size, 0);
+	x86_irdisp(code, OP_IMMED_ARITH, OP_EX_ORI, val, dst_base, disp, size);
 }
 
-uint8_t * or_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
+void or_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rrdisp8_sizedir(out, OP_OR, dst, src_base, disp, size, BIT_DIR);
+	x86_rrdisp_sizedir(code, OP_OR, src, dst_base, disp, size, 0);
 }
 
-uint8_t * and_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
+void or_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
 {
-	return x86_rr_sizedir(out, OP_AND, src, dst, size);
+	x86_rrdisp_sizedir(code, OP_OR, dst, src_base, disp, size, BIT_DIR);
 }
 
-uint8_t * and_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
+void and_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
 {
-	return x86_ir(out, OP_IMMED_ARITH, OP_EX_ANDI, OP_AND, val, dst, size);
+	x86_rr_sizedir(code, OP_AND, src, dst, size);
 }
 
-uint8_t * and_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+void and_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
 {
-	return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_ANDI, val, dst_base, disp, size);
+	x86_ir(code, OP_IMMED_ARITH, OP_EX_ANDI, OP_AND, val, dst, size);
 }
 
-uint8_t * and_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
+void and_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rrdisp8_sizedir(out, OP_AND, src, dst_base, disp, size, 0);
+	x86_irdisp(code, OP_IMMED_ARITH, OP_EX_ANDI, val, dst_base, disp, size);
 }
 
-uint8_t * and_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
+void and_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rrdisp8_sizedir(out, OP_AND, dst, src_base, disp, size, BIT_DIR);
+	x86_rrdisp_sizedir(code, OP_AND, src, dst_base, disp, size, 0);
 }
 
-uint8_t * xor_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
+void and_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
 {
-	return x86_rr_sizedir(out, OP_XOR, src, dst, size);
+	x86_rrdisp_sizedir(code, OP_AND, dst, src_base, disp, size, BIT_DIR);
 }
 
-uint8_t * xor_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
+void xor_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
 {
-	return x86_ir(out, OP_IMMED_ARITH, OP_EX_XORI, OP_XOR, val, dst, size);
+	x86_rr_sizedir(code, OP_XOR, src, dst, size);
 }
 
-uint8_t * xor_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+void xor_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
 {
-	return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_XORI, val, dst_base, disp, size);
+	x86_ir(code, OP_IMMED_ARITH, OP_EX_XORI, OP_XOR, val, dst, size);
 }
 
-uint8_t * xor_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
+void xor_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rrdisp8_sizedir(out, OP_XOR, src, dst_base, disp, size, 0);
+	x86_irdisp(code, OP_IMMED_ARITH, OP_EX_XORI, val, dst_base, disp, size);
 }
 
-uint8_t * xor_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
+void xor_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rrdisp8_sizedir(out, OP_XOR, dst, src_base, disp, size, BIT_DIR);
+	x86_rrdisp_sizedir(code, OP_XOR, src, dst_base, disp, size, 0);
 }
 
-uint8_t * sub_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
+void xor_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
 {
-	return x86_rr_sizedir(out, OP_SUB, src, dst, size);
+	x86_rrdisp_sizedir(code, OP_XOR, dst, src_base, disp, size, BIT_DIR);
 }
 
-uint8_t * sub_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
+void sub_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
 {
-	return x86_ir(out, OP_IMMED_ARITH, OP_EX_SUBI, OP_SUB, val, dst, size);
+	x86_rr_sizedir(code, OP_SUB, src, dst, size);
 }
 
-uint8_t * sub_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+void sub_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
 {
-	return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_SUBI, val, dst_base, disp, size);
+	x86_ir(code, OP_IMMED_ARITH, OP_EX_SUBI, OP_SUB, val, dst, size);
 }
 
-uint8_t * sub_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
+void sub_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rrdisp8_sizedir(out, OP_SUB, src, dst_base, disp, size, 0);
+	x86_irdisp(code, OP_IMMED_ARITH, OP_EX_SUBI, val, dst_base, disp, size);
 }
 
-uint8_t * sub_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
+void sub_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rrdisp8_sizedir(out, OP_SUB, dst, src_base, disp, size, BIT_DIR);
+	x86_rrdisp_sizedir(code, OP_SUB, src, dst_base, disp, size, 0);
 }
 
-uint8_t * sbb_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
+void sub_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
 {
-	return x86_rr_sizedir(out, OP_SBB, src, dst, size);
+	x86_rrdisp_sizedir(code, OP_SUB, dst, src_base, disp, size, BIT_DIR);
 }
 
-uint8_t * sbb_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
+void sbb_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
 {
-	return x86_ir(out, OP_IMMED_ARITH, OP_EX_SBBI, OP_SBB, val, dst, size);
+	x86_rr_sizedir(code, OP_SBB, src, dst, size);
 }
 
-uint8_t * sbb_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+void sbb_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
 {
-	return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_SBBI, val, dst_base, disp, size);
+	x86_ir(code, OP_IMMED_ARITH, OP_EX_SBBI, OP_SBB, val, dst, size);
 }
 
-uint8_t * sbb_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
+void sbb_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rrdisp8_sizedir(out, OP_SBB, src, dst_base, disp, size, 0);
+	x86_irdisp(code, OP_IMMED_ARITH, OP_EX_SBBI, val, dst_base, disp, size);
 }
 
-uint8_t * sbb_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
+void sbb_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rrdisp8_sizedir(out, OP_SBB, dst, src_base, disp, size, BIT_DIR);
+	x86_rrdisp_sizedir(code, OP_SBB, src, dst_base, disp, size, 0);
 }
 
-uint8_t * cmp_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
+void sbb_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
 {
-	return x86_rr_sizedir(out, OP_CMP, src, dst, size);
+	x86_rrdisp_sizedir(code, OP_SBB, dst, src_base, disp, size, BIT_DIR);
 }
 
-uint8_t * cmp_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
+void cmp_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
 {
-	return x86_ir(out, OP_IMMED_ARITH, OP_EX_CMPI, OP_CMP, val, dst, size);
+	x86_rr_sizedir(code, OP_CMP, src, dst, size);
 }
 
-uint8_t * cmp_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+void cmp_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
 {
-	return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_CMPI, val, dst_base, disp, size);
+	x86_ir(code, OP_IMMED_ARITH, OP_EX_CMPI, OP_CMP, val, dst, size);
 }
 
-uint8_t * cmp_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
+void cmp_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rrdisp8_sizedir(out, OP_CMP, src, dst_base, disp, size, 0);
+	x86_irdisp(code, OP_IMMED_ARITH, OP_EX_CMPI, val, dst_base, disp, size);
 }
 
-uint8_t * cmp_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
+void cmp_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rrdisp8_sizedir(out, OP_CMP, dst, src_base, disp, size, BIT_DIR);
+	x86_rrdisp_sizedir(code, OP_CMP, src, dst_base, disp, size, 0);
 }
 
-uint8_t * test_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
+void cmp_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
 {
-	return x86_rr_sizedir(out, OP_TEST, src, dst, size);
+	x86_rrdisp_sizedir(code, OP_CMP, dst, src_base, disp, size, BIT_DIR);
 }
 
-uint8_t * test_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
+void test_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
 {
-	return x86_ir(out, OP_NOT_NEG, OP_EX_TEST_I, OP_TEST, val, dst, size);
+	x86_rr_sizedir(code, OP_TEST, src, dst, size);
 }
 
-uint8_t * test_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+void test_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
 {
-	return x86_irdisp8(out, OP_NOT_NEG, OP_EX_TEST_I, val, dst_base, disp, size);
+	x86_ir(code, OP_NOT_NEG, OP_EX_TEST_I, OP_TEST, val, dst, size);
 }
 
-uint8_t * test_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
+void test_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rrdisp8_sizedir(out, OP_TEST, src, dst_base, disp, size, 0);
+	x86_irdisp(code, OP_NOT_NEG, OP_EX_TEST_I, val, dst_base, disp, size);
 }
 
-uint8_t * test_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
+void test_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rrdisp8_sizedir(out, OP_TEST, dst, src_base, disp, size, BIT_DIR);
+	x86_rrdisp_sizedir(code, OP_TEST, src, dst_base, disp, size, 0);
 }
 
-uint8_t * imul_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
+void test_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
 {
-	return x86_rr_sizedir(out, OP2_IMUL | (PRE_2BYTE << 8), dst, src, size);
+	x86_rrdisp_sizedir(code, OP_TEST, dst, src_base, disp, size, BIT_DIR);
 }
 
-uint8_t * imul_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
+void imul_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
 {
-	return x86_rrdisp8_sizedir(out, OP2_IMUL | (PRE_2BYTE << 8), dst, src_base, disp, size, 0);
+	x86_rr_sizedir(code, OP2_IMUL | (PRE_2BYTE << 8), dst, src, size);
 }
 
-uint8_t * not_r(uint8_t * out, uint8_t dst, uint8_t size)
+void imul_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
 {
-	return x86_r_size(out, OP_NOT_NEG, OP_EX_NOT, dst, size);
+	x86_rrdisp_sizedir(code, OP2_IMUL | (PRE_2BYTE << 8), dst, src_base, disp, size, 0);
 }
 
-uint8_t * neg_r(uint8_t * out, uint8_t dst, uint8_t size)
+void not_r(code_info *code, uint8_t dst, uint8_t size)
 {
-	return x86_r_size(out, OP_NOT_NEG, OP_EX_NEG, dst, size);
+	x86_r_size(code, OP_NOT_NEG, OP_EX_NOT, dst, size);
 }
 
-uint8_t * not_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size)
+void neg_r(code_info *code, uint8_t dst, uint8_t size)
 {
-	return x86_rdisp8_size(out, OP_NOT_NEG, OP_EX_NOT, dst_base, disp, size);
+	x86_r_size(code, OP_NOT_NEG, OP_EX_NEG, dst, size);
 }
 
-uint8_t * neg_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size)
+void not_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rdisp8_size(out, OP_NOT_NEG, OP_EX_NEG, dst_base, disp, size);
+	x86_rdisp_size(code, OP_NOT_NEG, OP_EX_NOT, dst_base, disp, size);
 }
 
-uint8_t * mul_r(uint8_t * out, uint8_t dst, uint8_t size)
+void neg_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_r_size(out, OP_NOT_NEG, OP_EX_MUL, dst, size);
+	x86_rdisp_size(code, OP_NOT_NEG, OP_EX_NEG, dst_base, disp, size);
 }
 
-uint8_t * imul_r(uint8_t * out, uint8_t dst, uint8_t size)
+void mul_r(code_info *code, uint8_t dst, uint8_t size)
 {
-	return x86_r_size(out, OP_NOT_NEG, OP_EX_IMUL, dst, size);
+	x86_r_size(code, OP_NOT_NEG, OP_EX_MUL, dst, size);
 }
 
-uint8_t * div_r(uint8_t * out, uint8_t dst, uint8_t size)
+void imul_r(code_info *code, uint8_t dst, uint8_t size)
 {
-	return x86_r_size(out, OP_NOT_NEG, OP_EX_DIV, dst, size);
+	x86_r_size(code, OP_NOT_NEG, OP_EX_IMUL, dst, size);
 }
 
-uint8_t * idiv_r(uint8_t * out, uint8_t dst, uint8_t size)
+void div_r(code_info *code, uint8_t dst, uint8_t size)
 {
-	return x86_r_size(out, OP_NOT_NEG, OP_EX_IDIV, dst, size);
+	x86_r_size(code, OP_NOT_NEG, OP_EX_DIV, dst, size);
 }
 
-uint8_t * mul_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size)
+void idiv_r(code_info *code, uint8_t dst, uint8_t size)
 {
-	return x86_rdisp8_size(out, OP_NOT_NEG, OP_EX_MUL, dst_base, disp, size);
+	x86_r_size(code, OP_NOT_NEG, OP_EX_IDIV, dst, size);
 }
 
-uint8_t * imul_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size)
+void mul_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rdisp8_size(out, OP_NOT_NEG, OP_EX_IMUL, dst_base, disp, size);
+	x86_rdisp_size(code, OP_NOT_NEG, OP_EX_MUL, dst_base, disp, size);
 }
 
-uint8_t * div_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size)
+void imul_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rdisp8_size(out, OP_NOT_NEG, OP_EX_DIV, dst_base, disp, size);
+	x86_rdisp_size(code, OP_NOT_NEG, OP_EX_IMUL, dst_base, disp, size);
 }
 
-uint8_t * idiv_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size)
+void div_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rdisp8_size(out, OP_NOT_NEG, OP_EX_IDIV, dst_base, disp, size);
+	x86_rdisp_size(code, OP_NOT_NEG, OP_EX_DIV, dst_base, disp, size);
 }
 
-uint8_t * mov_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
+void idiv_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rr_sizedir(out, OP_MOV, src, dst, size);
+	x86_rdisp_size(code, OP_NOT_NEG, OP_EX_IDIV, dst_base, disp, size);
 }
 
-uint8_t * mov_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
+void mov_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
 {
-	return x86_rrdisp8_sizedir(out, OP_MOV, src, dst_base, disp, size, 0);
+	x86_rr_sizedir(code, OP_MOV, src, dst, size);
 }
 
-uint8_t * mov_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
+void mov_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
 {
-	return x86_rrdisp8_sizedir(out, OP_MOV, dst, src_base, disp, size, BIT_DIR);
+	x86_rrdisp_sizedir(code, OP_MOV, src, dst_base, disp, size, 0);
 }
 
-uint8_t * mov_rrdisp32(uint8_t * out, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
+void mov_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
 {
-	return x86_rrdisp32_sizedir(out, OP_MOV, src, dst_base, disp, size, 0);
+	x86_rrdisp_sizedir(code, OP_MOV, dst, src_base, disp, size, BIT_DIR);
 }
 
-uint8_t * mov_rdisp32r(uint8_t * out, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
+void mov_rrind(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
 {
-	return x86_rrdisp32_sizedir(out, OP_MOV, dst, src_base, disp, size, BIT_DIR);
+	x86_rrind_sizedir(code, OP_MOV, src, dst, size, 0);
 }
 
-uint8_t * mov_rrind(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
+void mov_rindr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
 {
-	return x86_rrind_sizedir(out, OP_MOV, src, dst, size, 0);
+	x86_rrind_sizedir(code, OP_MOV, dst, src, size, BIT_DIR);
 }
 
-uint8_t * mov_rindr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
+void mov_rrindex(code_info *code, uint8_t src, uint8_t dst_base, uint8_t dst_index, uint8_t scale, uint8_t size)
 {
-	return x86_rrind_sizedir(out, OP_MOV, dst, src, size, BIT_DIR);
+	x86_rrindex_sizedir(code, OP_MOV, src, dst_base, dst_index, scale, size, 0);
 }
 
-uint8_t * mov_rrindex(uint8_t * out, uint8_t src, uint8_t dst_base, uint8_t dst_index, uint8_t scale, uint8_t size)
+void mov_rindexr(code_info *code, uint8_t src_base, uint8_t src_index, uint8_t scale, uint8_t dst, uint8_t size)
 {
-	return x86_rrindex_sizedir(out, OP_MOV, src, dst_base, dst_index, scale, size, 0);
+	x86_rrindex_sizedir(code, OP_MOV, dst, src_base, src_index, scale, size, BIT_DIR);
 }
 
-uint8_t * mov_rindexr(uint8_t * out, uint8_t src_base, uint8_t src_index, uint8_t scale, uint8_t dst, uint8_t size)
+void mov_ir(code_info *code, int64_t val, uint8_t dst, uint8_t size)
 {
-	return x86_rrindex_sizedir(out, OP_MOV, dst, src_base, src_index, scale, size, BIT_DIR);
-}
-
-uint8_t * mov_ir(uint8_t * out, int64_t val, uint8_t dst, uint8_t size)
-{
+	check_alloc_code(code, 14);
+	code_ptr out = code->cur;
 	uint8_t sign_extend = 0;
 	if (size == SZ_Q && val <= 0x7FFFFFFF && val >= -2147483648) {
 		sign_extend = 1;
@@ -1216,11 +1225,13 @@
 			}
 		}
 	}
-	return out;
+	code->cur = out;
 }
 
-uint8_t * mov_irdisp8(uint8_t * out, int32_t val, uint8_t dst, int8_t disp, uint8_t size)
+void mov_irdisp(code_info *code, int32_t val, uint8_t dst, int32_t disp, uint8_t size)
 {
+	check_alloc_code(code, 12);
+	code_ptr out = code->cur;
 	if (size == SZ_W) {
 		*(out++) = PRE_SIZE;
 	}
@@ -1239,8 +1250,16 @@
 		dst -= (AH-X86_AH);
 	}
 	*(out++) = OP_MOV_IEA | (size == SZ_B ? 0 : BIT_SIZE);
-	*(out++) = MODE_REG_DISPLACE8 | dst;
-	*(out++) = disp;
+	if (disp < 128 && disp >= -128) {
+		*(out++) = MODE_REG_DISPLACE8 | dst;
+		*(out++) = disp;
+	} else {
+		*(out++) = MODE_REG_DISPLACE32 | dst;
+		*(out++) = disp;
+		*(out++) = disp >> 8;
+		*(out++) = disp >> 16;
+		*(out++) = disp >> 24;
+	}
 
 	*(out++) = val;
 	if (size != SZ_B) {
@@ -1253,11 +1272,13 @@
 			*(out++) = val;
 		}
 	}
-	return out;
+	code->cur = out;
 }
 
-uint8_t * mov_irind(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
+void mov_irind(code_info *code, int32_t val, uint8_t dst, uint8_t size)
 {
+	check_alloc_code(code, 8);
+	code_ptr out = code->cur;
 	if (size == SZ_W) {
 		*(out++) = PRE_SIZE;
 	}
@@ -1289,11 +1310,13 @@
 			*(out++) = val;
 		}
 	}
-	return out;
+	code->cur = out;
 }
 
-uint8_t * movsx_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t src_size, uint8_t size)
+void movsx_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t src_size, uint8_t size)
 {
+	check_alloc_code(code, 5);
+	code_ptr out = code->cur;
 	if (size == SZ_W) {
 		*(out++) = PRE_SIZE;
 	}
@@ -1319,11 +1342,13 @@
 		*(out++) = OP2_MOVSX | (src_size == SZ_B ? 0 : BIT_SIZE);
 	}
 	*(out++) = MODE_REG_DIRECT | src | (dst << 3);
-	return out;
+	code->cur = out;
 }
 
-uint8_t * movsx_rdisp8r(uint8_t * out, uint8_t src, int8_t disp, uint8_t dst, uint8_t src_size, uint8_t size)
+void movsx_rdispr(code_info *code, uint8_t src, int32_t disp, uint8_t dst, uint8_t src_size, uint8_t size)
 {
+	check_alloc_code(code, 12);
+	code_ptr out = code->cur;
 	if (size == SZ_W) {
 		*(out++) = PRE_SIZE;
 	}
@@ -1348,13 +1373,23 @@
 		*(out++) = PRE_2BYTE;
 		*(out++) = OP2_MOVSX | (src_size == SZ_B ? 0 : BIT_SIZE);
 	}
-	*(out++) = MODE_REG_DISPLACE8 | src | (dst << 3);
-	*(out++) = disp;
-	return out;
+	if (disp < 128 && disp >= -128) {
+		*(out++) = MODE_REG_DISPLACE8 | src | (dst << 3);
+		*(out++) = disp;
+	} else {
+		*(out++) = MODE_REG_DISPLACE32 | src | (dst << 3);
+		*(out++) = disp;
+		*(out++) = disp >> 8;
+		*(out++) = disp >> 16;
+		*(out++) = disp >> 24;
+	}
+	code->cur = out;
 }
 
-uint8_t * movzx_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t src_size, uint8_t size)
+void movzx_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t src_size, uint8_t size)
 {
+	check_alloc_code(code, 5);
+	code_ptr out = code->cur;
 	if (size == SZ_W) {
 		*(out++) = PRE_SIZE;
 	}
@@ -1376,11 +1411,13 @@
 	*(out++) = PRE_2BYTE;
 	*(out++) = OP2_MOVZX | (src_size == SZ_B ? 0 : BIT_SIZE);
 	*(out++) = MODE_REG_DIRECT | src | (dst << 3);
-	return out;
+	code->cur = out;
 }
 
-uint8_t * movzx_rdisp8r(uint8_t * out, uint8_t src, int8_t disp, uint8_t dst, uint8_t src_size, uint8_t size)
+void movzx_rdispr(code_info *code, uint8_t src, int32_t disp, uint8_t dst, uint8_t src_size, uint8_t size)
 {
+	check_alloc_code(code, 9);
+	code_ptr out = code->cur;
 	if (size == SZ_W) {
 		*(out++) = PRE_SIZE;
 	}
@@ -1401,13 +1438,23 @@
 	}
 	*(out++) = PRE_2BYTE;
 	*(out++) = OP2_MOVZX | (src_size == SZ_B ? 0 : BIT_SIZE);
-	*(out++) = MODE_REG_DISPLACE8 | src | (dst << 3);
-	*(out++) = disp;
-	return out;
+	if (disp < 128 && disp >= -128) {
+		*(out++) = MODE_REG_DISPLACE8 | src | (dst << 3);
+		*(out++) = disp;
+	} else {
+		*(out++) = MODE_REG_DISPLACE32 | src | (dst << 3);
+		*(out++) = disp;
+		*(out++) = disp >> 8;
+		*(out++) = disp >> 16;
+		*(out++) = disp >> 24;
+	}
+	code->cur = out;
 }
 
-uint8_t * xchg_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
+void xchg_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
 {
+	check_alloc_code(code, 4);
+	code_ptr out = code->cur;
 	//TODO: Use OP_XCHG_AX when one of the registers is AX, EAX or RAX
 	uint8_t tmp;
 	if (size == SZ_W) {
@@ -1446,43 +1493,73 @@
 	}
 	*(out++) = opcode;
 	*(out++) = MODE_REG_DIRECT | dst | (src << 3);
-	return out;
+	code->cur = out;
 }
 
-uint8_t * pushf(uint8_t * out)
+void pushf(code_info *code)
 {
+	check_alloc_code(code, 1);
+	code_ptr out = code->cur;
 	*(out++) = OP_PUSHF;
-	return out;
+	code->cur = out;
 }
 
-uint8_t * popf(uint8_t * out)
+void popf(code_info *code)
 {
+	check_alloc_code(code, 1);
+	code_ptr out = code->cur;
 	*(out++) = OP_POPF;
-	return out;
+	code->cur = out;
 }
 
-uint8_t * push_r(uint8_t * out, uint8_t reg)
+void push_r(code_info *code, uint8_t reg)
 {
+	check_alloc_code(code, 2);
+	code_ptr out = code->cur;
 	if (reg >= R8) {
 		*(out++) = PRE_REX | REX_RM_FIELD;
 		reg -= R8 - X86_R8;
 	}
 	*(out++) = OP_PUSH | reg;
-	return out;
+	code->cur = out;
 }
 
-uint8_t * pop_r(uint8_t * out, uint8_t reg)
+void push_rdisp(code_info *code, uint8_t base, int32_t disp)
 {
+	//This instruction has no explicit size, so we pass SZ_B
+	//to avoid any prefixes or bits being set
+	x86_rdisp_size(code, OP_SINGLE_EA, OP_EX_PUSH_EA, base, disp, SZ_B);
+}
+
+void pop_r(code_info *code, uint8_t reg)
+{
+	check_alloc_code(code, 2);
+	code_ptr out = code->cur;
 	if (reg >= R8) {
 		*(out++) = PRE_REX | REX_RM_FIELD;
 		reg -= R8 - X86_R8;
 	}
 	*(out++) = OP_POP | reg;
-	return out;
+	code->cur = out;
 }
 
-uint8_t * setcc_r(uint8_t * out, uint8_t cc, uint8_t dst)
+void pop_rind(code_info *code, uint8_t reg)
 {
+	check_alloc_code(code, 3);
+	code_ptr out = code->cur;
+	if (reg >= R8) {
+		*(out++) = PRE_REX | REX_RM_FIELD;
+		reg -= R8 - X86_R8;
+	}
+	*(out++) = PRE_XOP;
+	*(out++) = MODE_REG_INDIRECT | reg;
+	code->cur = out;
+}
+
+void setcc_r(code_info *code, uint8_t cc, uint8_t dst)
+{
+	check_alloc_code(code, 4);
+	code_ptr out = code->cur;
 	if (dst >= R8) {
 		*(out++) = PRE_REX | REX_RM_FIELD;
 		dst -= R8 - X86_R8;
@@ -1494,11 +1571,13 @@
 	*(out++) = PRE_2BYTE;
 	*(out++) = OP2_SETCC | cc;
 	*(out++) = MODE_REG_DIRECT | dst;
-	return out;
+	code->cur = out;
 }
 
-uint8_t * setcc_rind(uint8_t * out, uint8_t cc, uint8_t dst)
+void setcc_rind(code_info *code, uint8_t cc, uint8_t dst)
 {
+	check_alloc_code(code, 4);
+	code_ptr out = code->cur;
 	if (dst >= R8) {
 		*(out++) = PRE_REX | REX_RM_FIELD;
 		dst -= R8 - X86_R8;
@@ -1506,24 +1585,36 @@
 	*(out++) = PRE_2BYTE;
 	*(out++) = OP2_SETCC | cc;
 	*(out++) = MODE_REG_INDIRECT | dst;
-	return out;
+	code->cur = out;
 }
 
-uint8_t * setcc_rdisp8(uint8_t * out, uint8_t cc, uint8_t dst, int8_t disp)
+void setcc_rdisp(code_info *code, uint8_t cc, uint8_t dst, int32_t disp)
 {
+	check_alloc_code(code, 8);
+	code_ptr out = code->cur;
 	if (dst >= R8) {
 		*(out++) = PRE_REX | REX_RM_FIELD;
 		dst -= R8 - X86_R8;
 	}
 	*(out++) = PRE_2BYTE;
 	*(out++) = OP2_SETCC | cc;
-	*(out++) = MODE_REG_DISPLACE8 | dst;
-	*(out++) = disp;
-	return out;
+	if (disp < 128 && disp >= -128) {
+		*(out++) = MODE_REG_DISPLACE8 | dst;
+		*(out++) = disp;
+	} else {
+		*(out++) = MODE_REG_DISPLACE32 | dst;
+		*(out++) = disp;
+		*(out++) = disp >> 8;
+		*(out++) = disp >> 16;
+		*(out++) = disp >> 24;
+	}
+	code->cur = out;
 }
 
-uint8_t * bit_rr(uint8_t * out, uint8_t op2, uint8_t src, uint8_t dst, uint8_t size)
+void bit_rr(code_info *code, uint8_t op2, uint8_t src, uint8_t dst, uint8_t size)
 {
+	check_alloc_code(code, 5);
+	code_ptr out = code->cur;
 	if (size == SZ_W) {
 		*(out++) = PRE_SIZE;
 	}
@@ -1545,38 +1636,13 @@
 	*(out++) = PRE_2BYTE;
 	*(out++) = op2;
 	*(out++) = MODE_REG_DIRECT | dst | (src << 3);
-	return out;
+	code->cur = out;
 }
 
-uint8_t * bit_rrdisp8(uint8_t * out, uint8_t op2, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size)
+void bit_rrdisp(code_info *code, uint8_t op2, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size)
 {
-	if (size == SZ_W) {
-		*(out++) = PRE_SIZE;
-	}
-	if (size == SZ_Q || src >= R8 || dst_base >= R8) {
-		*out = PRE_REX;
-		if (size == SZ_Q) {
-			*out |= REX_QUAD;
-		}
-		if (src >= R8) {
-			*out |= REX_REG_FIELD;
-			src -= (R8 - X86_R8);
-		}
-		if (dst_base >= R8) {
-			*out |= REX_RM_FIELD;
-			dst_base -= (R8 - X86_R8);
-		}
-		out++;
-	}
-	*(out++) = PRE_2BYTE;
-	*(out++) = op2;
-	*(out++) = MODE_REG_DISPLACE8 | dst_base | (src << 3);
-	*(out++) = dst_disp;
-	return out;
-}
-
-uint8_t * bit_rrdisp32(uint8_t * out, uint8_t op2, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size)
-{
+	check_alloc_code(code, 9);
+	code_ptr out = code->cur;
 	if (size == SZ_W) {
 		*(out++) = PRE_SIZE;
 	}
@@ -1597,16 +1663,23 @@
 	}
 	*(out++) = PRE_2BYTE;
 	*(out++) = op2;
-	*(out++) = MODE_REG_DISPLACE32 | dst_base | (src << 3);
-	*(out++) = dst_disp;
-	*(out++) = dst_disp >> 8;
-	*(out++) = dst_disp >> 16;
-	*(out++) = dst_disp >> 24;
-	return out;
+	if (dst_disp < 128 && dst_disp >= -128) {
+		*(out++) = MODE_REG_DISPLACE8 | dst_base | (src << 3);
+		*(out++) = dst_disp;
+	} else {
+		*(out++) = MODE_REG_DISPLACE32 | dst_base | (src << 3);
+		*(out++) = dst_disp;
+		*(out++) = dst_disp >> 8;
+		*(out++) = dst_disp >> 16;
+		*(out++) = dst_disp >> 24;
+	}
+	code->cur = out;
 }
 
-uint8_t * bit_ir(uint8_t * out, uint8_t op_ex, uint8_t val, uint8_t dst, uint8_t size)
+void bit_ir(code_info *code, uint8_t op_ex, uint8_t val, uint8_t dst, uint8_t size)
 {
+	check_alloc_code(code, 6);
+	code_ptr out = code->cur;
 	if (size == SZ_W) {
 		*(out++) = PRE_SIZE;
 	}
@@ -1625,11 +1698,13 @@
 	*(out++) = OP2_BTX_I;
 	*(out++) = MODE_REG_DIRECT | dst | (op_ex << 3);
 	*(out++) = val;
-	return out;
+	code->cur = out;
 }
 
-uint8_t * bit_irdisp8(uint8_t * out, uint8_t op_ex, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size)
+void bit_irdisp(code_info *code, uint8_t op_ex, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size)
 {
+	check_alloc_code(code, 10);
+	code_ptr out = code->cur;
 	if (size == SZ_W) {
 		*(out++) = PRE_SIZE;
 	}
@@ -1646,99 +1721,104 @@
 	}
 	*(out++) = PRE_2BYTE;
 	*(out++) = OP2_BTX_I;
-	*(out++) = MODE_REG_DISPLACE8 | dst_base | (op_ex << 3);
-	*(out++) = dst_disp;
+	if (dst_disp < 128 && dst_disp >= -128) {
+		*(out++) = MODE_REG_DISPLACE8 | dst_base | (op_ex << 3);
+		*(out++) = dst_disp;
+	} else {
+		*(out++) = MODE_REG_DISPLACE32 | dst_base | (op_ex << 3);
+		*(out++) = dst_disp;
+		*(out++) = dst_disp >> 8;
+		*(out++) = dst_disp >> 16;
+		*(out++) = dst_disp >> 24;
+	}
 	*(out++) = val;
-	return out;
+	code->cur = out;
 }
 
-uint8_t * bt_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
+void bt_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
 {
-	return bit_rr(out, OP2_BT, src, dst, size);
+	return bit_rr(code, OP2_BT, src, dst, size);
 }
 
-uint8_t * bt_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size)
+void bt_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size)
 {
-	return bit_rrdisp8(out, OP2_BT, src, dst_base, dst_disp, size);
-}
-
-uint8_t * bt_rrdisp32(uint8_t * out, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size)
-{
-	return bit_rrdisp32(out, OP2_BT, src, dst_base, dst_disp, size);
+	return bit_rrdisp(code, OP2_BT, src, dst_base, dst_disp, size);
 }
 
-uint8_t * bt_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size)
+void bt_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
 {
-	return bit_ir(out, OP_EX_BT, val, dst, size);
+	return bit_ir(code, OP_EX_BT, val, dst, size);
 }
 
-uint8_t * bt_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size)
+void bt_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size)
 {
-	return bit_irdisp8(out, OP_EX_BT, val, dst_base, dst_disp, size);
+	return bit_irdisp(code, OP_EX_BT, val, dst_base, dst_disp, size);
 }
 
-uint8_t * bts_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
+void bts_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
 {
-	return bit_rr(out, OP2_BTS, src, dst, size);
+	return bit_rr(code, OP2_BTS, src, dst, size);
 }
 
-uint8_t * bts_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size)
+void bts_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size)
 {
-	return bit_rrdisp8(out, OP2_BTS, src, dst_base, dst_disp, size);
+	return bit_rrdisp(code, OP2_BTS, src, dst_base, dst_disp, size);
 }
 
-uint8_t * bts_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size)
+void bts_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
 {
-	return bit_ir(out, OP_EX_BTS, val, dst, size);
+	return bit_ir(code, OP_EX_BTS, val, dst, size);
 }
 
-uint8_t * bts_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size)
+void bts_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size)
 {
-	return bit_irdisp8(out, OP_EX_BTS, val, dst_base, dst_disp, size);
+	return bit_irdisp(code, OP_EX_BTS, val, dst_base, dst_disp, size);
+}
+
+void btr_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
+{
+	return bit_rr(code, OP2_BTR, src, dst, size);
 }
 
-uint8_t * btr_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
+void btr_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size)
 {
-	return bit_rr(out, OP2_BTR, src, dst, size);
+	return bit_rrdisp(code, OP2_BTR, src, dst_base, dst_disp, size);
 }
 
-uint8_t * btr_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size)
+void btr_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
 {
-	return bit_rrdisp8(out, OP2_BTR, src, dst_base, dst_disp, size);
+	return bit_ir(code, OP_EX_BTR, val, dst, size);
 }
 
-uint8_t * btr_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size)
+void btr_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size)
 {
-	return bit_ir(out, OP_EX_BTR, val, dst, size);
+	return bit_irdisp(code, OP_EX_BTR, val, dst_base, dst_disp, size);
 }
 
-uint8_t * btr_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size)
+void btc_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
 {
-	return bit_irdisp8(out, OP_EX_BTR, val, dst_base, dst_disp, size);
+	return bit_rr(code, OP2_BTC, src, dst, size);
 }
 
-uint8_t * btc_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
+void btc_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size)
 {
-	return bit_rr(out, OP2_BTC, src, dst, size);
+	return bit_rrdisp(code, OP2_BTC, src, dst_base, dst_disp, size);
 }
 
-uint8_t * btc_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size)
+void btc_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
 {
-	return bit_rrdisp8(out, OP2_BTC, src, dst_base, dst_disp, size);
+	return bit_ir(code, OP_EX_BTC, val, dst, size);
 }
 
-uint8_t * btc_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size)
+void btc_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size)
 {
-	return bit_ir(out, OP_EX_BTC, val, dst, size);
+	return bit_irdisp(code, OP_EX_BTC, val, dst_base, dst_disp, size);
 }
 
-uint8_t * btc_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size)
+void jcc(code_info *code, uint8_t cc, code_ptr dest)
 {
-	return bit_irdisp8(out, OP_EX_BTC, val, dst_base, dst_disp, size);
-}
-
-uint8_t * jcc(uint8_t * out, uint8_t cc, uint8_t * dest)
-{
+	check_alloc_code(code, 6);
+	code_ptr out = code->cur;
 	ptrdiff_t disp = dest-(out+2);
 	if (disp <= 0x7F && disp >= -0x80) {
 		*(out++) = OP_JCC | cc;
@@ -1756,15 +1836,17 @@
 			disp >>= 8;
 			*(out++) = disp;
 		} else {
-			printf("%p - %p = %lX\n", dest, out + 6, disp);
-			return NULL;
+			fprintf(stderr, "jcc: %p - %p = %lX\n", dest, out + 6, (long)disp);
+			exit(1);
 		}
 	}
-	return out;
+	code->cur = out;
 }
 
-uint8_t * jmp(uint8_t * out, uint8_t * dest)
+void jmp(code_info *code, code_ptr dest)
 {
+	check_alloc_code(code, 5);
+	code_ptr out = code->cur;
 	ptrdiff_t disp = dest-(out+2);
 	if (disp <= 0x7F && disp >= -0x80) {
 		*(out++) = OP_JMP_BYTE;
@@ -1781,26 +1863,43 @@
 			disp >>= 8;
 			*(out++) = disp;
 		} else {
-			printf("%p - %p = %lX\n", dest, out + 6, disp);
-			return NULL;
+			fprintf(stderr, "jmp: %p - %p = %lX\n", dest, out + 6, (long)disp);
+			exit(1);
 		}
 	}
-	return out;
+	code->cur = out;
 }
 
-uint8_t * jmp_r(uint8_t * out, uint8_t dst)
+void jmp_r(code_info *code, uint8_t dst)
 {
+	check_alloc_code(code, 3);
+	code_ptr out = code->cur;
 	if (dst >= R8) {
 		dst -= R8 - X86_R8;
 		*(out++) = PRE_REX | REX_RM_FIELD;
 	}
 	*(out++) = OP_SINGLE_EA;
 	*(out++) = MODE_REG_DIRECT | dst | (OP_EX_JMP_EA << 3);
-	return out;
+	code->cur = out;
 }
 
-uint8_t * call(uint8_t * out, uint8_t * fun)
+void jmp_rind(code_info *code, uint8_t dst)
 {
+	check_alloc_code(code, 3);
+	code_ptr out = code->cur;
+	if (dst >= R8) {
+		dst -= R8 - X86_R8;
+		*(out++) = PRE_REX | REX_RM_FIELD;
+	}
+	*(out++) = OP_SINGLE_EA;
+	*(out++) = MODE_REG_INDIRECT | dst | (OP_EX_JMP_EA << 3);
+	code->cur = out;
+}
+
+void call(code_info *code, code_ptr fun)
+{
+	check_alloc_code(code, 5);
+	code_ptr out = code->cur;
 	ptrdiff_t disp = fun-(out+5);
 	if (disp <= 0x7FFFFFFF && disp >= -2147483648) {
 		*(out++) = OP_CALL;
@@ -1813,35 +1912,44 @@
 		*(out++) = disp;
 	} else {
 		//TODO: Implement far call???
-		printf("%p - %p = %lX\n", fun, out + 5, disp);
-		return NULL;
+		fprintf(stderr, "%p - %p = %lX\n", fun, out + 5, (long)disp);
+		exit(1);
 	}
-	return out;
+	code->cur = out;
 }
 
-uint8_t * call_r(uint8_t * out, uint8_t dst)
+void call_r(code_info *code, uint8_t dst)
 {
+	check_alloc_code(code, 2);
+	code_ptr out = code->cur;
 	*(out++) = OP_SINGLE_EA;
 	*(out++) = MODE_REG_DIRECT | dst | (OP_EX_CALL_EA << 3);
-	return out;
+	code->cur = out;
 }
 
-uint8_t * retn(uint8_t * out)
+void retn(code_info *code)
 {
+	check_alloc_code(code, 1);
+	code_ptr out = code->cur;
 	*(out++) = OP_RETN;
-	return out;
+	code->cur = out;
 }
 
-uint8_t * cdq(uint8_t * out)
+void cdq(code_info *code)
 {
+	check_alloc_code(code, 1);
+	code_ptr out = code->cur;
 	*(out++) = OP_CDQ;
-	return out;
+	code->cur = out;
 }
 
-uint8_t * loop(uint8_t * out, uint8_t * dst)
+void loop(code_info *code, code_ptr dst)
 {
+	check_alloc_code(code, 2);
+	code_ptr out = code->cur;
 	ptrdiff_t disp = dst-(out+2);
 	*(out++) = OP_LOOP;
 	*(out++) = disp;
-	return out;
+	code->cur = out;
 }
+
--- a/gen_x86.h	Tue Dec 16 01:10:54 2014 -0800
+++ b/gen_x86.h	Tue Dec 30 19:11:34 2014 -0800
@@ -7,6 +7,7 @@
 #define GEN_X86_H_
 
 #include <stdint.h>
+#include "gen.h"
 
 enum {
 	RAX = 0,
@@ -35,7 +36,9 @@
 	CC_O = 0,
 	CC_NO,
 	CC_C,
+	CC_B = CC_C,
 	CC_NC,
+	CC_NB = CC_NC,
 	CC_Z,
 	CC_NZ,
 	CC_BE,
@@ -57,6 +60,14 @@
 	SZ_Q
 } x86_size;
 
+#ifdef X86_64
+#define SZ_PTR SZ_Q
+#define MAX_INST_LEN 14
+#else
+#define SZ_PTR SZ_D
+#define MAX_INST_LEN 11
+#endif
+
 enum {
 	MODE_REG_INDIRECT = 0,
 	MODE_REG_INDEXED = 4,
@@ -69,145 +80,142 @@
 	MODE_IMMED = 0xFF
 } x86_modes;
 
+void check_alloc_code(code_info *code, uint32_t inst_size);
 
-uint8_t * rol_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size);
-uint8_t * ror_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size);
-uint8_t * rcl_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size);
-uint8_t * rcr_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size);
-uint8_t * shl_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size);
-uint8_t * shr_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size);
-uint8_t * sar_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size);
-uint8_t * rol_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size);
-uint8_t * ror_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size);
-uint8_t * rcl_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size);
-uint8_t * rcr_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size);
-uint8_t * shl_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size);
-uint8_t * shr_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size);
-uint8_t * sar_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size);
-uint8_t * rol_clr(uint8_t * out, uint8_t dst, uint8_t size);
-uint8_t * ror_clr(uint8_t * out, uint8_t dst, uint8_t size);
-uint8_t * rcl_clr(uint8_t * out, uint8_t dst, uint8_t size);
-uint8_t * rcr_clr(uint8_t * out, uint8_t dst, uint8_t size);
-uint8_t * shl_clr(uint8_t * out, uint8_t dst, uint8_t size);
-uint8_t * shr_clr(uint8_t * out, uint8_t dst, uint8_t size);
-uint8_t * sar_clr(uint8_t * out, uint8_t dst, uint8_t size);
-uint8_t * rol_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size);
-uint8_t * ror_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size);
-uint8_t * rcl_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size);
-uint8_t * rcr_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size);
-uint8_t * shl_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size);
-uint8_t * shr_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size);
-uint8_t * sar_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size);
-uint8_t * add_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size);
-uint8_t * adc_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);
-uint8_t * and_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size);
-uint8_t * sub_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size);
-uint8_t * sbb_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size);
-uint8_t * cmp_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size);
-uint8_t * add_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size);
-uint8_t * adc_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size);
-uint8_t * or_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size);
-uint8_t * xor_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size);
-uint8_t * and_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size);
-uint8_t * sub_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size);
-uint8_t * sbb_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 * add_irdisp32(uint8_t * out, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size);
-uint8_t * adc_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 * sbb_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 * adc_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 * adc_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 * sbb_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size);
-uint8_t * sbb_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 * imul_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size);
-uint8_t * imul_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size);
-uint8_t * imul_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size);
-uint8_t * not_r(uint8_t * out, uint8_t dst, uint8_t size);
-uint8_t * neg_r(uint8_t * out, uint8_t dst, uint8_t size);
-uint8_t * not_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size);
-uint8_t * neg_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size);
-uint8_t * mul_r(uint8_t * out, uint8_t dst, uint8_t size);
-uint8_t * imul_r(uint8_t * out, uint8_t dst, uint8_t size);
-uint8_t * div_r(uint8_t * out, uint8_t dst, uint8_t size);
-uint8_t * idiv_r(uint8_t * out, uint8_t dst, uint8_t size);
-uint8_t * mul_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size);
-uint8_t * imul_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size);
-uint8_t * div_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size);
-uint8_t * idiv_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size);
-uint8_t * test_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size);
-uint8_t * test_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size);
-uint8_t * test_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size);
-uint8_t * test_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size);
-uint8_t * test_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_rrdisp32(uint8_t * out, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size);
-uint8_t * mov_rdisp32r(uint8_t * out, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size);
-uint8_t * mov_rrindex(uint8_t * out, uint8_t src, uint8_t dst_base, uint8_t dst_index, uint8_t scale, uint8_t size);
-uint8_t * mov_rindexr(uint8_t * out, uint8_t src_base, uint8_t src_index, uint8_t scale, 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 * mov_irind(uint8_t * out, int32_t val, uint8_t dst, uint8_t size);
-uint8_t * movsx_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t src_size, uint8_t size);
-uint8_t * movsx_rdisp8r(uint8_t * out, uint8_t src, int8_t disp, uint8_t dst, uint8_t src_size, uint8_t size);
-uint8_t * movzx_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t src_size, uint8_t size);
-uint8_t * movzx_rdisp8r(uint8_t * out, uint8_t src, int8_t disp, uint8_t dst, uint8_t src_size, uint8_t size);
-uint8_t * xchg_rr(uint8_t * out, uint8_t src, uint8_t dst, 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 * setcc_rdisp8(uint8_t * out, uint8_t cc, uint8_t dst, int8_t disp);
-uint8_t * bt_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size);
-uint8_t * bt_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size);
-uint8_t * bt_rrdisp32(uint8_t * out, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size);
-uint8_t * bt_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size);
-uint8_t * bt_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size);
-uint8_t * bts_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size);
-uint8_t * bts_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size);
-uint8_t * bts_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size);
-uint8_t * bts_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size);
-uint8_t * btr_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size);
-uint8_t * btr_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size);
-uint8_t * btr_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size);
-uint8_t * btr_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size);
-uint8_t * btc_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size);
-uint8_t * btc_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size);
-uint8_t * btc_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size);
-uint8_t * btc_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size);
-uint8_t * jcc(uint8_t * out, uint8_t cc, uint8_t *dest);
-uint8_t * jmp(uint8_t * out, uint8_t *dest);
-uint8_t * jmp_r(uint8_t * out, uint8_t dst);
-uint8_t * call(uint8_t * out, uint8_t * fun);
-uint8_t * call_r(uint8_t * out, uint8_t dst);
-uint8_t * retn(uint8_t * out);
-uint8_t * cdq(uint8_t * out);
-uint8_t * loop(uint8_t * out, uint8_t * dst);
+void rol_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
+void ror_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
+void rcl_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
+void rcr_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
+void shl_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
+void shr_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
+void sar_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
+void rol_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size);
+void ror_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size);
+void rcl_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size);
+void rcr_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size);
+void shl_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size);
+void shr_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size);
+void sar_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size);
+void rol_clr(code_info *code, uint8_t dst, uint8_t size);
+void ror_clr(code_info *code, uint8_t dst, uint8_t size);
+void rcl_clr(code_info *code, uint8_t dst, uint8_t size);
+void rcr_clr(code_info *code, uint8_t dst, uint8_t size);
+void shl_clr(code_info *code, uint8_t dst, uint8_t size);
+void shr_clr(code_info *code, uint8_t dst, uint8_t size);
+void sar_clr(code_info *code, uint8_t dst, uint8_t size);
+void rol_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
+void ror_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
+void rcl_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
+void rcr_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
+void shl_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
+void shr_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
+void sar_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
+void add_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
+void adc_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
+void or_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
+void xor_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
+void and_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
+void sub_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
+void sbb_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
+void cmp_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
+void add_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size);
+void adc_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size);
+void or_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size);
+void xor_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size);
+void and_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size);
+void sub_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size);
+void sbb_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size);
+void cmp_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size);
+void add_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size);
+void adc_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size);
+void or_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size);
+void xor_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size);
+void and_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size);
+void sub_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size);
+void sbb_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size);
+void cmp_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size);
+void add_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size);
+void adc_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size);
+void add_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size);
+void adc_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size);
+void or_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size);
+void or_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size);
+void xor_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size);
+void xor_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size);
+void and_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size);
+void and_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size);
+void sub_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size);
+void sub_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size);
+void sbb_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size);
+void sbb_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size);
+void cmp_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size);
+void cmp_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size);
+void imul_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
+void imul_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size);
+void imul_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size);
+void not_r(code_info *code, uint8_t dst, uint8_t size);
+void neg_r(code_info *code, uint8_t dst, uint8_t size);
+void not_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
+void neg_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
+void mul_r(code_info *code, uint8_t dst, uint8_t size);
+void imul_r(code_info *code, uint8_t dst, uint8_t size);
+void div_r(code_info *code, uint8_t dst, uint8_t size);
+void idiv_r(code_info *code, uint8_t dst, uint8_t size);
+void mul_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
+void imul_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
+void div_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
+void idiv_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
+void test_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
+void test_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size);
+void test_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size);
+void test_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size);
+void test_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size);
+void mov_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
+void mov_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size);
+void mov_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size);
+void mov_rrindex(code_info *code, uint8_t src, uint8_t dst_base, uint8_t dst_index, uint8_t scale, uint8_t size);
+void mov_rindexr(code_info *code, uint8_t src_base, uint8_t src_index, uint8_t scale, uint8_t dst, uint8_t size);
+void mov_rrind(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
+void mov_rindr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
+void mov_ir(code_info *code, int64_t val, uint8_t dst, uint8_t size);
+void mov_irdisp(code_info *code, int32_t val, uint8_t dst, int32_t disp, uint8_t size);
+void mov_irind(code_info *code, int32_t val, uint8_t dst, uint8_t size);
+void movsx_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t src_size, uint8_t size);
+void movsx_rdispr(code_info *code, uint8_t src, int32_t disp, uint8_t dst, uint8_t src_size, uint8_t size);
+void movzx_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t src_size, uint8_t size);
+void movzx_rdispr(code_info *code, uint8_t src, int32_t disp, uint8_t dst, uint8_t src_size, uint8_t size);
+void xchg_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
+void pushf(code_info *code);
+void popf(code_info *code);
+void push_r(code_info *code, uint8_t reg);
+void push_rdisp(code_info *code, uint8_t base, int32_t disp);
+void pop_r(code_info *code, uint8_t reg);
+void pop_rind(code_info *code, uint8_t reg);
+void setcc_r(code_info *code, uint8_t cc, uint8_t dst);
+void setcc_rind(code_info *code, uint8_t cc, uint8_t dst);
+void setcc_rdisp(code_info *code, uint8_t cc, uint8_t dst, int32_t disp);
+void bt_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
+void bt_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size);
+void bt_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
+void bt_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size);
+void bts_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
+void bts_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size);
+void bts_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
+void bts_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size);
+void btr_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
+void btr_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size);
+void btr_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
+void btr_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size);
+void btc_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
+void btc_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size);
+void btc_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
+void btc_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size);
+void jcc(code_info *code, uint8_t cc, code_ptr dest);
+void jmp_rind(code_info *code, uint8_t dst);
+void call_r(code_info *code, uint8_t dst);
+void retn(code_info *code);
+void cdq(code_info *code);
+void loop(code_info *code, code_ptr dst);
 
 #endif //GEN_X86_H_
 
--- a/gentests.py	Tue Dec 16 01:10:54 2014 -0800
+++ b/gentests.py	Tue Dec 30 19:11:34 2014 -0800
@@ -178,9 +178,17 @@
 					self.disp -= (address & 0xFFFFFF)
 				else:
 					self.disp += 0xE00000-(address & 0xFFFFFF)
+				if self.disp > 127:
+					self.disp = 127
+				elif self.disp < -128:
+					self.disp = -128
 				address = base + index + self.disp
 			elif (address & 0xFFFFFF) > 0xFFFFFC:
 				self.disp -= (address & 0xFFFFFF) - 0xFFFFFC
+				if self.disp > 127:
+					self.disp = 127
+				elif self.disp < -128:
+					self.disp = -128
 				address = base + index + self.disp
 			if size != 'b' and address & 1:
 				self.disp = self.disp ^ 1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m68k_core.c	Tue Dec 30 19:11:34 2014 -0800
@@ -0,0 +1,939 @@
+/*
+ Copyright 2014 Michael Pavone
+ This file is part of BlastEm.
+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
+*/
+#include "m68k_core.h"
+#include "m68k_internal.h"
+#include "68kinst.h"
+#include "backend.h"
+#include "gen.h"
+#include <stdio.h>
+#include <stddef.h>
+#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) {
+		return opts->dregs[op->params.regs.pri];
+	}
+	if (op->addr_mode == MODE_AREG) {
+		return opts->aregs[op->params.regs.pri];
+	}
+	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)
+{
+	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)
+{
+	printf("XNZVC\n%d%d%d%d%d\n", context->flags[0], context->flags[1], context->flags[2], context->flags[3], context->flags[4]);
+	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);
+}
+
+void m68k_read_size(m68k_options *opts, uint8_t size)
+{
+	switch (size)
+	{
+	case OPSIZE_BYTE:
+		call(&opts->gen.code, opts->read_8);
+		break;
+	case OPSIZE_WORD:
+		call(&opts->gen.code, opts->read_16);
+		break;
+	case OPSIZE_LONG:
+		call(&opts->gen.code, opts->read_32);
+		break;
+	}
+}
+
+void m68k_write_size(m68k_options *opts, uint8_t size)
+{
+	switch (size)
+	{
+	case OPSIZE_BYTE:
+		call(&opts->gen.code, opts->write_8);
+		break;
+	case OPSIZE_WORD:
+		call(&opts->gen.code, opts->write_16);
+		break;
+	case OPSIZE_LONG:
+		call(&opts->gen.code, opts->write_32_highfirst);
+		break;
+	}
+}
+
+void translate_m68k_lea_pea(m68k_options * opts, m68kinst * inst)
+{
+	code_info *code = &opts->gen.code;
+	int8_t dst_reg = inst->op == M68K_PEA ? opts->gen.scratch1 : 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 && inst->op != M68K_PEA) {
+			native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
+		}
+		break;
+	case MODE_PC_DISPLACE:
+		cycles(&opts->gen, 8);
+		if (inst->op == M68K_PEA) {
+			ldi_native(opts, inst->src.params.regs.displacement + inst->address+2, dst_reg);
+		} else {
+			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 && inst->op != M68K_PEA) {
+			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);
+		if (inst->op == M68K_PEA) {
+			ldi_native(opts, inst->src.params.immed, dst_reg);
+		} else {
+			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);
+	}
+	if (inst->op == M68K_PEA) {
+		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 translate_m68k_move_usp(m68k_options *opts, m68kinst *inst)
+{
+	cycles(&opts->gen, BUS);
+	int8_t reg;
+	if (inst->src.addr_mode == MODE_UNUSED) {
+		reg = native_reg(&inst->dst, opts);
+		if (reg < 0) {
+			reg = opts->gen.scratch1;
+		}
+		areg_to_native(opts, 8, reg);
+		if (reg == opts->gen.scratch1) {
+			native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
+		}
+	} else {
+		reg = native_reg(&inst->src, opts);
+		if (reg < 0) {
+			reg = opts->gen.scratch1;
+			areg_to_native(opts, inst->src.params.regs.pri, reg);
+		}
+		native_to_areg(opts, reg, 8);
+	}
+}
+
+void translate_m68k_movem(m68k_options * opts, m68kinst * inst)
+{
+	code_info *code = &opts->gen.code;
+	int8_t bit,reg,sec_reg;
+	uint8_t early_cycles;
+	if(inst->src.addr_mode == MODE_REG) {
+		//reg to mem
+		early_cycles = 8;
+		int8_t dir;
+		switch (inst->dst.addr_mode)
+		{
+		case MODE_AREG_INDIRECT:
+		case MODE_AREG_PREDEC:
+			areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2);
+			break;
+		case MODE_AREG_DISPLACE:
+			early_cycles += BUS;
+			calc_areg_displace(opts, &inst->dst, opts->gen.scratch2);
+			break;
+		case MODE_AREG_INDEX_DISP8:
+			early_cycles += 6;
+			calc_areg_index_disp8(opts, &inst->dst, opts->gen.scratch2);
+			break;
+		case MODE_PC_DISPLACE:
+			early_cycles += BUS;
+			ldi_native(opts, inst->dst.params.regs.displacement + inst->address+2, opts->gen.scratch2);
+			break;
+		case MODE_PC_INDEX_DISP8:
+			early_cycles += 6;
+			ldi_native(opts, inst->address+2, opts->gen.scratch2);
+			calc_index_disp8(opts, &inst->dst, opts->gen.scratch2);
+		case MODE_ABSOLUTE:
+			early_cycles += 4;
+		case MODE_ABSOLUTE_SHORT:
+			early_cycles += 4;
+			ldi_native(opts, inst->dst.params.immed, opts->gen.scratch2);
+			break;
+		default:
+			m68k_disasm(inst, disasm_buf);
+			printf("%X: %s\naddress mode %d not implemented (movem dst)\n", inst->address, disasm_buf, inst->dst.addr_mode);
+			exit(1);
+		}
+		if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
+			reg = 15;
+			dir = -1;
+		} else {
+			reg = 0;
+			dir = 1;
+		}
+		cycles(&opts->gen, early_cycles);
+		for(bit=0; reg < 16 && reg >= 0; reg += dir, bit++) {
+			if (inst->src.params.immed & (1 << bit)) {
+				if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
+					subi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch2);
+				}
+				push_native(opts, opts->gen.scratch2);
+				if (reg > 7) {
+					areg_to_native(opts, reg-8, opts->gen.scratch1);
+				} else {
+					dreg_to_native(opts, reg, opts->gen.scratch1);
+				}
+				if (inst->extra.size == OPSIZE_LONG) {
+					call(code, opts->write_32_lowfirst);
+				} else {
+					call(code, opts->write_16);
+				}
+				pop_native(opts, opts->gen.scratch2);
+				if (inst->dst.addr_mode != MODE_AREG_PREDEC) {
+					addi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch2);
+				}
+			}
+		}
+		if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
+			native_to_areg(opts, opts->gen.scratch2, inst->dst.params.regs.pri);
+		}
+	} else {
+		//mem to reg
+		early_cycles = 4;
+		switch (inst->src.addr_mode)
+		{
+		case MODE_AREG_INDIRECT:
+		case MODE_AREG_POSTINC:
+			areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1);
+			break;
+		case MODE_AREG_DISPLACE:
+			early_cycles += BUS;
+			reg = opts->gen.scratch2;
+			calc_areg_displace(opts, &inst->src, opts->gen.scratch1);
+			break;
+		case MODE_AREG_INDEX_DISP8:
+			early_cycles += 6;
+			calc_areg_index_disp8(opts, &inst->src, opts->gen.scratch1);
+			break;
+		case MODE_PC_DISPLACE:
+			early_cycles += BUS;
+			ldi_native(opts, inst->src.params.regs.displacement + inst->address+2, opts->gen.scratch1);
+			break;
+		case MODE_PC_INDEX_DISP8:
+			early_cycles += 6;
+			ldi_native(opts, inst->address+2, opts->gen.scratch1);
+			calc_index_disp8(opts, &inst->src, opts->gen.scratch1);
+			break;
+		case MODE_ABSOLUTE:
+			early_cycles += 4;
+		case MODE_ABSOLUTE_SHORT:
+			early_cycles += 4;
+			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 (movem src)\n", inst->address, disasm_buf, inst->src.addr_mode);
+			exit(1);
+		}
+		cycles(&opts->gen, early_cycles);
+		for(reg = 0; reg < 16; reg ++) {
+			if (inst->dst.params.immed & (1 << reg)) {
+				push_native(opts, opts->gen.scratch1);
+				if (inst->extra.size == OPSIZE_LONG) {
+					call(code, opts->read_32);
+				} else {
+					call(code, opts->read_16);
+				}
+				if (inst->extra.size == OPSIZE_WORD) {
+					sign_extend16_native(opts, opts->gen.scratch1);
+				}
+				if (reg > 7) {
+					native_to_areg(opts, opts->gen.scratch1, reg-8);
+				} else {
+					native_to_dreg(opts, opts->gen.scratch1, reg);
+				}
+				pop_native(opts, opts->gen.scratch1);
+				addi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch1);
+			}
+		}
+		if (inst->src.addr_mode == MODE_AREG_POSTINC) {
+			native_to_areg(opts, opts->gen.scratch1, inst->src.params.regs.pri);
+		}
+	}
+	//prefetch
+	cycles(&opts->gen, 4);
+}
+
+void translate_m68k_nop(m68k_options *opts, m68kinst *inst)
+{
+	cycles(&opts->gen, BUS);
+}
+
+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;
+	address /= 2;
+	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 || native_code_map[chunk].offsets[offset] == EXTENSION_WORD) {
+		return NULL;
+	}
+	return native_code_map[chunk].base + native_code_map[chunk].offsets[offset];
+}
+
+code_ptr get_native_from_context(m68k_context * context, uint32_t address)
+{
+	return get_native_address(context->native_code_map, address);
+}
+
+uint32_t get_instruction_start(native_map_slot * native_code_map, uint32_t address)
+{
+	address &= 0xFFFFFF;
+	address /= 2;
+	uint32_t chunk = address / NATIVE_CHUNK_SIZE;
+	if (!native_code_map[chunk].base) {
+		return 0;
+	}
+	uint32_t offset = address % NATIVE_CHUNK_SIZE;
+	if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET) {
+		return 0;
+	}
+	while (native_code_map[chunk].offsets[offset] == EXTENSION_WORD) {
+		--address;
+		chunk = address / NATIVE_CHUNK_SIZE;
+		offset = address % NATIVE_CHUNK_SIZE;
+	}
+	return address*2;
+}
+
+void map_native_address(m68k_context * context, uint32_t address, code_ptr native_addr, uint8_t size, uint8_t native_size)
+{
+	native_map_slot * native_code_map = context->native_code_map;
+	m68k_options * opts = context->options;
+	address &= 0xFFFFFF;
+	if (address > 0xE00000) {
+		context->ram_code_flags[(address & 0xC000) >> 14] |= 1 << ((address & 0x3800) >> 11);
+		if (((address & 0x3FFF) + size) & 0xC000) {
+			context->ram_code_flags[((address+size) & 0xC000) >> 14] |= 1 << (((address+size) & 0x3800) >> 11);
+		}
+		uint32_t slot = (address & 0xFFFF)/1024;
+		if (!opts->gen.ram_inst_sizes[slot]) {
+			opts->gen.ram_inst_sizes[slot] = malloc(sizeof(uint8_t) * 512);
+		}
+		opts->gen.ram_inst_sizes[slot][((address & 0xFFFF)/2)%512] = native_size;
+	}
+	address/= 2;
+	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(int32_t) * NATIVE_CHUNK_SIZE);
+		memset(native_code_map[chunk].offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE);
+	}
+	uint32_t offset = address % NATIVE_CHUNK_SIZE;
+	native_code_map[chunk].offsets[offset] = native_addr-native_code_map[chunk].base;
+	for(address++,size-=2; size; address++,size-=2) {
+		chunk = address / NATIVE_CHUNK_SIZE;
+		offset = address % NATIVE_CHUNK_SIZE;
+		if (!native_code_map[chunk].base) {
+			native_code_map[chunk].base = native_addr;
+			native_code_map[chunk].offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE);
+			memset(native_code_map[chunk].offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE);
+		}
+		native_code_map[chunk].offsets[offset] = EXTENSION_WORD;
+	}
+}
+
+uint8_t get_native_inst_size(m68k_options * opts, uint32_t address)
+{
+	if (address < 0xE00000) {
+		return 0;
+	}
+	uint32_t slot = (address & 0xFFFF)/1024;
+	return opts->gen.ram_inst_sizes[slot][((address & 0xFFFF)/2)%512];
+}
+
+uint8_t m68k_is_terminal(m68kinst * inst)
+{
+	return inst->op == M68K_RTS || inst->op == M68K_RTE || inst->op == M68K_RTR || inst->op == M68K_JMP
+		|| inst->op == M68K_TRAP || inst->op == M68K_ILLEGAL || inst->op == M68K_INVALID || inst->op == M68K_RESET
+		|| (inst->op == M68K_BCC && inst->extra.cond == COND_TRUE);
+}
+
+void m68k_handle_deferred(m68k_context * context)
+{
+	m68k_options * opts = context->options;
+	process_deferred(&opts->gen.deferred, context, (native_addr_func)get_native_from_context);
+	if (opts->gen.deferred) {
+		translate_m68k_stream(opts->gen.deferred->address, context);
+	}
+}
+
+typedef enum {
+	RAW_FUNC = 1,
+	BINARY_ARITH,
+	UNARY_ARITH,
+	OP_FUNC
+} impl_type;
+
+typedef void (*raw_fun)(m68k_options * opts, m68kinst *inst);
+typedef void (*op_fun)(m68k_options * opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
+
+typedef struct {
+	union {
+		raw_fun  raw;
+		uint32_t flag_mask;
+		op_fun   op;
+	} impl;
+	impl_type itype;
+} impl_info;
+
+#define RAW_IMPL(inst, fun)     [inst] = { .impl = { .raw = fun }, .itype = RAW_FUNC }
+#define OP_IMPL(inst, fun)      [inst] = { .impl = { .op = fun }, .itype = OP_FUNC }
+#define UNARY_IMPL(inst, mask)  [inst] = { .impl = { .flag_mask = mask }, .itype = UNARY_ARITH }
+#define BINARY_IMPL(inst, mask) [inst] = { .impl = { .flag_mask = mask}, .itype = BINARY_ARITH }
+
+impl_info m68k_impls[] = {
+	//math
+	BINARY_IMPL(M68K_ADD, X|N|Z|V|C),
+	BINARY_IMPL(M68K_SUB, X|N|Z|V|C),
+	//z flag is special cased for ADDX/SUBX
+	BINARY_IMPL(M68K_ADDX, X|N|V|C),
+	BINARY_IMPL(M68K_SUBX, X|N|V|C),
+	OP_IMPL(M68K_ABCD, translate_m68k_abcd_sbcd),
+	OP_IMPL(M68K_SBCD, translate_m68k_abcd_sbcd),
+	BINARY_IMPL(M68K_AND, N|Z|V0|C0),
+	BINARY_IMPL(M68K_EOR, N|Z|V0|C0),
+	BINARY_IMPL(M68K_OR, N|Z|V0|C0),
+	RAW_IMPL(M68K_CMP, translate_m68k_cmp),
+	OP_IMPL(M68K_DIVS, translate_m68k_div),
+	OP_IMPL(M68K_DIVU, translate_m68k_div),
+	OP_IMPL(M68K_MULS, translate_m68k_mul),
+	OP_IMPL(M68K_MULU, translate_m68k_mul),
+	RAW_IMPL(M68K_EXT, translate_m68k_ext),
+	UNARY_IMPL(M68K_NEG, X|N|Z|V|C),
+	OP_IMPL(M68K_NEGX, translate_m68k_negx),
+	UNARY_IMPL(M68K_NOT, N|Z|V|C),
+	UNARY_IMPL(M68K_TST, N|Z|V0|C0),
+
+	//shift/rotate
+	OP_IMPL(M68K_ASL, translate_m68k_sl),
+	OP_IMPL(M68K_LSL, translate_m68k_sl),
+	OP_IMPL(M68K_ASR, translate_m68k_asr),
+	OP_IMPL(M68K_LSR, translate_m68k_lsr),
+	OP_IMPL(M68K_ROL, translate_m68k_rot),
+	OP_IMPL(M68K_ROR, translate_m68k_rot),
+	OP_IMPL(M68K_ROXL, translate_m68k_rot),
+	OP_IMPL(M68K_ROXR, translate_m68k_rot),
+	UNARY_IMPL(M68K_SWAP, N|Z|V0|C0),
+
+	//bit
+	OP_IMPL(M68K_BCHG, translate_m68k_bit),
+	OP_IMPL(M68K_BCLR, translate_m68k_bit),
+	OP_IMPL(M68K_BSET, translate_m68k_bit),
+	OP_IMPL(M68K_BTST, translate_m68k_bit),
+
+	//data movement
+	RAW_IMPL(M68K_MOVE, translate_m68k_move),
+	RAW_IMPL(M68K_MOVEM, translate_m68k_movem),
+	RAW_IMPL(M68K_MOVEP, translate_m68k_movep),
+	RAW_IMPL(M68K_MOVE_USP, translate_m68k_move_usp),
+	RAW_IMPL(M68K_LEA, translate_m68k_lea_pea),
+	RAW_IMPL(M68K_PEA, translate_m68k_lea_pea),
+	RAW_IMPL(M68K_CLR, translate_m68k_clr),
+	OP_IMPL(M68K_EXG, translate_m68k_exg),
+	RAW_IMPL(M68K_SCC, translate_m68k_scc),
+
+	//function calls and branches
+	RAW_IMPL(M68K_BCC, translate_m68k_bcc),
+	RAW_IMPL(M68K_BSR, translate_m68k_bsr),
+	RAW_IMPL(M68K_DBCC, translate_m68k_dbcc),
+	RAW_IMPL(M68K_JMP, translate_m68k_jmp_jsr),
+	RAW_IMPL(M68K_JSR, translate_m68k_jmp_jsr),
+	RAW_IMPL(M68K_RTS, translate_m68k_rts),
+	RAW_IMPL(M68K_RTE, translate_m68k_rte),
+	RAW_IMPL(M68K_RTR, translate_m68k_rtr),
+	RAW_IMPL(M68K_LINK, translate_m68k_link),
+	RAW_IMPL(M68K_UNLK, translate_m68k_unlk),
+
+	//SR/CCR stuff
+	RAW_IMPL(M68K_ANDI_CCR, translate_m68k_andi_ori_ccr_sr),
+	RAW_IMPL(M68K_ANDI_SR, translate_m68k_andi_ori_ccr_sr),
+	RAW_IMPL(M68K_EORI_CCR, translate_m68k_eori_ccr_sr),
+	RAW_IMPL(M68K_EORI_SR, translate_m68k_eori_ccr_sr),
+	RAW_IMPL(M68K_ORI_CCR, translate_m68k_andi_ori_ccr_sr),
+	RAW_IMPL(M68K_ORI_SR, translate_m68k_andi_ori_ccr_sr),
+	OP_IMPL(M68K_MOVE_CCR, translate_m68k_move_ccr_sr),
+	OP_IMPL(M68K_MOVE_SR, translate_m68k_move_ccr_sr),
+	OP_IMPL(M68K_MOVE_FROM_SR, translate_m68k_move_from_sr),
+	RAW_IMPL(M68K_STOP, translate_m68k_stop),
+
+	//traps
+	OP_IMPL(M68K_CHK, translate_m68k_chk),
+	RAW_IMPL(M68K_TRAP, translate_m68k_trap),
+	RAW_IMPL(M68K_ILLEGAL, translate_m68k_illegal),
+	RAW_IMPL(M68K_INVALID, translate_m68k_invalid),
+
+	//misc
+	RAW_IMPL(M68K_NOP, translate_m68k_nop),
+	RAW_IMPL(M68K_RESET, translate_m68k_reset),
+
+	//currently unimplemented
+	//M68K_NBCD
+	//M68K_TAS
+	//M68K_TRAPV
+};
+
+void translate_m68k(m68k_options * opts, m68kinst * inst)
+{
+	check_cycles_int(&opts->gen, inst->address);
+	impl_info * info = m68k_impls + inst->op;
+	if (info->itype == RAW_FUNC) {
+		info->impl.raw(opts, inst);
+		return;
+	}
+
+	host_ea src_op, dst_op;
+	if (inst->src.addr_mode != MODE_UNUSED) {
+		translate_m68k_op(inst, &src_op, opts, 0);
+	}
+	if (inst->dst.addr_mode != MODE_UNUSED) {
+		translate_m68k_op(inst, &dst_op, opts, 1);
+	}
+	if (info->itype == OP_FUNC) {
+		info->impl.op(opts, inst, &src_op, &dst_op);
+	} else if (info->itype == BINARY_ARITH) {
+		translate_m68k_arith(opts, inst, info->impl.flag_mask, &src_op, &dst_op);
+	} else if (info->itype == UNARY_ARITH) {
+		translate_m68k_unary(opts, inst, info->impl.flag_mask, inst->dst.addr_mode != MODE_UNUSED ? &dst_op : &src_op);
+	} else {
+		m68k_disasm(inst, disasm_buf);
+		printf("%X: %s\ninstruction %d not yet implemented\n", inst->address, disasm_buf, inst->op);
+		exit(1);
+	}
+}
+
+void translate_m68k_stream(uint32_t address, m68k_context * context)
+{
+	m68kinst instbuf;
+	m68k_options * opts = context->options;
+	code_info *code = &opts->gen.code;
+	address &= 0xFFFFFF;
+	if(get_native_address(opts->gen.native_code_map, address)) {
+		return;
+	}
+	char disbuf[1024];
+	uint16_t *encoded, *next;
+	if ((address & 0xFFFFFF) < 0x400000) {
+		encoded = context->mem_pointers[0] + (address & 0xFFFFFF)/2;
+	} else if ((address & 0xFFFFFF) > 0xE00000) {
+		encoded = context->mem_pointers[1] + (address  & 0xFFFF)/2;
+	} else {
+		printf("attempt to translate non-memory address: %X\n", address);
+		exit(1);
+	}
+	do {
+		if (opts->address_log) {
+			fprintf(opts->address_log, "%X\n", address);
+		}
+		do {
+			if (address >= 0x400000 && address < 0xE00000) {
+				translate_out_of_bounds(code);
+				break;
+			}
+			code_ptr existing = get_native_address(opts->gen.native_code_map, address);
+			if (existing) {
+				jmp(code, existing);
+				break;
+			}
+			next = m68k_decode(encoded, &instbuf, address);
+			if (instbuf.op == M68K_INVALID) {
+				instbuf.src.params.immed = *encoded;
+			}
+			uint16_t m68k_size = (next-encoded)*2;
+			address += m68k_size;
+			encoded = next;
+			//m68k_disasm(&instbuf, disbuf);
+			//printf("%X: %s\n", instbuf.address, disbuf);
+
+			//make sure the beginning of the code for an instruction is contiguous
+			check_code_prologue(code);
+			code_ptr start = code->cur;
+			translate_m68k(opts, &instbuf);
+			code_ptr after = code->cur;
+			map_native_address(context, instbuf.address, start, m68k_size, after-start);
+		} while(!m68k_is_terminal(&instbuf));
+		process_deferred(&opts->gen.deferred, context, (native_addr_func)get_native_from_context);
+		if (opts->gen.deferred) {
+			address = opts->gen.deferred->address;
+			if ((address & 0xFFFFFF) < 0x400000) {
+				encoded = context->mem_pointers[0] + (address & 0xFFFFFF)/2;
+			} else if ((address & 0xFFFFFF) > 0xE00000) {
+				encoded = context->mem_pointers[1] + (address  & 0xFFFF)/2;
+			} else {
+				printf("attempt to translate non-memory address: %X\n", address);
+				exit(1);
+			}
+		} else {
+			encoded = NULL;
+		}
+	} while(encoded != NULL);
+}
+
+void * m68k_retranslate_inst(uint32_t address, m68k_context * context)
+{
+	m68k_options * opts = context->options;
+	code_info *code = &opts->gen.code;
+	uint8_t orig_size = get_native_inst_size(opts, address);
+	code_ptr orig_start = get_native_address(context->native_code_map, address);
+	uint32_t orig = address;
+	code_info orig_code;
+	orig_code.cur = orig_start;
+	orig_code.last = orig_start + orig_size + 5;
+	address &= 0xFFFF;
+	uint16_t *after, *inst = context->mem_pointers[1] + address/2;
+	m68kinst instbuf;
+	after = m68k_decode(inst, &instbuf, orig);
+	if (orig_size != MAX_NATIVE_SIZE) {
+		deferred_addr * orig_deferred = opts->gen.deferred;
+
+		//make sure the beginning of the code for an instruction is contiguous
+		check_code_prologue(code);
+		code_ptr native_start = code->cur;
+		translate_m68k(opts, &instbuf);
+		code_ptr native_end = code->cur;
+		uint8_t is_terminal = m68k_is_terminal(&instbuf);
+		if ((native_end - native_start) <= orig_size) {
+			code_ptr native_next;
+			if (!is_terminal) {
+				native_next = get_native_address(context->native_code_map, orig + (after-inst)*2);
+			}
+			if (is_terminal || (native_next && ((native_next == orig_start + orig_size) || (orig_size - (native_end - native_start)) > 5))) {
+				remove_deferred_until(&opts->gen.deferred, orig_deferred);
+				code_info tmp;
+				tmp.cur = code->cur;
+				tmp.last = code->last;
+				code->cur = orig_code.cur;
+				code->last = orig_code.last;
+				translate_m68k(opts, &instbuf);
+				native_end = orig_code.cur = code->cur;
+				code->cur = tmp.cur;
+				code->last = tmp.last;
+				if (!is_terminal) {
+					nop_fill_or_jmp_next(&orig_code, orig_start + orig_size, native_next);
+				}
+				m68k_handle_deferred(context);
+				return orig_start;
+			}
+		}
+
+		map_native_address(context, instbuf.address, native_start, (after-inst)*2, MAX_NATIVE_SIZE);
+
+		jmp(&orig_code, native_start);
+		if (!m68k_is_terminal(&instbuf)) {
+			code_ptr native_end = code->cur;
+			code->cur = native_start + MAX_NATIVE_SIZE;
+			code_ptr rest = get_native_address_trans(context, orig + (after-inst)*2);
+			code_ptr tmp = code->cur;
+			code->cur = native_end;
+			jmp(code, rest);
+			code->cur = tmp;
+		} else {
+			code->cur = native_start + MAX_NATIVE_SIZE;
+		}
+		m68k_handle_deferred(context);
+		return native_start;
+	} else {
+		code_info tmp;
+		tmp.cur = code->cur;
+		tmp.last = code->last;
+		code->cur = orig_code.cur;
+		code->last = orig_code.last;
+		translate_m68k(opts, &instbuf);
+		if (!m68k_is_terminal(&instbuf)) {
+			jmp(code, get_native_address_trans(context, orig + (after-inst)*2));
+		}
+		code->cur = tmp.cur;
+		code->last = tmp.last;
+		m68k_handle_deferred(context);
+		return orig_start;
+	}
+}
+
+code_ptr get_native_address_trans(m68k_context * context, uint32_t address)
+{
+	address &= 0xFFFFFF;
+	code_ptr ret = get_native_address(context->native_code_map, address);
+	if (!ret) {
+		translate_m68k_stream(address, context);
+		ret = get_native_address(context->native_code_map, address);
+	}
+	return ret;
+}
+
+void remove_breakpoint(m68k_context * context, uint32_t address)
+{
+	code_ptr native = get_native_address(context->native_code_map, address);
+	check_cycles_int(context->options, address);
+}
+
+void start_68k_context(m68k_context * context, uint32_t address)
+{
+	code_ptr addr = get_native_address_trans(context, address);
+	m68k_options * options = context->options;
+	options->start_context(addr, context);
+}
+
+void m68k_reset(m68k_context * context)
+{
+	//TODO: Make this actually use the normal read functions
+	context->aregs[7] = context->mem_pointers[0][0] << 16 | context->mem_pointers[0][1];
+	uint32_t address = context->mem_pointers[0][2] << 16 | context->mem_pointers[0][3];
+	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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m68k_core.h	Tue Dec 30 19:11:34 2014 -0800
@@ -0,0 +1,79 @@
+/*
+ Copyright 2013 Michael Pavone
+ This file is part of BlastEm.
+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
+*/
+#ifndef M68K_CORE_H_
+#define M68K_CORE_H_
+#include <stdint.h>
+#include <stdio.h>
+#include "backend.h"
+//#include "68kinst.h"
+struct m68kinst;
+
+#define NUM_MEM_AREAS 4
+#define NATIVE_MAP_CHUNKS (64*1024)
+#define NATIVE_CHUNK_SIZE ((16 * 1024 * 1024 / NATIVE_MAP_CHUNKS)/2)
+#define MAX_NATIVE_SIZE 255
+
+typedef void (*start_fun)(uint8_t * addr, void * context);
+
+typedef struct {
+	cpu_options     gen;
+
+	int8_t          dregs[8];
+	int8_t          aregs[8];
+	int8_t			flag_regs[5];
+	FILE            *address_log;
+	code_ptr        read_16;
+	code_ptr        write_16;
+	code_ptr        read_8;
+	code_ptr        write_8;
+	code_ptr        read_32;
+	code_ptr        write_32_lowfirst;
+	code_ptr        write_32_highfirst;
+	code_ptr        do_sync;
+	code_ptr        trap;
+	start_fun       start_context;
+	code_ptr        retrans_stub;
+	code_ptr        native_addr;
+	code_ptr        native_addr_and_sync;
+	code_ptr		get_sr;
+	code_ptr		set_sr;
+	code_ptr		set_ccr;
+} m68k_options;
+
+typedef struct {
+	uint8_t         flags[5];
+	uint8_t         status;
+	uint16_t        int_ack;
+	uint32_t        dregs[8];
+	uint32_t        aregs[9];
+	uint32_t		target_cycle; //cycle at which the next synchronization or interrupt occurs
+	uint32_t		current_cycle;
+	uint32_t        sync_cycle;
+	uint32_t        int_cycle;
+	uint32_t        int_num;
+	uint16_t        *mem_pointers[NUM_MEM_AREAS];
+	void            *video_context;
+	uint16_t        reserved;
+
+	native_map_slot *native_code_map;
+	void            *options;
+	uint8_t         ram_code_flags[32/8];
+	void            *system;
+} m68k_context;
+
+void translate_m68k(m68k_options * opts, struct m68kinst * inst);
+void translate_m68k_stream(uint32_t address, m68k_context * context);
+void start_68k_context(m68k_context * context, uint32_t address);
+void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks);
+void init_68k_context(m68k_context * context, native_map_slot * native_code_map, void * opts);
+void m68k_reset(m68k_context * context);
+void insert_breakpoint(m68k_context * context, uint32_t address, uint8_t * bp_handler);
+void remove_breakpoint(m68k_context * context, uint32_t address);
+m68k_context * m68k_handle_code_write(uint32_t address, m68k_context * context);
+uint32_t get_instruction_start(native_map_slot * native_code_map, uint32_t address);
+
+#endif //M68K_CORE_H_
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m68k_core_x86.c	Tue Dec 30 19:11:34 2014 -0800
@@ -0,0 +1,2652 @@
+/*
+ Copyright 2013 Michael Pavone
+ This file is part of BlastEm.
+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
+*/
+#include "gen_x86.h"
+#include "m68k_core.h"
+#include "m68k_internal.h"
+#include "68kinst.h"
+#include "mem.h"
+#include "backend.h"
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define CYCLES RAX
+#define LIMIT RBP
+#define CONTEXT RSI
+#define SCRATCH1 RCX
+
+#ifdef X86_64
+#define SCRATCH2 RDI
+#else
+#define SCRATCH2 RBX
+#endif
+
+enum {
+	FLAG_X,
+	FLAG_N,
+	FLAG_Z,
+	FLAG_V,
+	FLAG_C
+};
+
+void set_flag(m68k_options * opts, uint8_t val, uint8_t flag)
+{
+	if (opts->flag_regs[flag] >= 0) {
+		mov_ir(&opts->gen.code, val, opts->flag_regs[flag], SZ_B);
+	} else {
+		int8_t offset = offsetof(m68k_context, flags) + flag;
+		if (offset) {
+			mov_irdisp(&opts->gen.code, val, opts->gen.context_reg, offset, SZ_B);
+		} else {
+			mov_irind(&opts->gen.code, val, opts->gen.context_reg, SZ_B);
+		}
+	}
+}
+
+void set_flag_cond(m68k_options *opts, uint8_t cond, uint8_t flag)
+{
+	if (opts->flag_regs[flag] >= 0) {
+		setcc_r(&opts->gen.code, cond, opts->flag_regs[flag]);
+	} else {
+		int8_t offset = offsetof(m68k_context, flags) + flag;
+		if (offset) {
+			setcc_rdisp(&opts->gen.code, cond, opts->gen.context_reg, offset);
+		} else {
+			setcc_rind(&opts->gen.code, cond, opts->gen.context_reg);
+		}
+	}
+}
+
+void check_flag(m68k_options *opts, uint8_t flag)
+{
+	if (opts->flag_regs[flag] >= 0) {
+		cmp_ir(&opts->gen.code, 0, opts->flag_regs[flag], SZ_B);
+	} else {
+		cmp_irdisp(&opts->gen.code, 0, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, SZ_B);
+	}
+}
+
+void flag_to_reg(m68k_options *opts, uint8_t flag, uint8_t reg)
+{
+	if (opts->flag_regs[flag] >= 0) {
+		mov_rr(&opts->gen.code, opts->flag_regs[flag], reg, SZ_B);
+	} else {
+		int8_t offset = offsetof(m68k_context, flags) + flag;
+		if (offset) {
+			mov_rdispr(&opts->gen.code, opts->gen.context_reg, offset, reg, SZ_B);
+		} else {
+			mov_rindr(&opts->gen.code, opts->gen.context_reg, reg, SZ_B);
+		}
+	}
+}
+
+void reg_to_flag(m68k_options *opts, uint8_t reg, uint8_t flag)
+{
+	if (opts->flag_regs[flag] >= 0) {
+		mov_rr(&opts->gen.code, reg, opts->flag_regs[flag], SZ_B);
+	} else {
+		int8_t offset = offsetof(m68k_context, flags) + flag;
+		if (offset) {
+			mov_rrdisp(&opts->gen.code, reg, opts->gen.context_reg, offset, SZ_B);
+		} else {
+			mov_rrind(&opts->gen.code, reg, opts->gen.context_reg, SZ_B);
+		}
+	}
+}
+
+void flag_to_flag(m68k_options *opts, uint8_t flag1, uint8_t flag2)
+{
+	code_info *code = &opts->gen.code;
+	if (opts->flag_regs[flag1] >= 0 && opts->flag_regs[flag2] >= 0) {
+		mov_rr(code, opts->flag_regs[flag1], opts->flag_regs[flag2], SZ_B);
+	} else if(opts->flag_regs[flag1] >= 0) {
+		mov_rrdisp(code, opts->flag_regs[flag1], opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B);
+	} else if (opts->flag_regs[flag2] >= 0) {
+		mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag1, opts->flag_regs[flag2], SZ_B);
+	} else {
+		push_r(code, opts->gen.scratch1);
+		mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag1, opts->gen.scratch1, SZ_B);
+		mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B);
+		pop_r(code, opts->gen.scratch1);
+	}
+}
+
+void update_flags(m68k_options *opts, uint32_t update_mask)
+{
+	uint8_t native_flags[] = {0, CC_S, CC_Z, CC_O, CC_C};
+	for (int8_t flag = FLAG_C; flag >= FLAG_X; --flag)
+	{
+		if (update_mask & X0 << (flag*3)) {
+			set_flag(opts, 0, flag);
+		} else if(update_mask & X1 << (flag*3)) {
+			set_flag(opts, 1, flag);
+		} else if(update_mask & X << (flag*3)) {
+			if (flag == FLAG_X) {
+				if (opts->flag_regs[FLAG_C] >= 0 || !(update_mask & (C0|C1|C))) {
+					flag_to_flag(opts, FLAG_C, FLAG_X);
+				} else if(update_mask & C0) {
+					set_flag(opts, 0, flag);
+				} else if(update_mask & C1) {
+					set_flag(opts, 1, flag);
+				} else {
+					set_flag_cond(opts, CC_C, flag);
+				}
+			} else {
+				set_flag_cond(opts, native_flags[flag], flag);
+			}
+		}
+	}
+}
+
+void flag_to_carry(m68k_options * opts, uint8_t flag)
+{
+	if (opts->flag_regs[flag] >= 0) {
+		bt_ir(&opts->gen.code, 0, opts->flag_regs[flag], SZ_B);
+	} else {
+		bt_irdisp(&opts->gen.code, 0, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, SZ_B);
+	}
+}
+
+void or_flag_to_reg(m68k_options *opts, uint8_t flag, uint8_t reg)
+{
+	if (opts->flag_regs[flag] >= 0) {
+		or_rr(&opts->gen.code, opts->flag_regs[flag], reg, SZ_B);
+	} else {
+		or_rdispr(&opts->gen.code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, reg, SZ_B);
+	}
+}
+
+void xor_flag_to_reg(m68k_options *opts, uint8_t flag, uint8_t reg)
+{
+	if (opts->flag_regs[flag] >= 0) {
+		xor_rr(&opts->gen.code, opts->flag_regs[flag], reg, SZ_B);
+	} else {
+		xor_rdispr(&opts->gen.code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, reg, SZ_B);
+	}
+}
+
+void xor_flag(m68k_options *opts, uint8_t val, uint8_t flag)
+{
+	if (opts->flag_regs[flag] >= 0) {
+		xor_ir(&opts->gen.code, val, opts->flag_regs[flag], SZ_B);
+	} else {
+		xor_irdisp(&opts->gen.code, val, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, SZ_B);
+	}
+}
+
+void cmp_flags(m68k_options *opts, uint8_t flag1, uint8_t flag2)
+{
+	code_info *code = &opts->gen.code;
+	if (opts->flag_regs[flag1] >= 0 && opts->flag_regs[flag2] >= 0) {
+		cmp_rr(code, opts->flag_regs[flag1], opts->flag_regs[flag2], SZ_B);
+	} else if(opts->flag_regs[flag1] >= 0 || opts->flag_regs[flag2] >= 0) {
+		if (opts->flag_regs[flag2] >= 0) {
+			uint8_t tmp = flag1;
+			flag1 = flag2;
+			flag2 = tmp;
+		}
+		cmp_rrdisp(code, opts->flag_regs[flag1], opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B);
+	} else {
+		mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag1, opts->gen.scratch1, SZ_B);
+		cmp_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B);
+	}
+}
+
+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_native(m68k_options *opts, int32_t value, uint8_t reg)
+{
+	add_ir(&opts->gen.code, value, reg, SZ_D);
+}
+
+void subi_native(m68k_options *opts, int32_t value, uint8_t reg)
+{
+	sub_ir(&opts->gen.code, value, reg, SZ_D);
+}
+
+void push_native(m68k_options *opts, uint8_t reg)
+{
+	push_r(&opts->gen.code, reg);
+}
+
+void pop_native(m68k_options *opts, uint8_t reg)
+{
+	pop_r(&opts->gen.code, reg);
+}
+
+void sign_extend16_native(m68k_options *opts, uint8_t reg)
+{
+	movsx_rr(&opts->gen.code, reg, reg, SZ_W, 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, host_ea * ea, m68k_options * opts, uint8_t dst)
+{
+	code_info *code = &opts->gen.code;
+	m68k_op_info *op = dst ? &inst->dst : &inst->src;
+	int8_t reg = native_reg(op, opts);
+	uint8_t sec_reg;
+	int32_t dec_amount,inc_amount;
+	if (reg >= 0) {
+		ea->mode = MODE_REG_DIRECT;
+		if (!dst && inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) {
+			movsx_rr(code, reg, opts->gen.scratch1, SZ_W, SZ_D);
+			ea->base = opts->gen.scratch1;
+		} else {
+			ea->base = reg;
+		}
+		return;
+	}
+	switch (op->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 if we're translating the src operand
+		if (dst || native_reg(&(inst->dst), opts) >= 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 = opts->gen.context_reg;
+			ea->disp = reg_offset(op);
+		} else {
+			if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) {
+				movsx_rdispr(code, opts->gen.context_reg, reg_offset(op), opts->gen.scratch1, SZ_W, SZ_D);
+			} else {
+				mov_rdispr(code, opts->gen.context_reg, reg_offset(op), opts->gen.scratch1, inst->extra.size);
+			}
+			ea->mode = MODE_REG_DIRECT;
+			ea->base = opts->gen.scratch1;
+			//we're explicitly handling the areg dest here, so we exit immediately
+			return;
+		}
+		break;
+	case MODE_AREG_PREDEC:
+		if (dst && inst->src.addr_mode == MODE_AREG_PREDEC) {
+			push_r(code, opts->gen.scratch1);
+		}
+		dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (op->params.regs.pri == 7 ? 2 :1));
+		if (!dst) {
+			cycles(&opts->gen, PREDEC_PENALTY);
+		}
+		subi_areg(opts, dec_amount, op->params.regs.pri);
+	case MODE_AREG_INDIRECT:
+	case MODE_AREG_POSTINC:
+		areg_to_native(opts, op->params.regs.pri, opts->gen.scratch1);
+		m68k_read_size(opts, inst->extra.size);
+
+		if (dst) {
+			if (inst->src.addr_mode == MODE_AREG_PREDEC) {
+				//restore src operand to opts->gen.scratch2
+				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
+				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));
+			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);
+		calc_areg_displace(opts, op, opts->gen.scratch1);
+		if (dst) {
+			push_r(code, opts->gen.scratch1);
+		}
+		m68k_read_size(opts, inst->extra.size);
+		if (dst) {
+			pop_r(code, opts->gen.scratch2);
+		}
+
+		ea->mode = MODE_REG_DIRECT;
+		ea->base = opts->gen.scratch1;
+		break;
+	case MODE_AREG_INDEX_DISP8:
+		cycles(&opts->gen, 6);
+		calc_areg_index_disp8(opts, op, opts->gen.scratch1);
+		if (dst) {
+			push_r(code, opts->gen.scratch1);
+		}
+		m68k_read_size(opts, inst->extra.size);
+		if (dst) {
+			pop_r(code, opts->gen.scratch2);
+		}
+
+		ea->mode = MODE_REG_DIRECT;
+		ea->base = opts->gen.scratch1;
+		break;
+	case MODE_PC_DISPLACE:
+		cycles(&opts->gen, BUS);
+		mov_ir(code, op->params.regs.displacement + inst->address+2, opts->gen.scratch1, SZ_D);
+		if (dst) {
+			push_r(code, opts->gen.scratch1);
+		}
+		m68k_read_size(opts, inst->extra.size);
+		if (dst) {
+			pop_r(code, opts->gen.scratch2);
+		}
+
+		ea->mode = MODE_REG_DIRECT;
+		ea->base = opts->gen.scratch1;
+		break;
+	case MODE_PC_INDEX_DISP8:
+		cycles(&opts->gen, 6);
+		mov_ir(code, inst->address+2, opts->gen.scratch1, SZ_D);
+		calc_index_disp8(opts, op, opts->gen.scratch1);
+		if (dst) {
+			push_r(code, opts->gen.scratch1);
+		}
+		m68k_read_size(opts, inst->extra.size);
+		if (dst) {
+			pop_r(code, opts->gen.scratch2);
+		}
+
+		ea->mode = MODE_REG_DIRECT;
+		ea->base = opts->gen.scratch1;
+		break;
+	case MODE_ABSOLUTE:
+	case MODE_ABSOLUTE_SHORT:
+		cycles(&opts->gen, op->addr_mode == MODE_ABSOLUTE ? BUS*2 : BUS);
+		mov_ir(code, op->params.immed, opts->gen.scratch1, SZ_D);
+		if (dst) {
+			push_r(code, opts->gen.scratch1);
+		}
+		m68k_read_size(opts, inst->extra.size);
+		if (dst) {
+			pop_r(code, opts->gen.scratch2);
+		}
+
+		ea->mode = MODE_REG_DIRECT;
+		ea->base = opts->gen.scratch1;
+		break;
+	case MODE_IMMEDIATE:
+	case MODE_IMMEDIATE_WORD:
+		if (inst->variant != VAR_QUICK) {
+			cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG && op->addr_mode == MODE_IMMEDIATE) ? BUS*2 : BUS);
+		}
+		ea->mode = MODE_IMMED;
+		ea->disp = op->params.immed;
+		//sign extend value when the destination is an address register
+		if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD && ea->disp & 0x8000) {
+			ea->disp |= 0xFFFF0000;
+		}
+		return;
+	default:
+		m68k_disasm(inst, disasm_buf);
+		printf("%X: %s\naddress mode %d not implemented (%s)\n", inst->address, disasm_buf, op->addr_mode, dst ? "dst" : "src");
+		exit(1);
+	}
+	if (!dst && inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) {
+		if (ea->mode == MODE_REG_DIRECT) {
+			movsx_rr(code, ea->base, opts->gen.scratch1, SZ_W, SZ_D);
+		} else {
+			movsx_rdispr(code, ea->base, ea->disp, opts->gen.scratch1, SZ_W, SZ_D);
+			ea->mode = MODE_REG_DIRECT;
+		}
+		ea->base = opts->gen.scratch1;
+	}
+}
+
+void m68k_save_result(m68kinst * inst, m68k_options * opts)
+{
+	code_info *code = &opts->gen.code;
+	if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG && inst->dst.addr_mode != MODE_UNUSED) {
+		if (inst->dst.addr_mode == MODE_AREG_PREDEC && inst->src.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) {
+			areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2);
+		}
+		switch (inst->extra.size)
+		{
+		case OPSIZE_BYTE:
+			call(code, opts->write_8);
+			break;
+		case OPSIZE_WORD:
+			call(code, opts->write_16);
+			break;
+		case OPSIZE_LONG:
+			call(code, opts->write_32_lowfirst);
+			break;
+		}
+	}
+}
+
+void translate_m68k_move(m68k_options * opts, m68kinst * inst)
+{
+	code_info *code = &opts->gen.code;
+	int8_t reg, flags_reg, sec_reg;
+	uint8_t dir = 0;
+	int32_t offset;
+	int32_t inc_amount, dec_amount;
+	host_ea src;
+	translate_m68k_op(inst, &src, opts, 0);
+	reg = native_reg(&(inst->dst), opts);
+
+	if (inst->dst.addr_mode != MODE_AREG) {
+		if (src.mode == MODE_REG_DIRECT) {
+			flags_reg = src.base;
+		} else {
+			if (reg >= 0) {
+				flags_reg = reg;
+			} else {
+				if(src.mode == MODE_REG_DISPLACE8) {
+					mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
+				} else {
+					mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
+				}
+				src.mode = MODE_REG_DIRECT;
+				flags_reg = src.base = opts->gen.scratch1;
+			}
+		}
+	}
+	uint8_t size = inst->extra.size;
+	switch(inst->dst.addr_mode)
+	{
+	case MODE_AREG:
+		size = OPSIZE_LONG;
+	case MODE_REG:
+		if (reg >= 0) {
+			if (src.mode == MODE_REG_DIRECT) {
+				mov_rr(code, src.base, reg, size);
+			} else if (src.mode == MODE_REG_DISPLACE8) {
+				mov_rdispr(code, src.base, src.disp, reg, size);
+			} else {
+				mov_ir(code, src.disp, reg, size);
+			}
+		} else if(src.mode == MODE_REG_DIRECT) {
+			mov_rrdisp(code, src.base, opts->gen.context_reg, reg_offset(&(inst->dst)), size);
+		} else {
+			mov_irdisp(code, src.disp, opts->gen.context_reg, reg_offset(&(inst->dst)), size);
+		}
+		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));
+	case MODE_AREG_INDIRECT:
+	case MODE_AREG_POSTINC:
+		if (src.mode == MODE_REG_DIRECT) {
+			if (src.base != opts->gen.scratch1) {
+				mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
+			}
+		} else if (src.mode == MODE_REG_DISPLACE8) {
+			mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
+		} else {
+			mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
+		}
+		if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
+			subi_areg(opts, dec_amount, inst->dst.params.regs.pri);
+		}
+		areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2);
+		break;
+	case MODE_AREG_DISPLACE:
+		cycles(&opts->gen, BUS);
+		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);
+			}
+		} else if (src.mode == MODE_REG_DISPLACE8) {
+			mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
+		} else {
+			mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
+		}
+		break;
+	case MODE_AREG_INDEX_DISP8:
+		cycles(&opts->gen, 6);//TODO: Check to make sure this is correct
+		//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);
+		}
+		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) {
+				mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
+			}
+		} else if (src.mode == MODE_REG_DISPLACE8) {
+			mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
+		} else {
+			mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
+		}
+		break;
+	case MODE_PC_DISPLACE:
+		cycles(&opts->gen, BUS);
+		mov_ir(code, inst->dst.params.regs.displacement + inst->address+2, opts->gen.scratch2, SZ_D);
+		if (src.mode == MODE_REG_DIRECT) {
+			if (src.base != opts->gen.scratch1) {
+				mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
+			}
+		} else if (src.mode == MODE_REG_DISPLACE8) {
+			mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
+		} else {
+			mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
+		}
+		break;
+	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);
+		if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) {
+			push_r(code, opts->gen.scratch1);
+		}
+		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) {
+				mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
+			}
+		} else if (src.mode == MODE_REG_DISPLACE8) {
+			mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
+		} else {
+			mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
+		}
+		break;
+	case MODE_ABSOLUTE:
+	case MODE_ABSOLUTE_SHORT:
+		if (src.mode == MODE_REG_DIRECT) {
+			if (src.base != opts->gen.scratch1) {
+				mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
+			}
+		} else if (src.mode == MODE_REG_DISPLACE8) {
+			mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
+		} else {
+			mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
+		}
+		if (inst->dst.addr_mode == MODE_ABSOLUTE) {
+			cycles(&opts->gen, BUS*2);
+		} else {
+			cycles(&opts->gen, BUS);
+		}
+		mov_ir(code, inst->dst.params.immed, opts->gen.scratch2, SZ_D);
+		break;
+	default:
+		m68k_disasm(inst, disasm_buf);
+		printf("%X: %s\naddress mode %d not implemented (move dst)\n", inst->address, disasm_buf, inst->dst.addr_mode);
+		exit(1);
+	}
+
+	if (inst->dst.addr_mode != MODE_AREG) {
+		cmp_ir(code, 0, flags_reg, inst->extra.size);
+		update_flags(opts, N|Z|V0|C0);
+	}
+	if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG) {
+		m68k_write_size(opts, inst->extra.size);
+		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));
+			addi_areg(opts, inc_amount, inst->dst.params.regs.pri);
+		}
+	}
+
+	//add cycles for prefetch
+	cycles(&opts->gen, BUS);
+}
+
+void translate_m68k_clr(m68k_options * opts, m68kinst * inst)
+{
+	code_info *code = &opts->gen.code;
+	update_flags(opts, N0|V0|C0|Z1);
+	int8_t reg = native_reg(&(inst->dst), opts);
+	if (reg >= 0) {
+		cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 6 : 4));
+		xor_rr(code, reg, reg, inst->extra.size);
+		return;
+	}
+	host_ea dst_op;
+	//TODO: fix timing
+	translate_m68k_op(inst, &dst_op, opts, 1);
+	if (dst_op.mode == MODE_REG_DIRECT) {
+		xor_rr(code, dst_op.base, dst_op.base, inst->extra.size);
+	} else {
+		mov_irdisp(code, 0, dst_op.base, dst_op.disp, inst->extra.size);
+	}
+	m68k_save_result(inst, opts);
+}
+
+void translate_m68k_ext(m68k_options * opts, m68kinst * inst)
+{
+	code_info *code = &opts->gen.code;
+	host_ea dst_op;
+	uint8_t dst_size = inst->extra.size;
+	inst->extra.size--;
+	translate_m68k_op(inst, &dst_op, opts, 1);
+	if (dst_op.mode == MODE_REG_DIRECT) {
+		movsx_rr(code, dst_op.base, dst_op.base, inst->extra.size, dst_size);
+		cmp_ir(code, 0, dst_op.base, dst_size);
+	} else {
+		movsx_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, inst->extra.size, dst_size);
+		cmp_ir(code, 0, opts->gen.scratch1, dst_size);
+		mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, dst_size);
+	}
+	inst->extra.size = dst_size;
+	update_flags(opts, N|V0|C0|Z);
+	//M68K EXT only operates on registers so no need for a call to save result here
+}
+
+uint8_t m68k_eval_cond(m68k_options * opts, uint8_t cc)
+{
+	uint8_t cond = CC_NZ;
+	switch (cc)
+	{
+	case COND_HIGH:
+		cond = CC_Z;
+	case COND_LOW_SAME:
+		flag_to_reg(opts, FLAG_Z, opts->gen.scratch1);
+		or_flag_to_reg(opts, FLAG_C, opts->gen.scratch1);
+		break;
+	case COND_CARRY_CLR:
+		cond = CC_Z;
+	case COND_CARRY_SET:
+		check_flag(opts, FLAG_C);
+		break;
+	case COND_NOT_EQ:
+		cond = CC_Z;
+	case COND_EQ:
+		check_flag(opts, FLAG_Z);
+		break;
+	case COND_OVERF_CLR:
+		cond = CC_Z;
+	case COND_OVERF_SET:
+		check_flag(opts, FLAG_V);
+		break;
+	case COND_PLUS:
+		cond = CC_Z;
+	case COND_MINUS:
+		check_flag(opts, FLAG_N);
+		break;
+	case COND_GREATER_EQ:
+		cond = CC_Z;
+	case COND_LESS:
+		cmp_flags(opts, FLAG_N, FLAG_V);
+		break;
+	case COND_GREATER:
+		cond = CC_Z;
+	case COND_LESS_EQ:
+		flag_to_reg(opts, FLAG_V, opts->gen.scratch1);
+		xor_flag_to_reg(opts, FLAG_N, opts->gen.scratch1);
+		or_flag_to_reg(opts, FLAG_Z, opts->gen.scratch1);
+		break;
+	}
+	return cond;
+}
+
+void translate_m68k_bcc(m68k_options * opts, m68kinst * inst)
+{
+	code_info *code = &opts->gen.code;
+	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;
+	if (inst->extra.cond == COND_TRUE) {
+		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);
+			//dummy address to be replaced later, make sure it generates a 4-byte displacement
+			dest_addr = code->cur + 256;
+		}
+		jcc(code, cond, dest_addr);
+	}
+}
+
+void translate_m68k_scc(m68k_options * opts, m68kinst * inst)
+{
+	code_info *code = &opts->gen.code;
+	uint8_t cond = inst->extra.cond;
+	host_ea dst_op;
+	inst->extra.size = OPSIZE_BYTE;
+	translate_m68k_op(inst, &dst_op, opts, 1);
+	if (cond == COND_TRUE || cond == COND_FALSE) {
+		if ((inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG) && inst->extra.cond == COND_TRUE) {
+			cycles(&opts->gen, 6);
+		} else {
+			cycles(&opts->gen, BUS);
+		}
+		if (dst_op.mode == MODE_REG_DIRECT) {
+			mov_ir(code, cond == COND_TRUE ? 0xFF : 0, dst_op.base, SZ_B);
+		} else {
+			mov_irdisp(code, cond == COND_TRUE ? 0xFF : 0, dst_op.base, dst_op.disp, SZ_B);
+		}
+	} else {
+		uint8_t cc = m68k_eval_cond(opts, cond);
+		check_alloc_code(code, 6*MAX_INST_LEN);
+		code_ptr true_off = code->cur + 1;
+		jcc(code, cc, code->cur+2);
+		cycles(&opts->gen, BUS);
+		if (dst_op.mode == MODE_REG_DIRECT) {
+			mov_ir(code, 0, dst_op.base, SZ_B);
+		} else {
+			mov_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B);
+		}
+		code_ptr end_off = code->cur+1;
+		jmp(code, code->cur+2);
+		*true_off = code->cur - (true_off+1);
+		cycles(&opts->gen, 6);
+		if (dst_op.mode == MODE_REG_DIRECT) {
+			mov_ir(code, 0xFF, dst_op.base, SZ_B);
+		} else {
+			mov_irdisp(code, 0xFF, dst_op.base, dst_op.disp, SZ_B);
+		}
+		*end_off = code->cur - (end_off+1);
+	}
+	m68k_save_result(inst, opts);
+}
+
+void translate_m68k_dbcc(m68k_options * opts, m68kinst * inst)
+{
+	code_info *code = &opts->gen.code;
+	//best case duration
+	cycles(&opts->gen, 10);
+	code_ptr skip_loc = NULL;
+	//TODO: Check if COND_TRUE technically valid here even though
+	//it's basically a slow NOP
+	if (inst->extra.cond != COND_FALSE) {
+		uint8_t cond = m68k_eval_cond(opts, inst->extra.cond);
+		check_alloc_code(code, 6*MAX_INST_LEN);
+		skip_loc = code->cur + 1;
+		jcc(code, cond, code->cur + 2);
+	}
+	if (opts->dregs[inst->dst.params.regs.pri] >= 0) {
+		sub_ir(code, 1, opts->dregs[inst->dst.params.regs.pri], SZ_W);
+		cmp_ir(code, -1, opts->dregs[inst->dst.params.regs.pri], SZ_W);
+	} else {
+		sub_irdisp(code, 1, opts->gen.context_reg, offsetof(m68k_context, dregs) + 4 * inst->dst.params.regs.pri, SZ_W);
+		cmp_irdisp(code, -1, opts->gen.context_reg, offsetof(m68k_context, dregs) + 4 * inst->dst.params.regs.pri, SZ_W);
+	}
+	code_ptr loop_end_loc = code->cur + 1;
+	jcc(code, CC_Z, code->cur + 2);
+	uint32_t after = inst->address + 2;
+	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);
+		*skip_loc = code->cur - (skip_loc+1);
+		cycles(&opts->gen, 2);
+	} else {
+		cycles(&opts->gen, 4);
+	}
+}
+
+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) {
+		calc_areg_displace(opts, &inst->dst, opts->gen.scratch2);
+		reg = native_reg(&(inst->src), opts);
+		if (inst->extra.size == OPSIZE_LONG) {
+			if (reg >= 0) {
+				mov_rr(code, reg, opts->gen.scratch1, SZ_D);
+				shr_ir(code, 24, opts->gen.scratch1, SZ_D);
+				push_r(code, opts->gen.scratch2);
+				call(code, opts->write_8);
+				pop_r(code, opts->gen.scratch2);
+				mov_rr(code, reg, opts->gen.scratch1, SZ_D);
+				shr_ir(code, 16, opts->gen.scratch1, SZ_D);
+
+			} else {
+				mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src))+3, opts->gen.scratch1, SZ_B);
+				push_r(code, opts->gen.scratch2);
+				call(code, opts->write_8);
+				pop_r(code, opts->gen.scratch2);
+				mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src))+2, opts->gen.scratch1, SZ_B);
+			}
+			add_ir(code, 2, opts->gen.scratch2, SZ_D);
+			push_r(code, opts->gen.scratch2);
+			call(code, opts->write_8);
+			pop_r(code, opts->gen.scratch2);
+			add_ir(code, 2, opts->gen.scratch2, SZ_D);
+		}
+		if (reg >= 0) {
+			mov_rr(code, reg, opts->gen.scratch1, SZ_W);
+			shr_ir(code, 8, opts->gen.scratch1, SZ_W);
+			push_r(code, opts->gen.scratch2);
+			call(code, opts->write_8);
+			pop_r(code, opts->gen.scratch2);
+			mov_rr(code, reg, opts->gen.scratch1, SZ_W);
+		} else {
+			mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src))+1, opts->gen.scratch1, SZ_B);
+			push_r(code, opts->gen.scratch2);
+			call(code, opts->write_8);
+			pop_r(code, opts->gen.scratch2);
+			mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src)), opts->gen.scratch1, SZ_B);
+		}
+		add_ir(code, 2, opts->gen.scratch2, SZ_D);
+		call(code, opts->write_8);
+	} else {
+		calc_areg_displace(opts, &inst->src, opts->gen.scratch1);
+		reg = native_reg(&(inst->dst), opts);
+		if (inst->extra.size == OPSIZE_LONG) {
+			if (reg >= 0) {
+				push_r(code, opts->gen.scratch1);
+				call(code, opts->read_8);
+				shl_ir(code, 24, opts->gen.scratch1, SZ_D);
+				mov_rr(code, opts->gen.scratch1, reg, SZ_D);
+				pop_r(code, opts->gen.scratch1);
+				add_ir(code, 2, opts->gen.scratch1, SZ_D);
+				push_r(code, opts->gen.scratch1);
+				call(code, opts->read_8);
+				shl_ir(code, 16, opts->gen.scratch1, SZ_D);
+				or_rr(code, opts->gen.scratch1, reg, SZ_D);
+			} else {
+				push_r(code, opts->gen.scratch1);
+				call(code, opts->read_8);
+				mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst))+3, SZ_B);
+				pop_r(code, opts->gen.scratch1);
+				add_ir(code, 2, opts->gen.scratch1, SZ_D);
+				push_r(code, opts->gen.scratch1);
+				call(code, opts->read_8);
+				mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst))+2, SZ_B);
+			}
+			pop_r(code, opts->gen.scratch1);
+			add_ir(code, 2, opts->gen.scratch1, SZ_D);
+		}
+		push_r(code, opts->gen.scratch1);
+		call(code, opts->read_8);
+		if (reg >= 0) {
+
+			shl_ir(code, 8, opts->gen.scratch1, SZ_W);
+			mov_rr(code, opts->gen.scratch1, reg, SZ_W);
+			pop_r(code, opts->gen.scratch1);
+			add_ir(code, 2, opts->gen.scratch1, SZ_D);
+			call(code, opts->read_8);
+			mov_rr(code, opts->gen.scratch1, reg, SZ_B);
+		} else {
+			mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst))+1, SZ_B);
+			pop_r(code, opts->gen.scratch1);
+			add_ir(code, 2, opts->gen.scratch1, SZ_D);
+			call(code, opts->read_8);
+			mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst)), SZ_B);
+		}
+	}
+}
+
+typedef void (*shift_ir_t)(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
+typedef void (*shift_irdisp_t)(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size);
+typedef void (*shift_clr_t)(code_info *code, uint8_t dst, uint8_t size);
+typedef void (*shift_clrdisp_t)(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
+
+void translate_shift(m68k_options * opts, m68kinst * inst, host_ea *src_op, host_ea * dst_op, shift_ir_t shift_ir, shift_irdisp_t shift_irdisp, shift_clr_t shift_clr, shift_clrdisp_t shift_clrdisp, shift_ir_t special, shift_irdisp_t special_disp)
+{
+	code_info *code = &opts->gen.code;
+	code_ptr end_off = NULL;
+	code_ptr nz_off = NULL;
+	code_ptr z_off = NULL;
+	if (inst->src.addr_mode == MODE_UNUSED) {
+		cycles(&opts->gen, BUS);
+		//Memory shift
+		shift_ir(code, 1, dst_op->base, SZ_W);
+	} else {
+		cycles(&opts->gen, inst->extra.size == OPSIZE_LONG ? 8 : 6);
+		if (src_op->mode == MODE_IMMED) {
+			if (src_op->disp != 1 && inst->op == M68K_ASL) {
+				set_flag(opts, 0, FLAG_V);
+				for (int i = 0; i < src_op->disp; i++) {
+					if (dst_op->mode == MODE_REG_DIRECT) {
+						shift_ir(code, 1, dst_op->base, inst->extra.size);
+					} else {
+						shift_irdisp(code, 1, dst_op->base, dst_op->disp, inst->extra.size);
+					}
+					check_alloc_code(code, 2*MAX_INST_LEN);
+					code_ptr after_flag_set = code->cur + 1;
+					jcc(code, CC_NO, code->cur + 2);
+					set_flag(opts, 1, FLAG_V);
+					*after_flag_set = code->cur - (after_flag_set+1);
+				}
+			} else {
+				if (dst_op->mode == MODE_REG_DIRECT) {
+					shift_ir(code, src_op->disp, dst_op->base, inst->extra.size);
+				} else {
+					shift_irdisp(code, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size);
+				}
+				set_flag_cond(opts, CC_O, FLAG_V);
+			}
+		} else {
+			if (src_op->base != RCX) {
+				if (src_op->mode == MODE_REG_DIRECT) {
+					mov_rr(code, src_op->base, RCX, SZ_B);
+				} else {
+					mov_rdispr(code, src_op->base, src_op->disp, RCX, SZ_B);
+				}
+
+			}
+			and_ir(code, 63, RCX, SZ_D);
+			check_alloc_code(code, 7*MAX_INST_LEN);
+			nz_off = code->cur + 1;
+			jcc(code, CC_NZ, code->cur + 2);
+			//Flag behavior for shift count of 0 is different for x86 than 68K
+			if (dst_op->mode == MODE_REG_DIRECT) {
+				cmp_ir(code, 0, dst_op->base, inst->extra.size);
+			} else {
+				cmp_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size);
+			}
+			set_flag_cond(opts, CC_Z, FLAG_Z);
+			set_flag_cond(opts, CC_S, FLAG_N);
+			set_flag(opts, 0, FLAG_C);
+			//For other instructions, this flag will be set below
+			if (inst->op == M68K_ASL) {
+				set_flag(opts, 0, FLAG_V);
+			}
+			z_off = code->cur + 1;
+			jmp(code, code->cur + 2);
+			*nz_off = code->cur - (nz_off + 1);
+			//add 2 cycles for every bit shifted
+			add_rr(code, RCX, CYCLES, SZ_D);
+			add_rr(code, RCX, CYCLES, SZ_D);
+			if (inst->op == M68K_ASL) {
+				//ASL has Overflow flag behavior that depends on all of the bits shifted through the MSB
+				//Easiest way to deal with this is to shift one bit at a time
+				set_flag(opts, 0, FLAG_V);
+				check_alloc_code(code, 5*MAX_INST_LEN);
+				code_ptr loop_start = code->cur;
+				if (dst_op->mode == MODE_REG_DIRECT) {
+					shift_ir(code, 1, dst_op->base, inst->extra.size);
+				} else {
+					shift_irdisp(code, 1, dst_op->base, dst_op->disp, inst->extra.size);
+				}
+				code_ptr after_flag_set = code->cur + 1;
+				jcc(code, CC_NO, code->cur + 2);
+				set_flag(opts, 1, FLAG_V);
+				*after_flag_set = code->cur - (after_flag_set+1);
+				loop(code, loop_start);
+			} else {
+				//x86 shifts modulo 32 for operand sizes less than 64-bits
+				//but M68K shifts modulo 64, so we need to check for large shifts here
+				cmp_ir(code, 32, RCX, SZ_B);
+				check_alloc_code(code, 14*MAX_INST_LEN);
+				code_ptr norm_shift_off = code->cur + 1;
+				jcc(code, CC_L, code->cur + 2);
+				if (special) {
+					code_ptr after_flag_set = NULL;
+					if (inst->extra.size == OPSIZE_LONG) {
+						code_ptr neq_32_off = code->cur + 1;
+						jcc(code, CC_NZ, code->cur + 2);
+
+						//set the carry bit to the lsb
+						if (dst_op->mode == MODE_REG_DIRECT) {
+							special(code, 1, dst_op->base, SZ_D);
+						} else {
+							special_disp(code, 1, dst_op->base, dst_op->disp, SZ_D);
+						}
+						set_flag_cond(opts, CC_C, FLAG_C);
+						after_flag_set = code->cur + 1;
+						jmp(code, code->cur + 2);
+						*neq_32_off = code->cur - (neq_32_off+1);
+					}
+					set_flag(opts, 0, FLAG_C);
+					if (after_flag_set) {
+						*after_flag_set = code->cur - (after_flag_set+1);
+					}
+					set_flag(opts, 1, FLAG_Z);
+					set_flag(opts, 0, FLAG_N);
+					if (dst_op->mode == MODE_REG_DIRECT) {
+						xor_rr(code, dst_op->base, dst_op->base, inst->extra.size);
+					} else {
+						mov_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size);
+					}
+				} else {
+					if (dst_op->mode == MODE_REG_DIRECT) {
+						shift_ir(code, 31, dst_op->base, inst->extra.size);
+						shift_ir(code, 1, dst_op->base, inst->extra.size);
+					} else {
+						shift_irdisp(code, 31, dst_op->base, dst_op->disp, inst->extra.size);
+						shift_irdisp(code, 1, dst_op->base, dst_op->disp, inst->extra.size);
+					}
+
+				}
+				end_off = code->cur + 1;
+				jmp(code, code->cur + 2);
+				*norm_shift_off = code->cur - (norm_shift_off+1);
+				if (dst_op->mode == MODE_REG_DIRECT) {
+					shift_clr(code, dst_op->base, inst->extra.size);
+				} else {
+					shift_clrdisp(code, dst_op->base, dst_op->disp, inst->extra.size);
+				}
+			}
+		}
+
+	}
+	if (!special && end_off) {
+		*end_off = code->cur - (end_off + 1);
+	}
+	update_flags(opts, C|Z|N);
+	if (special && end_off) {
+		*end_off = code->cur - (end_off + 1);
+	}
+	//set X flag to same as C flag
+	if (opts->flag_regs[FLAG_C] >= 0) {
+		flag_to_flag(opts, FLAG_C, FLAG_X);
+	} else {
+		set_flag_cond(opts, CC_C, FLAG_X);
+	}
+	if (z_off) {
+		*z_off = code->cur - (z_off + 1);
+	}
+	if (inst->op != M68K_ASL) {
+		set_flag(opts, 0, FLAG_V);
+	}
+	if (inst->src.addr_mode == MODE_UNUSED) {
+		m68k_save_result(inst, opts);
+	}
+}
+
+void op_ir(code_info *code, m68kinst *inst, int32_t val, uint8_t dst, uint8_t size)
+{
+	switch (inst->op)
+	{
+	case M68K_ADD:  add_ir(code, val, dst, size); break;
+	case M68K_ADDX: adc_ir(code, val, dst, size); break;
+	case M68K_AND:  and_ir(code, val, dst, size); break;
+	case M68K_BTST: bt_ir(code, val, dst, size); break;
+	case M68K_BSET: bts_ir(code, val, dst, size); break;
+	case M68K_BCLR: btr_ir(code, val, dst, size); break;
+	case M68K_BCHG: btc_ir(code, val, dst, size); break;
+	case M68K_CMP:  cmp_ir(code, val, dst, size); break;
+	case M68K_EOR:  xor_ir(code, val, dst, size); break;
+	case M68K_OR:   or_ir(code, val, dst, size); break;
+	case M68K_ROL:  rol_ir(code, val, dst, size); break;
+	case M68K_ROR:  ror_ir(code, val, dst, size); break;
+	case M68K_ROXL: rcl_ir(code, val, dst, size); break;
+	case M68K_ROXR: rcr_ir(code, val, dst, size); break;
+	case M68K_SUB:  sub_ir(code, val, dst, size); break;
+	case M68K_SUBX: sbb_ir(code, val, dst, size); break;
+	}
+}
+
+void op_irdisp(code_info *code, m68kinst *inst, int32_t val, uint8_t dst, int32_t disp, uint8_t size)
+{
+	switch (inst->op)
+	{
+	case M68K_ADD:  add_irdisp(code, val, dst, disp, size); break;
+	case M68K_ADDX: adc_irdisp(code, val, dst, disp, size); break;
+	case M68K_AND:  and_irdisp(code, val, dst, disp, size); break;
+	case M68K_BTST: bt_irdisp(code, val, dst, disp, size); break;
+	case M68K_BSET: bts_irdisp(code, val, dst, disp, size); break;
+	case M68K_BCLR: btr_irdisp(code, val, dst, disp, size); break;
+	case M68K_BCHG: btc_irdisp(code, val, dst, disp, size); break;
+	case M68K_CMP:  cmp_irdisp(code, val, dst, disp, size); break;
+	case M68K_EOR:  xor_irdisp(code, val, dst, disp, size); break;
+	case M68K_OR:   or_irdisp(code, val, dst, disp, size); break;
+	case M68K_ROL:  rol_irdisp(code, val, dst, disp, size); break;
+	case M68K_ROR:  ror_irdisp(code, val, dst, disp, size); break;
+	case M68K_ROXL: rcl_irdisp(code, val, dst, disp, size); break;
+	case M68K_ROXR: rcr_irdisp(code, val, dst, disp, size); break;
+	case M68K_SUB:  sub_irdisp(code, val, dst, disp, size); break;
+	case M68K_SUBX: sbb_irdisp(code, val, dst, disp, size); break;
+	}
+}
+
+void op_rr(code_info *code, m68kinst *inst, uint8_t src, uint8_t dst, uint8_t size)
+{
+	switch (inst->op)
+	{
+	case M68K_ADD:  add_rr(code, src, dst, size); break;
+	case M68K_ADDX: adc_rr(code, src, dst, size); break;
+	case M68K_AND:  and_rr(code, src, dst, size); break;
+	case M68K_BTST: bt_rr(code, src, dst, size); break;
+	case M68K_BSET: bts_rr(code, src, dst, size); break;
+	case M68K_BCLR: btr_rr(code, src, dst, size); break;
+	case M68K_BCHG: btc_rr(code, src, dst, size); break;
+	case M68K_CMP:  cmp_rr(code, src, dst, size); break;
+	case M68K_EOR:  xor_rr(code, src, dst, size); break;
+	case M68K_OR:   or_rr(code, src, dst, size); break;
+	case M68K_SUB:  sub_rr(code, src, dst, size); break;
+	case M68K_SUBX: sbb_rr(code, src, dst, size); break;
+	}
+}
+
+void op_rrdisp(code_info *code, m68kinst *inst, uint8_t src, uint8_t dst, int32_t disp, uint8_t size)
+{
+	switch (inst->op)
+	{
+	case M68K_ADD:  add_rrdisp(code, src, dst, disp, size); break;
+	case M68K_ADDX: adc_rrdisp(code, src, dst, disp, size); break;
+	case M68K_AND:  and_rrdisp(code, src, dst, disp, size); break;
+	case M68K_BTST: bt_rrdisp(code, src, dst, disp, size); break;
+	case M68K_BSET: bts_rrdisp(code, src, dst, disp, size); break;
+	case M68K_BCLR: btr_rrdisp(code, src, dst, disp, size); break;
+	case M68K_BCHG: btc_rrdisp(code, src, dst, disp, size); break;
+	case M68K_CMP:  cmp_rrdisp(code, src, dst, disp, size); break;
+	case M68K_EOR:  xor_rrdisp(code, src, dst, disp, size); break;
+	case M68K_OR:   or_rrdisp(code, src, dst, disp, size); break;
+	case M68K_SUB:  sub_rrdisp(code, src, dst, disp, size); break;
+	case M68K_SUBX: sbb_rrdisp(code, src, dst, disp, size); break;
+	}
+}
+
+void op_rdispr(code_info *code, m68kinst *inst, uint8_t src, int32_t disp, uint8_t dst, uint8_t size)
+{
+	switch (inst->op)
+	{
+	case M68K_ADD:  add_rdispr(code, src, disp, dst, size); break;
+	case M68K_ADDX: adc_rdispr(code, src, disp, dst, size); break;
+	case M68K_AND:  and_rdispr(code, src, disp, dst, size); break;
+	case M68K_CMP:  cmp_rdispr(code, src, disp, dst, size); break;
+	case M68K_EOR:  xor_rdispr(code, src, disp, dst, size); break;
+	case M68K_OR:   or_rdispr(code, src, disp, dst, size); break;
+	case M68K_SUB:  sub_rdispr(code, src, disp, dst, size); break;
+	case M68K_SUBX: sbb_rdispr(code, src, disp, dst, size); break;
+	}
+}
+
+void translate_m68k_arith(m68k_options *opts, m68kinst * inst, uint32_t flag_mask, host_ea *src_op, host_ea *dst_op)
+{
+	code_info *code = &opts->gen.code;
+	cycles(&opts->gen, BUS);
+	if (inst->op == M68K_ADDX || inst->op == M68K_SUBX) {
+		flag_to_carry(opts, FLAG_X);
+	}
+	uint8_t size = inst->dst.addr_mode == MODE_AREG ? OPSIZE_LONG : inst->extra.size;
+	if (src_op->mode == MODE_REG_DIRECT) {
+		if (dst_op->mode == MODE_REG_DIRECT) {
+			op_rr(code, inst, src_op->base, dst_op->base, size);
+		} else {
+			op_rrdisp(code, inst, src_op->base, dst_op->base, dst_op->disp, size);
+		}
+	} else if (src_op->mode == MODE_REG_DISPLACE8) {
+		op_rdispr(code, inst, src_op->base, src_op->disp, dst_op->base, size);
+	} else {
+		if (dst_op->mode == MODE_REG_DIRECT) {
+			op_ir(code, inst, src_op->disp, dst_op->base, size);
+		} else {
+			op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, size);
+		}
+	}
+	if (inst->dst.addr_mode != MODE_AREG || inst->op == M68K_CMP) {
+		update_flags(opts, flag_mask);
+		if (inst->op == M68K_ADDX || inst->op == M68K_SUBX) {
+			check_alloc_code(code, 2*MAX_INST_LEN);
+			code_ptr after_flag_set = code->cur + 1;
+			jcc(code, CC_Z, code->cur + 2);
+			set_flag(opts, 0, FLAG_Z);
+			*after_flag_set = code->cur - (after_flag_set+1);
+		}
+	}
+	if (inst->op != M68K_CMP) {
+		m68k_save_result(inst, opts);
+	}
+}
+
+void translate_m68k_cmp(m68k_options * opts, m68kinst * inst)
+{
+	code_info *code = &opts->gen.code;
+	uint8_t size = inst->extra.size;
+	host_ea src_op, dst_op;
+	translate_m68k_op(inst, &src_op, opts, 0);
+	if (inst->dst.addr_mode == MODE_AREG_POSTINC) {
+		push_r(code, opts->gen.scratch1);
+		translate_m68k_op(inst, &dst_op, opts, 1);
+		pop_r(code, opts->gen.scratch2);
+		src_op.base = opts->gen.scratch2;
+	} else {
+		translate_m68k_op(inst, &dst_op, opts, 1);
+		if (inst->dst.addr_mode == MODE_AREG && size == OPSIZE_WORD) {
+			size = OPSIZE_LONG;
+		}
+	}
+	translate_m68k_arith(opts, inst, N|Z|V|C, &src_op, &dst_op);
+}
+
+void op_r(code_info *code, m68kinst *inst, uint8_t dst, uint8_t size)
+{
+	switch(inst->op)
+	{
+	case M68K_NEG:   neg_r(code, dst, size); break;
+	case M68K_NOT:   not_r(code, dst, size); cmp_ir(code, 0, dst, size); break;
+	case M68K_ROL:   rol_clr(code, dst, size); break;
+	case M68K_ROR:   ror_clr(code, dst, size); break;
+	case M68K_ROXL:  rcl_clr(code, dst, size); break;
+	case M68K_ROXR:  rcr_clr(code, dst, size); break;
+	case M68K_SWAP:  rol_ir(code, 16, dst, SZ_D); cmp_ir(code, 0, dst, SZ_D); break;
+	case M68K_TST:   cmp_ir(code, 0, dst, size); break;
+	}
+}
+
+void op_rdisp(code_info *code, m68kinst *inst, uint8_t dst, int32_t disp, uint8_t size)
+{
+	switch(inst->op)
+	{
+	case M68K_NEG:   neg_rdisp(code, dst, disp, size); break;
+	case M68K_NOT:   not_rdisp(code, dst, disp, size); cmp_irdisp(code, 0, dst, disp, size); break;
+	case M68K_ROL:   rol_clrdisp(code, dst, disp, size); break;
+	case M68K_ROR:   ror_clrdisp(code, dst, disp, size); break;
+	case M68K_ROXL:  rcl_clrdisp(code, dst, disp, size); break;
+	case M68K_ROXR:  rcr_clrdisp(code, dst, disp, size); break;
+	case M68K_SWAP:  rol_irdisp(code, 16, dst, disp, SZ_D); cmp_irdisp(code, 0, dst, disp, SZ_D); break;
+	case M68K_TST:   cmp_irdisp(code, 0, dst, disp, size); break;
+	}
+}
+
+void translate_m68k_unary(m68k_options *opts, m68kinst *inst, uint32_t flag_mask, host_ea *dst_op)
+{
+	code_info *code = &opts->gen.code;
+	cycles(&opts->gen, BUS);
+	if (dst_op->mode == MODE_REG_DIRECT) {
+		op_r(code, inst, dst_op->base, inst->extra.size);
+	} else {
+		op_rdisp(code, inst, dst_op->base, dst_op->disp, inst->extra.size);
+	}
+	update_flags(opts, flag_mask);
+	m68k_save_result(inst, opts);
+}
+
+void translate_m68k_invalid(m68k_options *opts, m68kinst *inst)
+{
+	code_info *code = &opts->gen.code;
+	if (inst->src.params.immed == 0x7100) {
+		retn(code);
+		return;
+	}
+	mov_ir(code, inst->address, opts->gen.scratch1, SZ_D);
+	call(code, (code_ptr)m68k_invalid);
+}
+
+void translate_m68k_abcd_sbcd(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
+{
+	code_info *code = &opts->gen.code;
+	if (src_op->base != opts->gen.scratch2) {
+		if (src_op->mode == MODE_REG_DIRECT) {
+			mov_rr(code, src_op->base, opts->gen.scratch2, SZ_B);
+		} else {
+			mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_B);
+		}
+	}
+	if (dst_op->base != opts->gen.scratch1) {
+		if (dst_op->mode == MODE_REG_DIRECT) {
+			mov_rr(code, dst_op->base, opts->gen.scratch1, SZ_B);
+		} else {
+			mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch1, SZ_B);
+		}
+	}
+	uint8_t other_reg;
+	//WARNING: This may need adjustment if register assignments change
+	if (opts->gen.scratch2 > RBX) {
+		other_reg = RAX;
+		xchg_rr(code, opts->gen.scratch2, RAX, SZ_D);
+	} else {
+		other_reg = opts->gen.scratch2;
+	}
+	mov_rr(code, opts->gen.scratch1, opts->gen.scratch1 + (AH-RAX), SZ_B);
+	mov_rr(code, other_reg, other_reg + (AH-RAX), SZ_B);
+	and_ir(code, 0xF0, opts->gen.scratch1, SZ_B);
+	and_ir(code, 0xF0, other_reg, SZ_B);
+	and_ir(code, 0xF, opts->gen.scratch1 + (AH-RAX), SZ_B);
+	and_ir(code, 0xF, other_reg + (AH-RAX), SZ_B);
+	//do op on low nibble
+	flag_to_carry(opts, FLAG_X);
+	if (inst->op == M68K_ABCD) {
+		adc_rr(code, other_reg + (AH-RAX), opts->gen.scratch1 + (AH-RAX), SZ_B);
+	} else {
+		sbb_rr(code, other_reg + (AH-RAX), opts->gen.scratch1 + (AH-RAX), SZ_B);
+	}
+	cmp_ir(code, 0xA, opts->gen.scratch1 + (AH-RAX), SZ_B);
+	code_ptr no_adjust = code->cur+1;
+	//add correction factor if necessary
+	jcc(code, CC_B, no_adjust);
+	if (inst->op == M68K_ABCD) {
+		add_ir(code, 6, opts->gen.scratch1 + (AH-RAX), SZ_B);
+	} else {
+		sub_ir(code, 6, opts->gen.scratch1 + (AH-RAX), SZ_B);
+	}
+	*no_adjust = code->cur - (no_adjust+1);
+	//add low nibble result to one of the high nibble operands
+	add_rr(code, opts->gen.scratch1 + (AH-RAX), opts->gen.scratch1, SZ_B);
+	if (inst->op == M68K_ABCD) {
+		add_rr(code, other_reg, opts->gen.scratch1, SZ_B);
+	} else {
+		sub_rr(code, other_reg, opts->gen.scratch1, SZ_B);
+	}
+	if (opts->gen.scratch2 > RBX) {
+		mov_rr(code, opts->gen.scratch2, RAX, SZ_D);
+	}
+	set_flag(opts, 0, FLAG_C);
+	set_flag(opts, 0, FLAG_V);
+	code_ptr def_adjust = code->cur+1;
+	jcc(code, CC_C, def_adjust);
+	cmp_ir(code, 0xA0, opts->gen.scratch1, SZ_B);
+	no_adjust = code->cur+1;
+	jcc(code, CC_B, no_adjust);
+	*def_adjust = code->cur - (def_adjust + 1);
+	set_flag(opts, 1, FLAG_C);
+	if (inst->op == M68K_ABCD) {
+		add_ir(code, 0x60, opts->gen.scratch1, SZ_B);
+	} else {
+		sub_ir(code, 0x60, opts->gen.scratch1, SZ_B);
+	}
+	//V flag is set based on the result of the addition of the
+	//result and the correction factor
+	set_flag_cond(opts, CC_O, FLAG_V);
+	*no_adjust = code->cur - (no_adjust+1);
+	flag_to_flag(opts, FLAG_C, FLAG_X);
+	
+	cmp_ir(code, 0, opts->gen.scratch1, SZ_B);
+	set_flag_cond(opts, CC_S, FLAG_N);
+	jcc(code, CC_Z, code->cur + 4);
+	set_flag(opts, 0, FLAG_Z);
+	if (dst_op->base != opts->gen.scratch1) {
+		if (dst_op->mode == MODE_REG_DIRECT) {
+			mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_B);
+		} else {
+			mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_B);
+		}
+	}
+	m68k_save_result(inst, opts);
+}
+
+void translate_m68k_sl(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
+{
+	translate_shift(opts, inst, src_op, dst_op, shl_ir, shl_irdisp, shl_clr, shl_clrdisp, shr_ir, shr_irdisp);
+}
+
+void translate_m68k_asr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
+{
+	translate_shift(opts, inst, src_op, dst_op, sar_ir, sar_irdisp, sar_clr, sar_clrdisp, NULL, NULL);
+}
+
+void translate_m68k_lsr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
+{
+	translate_shift(opts, inst, src_op, dst_op, shr_ir, shr_irdisp, shr_clr, shr_clrdisp, shl_ir, shl_irdisp);
+}
+
+void translate_m68k_bit(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
+{
+	code_info *code = &opts->gen.code;
+	cycles(&opts->gen, inst->extra.size == OPSIZE_BYTE ? 4 : (
+		inst->op == M68K_BTST ? 6 : (inst->op == M68K_BCLR ? 10 : 8))
+	);
+	if (src_op->mode == MODE_IMMED) {
+		if (inst->extra.size == OPSIZE_BYTE) {
+			src_op->disp &= 0x7;
+		}
+		if (dst_op->mode == MODE_REG_DIRECT) {
+			op_ir(code, inst, src_op->disp, dst_op->base, inst->extra.size);
+		} else {
+			op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size);
+		}
+	} else {
+		if (src_op->mode == MODE_REG_DISPLACE8 || (inst->dst.addr_mode != MODE_REG && src_op->base != opts->gen.scratch1 && src_op->base != opts->gen.scratch2)) {
+			if (dst_op->base == opts->gen.scratch1) {
+				push_r(code, opts->gen.scratch2);
+				if (src_op->mode == MODE_REG_DIRECT) {
+					mov_rr(code, src_op->base, opts->gen.scratch2, SZ_B);
+				} else {
+					mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_B);
+				}
+				src_op->base = opts->gen.scratch2;
+			} else {
+				if (src_op->mode == MODE_REG_DIRECT) {
+					mov_rr(code, src_op->base, opts->gen.scratch1, SZ_B);
+				} else {
+					mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_B);
+				}
+				src_op->base = opts->gen.scratch1;
+			}
+		}
+		uint8_t size = inst->extra.size;
+		if (dst_op->mode == MODE_REG_DISPLACE8) {
+			if (src_op->base != opts->gen.scratch1 && src_op->base != opts->gen.scratch2) {
+				if (src_op->mode == MODE_REG_DIRECT) {
+					mov_rr(code, src_op->base, opts->gen.scratch1, SZ_D);
+				} else {
+					mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_D);
+					src_op->mode = MODE_REG_DIRECT;
+				}
+				src_op->base = opts->gen.scratch1;
+			}
+			//b### with register destination is modulo 32
+			//x86 with a memory destination isn't modulo anything
+			//so use an and here to force the value to be modulo 32
+			and_ir(code, 31, opts->gen.scratch1, SZ_D);
+		} else if(inst->dst.addr_mode != MODE_REG) {
+			//b### with memory destination is modulo 8
+			//x86-64 doesn't support 8-bit bit operations
+			//so we fake it by forcing the bit number to be modulo 8
+			and_ir(code, 7, src_op->base, SZ_D);
+			size = SZ_D;
+		}
+		if (dst_op->mode == MODE_REG_DIRECT) {
+			op_rr(code, inst, src_op->base, dst_op->base, size);
+		} else {
+			op_rrdisp(code, inst, src_op->base, dst_op->base, dst_op->disp, size);
+		}
+		if (src_op->base == opts->gen.scratch2) {
+			pop_r(code, opts->gen.scratch2);
+		}
+	}
+	//x86 sets the carry flag to the value of the bit tested
+	//68K sets the zero flag to the complement of the bit tested
+	set_flag_cond(opts, CC_NC, FLAG_Z);
+	if (inst->op != M68K_BTST) {
+		m68k_save_result(inst, opts);
+	}
+}
+
+void translate_m68k_chk(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
+{
+	code_info *code = &opts->gen.code;
+	cycles(&opts->gen, 6);
+	if (dst_op->mode == MODE_REG_DIRECT) {
+		cmp_ir(code, 0, dst_op->base, inst->extra.size);
+	} else {
+		cmp_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size);
+	}
+	uint32_t isize;
+	switch(inst->src.addr_mode)
+	{
+	case MODE_AREG_DISPLACE:
+	case MODE_AREG_INDEX_DISP8:
+	case MODE_ABSOLUTE_SHORT:
+	case MODE_PC_INDEX_DISP8:
+	case MODE_PC_DISPLACE:
+	case MODE_IMMEDIATE:
+		isize = 4;
+		break;
+	case MODE_ABSOLUTE:
+		isize = 6;
+		break;
+	default:
+		isize = 2;
+	}
+	//make sure we won't start a new chunk in the middle of these branches
+	check_alloc_code(code, MAX_INST_LEN * 11);
+	code_ptr passed = code->cur + 1;
+	jcc(code, CC_GE, code->cur + 2);
+	set_flag(opts, 1, FLAG_N);
+	mov_ir(code, VECTOR_CHK, opts->gen.scratch2, SZ_D);
+	mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D);
+	jmp(code, opts->trap);
+	*passed = code->cur - (passed+1);
+	if (dst_op->mode == MODE_REG_DIRECT) {
+		if (src_op->mode == MODE_REG_DIRECT) {
+			cmp_rr(code, src_op->base, dst_op->base, inst->extra.size);
+		} else if(src_op->mode == MODE_REG_DISPLACE8) {
+			cmp_rdispr(code, src_op->base, src_op->disp, dst_op->base, inst->extra.size);
+		} else {
+			cmp_ir(code, src_op->disp, dst_op->base, inst->extra.size);
+		}
+	} else if(dst_op->mode == MODE_REG_DISPLACE8) {
+		if (src_op->mode == MODE_REG_DIRECT) {
+			cmp_rrdisp(code, src_op->base, dst_op->base, dst_op->disp, inst->extra.size);
+		} else {
+			cmp_irdisp(code, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size);
+		}
+	}
+	passed = code->cur + 1;
+	jcc(code, CC_LE, code->cur + 2);
+	set_flag(opts, 0, FLAG_N);
+	mov_ir(code, VECTOR_CHK, opts->gen.scratch2, SZ_D);
+	mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D);
+	jmp(code, opts->trap);
+	*passed = code->cur - (passed+1);
+	cycles(&opts->gen, 4);
+}
+
+void translate_m68k_div(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
+{
+	code_info *code = &opts->gen.code;
+	check_alloc_code(code, MAX_NATIVE_SIZE);
+	//TODO: cycle exact division
+	cycles(&opts->gen, inst->op == M68K_DIVS ? 158 : 140);
+	set_flag(opts, 0, FLAG_C);
+	push_r(code, RDX);
+	push_r(code, RAX);
+	if (dst_op->mode == MODE_REG_DIRECT) {
+		mov_rr(code, dst_op->base, RAX, SZ_D);
+	} else {
+		mov_rdispr(code, dst_op->base, dst_op->disp, RAX, SZ_D);
+	}
+	if (src_op->mode == MODE_IMMED) {
+		mov_ir(code, (src_op->disp & 0x8000) && inst->op == M68K_DIVS ? src_op->disp | 0xFFFF0000 : src_op->disp, opts->gen.scratch2, SZ_D);
+	} else if (src_op->mode == MODE_REG_DIRECT) {
+		if (inst->op == M68K_DIVS) {
+			movsx_rr(code, src_op->base, opts->gen.scratch2, SZ_W, SZ_D);
+		} else {
+			movzx_rr(code, src_op->base, opts->gen.scratch2, SZ_W, SZ_D);
+		}
+	} else if (src_op->mode == MODE_REG_DISPLACE8) {
+		if (inst->op == M68K_DIVS) {
+			movsx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_W, SZ_D);
+		} else {
+			movzx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_W, SZ_D);
+		}
+	}
+	uint32_t isize = 2;
+	switch(inst->src.addr_mode)
+	{
+	case MODE_AREG_DISPLACE:
+	case MODE_AREG_INDEX_DISP8:
+	case MODE_ABSOLUTE_SHORT:
+	case MODE_PC_INDEX_DISP8:
+	case MODE_IMMEDIATE:
+		isize = 4;		
+		break;
+	case MODE_ABSOLUTE:
+		isize = 6;
+		break;
+	}
+	cmp_ir(code, 0, opts->gen.scratch2, SZ_D);
+	check_alloc_code(code, 6*MAX_INST_LEN);
+	code_ptr not_zero = code->cur + 1;
+	jcc(code, CC_NZ, code->cur + 2);
+	pop_r(code, RAX);
+	pop_r(code, RDX);
+	mov_ir(code, VECTOR_INT_DIV_ZERO, opts->gen.scratch2, SZ_D);
+	mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D);
+	jmp(code, opts->trap);
+	*not_zero = code->cur - (not_zero+1);
+	if (inst->op == M68K_DIVS) {
+		cdq(code);
+	} else {
+		xor_rr(code, RDX, RDX, SZ_D);
+	}
+	if (inst->op == M68K_DIVS) {
+		idiv_r(code, opts->gen.scratch2, SZ_D);
+	} else {
+		div_r(code, opts->gen.scratch2, SZ_D);
+	}
+	code_ptr skip_sec_check, norm_off;
+	if (inst->op == M68K_DIVS) {
+		cmp_ir(code, 0x8000, RAX, SZ_D);
+		skip_sec_check = code->cur + 1;
+		jcc(code, CC_GE, code->cur + 2);
+		cmp_ir(code, -0x8000, RAX, SZ_D);
+		norm_off = code->cur + 1;
+		jcc(code, CC_L, code->cur + 2);
+	} else {
+		cmp_ir(code, 0x10000, RAX, SZ_D);
+		norm_off = code->cur + 1;
+		jcc(code, CC_NC, code->cur + 2);
+	}
+	if (dst_op->mode == MODE_REG_DIRECT) {
+		mov_rr(code, RDX, dst_op->base, SZ_W);
+		shl_ir(code, 16, dst_op->base, SZ_D);
+		mov_rr(code, RAX, dst_op->base, SZ_W);
+	} else {
+		mov_rrdisp(code, RDX, dst_op->base, dst_op->disp, SZ_W);
+		shl_irdisp(code, 16, dst_op->base, dst_op->disp, SZ_D);
+		mov_rrdisp(code, RAX, dst_op->base, dst_op->disp, SZ_W);
+	}
+	cmp_ir(code, 0, RAX, SZ_W);
+	pop_r(code, RAX);
+	pop_r(code, RDX);
+	update_flags(opts, V0|Z|N);
+	code_ptr end_off = code->cur + 1;
+	jmp(code, code->cur + 2);
+	*norm_off = code->cur - (norm_off + 1);
+	if (inst->op == M68K_DIVS) {
+		*skip_sec_check = code->cur - (skip_sec_check+1);
+	}
+	pop_r(code, RAX);
+	pop_r(code, RDX);
+	set_flag(opts, 1, FLAG_V);
+	*end_off = code->cur - (end_off + 1);
+}
+
+void translate_m68k_exg(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
+{
+	code_info *code = &opts->gen.code;
+	cycles(&opts->gen, 6);
+	if (dst_op->mode == MODE_REG_DIRECT) {
+		mov_rr(code, dst_op->base, opts->gen.scratch2, SZ_D);
+		if (src_op->mode == MODE_REG_DIRECT) {
+			mov_rr(code, src_op->base, dst_op->base, SZ_D);
+			mov_rr(code, opts->gen.scratch2, src_op->base, SZ_D);
+		} else {
+			mov_rdispr(code, src_op->base, src_op->disp, dst_op->base, SZ_D);
+			mov_rrdisp(code, opts->gen.scratch2, src_op->base, src_op->disp, SZ_D);
+		}
+	} else {
+		mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_D);
+		if (src_op->mode == MODE_REG_DIRECT) {
+			mov_rrdisp(code, src_op->base, dst_op->base, dst_op->disp, SZ_D);
+			mov_rr(code, opts->gen.scratch2, src_op->base, SZ_D);
+		} else {
+			mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_D);
+			mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_D);
+			mov_rrdisp(code, opts->gen.scratch2, src_op->base, src_op->disp, SZ_D);
+		}
+	}
+}
+
+void translate_m68k_mul(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
+{
+	code_info *code = &opts->gen.code;
+	cycles(&opts->gen, 70); //TODO: Calculate the actual value based on the value of the <ea> parameter
+	if (src_op->mode == MODE_IMMED) {
+		mov_ir(code, inst->op == M68K_MULU ? (src_op->disp & 0xFFFF) : ((src_op->disp & 0x8000) ? src_op->disp | 0xFFFF0000 : src_op->disp), opts->gen.scratch1, SZ_D);
+	} else if (src_op->mode == MODE_REG_DIRECT) {
+		if (inst->op == M68K_MULS) {
+			movsx_rr(code, src_op->base, opts->gen.scratch1, SZ_W, SZ_D);
+		} else {
+			movzx_rr(code, src_op->base, opts->gen.scratch1, SZ_W, SZ_D);
+		}
+	} else {
+		if (inst->op == M68K_MULS) {
+			movsx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D);
+		} else {
+			movzx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D);
+		}
+	}
+	uint8_t dst_reg;
+	if (dst_op->mode == MODE_REG_DIRECT) {
+		dst_reg = dst_op->base;
+		if (inst->op == M68K_MULS) {
+			movsx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D);
+		} else {
+			movzx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D);
+		}
+	} else {
+		dst_reg = opts->gen.scratch2;
+		if (inst->op == M68K_MULS) {
+			movsx_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_W, SZ_D);
+		} else {
+			movzx_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_W, SZ_D);
+		}
+	}
+	imul_rr(code, opts->gen.scratch1, dst_reg, SZ_D);
+	if (dst_op->mode == MODE_REG_DISPLACE8) {
+		mov_rrdisp(code, dst_reg, dst_op->base, dst_op->disp, SZ_D);
+	}
+	cmp_ir(code, 0, dst_reg, SZ_D);
+	update_flags(opts, N|Z|V0|C0);
+}
+
+void translate_m68k_negx(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
+{
+	code_info *code = &opts->gen.code;
+	cycles(&opts->gen, BUS);
+	if (dst_op->mode == MODE_REG_DIRECT) {
+		if (dst_op->base == opts->gen.scratch1) {
+			push_r(code, opts->gen.scratch2);
+			xor_rr(code, opts->gen.scratch2, opts->gen.scratch2, inst->extra.size);
+			flag_to_carry(opts, FLAG_X);
+			sbb_rr(code, dst_op->base, opts->gen.scratch2, inst->extra.size);
+			mov_rr(code, opts->gen.scratch2, dst_op->base, inst->extra.size);
+			pop_r(code, opts->gen.scratch2);
+		} else {
+			xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, inst->extra.size);
+			flag_to_carry(opts, FLAG_X);
+			sbb_rr(code, dst_op->base, opts->gen.scratch1, inst->extra.size);
+			mov_rr(code, opts->gen.scratch1, dst_op->base, inst->extra.size);
+		}
+	} else {
+		xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, inst->extra.size);
+		flag_to_carry(opts, FLAG_X);
+		sbb_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch1, inst->extra.size);
+		mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, inst->extra.size);
+	}
+	set_flag_cond(opts, CC_C, FLAG_C);
+	code_ptr after_flag_set = code->cur + 1;
+	jcc(code, CC_Z, code->cur + 2);
+	set_flag(opts, 0, FLAG_Z);
+	*after_flag_set = code->cur - (after_flag_set+1);
+	set_flag_cond(opts, CC_S, FLAG_N);
+	set_flag_cond(opts, CC_O, FLAG_V);
+	if (opts->flag_regs[FLAG_C] >= 0) {
+		flag_to_flag(opts, FLAG_C, FLAG_X);
+	} else {
+		set_flag_cond(opts, CC_C, FLAG_X);
+	}
+	m68k_save_result(inst, opts);
+}
+
+void translate_m68k_rot(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
+{
+	code_info *code = &opts->gen.code;
+	int32_t init_flags = C|V0;
+	if (inst->src.addr_mode == MODE_UNUSED) {
+		cycles(&opts->gen, BUS);
+		//Memory rotate
+		if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) {
+			flag_to_carry(opts, FLAG_X);
+			init_flags |= X;
+		}
+		op_ir(code, inst, 1, dst_op->base, inst->extra.size);
+		update_flags(opts, init_flags);
+		cmp_ir(code, 0, dst_op->base, inst->extra.size);
+		update_flags(opts, Z|N);
+		m68k_save_result(inst, opts);
+	} else {
+		if (src_op->mode == MODE_IMMED) {
+			cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 8 : 6) + src_op->disp*2);
+			if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) {
+				flag_to_carry(opts, FLAG_X);
+				init_flags |= X;
+			}
+			if (dst_op->mode == MODE_REG_DIRECT) {
+				op_ir(code, inst, src_op->disp, dst_op->base, inst->extra.size);
+			} else {
+				op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size);
+			}
+			update_flags(opts, init_flags);
+		} else {
+			if (src_op->mode == MODE_REG_DIRECT) {
+				if (src_op->base != opts->gen.scratch1) {
+					mov_rr(code, src_op->base, opts->gen.scratch1, SZ_B);
+				}
+			} else {
+				mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_B);
+			}
+			and_ir(code, 63, opts->gen.scratch1, SZ_D);
+			code_ptr zero_off = code->cur + 1;
+			jcc(code, CC_Z, code->cur + 2);
+			add_rr(code, opts->gen.scratch1, CYCLES, SZ_D);
+			add_rr(code, opts->gen.scratch1, CYCLES, SZ_D);
+			cmp_ir(code, 32, opts->gen.scratch1, SZ_B);
+			code_ptr norm_off = code->cur + 1;
+			jcc(code, CC_L, code->cur + 2);
+			if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) {
+				flag_to_carry(opts, FLAG_X);
+				init_flags |= X;
+			} else {
+				sub_ir(code, 32, opts->gen.scratch1, SZ_B);
+			}
+			if (dst_op->mode == MODE_REG_DIRECT) {
+				op_ir(code, inst, 31, dst_op->base, inst->extra.size);
+				op_ir(code, inst, 1, dst_op->base, inst->extra.size);
+			} else {
+				op_irdisp(code, inst, 31, dst_op->base, dst_op->disp, inst->extra.size);
+				op_irdisp(code, inst, 1, dst_op->base, dst_op->disp, inst->extra.size);
+			}
+
+			if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) {
+				set_flag_cond(opts, CC_C, FLAG_X);
+				sub_ir(code, 32, opts->gen.scratch1, SZ_B);
+				*norm_off = code->cur - (norm_off+1);
+				flag_to_carry(opts, FLAG_X);
+			} else {
+				*norm_off = code->cur - (norm_off+1);
+			}
+			if (dst_op->mode == MODE_REG_DIRECT) {
+				op_r(code, inst, dst_op->base, inst->extra.size);
+			} else {
+				op_rdisp(code, inst, dst_op->base, dst_op->disp, inst->extra.size);
+			}
+			update_flags(opts, init_flags);
+			code_ptr end_off = code->cur + 1;
+			jmp(code, code->cur + 2);
+			*zero_off = code->cur - (zero_off+1);
+			if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) {
+				//Carry flag is set to X flag when count is 0, this is different from ROR/ROL
+				flag_to_flag(opts, FLAG_X, FLAG_C);
+			} else {
+				set_flag(opts, 0, FLAG_C);
+			}
+			*end_off = code->cur - (end_off+1);
+		}
+		if (dst_op->mode == MODE_REG_DIRECT) {
+			cmp_ir(code, 0, dst_op->base, inst->extra.size);
+		} else {
+			cmp_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size);
+		}
+		update_flags(opts, Z|N);
+	}
+}
+
+void translate_m68k_illegal(m68k_options *opts, m68kinst *inst)
+{
+	code_info *code = &opts->gen.code;
+	call(code, opts->gen.save_context);
+#ifdef X86_64
+	mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR);
+#else
+	push_r(code, opts->gen.context_reg);
+#endif
+	call(code, (code_ptr)print_regs_exit);
+}
+
+#define BIT_SUPERVISOR 5
+
+void translate_m68k_andi_ori_ccr_sr(m68k_options *opts, m68kinst *inst)
+{
+	code_info *code = &opts->gen.code;
+	cycles(&opts->gen, 20);
+	//TODO: If ANDI to SR, trap if not in supervisor mode
+	uint32_t flag_mask = 0;
+	uint32_t base_flag = inst->op == M68K_ANDI_SR || inst->op == M68K_ANDI_CCR ? X0 : X1;
+	for (int i = 0; i < 5; i++)
+	{
+		if ((base_flag == X0) ^ (inst->src.params.immed & 1 << i) > 0)
+		{
+			flag_mask |= base_flag << ((4 - i) * 3);
+		}
+	}
+	update_flags(opts, flag_mask);
+	if (inst->op == M68K_ANDI_SR || inst->op == M68K_ORI_SR) {
+		if (inst->op == M68K_ANDI_SR) {
+			and_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
+		} else {
+			or_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
+		}
+		if (inst->op == M68K_ANDI_SR && !(inst->src.params.immed & (1 << (BIT_SUPERVISOR + 8)))) {
+			//leave supervisor mode
+			swap_ssp_usp(opts);
+		}
+		if ((inst->op == M68K_ANDI_SR && (inst->src.params.immed  & 0x700) != 0x700)
+		    || (inst->op == M68K_ORI_SR && inst->src.params.immed & 0x700)) {
+			call(code, opts->do_sync);
+		}
+	}
+}
+
+void translate_m68k_eori_ccr_sr(m68k_options *opts, m68kinst *inst)
+{
+	code_info *code = &opts->gen.code;
+	cycles(&opts->gen, 20);
+	//TODO: If ANDI to SR, trap if not in supervisor mode
+	if (inst->src.params.immed & 0x1) {
+		xor_flag(opts, 1, FLAG_C);
+	}
+	if (inst->src.params.immed & 0x2) {
+		xor_flag(opts, 1, FLAG_V);
+	}
+	if (inst->src.params.immed & 0x4) {
+		xor_flag(opts, 1, FLAG_Z);
+	}
+	if (inst->src.params.immed & 0x8) {
+		xor_flag(opts, 1, FLAG_N);
+	}
+	if (inst->src.params.immed & 0x10) {
+		xor_flag(opts, 1, FLAG_X);
+	}
+	if (inst->op == M68K_ORI_SR) {
+		xor_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
+		if (inst->src.params.immed & 0x700) {
+			call(code, opts->do_sync);
+		}
+	}
+}
+
+void set_all_flags(m68k_options *opts, uint8_t flags)
+{
+	uint32_t flag_mask = flags & 0x10 ? X1 : X0;
+	flag_mask |= flags & 0x8 ? N1 : N0;
+	flag_mask |= flags & 0x4 ? Z1 : Z0;
+	flag_mask |= flags & 0x2 ? V1 : V0;
+	flag_mask |= flags & 0x1 ? C1 : C0;
+	update_flags(opts, flag_mask);
+}
+
+void translate_m68k_move_ccr_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
+{
+	code_info *code = &opts->gen.code;
+	//TODO: Privilege check for MOVE to SR
+	if (src_op->mode == MODE_IMMED) {
+		set_all_flags(opts, src_op->disp);
+		if (inst->op == M68K_MOVE_SR) {
+			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
+				swap_ssp_usp(opts);
+			}
+			call(code, opts->do_sync);
+		}
+		cycles(&opts->gen, 12);
+	} else {
+		if (src_op->base != opts->gen.scratch1) {
+			if (src_op->mode == MODE_REG_DIRECT) {
+				mov_rr(code, src_op->base, opts->gen.scratch1, SZ_W);
+			} else {
+				mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W);
+			}
+		}
+		call(code, inst->op == M68K_MOVE_SR ? opts->set_sr : opts->set_ccr);
+		cycles(&opts->gen, 12);
+	}
+}
+
+void translate_m68k_stop(m68k_options *opts, m68kinst *inst)
+{
+	//TODO: Trap if not in system mode
+	//manual says 4 cycles, but it has to be at least 8 since it's a 2-word instruction
+	//possibly even 12 since that's how long MOVE to SR takes
+	//On further thought prefetch + the fact that this stops the CPU may make
+	//Motorola's accounting make sense here
+	code_info *code = &opts->gen.code;
+	cycles(&opts->gen, BUS*2);
+	set_all_flags(opts,  inst->src.params.immed);
+	mov_irdisp(code, (inst->src.params.immed >> 8), opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
+	if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) {
+		//leave supervisor mode
+		swap_ssp_usp(opts);
+	}
+	code_ptr loop_top = code->cur;
+	call(code, opts->do_sync);
+	cmp_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D);
+	code_ptr normal_cycle_up = code->cur + 1;
+	jcc(code, CC_A, code->cur + 2);
+	cycles(&opts->gen, BUS);
+	code_ptr after_cycle_up = code->cur + 1;
+	jmp(code, code->cur + 2);
+	*normal_cycle_up = code->cur - (normal_cycle_up + 1);
+	mov_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D);
+	*after_cycle_up = code->cur - (after_cycle_up+1);
+	cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), opts->gen.cycles, SZ_D);
+	jcc(code, CC_C, loop_top);
+}
+
+void translate_m68k_move_from_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
+{
+	code_info *code = &opts->gen.code;
+	//TODO: Trap if not in system mode
+	call(code, opts->get_sr);
+	if (dst_op->mode == MODE_REG_DIRECT) {
+		mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_W);
+	} else {
+		mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_W);
+	}
+	m68k_save_result(inst, opts);
+}
+
+void translate_m68k_reset(m68k_options *opts, m68kinst *inst)
+{
+	code_info *code = &opts->gen.code;
+	call(code, opts->gen.save_context);
+#ifdef X86_64
+	mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR);
+#else
+	push_r(code, opts->gen.context_reg);
+#endif
+	call(code, (code_ptr)print_regs_exit);
+}
+
+void translate_m68k_rte(m68k_options *opts, m68kinst *inst)
+{
+	code_info *code = &opts->gen.code;
+	//TODO: Trap if not in system mode
+	//Read saved SR
+	areg_to_native(opts, 7, opts->gen.scratch1);
+	call(code, opts->read_16);
+	addi_areg(opts, 2, 7);
+	call(code, opts->set_sr);
+	//Read saved PC
+	areg_to_native(opts, 7, opts->gen.scratch1);
+	call(code, opts->read_32);
+	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);
+	code_ptr end_off = code->cur + 1;
+	jcc(code, CC_C, code->cur + 2);
+	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);
+}
+
+void translate_out_of_bounds(code_info *code)
+{
+	xor_rr(code, RDI, RDI, SZ_D);
+#ifdef X86_32
+	push_r(code, RDI);
+#endif
+	call(code, (code_ptr)exit);
+}
+
+void nop_fill_or_jmp_next(code_info *code, code_ptr old_end, code_ptr next_inst)
+{
+	if (next_inst == old_end && next_inst - code->cur < 2) {
+		while (code->cur < old_end) {
+			*(code->cur++) = 0x90; //NOP
+		}
+	} else {
+		jmp(code, next_inst);
+	}
+}
+
+m68k_context * m68k_handle_code_write(uint32_t address, m68k_context * context)
+{
+	uint32_t inst_start = get_instruction_start(context->native_code_map, address | 0xFF0000);
+	if (inst_start) {
+		m68k_options * options = context->options;
+		code_info *code = &options->gen.code;
+		code_ptr dst = get_native_address(context->native_code_map, inst_start);
+		code_info orig;
+		orig.cur = dst;
+		orig.last = dst + 128;
+		mov_ir(&orig, inst_start, options->gen.scratch2, SZ_D);
+
+		if (!options->retrans_stub) {
+			options->retrans_stub = code->cur;
+			call(code, options->gen.save_context);
+			push_r(code, options->gen.context_reg);
+#ifdef X86_32
+			push_r(code, options->gen.context_reg);
+			push_r(code, options->gen.scratch2);
+#endif
+			call(code, (code_ptr)m68k_retranslate_inst);
+#ifdef X86_32
+			add_ir(code, 8, RSP, SZ_D);
+#endif
+			pop_r(code, options->gen.context_reg);
+			mov_rr(code, RAX, options->gen.scratch1, SZ_PTR);
+			call(code, options->gen.load_context);
+			jmp_r(code, options->gen.scratch1);
+		}
+		jmp(&orig, options->retrans_stub);
+	}
+	return context;
+}
+
+void insert_breakpoint(m68k_context * context, uint32_t address, code_ptr bp_handler)
+{
+	static code_ptr bp_stub = NULL;
+	m68k_options * opts = context->options;
+	code_info native;
+	native.cur = get_native_address_trans(context, address);
+	native.last = native.cur + 128;
+	code_ptr start_native = native.cur;
+	mov_ir(&native, address, opts->gen.scratch1, SZ_D);
+	if (!bp_stub) {
+		code_info *code = &opts->gen.code;
+		check_alloc_code(code, 5);
+		bp_stub = code->cur;
+		call(&native, bp_stub);
+
+		//Calculate length of prologue
+		check_cycles_int(&opts->gen, address);
+		int check_int_size = code->cur-bp_stub;
+		code->cur = bp_stub;
+
+		//Save context and call breakpoint handler
+		call(code, opts->gen.save_context);
+		push_r(code, opts->gen.scratch1);
+#ifdef X86_64
+		mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR);
+		mov_rr(code, opts->gen.scratch1, RSI, SZ_D);
+#else
+		push_r(code, opts->gen.scratch1);
+		push_r(code, opts->gen.context_reg);
+#endif
+		call(code, bp_handler);
+#ifdef X86_32
+		add_ir(code, 8, RSP, SZ_D);
+#endif
+		mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR);
+		//Restore context
+		call(code, opts->gen.load_context);
+		pop_r(code, opts->gen.scratch1);
+		//do prologue stuff
+		cmp_rr(code, opts->gen.cycles, opts->gen.limit, SZ_D);
+		code_ptr jmp_off = code->cur + 1;
+		jcc(code, CC_NC, code->cur + 7);
+		call(code, opts->gen.handle_cycle_limit_int);
+		*jmp_off = code->cur - (jmp_off+1);
+		//jump back to body of translated instruction
+		pop_r(code, opts->gen.scratch1);
+		add_ir(code, check_int_size - (native.cur-start_native), opts->gen.scratch1, SZ_PTR);
+		jmp_r(code, opts->gen.scratch1);
+	} else {
+		call(&native, bp_stub);
+	}
+}
+
+void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks)
+{
+	memset(opts, 0, sizeof(*opts));
+	opts->gen.address_size = SZ_D;
+	opts->gen.address_mask = 0xFFFFFF;
+	opts->gen.byte_swap = 1;
+	opts->gen.max_address = 0x1000000;
+	opts->gen.bus_cycles = BUS;
+	opts->gen.mem_ptr_off = offsetof(m68k_context, mem_pointers);
+	opts->gen.ram_flags_off = offsetof(m68k_context, ram_code_flags);
+	opts->gen.ram_flags_shift = 11;
+	for (int i = 0; i < 8; i++)
+	{
+		opts->dregs[i] = opts->aregs[i] = -1;
+	}
+#ifdef X86_64
+	opts->dregs[0] = R10;
+	opts->dregs[1] = R11;
+	opts->dregs[2] = R12;
+	opts->dregs[3] = R8;
+	opts->aregs[0] = R13;
+	opts->aregs[1] = R14;
+	opts->aregs[2] = R9;
+	opts->aregs[7] = R15;
+
+	opts->flag_regs[0] = -1;
+	opts->flag_regs[1] = RBX;
+	opts->flag_regs[2] = RDX;
+	opts->flag_regs[3] = BH;
+	opts->flag_regs[4] = DH;
+
+	opts->gen.scratch2 = RDI;
+#else
+	opts->dregs[0] = RDX;
+	opts->aregs[7] = RDI;
+
+	for (int i = 0; i < 5; i++)
+	{
+		opts->flag_regs[i] = -1;
+	}
+	opts->gen.scratch2 = RBX;
+#endif
+	opts->gen.context_reg = RSI;
+	opts->gen.cycles = RAX;
+	opts->gen.limit = RBP;
+	opts->gen.scratch1 = RCX;
+
+
+	opts->gen.native_code_map = malloc(sizeof(native_map_slot) * NATIVE_MAP_CHUNKS);
+	memset(opts->gen.native_code_map, 0, sizeof(native_map_slot) * NATIVE_MAP_CHUNKS);
+	opts->gen.deferred = NULL;
+	opts->gen.ram_inst_sizes = malloc(sizeof(uint8_t *) * 64);
+	memset(opts->gen.ram_inst_sizes, 0, sizeof(uint8_t *) * 64);
+
+	code_info *code = &opts->gen.code;
+	init_code_info(code);
+
+	opts->gen.save_context = code->cur;
+	for (int i = 0; i < 5; i++)
+		if (opts->flag_regs[i] >= 0) {
+			mov_rrdisp(code, opts->flag_regs[i], opts->gen.context_reg, offsetof(m68k_context, flags) + i, SZ_B);
+		}
+	for (int i = 0; i < 8; i++)
+	{
+		if (opts->dregs[i] >= 0) {
+			mov_rrdisp(code, opts->dregs[i], opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t) * i, SZ_D);
+		}
+		if (opts->aregs[i] >= 0) {
+			mov_rrdisp(code, opts->aregs[i], opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * i, SZ_D);
+		}
+	}
+	mov_rrdisp(code, opts->gen.cycles, opts->gen.context_reg, offsetof(m68k_context, current_cycle), SZ_D);
+	retn(code);
+
+	opts->gen.load_context = code->cur;
+	for (int i = 0; i < 5; i++)
+		if (opts->flag_regs[i] >= 0) {
+			mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + i, opts->flag_regs[i], SZ_B);
+		}
+	for (int i = 0; i < 8; i++)
+	{
+		if (opts->dregs[i] >= 0) {
+			mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t) * i, opts->dregs[i], SZ_D);
+		}
+		if (opts->aregs[i] >= 0) {
+			mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * i, opts->aregs[i], SZ_D);
+		}
+	}
+	mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, current_cycle), CYCLES, SZ_D);
+	mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, target_cycle), LIMIT, SZ_D);
+	retn(code);
+
+	opts->start_context = (start_fun)code->cur;
+#ifdef X86_64
+	if (opts->gen.scratch2 != RDI) {
+		mov_rr(code, RDI, opts->gen.scratch2, SZ_PTR);
+	}
+	//save callee save registers
+	push_r(code, RBP);
+	push_r(code, R12);
+	push_r(code, R13);
+	push_r(code, R14);
+	push_r(code, R15);
+#else
+	//save callee save registers
+	push_r(code, RBP);
+	push_r(code, RBX);
+	push_r(code, RSI);
+	push_r(code, RDI);
+
+	mov_rdispr(code, RSP, 20, opts->gen.scratch2, SZ_D);
+	mov_rdispr(code, RSP, 24, opts->gen.context_reg, SZ_D);
+#endif
+	call(code, opts->gen.load_context);
+	call_r(code, opts->gen.scratch2);
+	call(code, opts->gen.save_context);
+#ifdef X86_64
+	//restore callee save registers
+	pop_r(code, R15);
+	pop_r(code, R14);
+	pop_r(code, R13);
+	pop_r(code, R12);
+	pop_r(code, RBP);
+#else
+	pop_r(code, RDI);
+	pop_r(code, RSI);
+	pop_r(code, RBX);
+	pop_r(code, RBP);
+#endif
+	retn(code);
+
+	opts->native_addr = code->cur;
+	call(code, opts->gen.save_context);
+	push_r(code, opts->gen.context_reg);
+#ifdef X86_64
+	mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR); //move context to 1st arg reg
+	mov_rr(code, opts->gen.scratch1, RSI, SZ_D); //move address to 2nd arg reg
+#else
+	push_r(code, opts->gen.scratch1);
+	push_r(code, opts->gen.context_reg);
+#endif
+	call(code, (code_ptr)get_native_address_trans);
+#ifdef X86_32
+	add_ir(code, 8, RSP, SZ_D);
+#endif
+	mov_rr(code, RAX, opts->gen.scratch1, SZ_PTR); //move result to scratch reg
+	pop_r(code, opts->gen.context_reg);
+	call(code, opts->gen.load_context);
+	retn(code);
+
+	opts->native_addr_and_sync = code->cur;
+	call(code, opts->gen.save_context);
+	push_r(code, opts->gen.scratch1);
+#ifdef X86_64
+	mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR);
+	xor_rr(code, RSI, RSI, SZ_D);
+	test_ir(code, 8, RSP, SZ_PTR); //check stack alignment
+	code_ptr do_adjust_rsp = code->cur + 1;
+	jcc(code, CC_NZ, code->cur + 2);
+	call(code, (code_ptr)sync_components);
+	code_ptr no_adjust_rsp = code->cur + 1;
+	jmp(code, code->cur + 2);
+	*do_adjust_rsp = code->cur - (do_adjust_rsp+1);
+	sub_ir(code, 8, RSP, SZ_PTR);
+	call(code, (code_ptr)sync_components);
+	add_ir(code, 8, RSP, SZ_PTR);
+	*no_adjust_rsp = code->cur - (no_adjust_rsp+1);
+	pop_r(code, RSI);
+	push_r(code, RAX);
+	mov_rr(code, RAX, RDI, SZ_PTR);
+	call(code, (code_ptr)get_native_address_trans);
+#else
+	//TODO: Add support for pushing a constant in gen_x86
+	xor_rr(code, RAX, RAX, SZ_D);
+	push_r(code, RAX);
+	push_r(code, opts->gen.context_reg);
+	call(code, (code_ptr)sync_components);
+	add_ir(code, 8, RSP, SZ_D);
+	pop_r(code, RSI); //restore saved address from opts->gen.scratch1
+	push_r(code, RAX); //save context pointer for later
+	push_r(code, RSI); //2nd arg -- address
+	push_r(code, RAX); //1st arg -- context pointer
+	call(code, (code_ptr)get_native_address_trans);
+	add_ir(code, 8, RSP, SZ_D);
+#endif
+
+	mov_rr(code, RAX, opts->gen.scratch1, SZ_PTR); //move result to scratch reg
+	pop_r(code, opts->gen.context_reg);
+	call(code, opts->gen.load_context);
+	retn(code);
+
+	opts->gen.handle_cycle_limit = code->cur;
+	cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), CYCLES, SZ_D);
+	code_ptr skip_sync = code->cur + 1;
+	jcc(code, CC_C, code->cur + 2);
+	opts->do_sync = code->cur;
+	push_r(code, opts->gen.scratch1);
+	push_r(code, opts->gen.scratch2);
+	call(code, opts->gen.save_context);
+#ifdef X86_64
+	mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR);
+	xor_rr(code, RSI, RSI, SZ_D);
+	test_ir(code, 8, RSP, SZ_D);
+	code_ptr adjust_rsp = code->cur + 1;
+	jcc(code, CC_NZ, code->cur + 2);
+	call(code, (code_ptr)sync_components);
+	code_ptr no_adjust = code->cur + 1;
+	jmp(code, code->cur + 2);
+	*adjust_rsp = code->cur - (adjust_rsp + 1);
+	sub_ir(code, 8, RSP, SZ_PTR);
+	call(code, (code_ptr)sync_components);
+	add_ir(code, 8, RSP, SZ_PTR);
+	*no_adjust = code->cur - (no_adjust+1);
+#else
+	//TODO: Add support for pushing a constant in gen_x86
+	xor_rr(code, RAX, RAX, SZ_D);
+	push_r(code, RAX);
+	push_r(code, opts->gen.context_reg);
+	call(code, (code_ptr)sync_components);
+	add_ir(code, 8, RSP, SZ_D);
+#endif
+	mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR);
+	call(code, opts->gen.load_context);
+	pop_r(code, opts->gen.scratch2);
+	pop_r(code, opts->gen.scratch1);
+	*skip_sync = code->cur - (skip_sync+1);
+	retn(code);
+
+	opts->gen.handle_code_write = (code_ptr)m68k_handle_code_write;
+
+	opts->read_16 = gen_mem_fun(&opts->gen, memmap, num_chunks, READ_16, NULL);
+	opts->read_8 = gen_mem_fun(&opts->gen, memmap, num_chunks, READ_8, NULL);
+	opts->write_16 = gen_mem_fun(&opts->gen, memmap, num_chunks, WRITE_16, NULL);
+	opts->write_8 = gen_mem_fun(&opts->gen, memmap, num_chunks, WRITE_8, NULL);
+
+	opts->read_32 = code->cur;
+	push_r(code, opts->gen.scratch1);
+	call(code, opts->read_16);
+	mov_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_W);
+	pop_r(code, opts->gen.scratch1);
+	push_r(code, opts->gen.scratch2);
+	add_ir(code, 2, opts->gen.scratch1, SZ_D);
+	call(code, opts->read_16);
+	pop_r(code, opts->gen.scratch2);
+	movzx_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_W, SZ_D);
+	shl_ir(code, 16, opts->gen.scratch2, SZ_D);
+	or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_D);
+	retn(code);
+
+	opts->write_32_lowfirst = code->cur;
+	push_r(code, opts->gen.scratch2);
+	push_r(code, opts->gen.scratch1);
+	add_ir(code, 2, opts->gen.scratch2, SZ_D);
+	call(code, opts->write_16);
+	pop_r(code, opts->gen.scratch1);
+	pop_r(code, opts->gen.scratch2);
+	shr_ir(code, 16, opts->gen.scratch1, SZ_D);
+	jmp(code, opts->write_16);
+
+	opts->write_32_highfirst = code->cur;
+	push_r(code, opts->gen.scratch1);
+	push_r(code, opts->gen.scratch2);
+	shr_ir(code, 16, opts->gen.scratch1, SZ_D);
+	call(code, opts->write_16);
+	pop_r(code, opts->gen.scratch2);
+	pop_r(code, opts->gen.scratch1);
+	add_ir(code, 2, opts->gen.scratch2, SZ_D);
+	jmp(code, opts->write_16);
+
+	opts->get_sr = code->cur;
+	mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, status), opts->gen.scratch1, SZ_B);
+	shl_ir(code, 8, opts->gen.scratch1, SZ_W);
+	if (opts->flag_regs[FLAG_X] >= 0) {
+		mov_rr(code, opts->flag_regs[FLAG_X], opts->gen.scratch1, SZ_B);
+	} else {
+		int8_t offset = offsetof(m68k_context, flags);
+		if (offset) {
+			mov_rdispr(code, opts->gen.context_reg, offset, opts->gen.scratch1, SZ_B);
+		} else {
+			mov_rindr(code, opts->gen.context_reg, opts->gen.scratch1, SZ_B);
+		}
+	}
+	for (int flag = FLAG_N; flag <= FLAG_C; flag++)
+	{
+		shl_ir(code, 1, opts->gen.scratch1, SZ_B);
+		if (opts->flag_regs[flag] >= 0) {
+			or_rr(code, opts->flag_regs[flag], opts->gen.scratch1, SZ_B);
+		} else {
+			or_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, opts->gen.scratch1, SZ_B);
+		}
+	}
+	retn(code);
+
+	opts->set_sr = code->cur;
+	for (int flag = FLAG_C; flag >= FLAG_X; flag--)
+	{
+		rcr_ir(code, 1, opts->gen.scratch1, SZ_B);
+		if (opts->flag_regs[flag] >= 0) {
+			setcc_r(code, CC_C, opts->flag_regs[flag]);
+		} else {
+			int8_t offset = offsetof(m68k_context, flags) + flag;
+			if (offset) {
+				setcc_rdisp(code, CC_C, opts->gen.context_reg, offset);
+			} else {
+				setcc_rind(code, CC_C, opts->gen.context_reg);
+			}
+		}
+	}
+	shr_ir(code, 8, opts->gen.scratch1, SZ_W);
+	mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
+	retn(code);
+
+	opts->set_ccr = code->cur;
+	for (int flag = FLAG_C; flag >= FLAG_X; flag--)
+	{
+		rcr_ir(code, 1, opts->gen.scratch1, SZ_B);
+		if (opts->flag_regs[flag] >= 0) {
+			setcc_r(code, CC_C, opts->flag_regs[flag]);
+		} else {
+			int8_t offset = offsetof(m68k_context, flags) + flag;
+			if (offset) {
+				setcc_rdisp(code, CC_C, opts->gen.context_reg, offset);
+			} else {
+				setcc_rind(code, CC_C, opts->gen.context_reg);
+			}
+		}
+	}
+	retn(code);
+
+	opts->gen.handle_cycle_limit_int = code->cur;
+	cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), CYCLES, SZ_D);
+	code_ptr do_int = code->cur + 1;
+	jcc(code, CC_NC, code->cur + 2);
+	cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), CYCLES, SZ_D);
+	skip_sync = code->cur + 1;
+	jcc(code, CC_C, code->cur + 2);
+	call(code, opts->gen.save_context);
+#ifdef X86_64
+	mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR);
+	mov_rr(code, opts->gen.scratch1, RSI, SZ_D);
+	test_ir(code, 8, RSP, SZ_D);
+	adjust_rsp = code->cur + 1;
+	jcc(code, CC_NZ, code->cur + 2);
+	call(code, (code_ptr)sync_components);
+	no_adjust = code->cur + 1;
+	jmp(code, code->cur + 2);
+	*adjust_rsp = code->cur - (adjust_rsp + 1);
+	sub_ir(code, 8, RSP, SZ_PTR);
+	call(code, (code_ptr)sync_components);
+	add_ir(code, 8, RSP, SZ_PTR);
+	*no_adjust = code->cur - (no_adjust+1);
+#else
+	push_r(code, opts->gen.scratch1);
+	push_r(code, opts->gen.context_reg);
+	call(code, (code_ptr)sync_components);
+	add_ir(code, 8, RSP, SZ_D);
+#endif
+	mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR);
+	jmp(code, opts->gen.load_context);
+	*skip_sync = code->cur - (skip_sync+1);
+	retn(code);
+	*do_int = code->cur - (do_int+1);
+	//set target cycle to sync cycle
+	mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), LIMIT, SZ_D);
+	//swap USP and SSP if not already in supervisor mode
+	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);
+	swap_ssp_usp(opts);
+	*already_supervisor = code->cur - (already_supervisor+1);
+	//save PC
+	subi_areg(opts, 4, 7);
+	areg_to_native(opts, 7, opts->gen.scratch2);
+	call(code, opts->write_32_lowfirst);
+	//save status register
+	subi_areg(opts, 2, 7);
+	call(code, opts->get_sr);
+	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);
+	mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch1, SZ_B);
+	or_ir(code, 0x20, opts->gen.scratch1, SZ_B);
+	or_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
+	//calculate interrupt vector address
+	mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch1, SZ_D);
+	mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, int_ack), SZ_W);
+	shl_ir(code, 2, opts->gen.scratch1, SZ_D);
+	add_ir(code, 0x60, opts->gen.scratch1, SZ_D);
+	call(code, opts->read_32);
+	call(code, opts->native_addr_and_sync);
+	cycles(&opts->gen, 24);
+	//discard function return address
+	pop_r(code, opts->gen.scratch2);
+	jmp_r(code, opts->gen.scratch1);
+
+	opts->trap = code->cur;
+	push_r(code, opts->gen.scratch2);
+	//swap USP and SSP if not already in supervisor mode
+	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);
+	swap_ssp_usp(opts);
+	*already_supervisor = code->cur - (already_supervisor+1);
+	//save PC
+	subi_areg(opts, 4, 7);
+	areg_to_native(opts, 7, opts->gen.scratch2);
+	call(code, opts->write_32_lowfirst);
+	//save status register
+	subi_areg(opts, 2, 7);
+	call(code, opts->get_sr);
+	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);
+	//calculate vector address
+	pop_r(code, opts->gen.scratch1);
+	shl_ir(code, 2, opts->gen.scratch1, SZ_D);
+	call(code, opts->read_32);
+	call(code, opts->native_addr_and_sync);
+	cycles(&opts->gen, 18);
+	jmp_r(code, opts->gen.scratch1);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m68k_internal.h	Tue Dec 30 19:11:34 2014 -0800
@@ -0,0 +1,116 @@
+/*
+ Copyright 2014 Michael Pavone
+ This file is part of BlastEm.
+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
+*/
+#ifndef M68K_INTERNAL_H_
+#define M68K_INTERNAL_H_
+
+#include "68kinst.h"
+
+//functions implemented in host CPU specfic file
+void translate_out_of_bounds(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_native(m68k_options *opts, int32_t value, uint8_t reg);
+void subi_native(m68k_options *opts, int32_t value, uint8_t reg);
+void push_native(m68k_options *opts, uint8_t reg);
+void pop_native(m68k_options *opts, uint8_t reg);
+void sign_extend16_native(m68k_options *opts, 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);
+void nop_fill_or_jmp_next(code_info *code, code_ptr old_end, code_ptr next_inst);
+
+//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 translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8_t dst);
+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);
+uint8_t m68k_is_terminal(m68kinst * inst);
+void m68k_handle_deferred(m68k_context * context);
+code_ptr get_native_address_trans(m68k_context * context, uint32_t address);
+void * m68k_retranslate_inst(uint32_t address, m68k_context * context);
+
+//individual instructions
+void translate_m68k_bcc(m68k_options * opts, m68kinst * inst);
+void translate_m68k_scc(m68k_options * opts, m68kinst * inst);
+void translate_m68k_dbcc(m68k_options * opts, m68kinst * inst);
+void translate_m68k_rtr(m68k_options *opts, m68kinst * inst);
+void translate_m68k_trap(m68k_options *opts, m68kinst *inst);
+void translate_m68k_move(m68k_options * opts, m68kinst * inst);
+void translate_m68k_movep(m68k_options * opts, m68kinst * inst);
+void translate_m68k_arith(m68k_options *opts, m68kinst * inst, uint32_t flag_mask, host_ea *src_op, host_ea *dst_op);
+void translate_m68k_unary(m68k_options *opts, m68kinst *inst, uint32_t flag_mask, host_ea *dst_op);
+void translate_m68k_invalid(m68k_options *opts, m68kinst *inst);
+void translate_m68k_cmp(m68k_options * opts, m68kinst * inst);
+void translate_m68k_clr(m68k_options * opts, m68kinst * inst);
+void translate_m68k_ext(m68k_options * opts, m68kinst * inst);
+void translate_m68k_abcd_sbcd(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
+void translate_m68k_sl(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
+void translate_m68k_asr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
+void translate_m68k_lsr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
+void translate_m68k_bit(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
+void translate_m68k_chk(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
+void translate_m68k_div(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
+void translate_m68k_exg(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
+void translate_m68k_mul(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
+void translate_m68k_negx(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
+void translate_m68k_rot(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
+void translate_m68k_illegal(m68k_options *opts, m68kinst *inst);
+void translate_m68k_andi_ori_ccr_sr(m68k_options *opts, m68kinst *inst);
+void translate_m68k_eori_ccr_sr(m68k_options *opts, m68kinst *inst);
+void translate_m68k_move_ccr_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
+void translate_m68k_stop(m68k_options *opts, m68kinst *inst);
+void translate_m68k_move_from_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
+void translate_m68k_reset(m68k_options *opts, m68kinst *inst);
+void translate_m68k_rte(m68k_options *opts, m68kinst *inst);
+
+//flag update bits
+#define X0  0x0001
+#define X1  0x0002
+#define X   0x0004
+#define N0  0x0008
+#define N1  0x0010
+#define N   0x0020
+#define Z0  0x0040
+#define Z1  0x0080
+#define Z   0x0100
+#define V0  0x0200
+#define V1  0x0400
+#define V   0x0800
+#define C0  0x1000
+#define C1  0x2000
+#define C   0x4000
+
+#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_
--- a/m68k_to_x86.c	Tue Dec 16 01:10:54 2014 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4561 +0,0 @@
-/*
- Copyright 2013 Michael Pavone
- This file is part of BlastEm.
- BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
-*/
-#include "gen_x86.h"
-#include "m68k_to_x86.h"
-#include "68kinst.h"
-#include "mem.h"
-#include "x86_backend.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 SCRATCH1 RCX
-#define SCRATCH2 RDI
-#define CONTEXT RSI
-
-#define FLAG_N RBX
-#define FLAG_V BH
-#define FLAG_Z RDX
-#define FLAG_C DH
-
-char disasm_buf[1024];
-
-m68k_context * sync_components(m68k_context * context, uint32_t address);
-
-void handle_cycle_limit();
-void m68k_save_context();
-void m68k_load_context();
-void m68k_modified_ret_addr();
-void m68k_native_addr();
-void m68k_native_addr_and_sync();
-void m68k_invalid();
-void m68k_retrans_stub();
-void set_sr();
-void set_ccr();
-void get_sr();
-void do_sync();
-void bcd_add();
-void bcd_sub();
-void m68k_start_context(uint8_t * addr, m68k_context * context);
-void debug_print_sr();
-
-uint8_t * cycles(uint8_t * dst, uint32_t num)
-{
-	dst = add_ir(dst, num, CYCLES, SZ_D);
-	return dst;
-}
-
-uint8_t * check_cycles_int(uint8_t * dst, uint32_t address, x86_68k_options * opts)
-{
-	dst = cmp_rr(dst, CYCLES, LIMIT, SZ_D);
-	uint8_t * jmp_off = dst+1;
-	dst = jcc(dst, CC_NC, dst + 7);
-	dst = mov_ir(dst, address, SCRATCH1, SZ_D);
-	dst = call(dst, opts->handle_cycle_limit_int);
-	*jmp_off = dst - (jmp_off+1);
-	return dst;
-}
-
-uint8_t * check_cycles(uint8_t * dst)
-{
-	dst = cmp_rr(dst, CYCLES, LIMIT, SZ_D);
-	uint8_t * jmp_off = dst+1;
-	dst = jcc(dst, CC_NC, dst + 7);
-	dst = call(dst, (uint8_t *)handle_cycle_limit);
-	*jmp_off = dst - (jmp_off+1);
-	return dst;
-}
-
-int8_t native_reg(m68k_op_info * op, x86_68k_options * opts)
-{
-	if (op->addr_mode == MODE_REG) {
-		return opts->dregs[op->params.regs.pri];
-	}
-	if (op->addr_mode == MODE_AREG) {
-		return opts->aregs[op->params.regs.pri];
-	}
-	return -1;
-}
-
-//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;
-}
-
-void print_regs_exit(m68k_context * context)
-{
-	printf("XNZVC\n%d%d%d%d%d\n", context->flags[0], context->flags[1], context->flags[2], context->flags[3], context->flags[4]);
-	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);
-	uint8_t sec_reg;
-	int32_t dec_amount,inc_amount;
-	if (reg >= 0) {
-		ea->mode = MODE_REG_DIRECT;
-		if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) {
-			out = movsx_rr(out, reg, SCRATCH1, SZ_W, SZ_D);
-			ea->base = SCRATCH1;
-		} else {
-			ea->base = reg;
-		}
-		return out;
-	}
-	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 = reg_offset(&(inst->src));
-		} else {
-			if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) {
-				out = movsx_rdisp8r(out, CONTEXT, reg_offset(&(inst->src)), SCRATCH1, SZ_W, SZ_D);
-			} else {
-				out = mov_rdisp8r(out, CONTEXT, reg_offset(&(inst->src)), SCRATCH1, inst->extra.size);
-			}
-			ea->mode = MODE_REG_DIRECT;
-			ea->base = SCRATCH1;
-			//we're explicitly handling the areg dest here, so we exit immediately
-			return out;
-		}
-		break;
-	case MODE_AREG_PREDEC:
-		dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->src.params.regs.pri == 7 ? 2 :1));
-		out = cycles(out, PREDEC_PENALTY);
-		if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-			out = sub_ir(out, dec_amount, opts->aregs[inst->src.params.regs.pri], SZ_D);
-		} else {
-			out = sub_irdisp8(out, dec_amount, CONTEXT, reg_offset(&(inst->src)), SZ_D);
-		}
-	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,  reg_offset(&(inst->src)), SCRATCH1, SZ_D);
-		}
-		switch (inst->extra.size)
-		{
-		case OPSIZE_BYTE:
-			out = call(out, opts->read_8);
-			break;
-		case OPSIZE_WORD:
-			out = call(out, opts->read_16);
-			break;
-		case OPSIZE_LONG:
-			out = call(out, opts->read_32);
-			break;
-		}
-
-		if (inst->src.addr_mode == MODE_AREG_POSTINC) {
-			inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->src.params.regs.pri == 7 ? 2 : 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, reg_offset(&(inst->src)), SZ_D);
-			}
-		}
-		ea->mode = MODE_REG_DIRECT;
-		ea->base = (inst->dst.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) ? SCRATCH2 : SCRATCH1;
-		break;
-	case MODE_AREG_DISPLACE:
-		out = cycles(out, BUS);
-		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,  reg_offset(&(inst->src)), SCRATCH1, SZ_D);
-		}
-		out = add_ir(out, inst->src.params.regs.displacement, SCRATCH1, SZ_D);
-		switch (inst->extra.size)
-		{
-		case OPSIZE_BYTE:
-			out = call(out, opts->read_8);
-			break;
-		case OPSIZE_WORD:
-			out = call(out, opts->read_16);
-			break;
-		case OPSIZE_LONG:
-			out = call(out, opts->read_32);
-			break;
-		}
-		ea->mode = MODE_REG_DIRECT;
-		ea->base = SCRATCH1;
-		break;
-	case MODE_AREG_INDEX_DISP8:
-		out = cycles(out, 6);
-		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,  reg_offset(&(inst->src)), 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) {
-					out = add_rr(out, opts->aregs[sec_reg], SCRATCH1, SZ_D);
-				} else {
-					out = add_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					out = add_rr(out, opts->dregs[sec_reg], SCRATCH1, SZ_D);
-				} else {
-					out = add_rdisp8r(out, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D);
-				}
-			}
-		} else {
-			if (inst->src.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					out = movsx_rr(out, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
-				} else {
-					out = movsx_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					out = movsx_rr(out, opts->dregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
-				} else {
-					out = movsx_rdisp8r(out, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D);
-				}
-			}
-			out = add_rr(out, SCRATCH2, SCRATCH1, SZ_D);
-		}
-		if (inst->src.params.regs.displacement) {
-			out = add_ir(out, inst->src.params.regs.displacement, SCRATCH1, SZ_D);
-		}
-		switch (inst->extra.size)
-		{
-		case OPSIZE_BYTE:
-			out = call(out, opts->read_8);
-			break;
-		case OPSIZE_WORD:
-			out = call(out, opts->read_16);
-			break;
-		case OPSIZE_LONG:
-			out = call(out, opts->read_32);
-			break;
-		}
-		ea->mode = MODE_REG_DIRECT;
-		ea->base = SCRATCH1;
-		break;
-	case MODE_PC_DISPLACE:
-		out = cycles(out, BUS);
-		out = mov_ir(out, inst->src.params.regs.displacement + inst->address+2, SCRATCH1, SZ_D);
-		switch (inst->extra.size)
-		{
-		case OPSIZE_BYTE:
-			out = call(out, opts->read_8);
-			break;
-		case OPSIZE_WORD:
-			out = call(out, opts->read_16);
-			break;
-		case OPSIZE_LONG:
-			out = call(out, opts->read_32);
-			break;
-		}
-		ea->mode = MODE_REG_DIRECT;
-		ea->base = SCRATCH1;
-		break;
-	case MODE_PC_INDEX_DISP8:
-		out = cycles(out, 6);
-		out = mov_ir(out, inst->address+2, 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) {
-					out = add_rr(out, opts->aregs[sec_reg], SCRATCH1, SZ_D);
-				} else {
-					out = add_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					out = add_rr(out, opts->dregs[sec_reg], SCRATCH1, SZ_D);
-				} else {
-					out = add_rdisp8r(out, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D);
-				}
-			}
-		} else {
-			if (inst->src.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					out = movsx_rr(out, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
-				} else {
-					out = movsx_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					out = movsx_rr(out, opts->dregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
-				} else {
-					out = movsx_rdisp8r(out, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D);
-				}
-			}
-			out = add_rr(out, SCRATCH2, SCRATCH1, SZ_D);
-		}
-		if (inst->src.params.regs.displacement) {
-			out = add_ir(out, inst->src.params.regs.displacement, SCRATCH1, SZ_D);
-		}
-		switch (inst->extra.size)
-		{
-		case OPSIZE_BYTE:
-			out = call(out, opts->read_8);
-			break;
-		case OPSIZE_WORD:
-			out = call(out, opts->read_16);
-			break;
-		case OPSIZE_LONG:
-			out = call(out, opts->read_32);
-			break;
-		}
-		ea->mode = MODE_REG_DIRECT;
-		ea->base = SCRATCH1;
-		break;
-	case MODE_ABSOLUTE:
-	case MODE_ABSOLUTE_SHORT:
-		if (inst->src.addr_mode == MODE_ABSOLUTE) {
-			out = cycles(out, BUS*2);
-		} else {
-			out = cycles(out, BUS);
-		}
-		out = mov_ir(out, inst->src.params.immed, SCRATCH1, SZ_D);
-		switch (inst->extra.size)
-		{
-		case OPSIZE_BYTE:
-			out = call(out, opts->read_8);
-			break;
-		case OPSIZE_WORD:
-			out = call(out, opts->read_16);
-			break;
-		case OPSIZE_LONG:
-			out = call(out, opts->read_32);
-			break;
-		}
-		ea->mode = MODE_REG_DIRECT;
-		ea->base = SCRATCH1;
-		break;
-	case MODE_IMMEDIATE:
-	case MODE_IMMEDIATE_WORD:
-		if (inst->variant != VAR_QUICK) {
-			out = cycles(out, (inst->extra.size == OPSIZE_LONG && inst->src.addr_mode == MODE_IMMEDIATE) ? BUS*2 : BUS);
-		}
-		ea->mode = MODE_IMMED;
-		ea->disp = inst->src.params.immed;
-		if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD && ea->disp & 0x8000) {
-			ea->disp |= 0xFFFF0000;
-		}
-		return out;
-	default:
-		m68k_disasm(inst, disasm_buf);
-		printf("%X: %s\naddress mode %d not implemented (src)\n", inst->address, disasm_buf, inst->src.addr_mode);
-		exit(1);
-	}
-	if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) {
-		if (ea->mode == MODE_REG_DIRECT) {
-			out = movsx_rr(out, ea->base, SCRATCH1, SZ_W, SZ_D);
-		} else {
-			out = movsx_rdisp8r(out, ea->base, ea->disp, SCRATCH1, SZ_W, SZ_D);
-			ea->mode = MODE_REG_DIRECT;
-		}
-		ea->base = SCRATCH1;
-	}
-	return out;
-}
-
-uint8_t * translate_m68k_dst(m68kinst * inst, x86_ea * ea, uint8_t * out, x86_68k_options * opts, uint8_t fake_read)
-{
-	int8_t reg = native_reg(&(inst->dst), opts), sec_reg;
-	int32_t dec_amount, inc_amount;
-	if (reg >= 0) {
-		ea->mode = MODE_REG_DIRECT;
-		ea->base = reg;
-		return out;
-	}
-	switch (inst->dst.addr_mode)
-	{
-	case MODE_REG:
-	case MODE_AREG:
-		ea->mode = MODE_REG_DISPLACE8;
-		ea->base = CONTEXT;
-		ea->disp = reg_offset(&(inst->dst));
-		break;
-	case MODE_AREG_PREDEC:
-		if (inst->src.addr_mode == MODE_AREG_PREDEC) {
-			out = push_r(out, SCRATCH1);
-		}
-		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) {
-			out = sub_ir(out, dec_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D);
-		} else {
-			out = sub_irdisp8(out, dec_amount, CONTEXT, reg_offset(&(inst->dst)), SZ_D);
-		}
-	case MODE_AREG_INDIRECT:
-	case MODE_AREG_POSTINC:
-		if (fake_read) {
-			out = cycles(out, inst->extra.size == OPSIZE_LONG ? 8 : 4);
-		} else {
-			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, reg_offset(&(inst->dst)), SCRATCH1, SZ_D);
-			}
-			switch (inst->extra.size)
-			{
-			case OPSIZE_BYTE:
-				out = call(out, opts->read_8);
-				break;
-			case OPSIZE_WORD:
-				out = call(out, opts->read_16);
-				break;
-			case OPSIZE_LONG:
-				out = call(out, opts->read_32);
-				break;
-			}
-		}
-		if (inst->src.addr_mode == MODE_AREG_PREDEC) {
-			//restore src operand to SCRATCH2
-			out =pop_r(out, SCRATCH2);
-		} else {
-			//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, reg_offset(&(inst->dst)), SCRATCH2, SZ_D);
-			}
-		}
-
-		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) {
-				out = add_ir(out, inc_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D);
-			} else {
-				out = add_irdisp8(out, inc_amount, CONTEXT, reg_offset(&(inst->dst)), SZ_D);
-			}
-		}
-		ea->mode = MODE_REG_DIRECT;
-		ea->base = SCRATCH1;
-		break;
-	case MODE_AREG_DISPLACE:
-		out = cycles(out, fake_read ? BUS+(inst->extra.size == OPSIZE_LONG ? BUS*2 : BUS) : BUS);
-		reg = fake_read ? SCRATCH2 : SCRATCH1;
-		if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
-			out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], reg, SZ_D);
-		} else {
-			out = mov_rdisp8r(out, CONTEXT,  reg_offset(&(inst->dst)), reg, SZ_D);
-		}
-		out = add_ir(out, inst->dst.params.regs.displacement, reg, SZ_D);
-		if (!fake_read) {
-			out = push_r(out, SCRATCH1);
-			switch (inst->extra.size)
-			{
-			case OPSIZE_BYTE:
-				out = call(out, opts->read_8);
-				break;
-			case OPSIZE_WORD:
-				out = call(out, opts->read_16);
-				break;
-			case OPSIZE_LONG:
-				out = call(out, opts->read_32);
-				break;
-			}
-			out = pop_r(out, SCRATCH2);
-		}
-		ea->mode = MODE_REG_DIRECT;
-		ea->base = SCRATCH1;
-		break;
-	case MODE_AREG_INDEX_DISP8:
-		out = cycles(out, fake_read ? (6 + inst->extra.size == OPSIZE_LONG ? 8 : 4) : 6);
-		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,  reg_offset(&(inst->dst)), SCRATCH1, 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) {
-					out = add_rr(out, opts->aregs[sec_reg], SCRATCH1, SZ_D);
-				} else {
-					out = add_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					out = add_rr(out, opts->dregs[sec_reg], SCRATCH1, SZ_D);
-				} else {
-					out = add_rdisp8r(out, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D);
-				}
-			}
-		} else {
-			if (inst->dst.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					out = movsx_rr(out, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
-				} else {
-					out = movsx_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					out = movsx_rr(out, opts->dregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
-				} else {
-					out = movsx_rdisp8r(out, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D);
-				}
-			}
-			out = add_rr(out, SCRATCH2, SCRATCH1, SZ_D);
-		}
-		if (inst->dst.params.regs.displacement) {
-			out = add_ir(out, inst->dst.params.regs.displacement, SCRATCH1, SZ_D);
-		}
-		if (fake_read) {
-			out = mov_rr(out, SCRATCH1, SCRATCH2, SZ_D);
-		} else {
-			out = push_r(out, SCRATCH1);
-			switch (inst->extra.size)
-			{
-			case OPSIZE_BYTE:
-				out = call(out, opts->read_8);
-				break;
-			case OPSIZE_WORD:
-				out = call(out, opts->read_16);
-				break;
-			case OPSIZE_LONG:
-				out = call(out, opts->read_32);
-				break;
-			}
-			out = pop_r(out, SCRATCH2);
-		}
-		ea->mode = MODE_REG_DIRECT;
-		ea->base = SCRATCH1;
-		break;
-	case MODE_PC_DISPLACE:
-		out = cycles(out, fake_read ? BUS+(inst->extra.size == OPSIZE_LONG ? BUS*2 : BUS) : BUS);
-		out = mov_ir(out, inst->dst.params.regs.displacement + inst->address+2, fake_read ? SCRATCH2 : SCRATCH1, SZ_D);
-		if (!fake_read) {
-			out = push_r(out, SCRATCH1);
-			switch (inst->extra.size)
-			{
-			case OPSIZE_BYTE:
-				out = call(out, opts->read_8);
-				break;
-			case OPSIZE_WORD:
-				out = call(out, opts->read_16);
-				break;
-			case OPSIZE_LONG:
-				out = call(out, opts->read_32);
-				break;
-			}
-			out = pop_r(out, SCRATCH2);
-		}
-		ea->mode = MODE_REG_DIRECT;
-		ea->base = SCRATCH1;
-		break;
-	case MODE_PC_INDEX_DISP8:
-		out = cycles(out, fake_read ? (6 + inst->extra.size == OPSIZE_LONG ? 8 : 4) : 6);
-		out = mov_ir(out, inst->address+2, SCRATCH1, 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) {
-					out = add_rr(out, opts->aregs[sec_reg], SCRATCH1, SZ_D);
-				} else {
-					out = add_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					out = add_rr(out, opts->dregs[sec_reg], SCRATCH1, SZ_D);
-				} else {
-					out = add_rdisp8r(out, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D);
-				}
-			}
-		} else {
-			if (inst->dst.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					out = movsx_rr(out, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
-				} else {
-					out = movsx_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					out = movsx_rr(out, opts->dregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
-				} else {
-					out = movsx_rdisp8r(out, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D);
-				}
-			}
-			out = add_rr(out, SCRATCH2, SCRATCH1, SZ_D);
-		}
-		if (inst->dst.params.regs.displacement) {
-			out = add_ir(out, inst->dst.params.regs.displacement, SCRATCH1, SZ_D);
-		}
-		if (fake_read) {
-			out = mov_rr(out, SCRATCH1, SCRATCH2, SZ_D);
-		} else {
-			out = push_r(out, SCRATCH1);
-			switch (inst->extra.size)
-			{
-			case OPSIZE_BYTE:
-				out = call(out, opts->read_8);
-				break;
-			case OPSIZE_WORD:
-				out = call(out, opts->read_16);
-				break;
-			case OPSIZE_LONG:
-				out = call(out, opts->read_32);
-				break;
-			}
-			out = pop_r(out, SCRATCH2);
-		}
-		ea->mode = MODE_REG_DIRECT;
-		ea->base = SCRATCH1;
-		break;
-	case MODE_ABSOLUTE:
-	case MODE_ABSOLUTE_SHORT:
-		//Add cycles for reading address from instruction stream
-		out = cycles(out, (inst->dst.addr_mode == MODE_ABSOLUTE ? BUS*2 : BUS) + (fake_read ? (inst->extra.size == OPSIZE_LONG ? BUS*2 : BUS) : 0));
-		out = mov_ir(out, inst->dst.params.immed, fake_read ? SCRATCH2 : SCRATCH1, SZ_D);
-		if (!fake_read) {
-			out = push_r(out, SCRATCH1);
-			switch (inst->extra.size)
-			{
-			case OPSIZE_BYTE:
-				out = call(out, opts->read_8);
-				break;
-			case OPSIZE_WORD:
-				out = call(out, opts->read_16);
-				break;
-			case OPSIZE_LONG:
-				out = call(out, opts->read_32);
-				break;
-			}
-			out = pop_r(out, SCRATCH2);
-		}
-		ea->mode = MODE_REG_DIRECT;
-		ea->base = SCRATCH1;
-		break;
-	default:
-		m68k_disasm(inst, disasm_buf);
-		printf("%X: %s\naddress mode %d not implemented (dst)\n", inst->address, disasm_buf, 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) {
-		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) {
-				out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D);
-			} else {
-				out = mov_rdisp8r(out, CONTEXT, reg_offset(&(inst->dst)), SCRATCH2, SZ_D);
-			}
-		}
-		switch (inst->extra.size)
-		{
-		case OPSIZE_BYTE:
-			out = call(out, opts->write_8);
-			break;
-		case OPSIZE_WORD:
-			out = call(out, opts->write_16);
-			break;
-		case OPSIZE_LONG:
-			out = call(out, opts->write_32_lowfirst);
-			break;
-		}
-	}
-	return out;
-}
-
-uint8_t * get_native_address(native_map_slot * native_code_map, uint32_t address)
-{
-	address &= 0xFFFFFF;
-	address /= 2;
-	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 || native_code_map[chunk].offsets[offset] == EXTENSION_WORD) {
-		return NULL;
-	}
-	return native_code_map[chunk].base + native_code_map[chunk].offsets[offset];
-}
-
-uint8_t * get_native_from_context(m68k_context * context, uint32_t address)
-{
-	return get_native_address(context->native_code_map, address);
-}
-
-uint32_t get_instruction_start(native_map_slot * native_code_map, uint32_t address)
-{
-	address &= 0xFFFFFF;
-	address /= 2;
-	uint32_t chunk = address / NATIVE_CHUNK_SIZE;
-	if (!native_code_map[chunk].base) {
-		return 0;
-	}
-	uint32_t offset = address % NATIVE_CHUNK_SIZE;
-	if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET) {
-		return 0;
-	}
-	while (native_code_map[chunk].offsets[offset] == EXTENSION_WORD) {
-		--address;
-		chunk = address / NATIVE_CHUNK_SIZE;
-		offset = address % NATIVE_CHUNK_SIZE;
-	}
-	return address*2;
-}
-
-void map_native_address(m68k_context * context, uint32_t address, uint8_t * native_addr, uint8_t size, uint8_t native_size)
-{
-	native_map_slot * native_code_map = context->native_code_map;
-	x86_68k_options * opts = context->options;
-	address &= 0xFFFFFF;
-	if (address > 0xE00000) {
-		context->ram_code_flags[(address & 0xC000) >> 14] |= 1 << ((address & 0x3800) >> 11);
-		if (((address & 0x3FFF) + size) & 0xC000) {
-			context->ram_code_flags[((address+size) & 0xC000) >> 14] |= 1 << (((address+size) & 0x3800) >> 11);
-		}
-		uint32_t slot = (address & 0xFFFF)/1024;
-		if (!opts->ram_inst_sizes[slot]) {
-			opts->ram_inst_sizes[slot] = malloc(sizeof(uint8_t) * 512);
-		}
-		opts->ram_inst_sizes[slot][((address & 0xFFFF)/2)%512] = native_size;
-	}
-	address/= 2;
-	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(int32_t) * NATIVE_CHUNK_SIZE);
-		memset(native_code_map[chunk].offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE);
-	}
-	uint32_t offset = address % NATIVE_CHUNK_SIZE;
-	native_code_map[chunk].offsets[offset] = native_addr-native_code_map[chunk].base;
-	for(address++,size-=2; size; address++,size-=2) {
-		chunk = address / NATIVE_CHUNK_SIZE;
-		offset = address % NATIVE_CHUNK_SIZE;
-		if (!native_code_map[chunk].base) {
-			native_code_map[chunk].base = native_addr;
-			native_code_map[chunk].offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE);
-			memset(native_code_map[chunk].offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE);
-		}
-		native_code_map[chunk].offsets[offset] = EXTENSION_WORD;
-	}
-}
-
-uint8_t get_native_inst_size(x86_68k_options * opts, uint32_t address)
-{
-	if (address < 0xE00000) {
-		return 0;
-	}
-	uint32_t slot = (address & 0xFFFF)/1024;
-	return opts->ram_inst_sizes[slot][((address & 0xFFFF)/2)%512];
-}
-
-uint8_t * translate_m68k_move(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
-{
-	int8_t reg, flags_reg, sec_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 (inst->dst.addr_mode != MODE_AREG) {
-		//update statically set flags
-		dst = mov_ir(dst, 0, FLAG_V, SZ_B);
-		dst = mov_ir(dst, 0, FLAG_C, SZ_B);
-	}
-
-	if (inst->dst.addr_mode != MODE_AREG) {
-		if (src.mode == MODE_REG_DIRECT) {
-			flags_reg = src.base;
-		} else {
-			if (reg >= 0) {
-				flags_reg = reg;
-			} 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);
-				}
-				src.mode = MODE_REG_DIRECT;
-				flags_reg = src.base = SCRATCH1;
-			}
-		}
-	}
-	uint8_t size = inst->extra.size;
-	switch(inst->dst.addr_mode)
-	{
-	case MODE_AREG:
-		size = OPSIZE_LONG;
-	case MODE_REG:
-		if (reg >= 0) {
-			if (src.mode == MODE_REG_DIRECT) {
-				dst = mov_rr(dst, src.base, reg, size);
-			} else if (src.mode == MODE_REG_DISPLACE8) {
-				dst = mov_rdisp8r(dst, src.base, src.disp, reg, size);
-			} else {
-				dst = mov_ir(dst, src.disp, reg, size);
-			}
-		} else if(src.mode == MODE_REG_DIRECT) {
-			dst = mov_rrdisp8(dst, src.base, CONTEXT, reg_offset(&(inst->dst)), size);
-		} else {
-			dst = mov_irdisp8(dst, src.disp, CONTEXT, reg_offset(&(inst->dst)), size);
-		}
-		if (inst->dst.addr_mode != MODE_AREG) {
-			dst = cmp_ir(dst, 0, flags_reg, size);
-			dst = setcc_r(dst, CC_Z, FLAG_Z);
-			dst = setcc_r(dst, CC_S, FLAG_N);
-		}
-		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) {
-			dst = sub_ir(dst, dec_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D);
-		} else {
-			dst = sub_irdisp8(dst, dec_amount, CONTEXT, reg_offset(&(inst->dst)), 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, reg_offset(&(inst->dst)), 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);
-		}
-		if (inst->dst.addr_mode != MODE_AREG) {
-			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);
-		}
-		switch (inst->extra.size)
-		{
-		case OPSIZE_BYTE:
-			dst = call(dst, opts->write_8);
-			break;
-		case OPSIZE_WORD:
-			dst = call(dst, opts->write_16);
-			break;
-		case OPSIZE_LONG:
-			dst = call(dst, opts->write_32_highfirst);
-			break;
-		}
-		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) {
-				dst = add_ir(dst, inc_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D);
-			} else {
-				dst = add_irdisp8(dst, inc_amount, CONTEXT, reg_offset(&(inst->dst)), SZ_D);
-			}
-		}
-		break;
-	case MODE_AREG_DISPLACE:
-		dst = cycles(dst, BUS);
-		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,  reg_offset(&(inst->dst)), SCRATCH2, SZ_D);
-		}
-		dst = add_ir(dst, inst->dst.params.regs.displacement, 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);
-		}
-		if (inst->dst.addr_mode != MODE_AREG) {
-			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);
-		}
-		switch (inst->extra.size)
-		{
-		case OPSIZE_BYTE:
-			dst = call(dst, opts->write_8);
-			break;
-		case OPSIZE_WORD:
-			dst = call(dst, opts->write_16);
-			break;
-		case OPSIZE_LONG:
-			dst = call(dst, opts->write_32_highfirst);
-			break;
-		}
-		break;
-	case MODE_AREG_INDEX_DISP8:
-		dst = cycles(dst, 6);//TODO: Check to make sure this is correct
-		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,  reg_offset(&(inst->dst)), 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) {
-					dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_D);
-				} else {
-					dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_D);
-				} else {
-					dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_D);
-				}
-			}
-		} else {
-			if (src.base == SCRATCH1) {
-				dst = push_r(dst, SCRATCH1);
-			}
-			if (inst->dst.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_W, SZ_D);
-				} else {
-					dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_W, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_W, SZ_D);
-				} else {
-					dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_W, SZ_D);
-				}
-			}
-			dst = add_rr(dst, SCRATCH1, SCRATCH2, SZ_D);
-			if (src.base == SCRATCH1) {
-				dst = pop_r(dst, SCRATCH1);
-			}
-		}
-		if (inst->dst.params.regs.displacement) {
-			dst = add_ir(dst, inst->dst.params.regs.displacement, 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);
-		}
-		if (inst->dst.addr_mode != MODE_AREG) {
-			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);
-		}
-		switch (inst->extra.size)
-		{
-		case OPSIZE_BYTE:
-			dst = call(dst, opts->write_8);
-			break;
-		case OPSIZE_WORD:
-			dst = call(dst, opts->write_16);
-			break;
-		case OPSIZE_LONG:
-			dst = call(dst, opts->write_32_highfirst);
-			break;
-		}
-		break;
-	case MODE_PC_DISPLACE:
-		dst = cycles(dst, BUS);
-		dst = mov_ir(dst, inst->dst.params.regs.displacement + inst->address+2, 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);
-		}
-		if (inst->dst.addr_mode != MODE_AREG) {
-			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);
-		}
-		switch (inst->extra.size)
-		{
-		case OPSIZE_BYTE:
-			dst = call(dst, opts->write_8);
-			break;
-		case OPSIZE_WORD:
-			dst = call(dst, opts->write_16);
-			break;
-		case OPSIZE_LONG:
-			dst = call(dst, opts->write_32_highfirst);
-			break;
-		}
-		break;
-	case MODE_PC_INDEX_DISP8:
-		dst = cycles(dst, 6);//TODO: Check to make sure this is correct
-		dst = mov_ir(dst, inst->address, 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) {
-					dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_D);
-				} else {
-					dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_D);
-				} else {
-					dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_D);
-				}
-			}
-		} else {
-			if (src.base == SCRATCH1) {
-				dst = push_r(dst, SCRATCH1);
-			}
-			if (inst->dst.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_W, SZ_D);
-				} else {
-					dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_W, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_W, SZ_D);
-				} else {
-					dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_W, SZ_D);
-				}
-			}
-			dst = add_rr(dst, SCRATCH1, SCRATCH2, SZ_D);
-			if (src.base == SCRATCH1) {
-				dst = pop_r(dst, SCRATCH1);
-			}
-		}
-		if (inst->dst.params.regs.displacement) {
-			dst = add_ir(dst, inst->dst.params.regs.displacement, 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);
-		}
-		if (inst->dst.addr_mode != MODE_AREG) {
-			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);
-		}
-		switch (inst->extra.size)
-		{
-		case OPSIZE_BYTE:
-			dst = call(dst, opts->write_8);
-			break;
-		case OPSIZE_WORD:
-			dst = call(dst, opts->write_16);
-			break;
-		case OPSIZE_LONG:
-			dst = call(dst, opts->write_32_highfirst);
-			break;
-		}
-		break;
-	case MODE_ABSOLUTE:
-	case MODE_ABSOLUTE_SHORT:
-		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);
-		}
-		if (inst->dst.addr_mode == MODE_ABSOLUTE) {
-			dst = cycles(dst, BUS*2);
-		} else {
-			dst = cycles(dst, BUS);
-		}
-		dst = mov_ir(dst, inst->dst.params.immed, SCRATCH2, SZ_D);
-		if (inst->dst.addr_mode != MODE_AREG) {
-			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);
-		}
-		switch (inst->extra.size)
-		{
-		case OPSIZE_BYTE:
-			dst = call(dst, opts->write_8);
-			break;
-		case OPSIZE_WORD:
-			dst = call(dst, opts->write_16);
-			break;
-		case OPSIZE_LONG:
-			dst = call(dst, opts->write_32_highfirst);
-			break;
-		}
-		break;
-	default:
-		m68k_disasm(inst, disasm_buf);
-		printf("%X: %s\naddress mode %d not implemented (move dst)\n", inst->address, disasm_buf, inst->dst.addr_mode);
-		exit(1);
-	}
-
-	//add cycles for prefetch
-	dst = cycles(dst, BUS);
-	return dst;
-}
-
-uint8_t * translate_m68k_movem(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
-{
-	int8_t bit,reg,sec_reg;
-	uint8_t early_cycles;
-	if(inst->src.addr_mode == MODE_REG) {
-		//reg to mem
-		early_cycles = 8;
-		int8_t dir;
-		switch (inst->dst.addr_mode)
-		{
-		case MODE_AREG_INDIRECT:
-		case MODE_AREG_PREDEC:
-			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, reg_offset(&(inst->dst)), SCRATCH2, SZ_D);
-			}
-			break;
-		case MODE_AREG_DISPLACE:
-			early_cycles += BUS;
-			reg = SCRATCH2;
-			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,  reg_offset(&(inst->dst)), SCRATCH2, SZ_D);
-			}
-			dst = add_ir(dst, inst->dst.params.regs.displacement, SCRATCH2, SZ_D);
-			break;
-		case MODE_AREG_INDEX_DISP8:
-			early_cycles += 6;
-			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,  reg_offset(&(inst->dst)), 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) {
-						dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_D);
-					} else {
-						dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_D);
-					}
-				} else {
-					if (opts->dregs[sec_reg] >= 0) {
-						dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_D);
-					} else {
-						dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_D);
-					}
-				}
-			} else {
-				if (inst->dst.params.regs.sec & 0x10) {
-					if (opts->aregs[sec_reg] >= 0) {
-						dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_W, SZ_D);
-					} else {
-						dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_W, SZ_D);
-					}
-				} else {
-					if (opts->dregs[sec_reg] >= 0) {
-						dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_W, SZ_D);
-					} else {
-						dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_W, SZ_D);
-					}
-				}
-				dst = add_rr(dst, SCRATCH1, SCRATCH2, SZ_D);
-			}
-			if (inst->dst.params.regs.displacement) {
-				dst = add_ir(dst, inst->dst.params.regs.displacement, SCRATCH2, SZ_D);
-			}
-			break;
-		case MODE_PC_DISPLACE:
-			early_cycles += BUS;
-			dst = mov_ir(dst, inst->dst.params.regs.displacement + inst->address+2, SCRATCH2, SZ_D);
-			break;
-		case MODE_PC_INDEX_DISP8:
-			early_cycles += 6;
-			dst = mov_ir(dst, inst->address+2, 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) {
-						dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_D);
-					} else {
-						dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_D);
-					}
-				} else {
-					if (opts->dregs[sec_reg] >= 0) {
-						dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_D);
-					} else {
-						dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_D);
-					}
-				}
-			} else {
-				if (inst->dst.params.regs.sec & 0x10) {
-					if (opts->aregs[sec_reg] >= 0) {
-						dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_W, SZ_D);
-					} else {
-						dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_W, SZ_D);
-					}
-				} else {
-					if (opts->dregs[sec_reg] >= 0) {
-						dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_W, SZ_D);
-					} else {
-						dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_W, SZ_D);
-					}
-				}
-				dst = add_rr(dst, SCRATCH1, SCRATCH2, SZ_D);
-			}
-			if (inst->dst.params.regs.displacement) {
-				dst = add_ir(dst, inst->dst.params.regs.displacement, SCRATCH2, SZ_D);
-			}
-			break;
-		case MODE_ABSOLUTE:
-			early_cycles += 4;
-		case MODE_ABSOLUTE_SHORT:
-			early_cycles += 4;
-			dst = mov_ir(dst, inst->dst.params.immed, SCRATCH2, SZ_D);
-			break;
-		default:
-			m68k_disasm(inst, disasm_buf);
-			printf("%X: %s\naddress mode %d not implemented (movem dst)\n", inst->address, disasm_buf, inst->dst.addr_mode);
-			exit(1);
-		}
-		if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
-			reg = 15;
-			dir = -1;
-		} else {
-			reg = 0;
-			dir = 1;
-		}
-		dst = cycles(dst, early_cycles);
-		for(bit=0; reg < 16 && reg >= 0; reg += dir, bit++) {
-			if (inst->src.params.immed & (1 << bit)) {
-				if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
-					dst = sub_ir(dst, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, SCRATCH2, SZ_D);
-				}
-				dst = push_r(dst, SCRATCH2);
-				if (reg > 7) {
-					if (opts->aregs[reg-8] >= 0) {
-						dst = mov_rr(dst, opts->aregs[reg-8], SCRATCH1, inst->extra.size);
-					} else {
-						dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * (reg-8), SCRATCH1, inst->extra.size);
-					}
-				} else {
-					if (opts->dregs[reg] >= 0) {
-						dst = mov_rr(dst, opts->dregs[reg], SCRATCH1, inst->extra.size);
-					} else {
-						dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t) * (reg), SCRATCH1, inst->extra.size);
-					}
-				}
-				if (inst->extra.size == OPSIZE_LONG) {
-					dst = call(dst, opts->write_32_lowfirst);
-				} else {
-					dst = call(dst, opts->write_16);
-				}
-				dst = pop_r(dst, SCRATCH2);
-				if (inst->dst.addr_mode != MODE_AREG_PREDEC) {
-					dst = add_ir(dst, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, SCRATCH2, SZ_D);
-				}
-			}
-		}
-		if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
-			if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
-				dst = mov_rr(dst, SCRATCH2, opts->aregs[inst->dst.params.regs.pri], SZ_D);
-			} else {
-				dst = mov_rrdisp8(dst, SCRATCH2, CONTEXT, reg_offset(&(inst->dst)), SZ_D);
-			}
-		}
-	} else {
-		//mem to reg
-		early_cycles = 4;
-		switch (inst->src.addr_mode)
-		{
-		case MODE_AREG_INDIRECT:
-		case MODE_AREG_POSTINC:
-			if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-				dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D);
-			} else {
-				dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src)), SCRATCH1, SZ_D);
-			}
-			break;
-		case MODE_AREG_DISPLACE:
-			early_cycles += BUS;
-			reg = SCRATCH2;
-			if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-				dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D);
-			} else {
-				dst = mov_rdisp8r(dst, CONTEXT,  reg_offset(&(inst->src)), SCRATCH1, SZ_D);
-			}
-			dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH1, SZ_D);
-			break;
-		case MODE_AREG_INDEX_DISP8:
-			early_cycles += 6;
-			if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-				dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D);
-			} else {
-				dst = mov_rdisp8r(dst, CONTEXT,  reg_offset(&(inst->src)), 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) {
-						dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_D);
-					} else {
-						dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D);
-					}
-				} else {
-					if (opts->dregs[sec_reg] >= 0) {
-						dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_D);
-					} else {
-						dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D);
-					}
-				}
-			} else {
-				if (inst->src.params.regs.sec & 0x10) {
-					if (opts->aregs[sec_reg] >= 0) {
-						dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
-					} else {
-						dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D);
-					}
-				} else {
-					if (opts->dregs[sec_reg] >= 0) {
-						dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
-					} else {
-						dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D);
-					}
-				}
-				dst = add_rr(dst, SCRATCH2, SCRATCH1, SZ_D);
-			}
-			if (inst->src.params.regs.displacement) {
-				dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH1, SZ_D);
-			}
-			break;
-		case MODE_PC_DISPLACE:
-			early_cycles += BUS;
-			dst = mov_ir(dst, inst->src.params.regs.displacement + inst->address+2, SCRATCH1, SZ_D);
-			break;
-		case MODE_PC_INDEX_DISP8:
-			early_cycles += 6;
-			dst = mov_ir(dst, inst->address+2, 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) {
-						dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_D);
-					} else {
-						dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D);
-					}
-				} else {
-					if (opts->dregs[sec_reg] >= 0) {
-						dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_D);
-					} else {
-						dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D);
-					}
-				}
-			} else {
-				if (inst->src.params.regs.sec & 0x10) {
-					if (opts->aregs[sec_reg] >= 0) {
-						dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
-					} else {
-						dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D);
-					}
-				} else {
-					if (opts->dregs[sec_reg] >= 0) {
-						dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
-					} else {
-						dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D);
-					}
-				}
-				dst = add_rr(dst, SCRATCH2, SCRATCH1, SZ_D);
-			}
-			if (inst->src.params.regs.displacement) {
-				dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH1, SZ_D);
-			}
-			break;
-		case MODE_ABSOLUTE:
-			early_cycles += 4;
-		case MODE_ABSOLUTE_SHORT:
-			early_cycles += 4;
-			dst = mov_ir(dst, inst->src.params.immed, SCRATCH1, SZ_D);
-			break;
-		default:
-			m68k_disasm(inst, disasm_buf);
-			printf("%X: %s\naddress mode %d not implemented (movem src)\n", inst->address, disasm_buf, inst->src.addr_mode);
-			exit(1);
-		}
-		dst = cycles(dst, early_cycles);
-		for(reg = 0; reg < 16; reg ++) {
-			if (inst->dst.params.immed & (1 << reg)) {
-				dst = push_r(dst, SCRATCH1);
-				if (inst->extra.size == OPSIZE_LONG) {
-					dst = call(dst, opts->read_32);
-				} else {
-					dst = call(dst, opts->read_16);
-				}
-				if (inst->extra.size == OPSIZE_WORD) {
-					dst = movsx_rr(dst, SCRATCH1, SCRATCH1, SZ_W, SZ_D);
-				}
-				if (reg > 7) {
-					if (opts->aregs[reg-8] >= 0) {
-						dst = mov_rr(dst, SCRATCH1, opts->aregs[reg-8], SZ_D);
-					} else {
-						dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * (reg-8), SZ_D);
-					}
-				} else {
-					if (opts->dregs[reg] >= 0) {
-						dst = mov_rr(dst, SCRATCH1, opts->dregs[reg], SZ_D);
-					} else {
-						dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t) * (reg), SZ_D);
-					}
-				}
-				dst = pop_r(dst, SCRATCH1);
-				dst = add_ir(dst, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, SCRATCH1, SZ_D);
-			}
-		}
-		if (inst->src.addr_mode == MODE_AREG_POSTINC) {
-			if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-				dst = mov_rr(dst, SCRATCH1, opts->aregs[inst->src.params.regs.pri], SZ_D);
-			} else {
-				dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, reg_offset(&(inst->src)), SZ_D);
-			}
-		}
-	}
-	//prefetch
-	dst = cycles(dst, 4);
-	return dst;
-}
-
-uint8_t * translate_m68k_clr(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
-{
-	dst = mov_ir(dst, 0, FLAG_N, SZ_B);
-	dst = mov_ir(dst, 0, FLAG_V, SZ_B);
-	dst = mov_ir(dst, 0, FLAG_C, SZ_B);
-	dst = mov_ir(dst, 1, FLAG_Z, SZ_B);
-	int8_t reg = native_reg(&(inst->dst), opts);
-	if (reg >= 0) {
-		dst = cycles(dst, (inst->extra.size == OPSIZE_LONG ? 6 : 4));
-		return  xor_rr(dst, reg, reg, inst->extra.size);
-	}
-	x86_ea dst_op;
-	dst = translate_m68k_dst(inst, &dst_op, dst, opts, 1);
-	if (dst_op.mode == MODE_REG_DIRECT) {
-		dst = xor_rr(dst, dst_op.base, dst_op.base, inst->extra.size);
-	} else {
-		dst = mov_irdisp8(dst, 0, dst_op.base, dst_op.disp, inst->extra.size);
-	}
-	dst = m68k_save_result(inst, dst, opts);
-	return dst;
-}
-
-uint8_t * translate_m68k_ext(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
-{
-	x86_ea dst_op;
-	uint8_t dst_size = inst->extra.size;
-	inst->extra.size--;
-	dst = translate_m68k_dst(inst, &dst_op, dst, opts, 0);
-	if (dst_op.mode == MODE_REG_DIRECT) {
-		dst = movsx_rr(dst, dst_op.base, dst_op.base, inst->extra.size, dst_size);
-		dst = cmp_ir(dst, 0, dst_op.base, dst_size);
-	} else {
-		dst = movsx_rdisp8r(dst, dst_op.base, dst_op.disp, SCRATCH1, inst->extra.size, dst_size);
-		dst = cmp_ir(dst, 0, SCRATCH1, dst_size);
-		dst = mov_rrdisp8(dst, SCRATCH1, dst_op.base, dst_op.disp, dst_size);
-	}
-	inst->extra.size = dst_size;
-	dst = mov_ir(dst, 0, FLAG_V, SZ_B);
-	dst = mov_ir(dst, 0, FLAG_C, SZ_B);
-	dst = setcc_r(dst, CC_Z, FLAG_Z);
-	dst = setcc_r(dst, CC_S, FLAG_N);
-	//M68K EXT only operates on registers so no need for a call to save result here
-	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), sec_reg;
-	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);
-			}
-		}
-		break;
-	case MODE_AREG_DISPLACE:
-		dst = cycles(dst, 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) {
-					dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], dst_reg, SZ_D);
-				} else {
-					dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src)), dst_reg, SZ_D);
-				}
-			}
-			dst = add_ir(dst, 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) {
-					dst = mov_rrdisp8(dst, opts->aregs[inst->src.params.regs.pri], CONTEXT, reg_offset(&(inst->dst)), SZ_D);
-				} else {
-					dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src)), SCRATCH1, SZ_D);
-					dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, reg_offset(&(inst->dst)), SZ_D);
-				}
-			}
-			dst = add_irdisp8(dst, inst->src.params.regs.displacement, CONTEXT, reg_offset(&(inst->dst)), SZ_D);
-		}
-		break;
-	case MODE_AREG_INDEX_DISP8:
-		dst = cycles(dst, 12);
-		if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-			dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH2, SZ_D);
-		} else {
-			dst = mov_rdisp8r(dst, CONTEXT,  reg_offset(&(inst->src)), 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) {
-					dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_D);
-				} else {
-					dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_D);
-				} else {
-					dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_D);
-				}
-			}
-		} else {
-			if (inst->src.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_W, SZ_D);
-				} else {
-					dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_W, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_W, SZ_D);
-				} else {
-					dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_W, SZ_D);
-				}
-			}
-			dst = add_rr(dst, SCRATCH1, SCRATCH2, SZ_D);
-		}
-		if (inst->src.params.regs.displacement) {
-			dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH2, SZ_D);
-		}
-		if (dst_reg >= 0) {
-			dst = mov_rr(dst, SCRATCH2, dst_reg, SZ_D);
-		} else {
-			dst = mov_rrdisp8(dst, SCRATCH2, CONTEXT, reg_offset(&(inst->dst)), SZ_D);
-		}
-		break;
-	case MODE_PC_DISPLACE:
-		dst = cycles(dst, 8);
-		if (dst_reg >= 0) {
-			dst = mov_ir(dst, inst->src.params.regs.displacement + inst->address+2, dst_reg, SZ_D);
-		} else {
-			dst = mov_irdisp8(dst, inst->src.params.regs.displacement + inst->address+2, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D);
-		}
-		break;
-	case MODE_PC_INDEX_DISP8:
-		dst = cycles(dst, BUS*3);
-		dst = mov_ir(dst, inst->address+2, 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) {
-					dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_D);
-				} else {
-					dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_D);
-				} else {
-					dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D);
-				}
-			}
-		} else {
-			if (inst->src.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
-				} else {
-					dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
-				} else {
-					dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D);
-				}
-			}
-			dst = add_rr(dst, SCRATCH2, SCRATCH1, SZ_D);
-		}
-		if (inst->src.params.regs.displacement) {
-			dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH1, SZ_D);
-		}
-		if (dst_reg >= 0) {
-			dst = mov_rr(dst, SCRATCH1, dst_reg, SZ_D);
-		} else {
-			dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, reg_offset(&(inst->dst)), SZ_D);
-		}
-		break;
-	case MODE_ABSOLUTE:
-	case MODE_ABSOLUTE_SHORT:
-		dst = cycles(dst, (inst->src.addr_mode == MODE_ABSOLUTE) ? BUS * 3 : BUS * 2);
-		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, 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);
-	}
-	return dst;
-}
-
-uint8_t * translate_m68k_pea(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
-{
-	uint8_t sec_reg;
-	switch(inst->src.addr_mode)
-	{
-	case MODE_AREG_INDIRECT:
-		dst = cycles(dst, BUS);
-		if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-			dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D);
-		} else {
-			dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SCRATCH1, SZ_D);
-		}
-		break;
-	case MODE_AREG_DISPLACE:
-		dst = cycles(dst, 8);
-		if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-			dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D);
-		} else {
-			dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src)), SCRATCH1, SZ_D);
-		}
-		dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH1, SZ_D);
-		break;
-	case MODE_AREG_INDEX_DISP8:
-		dst = cycles(dst, 6);//TODO: Check to make sure this is correct
-		if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-			dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D);
-		} else {
-			dst = mov_rdisp8r(dst, CONTEXT,  reg_offset(&(inst->src)), 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) {
-					dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_D);
-				} else {
-					dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_D);
-				} else {
-					dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D);
-				}
-			}
-		} else {
-			if (inst->src.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
-				} else {
-					dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
-				} else {
-					dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D);
-				}
-			}
-			dst = add_rr(dst, SCRATCH2, SCRATCH1, SZ_D);
-		}
-		if (inst->src.params.regs.displacement) {
-			dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH1, SZ_D);
-		}
-		break;
-	case MODE_PC_DISPLACE:
-		dst = cycles(dst, 8);
-		dst = mov_ir(dst, inst->src.params.regs.displacement + inst->address+2, SCRATCH1, SZ_D);
-		break;
-	case MODE_ABSOLUTE:
-	case MODE_ABSOLUTE_SHORT:
-		dst = cycles(dst, (inst->src.addr_mode == MODE_ABSOLUTE) ? BUS * 3 : BUS * 2);
-		dst = mov_ir(dst, inst->src.params.immed, 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);
-	}
-	dst = sub_ir(dst, 4, opts->aregs[7], SZ_D);
-	dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D);
-	dst = call(dst, opts->write_32_lowfirst);
-	return dst;
-}
-
-uint8_t * translate_m68k_bsr(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
-{
-	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
-	dst = cycles(dst, 10);
-	dst = mov_ir(dst, after, SCRATCH1, SZ_D);
-	if (opts->flags & OPT_NATIVE_CALL_STACK) {
-		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, opts->write_32_highfirst);
-	uint8_t * dest_addr = get_native_address(opts->native_code_map, (inst->address+2) + disp);
-	if (!dest_addr) {
-		opts->deferred = defer_address(opts->deferred, (inst->address+2) + disp, dst + 1);
-		//dummy address to be replaced later
-		dest_addr = dst + 256;
-	}
-	if (opts->flags & OPT_NATIVE_CALL_STACK) {
-		dst = call(dst, (char *)dest_addr);
-		//would add_ir(dst, 8, RSP, SZ_Q) be faster here?
-		dst = pop_r(dst, SCRATCH1);
-	} else {
-		dst = jmp(dst, (char *)dest_addr);
-	}
-	return dst;
-}
-
-uint8_t * translate_m68k_bcc(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
-{
-	dst = cycles(dst, 10);//TODO: Adjust this for branch not taken case
-	int32_t disp = inst->src.params.immed;
-	uint32_t after = inst->address + 2;
-	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_scc(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
-{
-	uint8_t cond = inst->extra.cond;
-	x86_ea dst_op;
-	inst->extra.size = OPSIZE_BYTE;
-	dst = translate_m68k_dst(inst, &dst_op, dst, opts, 1);
-	if (cond == COND_TRUE || cond == COND_FALSE) {
-		if ((inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG) && inst->extra.cond == COND_TRUE) {
-			dst = cycles(dst, 6);
-		} else {
-			dst = cycles(dst, BUS);
-		}
-		if (dst_op.mode == MODE_REG_DIRECT) {
-			dst = mov_ir(dst, cond == COND_TRUE ? 0xFF : 0, dst_op.base, SZ_B);
-		} else {
-			dst = mov_irdisp8(dst, cond == COND_TRUE ? 0xFF : 0, dst_op.base, dst_op.disp, SZ_B);
-		}
-	} else {
-		uint8_t cc = CC_NZ;
-		switch (cond)
-		{
-		case COND_HIGH:
-			cc = CC_Z;
-		case COND_LOW_SAME:
-			dst = mov_rr(dst, FLAG_Z, SCRATCH1, SZ_B);
-			dst = or_rr(dst, FLAG_C, SCRATCH1, SZ_B);
-			break;
-		case COND_CARRY_CLR:
-			cc = CC_Z;
-		case COND_CARRY_SET:
-			dst = cmp_ir(dst, 0, FLAG_C, SZ_B);
-			break;
-		case COND_NOT_EQ:
-			cc = CC_Z;
-		case COND_EQ:
-			dst = cmp_ir(dst, 0, FLAG_Z, SZ_B);
-			break;
-		case COND_OVERF_CLR:
-			cc = CC_Z;
-		case COND_OVERF_SET:
-			dst = cmp_ir(dst, 0, FLAG_V, SZ_B);
-			break;
-		case COND_PLUS:
-			cc = CC_Z;
-		case COND_MINUS:
-			dst = cmp_ir(dst, 0, FLAG_N, SZ_B);
-			break;
-		case COND_GREATER_EQ:
-			cc = CC_Z;
-		case COND_LESS:
-			dst = cmp_rr(dst, FLAG_N, FLAG_V, SZ_B);
-			break;
-		case COND_GREATER:
-			cc = CC_Z;
-		case COND_LESS_EQ:
-			dst = mov_rr(dst, FLAG_V, SCRATCH1, SZ_B);
-			dst = xor_rr(dst, FLAG_N, SCRATCH1, SZ_B);
-			dst = or_rr(dst, FLAG_Z, SCRATCH1, SZ_B);
-			break;
-		}
-		uint8_t *true_off = dst + 1;
-		dst = jcc(dst, cc, dst+2);
-		dst = cycles(dst, BUS);
-		if (dst_op.mode == MODE_REG_DIRECT) {
-			dst = mov_ir(dst, 0, dst_op.base, SZ_B);
-		} else {
-			dst = mov_irdisp8(dst, 0, dst_op.base, dst_op.disp, SZ_B);
-		}
-		uint8_t *end_off = dst+1;
-		dst = jmp(dst, dst+2);
-		*true_off = dst - (true_off+1);
-		dst = cycles(dst, 6);
-		if (dst_op.mode == MODE_REG_DIRECT) {
-			dst = mov_ir(dst, 0xFF, dst_op.base, SZ_B);
-		} else {
-			dst = mov_irdisp8(dst, 0xFF, dst_op.base, dst_op.disp, SZ_B);
-		}
-		*end_off = dst - (end_off+1);
-	}
-	dst = m68k_save_result(inst, dst, opts);
-	return dst;
-}
-
-uint8_t * translate_m68k_jmp(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
-{
-	uint8_t * dest_addr, sec_reg;
-	uint32_t m68k_addr;
-	switch(inst->src.addr_mode)
-	{
-	case MODE_AREG_INDIRECT:
-		dst = cycles(dst, BUS*2);
-		if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-			dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D);
-		} else {
-			dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SCRATCH1, SZ_D);
-		}
-		dst = call(dst, (uint8_t *)m68k_native_addr);
-		dst = jmp_r(dst, SCRATCH1);
-		break;
-	case MODE_AREG_INDEX_DISP8:
-		dst = cycles(dst, BUS*3);//TODO: CHeck that this is correct
-		if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-			dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D);
-		} else {
-			dst = mov_rdisp8r(dst, CONTEXT,  reg_offset(&(inst->src)), 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) {
-					dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_D);
-				} else {
-					dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_D);
-				} else {
-					dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D);
-				}
-			}
-		} else {
-			//16-bit index register
-			if (inst->src.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
-				} else {
-					dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
-				} else {
-					dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D);
-				}
-			}
-			dst = add_rr(dst, SCRATCH2, SCRATCH1, SZ_D);
-		}
-		if (inst->src.params.regs.displacement) {
-			dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH1, SZ_D);
-		}
-		dst = call(dst, (uint8_t *)m68k_native_addr);
-		dst = jmp_r(dst, SCRATCH1);
-		break;
-	case MODE_PC_DISPLACE:
-		dst = cycles(dst, 10);
-		m68k_addr = inst->src.params.regs.displacement + inst->address + 2;
-		if ((m68k_addr & 0xFFFFFF) < 0x400000) {
-			dest_addr = get_native_address(opts->native_code_map, m68k_addr);
-			if (!dest_addr) {
-				opts->deferred = defer_address(opts->deferred, m68k_addr, 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 {
-			dst = mov_ir(dst, m68k_addr, SCRATCH1, SZ_D);
-			dst = call(dst, (uint8_t *)m68k_native_addr);
-			dst = jmp_r(dst, SCRATCH1);
-		}
-		break;
-	case MODE_PC_INDEX_DISP8:
-		dst = cycles(dst, BUS*3);//TODO: CHeck that this is correct
-		dst = mov_ir(dst, inst->address+2, 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) {
-					dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_D);
-				} else {
-					dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_D);
-				} else {
-					dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D);
-				}
-			}
-		} else {
-			if (inst->src.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
-				} else {
-					dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
-				} else {
-					dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D);
-				}
-			}
-			dst = add_rr(dst, SCRATCH2, SCRATCH1, SZ_D);
-		}
-		if (inst->src.params.regs.displacement) {
-			dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH1, SZ_D);
-		}
-		dst = call(dst, (uint8_t *)m68k_native_addr);
-		dst = jmp_r(dst, SCRATCH1);
-		break;
-	case MODE_ABSOLUTE:
-	case MODE_ABSOLUTE_SHORT:
-		dst = cycles(dst, inst->src.addr_mode == MODE_ABSOLUTE ? 12 : 10);
-		m68k_addr = inst->src.params.immed;
-		if ((m68k_addr & 0xFFFFFF) < 0x400000) {
-			dest_addr = get_native_address(opts->native_code_map, m68k_addr);
-			if (!dest_addr) {
-				opts->deferred = defer_address(opts->deferred, m68k_addr, 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 {
-			dst = mov_ir(dst, m68k_addr, SCRATCH1, SZ_D);
-			dst = call(dst, (uint8_t *)m68k_native_addr);
-			dst = jmp_r(dst, SCRATCH1);
-		}
-		break;
-	default:
-		m68k_disasm(inst, disasm_buf);
-		printf("%s\naddress mode %d not yet supported (jmp)\n", disasm_buf, inst->src.addr_mode);
-		exit(1);
-	}
-	return dst;
-}
-
-uint8_t * translate_m68k_jsr(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
-{
-	uint8_t * dest_addr, sec_reg;
-	uint32_t after;
-	uint32_t m68k_addr;
-	switch(inst->src.addr_mode)
-	{
-	case MODE_AREG_INDIRECT:
-		dst = cycles(dst, BUS*2);
-		dst = mov_ir(dst, inst->address + 2, SCRATCH1, SZ_D);
-		if (opts->flags & OPT_NATIVE_CALL_STACK) {
-			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, opts->write_32_highfirst);
-		if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-			dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D);
-		} else {
-			dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SCRATCH1, SZ_D);
-		}
-		dst = call(dst, (uint8_t *)m68k_native_addr);
-		if (opts->flags & OPT_NATIVE_CALL_STACK) {
-			dst = call_r(dst, SCRATCH1);
-			//would add_ir(dst, 8, RSP, SZ_Q) be faster here?
-			dst = pop_r(dst, SCRATCH1);
-		} else {
-			dst = jmp_r(dst, SCRATCH1);
-		}
-		break;
-	case MODE_AREG_DISPLACE:
-		dst = cycles(dst, BUS*2);
-		dst = mov_ir(dst, inst->address + 4, SCRATCH1, SZ_D);
-		if (opts->flags & OPT_NATIVE_CALL_STACK) {
-			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, opts->write_32_highfirst);
-		if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-			dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D);
-		} else {
-			dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SCRATCH1, SZ_D);
-		}
-		dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH1, SZ_D);
-		dst = call(dst, (uint8_t *)m68k_native_addr);
-		if (opts->flags & OPT_NATIVE_CALL_STACK) {
-			dst = call_r(dst, SCRATCH1);
-			//would add_ir(dst, 8, RSP, SZ_Q) be faster here?
-			dst = pop_r(dst, SCRATCH1);
-		} else {
-			dst = jmp_r(dst, SCRATCH1);
-		}
-		break;
-	case MODE_AREG_INDEX_DISP8:
-		dst = cycles(dst, BUS*3);//TODO: CHeck that this is correct
-		dst = mov_ir(dst, inst->address + 4, SCRATCH1, SZ_D);
-		if (opts->flags & OPT_NATIVE_CALL_STACK) {
-			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, opts->write_32_highfirst);
-		if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-			dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D);
-		} else {
-			dst = mov_rdisp8r(dst, CONTEXT,  reg_offset(&(inst->src)), 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) {
-					dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_D);
-				} else {
-					dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_D);
-				} else {
-					dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D);
-				}
-			}
-		} else {
-			if (inst->src.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
-				} else {
-					dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
-				} else {
-					dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D);
-				}
-			}
-			dst = add_rr(dst, SCRATCH2, SCRATCH1, SZ_D);
-		}
-		if (inst->src.params.regs.displacement) {
-			dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH1, SZ_D);
-		}
-		dst = call(dst, (uint8_t *)m68k_native_addr);
-		if (opts->flags & OPT_NATIVE_CALL_STACK) {
-			dst = call_r(dst, SCRATCH1);
-			//would add_ir(dst, 8, RSP, SZ_Q) be faster here?
-			dst = pop_r(dst, SCRATCH1);
-		} else {
-			dst = jmp_r(dst, SCRATCH1);
-		}
-		break;
-	case MODE_PC_DISPLACE:
-		//TODO: Add cycles in the right place relative to pushing the return address on the stack
-		dst = cycles(dst, 10);
-		dst = mov_ir(dst, inst->address + 4, SCRATCH1, SZ_D);
-		if (opts->flags & OPT_NATIVE_CALL_STACK) {
-			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, 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->native_code_map, m68k_addr);
-			if (!dest_addr) {
-				opts->deferred = defer_address(opts->deferred, m68k_addr, dst + 1);
-				//dummy address to be replaced later, make sure it generates a 4-byte displacement
-				dest_addr = dst + 256;
-			}
-			if (opts->flags & OPT_NATIVE_CALL_STACK) {
-				dst = call(dst, (char *)dest_addr);
-			} else {
-				dst = jmp(dst, dest_addr);
-			}
-		} else {
-			dst = mov_ir(dst, m68k_addr, SCRATCH1, SZ_D);
-			dst = call(dst, (uint8_t *)m68k_native_addr);
-			if (opts->flags & OPT_NATIVE_CALL_STACK) {
-				dst = call_r(dst, SCRATCH1);
-			} else {
-				dst = jmp_r(dst, SCRATCH1);
-			}
-		}
-		if (opts->flags & OPT_NATIVE_CALL_STACK) {
-			//would add_ir(dst, 8, RSP, SZ_Q) be faster here?
-			dst = pop_r(dst, SCRATCH1);
-		}
-		break;
-	case MODE_PC_INDEX_DISP8:
-		dst = cycles(dst, BUS*3);//TODO: CHeck that this is correct
-		dst = mov_ir(dst, inst->address + 4, SCRATCH1, SZ_D);
-		if (opts->flags & OPT_NATIVE_CALL_STACK) {
-			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, opts->write_32_highfirst);
-		dst = mov_ir(dst, inst->address+2, 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) {
-					dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_D);
-				} else {
-					dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_D);
-				} else {
-					dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D);
-				}
-			}
-		} else {
-			if (inst->src.params.regs.sec & 0x10) {
-				if (opts->aregs[sec_reg] >= 0) {
-					dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
-				} else {
-					dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D);
-				}
-			} else {
-				if (opts->dregs[sec_reg] >= 0) {
-					dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_W, SZ_D);
-				} else {
-					dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D);
-				}
-			}
-			dst = add_rr(dst, SCRATCH2, SCRATCH1, SZ_D);
-		}
-		if (inst->src.params.regs.displacement) {
-			dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH1, SZ_D);
-		}
-		dst = call(dst, (uint8_t *)m68k_native_addr);
-		if (opts->flags & OPT_NATIVE_CALL_STACK) {
-			dst = call_r(dst, SCRATCH1);
-			//would add_ir(dst, 8, RSP, SZ_Q) be faster here?
-			dst = pop_r(dst, SCRATCH1);
-		} else {
-			dst = jmp_r(dst, 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
-		dst = cycles(dst, inst->src.addr_mode == MODE_ABSOLUTE ? 12 : 10);
-		dst = mov_ir(dst, inst->address + (inst->src.addr_mode == MODE_ABSOLUTE ? 6 : 4), SCRATCH1, SZ_D);
-		if (opts->flags & OPT_NATIVE_CALL_STACK) {
-			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, opts->write_32_highfirst);
-		m68k_addr = inst->src.params.immed;
-		if ((m68k_addr & 0xFFFFFF) < 0x400000) {
-			dest_addr = get_native_address(opts->native_code_map, m68k_addr);
-			if (!dest_addr) {
-				opts->deferred = defer_address(opts->deferred, m68k_addr, dst + 1);
-				//dummy address to be replaced later, make sure it generates a 4-byte displacement
-				dest_addr = dst + 256;
-			}
-			if (opts->flags & OPT_NATIVE_CALL_STACK) {
-				dst = call(dst, (char *)dest_addr);
-			} else {
-				dst = jmp(dst, dest_addr);
-			}
-		} else {
-			dst = mov_ir(dst, m68k_addr, SCRATCH1, SZ_D);
-			dst = call(dst, (uint8_t *)m68k_native_addr);
-			if (opts->flags & OPT_NATIVE_CALL_STACK) {
-				dst = call_r(dst, SCRATCH1);
-			} else {
-				dst = jmp_r(dst, SCRATCH1);
-			}
-		}
-		if (opts->flags & OPT_NATIVE_CALL_STACK) {
-			//would add_ir(dst, 8, RSP, SZ_Q) be faster here?
-			dst = pop_r(dst, SCRATCH1);
-		}
-		break;
-	default:
-		m68k_disasm(inst, disasm_buf);
-		printf("%s\naddress mode %d not yet supported (jsr)\n", disasm_buf, inst->src.addr_mode);
-		exit(1);
-	}
-	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, opts->read_32);
-	if (opts->flags & OPT_NATIVE_CALL_STACK) {
-		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);
-	} else {
-		dst = call(dst, (uint8_t *)m68k_native_addr);
-		dst = jmp_r(dst, SCRATCH1);
-	}
-	return dst;
-}
-
-uint8_t * translate_m68k_dbcc(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
-{
-	//best case duration
-	dst = cycles(dst, 10);
-	uint8_t * skip_loc = NULL;
-	//TODO: Check if COND_TRUE technically valid here even though
-	//it's basically a slow NOP
-	if (inst->extra.cond != COND_FALSE) {
-		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;
-		}
-		skip_loc = dst + 1;
-		dst = jcc(dst, cond, dst + 2);
-	}
-	if (opts->dregs[inst->dst.params.regs.pri] >= 0) {
-		dst = sub_ir(dst, 1, opts->dregs[inst->dst.params.regs.pri], SZ_W);
-		dst = cmp_ir(dst, -1, opts->dregs[inst->dst.params.regs.pri], SZ_W);
-	} else {
-		dst = sub_irdisp8(dst, 1, CONTEXT, offsetof(m68k_context, dregs) + 4 * inst->dst.params.regs.pri, SZ_W);
-		dst = cmp_irdisp8(dst, -1, CONTEXT, offsetof(m68k_context, dregs) + 4 * inst->dst.params.regs.pri, SZ_W);
-	}
-	uint8_t *loop_end_loc = dst+1;
-	dst = jcc(dst, CC_Z, dst+2);
-	uint32_t after = inst->address + 2;
-	uint8_t * dest_addr = get_native_address(opts->native_code_map, after + inst->src.params.immed);
-	if (!dest_addr) {
-		opts->deferred = defer_address(opts->deferred, after + inst->src.params.immed, 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);
-	*loop_end_loc = dst - (loop_end_loc+1);
-	if (skip_loc) {
-		dst = cycles(dst, 2);
-		*skip_loc = dst - (skip_loc+1);
-		dst = cycles(dst, 2);
-	} else {
-		dst = cycles(dst, 4);
-	}
-	return dst;
-}
-
-uint8_t * translate_m68k_link(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
-{
-	int8_t reg = native_reg(&(inst->src), opts);
-	//compensate for displacement word
-	dst = cycles(dst, BUS);
-	dst = sub_ir(dst, 4, opts->aregs[7], SZ_D);
-	dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D);
-	if (reg >= 0) {
-		dst = mov_rr(dst, reg, SCRATCH1, SZ_D);
-	} else {
-		dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src)), SCRATCH1, SZ_D);
-	}
-	dst = call(dst, opts->write_32_highfirst);
-	if (reg >= 0) {
-		dst = mov_rr(dst, opts->aregs[7], reg, SZ_D);
-	} else {
-		dst = mov_rrdisp8(dst, opts->aregs[7], CONTEXT, reg_offset(&(inst->src)), SZ_D);
-	}
-	dst = add_ir(dst, inst->dst.params.immed, opts->aregs[7], SZ_D);
-	//prefetch
-	dst = cycles(dst, BUS);
-	return dst;
-}
-
-uint8_t * translate_m68k_movep(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
-{
-	int8_t reg;
-	dst = cycles(dst, BUS*2);
-	if (inst->src.addr_mode == MODE_REG) {
-		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, reg_offset(&(inst->dst)), SCRATCH2, SZ_D);
-		}
-		if (inst->dst.params.regs.displacement) {
-			dst = add_ir(dst, inst->dst.params.regs.displacement, SCRATCH2, SZ_D);
-		}
-		reg = native_reg(&(inst->src), opts);
-		if (inst->extra.size == OPSIZE_LONG) {
-			if (reg >= 0) {
-				dst = mov_rr(dst, reg, SCRATCH1, SZ_D);
-				dst = shr_ir(dst, 24, SCRATCH1, SZ_D);
-				dst = push_r(dst, SCRATCH2);
-				dst = call(dst, opts->write_8);
-				dst = pop_r(dst, SCRATCH2);
-				dst = mov_rr(dst, reg, SCRATCH1, SZ_D);
-				dst = shr_ir(dst, 16, SCRATCH1, SZ_D);
-
-			} else {
-				dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src))+3, SCRATCH1, SZ_B);
-				dst = push_r(dst, SCRATCH2);
-				dst = call(dst, opts->write_8);
-				dst = pop_r(dst, SCRATCH2);
-				dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src))+2, SCRATCH1, SZ_B);
-			}
-			dst = add_ir(dst, 2, SCRATCH2, SZ_D);
-			dst = push_r(dst, SCRATCH2);
-			dst = call(dst, opts->write_8);
-			dst = pop_r(dst, SCRATCH2);
-			dst = add_ir(dst, 2, SCRATCH2, SZ_D);
-		}
-		if (reg >= 0) {
-			dst = mov_rr(dst, reg, SCRATCH1, SZ_W);
-			dst = shr_ir(dst, 8, SCRATCH1, SZ_W);
-			dst = push_r(dst, SCRATCH2);
-			dst = call(dst, opts->write_8);
-			dst = pop_r(dst, SCRATCH2);
-			dst = mov_rr(dst, reg, SCRATCH1, SZ_W);
-		} else {
-			dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src))+1, SCRATCH1, SZ_B);
-			dst = push_r(dst, SCRATCH2);
-			dst = call(dst, opts->write_8);
-			dst = pop_r(dst, SCRATCH2);
-			dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src)), SCRATCH1, SZ_B);
-		}
-		dst = add_ir(dst, 2, SCRATCH2, SZ_D);
-		dst = call(dst, opts->write_8);
-	} else {
-		if (opts->aregs[inst->src.params.regs.pri] >= 0) {
-			dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D);
-		} else {
-			dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src)), SCRATCH1, SZ_D);
-		}
-		if (inst->src.params.regs.displacement) {
-			dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH1, SZ_D);
-		}
-		reg = native_reg(&(inst->dst), opts);
-		if (inst->extra.size == OPSIZE_LONG) {
-			if (reg >= 0) {
-				dst = push_r(dst, SCRATCH1);
-				dst = call(dst, opts->read_8);
-				dst = shl_ir(dst, 24, SCRATCH1, SZ_D);
-				dst = mov_rr(dst, SCRATCH1, reg, SZ_D);
-				dst = pop_r(dst, SCRATCH1);
-				dst = add_ir(dst, 2, SCRATCH1, SZ_D);
-				dst = push_r(dst, SCRATCH1);
-				dst = call(dst, opts->read_8);
-				dst = shl_ir(dst, 16, SCRATCH1, SZ_D);
-				dst = or_rr(dst, SCRATCH1, reg, SZ_D);
-			} else {
-				dst = push_r(dst, SCRATCH1);
-				dst = call(dst, opts->read_8);
-				dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, reg_offset(&(inst->dst))+3, SZ_B);
-				dst = pop_r(dst, SCRATCH1);
-				dst = add_ir(dst, 2, SCRATCH1, SZ_D);
-				dst = push_r(dst, SCRATCH1);
-				dst = call(dst, opts->read_8);
-				dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, reg_offset(&(inst->dst))+2, SZ_B);
-			}
-			dst = pop_r(dst, SCRATCH1);
-			dst = add_ir(dst, 2, SCRATCH1, SZ_D);
-		}
-		dst = push_r(dst, SCRATCH1);
-		dst = call(dst, opts->read_8);
-		if (reg >= 0) {
-
-			dst = shl_ir(dst, 8, SCRATCH1, SZ_W);
-			dst = mov_rr(dst, SCRATCH1, reg, SZ_W);
-			dst = pop_r(dst, SCRATCH1);
-			dst = add_ir(dst, 2, SCRATCH1, SZ_D);
-			dst = call(dst, opts->read_8);
-			dst = mov_rr(dst, SCRATCH1, reg, SZ_B);
-		} else {
-			dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, reg_offset(&(inst->dst))+1, SZ_B);
-			dst = pop_r(dst, SCRATCH1);
-			dst = add_ir(dst, 2, SCRATCH1, SZ_D);
-			dst = call(dst, opts->read_8);
-			dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, reg_offset(&(inst->dst)), SZ_B);
-		}
-	}
-	return dst;
-}
-
-uint8_t * translate_m68k_cmp(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
-{
-	uint8_t size = inst->extra.size;
-	x86_ea src_op, dst_op;
-	dst = translate_m68k_src(inst, &src_op, dst, opts);
-	if (inst->dst.addr_mode == MODE_AREG_POSTINC) {
-		dst = push_r(dst, SCRATCH1);
-		dst = translate_m68k_dst(inst, &dst_op, dst, opts, 0);
-		dst = pop_r(dst, SCRATCH2);
-		src_op.base = SCRATCH2;
-	} else {
-		dst = translate_m68k_dst(inst, &dst_op, dst, opts, 0);
-		if (inst->dst.addr_mode == MODE_AREG && size == OPSIZE_WORD) {
-			size = OPSIZE_LONG;
-		}
-	}
-	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, size);
-		} else {
-			dst = cmp_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, size);
-		}
-	} else if (src_op.mode == MODE_REG_DISPLACE8) {
-		dst = cmp_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, size);
-	} else {
-		if (dst_op.mode == MODE_REG_DIRECT) {
-			dst = cmp_ir(dst, src_op.disp, dst_op.base, size);
-		} else {
-			dst = cmp_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, 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);
-	return dst;
-}
-
-typedef uint8_t * (*shift_ir_t)(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size);
-typedef uint8_t * (*shift_irdisp8_t)(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size);
-typedef uint8_t * (*shift_clr_t)(uint8_t * out, uint8_t dst, uint8_t size);
-typedef uint8_t * (*shift_clrdisp8_t)(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size);
-
-uint8_t * translate_shift(uint8_t * dst, m68kinst * inst, x86_ea *src_op, x86_ea * dst_op, x86_68k_options * opts, shift_ir_t shift_ir, shift_irdisp8_t shift_irdisp8, shift_clr_t shift_clr, shift_clrdisp8_t shift_clrdisp8, shift_ir_t special, shift_irdisp8_t special_disp8)
-{
-	uint8_t * end_off = NULL;
-	uint8_t * nz_off = NULL;
-	uint8_t * z_off = NULL;
-	if (inst->src.addr_mode == MODE_UNUSED) {
-		dst = cycles(dst, BUS);
-		//Memory shift
-		dst = shift_ir(dst, 1, dst_op->base, SZ_W);
-	} else {
-		dst = cycles(dst, inst->extra.size == OPSIZE_LONG ? 8 : 6);
-		if (src_op->mode == MODE_IMMED) {
-			if (src_op->disp != 1 && inst->op == M68K_ASL) {
-				dst = mov_ir(dst, 0, FLAG_V, SZ_B);
-				for (int i = 0; i < src_op->disp; i++) {
-					if (dst_op->mode == MODE_REG_DIRECT) {
-						dst = shift_ir(dst, 1, dst_op->base, inst->extra.size);
-					} else {
-						dst = shift_irdisp8(dst, 1, dst_op->base, dst_op->disp, inst->extra.size);
-					}
-					//dst = setcc_r(dst, CC_O, FLAG_V);
-					dst = jcc(dst, CC_NO, dst+4);
-					dst = mov_ir(dst, 1, FLAG_V, SZ_B);
-				}
-			} else {
-				if (dst_op->mode == MODE_REG_DIRECT) {
-					dst = shift_ir(dst, src_op->disp, dst_op->base, inst->extra.size);
-				} else {
-					dst = shift_irdisp8(dst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size);
-				}
-				dst = setcc_r(dst, CC_O, FLAG_V);
-			}
-		} else {
-			if (src_op->base != RCX) {
-				if (src_op->mode == MODE_REG_DIRECT) {
-					dst = mov_rr(dst, src_op->base, RCX, SZ_B);
-				} else {
-					dst = mov_rdisp8r(dst, src_op->base, src_op->disp, RCX, SZ_B);
-				}
-
-			}
-			dst = and_ir(dst, 63, RCX, SZ_D);
-			nz_off = dst+1;
-			dst = jcc(dst, CC_NZ, dst+2);
-			//Flag behavior for shift count of 0 is different for x86 than 68K
-			if (dst_op->mode == MODE_REG_DIRECT) {
-				dst = cmp_ir(dst, 0, dst_op->base, inst->extra.size);
-			} else {
-				dst = cmp_irdisp8(dst, 0, dst_op->base, dst_op->disp, inst->extra.size);
-			}
-			dst = setcc_r(dst, CC_Z, FLAG_Z);
-			dst = setcc_r(dst, CC_S, FLAG_N);
-			dst = mov_ir(dst, 0, FLAG_C, SZ_B);
-			//For other instructions, this flag will be set below
-			if (inst->op == M68K_ASL) {
-				dst = mov_ir(dst, 0, FLAG_V, SZ_B);
-			}
-			z_off = dst+1;
-			dst = jmp(dst, dst+2);
-			*nz_off = dst - (nz_off + 1);
-			//add 2 cycles for every bit shifted
-			dst = add_rr(dst, RCX, CYCLES, SZ_D);
-			dst = add_rr(dst, RCX, CYCLES, SZ_D);
-			if (inst->op == M68K_ASL) {
-				//ASL has Overflow flag behavior that depends on all of the bits shifted through the MSB
-				//Easiest way to deal with this is to shift one bit at a time
-				dst = mov_ir(dst, 0, FLAG_V, SZ_B);
-				uint8_t * loop_start = dst;
-				if (dst_op->mode == MODE_REG_DIRECT) {
-					dst = shift_ir(dst, 1, dst_op->base, inst->extra.size);
-				} else {
-					dst = shift_irdisp8(dst, 1, dst_op->base, dst_op->disp, inst->extra.size);
-				}
-				//dst = setcc_r(dst, CC_O, FLAG_V);
-				dst = jcc(dst, CC_NO, dst+4);
-				dst = mov_ir(dst, 1, FLAG_V, SZ_B);
-				dst = loop(dst, loop_start);
-			} else {
-				//x86 shifts modulo 32 for operand sizes less than 64-bits
-				//but M68K shifts modulo 64, so we need to check for large shifts here
-				dst = cmp_ir(dst, 32, RCX, SZ_B);
-				uint8_t * norm_shift_off = dst + 1;
-				dst = jcc(dst, CC_L, dst+2);
-				if (special) {
-					if (inst->extra.size == OPSIZE_LONG) {
-						uint8_t * neq_32_off = dst + 1;
-						dst = jcc(dst, CC_NZ, dst+2);
-
-						//set the carry bit to the lsb
-						if (dst_op->mode == MODE_REG_DIRECT) {
-							dst = special(dst, 1, dst_op->base, SZ_D);
-						} else {
-							dst = special_disp8(dst, 1, dst_op->base, dst_op->disp, SZ_D);
-						}
-						dst = setcc_r(dst, CC_C, FLAG_C);
-						dst = jmp(dst, dst+4);
-						*neq_32_off = dst - (neq_32_off+1);
-					}
-					dst = mov_ir(dst, 0, FLAG_C, SZ_B);
-					dst = mov_ir(dst, 1, FLAG_Z, SZ_B);
-					dst = mov_ir(dst, 0, FLAG_N, SZ_B);
-					if (dst_op->mode == MODE_REG_DIRECT) {
-						dst = xor_rr(dst, dst_op->base, dst_op->base, inst->extra.size);
-					} else {
-						dst = mov_irdisp8(dst, 0, dst_op->base, dst_op->disp, inst->extra.size);
-					}
-				} else {
-					if (dst_op->mode == MODE_REG_DIRECT) {
-						dst = shift_ir(dst, 31, dst_op->base, inst->extra.size);
-						dst = shift_ir(dst, 1, dst_op->base, inst->extra.size);
-					} else {
-						dst = shift_irdisp8(dst, 31, dst_op->base, dst_op->disp, inst->extra.size);
-						dst = shift_irdisp8(dst, 1, dst_op->base, dst_op->disp, inst->extra.size);
-					}
-
-				}
-				end_off = dst+1;
-				dst = jmp(dst, dst+2);
-				*norm_shift_off = dst - (norm_shift_off+1);
-				if (dst_op->mode == MODE_REG_DIRECT) {
-					dst = shift_clr(dst, dst_op->base, inst->extra.size);
-				} else {
-					dst = shift_clrdisp8(dst, dst_op->base, dst_op->disp, inst->extra.size);
-				}
-			}
-		}
-
-	}
-	if (!special && end_off) {
-		*end_off = dst - (end_off + 1);
-	}
-	dst = setcc_r(dst, CC_C, FLAG_C);
-	dst = setcc_r(dst, CC_Z, FLAG_Z);
-	dst = setcc_r(dst, CC_S, FLAG_N);
-	if (special && end_off) {
-		*end_off = dst - (end_off + 1);
-	}
-	//set X flag to same as C flag
-	dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B);
-	if (z_off) {
-		*z_off = dst - (z_off + 1);
-	}
-	if (inst->op != M68K_ASL) {
-		dst = mov_ir(dst, 0, FLAG_V, SZ_B);
-	}
-	if (inst->src.addr_mode == MODE_UNUSED) {
-		dst = m68k_save_result(inst, dst, opts);
-	}
-	return dst;
-}
-
-#define BIT_SUPERVISOR 5
-
-uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
-{
-	uint8_t * end_off, *zero_off, *norm_off;
-	uint8_t dst_reg;
-	dst = check_cycles_int(dst, inst->address, opts);
-	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_PEA) {
-		return translate_m68k_pea(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_JMP) {
-		return translate_m68k_jmp(dst, inst, opts);
-	} else if(inst->op == M68K_JSR) {
-		return translate_m68k_jsr(dst, inst, opts);
-	} else if(inst->op == M68K_RTS) {
-		return translate_m68k_rts(dst, inst, opts);
-	} else if(inst->op == M68K_DBCC) {
-		return translate_m68k_dbcc(dst, inst, opts);
-	} else if(inst->op == M68K_CLR) {
-		return translate_m68k_clr(dst, inst, opts);
-	} else if(inst->op == M68K_MOVEM) {
-		return translate_m68k_movem(dst, inst, opts);
-	} else if(inst->op == M68K_LINK) {
-		return translate_m68k_link(dst, inst, opts);
-	} else if(inst->op == M68K_EXT) {
-		return translate_m68k_ext(dst, inst, opts);
-	} else if(inst->op == M68K_SCC) {
-		return translate_m68k_scc(dst, inst, opts);
-	} else if(inst->op == M68K_MOVEP) {
-		return translate_m68k_movep(dst, inst, opts);
-	} else if(inst->op == M68K_INVALID) {
-		if (inst->src.params.immed == 0x7100) {
-			return retn(dst);
-		}
-		dst = mov_ir(dst, inst->address, SCRATCH1, SZ_D);
-		return call(dst, (uint8_t *)m68k_invalid);
-	} else if(inst->op == M68K_CMP) {
-		return translate_m68k_cmp(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, 0);
-	}
-	uint8_t size;
-	switch(inst->op)
-	{
-	case M68K_ABCD:
-		if (src_op.base != SCRATCH2) {
-			if (src_op.mode == MODE_REG_DIRECT) {
-				dst = mov_rr(dst, src_op.base, SCRATCH2, SZ_B);
-			} else {
-				dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH2, SZ_B);
-			}
-		}
-		if (dst_op.base != SCRATCH1) {
-			if (dst_op.mode == MODE_REG_DIRECT) {
-				dst = mov_rr(dst, dst_op.base, SCRATCH1, SZ_B);
-			} else {
-				dst = mov_rdisp8r(dst, dst_op.base, dst_op.disp, SCRATCH1, SZ_B);
-			}
-		}
-		dst = bt_irdisp8(dst, 0, CONTEXT, 0, SZ_B);
-		dst = jcc(dst, CC_NC, dst+5);
-		dst = add_ir(dst, 1, SCRATCH1, SZ_B);
-		dst = call(dst, (uint8_t *)bcd_add);
-		dst = mov_rr(dst, CH, FLAG_C, SZ_B);
-		dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B);
-		dst = cmp_ir(dst, 0, SCRATCH1, SZ_B);
-		dst = jcc(dst, CC_Z, dst+4);
-		dst = mov_ir(dst, 0, FLAG_Z, SZ_B);
-		if (dst_op.base != SCRATCH1) {
-			if (dst_op.mode == MODE_REG_DIRECT) {
-				dst = mov_rr(dst, SCRATCH1, dst_op.base, SZ_B);
-			} else {
-				dst = mov_rrdisp8(dst, SCRATCH1, dst_op.base, dst_op.disp, SZ_B);
-			}
-		}
-		dst = m68k_save_result(inst, dst, opts);
-		break;
-	case M68K_ADD:
-		dst = cycles(dst, BUS);
-		size = inst->dst.addr_mode == MODE_AREG ? OPSIZE_LONG : inst->extra.size;
-		if (src_op.mode == MODE_REG_DIRECT) {
-			if (dst_op.mode == MODE_REG_DIRECT) {
-				dst = add_rr(dst, src_op.base, dst_op.base, size);
-			} else {
-				dst = add_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, size);
-			}
-		} else if (src_op.mode == MODE_REG_DISPLACE8) {
-			dst = add_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, size);
-		} else {
-			if (dst_op.mode == MODE_REG_DIRECT) {
-				dst = add_ir(dst, src_op.disp, dst_op.base, size);
-			} else {
-				dst = add_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, size);
-			}
-		}
-		if (inst->dst.addr_mode != MODE_AREG) {
-			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 = m68k_save_result(inst, dst, opts);
-		break;
-	case M68K_ADDX:
-		dst = cycles(dst, BUS);
-		dst = bt_irdisp8(dst, 0, CONTEXT, 0, SZ_B);
-		if (src_op.mode == MODE_REG_DIRECT) {
-			if (dst_op.mode == MODE_REG_DIRECT) {
-				dst = adc_rr(dst, src_op.base, dst_op.base, inst->extra.size);
-			} else {
-				dst = adc_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, inst->extra.size);
-			}
-		} else if (src_op.mode == MODE_REG_DISPLACE8) {
-			dst = adc_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, inst->extra.size);
-		} else {
-			if (dst_op.mode == MODE_REG_DIRECT) {
-				dst = adc_ir(dst, src_op.disp, dst_op.base, inst->extra.size);
-			} else {
-				dst = adc_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size);
-			}
-		}
-		dst = setcc_r(dst, CC_C, FLAG_C);
-		dst = jcc(dst, CC_Z, dst+4);
-		dst = mov_ir(dst, 0, FLAG_Z, SZ_B);
-		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 = m68k_save_result(inst, dst, opts);
-		break;
-	case M68K_AND:
-		dst = cycles(dst, BUS);
-		if (src_op.mode == MODE_REG_DIRECT) {
-			if (dst_op.mode == MODE_REG_DIRECT) {
-				dst = and_rr(dst, src_op.base, dst_op.base, inst->extra.size);
-			} else {
-				dst = and_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, inst->extra.size);
-			}
-		} else if (src_op.mode == MODE_REG_DISPLACE8) {
-			dst = and_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, inst->extra.size);
-		} else {
-			if (dst_op.mode == MODE_REG_DIRECT) {
-				dst = and_ir(dst, src_op.disp, dst_op.base, inst->extra.size);
-			} else {
-				dst = and_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size);
-			}
-		}
-		dst = mov_ir(dst, 0, FLAG_C, SZ_B);
-		dst = setcc_r(dst, CC_Z, FLAG_Z);
-		dst = setcc_r(dst, CC_S, FLAG_N);
-		dst = mov_ir(dst, 0, FLAG_V, SZ_B);
-		dst = m68k_save_result(inst, dst, opts);
-		break;
-	case M68K_ANDI_CCR:
-	case M68K_ANDI_SR:
-		dst = cycles(dst, 20);
-		//TODO: If ANDI to SR, trap if not in supervisor mode
-		if (!(inst->src.params.immed & 0x1)) {
-			dst = mov_ir(dst, 0, FLAG_C, SZ_B);
-		}
-		if (!(inst->src.params.immed & 0x2)) {
-			dst = mov_ir(dst, 0, FLAG_V, SZ_B);
-		}
-		if (!(inst->src.params.immed & 0x4)) {
-			dst = mov_ir(dst, 0, FLAG_Z, SZ_B);
-		}
-		if (!(inst->src.params.immed & 0x8)) {
-			dst = mov_ir(dst, 0, FLAG_N, SZ_B);
-		}
-		if (!(inst->src.params.immed & 0x10)) {
-			dst = mov_irind(dst, 0, CONTEXT, SZ_B);
-		}
-		if (inst->op == M68K_ANDI_SR) {
-			dst = and_irdisp8(dst, inst->src.params.immed >> 8, CONTEXT, offsetof(m68k_context, status), SZ_B);
-			if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) {
-				//leave supervisor mode
-				dst = mov_rr(dst, opts->aregs[7], SCRATCH1, SZ_B);
-				dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, opts->aregs[7], SZ_B);
-				dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_B);
-			}
-			//dst = call(dst, (uint8_t *)debug_print_sr);
-			if (inst->src.params.immed & 0x700) {
-				dst = call(dst, (uint8_t *)do_sync);
-			}
-		}
-		break;
-	case M68K_ASL:
-	case M68K_LSL:
-		dst = translate_shift(dst, inst, &src_op, &dst_op, opts, shl_ir, shl_irdisp8, shl_clr, shl_clrdisp8, shr_ir, shr_irdisp8);
-		break;
-	case M68K_ASR:
-		dst = translate_shift(dst, inst, &src_op, &dst_op, opts, sar_ir, sar_irdisp8, sar_clr, sar_clrdisp8, NULL, NULL);
-		break;
-	case M68K_LSR:
-		dst = translate_shift(dst, inst, &src_op, &dst_op, opts, shr_ir, shr_irdisp8, shr_clr, shr_clrdisp8, shl_ir, shl_irdisp8);
-		break;
-	case M68K_BCHG:
-	case M68K_BCLR:
-	case M68K_BSET:
-	case M68K_BTST:
-		dst = cycles(dst, inst->extra.size == OPSIZE_BYTE ? 4 : (
-			inst->op == M68K_BTST ? 6 : (inst->op == M68K_BCLR ? 10 : 8))
-		);
-		if (src_op.mode == MODE_IMMED) {
-			if (inst->extra.size == OPSIZE_BYTE) {
-				src_op.disp &= 0x7;
-			}
-			if (inst->op == M68K_BTST) {
-				if (dst_op.mode == MODE_REG_DIRECT) {
-					dst = bt_ir(dst, src_op.disp, dst_op.base, inst->extra.size);
-				} else {
-					dst = bt_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size);
-				}
-			} else if (inst->op == M68K_BSET) {
-				if (dst_op.mode == MODE_REG_DIRECT) {
-					dst = bts_ir(dst, src_op.disp, dst_op.base, inst->extra.size);
-				} else {
-					dst = bts_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size);
-				}
-			} else if (inst->op == M68K_BCLR) {
-				if (dst_op.mode == MODE_REG_DIRECT) {
-					dst = btr_ir(dst, src_op.disp, dst_op.base, inst->extra.size);
-				} else {
-					dst = btr_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size);
-				}
-			} else {
-				if (dst_op.mode == MODE_REG_DIRECT) {
-					dst = btc_ir(dst, src_op.disp, dst_op.base, inst->extra.size);
-				} else {
-					dst = btc_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size);
-				}
-			}
-		} else {
-			if (src_op.mode == MODE_REG_DISPLACE8 || (inst->dst.addr_mode != MODE_REG && src_op.base != SCRATCH1 && src_op.base != SCRATCH2)) {
-				if (dst_op.base == SCRATCH1) {
-					dst = push_r(dst, SCRATCH2);
-					if (src_op.mode == MODE_REG_DIRECT) {
-						dst = mov_rr(dst, src_op.base, SCRATCH2, SZ_B);
-					} else {
-						dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH2, SZ_B);
-					}
-					src_op.base = SCRATCH2;
-				} else {
-					if (src_op.mode == MODE_REG_DIRECT) {
-						dst = mov_rr(dst, src_op.base, SCRATCH1, SZ_B);
-					} else {
-						dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_B);
-					}
-					src_op.base = SCRATCH1;
-				}
-			}
-			uint8_t size = inst->extra.size;
-			if (dst_op.mode == MODE_REG_DISPLACE8) {
-				if (src_op.base != SCRATCH1 && src_op.base != SCRATCH2) {
-					if (src_op.mode == MODE_REG_DIRECT) {
-						dst = mov_rr(dst, src_op.base, SCRATCH1, SZ_D);
-					} else {
-						dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_D);
-						src_op.mode = MODE_REG_DIRECT;
-					}
-					src_op.base = SCRATCH1;
-				}
-				//b### with register destination is modulo 32
-				//x86 with a memory destination isn't modulo anything
-				//so use an and here to force the value to be modulo 32
-				dst = and_ir(dst, 31, SCRATCH1, SZ_D);
-			} else if(inst->dst.addr_mode != MODE_REG) {
-				//b### with memory destination is modulo 8
-				//x86-64 doesn't support 8-bit bit operations
-				//so we fake it by forcing the bit number to be modulo 8
-				dst = and_ir(dst, 7, src_op.base, SZ_D);
-				size = SZ_D;
-			}
-			if (inst->op == M68K_BTST) {
-				if (dst_op.mode == MODE_REG_DIRECT) {
-					dst = bt_rr(dst, src_op.base, dst_op.base, size);
-				} else {
-					dst = bt_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, size);
-				}
-			} else if (inst->op == M68K_BSET) {
-				if (dst_op.mode == MODE_REG_DIRECT) {
-					dst = bts_rr(dst, src_op.base, dst_op.base, size);
-				} else {
-					dst = bts_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, size);
-				}
-			} else if (inst->op == M68K_BCLR) {
-				if (dst_op.mode == MODE_REG_DIRECT) {
-					dst = btr_rr(dst, src_op.base, dst_op.base, size);
-				} else {
-					dst = btr_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, size);
-				}
-			} else {
-				if (dst_op.mode == MODE_REG_DIRECT) {
-					dst = btc_rr(dst, src_op.base, dst_op.base, size);
-				} else {
-					dst = btc_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, size);
-				}
-			}
-			if (src_op.base == SCRATCH2) {
-				dst = pop_r(dst, SCRATCH2);
-			}
-		}
-		//x86 sets the carry flag to the value of the bit tested
-		//68K sets the zero flag to the complement of the bit tested
-		dst = setcc_r(dst, CC_NC, FLAG_Z);
-		if (inst->op != M68K_BTST) {
-			dst = m68k_save_result(inst, dst, opts);
-		}
-		break;
-	case M68K_CHK:
-	{
-		dst = cycles(dst, 6);
-		if (dst_op.mode == MODE_REG_DIRECT) {
-			dst = cmp_ir(dst, 0, dst_op.base, inst->extra.size);
-		} else {
-			dst = cmp_irdisp8(dst, 0, dst_op.base, dst_op.disp, inst->extra.size);
-		}
-		uint32_t isize;
-		switch(inst->src.addr_mode)
-		{
-		case MODE_AREG_DISPLACE:
-		case MODE_AREG_INDEX_DISP8:
-		case MODE_ABSOLUTE_SHORT:
-		case MODE_PC_INDEX_DISP8:
-		case MODE_PC_DISPLACE:
-		case MODE_IMMEDIATE:
-			isize = 4;
-			break;
-		case MODE_ABSOLUTE:
-			isize = 6;
-			break;
-		default:
-			isize = 2;
-		}
-		uint8_t * passed = dst+1;
-		dst = jcc(dst, CC_GE, dst+2);
-		dst = mov_ir(dst, 1, FLAG_N, SZ_B);
-		dst = mov_ir(dst, VECTOR_CHK, SCRATCH2, SZ_D);
-		dst = mov_ir(dst, inst->address+isize, SCRATCH1, SZ_D);
-		dst = jmp(dst, opts->trap);
-		*passed = dst - (passed+1);
-		if (dst_op.mode == MODE_REG_DIRECT) {
-			if (src_op.mode == MODE_REG_DIRECT) {
-				dst = cmp_rr(dst, src_op.base, dst_op.base, 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 {
-				dst = cmp_ir(dst, src_op.disp, dst_op.base, inst->extra.size);
-			}
-		} else if(dst_op.mode == MODE_REG_DISPLACE8) {
-			if (src_op.mode == MODE_REG_DIRECT) {
-				dst = cmp_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, inst->extra.size);
-			} else {
-				dst = cmp_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size);
-			}
-		}
-		passed = dst+1;
-		dst = jcc(dst, CC_LE, dst+2);
-		dst = mov_ir(dst, 0, FLAG_N, SZ_B);
-		dst = mov_ir(dst, VECTOR_CHK, SCRATCH2, SZ_D);
-		dst = mov_ir(dst, inst->address+isize, SCRATCH1, SZ_D);
-		dst = jmp(dst, opts->trap);
-		*passed = dst - (passed+1);
-		dst = cycles(dst, 4);
-		break;
-	}
-	case M68K_DIVS:
-	case M68K_DIVU:
-	{
-		//TODO: cycle exact division
-		dst = cycles(dst, inst->op == M68K_DIVS ? 158 : 140);
-		dst = mov_ir(dst, 0, FLAG_C, SZ_B);
-		dst = push_r(dst, RDX);
-		dst = push_r(dst, RAX);
-		if (dst_op.mode == MODE_REG_DIRECT) {
-			dst = mov_rr(dst, dst_op.base, RAX, SZ_D);
-		} else {
-			dst = mov_rdisp8r(dst, dst_op.base, dst_op.disp, RAX, SZ_D);
-		}
-		if (src_op.mode == MODE_IMMED) {
-			dst = mov_ir(dst, (src_op.disp & 0x8000) && inst->op == M68K_DIVS ? src_op.disp | 0xFFFF0000 : src_op.disp, SCRATCH2, SZ_D);
-		} else if (src_op.mode == MODE_REG_DIRECT) {
-			if (inst->op == M68K_DIVS) {
-				dst = movsx_rr(dst, src_op.base, SCRATCH2, SZ_W, SZ_D);
-			} else {
-				dst = movzx_rr(dst, src_op.base, SCRATCH2, SZ_W, SZ_D);
-			}
-		} else if (src_op.mode == MODE_REG_DISPLACE8) {
-			if (inst->op == M68K_DIVS) {
-				dst = movsx_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH2, SZ_W, SZ_D);
-			} else {
-				dst = movzx_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH2, SZ_W, SZ_D);
-			}
-		}
-		dst = cmp_ir(dst, 0, SCRATCH2, SZ_D);
-		uint8_t * not_zero = dst+1;
-		dst = jcc(dst, CC_NZ, dst+2);
-		dst = pop_r(dst, RAX);
-		dst = pop_r(dst, RDX);
-		dst = mov_ir(dst, VECTOR_INT_DIV_ZERO, SCRATCH2, SZ_D);
-		dst = mov_ir(dst, inst->address+2, SCRATCH1, SZ_D);
-		dst = jmp(dst, opts->trap);
-		*not_zero = dst - (not_zero+1);
-		if (inst->op == M68K_DIVS) {
-			dst = cdq(dst);
-		} else {
-			dst = xor_rr(dst, RDX, RDX, SZ_D);
-		}
-		if (inst->op == M68K_DIVS) {
-			dst = idiv_r(dst, SCRATCH2, SZ_D);
-		} else {
-			dst = div_r(dst, SCRATCH2, SZ_D);
-		}
-		uint8_t * skip_sec_check;
-		if (inst->op == M68K_DIVS) {
-			dst = cmp_ir(dst, 0x8000, RAX, SZ_D);
-			skip_sec_check = dst + 1;
-			dst = jcc(dst, CC_GE, dst+2);
-			dst = cmp_ir(dst, -0x8000, RAX, SZ_D);
-			norm_off = dst+1;
-			dst = jcc(dst, CC_L, dst+2);
-		} else {
-			dst = cmp_ir(dst, 0x10000, RAX, SZ_D);
-			norm_off = dst+1;
-			dst = jcc(dst, CC_NC, dst+2);
-		}
-		if (dst_op.mode == MODE_REG_DIRECT) {
-			dst = mov_rr(dst, RDX, dst_op.base, SZ_W);
-			dst = shl_ir(dst, 16, dst_op.base, SZ_D);
-			dst = mov_rr(dst, RAX, dst_op.base, SZ_W);
-		} else {
-			dst = mov_rrdisp8(dst, RDX, dst_op.base, dst_op.disp, SZ_W);
-			dst = shl_irdisp8(dst, 16, dst_op.base, dst_op.disp, SZ_D);
-			dst = mov_rrdisp8(dst, RAX, dst_op.base, dst_op.disp, SZ_W);
-		}
-		dst = cmp_ir(dst, 0, RAX, SZ_W);
-		dst = pop_r(dst, RAX);
-		dst = pop_r(dst, RDX);
-		dst = mov_ir(dst, 0, FLAG_V, SZ_B);
-		dst = setcc_r(dst, CC_Z, FLAG_Z);
-		dst = setcc_r(dst, CC_S, FLAG_N);
-		end_off = dst+1;
-		dst = jmp(dst, dst+2);
-		*norm_off = dst - (norm_off + 1);
-		if (inst->op == M68K_DIVS) {
-			*skip_sec_check = dst - (skip_sec_check+1);
-		}
-		dst = pop_r(dst, RAX);
-		dst = pop_r(dst, RDX);
-		dst = mov_ir(dst, 1, FLAG_V, SZ_B);
-		*end_off = dst - (end_off + 1);
-		break;
-	}
-	case M68K_EOR:
-		dst = cycles(dst, BUS);
-		if (src_op.mode == MODE_REG_DIRECT) {
-			if (dst_op.mode == MODE_REG_DIRECT) {
-				dst = xor_rr(dst, src_op.base, dst_op.base, inst->extra.size);
-			} else {
-				dst = xor_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, inst->extra.size);
-			}
-		} else if (src_op.mode == MODE_REG_DISPLACE8) {
-			dst = xor_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, inst->extra.size);
-		} else {
-			if (dst_op.mode == MODE_REG_DIRECT) {
-				dst = xor_ir(dst, src_op.disp, dst_op.base, inst->extra.size);
-			} else {
-				dst = xor_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size);
-			}
-		}
-		dst = mov_ir(dst, 0, FLAG_C, SZ_B);
-		dst = setcc_r(dst, CC_Z, FLAG_Z);
-		dst = setcc_r(dst, CC_S, FLAG_N);
-		dst = mov_ir(dst, 0, FLAG_V, SZ_B);
-		dst = m68k_save_result(inst, dst, opts);
-		break;
-	case M68K_EORI_CCR:
-	case M68K_EORI_SR:
-		dst = cycles(dst, 20);
-		//TODO: If ANDI to SR, trap if not in supervisor mode
-		if (inst->src.params.immed & 0x1) {
-			dst = xor_ir(dst, 1, FLAG_C, SZ_B);
-		}
-		if (inst->src.params.immed & 0x2) {
-			dst = xor_ir(dst, 1, FLAG_V, SZ_B);
-		}
-		if (inst->src.params.immed & 0x4) {
-			dst = xor_ir(dst, 1, FLAG_Z, SZ_B);
-		}
-		if (inst->src.params.immed & 0x8) {
-			dst = xor_ir(dst, 1, FLAG_N, SZ_B);
-		}
-		if (inst->src.params.immed & 0x10) {
-			dst = xor_irdisp8(dst, 1, CONTEXT, 0, SZ_B);
-		}
-		if (inst->op == M68K_ORI_SR) {
-			dst = xor_irdisp8(dst, inst->src.params.immed >> 8, CONTEXT, offsetof(m68k_context, status), SZ_B);
-			//dst = call(dst, (uint8_t *)debug_print_sr);
-			if (inst->src.params.immed & 0x700) {
-				dst = call(dst, (uint8_t *)do_sync);
-			}
-		}
-		break;
-	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);
-			}
-		}
-		break;
-	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_MOVE_FROM_SR:
-		//TODO: Trap if not in system mode
-		dst = call(dst, (uint8_t *)get_sr);
-		if (dst_op.mode == MODE_REG_DIRECT) {
-			dst = mov_rr(dst, SCRATCH1, dst_op.base, SZ_W);
-		} else {
-			dst = mov_rrdisp8(dst, SCRATCH1, dst_op.base, dst_op.disp, SZ_W);
-		}
-		dst = m68k_save_result(inst, dst, opts);
-		break;
-	case M68K_MOVE_CCR:
-	case M68K_MOVE_SR:
-		//TODO: Privilege check for MOVE to SR
-		if (src_op.mode == MODE_IMMED) {
-			dst = mov_ir(dst, src_op.disp & 0x1, FLAG_C, SZ_B);
-			dst = mov_ir(dst, (src_op.disp >> 1) & 0x1, FLAG_V, SZ_B);
-			dst = mov_ir(dst, (src_op.disp >> 2) & 0x1, FLAG_Z, SZ_B);
-			dst = mov_ir(dst, (src_op.disp >> 3) & 0x1, FLAG_N, SZ_B);
-			dst = mov_irind(dst, (src_op.disp >> 4) & 0x1, CONTEXT, SZ_B);
-			if (inst->op == M68K_MOVE_SR) {
-				dst = mov_irdisp8(dst, (src_op.disp >> 8), CONTEXT, offsetof(m68k_context, status), SZ_B);
-				if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) {
-					//leave supervisor mode
-					dst = mov_rr(dst, opts->aregs[7], SCRATCH1, SZ_D);
-					dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, opts->aregs[7], SZ_D);
-					dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D);
-				}
-				//dst = call(dst, (uint8_t *)debug_print_sr);
-				dst = call(dst, (uint8_t *)do_sync);
-			}
-			dst = cycles(dst, 12);
-		} else {
-			if (src_op.base != SCRATCH1) {
-				if (src_op.mode == MODE_REG_DIRECT) {
-					dst = mov_rr(dst, src_op.base, SCRATCH1, SZ_W);
-				} else {
-					dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_W);
-				}
-			}
-			dst = call(dst, (uint8_t *)(inst->op == M68K_MOVE_SR ? set_sr : set_ccr));
-			dst = cycles(dst, 12);
-
-		}
-		break;
-	case M68K_MOVE_USP:
-		dst = cycles(dst, BUS);
-		//TODO: Trap if not in supervisor mode
-		//dst = bt_irdisp8(dst, BIT_SUPERVISOR, CONTEXT, offsetof(m68k_context, status), SZ_B);
-		if (inst->src.addr_mode == MODE_UNUSED) {
-			if (dst_op.mode == MODE_REG_DIRECT) {
-				dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, dst_op.base, SZ_D);
-			} else {
-				dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SCRATCH1, SZ_D);
-				dst = mov_rrdisp8(dst, SCRATCH1, dst_op.base, dst_op.disp, SZ_D);
-			}
-		} else {
-			if (src_op.mode == MODE_REG_DIRECT) {
-				dst = mov_rrdisp8(dst, src_op.base, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D);
-			} else {
-				dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_D);
-				dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D);
-			}
-		}
-		break;
-	//case M68K_MOVEP:
-	case M68K_MULS:
-	case M68K_MULU:
-		dst = cycles(dst, 70); //TODO: Calculate the actual value based on the value of the <ea> parameter
-		if (src_op.mode == MODE_IMMED) {
-			dst = mov_ir(dst, inst->op == M68K_MULU ? (src_op.disp & 0xFFFF) : ((src_op.disp & 0x8000) ? src_op.disp | 0xFFFF0000 : src_op.disp), SCRATCH1, SZ_D);
-		} else if (src_op.mode == MODE_REG_DIRECT) {
-			if (inst->op == M68K_MULS) {
-				dst = movsx_rr(dst, src_op.base, SCRATCH1, SZ_W, SZ_D);
-			} else {
-				dst = movzx_rr(dst, src_op.base, SCRATCH1, SZ_W, SZ_D);
-			}
-		} else {
-			if (inst->op == M68K_MULS) {
-				dst = movsx_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_W, SZ_D);
-			} else {
-				dst = movzx_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_W, SZ_D);
-			}
-		}
-		if (dst_op.mode == MODE_REG_DIRECT) {
-			dst_reg = dst_op.base;
-			if (inst->op == M68K_MULS) {
-				dst = movsx_rr(dst, dst_reg, dst_reg, SZ_W, SZ_D);
-			} else {
-				dst = movzx_rr(dst, dst_reg, dst_reg, SZ_W, SZ_D);
-			}
-		} else {
-			dst_reg = SCRATCH2;
-			if (inst->op == M68K_MULS) {
-				dst = movsx_rdisp8r(dst, dst_op.base, dst_op.disp, SCRATCH2, SZ_W, SZ_D);
-			} else {
-				dst = movzx_rdisp8r(dst, dst_op.base, dst_op.disp, SCRATCH2, SZ_W, SZ_D);
-			}
-		}
-		dst = imul_rr(dst, SCRATCH1, dst_reg, SZ_D);
-		if (dst_op.mode == MODE_REG_DISPLACE8) {
-			dst = mov_rrdisp8(dst, dst_reg, dst_op.base, dst_op.disp, SZ_D);
-		}
-		dst = mov_ir(dst, 0, FLAG_V, SZ_B);
-		dst = mov_ir(dst, 0, FLAG_C, SZ_B);
-		dst = cmp_ir(dst, 0, dst_reg, SZ_D);
-		dst = setcc_r(dst, CC_Z, FLAG_Z);
-		dst = setcc_r(dst, CC_S, FLAG_N);
-		break;
-	//case M68K_NBCD:
-	case M68K_NEG:
-		dst = cycles(dst, BUS);
-		if (dst_op.mode == MODE_REG_DIRECT) {
-			dst = neg_r(dst, dst_op.base, inst->extra.size);
-		} else {
-			dst = neg_rdisp8(dst, 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 = m68k_save_result(inst, dst, opts);
-		break;
-	case M68K_NEGX:
-		dst = cycles(dst, BUS);
-		if (dst_op.mode == MODE_REG_DIRECT) {
-			if (dst_op.base == SCRATCH1) {
-				dst = push_r(dst, SCRATCH2);
-				dst = xor_rr(dst, SCRATCH2, SCRATCH2, inst->extra.size);
-				dst = bt_irdisp8(dst, 0, CONTEXT, 0, SZ_B);
-				dst = sbb_rr(dst, dst_op.base, SCRATCH2, inst->extra.size);
-				dst = mov_rr(dst, SCRATCH2, dst_op.base, inst->extra.size);
-				dst = pop_r(dst, SCRATCH2);
-			} else {
-				dst = xor_rr(dst, SCRATCH1, SCRATCH1, inst->extra.size);
-				dst = bt_irdisp8(dst, 0, CONTEXT, 0, SZ_B);
-				dst = sbb_rr(dst, dst_op.base, SCRATCH1, inst->extra.size);
-				dst = mov_rr(dst, SCRATCH1, dst_op.base, inst->extra.size);
-			}
-		} else {
-			dst = xor_rr(dst, SCRATCH1, SCRATCH1, inst->extra.size);
-			dst = bt_irdisp8(dst, 0, CONTEXT, 0, SZ_B);
-			dst = sbb_rdisp8r(dst, dst_op.base, dst_op.disp, SCRATCH1, inst->extra.size);
-			dst = mov_rrdisp8(dst, SCRATCH1, dst_op.base, dst_op.disp, inst->extra.size);
-		}
-		dst = setcc_r(dst, CC_C, FLAG_C);
-		dst = jcc(dst, CC_Z, dst+4);
-		dst = mov_ir(dst, 0, FLAG_Z, SZ_B);
-		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 = m68k_save_result(inst, dst, opts);
-		break;
-		break;
-	case M68K_NOP:
-		dst = cycles(dst, BUS);
-		break;
-	case M68K_NOT:
-		if (dst_op.mode == MODE_REG_DIRECT) {
-			dst = not_r(dst, dst_op.base, inst->extra.size);
-			dst = cmp_ir(dst, 0, dst_op.base, inst->extra.size);
-		} else {
-			dst = not_rdisp8(dst, dst_op.base, dst_op.disp, inst->extra.size);
-			dst = cmp_irdisp8(dst, 0, dst_op.base, dst_op.disp, inst->extra.size);
-		}
-
-		dst = mov_ir(dst, 0, FLAG_C, SZ_B);
-		dst = setcc_r(dst, CC_Z, FLAG_Z);
-		dst = setcc_r(dst, CC_S, FLAG_N);
-		dst = mov_ir(dst, 0, FLAG_V, SZ_B);
-		dst = m68k_save_result(inst, dst, opts);
-		break;
-	case M68K_OR:
-		dst = cycles(dst, BUS);
-		if (src_op.mode == MODE_REG_DIRECT) {
-			if (dst_op.mode == MODE_REG_DIRECT) {
-				dst = or_rr(dst, src_op.base, dst_op.base, inst->extra.size);
-			} else {
-				dst = or_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, inst->extra.size);
-			}
-		} else if (src_op.mode == MODE_REG_DISPLACE8) {
-			dst = or_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, inst->extra.size);
-		} else {
-			if (dst_op.mode == MODE_REG_DIRECT) {
-				dst = or_ir(dst, src_op.disp, dst_op.base, inst->extra.size);
-			} else {
-				dst = or_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size);
-			}
-		}
-		dst = mov_ir(dst, 0, FLAG_C, SZ_B);
-		dst = setcc_r(dst, CC_Z, FLAG_Z);
-		dst = setcc_r(dst, CC_S, FLAG_N);
-		dst = mov_ir(dst, 0, FLAG_V, SZ_B);
-		dst = m68k_save_result(inst, dst, opts);
-		break;
-	case M68K_ORI_CCR:
-	case M68K_ORI_SR:
-		dst = cycles(dst, 20);
-		//TODO: If ANDI to SR, trap if not in supervisor mode
-		if (inst->src.params.immed & 0x1) {
-			dst = mov_ir(dst, 1, FLAG_C, SZ_B);
-		}
-		if (inst->src.params.immed & 0x2) {
-			dst = mov_ir(dst, 1, FLAG_V, SZ_B);
-		}
-		if (inst->src.params.immed & 0x4) {
-			dst = mov_ir(dst, 1, FLAG_Z, SZ_B);
-		}
-		if (inst->src.params.immed & 0x8) {
-			dst = mov_ir(dst, 1, FLAG_N, SZ_B);
-		}
-		if (inst->src.params.immed & 0x10) {
-			dst = mov_irind(dst, 1, CONTEXT, SZ_B);
-		}
-		if (inst->op == M68K_ORI_SR) {
-			dst = or_irdisp8(dst, inst->src.params.immed >> 8, CONTEXT, offsetof(m68k_context, status), SZ_B);
-			//dst = call(dst, (uint8_t *)debug_print_sr);
-			if (inst->src.params.immed & 0x700) {
-				dst = call(dst, (uint8_t *)do_sync);
-			}
-		}
-		break;
-	case M68K_RESET:
-		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_ROL:
-	case M68K_ROR:
-		dst = mov_ir(dst, 0, FLAG_V, SZ_B);
-		if (inst->src.addr_mode == MODE_UNUSED) {
-			dst = cycles(dst, BUS);
-			//Memory rotate
-			if (inst->op == M68K_ROL) {
-				dst = rol_ir(dst, 1, dst_op.base, inst->extra.size);
-			} else {
-				dst = ror_ir(dst, 1, dst_op.base, inst->extra.size);
-			}
-			dst = setcc_r(dst, CC_C, FLAG_C);
-			dst = cmp_ir(dst, 0, dst_op.base, inst->extra.size);
-			dst = setcc_r(dst, CC_Z, FLAG_Z);
-			dst = setcc_r(dst, CC_S, FLAG_N);
-			dst = m68k_save_result(inst, dst, opts);
-		} else {
-			if (src_op.mode == MODE_IMMED) {
-				dst = cycles(dst, (inst->extra.size == OPSIZE_LONG ? 8 : 6) + src_op.disp*2);
-				if (dst_op.mode == MODE_REG_DIRECT) {
-					if (inst->op == M68K_ROL) {
-						dst = rol_ir(dst, src_op.disp, dst_op.base, inst->extra.size);
-					} else {
-						dst = ror_ir(dst, src_op.disp, dst_op.base, inst->extra.size);
-					}
-				} else {
-					if (inst->op == M68K_ROL) {
-						dst = rol_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size);
-					} else {
-						dst = ror_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size);
-					}
-				}
-				dst = setcc_r(dst, CC_C, FLAG_C);
-			} else {
-				if (src_op.mode == MODE_REG_DIRECT) {
-					if (src_op.base != SCRATCH1) {
-						dst = mov_rr(dst, src_op.base, SCRATCH1, SZ_B);
-					}
-				} else {
-					dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_B);
-				}
-				dst = and_ir(dst, 63, SCRATCH1, SZ_D);
-				zero_off = dst+1;
-				dst = jcc(dst, CC_Z, dst+2);
-				dst = add_rr(dst, SCRATCH1, CYCLES, SZ_D);
-				dst = add_rr(dst, SCRATCH1, CYCLES, SZ_D);
-				dst = cmp_ir(dst, 32, SCRATCH1, SZ_B);
-				norm_off = dst+1;
-				dst = jcc(dst, CC_L, dst+2);
-				dst = sub_ir(dst, 32, SCRATCH1, SZ_B);
-				if (dst_op.mode == MODE_REG_DIRECT) {
-					if (inst->op == M68K_ROL) {
-						dst = rol_ir(dst, 31, dst_op.base, inst->extra.size);
-						dst = rol_ir(dst, 1, dst_op.base, inst->extra.size);
-					} else {
-						dst = ror_ir(dst, 31, dst_op.base, inst->extra.size);
-						dst = ror_ir(dst, 1, dst_op.base, inst->extra.size);
-					}
-				} else {
-					if (inst->op == M68K_ROL) {
-						dst = rol_irdisp8(dst, 31, dst_op.base, dst_op.disp, inst->extra.size);
-						dst = rol_irdisp8(dst, 1, dst_op.base, dst_op.disp, inst->extra.size);
-					} else {
-						dst = ror_irdisp8(dst, 31, dst_op.base, dst_op.disp, inst->extra.size);
-						dst = ror_irdisp8(dst, 1, dst_op.base, dst_op.disp, inst->extra.size);
-					}
-				}
-				*norm_off = dst - (norm_off+1);
-				if (dst_op.mode == MODE_REG_DIRECT) {
-					if (inst->op == M68K_ROL) {
-						dst = rol_clr(dst, dst_op.base, inst->extra.size);
-					} else {
-						dst = ror_clr(dst, dst_op.base, inst->extra.size);
-					}
-				} else {
-					if (inst->op == M68K_ROL) {
-						dst = rol_clrdisp8(dst, dst_op.base, dst_op.disp, inst->extra.size);
-					} else {
-						dst = ror_clrdisp8(dst, dst_op.base, dst_op.disp, inst->extra.size);
-					}
-				}
-				dst = setcc_r(dst, CC_C, FLAG_C);
-				end_off = dst + 1;
-				dst = jmp(dst, dst+2);
-				*zero_off = dst - (zero_off+1);
-				dst = mov_ir(dst, 0, FLAG_C, SZ_B);
-				*end_off = dst - (end_off+1);
-			}
-			if (dst_op.mode == MODE_REG_DIRECT) {
-				dst = cmp_ir(dst, 0, dst_op.base, inst->extra.size);
-			} else {
-				dst = cmp_irdisp8(dst, 0, dst_op.base, dst_op.disp, inst->extra.size);
-			}
-			dst = setcc_r(dst, CC_Z, FLAG_Z);
-			dst = setcc_r(dst, CC_S, FLAG_N);
-		}
-		break;
-	case M68K_ROXL:
-	case M68K_ROXR:
-		dst = mov_ir(dst, 0, FLAG_V, SZ_B);
-		if (inst->src.addr_mode == MODE_UNUSED) {
-			dst = cycles(dst, BUS);
-			//Memory rotate
-			dst = bt_irdisp8(dst, 0, CONTEXT, 0, SZ_B);
-			if (inst->op == M68K_ROXL) {
-				dst = rcl_ir(dst, 1, dst_op.base, inst->extra.size);
-			} else {
-				dst = rcr_ir(dst, 1, dst_op.base, inst->extra.size);
-			}
-			dst = setcc_r(dst, CC_C, FLAG_C);
-			dst = cmp_ir(dst, 0, dst_op.base, inst->extra.size);
-			dst = setcc_r(dst, CC_Z, FLAG_Z);
-			dst = setcc_r(dst, CC_S, FLAG_N);
-			dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B);
-			dst = m68k_save_result(inst, dst, opts);
-		} else {
-			if (src_op.mode == MODE_IMMED) {
-				dst = cycles(dst, (inst->extra.size == OPSIZE_LONG ? 8 : 6) + src_op.disp*2);
-				dst = bt_irdisp8(dst, 0, CONTEXT, 0, SZ_B);
-				if (dst_op.mode == MODE_REG_DIRECT) {
-					if (inst->op == M68K_ROXL) {
-						dst = rcl_ir(dst, src_op.disp, dst_op.base, inst->extra.size);
-					} else {
-						dst = rcr_ir(dst, src_op.disp, dst_op.base, inst->extra.size);
-					}
-				} else {
-					if (inst->op == M68K_ROXL) {
-						dst = rcl_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size);
-					} else {
-						dst = rcr_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size);
-					}
-				}
-				dst = setcc_r(dst, CC_C, FLAG_C);
-				dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B);
-			} else {
-				if (src_op.mode == MODE_REG_DIRECT) {
-					if (src_op.base != SCRATCH1) {
-						dst = mov_rr(dst, src_op.base, SCRATCH1, SZ_B);
-					}
-				} else {
-					dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_B);
-				}
-				dst = and_ir(dst, 63, SCRATCH1, SZ_D);
-				zero_off = dst+1;
-				dst = jcc(dst, CC_Z, dst+2);
-				dst = add_rr(dst, SCRATCH1, CYCLES, SZ_D);
-				dst = add_rr(dst, SCRATCH1, CYCLES, SZ_D);
-				dst = cmp_ir(dst, 32, SCRATCH1, SZ_B);
-				norm_off = dst+1;
-				dst = jcc(dst, CC_L, dst+2);
-				dst = bt_irdisp8(dst, 0, CONTEXT, 0, SZ_B);
-				if (dst_op.mode == MODE_REG_DIRECT) {
-					if (inst->op == M68K_ROXL) {
-						dst = rcl_ir(dst, 31, dst_op.base, inst->extra.size);
-						dst = rcl_ir(dst, 1, dst_op.base, inst->extra.size);
-					} else {
-						dst = rcr_ir(dst, 31, dst_op.base, inst->extra.size);
-						dst = rcr_ir(dst, 1, dst_op.base, inst->extra.size);
-					}
-				} else {
-					if (inst->op == M68K_ROXL) {
-						dst = rcl_irdisp8(dst, 31, dst_op.base, dst_op.disp, inst->extra.size);
-						dst = rcl_irdisp8(dst, 1, dst_op.base, dst_op.disp, inst->extra.size);
-					} else {
-						dst = rcr_irdisp8(dst, 31, dst_op.base, dst_op.disp, inst->extra.size);
-						dst = rcr_irdisp8(dst, 1, dst_op.base, dst_op.disp, inst->extra.size);
-					}
-				}
-				dst = setcc_rind(dst, CC_C, CONTEXT);
-				dst = sub_ir(dst, 32, SCRATCH1, SZ_B);
-				*norm_off = dst - (norm_off+1);
-				dst = bt_irdisp8(dst, 0, CONTEXT, 0, SZ_B);
-				if (dst_op.mode == MODE_REG_DIRECT) {
-					if (inst->op == M68K_ROXL) {
-						dst = rcl_clr(dst, dst_op.base, inst->extra.size);
-					} else {
-						dst = rcr_clr(dst, dst_op.base, inst->extra.size);
-					}
-				} else {
-					if (inst->op == M68K_ROXL) {
-						dst = rcl_clrdisp8(dst, dst_op.base, dst_op.disp, inst->extra.size);
-					} else {
-						dst = rcr_clrdisp8(dst, dst_op.base, dst_op.disp, inst->extra.size);
-					}
-				}
-				dst = setcc_r(dst, CC_C, FLAG_C);
-				dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B);
-				end_off = dst + 1;
-				dst = jmp(dst, dst+2);
-				*zero_off = dst - (zero_off+1);
-				//Carry flag is set to X flag when count is 0, this is different from ROR/ROL
-				dst = mov_rindr(dst, CONTEXT, FLAG_C, SZ_B);
-				*end_off = dst - (end_off+1);
-			}
-			if (dst_op.mode == MODE_REG_DIRECT) {
-				dst = cmp_ir(dst, 0, dst_op.base, inst->extra.size);
-			} else {
-				dst = cmp_irdisp8(dst, 0, dst_op.base, dst_op.disp, inst->extra.size);
-			}
-			dst = setcc_r(dst, CC_Z, FLAG_Z);
-			dst = setcc_r(dst, CC_S, FLAG_N);
-		}
-		break;
-	case M68K_RTE:
-		//TODO: Trap if not in system mode
-		//Read saved SR
-		dst = mov_rr(dst, opts->aregs[7], SCRATCH1, SZ_D);
-		dst = call(dst, opts->read_16);
-		dst = add_ir(dst, 2, opts->aregs[7], SZ_D);
-		dst = call(dst, (uint8_t *)set_sr);
-		//Read saved PC
-		dst = mov_rr(dst, opts->aregs[7], SCRATCH1, SZ_D);
-		dst = call(dst, opts->read_32);
-		dst = add_ir(dst, 4, opts->aregs[7], SZ_D);
-		//Check if we've switched to user mode and swap stack pointers if needed
-		dst = bt_irdisp8(dst, 5, CONTEXT, offsetof(m68k_context, status), SZ_B);
-		end_off = dst+1;
-		dst = jcc(dst, CC_C, dst+2);
-		dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D);
-		dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, opts->aregs[7], SZ_D);
-		dst = mov_rrdisp8(dst, SCRATCH2, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D);
-		*end_off = dst - (end_off+1);
-		//Get native address, sync components, recalculate integer points and jump to returned address
-		dst = call(dst, (uint8_t *)m68k_native_addr_and_sync);
-		dst = jmp_r(dst, SCRATCH1);
-		break;
-	case M68K_RTR:
-		//Read saved CCR
-		dst = mov_rr(dst, opts->aregs[7], SCRATCH1, SZ_D);
-		dst = call(dst, opts->read_16);
-		dst = add_ir(dst, 2, opts->aregs[7], SZ_D);
-		dst = call(dst, (uint8_t *)set_ccr);
-		//Read saved PC
-		dst = mov_rr(dst, opts->aregs[7], SCRATCH1, SZ_D);
-		dst = call(dst, opts->read_32);
-		dst = add_ir(dst, 4, opts->aregs[7], SZ_D);
-		//Get native address and jump to it
-		dst = call(dst, (uint8_t *)m68k_native_addr);
-		dst = jmp_r(dst, SCRATCH1);
-		break;
-	case M68K_SBCD:
-		if (src_op.base != SCRATCH2) {
-			if (src_op.mode == MODE_REG_DIRECT) {
-				dst = mov_rr(dst, src_op.base, SCRATCH2, SZ_B);
-			} else {
-				dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH2, SZ_B);
-			}
-		}
-		if (dst_op.base != SCRATCH1) {
-			if (dst_op.mode == MODE_REG_DIRECT) {
-				dst = mov_rr(dst, dst_op.base, SCRATCH1, SZ_B);
-			} else {
-				dst = mov_rdisp8r(dst, dst_op.base, dst_op.disp, SCRATCH1, SZ_B);
-			}
-		}
-		dst = bt_irdisp8(dst, 0, CONTEXT, 0, SZ_B);
-		dst = jcc(dst, CC_NC, dst+5);
-		dst = sub_ir(dst, 1, SCRATCH1, SZ_B);
-		dst = call(dst, (uint8_t *)bcd_sub);
-		dst = mov_rr(dst, CH, FLAG_C, SZ_B);
-		dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B);
-		dst = cmp_ir(dst, 0, SCRATCH1, SZ_B);
-		dst = jcc(dst, CC_Z, dst+4);
-		dst = mov_ir(dst, 0, FLAG_Z, SZ_B);
-		if (dst_op.base != SCRATCH1) {
-			if (dst_op.mode == MODE_REG_DIRECT) {
-				dst = mov_rr(dst, SCRATCH1, dst_op.base, SZ_B);
-			} else {
-				dst = mov_rrdisp8(dst, SCRATCH1, dst_op.base, dst_op.disp, SZ_B);
-			}
-		}
-		dst = m68k_save_result(inst, dst, opts);
-		break;
-	case M68K_STOP: {
-		//TODO: Trap if not in system mode
-		//manual says 4 cycles, but it has to be at least 8 since it's a 2-word instruction
-		//possibly even 12 since that's how long MOVE to SR takes
-		dst = cycles(dst, BUS*2);
-		dst = mov_ir(dst, src_op.disp & 0x1, FLAG_C, SZ_B);
-		dst = mov_ir(dst, (src_op.disp >> 1) & 0x1, FLAG_V, SZ_B);
-		dst = mov_ir(dst, (src_op.disp >> 2) & 0x1, FLAG_Z, SZ_B);
-		dst = mov_ir(dst, (src_op.disp >> 3) & 0x1, FLAG_N, SZ_B);
-		dst = mov_irind(dst, (src_op.disp >> 4) & 0x1, CONTEXT, SZ_B);
-		dst = mov_irdisp8(dst, (src_op.disp >> 8), CONTEXT, offsetof(m68k_context, status), SZ_B);
-		if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) {
-			//leave supervisor mode
-			dst = mov_rr(dst, opts->aregs[7], SCRATCH1, SZ_D);
-			dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, opts->aregs[7], SZ_D);
-			dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D);
-		}
-		uint8_t * loop_top = dst;
-		dst = call(dst, (uint8_t *)do_sync);
-    dst = cmp_rr(dst, LIMIT, CYCLES, SZ_D);
-    uint8_t * normal_cycle_up = dst + 1;
-    dst = jcc(dst, CC_A, dst+2);
-    dst = cycles(dst, BUS);
-    uint8_t * after_cycle_up = dst + 1;
-    dst = jmp(dst, dst+2);
-    *normal_cycle_up = dst - (normal_cycle_up + 1);
-		dst = mov_rr(dst, LIMIT, CYCLES, SZ_D);
-    *after_cycle_up = dst - (after_cycle_up+1);
-		dst = cmp_rdisp8r(dst, CONTEXT, offsetof(m68k_context, int_cycle), CYCLES, SZ_D);
-		dst = jcc(dst, CC_C, loop_top);
-		break;
-	}
-	case M68K_SUB:
-		size = inst->dst.addr_mode == MODE_AREG ? OPSIZE_LONG : inst->extra.size;
-		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, size);
-			} else {
-				dst = sub_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, size);
-			}
-		} else if (src_op.mode == MODE_REG_DISPLACE8) {
-			dst = sub_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, size);
-		} else {
-			if (dst_op.mode == MODE_REG_DIRECT) {
-				dst = sub_ir(dst, src_op.disp, dst_op.base, size);
-			} else {
-				dst = sub_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, size);
-			}
-		}
-		if (inst->dst.addr_mode != MODE_AREG) {
-			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 = m68k_save_result(inst, dst, opts);
-		break;
-	case M68K_SUBX:
-		dst = cycles(dst, BUS);
-		dst = bt_irdisp8(dst, 0, CONTEXT, 0, SZ_B);
-		if (src_op.mode == MODE_REG_DIRECT) {
-			if (dst_op.mode == MODE_REG_DIRECT) {
-				dst = sbb_rr(dst, src_op.base, dst_op.base, inst->extra.size);
-			} else {
-				dst = sbb_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, inst->extra.size);
-			}
-		} else if (src_op.mode == MODE_REG_DISPLACE8) {
-			dst = sbb_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, inst->extra.size);
-		} else {
-			if (dst_op.mode == MODE_REG_DIRECT) {
-				dst = sbb_ir(dst, src_op.disp, dst_op.base, inst->extra.size);
-			} else {
-				dst = sbb_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size);
-			}
-		}
-		dst = setcc_r(dst, CC_C, FLAG_C);
-		dst = jcc(dst, CC_Z, dst+4);
-		dst = mov_ir(dst, 0, FLAG_Z, SZ_B);
-		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 = m68k_save_result(inst, dst, opts);
-		break;
-	case M68K_SWAP:
-		dst = cycles(dst, BUS);
-		if (src_op.mode == MODE_REG_DIRECT) {
-			dst = rol_ir(dst, 16, src_op.base, SZ_D);
-			dst = cmp_ir(dst, 0, src_op.base, SZ_D);
-		} else{
-			dst = rol_irdisp8(dst, 16, src_op.base, src_op.disp, SZ_D);
-			dst = cmp_irdisp8(dst, 0, src_op.base, src_op.disp, SZ_D);
-		}
-
-		dst = mov_ir(dst, 0, FLAG_C, SZ_B);
-		dst = setcc_r(dst, CC_Z, FLAG_Z);
-		dst = setcc_r(dst, CC_S, FLAG_N);
-		dst = mov_ir(dst, 0, FLAG_V, SZ_B);
-		break;
-	//case M68K_TAS:
-	case M68K_TRAP:
-		dst = mov_ir(dst, src_op.disp + VECTOR_TRAP_0, SCRATCH2, SZ_D);
-		dst = mov_ir(dst, inst->address+2, SCRATCH1, SZ_D);
-		dst = jmp(dst, opts->trap);
-		break;
-	//case M68K_TRAPV:
-	case M68K_TST:
-		dst = cycles(dst, BUS);
-		if (src_op.mode == MODE_REG_DIRECT) {
-			dst = cmp_ir(dst, 0, src_op.base, inst->extra.size);
-		} else { //M68000 doesn't support immedate operand for tst, so this must be MODE_REG_DISPLACE8
-			dst = cmp_irdisp8(dst, 0, src_op.base, src_op.disp, inst->extra.size);
-		}
-		dst = mov_ir(dst, 0, FLAG_C, SZ_B);
-		dst = setcc_r(dst, CC_Z, FLAG_Z);
-		dst = setcc_r(dst, CC_S, FLAG_N);
-		dst = mov_ir(dst, 0, FLAG_V, SZ_B);
-		break;
-	case M68K_UNLK:
-		dst = cycles(dst, BUS);
-		if (dst_op.mode == MODE_REG_DIRECT) {
-			dst = mov_rr(dst, dst_op.base, opts->aregs[7], SZ_D);
-		} else {
-			dst = mov_rdisp8r(dst, dst_op.base, dst_op.disp, opts->aregs[7], SZ_D);
-		}
-		dst = mov_rr(dst, opts->aregs[7], SCRATCH1, SZ_D);
-		dst = call(dst, opts->read_32);
-		if (dst_op.mode == MODE_REG_DIRECT) {
-			dst = mov_rr(dst, SCRATCH1, dst_op.base, SZ_D);
-		} else {
-			dst = mov_rrdisp8(dst, SCRATCH1, dst_op.base, dst_op.disp, SZ_D);
-		}
-		dst = add_ir(dst, 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);
-		exit(1);
-	}
-	return dst;
-}
-
-uint8_t m68k_is_terminal(m68kinst * inst)
-{
-	return inst->op == M68K_RTS || inst->op == M68K_RTE || inst->op == M68K_RTR || inst->op == M68K_JMP
-		|| inst->op == M68K_TRAP || inst->op == M68K_ILLEGAL || inst->op == M68K_INVALID || inst->op == M68K_RESET
-		|| (inst->op == M68K_BCC && inst->extra.cond == COND_TRUE);
-}
-
-void m68k_handle_deferred(m68k_context * context)
-{
-	x86_68k_options * opts = context->options;
-	process_deferred(&opts->deferred, context, (native_addr_func)get_native_from_context);
-	if (opts->deferred) {
-		translate_m68k_stream(opts->deferred->address, context);
-	}
-}
-
-uint8_t * translate_m68k_stream(uint32_t address, m68k_context * context)
-{
-	m68kinst instbuf;
-	x86_68k_options * opts = context->options;
-	uint8_t * dst = opts->cur_code;
-	uint8_t * dst_end = opts->code_end;
-	address &= 0xFFFFFF;
-	if(get_native_address(opts->native_code_map, address)) {
-		return dst;
-	}
-	char disbuf[1024];
-	uint16_t *encoded, *next;
-	if ((address & 0xFFFFFF) < 0x400000) {
-		encoded = context->mem_pointers[0] + (address & 0xFFFFFF)/2;
-	} else if ((address & 0xFFFFFF) > 0xE00000) {
-		encoded = context->mem_pointers[1] + (address  & 0xFFFF)/2;
-	} else {
-		printf("attempt to translate non-memory address: %X\n", address);
-		exit(1);
-	}
-	do {
-		if (opts->address_log) {
-			fprintf(opts->address_log, "%X\n", address);
-		}
-		do {
-			if (dst_end-dst < MAX_NATIVE_SIZE) {
-				if (dst_end-dst < 5) {
-					puts("out of code memory, not enough space for jmp to next chunk");
-					exit(1);
-				}
-				size_t size = 1024*1024;
-				opts->cur_code = alloc_code(&size);
-				opts->code_end = opts->cur_code + size;
-				jmp(dst, opts->cur_code);
-				dst = opts->cur_code;
-				dst_end = opts->code_end;
-			}
-			if (address >= 0x400000 && address < 0xE00000) {
-				dst = xor_rr(dst, RDI, RDI, SZ_D);
-				dst = call(dst, (uint8_t *)exit);
-				break;
-			}
-			uint8_t * existing = get_native_address(opts->native_code_map, address);
-			if (existing) {
-				dst = jmp(dst, existing);
-				break;
-			}
-			next = m68k_decode(encoded, &instbuf, address);
-			if (instbuf.op == M68K_INVALID) {
-				instbuf.src.params.immed = *encoded;
-			}
-			uint16_t m68k_size = (next-encoded)*2;
-			address += m68k_size;
-			encoded = next;
-			//m68k_disasm(&instbuf, disbuf);
-			//printf("%X: %s\n", instbuf.address, disbuf);
-			uint8_t * after = translate_m68k(dst, &instbuf, opts);
-			map_native_address(context, instbuf.address, dst, m68k_size, after-dst);
-			dst = after;
-		} while(!m68k_is_terminal(&instbuf));
-		process_deferred(&opts->deferred, context, (native_addr_func)get_native_from_context);
-		if (opts->deferred) {
-			address = opts->deferred->address;
-			if ((address & 0xFFFFFF) < 0x400000) {
-				encoded = context->mem_pointers[0] + (address & 0xFFFFFF)/2;
-			} else if ((address & 0xFFFFFF) > 0xE00000) {
-				encoded = context->mem_pointers[1] + (address  & 0xFFFF)/2;
-			} else {
-				printf("attempt to translate non-memory address: %X\n", address);
-				exit(1);
-			}
-		} else {
-			encoded = NULL;
-		}
-	} while(encoded != NULL);
-	opts->cur_code = dst;
-	return dst;
-}
-
-uint8_t * get_native_address_trans(m68k_context * context, uint32_t address)
-{
-	address &= 0xFFFFFF;
-	uint8_t * ret = get_native_address(context->native_code_map, address);
-	if (!ret) {
-		translate_m68k_stream(address, context);
-		ret = get_native_address(context->native_code_map, address);
-	}
-	return ret;
-}
-
-void * m68k_retranslate_inst(uint32_t address, m68k_context * context)
-{
-	x86_68k_options * opts = context->options;
-	uint8_t orig_size = get_native_inst_size(opts, address);
-	uint8_t * orig_start = get_native_address(context->native_code_map, address);
-	uint32_t orig = address;
-	address &= 0xFFFF;
-	uint8_t * dst = opts->cur_code;
-	uint8_t * dst_end = opts->code_end;
-	uint16_t *after, *inst = context->mem_pointers[1] + address/2;
-	m68kinst instbuf;
-	after = m68k_decode(inst, &instbuf, orig);
-	if (orig_size != MAX_NATIVE_SIZE) {
-		if (dst_end - dst < 128) {
-			size_t size = 1024*1024;
-			dst = alloc_code(&size);
-			opts->code_end = dst_end = dst + size;
-			opts->cur_code = dst;
-		}
-		deferred_addr * orig_deferred = opts->deferred;
-		uint8_t * native_end = translate_m68k(dst, &instbuf, opts);
-		uint8_t is_terminal = m68k_is_terminal(&instbuf);
-		if ((native_end - dst) <= orig_size) {
-			uint8_t * native_next;
-			if (!is_terminal) {
-				native_next = get_native_address(context->native_code_map, orig + (after-inst)*2);
-			}
-			if (is_terminal || (native_next && ((native_next == orig_start + orig_size) || (orig_size - (native_end - dst)) > 5))) {
-				remove_deferred_until(&opts->deferred, orig_deferred);
-				native_end = translate_m68k(orig_start, &instbuf, opts);
-				if (!is_terminal) {
-					if (native_next == orig_start + orig_size && (native_next-native_end) < 2) {
-						while (native_end < orig_start + orig_size) {
-							*(native_end++) = 0x90; //NOP
-						}
-					} else {
-						jmp(native_end, native_next);
-					}
-				}
-				m68k_handle_deferred(context);
-				return orig_start;
-			}
-		}
-
-		map_native_address(context, instbuf.address, dst, (after-inst)*2, MAX_NATIVE_SIZE);
-		opts->cur_code = dst+MAX_NATIVE_SIZE;
-		jmp(orig_start, dst);
-		if (!m68k_is_terminal(&instbuf)) {
-			jmp(native_end, get_native_address_trans(context, orig + (after-inst)*2));
-		}
-		m68k_handle_deferred(context);
-		return dst;
-	} else {
-		dst = translate_m68k(orig_start, &instbuf, opts);
-		if (!m68k_is_terminal(&instbuf)) {
-			dst = jmp(dst, get_native_address_trans(context, orig + (after-inst)*2));
-		}
-		m68k_handle_deferred(context);
-		return orig_start;
-	}
-}
-
-m68k_context * m68k_handle_code_write(uint32_t address, m68k_context * context)
-{
-	uint32_t inst_start = get_instruction_start(context->native_code_map, address | 0xFF0000);
-	if (inst_start) {
-		uint8_t * dst = get_native_address(context->native_code_map, inst_start);
-		dst = mov_ir(dst, inst_start, SCRATCH2, SZ_D);
-		dst = jmp(dst, (uint8_t *)m68k_retrans_stub);
-	}
-	return context;
-}
-
-void insert_breakpoint(m68k_context * context, uint32_t address, uint8_t * bp_handler)
-{
-	static uint8_t * bp_stub = NULL;
-	uint8_t * native = get_native_address_trans(context, address);
-	uint8_t * start_native = native;
-	native = mov_ir(native, address, SCRATCH1, SZ_D);
-	if (!bp_stub) {
-		x86_68k_options * opts = context->options;
-		uint8_t * dst = opts->cur_code;
-		uint8_t * dst_end = opts->code_end;
-		if (dst_end - dst < 128) {
-			size_t size = 1024*1024;
-			dst = alloc_code(&size);
-			opts->code_end = dst_end = dst + size;
-		}
-		bp_stub = dst;
-		native = call(native, bp_stub);
-
-		//Calculate length of prologue
-		dst = check_cycles_int(dst, address, opts);
-		int check_int_size = dst-bp_stub;
-		dst = bp_stub;
-
-		//Save context and call breakpoint handler
-		dst = call(dst, (uint8_t *)m68k_save_context);
-		dst = push_r(dst, SCRATCH1);
-		dst = mov_rr(dst, CONTEXT, RDI, SZ_Q);
-		dst = mov_rr(dst, SCRATCH1, RSI, SZ_D);
-		dst = call(dst, bp_handler);
-		dst = mov_rr(dst, RAX, CONTEXT, SZ_Q);
-		//Restore context
-		dst = call(dst, (uint8_t *)m68k_load_context);
-		dst = pop_r(dst, SCRATCH1);
-		//do prologue stuff
-		dst = cmp_rr(dst, CYCLES, LIMIT, SZ_D);
-		uint8_t * jmp_off = dst+1;
-		dst = jcc(dst, CC_NC, dst + 7);
-		dst = call(dst, opts->handle_cycle_limit_int);
-		*jmp_off = dst - (jmp_off+1);
-		//jump back to body of translated instruction
-		dst = pop_r(dst, SCRATCH1);
-		dst = add_ir(dst, check_int_size - (native-start_native), SCRATCH1, SZ_Q);
-		dst = jmp_r(dst, SCRATCH1);
-		opts->cur_code = dst;
-	} else {
-		native = call(native, bp_stub);
-	}
-}
-
-void remove_breakpoint(m68k_context * context, uint32_t address)
-{
-	uint8_t * native = get_native_address(context->native_code_map, address);
-	check_cycles_int(native, address, context->options);
-}
-
-void start_68k_context(m68k_context * context, uint32_t address)
-{
-	uint8_t * addr = get_native_address_trans(context, address);
-	m68k_start_context(addr, context);
-}
-
-void m68k_reset(m68k_context * context)
-{
-	//TODO: Make this actually use the normal read functions
-	context->aregs[7] = context->mem_pointers[0][0] << 16 | context->mem_pointers[0][1];
-	uint32_t address = context->mem_pointers[0][2] << 16 | context->mem_pointers[0][3];
-	start_68k_context(context, address);
-}
-
-typedef enum {
-	READ_16,
-	READ_8,
-	WRITE_16,
-	WRITE_8
-} ftype;
-
-uint8_t * gen_mem_fun(x86_68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks, ftype fun_type)
-{
-	uint8_t * dst = opts->cur_code;
-	uint8_t * start = dst;
-	dst = check_cycles(dst);
-	dst = cycles(dst, BUS);
-	dst = and_ir(dst, 0xFFFFFF, SCRATCH1, SZ_D);
-	uint8_t *lb_jcc = NULL, *ub_jcc = NULL;
-	uint8_t is_write = fun_type == WRITE_16 || fun_type == WRITE_8;
-	uint8_t adr_reg = is_write ? SCRATCH2 : SCRATCH1;
-	uint16_t access_flag = is_write ? MMAP_WRITE : MMAP_READ;
-	uint8_t size =  (fun_type == READ_16 || fun_type == WRITE_16) ? SZ_W : SZ_B;
-	for (uint32_t chunk = 0; chunk < num_chunks; chunk++)
-	{
-		if (memmap[chunk].start > 0) {
-			dst = cmp_ir(dst, memmap[chunk].start, adr_reg, SZ_D);
-			lb_jcc = dst + 1;
-			dst = jcc(dst, CC_C, dst+2);
-		}
-		if (memmap[chunk].end < 0x1000000) {
-			dst = cmp_ir(dst, memmap[chunk].end, adr_reg, SZ_D);
-			ub_jcc = dst + 1;
-			dst = jcc(dst, CC_NC, dst+2);
-		}
-
-		if (memmap[chunk].mask != 0xFFFFFF) {
-			dst = and_ir(dst, memmap[chunk].mask, adr_reg, SZ_D);
-		}
-		void * cfun;
-		switch (fun_type)
-		{
-		case READ_16:
-			cfun = memmap[chunk].read_16;
-			break;
-		case READ_8:
-			cfun = memmap[chunk].read_8;
-			break;
-		case WRITE_16:
-			cfun = memmap[chunk].write_16;
-			break;
-		case WRITE_8:
-			cfun = memmap[chunk].write_8;
-			break;
-		default:
-			cfun = NULL;
-		}
-		if(memmap[chunk].buffer && memmap[chunk].flags & access_flag) {
-			if (memmap[chunk].flags & MMAP_PTR_IDX) {
-				if (memmap[chunk].flags & MMAP_FUNC_NULL) {
-					dst = cmp_irdisp8(dst, 0, CONTEXT, offsetof(m68k_context, mem_pointers) + sizeof(void*) * memmap[chunk].ptr_index, SZ_Q);
-					uint8_t * not_null = dst+1;
-					dst = jcc(dst, CC_NZ, dst+2);
-					dst = call(dst, (uint8_t *)m68k_save_context);
-					if (is_write) {
-						//SCRATCH2 is RDI, so no need to move it there
-						dst = mov_rr(dst, SCRATCH1, RDX, size);
-					} else {
-						dst = push_r(dst, CONTEXT);
-						dst = mov_rr(dst, SCRATCH1, RDI, SZ_D);
-					}
-					dst = test_ir(dst, 8, RSP, SZ_D);
-					uint8_t *adjust_rsp = dst+1;
-					dst = jcc(dst, CC_NZ, dst+2);
-					dst = call(dst, cfun);
-					uint8_t *no_adjust = dst+1;
-					dst = jmp(dst, dst+2);
-					*adjust_rsp = dst - (adjust_rsp + 1);
-					dst = sub_ir(dst, 8, RSP, SZ_Q);
-					dst = call(dst, cfun);
-					dst = add_ir(dst, 8, RSP, SZ_Q);
-					*no_adjust = dst - (no_adjust + 1);
-					if (is_write) {
-						dst = mov_rr(dst, RAX, CONTEXT, SZ_Q);
-					} else {
-						dst = pop_r(dst, CONTEXT);
-						dst = mov_rr(dst, RAX, SCRATCH1, size);
-					}
-					dst = jmp(dst, (uint8_t *)m68k_load_context);
-
-					*not_null = dst - (not_null + 1);
-				}
-				if (size == SZ_B) {
-					dst = xor_ir(dst, 1, adr_reg, SZ_D);
-				}
-				dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, mem_pointers) + sizeof(void*) * memmap[chunk].ptr_index, adr_reg, SZ_Q);
-				if (is_write) {
-					dst = mov_rrind(dst, SCRATCH1, SCRATCH2, size);
-
-				} else {
-					dst = mov_rindr(dst, SCRATCH1, SCRATCH1, size);
-				}
-			} else {
-				uint8_t tmp_size = size;
-				if (size == SZ_B) {
-					if ((memmap[chunk].flags & MMAP_ONLY_ODD) || (memmap[chunk].flags & MMAP_ONLY_EVEN)) {
-						dst = bt_ir(dst, 0, adr_reg, SZ_D);
-						uint8_t * good_addr = dst + 1;
-						dst = jcc(dst, (memmap[chunk].flags & MMAP_ONLY_ODD) ? CC_C : CC_NC, dst+2);
-						if (!is_write) {
-							dst = mov_ir(dst, 0xFF, SCRATCH1, SZ_B);
-						}
-						dst = retn(dst);
-						*good_addr = dst - (good_addr + 1);
-						dst = shr_ir(dst, 1, adr_reg, SZ_D);
-					} else {
-						dst = xor_ir(dst, 1, adr_reg, SZ_D);
-					}
-				} else if ((memmap[chunk].flags & MMAP_ONLY_ODD) || (memmap[chunk].flags & MMAP_ONLY_EVEN)) {
-					tmp_size = SZ_B;
-					dst = shr_ir(dst, 1, adr_reg, SZ_D);
-					if ((memmap[chunk].flags & MMAP_ONLY_EVEN) && is_write) {
-						dst = shr_ir(dst, 8, SCRATCH1, SZ_W);
-					}
-				}
-				if ((int64_t)memmap[chunk].buffer <= 0x7FFFFFFF && (int64_t)memmap[chunk].buffer >= -2147483648) {
-					if (is_write) {
-						dst = mov_rrdisp32(dst, SCRATCH1, SCRATCH2, (int64_t)memmap[chunk].buffer, tmp_size);
-					} else {
-						dst = mov_rdisp32r(dst, SCRATCH1, (int64_t)memmap[chunk].buffer, SCRATCH1, tmp_size);
-					}
-				} else {
-					if (is_write) {
-						dst = push_r(dst, SCRATCH1);
-						dst = mov_ir(dst, (int64_t)memmap[chunk].buffer, SCRATCH1, SZ_Q);
-						dst = add_rr(dst, SCRATCH1, SCRATCH2, SZ_Q);
-						dst = pop_r(dst, SCRATCH1);
-						dst = mov_rrind(dst, SCRATCH1, SCRATCH2, tmp_size);
-					} else {
-						dst = mov_ir(dst, (int64_t)memmap[chunk].buffer, SCRATCH2, SZ_Q);
-						dst = mov_rindexr(dst, SCRATCH2, SCRATCH1, 1, SCRATCH1, tmp_size);
-					}
-				}
-				if (size != tmp_size && !is_write) {
-					if (memmap[chunk].flags & MMAP_ONLY_EVEN) {
-						dst = shl_ir(dst, 8, SCRATCH1, SZ_W);
-						dst = mov_ir(dst, 0xFF, SCRATCH1, SZ_B);
-					} else {
-						dst = or_ir(dst, 0xFF00, SCRATCH1, SZ_W);
-					}
-				}
-			}
-			if (is_write && (memmap[chunk].flags & MMAP_CODE)) {
-				dst = mov_rr(dst, SCRATCH2, SCRATCH1, SZ_D);
-				dst = shr_ir(dst, 11, SCRATCH1, SZ_D);
-				dst = bt_rrdisp32(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, ram_code_flags), SZ_D);
-				uint8_t * not_code = dst+1;
-				dst = jcc(dst, CC_NC, dst+2);
-				dst = call(dst, (uint8_t *)m68k_save_context);
-				dst = call(dst, (uint8_t *)m68k_handle_code_write);
-				dst = mov_rr(dst, RAX, CONTEXT, SZ_Q);
-				dst = call(dst, (uint8_t *)m68k_load_context);
-				*not_code = dst - (not_code+1);
-			}
-			dst = retn(dst);
-		} else if (cfun) {
-			dst = call(dst, (uint8_t *)m68k_save_context);
-			if (is_write) {
-				//SCRATCH2 is RDI, so no need to move it there
-				dst = mov_rr(dst, SCRATCH1, RDX, size);
-			} else {
-				dst = push_r(dst, CONTEXT);
-				dst = mov_rr(dst, SCRATCH1, RDI, SZ_D);
-			}
-			dst = test_ir(dst, 8, RSP, SZ_D);
-			uint8_t *adjust_rsp = dst+1;
-			dst = jcc(dst, CC_NZ, dst+2);
-			dst = call(dst, cfun);
-			uint8_t *no_adjust = dst+1;
-			dst = jmp(dst, dst+2);
-			*adjust_rsp = dst - (adjust_rsp + 1);
-			dst = sub_ir(dst, 8, RSP, SZ_Q);
-			dst = call(dst, cfun);
-			dst = add_ir(dst, 8, RSP, SZ_Q);
-			*no_adjust = dst - (no_adjust+1);
-			if (is_write) {
-				dst = mov_rr(dst, RAX, CONTEXT, SZ_Q);
-			} else {
-				dst = pop_r(dst, CONTEXT);
-				dst = mov_rr(dst, RAX, SCRATCH1, size);
-			}
-			dst = jmp(dst, (uint8_t *)m68k_load_context);
-		} else {
-			//Not sure the best course of action here
-			if (!is_write) {
-				dst = mov_ir(dst, size == SZ_B ? 0xFF : 0xFFFF, SCRATCH1, size);
-			}
-			dst = retn(dst);
-		}
-		if (lb_jcc) {
-			*lb_jcc = dst - (lb_jcc+1);
-			lb_jcc = NULL;
-		}
-		if (ub_jcc) {
-			*ub_jcc = dst - (ub_jcc+1);
-			ub_jcc = NULL;
-		}
-	}
-	if (!is_write) {
-		dst = mov_ir(dst, size == SZ_B ? 0xFF : 0xFFFF, SCRATCH1, size);
-	}
-	dst = retn(dst);
-	opts->cur_code = dst;
-	return start;
-}
-
-void init_x86_68k_opts(x86_68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks)
-{
-	memset(opts, 0, sizeof(*opts));
-	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->dregs[3] = R8;
-	opts->aregs[0] = R13;
-	opts->aregs[1] = R14;
-	opts->aregs[2] = R9;
-	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;
-	size_t size = 1024 * 1024;
-	opts->cur_code = alloc_code(&size);
-	opts->code_end = opts->cur_code + size;
-	opts->ram_inst_sizes = malloc(sizeof(uint8_t *) * 64);
-	memset(opts->ram_inst_sizes, 0, sizeof(uint8_t *) * 64);
-
-	opts->read_16 = gen_mem_fun(opts, memmap, num_chunks, READ_16);
-	opts->read_8 = gen_mem_fun(opts, memmap, num_chunks, READ_8);
-	opts->write_16 = gen_mem_fun(opts, memmap, num_chunks, WRITE_16);
-	opts->write_8 = gen_mem_fun(opts, memmap, num_chunks, WRITE_8);
-
-	uint8_t * dst = opts->cur_code;
-
-	opts->read_32 = dst;
-	dst = push_r(dst, SCRATCH1);
-	dst = call(dst, opts->read_16);
-	dst = mov_rr(dst, SCRATCH1, SCRATCH2, SZ_W);
-	dst = pop_r(dst, SCRATCH1);
-	dst = push_r(dst, SCRATCH2);
-	dst = add_ir(dst, 2, SCRATCH1, SZ_D);
-	dst = call(dst, opts->read_16);
-	dst = pop_r(dst, SCRATCH2);
-	dst = movzx_rr(dst, SCRATCH1, SCRATCH1, SZ_W, SZ_D);
-	dst = shl_ir(dst, 16, SCRATCH2, SZ_D);
-	dst = or_rr(dst, SCRATCH2, SCRATCH1, SZ_D);
-	dst = retn(dst);
-
-	opts->write_32_lowfirst = dst;
-	dst = push_r(dst, SCRATCH2);
-	dst = push_r(dst, SCRATCH1);
-	dst = add_ir(dst, 2, SCRATCH2, SZ_D);
-	dst = call(dst, opts->write_16);
-	dst = pop_r(dst, SCRATCH1);
-	dst = pop_r(dst, SCRATCH2);
-	dst = shr_ir(dst, 16, SCRATCH1, SZ_D);
-	dst = jmp(dst, opts->write_16);
-
-	opts->write_32_highfirst = dst;
-	dst = push_r(dst, SCRATCH1);
-	dst = push_r(dst, SCRATCH2);
-	dst = shr_ir(dst, 16, SCRATCH1, SZ_D);
-	dst = call(dst, opts->write_16);
-	dst = pop_r(dst, SCRATCH2);
-	dst = pop_r(dst, SCRATCH1);
-	dst = add_ir(dst, 2, SCRATCH2, SZ_D);
-	dst = jmp(dst, opts->write_16);
-
-	opts->handle_cycle_limit_int = dst;
-	dst = cmp_rdisp8r(dst, CONTEXT, offsetof(m68k_context, int_cycle), CYCLES, SZ_D);
-	uint8_t * do_int = dst+1;
-	dst = jcc(dst, CC_NC, dst+2);
-	dst = cmp_rdisp8r(dst, CONTEXT, offsetof(m68k_context, sync_cycle), CYCLES, SZ_D);
-	uint8_t * skip_sync = dst+1;
-	dst = jcc(dst, CC_C, dst+2);
-	dst = call(dst, (uint8_t *)m68k_save_context);
-	dst = mov_rr(dst, CONTEXT, RDI, SZ_Q);
-	dst = mov_rr(dst, SCRATCH1, RSI, SZ_D);
-	dst = test_ir(dst, 8, RSP, SZ_D);
-	uint8_t *adjust_rsp = dst+1;
-	dst = jcc(dst, CC_NZ, dst+2);
-	dst = call(dst, (uint8_t *)sync_components);
-	uint8_t *no_adjust = dst+1;
-	dst = jmp(dst, dst+2);
-	*adjust_rsp = dst - (adjust_rsp + 1);
-	dst = sub_ir(dst, 8, RSP, SZ_Q);
-	dst = call(dst, (uint8_t *)sync_components);
-	dst = add_ir(dst, 8, RSP, SZ_Q);
-	*no_adjust = dst - (no_adjust+1);
-	dst = mov_rr(dst, RAX, CONTEXT, SZ_Q);
-	dst = jmp(dst, (uint8_t *)m68k_load_context);
-	*skip_sync = dst - (skip_sync+1);
-	dst = retn(dst);
-	*do_int = dst - (do_int+1);
-	//set target cycle to sync cycle
-	dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, sync_cycle), LIMIT, SZ_D);
-	//swap USP and SSP if not already in supervisor mode
-	dst = bt_irdisp8(dst, 5, CONTEXT, offsetof(m68k_context, status), SZ_B);
-	uint8_t *already_supervisor = dst+1;
-	dst = jcc(dst, CC_C, dst+2);
-	dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SCRATCH2, SZ_D);
-	dst = mov_rrdisp8(dst, opts->aregs[7], CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D);
-	dst = mov_rr(dst, SCRATCH2, opts->aregs[7], SZ_D);
-	*already_supervisor = dst - (already_supervisor+1);
-	//save PC
-	dst = sub_ir(dst, 4, opts->aregs[7], SZ_D);
-	dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D);
-	dst = call(dst, opts->write_32_lowfirst);
-	//save status register
-	dst = sub_ir(dst, 2, opts->aregs[7], SZ_D);
-	dst = call(dst, (uint8_t *)get_sr);
-	dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D);
-	dst = call(dst, opts->write_16);
-	//update status register
-	dst = and_irdisp8(dst, 0xF8, CONTEXT, offsetof(m68k_context, status), SZ_B);
-	dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, int_num), SCRATCH1, SZ_B);
-	dst = or_ir(dst, 0x20, SCRATCH1, SZ_B);
-	dst = or_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, status), SZ_B);
-	//calculate interrupt vector address
-	dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, int_num), SCRATCH1, SZ_D);
-	dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, int_ack), SZ_W);
-	dst = shl_ir(dst, 2, SCRATCH1, SZ_D);
-	dst = add_ir(dst, 0x60, SCRATCH1, SZ_D);
-	dst = call(dst, opts->read_32);
-	dst = call(dst, (uint8_t *)m68k_native_addr_and_sync);
-	dst = cycles(dst, 24);
-	//discard function return address
-	dst = pop_r(dst, SCRATCH2);
-	dst = jmp_r(dst, SCRATCH1);
-
-	opts->trap = dst;
-	dst = push_r(dst, SCRATCH2);
-	//swap USP and SSP if not already in supervisor mode
-	dst = bt_irdisp8(dst, 5, CONTEXT, offsetof(m68k_context, status), SZ_B);
-	already_supervisor = dst+1;
-	dst = jcc(dst, CC_C, dst+2);
-	dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SCRATCH2, SZ_D);
-	dst = mov_rrdisp8(dst, opts->aregs[7], CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D);
-	dst = mov_rr(dst, SCRATCH2, opts->aregs[7], SZ_D);
-	*already_supervisor = dst - (already_supervisor+1);
-	//save PC
-	dst = sub_ir(dst, 4, opts->aregs[7], SZ_D);
-	dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D);
-	dst = call(dst, opts->write_32_lowfirst);
-	//save status register
-	dst = sub_ir(dst, 2, opts->aregs[7], SZ_D);
-	dst = call(dst, (uint8_t *)get_sr);
-	dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D);
-	dst = call(dst, opts->write_16);
-	//set supervisor bit
-	dst = or_irdisp8(dst, 0x20, CONTEXT, offsetof(m68k_context, status), SZ_B);
-	//calculate vector address
-	dst = pop_r(dst, SCRATCH1);
-	dst = shl_ir(dst, 2, SCRATCH1, SZ_D);
-	dst = call(dst, opts->read_32);
-	dst = call(dst, (uint8_t *)m68k_native_addr_and_sync);
-	dst = cycles(dst, 18);
-	dst = jmp_r(dst, SCRATCH1);
-
-	opts->cur_code = dst;
-}
-
-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_to_x86.h	Tue Dec 16 01:10:54 2014 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-/*
- Copyright 2013 Michael Pavone
- This file is part of BlastEm. 
- BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
-*/
-#ifndef M68K_TO_X86_H_
-#define M68K_TO_X86_H_
-#include <stdint.h>
-#include <stdio.h>
-#include "x86_backend.h"
-//#include "68kinst.h"
-struct m68kinst;
-
-#define NUM_MEM_AREAS 4
-#define NATIVE_MAP_CHUNKS (64*1024)
-#define NATIVE_CHUNK_SIZE ((16 * 1024 * 1024 / NATIVE_MAP_CHUNKS)/2)
-#define MAX_NATIVE_SIZE 255
-
-#define OPT_NATIVE_CALL_STACK 0x1
-
-typedef struct {
-	uint32_t        flags;
-	int8_t          dregs[8];
-	int8_t          aregs[8];
-	native_map_slot *native_code_map;
-	deferred_addr   *deferred;
-	uint8_t         *cur_code;
-	uint8_t         *code_end;
-	uint8_t         **ram_inst_sizes;
-	FILE            *address_log;
-	uint8_t         *read_16;
-	uint8_t         *write_16;
-	uint8_t         *read_8;
-	uint8_t         *write_8;
-	uint8_t         *read_32;
-	uint8_t         *write_32_lowfirst;
-	uint8_t         *write_32_highfirst;
-	uint8_t         *handle_cycle_limit_int;
-	uint8_t         *trap;
-} x86_68k_options;
-
-typedef struct {
-	uint8_t         flags[5];
-	uint8_t         status;
-	uint16_t        int_ack;
-	uint32_t        dregs[8];
-	uint32_t        aregs[9];
-	uint32_t		target_cycle; //cycle at which the next synchronization or interrupt occurs
-	uint32_t		current_cycle;
-	uint32_t        sync_cycle;
-	uint32_t        int_cycle;
-	uint32_t        int_num;
-	uint16_t        *mem_pointers[NUM_MEM_AREAS];
-	void            *video_context;
-	uint16_t        reserved;
-	
-	native_map_slot *native_code_map;
-	void            *options;
-	uint8_t         ram_code_flags[32/8];
-	void            *system;
-} m68k_context;
-
-uint8_t * translate_m68k(uint8_t * dst, struct m68kinst * inst, x86_68k_options * opts);
-uint8_t * translate_m68k_stream(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, memmap_chunk * memmap, uint32_t num_chunks);
-void init_68k_context(m68k_context * context, native_map_slot * native_code_map, void * opts);
-void m68k_reset(m68k_context * context);
-void insert_breakpoint(m68k_context * context, uint32_t address, uint8_t * bp_handler);
-void remove_breakpoint(m68k_context * context, uint32_t address);
-m68k_context * m68k_handle_code_write(uint32_t address, m68k_context * context);
-
-#endif //M68K_TO_X86_H_
-
--- a/runtime.S	Tue Dec 16 01:10:54 2014 -0800
+++ b/runtime.S	Tue Dec 30 19:11:34 2014 -0800
@@ -1,57 +1,4 @@
 
-	.global handle_cycle_limit
-	.global do_sync
-handle_cycle_limit:
-	cmp 84(%rsi), %eax
-	jb skip_sync
-do_sync:
-	push %rcx
-	push %rdi
-	call m68k_save_context
-	mov %rsi, %rdi
-	xor %esi, %esi
-	test $8, %esp
-	jnz adjust_rsp
-	call sync_components
-	jmp done_adjust
-adjust_rsp:
-	sub $8, %rsp
-	call sync_components
-	add $8, %rsp
-done_adjust:
-	mov %rax, %rsi
-	call m68k_load_context
-	pop %rdi
-	pop %rcx
-skip_sync:
-	ret
-
-sr_msg_int:
-	.asciz "SR set to $%X due to interrupt\n"
-debug_print_sr_int:
-	call m68k_save_context
-	push %rsi
-	lea sr_msg_int(%rip), %rdi
-	movzxb 5(%rsi), %rsi
-	xor %rax, %rax
-	call printf
-	pop %rsi
-	call m68k_load_context
-	ret
-
-sr_msg:
-	.asciz "SR set to $%X\n"
-	.global debug_print_sr
-debug_print_sr:
-	call m68k_save_context
-	push %rsi
-	lea sr_msg(%rip), %rdi
-	movzxb 5(%rsi), %rsi
-	xor %rax, %rax
-	call printf
-	pop %rsi
-	call m68k_load_context
-	ret
 
 invalid_msg:
 	.asciz "Invalid instruction at %X\n"
@@ -65,221 +12,5 @@
 	mov $1, %rdi
 	call exit
 
-	.global bcd_add
-bcd_add:
-	xchg %rax, %rdi
-
-	mov %cl, %ch
-	mov %al, %ah
-	and $0xF, %ch
-	and $0xF, %ah
-	and $0xF0, %cl
-	and $0xF0, %al
-	add %ah, %ch
-	cmp $10, %ch
-	jb no_adjust
-	add $6, %ch
-no_adjust:
-	add %ch, %al
-	add %al, %cl
-	mov $0, %ch
-	jc def_adjust
-	cmp $0xA0, %cl
-	jb no_adjust_h
-def_adjust:
-	add $0x60, %cl
-	mov $1, %ch
-no_adjust_h:
-
-	mov %rdi, %rax
-	ret
-
-	.global bcd_sub
-bcd_sub:
-	xchg %rax, %rdi
-
-	mov %cl, %ch
-	mov %al, %ah
-	and $0xF, %ch
-	and $0xF, %ah
-	and $0xF0, %cl
-	and $0xF0, %al
-	sub %ah, %ch
-	cmp $10, %ch
-	jb no_adjusts
-	sub $6, %ch
-no_adjusts:
-	add %ch, %cl
-	sub %al, %cl
-	mov $0, %ch
-	jc def_adjusts
-	cmp $0xA0, %cl
-	jb no_adjust_hs
-def_adjusts:
-	sub $0x60, %cl
-	mov $1, %ch
-no_adjust_hs:
-
-	mov %rdi, %rax
-	ret
-
-	.global get_sr
-get_sr:
-	mov 5(%rsi), %cl
-	shl $8, %cx
-	mov (%rsi), %cl
-	shl $1, %cl
-	or %bl, %cl
-	shl $1, %cl
-	or %dl, %cl
-	shl $1, %cl
-	or %bh, %cl
-	shl $1, %cl
-	or %dh, %cl
-	ret
-
-	.global set_sr
-set_sr:
-	mov %cl, %dh
-	and $1, %dh
-	shr $1, %cl
-	mov %cl, %bh
-	and $1, %bh
-	shr $1, %cl
-	mov %cl, %dl
-	and $1, %dl
-	shr $1, %cl
-	mov %cl, %bl
-	and $1, %bl
-	shr $1, %cl
-	and $1, %cl
-	mov %cl, (%rsi)
-	shr $8, %cx
-	mov %cl, 5(%rsi)
-	/* call debug_print_sr */
-	ret
 
-	.global set_ccr
-set_ccr:
-	mov %cl, %dh
-	and $1, %dh
-	shr $1, %cl
-	mov %cl, %bh
-	and $1, %bh
-	shr $1, %cl
-	mov %cl, %dl
-	and $1, %dl
-	shr $1, %cl
-	mov %cl, %bl
-	and $1, %bl
-	shr $1, %cl
-	and $1, %cl
-	mov %cl, (%rsi)
-	ret
 
-	.global m68k_modified_ret_addr
-m68k_modified_ret_addr:
-	add $16, %rsp
-	call m68k_native_addr
-	jmp *%rcx
-
-	.global m68k_native_addr_and_sync
-m68k_native_addr_and_sync:
-	call m68k_save_context
-	push %rcx
-	mov %rsi, %rdi
-	xor %esi, %esi
-	test $8, %rsp
-	jnz adjust_rsp_na
-	call sync_components
-	jmp no_adjust_rsp_na
-adjust_rsp_na:
-	sub $8, %rsp
-	call sync_components
-	add $8, %rsp
-no_adjust_rsp_na:
-	pop %rsi
-	push %rax
-	mov %rax, %rdi
-	call get_native_address_trans
-	mov %rax, %rcx
-	pop %rsi
-	call m68k_load_context
-	ret
-
-	.global m68k_native_addr
-m68k_native_addr:
-	call m68k_save_context
-	push %rsi
-	mov %rsi, %rdi
-	mov %ecx, %esi
-	call get_native_address_trans
-	mov %rax, %rcx
-	pop %rsi
-	call m68k_load_context
-	ret
-
-	.global m68k_retrans_stub
-m68k_retrans_stub:
-	call m68k_save_context
-	push %rsi
-	call m68k_retranslate_inst
-	pop %rsi
-	mov %rax, %rcx
-	call m68k_load_context
-	jmp *%rcx
-
-	.global m68k_save_context
-m68k_save_context:
-	mov %bl, 1(%rsi) /* N Flag */
-	mov %dl, 2(%rsi) /* Z flag */
-	mov %bh, 3(%rsi) /* V flag */
-	mov %dh, 4(%rsi) /* C flag */
-	mov %r10d, 8(%rsi) /* d0 */
-	mov %r11d, 12(%rsi) /* d1 */
-	mov %r12d, 16(%rsi) /* d2 */
-	mov %r8d,  20(%rsi) /* d3 */
-	mov %r13d, 40(%rsi) /* a0 */
-	mov %r14d, 44(%rsi) /* a1 */
-	mov %r9d,  48(%rsi) /* a2 */
-	mov %r15d, 68(%rsi) /* a7 */
-	mov %eax, 80(%rsi) /* current cycle count */
-	ret
-
-	.global m68k_load_context
-m68k_load_context:
-	mov 1(%rsi), %bl /* N Flag */
-	mov 2(%rsi), %dl /* Z flag */
-	mov 3(%rsi), %bh /* V flag */
-	mov 4(%rsi), %dh /* C flag */
-	mov 8(%rsi), %r10d /* d0 */
-	mov 12(%rsi), %r11d /* d1 */
-	mov 16(%rsi), %r12d /* d2 */
-	mov 20(%rsi), %r8d  /* d3 */
-	mov 40(%rsi), %r13d /* a0 */
-	mov 44(%rsi), %r14d /* a1 */
-	mov 48(%rsi), %r9d  /* a2 */
-	mov 68(%rsi), %r15d /* a7 */
-	mov 76(%rsi), %ebp /* target cycle count */
-	mov 80(%rsi), %eax /* current cycle count */
-	ret
-
-	.global m68k_start_context
-m68k_start_context:
-	push %rbp
-	push %r12
-	push %r13
-	push %r14
-	push %r15
-
-	call m68k_load_context
-	call *%rdi
-	call m68k_save_context
-
-	pop %r15
-	pop %r14
-	pop %r13
-	pop %r12
-	pop %rbp
-
-	ret
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/runtime_32.S	Tue Dec 30 19:11:34 2014 -0800
@@ -0,0 +1,17 @@
+
+
+invalid_msg:
+	.asciz "Invalid instruction at %X\n"
+
+	.global m68k_invalid
+m68k_invalid:
+	push %ecx
+	push invalid_msg
+	xor %eax, %eax
+	call printf
+	push $1
+	call exit
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test_arm.c	Tue Dec 30 19:11:34 2014 -0800
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include "gen_arm.h"
+
+typedef int32_t (*fib_fun)(int32_t);
+
+int main(int arc, char **argv)
+{
+	code_info code;
+	init_code_info(&code);
+	uint32_t *fib = code.cur;
+	subi(&code, r0, r0, 2, SET_COND);
+	movi_cc(&code, r0, 1, NO_COND, CC_LT);
+	bx_cc(&code, lr, CC_LT);
+	pushm(&code, LR | R4);
+	mov(&code, r4, r0, NO_COND);
+	bl(&code, fib);
+	mov(&code, r1, r0, NO_COND);
+	addi(&code, r0, r4, 1, NO_COND);
+	mov(&code, r4, r1, NO_COND);
+	bl(&code, fib);
+	add(&code, r0, r4, r0, NO_COND);
+	popm(&code, LR | R4);
+	bx(&code, lr);
+
+	fib_fun fibc = (fib_fun)fib;
+	printf("fib(10): %d\n", fibc(10));
+
+	return 0;
+}
--- a/test_x86.c	Tue Dec 16 01:10:54 2014 -0800
+++ b/test_x86.c	Tue Dec 30 19:11:34 2014 -0800
@@ -1,10 +1,10 @@
 /*
  Copyright 2013 Michael Pavone
- This file is part of BlastEm. 
+ This file is part of BlastEm.
  BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
 */
 #include "gen_x86.h"
-#include "m68k_to_x86.h"
+#include "m68k_core.h"
 #include <stdio.h>
 #include <stddef.h>
 
--- a/testcases.txt	Tue Dec 16 01:10:54 2014 -0800
+++ b/testcases.txt	Tue Dec 30 19:11:34 2014 -0800
@@ -1,87 +1,88 @@
 Name	Sizes	Src Modes														Dst Modes
-#add		bwl		d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	d
-#add		bwl		d																(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#adda	wl		d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	a
-#addi	bwl		#n																d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#addq	bwl		#(1-8)															d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#addx	bwl		d																d
-#addx	bwl		-(a)															-(a)
-#and		bwl		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	d
-#and		bwl		d																(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#andi	bwl		#n																d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#asl		bwl		d;#(1-8)														d
-#asr		bwl		d;#(1-8)														d
-#lsl		bwl		d;#(1-8)														d
-#lsr		bwl		d;#(1-8)														d
-#sub		bwl		d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	d
-#sub		bwl		d																(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#suba	wl		d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	a
-#subi	bwl		#n																d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#subq	bwl		#(1-8)															d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#subx	bwl		d																d
-#subx	bwl		-(a)															-(a)
-#bchg	b		d;#(0-255)														(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#bchg	l		d;#(0-255)														d
-#bset	b		d;#(0-255)														(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#bset	l		d;#(0-255)														d
-#bclr	b		d;#(0-255)														(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#bclr	l		d;#(0-255)														d
-#btst	b		d;#(0-255)														(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#btst	l		d;#(0-255)														d
-#rol		bwl		d;#(1-8)														d
-#ror		bwl		d;#(1-8)														d
-#abcd	b		d																d
-#abcd	b		-(a)															-(a)
-#sbcd	b		d																d
-#sbcd	b		-(a)															-(a)
-#muls	w		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	d
-#mulu	w		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	d
-#move	bwl		d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#movea	wl		d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	a
-#moveq	l		#(-128-127)														d
-#roxl	bwl		d;#(1-8)														d
-#roxr	bwl		d;#(1-8)														d
-#divs	w		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	d
-#divu	w		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	d
-#chk		w		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	d
-#cmp		bwl		d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	d
-#cmpa	wl		d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	a
-#cmpi	bwl		#n																d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#cmpm	bwl		(a)+															(a)+
-#eor		bwl		d																d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#eori	bwl		#n																d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#exg		l		d																d;a
-#exg		l		a																a
-#link	w		a																#n
-#or		bwl		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	d
-#or		bwl		d																(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#ori		bwl		#n																d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#clr		bwl		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#ext		wl		d
-#neg		bwl		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#negx	bwl		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#not		bwl		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#pea		l		(a);(n,a);(n,a,x);(n).w;(n).l;(n,pc);(n,pc,x)
-#rol		w		(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#ror		w		(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#roxl	w		(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#roxr	w		(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#st		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#sf		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#shi		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#sls		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#scc		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#scs		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#sne		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#seq		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#svc		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#svs		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#spl		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#smi		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#sge		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#slt		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#sgt		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#sle		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
-#swap	w		d
+add		bwl		d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	d
+add		bwl		d																(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+adda	wl		d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	a
+addi	bwl		#n																d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+addq	bwl		#(1-8)															d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+addx	bwl		d																d
+addx	bwl		-(a)															-(a)
+and		bwl		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	d
+and		bwl		d																(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+andi	bwl		#n																d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+asl		bwl		d;#(1-8)														d
+asr		bwl		d;#(1-8)														d
+lsl		bwl		d;#(1-8)														d
+lsr		bwl		d;#(1-8)														d
+sub		bwl		d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	d
+sub		bwl		d																(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+suba	wl		d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	a
+subi	bwl		#n																d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+subq	bwl		#(1-8)															d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+subx	bwl		d																d
+subx	bwl		-(a)															-(a)
+bchg	b		d;#(0-255)														(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+bchg	l		d;#(0-255)														d
+bset	b		d;#(0-255)														(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+bset	l		d;#(0-255)														d
+bclr	b		d;#(0-255)														(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+bclr	l		d;#(0-255)														d
+btst	b		d;#(0-255)														(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+btst	l		d;#(0-255)														d
+rol		bwl		d;#(1-8)														d
+ror		bwl		d;#(1-8)														d
+abcd	b		d																d
+abcd	b		-(a)															-(a)
+sbcd	b		d																d
+sbcd	b		-(a)															-(a)
+muls	w		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	d
+mulu	w		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	d
+move	bwl		d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+movea	wl		d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	a
+moveq	l		#(-128-127)														d
+roxl	bwl		d;#(1-8)														d
+roxr	bwl		d;#(1-8)														d
+divs	w		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	d
+divu	w		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	d
+chk		w		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	d
+cmp		bwl		d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	d
+cmpa	wl		d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	a
+cmpi	bwl		#n																d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+cmpm	bwl		(a)+															(a)+
+eor		bwl		d																d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+eori	bwl		#n																d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+exg		l		d																d;a
+exg		l		a																a
+link	w		a																#n
+or		bwl		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x)	d
+or		bwl		d																(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+ori		bwl		#n																d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+clr		bwl		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+ext		wl		d
+neg		bwl		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+negx	bwl		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+not		bwl		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+pea		l		(a);(n,a);(n,a,x);(n).w;(n).l;(n,pc);(n,pc,x)
+rol		w		(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+ror		w		(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+roxl	w		(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+roxr	w		(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+st		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+sf		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+shi		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+sls		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+scc		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+scs		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+sne		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+seq		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+svc		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+svs		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+spl		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+smi		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+sge		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+slt		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+sgt		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+sle		b		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+swap	w		d
 tst		bwl		d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
+lea		l		(a);(n,a);(n,a,x);(n).w;(n).l;(n,pc);(n,pc,x)					a
 
--- a/trans.c	Tue Dec 16 01:10:54 2014 -0800
+++ b/trans.c	Tue Dec 30 19:11:34 2014 -0800
@@ -1,10 +1,10 @@
 /*
  Copyright 2013 Michael Pavone
- This file is part of BlastEm. 
+ This file is part of BlastEm.
  BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
 */
 #include "68kinst.h"
-#include "m68k_to_x86.h"
+#include "m68k_core.h"
 #include "mem.h"
 #include <stdio.h>
 #include <stdlib.h>
@@ -24,14 +24,15 @@
 	unsigned short *filebuf;
 	char disbuf[1024];
 	unsigned short * cur;
-	x86_68k_options opts;
+	m68k_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 > 0x400000 ? filesize : 0x400000);
-	fread(filebuf, 2, filesize/2, f);
+	filebuf = malloc(0x400000);
+	memset(filebuf, 0, 0x400000);
+	fread(filebuf, 2, filesize/2 > 0x200000 ? 0x200000 : filesize/2, f);
 	fclose(f);
 	for(cur = filebuf; cur - filebuf < (filesize/2); ++cur)
 	{
@@ -43,14 +44,15 @@
 	memmap[0].mask = 0xFFFFFF;
 	memmap[0].flags = MMAP_READ;
 	memmap[0].buffer = filebuf;
-	
+
 	memmap[1].start = 0xE00000;
 	memmap[1].end = 0x1000000;
 	memmap[1].mask = 0xFFFF;
 	memmap[1].flags = MMAP_READ | MMAP_WRITE | MMAP_CODE;
 	memmap[1].buffer = malloc(64 * 1024);
-	init_x86_68k_opts(&opts, memmap, 2);
-	init_68k_context(&context, opts.native_code_map, &opts);
+	memset(memmap[1].buffer, 0, 64 * 1024);
+	init_m68k_opts(&opts, memmap, 2);
+	init_68k_context(&context, opts.gen.native_code_map, &opts);
 	context.mem_pointers[0] = memmap[0].buffer;
 	context.mem_pointers[1] = memmap[1].buffer;
 	context.target_cycle = context.sync_cycle = 0x80000000;
--- a/util.c	Tue Dec 16 01:10:54 2014 -0800
+++ b/util.c	Tue Dec 30 19:11:34 2014 -0800
@@ -94,7 +94,8 @@
 			free(linktext);
 			linktext = NULL;
 		}
-	} while (linksize > cursize);
+	} while ((linksize+1) > cursize);
+	linktext[linksize] = 0;
 	return linktext;
 }
 
--- a/vgmplay.c	Tue Dec 16 01:10:54 2014 -0800
+++ b/vgmplay.c	Tue Dec 30 19:11:34 2014 -0800
@@ -101,7 +101,7 @@
 {
 }
 
-uint8_t headless = 0;
+int headless = 0;
 
 #define CYCLE_LIMIT MCLKS_NTSC/60
 #define MAX_SOUND_CYCLES 100000
--- a/x86_backend.c	Tue Dec 16 01:10:54 2014 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- Copyright 2013 Michael Pavone
- This file is part of BlastEm. 
- BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
-*/
-#include "x86_backend.h"
-#include <stdlib.h>
-
-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 remove_deferred_until(deferred_addr **head_ptr, deferred_addr * remove_to)
-{
-	for(deferred_addr *cur = *head_ptr; cur && cur != remove_to; cur = *head_ptr)
-	{
-		*head_ptr = cur->next;
-		free(cur);
-	}
-}
-
-void process_deferred(deferred_addr ** head_ptr, void * context, native_addr_func get_native)
-{
-	deferred_addr * cur = *head_ptr;
-	deferred_addr **last_next = head_ptr;
-	while(cur)
-	{
-		uint8_t * native = get_native(context, cur->address);//get_native_address(opts->native_code_map, cur->address);
-		if (native) {
-			int32_t disp = native - (cur->dest + 4);
-			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;
-		}
-	}
-}
-
--- a/x86_backend.h	Tue Dec 16 01:10:54 2014 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- Copyright 2013 Michael Pavone
- This file is part of BlastEm. 
- BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
-*/
-#ifndef X86_BACKEND_H_
-#define X86_BACKEND_H_
-
-#include <stdint.h>
-
-#define INVALID_OFFSET 0xFFFFFFFF
-#define EXTENSION_WORD 0xFFFFFFFE
-
-typedef struct {
-	int32_t disp;
-	uint8_t mode;
-	uint8_t base;
-	uint8_t index;
-	uint8_t cycles;
-} x86_ea;
-
-typedef struct {
-	uint8_t  *base;
-	int32_t  *offsets;
-} native_map_slot;
-
-typedef struct deferred_addr {
-	struct deferred_addr *next;
-	uint8_t              *dest;
-	uint32_t             address;
-} deferred_addr;
-
-
-#define MMAP_READ      0x01
-#define MMAP_WRITE     0x02
-#define MMAP_CODE      0x04
-#define MMAP_PTR_IDX   0x08
-#define MMAP_ONLY_ODD  0x10
-#define MMAP_ONLY_EVEN 0x20
-#define MMAP_FUNC_NULL 0x40
-
-typedef uint16_t (*read_16_fun)(uint32_t address, void * context);
-typedef uint8_t (*read_8_fun)(uint32_t address, void * context);
-typedef void * (*write_16_fun)(uint32_t address, void * context, uint16_t value);
-typedef void * (*write_8_fun)(uint32_t address, void * context, uint8_t value);
-
-typedef struct {
-	uint32_t     start;
-	uint32_t     end;
-	uint32_t     mask;
-	uint16_t     ptr_index;
-	uint16_t     flags;
-	void *       buffer;
-	read_16_fun  read_16;
-	write_16_fun write_16;
-	read_8_fun   read_8;
-	write_8_fun  write_8;
-} memmap_chunk;
-
-typedef uint8_t * (*native_addr_func)(void * context, uint32_t address);
-
-deferred_addr * defer_address(deferred_addr * old_head, uint32_t address, uint8_t *dest);
-void remove_deferred_until(deferred_addr **head_ptr, deferred_addr * remove_to);
-void process_deferred(deferred_addr ** head_ptr, void * context, native_addr_func get_native);
-
-#endif //X86_BACKEND_H_
-
--- a/z80_to_x86.c	Tue Dec 16 01:10:54 2014 -0800
+++ b/z80_to_x86.c	Tue Dec 30 19:11:34 2014 -0800
@@ -28,23 +28,7 @@
 #define dprintf
 #endif
 
-void z80_read_byte();
-void z80_read_word();
-void z80_write_byte();
-void z80_write_word_highfirst();
-void z80_write_word_lowfirst();
-void z80_save_context();
-void z80_native_addr();
-void z80_do_sync();
-void z80_handle_cycle_limit_int();
-void z80_retrans_stub();
-void z80_io_read();
-void z80_io_write();
-void z80_halt();
-void z80_save_context();
-void z80_load_context();
-
-uint8_t *  zbreakpoint_patch(z80_context * context, uint16_t address, uint8_t * native);
+uint32_t zbreakpoint_patch(z80_context * context, uint16_t address, code_ptr dst);
 
 uint8_t z80_size(z80inst * inst)
 {
@@ -56,24 +40,9 @@
 	return SZ_B;
 }
 
-uint8_t * zcycles(uint8_t * dst, uint32_t num_cycles)
-{
-	return add_ir(dst, num_cycles, ZCYCLES, SZ_D);
-}
-
-uint8_t * z80_check_cycles_int(uint8_t * dst, uint16_t address)
+void translate_z80_reg(z80inst * inst, host_ea * ea, z80_options * opts)
 {
-	dst = cmp_rr(dst, ZCYCLES, ZLIMIT, SZ_D);
-	uint8_t * jmp_off = dst+1;
-	dst = jcc(dst, CC_NC, dst + 7);
-	dst = mov_ir(dst, address, SCRATCH1, SZ_W);
-	dst = call(dst, (uint8_t *)z80_handle_cycle_limit_int);
-	*jmp_off = dst - (jmp_off+1);
-	return dst;
-}
-
-uint8_t * translate_z80_reg(z80inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_options * opts)
-{
+	code_info *code = &opts->gen.code;
 	if (inst->reg == Z80_USE_IMMED) {
 		ea->mode = MODE_IMMED;
 		ea->disp = inst->immed;
@@ -83,12 +52,12 @@
 		ea->mode = MODE_REG_DIRECT;
 		if (inst->reg == Z80_IYH) {
 			if ((inst->addr_mode & 0x1F) == Z80_REG && inst->ea_reg == Z80_IYL) {
-				dst = mov_rr(dst, opts->regs[Z80_IY], SCRATCH1, SZ_W);
-				dst = ror_ir(dst, 8, SCRATCH1, SZ_W);
-				ea->base = SCRATCH1;
+				mov_rr(code, opts->regs[Z80_IY], opts->gen.scratch1, SZ_W);
+				ror_ir(code, 8, opts->gen.scratch1, SZ_W);
+				ea->base = opts->gen.scratch1;
 			} else {
 				ea->base = opts->regs[Z80_IYL];
-				dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W);
+				ror_ir(code, 8, opts->regs[Z80_IY], SZ_W);
 			}
 		} else if(opts->regs[inst->reg] >= 0) {
 			ea->base = opts->regs[inst->reg];
@@ -98,64 +67,64 @@
 					if (other_reg >= R8 || (other_reg >= RSP && other_reg <= RDI)) {
 						//we can't mix an *H reg with a register that requires the REX prefix
 						ea->base = opts->regs[z80_low_reg(inst->reg)];
-						dst = ror_ir(dst, 8, ea->base, SZ_W);
+						ror_ir(code, 8, ea->base, SZ_W);
 					}
 				} else if((inst->addr_mode & 0x1F) != Z80_UNUSED && (inst->addr_mode & 0x1F) != Z80_IMMED) {
 					//temp regs require REX prefix too
 					ea->base = opts->regs[z80_low_reg(inst->reg)];
-					dst = ror_ir(dst, 8, ea->base, SZ_W);
+					ror_ir(code, 8, ea->base, SZ_W);
 				}
 			}
 		} else {
 			ea->mode = MODE_REG_DISPLACE8;
-			ea->base = CONTEXT;
+			ea->base = opts->gen.context_reg;
 			ea->disp = offsetof(z80_context, regs) + inst->reg;
 		}
 	}
-	return dst;
 }
 
-uint8_t * z80_save_reg(uint8_t * dst, z80inst * inst, x86_z80_options * opts)
+void z80_save_reg(z80inst * inst, z80_options * opts)
 {
+	code_info *code = &opts->gen.code;
 	if (inst->reg == Z80_IYH) {
 		if ((inst->addr_mode & 0x1F) == Z80_REG && inst->ea_reg == Z80_IYL) {
-			dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W);
-			dst = mov_rr(dst, SCRATCH1, opts->regs[Z80_IYL], SZ_B);
-			dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W);
+			ror_ir(code, 8, opts->regs[Z80_IY], SZ_W);
+			mov_rr(code, opts->gen.scratch1, opts->regs[Z80_IYL], SZ_B);
+			ror_ir(code, 8, opts->regs[Z80_IY], SZ_W);
 		} else {
-			dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W);
+			ror_ir(code, 8, opts->regs[Z80_IY], SZ_W);
 		}
 	} else if (opts->regs[inst->reg] >= AH && opts->regs[inst->reg] <= BH) {
 		if ((inst->addr_mode & 0x1F) == Z80_REG) {
 			uint8_t other_reg = opts->regs[inst->ea_reg];
 			if (other_reg >= R8 || (other_reg >= RSP && other_reg <= RDI)) {
 				//we can't mix an *H reg with a register that requires the REX prefix
-				dst = ror_ir(dst, 8, opts->regs[z80_low_reg(inst->reg)], SZ_W);
+				ror_ir(code, 8, opts->regs[z80_low_reg(inst->reg)], SZ_W);
 			}
 		} else if((inst->addr_mode & 0x1F) != Z80_UNUSED && (inst->addr_mode & 0x1F) != Z80_IMMED) {
 			//temp regs require REX prefix too
-			dst = ror_ir(dst, 8, opts->regs[z80_low_reg(inst->reg)], SZ_W);
+			ror_ir(code, 8, opts->regs[z80_low_reg(inst->reg)], SZ_W);
 		}
 	}
-	return dst;
 }
 
-uint8_t * translate_z80_ea(z80inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_options * opts, uint8_t read, uint8_t modify)
+void translate_z80_ea(z80inst * inst, host_ea * ea, z80_options * opts, uint8_t read, uint8_t modify)
 {
+	code_info *code = &opts->gen.code;
 	uint8_t size, reg, areg;
 	ea->mode = MODE_REG_DIRECT;
-	areg = read ? SCRATCH1 : SCRATCH2;
+	areg = read ? opts->gen.scratch1 : opts->gen.scratch2;
 	switch(inst->addr_mode & 0x1F)
 	{
 	case Z80_REG:
 		if (inst->ea_reg == Z80_IYH) {
 			if (inst->reg == Z80_IYL) {
-				dst = mov_rr(dst, opts->regs[Z80_IY], SCRATCH1, SZ_W);
-				dst = ror_ir(dst, 8, SCRATCH1, SZ_W);
-				ea->base = SCRATCH1;
+				mov_rr(code, opts->regs[Z80_IY], opts->gen.scratch1, SZ_W);
+				ror_ir(code, 8, opts->gen.scratch1, SZ_W);
+				ea->base = opts->gen.scratch1;
 			} else {
 				ea->base = opts->regs[Z80_IYL];
-				dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W);
+				ror_ir(code, 8, opts->regs[Z80_IY], SZ_W);
 			}
 		} else if(opts->regs[inst->ea_reg] >= 0) {
 			ea->base = opts->regs[inst->ea_reg];
@@ -164,7 +133,7 @@
 				if (other_reg >= R8 || (other_reg >= RSP && other_reg <= RDI)) {
 					//we can't mix an *H reg with a register that requires the REX prefix
 					ea->base = opts->regs[z80_low_reg(inst->ea_reg)];
-					dst = ror_ir(dst, 8, ea->base, SZ_W);
+					ror_ir(code, 8, ea->base, SZ_W);
 				}
 			}
 		} else {
@@ -174,70 +143,70 @@
 		}
 		break;
 	case Z80_REG_INDIRECT:
-		dst = mov_rr(dst, opts->regs[inst->ea_reg], areg, SZ_W);
+		mov_rr(code, opts->regs[inst->ea_reg], areg, SZ_W);
 		size = z80_size(inst);
 		if (read) {
 			if (modify) {
-				//dst = push_r(dst, SCRATCH1);
-				dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(z80_context, scratch1), SZ_W);
+				//push_r(code, opts->gen.scratch1);
+				mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_W);
 			}
 			if (size == SZ_B) {
-				dst = call(dst, (uint8_t *)z80_read_byte);
+				call(code, opts->read_8);
 			} else {
-				dst = call(dst, (uint8_t *)z80_read_word);
+				call(code, opts->read_16);
 			}
 			if (modify) {
-				//dst = pop_r(dst, SCRATCH2);
-				dst = mov_rdisp8r(dst, CONTEXT, offsetof(z80_context, scratch1), SCRATCH2, SZ_W);
+				//pop_r(code, opts->gen.scratch2);
+				mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, scratch1), opts->gen.scratch2, SZ_W);
 			}
 		}
-		ea->base = SCRATCH1;
+		ea->base = opts->gen.scratch1;
 		break;
 	case Z80_IMMED:
 		ea->mode = MODE_IMMED;
 		ea->disp = inst->immed;
 		break;
 	case Z80_IMMED_INDIRECT:
-		dst = mov_ir(dst, inst->immed, areg, SZ_W);
+		mov_ir(code, inst->immed, areg, SZ_W);
 		size = z80_size(inst);
 		if (read) {
 			/*if (modify) {
-				dst = push_r(dst, SCRATCH1);
+				push_r(code, opts->gen.scratch1);
 			}*/
 			if (size == SZ_B) {
-				dst = call(dst, (uint8_t *)z80_read_byte);
+				call(code, opts->read_8);
 			} else {
-				dst = call(dst, (uint8_t *)z80_read_word);
+				call(code, opts->read_16);
 			}
 			if (modify) {
-				//dst = pop_r(dst, SCRATCH2);
-				dst = mov_ir(dst, inst->immed, SCRATCH2, SZ_W);
+				//pop_r(code, opts->gen.scratch2);
+				mov_ir(code, inst->immed, opts->gen.scratch2, SZ_W);
 			}
 		}
-		ea->base = SCRATCH1;
+		ea->base = opts->gen.scratch1;
 		break;
 	case Z80_IX_DISPLACE:
 	case Z80_IY_DISPLACE:
 		reg = opts->regs[(inst->addr_mode & 0x1F) == Z80_IX_DISPLACE ? Z80_IX : Z80_IY];
-		dst = mov_rr(dst, reg, areg, SZ_W);
-		dst = add_ir(dst, inst->ea_reg & 0x80 ? inst->ea_reg - 256 : inst->ea_reg, areg, SZ_W);
+		mov_rr(code, reg, areg, SZ_W);
+		add_ir(code, inst->ea_reg & 0x80 ? inst->ea_reg - 256 : inst->ea_reg, areg, SZ_W);
 		size = z80_size(inst);
 		if (read) {
 			if (modify) {
-				//dst = push_r(dst, SCRATCH1);
-				dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(z80_context, scratch1), SZ_W);
+				//push_r(code, opts->gen.scratch1);
+				mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_W);
 			}
 			if (size == SZ_B) {
-				dst = call(dst, (uint8_t *)z80_read_byte);
+				call(code, opts->read_8);
 			} else {
-				dst = call(dst, (uint8_t *)z80_read_word);
+				call(code, opts->read_16);
 			}
 			if (modify) {
-				//dst = pop_r(dst, SCRATCH2);
-				dst = mov_rdisp8r(dst, CONTEXT, offsetof(z80_context, scratch1), SCRATCH2, SZ_W);
+				//pop_r(code, opts->gen.scratch2);
+				mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, scratch1), opts->gen.scratch2, SZ_W);
 			}
 		}
-		ea->base = SCRATCH1;
+		ea->base = opts->gen.scratch1;
 		break;
 	case Z80_UNUSED:
 		ea->mode = MODE_UNUSED;
@@ -246,32 +215,30 @@
 		fprintf(stderr, "Unrecognized Z80 addressing mode %d\n", inst->addr_mode & 0x1F);
 		exit(1);
 	}
-	return dst;
 }
 
-uint8_t * z80_save_ea(uint8_t * dst, z80inst * inst, x86_z80_options * opts)
+void z80_save_ea(code_info *code, z80inst * inst, z80_options * opts)
 {
 	if ((inst->addr_mode & 0x1F) == Z80_REG) {
 		if (inst->ea_reg == Z80_IYH) {
 			if (inst->reg == Z80_IYL) {
-				dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W);
-				dst = mov_rr(dst, SCRATCH1, opts->regs[Z80_IYL], SZ_B);
-				dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W);
+				ror_ir(code, 8, opts->regs[Z80_IY], SZ_W);
+				mov_rr(code, opts->gen.scratch1, opts->regs[Z80_IYL], SZ_B);
+				ror_ir(code, 8, opts->regs[Z80_IY], SZ_W);
 			} else {
-				dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W);
+				ror_ir(code, 8, opts->regs[Z80_IY], SZ_W);
 			}
 		} else if (inst->reg != Z80_UNUSED && inst->reg != Z80_USE_IMMED && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) {
 			uint8_t other_reg = opts->regs[inst->reg];
 			if (other_reg >= R8 || (other_reg >= RSP && other_reg <= RDI)) {
 				//we can't mix an *H reg with a register that requires the REX prefix
-				dst = ror_ir(dst, 8, opts->regs[z80_low_reg(inst->ea_reg)], SZ_W);
+				ror_ir(code, 8, opts->regs[z80_low_reg(inst->ea_reg)], SZ_W);
 			}
 		}
 	}
-	return dst;
 }
 
-uint8_t * z80_save_result(uint8_t * dst, z80inst * inst)
+void z80_save_result(z80_options *opts, z80inst * inst)
 {
 	switch(inst->addr_mode & 0x1f)
 	{
@@ -280,12 +247,11 @@
 	case Z80_IX_DISPLACE:
 	case Z80_IY_DISPLACE:
 		if (z80_size(inst) == SZ_B) {
-			dst = call(dst, (uint8_t *)z80_write_byte);
+			call(&opts->gen.code, opts->write_8);
 		} else {
-			dst = call(dst, (uint8_t *)z80_write_word_lowfirst);
+			call(&opts->gen.code, opts->write_16_lowfirst);
 		}
 	}
-	return dst;
 }
 
 enum {
@@ -332,15 +298,16 @@
 	exit(0);
 }
 
-uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context, uint16_t address, uint8_t interp)
+void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, uint8_t interp)
 {
-	uint32_t cycles;
-	x86_ea src_op, dst_op;
+	uint32_t num_cycles;
+	host_ea src_op, dst_op;
 	uint8_t size;
-	x86_z80_options *opts = context->options;
-	uint8_t * start = dst;
+	z80_options *opts = context->options;
+	uint8_t * start = opts->gen.code.cur;
+	code_info *code = &opts->gen.code;
 	if (!interp) {
-		dst = z80_check_cycles_int(dst, address);
+		check_cycles_int(&opts->gen, address);
 		if (context->breakpoint_flags[address / sizeof(uint8_t)] & (1 << (address % sizeof(uint8_t)))) {
 			zbreakpoint_patch(context, address, start);
 		}
@@ -353,253 +320,253 @@
 		{
 		case Z80_REG:
 		case Z80_REG_INDIRECT:
- 			cycles = size == SZ_B ? 4 : 6;
+ 			num_cycles = size == SZ_B ? 4 : 6;
 			if (inst->ea_reg == Z80_IX || inst->ea_reg == Z80_IY) {
-				cycles += 4;
+				num_cycles += 4;
 			}
 			if (inst->reg == Z80_I || inst->ea_reg == Z80_I) {
-				cycles += 5;
+				num_cycles += 5;
 			}
 			break;
 		case Z80_IMMED:
-			cycles = size == SZ_B ? 7 : 10;
+			num_cycles = size == SZ_B ? 7 : 10;
 			break;
 		case Z80_IMMED_INDIRECT:
-			cycles = 10;
+			num_cycles = 10;
 			break;
 		case Z80_IX_DISPLACE:
 		case Z80_IY_DISPLACE:
-			cycles = 16;
+			num_cycles = 16;
 			break;
 		}
 		if ((inst->reg >= Z80_IXL && inst->reg <= Z80_IYH) || inst->reg == Z80_IX || inst->reg == Z80_IY) {
-			cycles += 4;
+			num_cycles += 4;
 		}
-		dst = zcycles(dst, cycles);
+		cycles(&opts->gen, num_cycles);
 		if (inst->addr_mode & Z80_DIR) {
-			dst = translate_z80_ea(inst, &dst_op, dst, opts, DONT_READ, MODIFY);
-			dst = translate_z80_reg(inst, &src_op, dst, opts);
+			translate_z80_ea(inst, &dst_op, opts, DONT_READ, MODIFY);
+			translate_z80_reg(inst, &src_op, opts);
 		} else {
-			dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY);
-			dst = translate_z80_reg(inst, &dst_op, dst, opts);
+			translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
+			translate_z80_reg(inst, &dst_op, opts);
 		}
 		if (src_op.mode == MODE_REG_DIRECT) {
 			if(dst_op.mode == MODE_REG_DISPLACE8) {
-				dst = mov_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, size);
+				mov_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, size);
 			} else {
-				dst = mov_rr(dst, src_op.base, dst_op.base, size);
+				mov_rr(code, src_op.base, dst_op.base, size);
 			}
 		} else if(src_op.mode == MODE_IMMED) {
-			dst = mov_ir(dst, src_op.disp, dst_op.base, size);
+			mov_ir(code, src_op.disp, dst_op.base, size);
 		} else {
-			dst = mov_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, size);
+			mov_rdispr(code, src_op.base, src_op.disp, dst_op.base, size);
 		}
 		if (inst->ea_reg == Z80_I && inst->addr_mode == Z80_REG) {
 			//ld a, i sets some flags
 			//TODO: Implement half-carry flag
-			dst = cmp_ir(dst, 0, dst_op.base, SZ_B);
-			dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z));
-			dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
-			dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);;
-			dst = mov_rdisp8r(dst, CONTEXT, offsetof(z80_context, iff2), SCRATCH1, SZ_B);
-			dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, zf_off(ZF_PV), SZ_B);
+			cmp_ir(code, 0, dst_op.base, SZ_B);
+			setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+			setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
+			mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);;
+			mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, iff2), SCRATCH1, SZ_B);
+			mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_PV), SZ_B);
 		}
-		dst = z80_save_reg(dst, inst, opts);
-		dst = z80_save_ea(dst, inst, opts);
+		z80_save_reg(inst, opts);
+		z80_save_ea(code, inst, opts);
 		if (inst->addr_mode & Z80_DIR) {
-			dst = z80_save_result(dst, inst);
+			z80_save_result(opts, inst);
 		}
 		break;
 	case Z80_PUSH:
-		dst = zcycles(dst, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 9 : 5);
-		dst = sub_ir(dst, 2, opts->regs[Z80_SP], SZ_W);
+		cycles(&opts->gen, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 9 : 5);
+		sub_ir(code, 2, opts->regs[Z80_SP], SZ_W);
 		if (inst->reg == Z80_AF) {
-			dst = mov_rr(dst, opts->regs[Z80_A], SCRATCH1, SZ_B);
-			dst = shl_ir(dst, 8, SCRATCH1, SZ_W);
-			dst = mov_rdisp8r(dst, CONTEXT, zf_off(ZF_S), SCRATCH1, SZ_B);
-			dst = shl_ir(dst, 1, SCRATCH1, SZ_B);
-			dst = or_rdisp8r(dst, CONTEXT, zf_off(ZF_Z), SCRATCH1, SZ_B);
-			dst = shl_ir(dst, 2, SCRATCH1, SZ_B);
-			dst = or_rdisp8r(dst, CONTEXT, zf_off(ZF_H), SCRATCH1, SZ_B);
-			dst = shl_ir(dst, 2, SCRATCH1, SZ_B);
-			dst = or_rdisp8r(dst, CONTEXT, zf_off(ZF_PV), SCRATCH1, SZ_B);
-			dst = shl_ir(dst, 1, SCRATCH1, SZ_B);
-			dst = or_rdisp8r(dst, CONTEXT, zf_off(ZF_N), SCRATCH1, SZ_B);
-			dst = shl_ir(dst, 1, SCRATCH1, SZ_B);
-			dst = or_rdisp8r(dst, CONTEXT, zf_off(ZF_C), SCRATCH1, SZ_B);
+			mov_rr(code, opts->regs[Z80_A], opts->gen.scratch1, SZ_B);
+			shl_ir(code, 8, opts->gen.scratch1, SZ_W);
+			mov_rdispr(code, opts->gen.context_reg, zf_off(ZF_S), opts->gen.scratch1, SZ_B);
+			shl_ir(code, 1, opts->gen.scratch1, SZ_B);
+			or_rdispr(code, opts->gen.context_reg, zf_off(ZF_Z), opts->gen.scratch1, SZ_B);
+			shl_ir(code, 2, opts->gen.scratch1, SZ_B);
+			or_rdispr(code, opts->gen.context_reg, zf_off(ZF_H), opts->gen.scratch1, SZ_B);
+			shl_ir(code, 2, opts->gen.scratch1, SZ_B);
+			or_rdispr(code, opts->gen.context_reg, zf_off(ZF_PV), opts->gen.scratch1, SZ_B);
+			shl_ir(code, 1, opts->gen.scratch1, SZ_B);
+			or_rdispr(code, opts->gen.context_reg, zf_off(ZF_N), opts->gen.scratch1, SZ_B);
+			shl_ir(code, 1, opts->gen.scratch1, SZ_B);
+			or_rdispr(code, opts->gen.context_reg, zf_off(ZF_C), opts->gen.scratch1, SZ_B);
 		} else {
-			dst = translate_z80_reg(inst, &src_op, dst, opts);
-			dst = mov_rr(dst, src_op.base, SCRATCH1, SZ_W);
+			translate_z80_reg(inst, &src_op, opts);
+			mov_rr(code, src_op.base, opts->gen.scratch1, SZ_W);
 		}
-		dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH2, SZ_W);
-		dst = call(dst, (uint8_t *)z80_write_word_highfirst);
+		mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
+		call(code, opts->write_16_highfirst);
 		//no call to save_z80_reg needed since there's no chance we'll use the only
 		//the upper half of a register pair
 		break;
 	case Z80_POP:
-		dst = zcycles(dst, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 8 : 4);
-		dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, SZ_W);
-		dst = call(dst, (uint8_t *)z80_read_word);
-		dst = add_ir(dst, 2, opts->regs[Z80_SP], SZ_W);
+		cycles(&opts->gen, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 8 : 4);
+		mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
+		call(code, opts->read_16);
+		add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
 		if (inst->reg == Z80_AF) {
 
-			dst = bt_ir(dst, 0, SCRATCH1, SZ_W);
-			dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C));
-			dst = bt_ir(dst, 1, SCRATCH1, SZ_W);
-			dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_N));
-			dst = bt_ir(dst, 2, SCRATCH1, SZ_W);
-			dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_PV));
-			dst = bt_ir(dst, 4, SCRATCH1, SZ_W);
-			dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_H));
-			dst = bt_ir(dst, 6, SCRATCH1, SZ_W);
-			dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_Z));
-			dst = bt_ir(dst, 7, SCRATCH1, SZ_W);
-			dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_S));
-			dst = shr_ir(dst, 8, SCRATCH1, SZ_W);
-			dst = mov_rr(dst, SCRATCH1, opts->regs[Z80_A], SZ_B);
+			bt_ir(code, 0, opts->gen.scratch1, SZ_W);
+			setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+			bt_ir(code, 1, opts->gen.scratch1, SZ_W);
+			setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_N));
+			bt_ir(code, 2, opts->gen.scratch1, SZ_W);
+			setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_PV));
+			bt_ir(code, 4, opts->gen.scratch1, SZ_W);
+			setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
+			bt_ir(code, 6, opts->gen.scratch1, SZ_W);
+			setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_Z));
+			bt_ir(code, 7, opts->gen.scratch1, SZ_W);
+			setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_S));
+			shr_ir(code, 8, opts->gen.scratch1, SZ_W);
+			mov_rr(code, opts->gen.scratch1, opts->regs[Z80_A], SZ_B);
 		} else {
-			dst = translate_z80_reg(inst, &src_op, dst, opts);
-			dst = mov_rr(dst, SCRATCH1, src_op.base, SZ_W);
+			translate_z80_reg(inst, &src_op, opts);
+			mov_rr(code, opts->gen.scratch1, src_op.base, SZ_W);
 		}
 		//no call to save_z80_reg needed since there's no chance we'll use the only
 		//the upper half of a register pair
 		break;
 	case Z80_EX:
 		if (inst->addr_mode == Z80_REG || inst->reg == Z80_HL) {
-			cycles = 4;
+			num_cycles = 4;
 		} else {
-			cycles = 8;
+			num_cycles = 8;
 		}
-		dst = zcycles(dst, cycles);
+		cycles(&opts->gen, num_cycles);
 		if (inst->addr_mode == Z80_REG) {
 			if(inst->reg == Z80_AF) {
-				dst = mov_rr(dst, opts->regs[Z80_A], SCRATCH1, SZ_B);
-				dst = mov_rdisp8r(dst, CONTEXT, zar_off(Z80_A), opts->regs[Z80_A], SZ_B);
-				dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, zar_off(Z80_A), SZ_B);
+				mov_rr(code, opts->regs[Z80_A], opts->gen.scratch1, SZ_B);
+				mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_A), opts->regs[Z80_A], SZ_B);
+				mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_A), SZ_B);
 
 				//Flags are currently word aligned, so we can move
 				//them efficiently a word at a time
 				for (int f = ZF_C; f < ZF_NUM; f+=2) {
-					dst = mov_rdisp8r(dst, CONTEXT, zf_off(f), SCRATCH1, SZ_W);
-					dst = mov_rdisp8r(dst, CONTEXT, zaf_off(f), SCRATCH2, SZ_W);
-					dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, zaf_off(f), SZ_W);
-					dst = mov_rrdisp8(dst, SCRATCH2, CONTEXT, zf_off(f), SZ_W);
+					mov_rdispr(code, opts->gen.context_reg, zf_off(f), opts->gen.scratch1, SZ_W);
+					mov_rdispr(code, opts->gen.context_reg, zaf_off(f), opts->gen.scratch2, SZ_W);
+					mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zaf_off(f), SZ_W);
+					mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(f), SZ_W);
 				}
 			} else {
-				dst = xchg_rr(dst, opts->regs[Z80_DE], opts->regs[Z80_HL], SZ_W);
+				xchg_rr(code, opts->regs[Z80_DE], opts->regs[Z80_HL], SZ_W);
 			}
 		} else {
-			dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, SZ_W);
-			dst = call(dst, (uint8_t *)z80_read_byte);
-			dst = xchg_rr(dst, opts->regs[inst->reg], SCRATCH1, SZ_B);
-			dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH2, SZ_W);
-			dst = call(dst, (uint8_t *)z80_write_byte);
-			dst = zcycles(dst, 1);
+			mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
+			call(code, opts->read_8);
+			xchg_rr(code, opts->regs[inst->reg], opts->gen.scratch1, SZ_B);
+			mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
+			call(code, opts->write_8);
+			cycles(&opts->gen, 1);
 			uint8_t high_reg = z80_high_reg(inst->reg);
 			uint8_t use_reg;
 			//even though some of the upper halves can be used directly
 			//the limitations on mixing *H regs with the REX prefix
 			//prevent us from taking advantage of it
 			use_reg = opts->regs[inst->reg];
-			dst = ror_ir(dst, 8, use_reg, SZ_W);
-			dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, SZ_W);
-			dst = add_ir(dst, 1, SCRATCH1, SZ_W);
-			dst = call(dst, (uint8_t *)z80_read_byte);
-			dst = xchg_rr(dst, use_reg, SCRATCH1, SZ_B);
-			dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH2, SZ_W);
-			dst = add_ir(dst, 1, SCRATCH2, SZ_W);
-			dst = call(dst, (uint8_t *)z80_write_byte);
+			ror_ir(code, 8, use_reg, SZ_W);
+			mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
+			add_ir(code, 1, opts->gen.scratch1, SZ_W);
+			call(code, opts->read_8);
+			xchg_rr(code, use_reg, opts->gen.scratch1, SZ_B);
+			mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
+			add_ir(code, 1, opts->gen.scratch2, SZ_W);
+			call(code, opts->write_8);
 			//restore reg to normal rotation
-			dst = ror_ir(dst, 8, use_reg, SZ_W);
-			dst = zcycles(dst, 2);
+			ror_ir(code, 8, use_reg, SZ_W);
+			cycles(&opts->gen, 2);
 		}
 		break;
 	case Z80_EXX:
-		dst = zcycles(dst, 4);
-		dst = mov_rr(dst, opts->regs[Z80_BC], SCRATCH1, SZ_W);
-		dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH2, SZ_W);
-		dst = mov_rdisp8r(dst, CONTEXT, zar_off(Z80_C), opts->regs[Z80_BC], SZ_W);
-		dst = mov_rdisp8r(dst, CONTEXT, zar_off(Z80_L), opts->regs[Z80_HL], SZ_W);
-		dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, zar_off(Z80_C), SZ_W);
-		dst = mov_rrdisp8(dst, SCRATCH2, CONTEXT, zar_off(Z80_L), SZ_W);
-		dst = mov_rr(dst, opts->regs[Z80_DE], SCRATCH1, SZ_W);
-		dst = mov_rdisp8r(dst, CONTEXT, zar_off(Z80_E), opts->regs[Z80_DE], SZ_W);
-		dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, zar_off(Z80_E), SZ_W);
+		cycles(&opts->gen, 4);
+		mov_rr(code, opts->regs[Z80_BC], opts->gen.scratch1, SZ_W);
+		mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W);
+		mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_C), opts->regs[Z80_BC], SZ_W);
+		mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_L), opts->regs[Z80_HL], SZ_W);
+		mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_C), SZ_W);
+		mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zar_off(Z80_L), SZ_W);
+		mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch1, SZ_W);
+		mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_E), opts->regs[Z80_DE], SZ_W);
+		mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_E), SZ_W);
 		break;
 	case Z80_LDI: {
-		dst = zcycles(dst, 8);
-		dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH1, SZ_W);
-		dst = call(dst, (uint8_t *)z80_read_byte);
-		dst = mov_rr(dst, opts->regs[Z80_DE], SCRATCH2, SZ_W);
-		dst = call(dst, (uint8_t *)z80_write_byte);
-		dst = zcycles(dst, 2);
-		dst = add_ir(dst, 1, opts->regs[Z80_DE], SZ_W);
-		dst = add_ir(dst, 1, opts->regs[Z80_HL], SZ_W);
-		dst = sub_ir(dst, 1, opts->regs[Z80_BC], SZ_W);
+		cycles(&opts->gen, 8);
+		mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W);
+		call(code, opts->read_8);
+		mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W);
+		call(code, opts->write_8);
+		cycles(&opts->gen, 2);
+		add_ir(code, 1, opts->regs[Z80_DE], SZ_W);
+		add_ir(code, 1, opts->regs[Z80_HL], SZ_W);
+		sub_ir(code, 1, opts->regs[Z80_BC], SZ_W);
 		//TODO: Implement half-carry
-		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
-		dst = setcc_rdisp8(dst, CC_NZ, CONTEXT, zf_off(ZF_PV));
+		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
+		setcc_rdisp(code, CC_NZ, opts->gen.context_reg, zf_off(ZF_PV));
 		break;
 	}
 	case Z80_LDIR: {
-		dst = zcycles(dst, 8);
-		dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH1, SZ_W);
-		dst = call(dst, (uint8_t *)z80_read_byte);
-		dst = mov_rr(dst, opts->regs[Z80_DE], SCRATCH2, SZ_W);
-		dst = call(dst, (uint8_t *)z80_write_byte);
-		dst = add_ir(dst, 1, opts->regs[Z80_DE], SZ_W);
-		dst = add_ir(dst, 1, opts->regs[Z80_HL], SZ_W);
+		cycles(&opts->gen, 8);
+		mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W);
+		call(code, opts->read_8);
+		mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W);
+		call(code, opts->write_8);
+		add_ir(code, 1, opts->regs[Z80_DE], SZ_W);
+		add_ir(code, 1, opts->regs[Z80_HL], SZ_W);
 
-		dst = sub_ir(dst, 1, opts->regs[Z80_BC], SZ_W);
-		uint8_t * cont = dst+1;
-		dst = jcc(dst, CC_Z, dst+2);
-		dst = zcycles(dst, 7);
+		sub_ir(code, 1, opts->regs[Z80_BC], SZ_W);
+		uint8_t * cont = code->cur+1;
+		jcc(code, CC_Z, code->cur+2);
+		cycles(&opts->gen, 7);
 		//TODO: Figure out what the flag state should be here
 		//TODO: Figure out whether an interrupt can interrupt this
-		dst = jmp(dst, start);
-		*cont = dst - (cont + 1);
-		dst = zcycles(dst, 2);
+		jmp(code, start);
+		*cont = code->cur - (cont + 1);
+		cycles(&opts->gen, 2);
 		//TODO: Implement half-carry
-		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
-		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_PV), SZ_B);
+		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
+		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B);
 		break;
 	}
 	case Z80_LDD: {
-		dst = zcycles(dst, 8);
-		dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH1, SZ_W);
-		dst = call(dst, (uint8_t *)z80_read_byte);
-		dst = mov_rr(dst, opts->regs[Z80_DE], SCRATCH2, SZ_W);
-		dst = call(dst, (uint8_t *)z80_write_byte);
-		dst = zcycles(dst, 2);
-		dst = sub_ir(dst, 1, opts->regs[Z80_DE], SZ_W);
-		dst = sub_ir(dst, 1, opts->regs[Z80_HL], SZ_W);
-		dst = sub_ir(dst, 1, opts->regs[Z80_BC], SZ_W);
+		cycles(&opts->gen, 8);
+		mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W);
+		call(code, opts->read_8);
+		mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W);
+		call(code, opts->write_8);
+		cycles(&opts->gen, 2);
+		sub_ir(code, 1, opts->regs[Z80_DE], SZ_W);
+		sub_ir(code, 1, opts->regs[Z80_HL], SZ_W);
+		sub_ir(code, 1, opts->regs[Z80_BC], SZ_W);
 		//TODO: Implement half-carry
-		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
-		dst = setcc_rdisp8(dst, CC_NZ, CONTEXT, zf_off(ZF_PV));
+		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
+		setcc_rdisp(code, CC_NZ, opts->gen.context_reg, zf_off(ZF_PV));
 		break;
 	}
 	case Z80_LDDR: {
-		dst = zcycles(dst, 8);
-		dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH1, SZ_W);
-		dst = call(dst, (uint8_t *)z80_read_byte);
-		dst = mov_rr(dst, opts->regs[Z80_DE], SCRATCH2, SZ_W);
-		dst = call(dst, (uint8_t *)z80_write_byte);
-		dst = sub_ir(dst, 1, opts->regs[Z80_DE], SZ_W);
-		dst = sub_ir(dst, 1, opts->regs[Z80_HL], SZ_W);
+		cycles(&opts->gen, 8);
+		mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W);
+		call(code, opts->read_8);
+		mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W);
+		call(code, opts->write_8);
+		sub_ir(code, 1, opts->regs[Z80_DE], SZ_W);
+		sub_ir(code, 1, opts->regs[Z80_HL], SZ_W);
 
-		dst = sub_ir(dst, 1, opts->regs[Z80_BC], SZ_W);
-		uint8_t * cont = dst+1;
-		dst = jcc(dst, CC_Z, dst+2);
-		dst = zcycles(dst, 7);
+		sub_ir(code, 1, opts->regs[Z80_BC], SZ_W);
+		uint8_t * cont = code->cur+1;
+		jcc(code, CC_Z, code->cur+2);
+		cycles(&opts->gen, 7);
 		//TODO: Figure out what the flag state should be here
 		//TODO: Figure out whether an interrupt can interrupt this
-		dst = jmp(dst, start);
-		*cont = dst - (cont + 1);
-		dst = zcycles(dst, 2);
+		jmp(code, start);
+		*cont = code->cur - (cont + 1);
+		cycles(&opts->gen, 2);
 		//TODO: Implement half-carry
-		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
-		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_PV), SZ_B);
+		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
+		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B);
 		break;
 	}
 	/*case Z80_CPI:
@@ -608,634 +575,644 @@
 	case Z80_CPDR:
 		break;*/
 	case Z80_ADD:
-		cycles = 4;
+		num_cycles = 4;
 		if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
-			cycles += 12;
+			num_cycles += 12;
 		} else if(inst->addr_mode == Z80_IMMED) {
-			cycles += 3;
+			num_cycles += 3;
 		} else if(z80_size(inst) == SZ_W) {
-			cycles += 4;
+			num_cycles += 4;
 		}
-		dst = zcycles(dst, cycles);
-		dst = translate_z80_reg(inst, &dst_op, dst, opts);
-		dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY);
+		cycles(&opts->gen, num_cycles);
+		translate_z80_reg(inst, &dst_op, opts);
+		translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
 		if (src_op.mode == MODE_REG_DIRECT) {
-			dst = add_rr(dst, src_op.base, dst_op.base, z80_size(inst));
+			add_rr(code, src_op.base, dst_op.base, z80_size(inst));
 		} else {
-			dst = add_ir(dst, src_op.disp, dst_op.base, z80_size(inst));
+			add_ir(code, src_op.disp, dst_op.base, z80_size(inst));
 		}
-		dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C));
-		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		//TODO: Implement half-carry flag
 		if (z80_size(inst) == SZ_B) {
-			dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV));
-			dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z));
-			dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
+			setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
+			setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+			setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		}
-		dst = z80_save_reg(dst, inst, opts);
-		dst = z80_save_ea(dst, inst, opts);
+		z80_save_reg(inst, opts);
+		z80_save_ea(code, inst, opts);
 		break;
 	case Z80_ADC:
-		cycles = 4;
+		num_cycles = 4;
 		if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
-			cycles += 12;
+			num_cycles += 12;
 		} else if(inst->addr_mode == Z80_IMMED) {
-			cycles += 3;
+			num_cycles += 3;
 		} else if(z80_size(inst) == SZ_W) {
-			cycles += 4;
+			num_cycles += 4;
 		}
-		dst = zcycles(dst, cycles);
-		dst = translate_z80_reg(inst, &dst_op, dst, opts);
-		dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY);
-		dst = bt_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B);
+		cycles(&opts->gen, num_cycles);
+		translate_z80_reg(inst, &dst_op, opts);
+		translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
+		bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
 		if (src_op.mode == MODE_REG_DIRECT) {
-			dst = adc_rr(dst, src_op.base, dst_op.base, z80_size(inst));
+			adc_rr(code, src_op.base, dst_op.base, z80_size(inst));
 		} else {
-			dst = adc_ir(dst, src_op.disp, dst_op.base, z80_size(inst));
+			adc_ir(code, src_op.disp, dst_op.base, z80_size(inst));
 		}
-		dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C));
-		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		//TODO: Implement half-carry flag
-		dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV));
-		dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z));
-		dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
-		dst = z80_save_reg(dst, inst, opts);
-		dst = z80_save_ea(dst, inst, opts);
+		setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
+		setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
+		z80_save_reg(inst, opts);
+		z80_save_ea(code, inst, opts);
 		break;
 	case Z80_SUB:
-		cycles = 4;
+		num_cycles = 4;
 		if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
-			cycles += 12;
+			num_cycles += 12;
 		} else if(inst->addr_mode == Z80_IMMED) {
-			cycles += 3;
+			num_cycles += 3;
 		}
-		dst = zcycles(dst, cycles);
-		dst = translate_z80_reg(inst, &dst_op, dst, opts);
-		dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY);
+		cycles(&opts->gen, num_cycles);
+		translate_z80_reg(inst, &dst_op, opts);
+		translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
 		if (src_op.mode == MODE_REG_DIRECT) {
-			dst = sub_rr(dst, src_op.base, dst_op.base, z80_size(inst));
+			sub_rr(code, src_op.base, dst_op.base, z80_size(inst));
 		} else {
-			dst = sub_ir(dst, src_op.disp, dst_op.base, z80_size(inst));
+			sub_ir(code, src_op.disp, dst_op.base, z80_size(inst));
 		}
-		dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C));
-		dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_N), SZ_B);
-		dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV));
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
+		setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
 		//TODO: Implement half-carry flag
-		dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z));
-		dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
-		dst = z80_save_reg(dst, inst, opts);
-		dst = z80_save_ea(dst, inst, opts);
+		setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
+		z80_save_reg(inst, opts);
+		z80_save_ea(code, inst, opts);
 		break;
 	case Z80_SBC:
-		cycles = 4;
+		num_cycles = 4;
 		if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
-			cycles += 12;
+			num_cycles += 12;
 		} else if(inst->addr_mode == Z80_IMMED) {
-			cycles += 3;
+			num_cycles += 3;
 		} else if(z80_size(inst) == SZ_W) {
-			cycles += 4;
+			num_cycles += 4;
 		}
-		dst = zcycles(dst, cycles);
-		dst = translate_z80_reg(inst, &dst_op, dst, opts);
-		dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY);
-		dst = bt_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B);
+		cycles(&opts->gen, num_cycles);
+		translate_z80_reg(inst, &dst_op, opts);
+		translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
+		bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
 		if (src_op.mode == MODE_REG_DIRECT) {
-			dst = sbb_rr(dst, src_op.base, dst_op.base, z80_size(inst));
+			sbb_rr(code, src_op.base, dst_op.base, z80_size(inst));
 		} else {
-			dst = sbb_ir(dst, src_op.disp, dst_op.base, z80_size(inst));
+			sbb_ir(code, src_op.disp, dst_op.base, z80_size(inst));
 		}
-		dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C));
-		dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_N), SZ_B);
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		//TODO: Implement half-carry flag
-		dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV));
-		dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z));
-		dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
-		dst = z80_save_reg(dst, inst, opts);
-		dst = z80_save_ea(dst, inst, opts);
+		setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
+		setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
+		z80_save_reg(inst, opts);
+		z80_save_ea(code, inst, opts);
 		break;
 	case Z80_AND:
-		cycles = 4;
+		num_cycles = 4;
 		if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
-			cycles += 12;
+			num_cycles += 12;
 		} else if(inst->addr_mode == Z80_IMMED) {
-			cycles += 3;
+			num_cycles += 3;
 		} else if(z80_size(inst) == SZ_W) {
-			cycles += 4;
+			num_cycles += 4;
 		}
-		dst = zcycles(dst, cycles);
-		dst = translate_z80_reg(inst, &dst_op, dst, opts);
-		dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY);
+		cycles(&opts->gen, num_cycles);
+		translate_z80_reg(inst, &dst_op, opts);
+		translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
 		if (src_op.mode == MODE_REG_DIRECT) {
-			dst = and_rr(dst, src_op.base, dst_op.base, z80_size(inst));
+			and_rr(code, src_op.base, dst_op.base, z80_size(inst));
 		} else {
-			dst = and_ir(dst, src_op.disp, dst_op.base, z80_size(inst));
+			and_ir(code, src_op.disp, dst_op.base, z80_size(inst));
 		}
 		//TODO: Cleanup flags
-		dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C));
-		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		//TODO: Implement half-carry flag
 		if (z80_size(inst) == SZ_B) {
-			dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV));
-			dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z));
-			dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
+			setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
+			setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+			setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		}
-		dst = z80_save_reg(dst, inst, opts);
-		dst = z80_save_ea(dst, inst, opts);
+		z80_save_reg(inst, opts);
+		z80_save_ea(code, inst, opts);
 		break;
 	case Z80_OR:
-		cycles = 4;
+		num_cycles = 4;
 		if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
-			cycles += 12;
+			num_cycles += 12;
 		} else if(inst->addr_mode == Z80_IMMED) {
-			cycles += 3;
+			num_cycles += 3;
 		} else if(z80_size(inst) == SZ_W) {
-			cycles += 4;
+			num_cycles += 4;
 		}
-		dst = zcycles(dst, cycles);
-		dst = translate_z80_reg(inst, &dst_op, dst, opts);
-		dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY);
+		cycles(&opts->gen, num_cycles);
+		translate_z80_reg(inst, &dst_op, opts);
+		translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
 		if (src_op.mode == MODE_REG_DIRECT) {
-			dst = or_rr(dst, src_op.base, dst_op.base, z80_size(inst));
+			or_rr(code, src_op.base, dst_op.base, z80_size(inst));
 		} else {
-			dst = or_ir(dst, src_op.disp, dst_op.base, z80_size(inst));
+			or_ir(code, src_op.disp, dst_op.base, z80_size(inst));
 		}
 		//TODO: Cleanup flags
-		dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C));
-		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		//TODO: Implement half-carry flag
 		if (z80_size(inst) == SZ_B) {
-			dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV));
-			dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z));
-			dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
+			setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
+			setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+			setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		}
-		dst = z80_save_reg(dst, inst, opts);
-		dst = z80_save_ea(dst, inst, opts);
+		z80_save_reg(inst, opts);
+		z80_save_ea(code, inst, opts);
 		break;
 	case Z80_XOR:
-		cycles = 4;
+		num_cycles = 4;
 		if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
-			cycles += 12;
+			num_cycles += 12;
 		} else if(inst->addr_mode == Z80_IMMED) {
-			cycles += 3;
+			num_cycles += 3;
 		} else if(z80_size(inst) == SZ_W) {
-			cycles += 4;
+			num_cycles += 4;
 		}
-		dst = zcycles(dst, cycles);
-		dst = translate_z80_reg(inst, &dst_op, dst, opts);
-		dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY);
+		cycles(&opts->gen, num_cycles);
+		translate_z80_reg(inst, &dst_op, opts);
+		translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
 		if (src_op.mode == MODE_REG_DIRECT) {
-			dst = xor_rr(dst, src_op.base, dst_op.base, z80_size(inst));
+			xor_rr(code, src_op.base, dst_op.base, z80_size(inst));
 		} else {
-			dst = xor_ir(dst, src_op.disp, dst_op.base, z80_size(inst));
+			xor_ir(code, src_op.disp, dst_op.base, z80_size(inst));
 		}
 		//TODO: Cleanup flags
-		dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C));
-		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		//TODO: Implement half-carry flag
 		if (z80_size(inst) == SZ_B) {
-			dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV));
-			dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z));
-			dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
+			setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
+			setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+			setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		}
-		dst = z80_save_reg(dst, inst, opts);
-		dst = z80_save_ea(dst, inst, opts);
+		z80_save_reg(inst, opts);
+		z80_save_ea(code, inst, opts);
 		break;
 	case Z80_CP:
-		cycles = 4;
+		num_cycles = 4;
 		if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
-			cycles += 12;
+			num_cycles += 12;
 		} else if(inst->addr_mode == Z80_IMMED) {
-			cycles += 3;
+			num_cycles += 3;
 		}
-		dst = zcycles(dst, cycles);
-		dst = translate_z80_reg(inst, &dst_op, dst, opts);
-		dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY);
+		cycles(&opts->gen, num_cycles);
+		translate_z80_reg(inst, &dst_op, opts);
+		translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
 		if (src_op.mode == MODE_REG_DIRECT) {
-			dst = cmp_rr(dst, src_op.base, dst_op.base, z80_size(inst));
+			cmp_rr(code, src_op.base, dst_op.base, z80_size(inst));
 		} else {
-			dst = cmp_ir(dst, src_op.disp, dst_op.base, z80_size(inst));
+			cmp_ir(code, src_op.disp, dst_op.base, z80_size(inst));
 		}
-		dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C));
-		dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_N), SZ_B);
-		dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV));
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
+		setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
 		//TODO: Implement half-carry flag
-		dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z));
-		dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
-		dst = z80_save_reg(dst, inst, opts);
-		dst = z80_save_ea(dst, inst, opts);
+		setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
+		z80_save_reg(inst, opts);
+		z80_save_ea(code, inst, opts);
 		break;
 	case Z80_INC:
-		cycles = 4;
+		num_cycles = 4;
 		if (inst->reg == Z80_IX || inst->reg == Z80_IY) {
-			cycles += 6;
+			num_cycles += 6;
 		} else if(z80_size(inst) == SZ_W) {
-			cycles += 2;
+			num_cycles += 2;
 		} else if(inst->reg == Z80_IXH || inst->reg == Z80_IXL || inst->reg == Z80_IYH || inst->reg == Z80_IYL || inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
-			cycles += 4;
+			num_cycles += 4;
 		}
-		dst = zcycles(dst, cycles);
-		dst = translate_z80_reg(inst, &dst_op, dst, opts);
+		cycles(&opts->gen, num_cycles);
+		translate_z80_reg(inst, &dst_op, opts);
 		if (dst_op.mode == MODE_UNUSED) {
-			dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY);
+			translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
 		}
-		dst = add_ir(dst, 1, dst_op.base, z80_size(inst));
+		add_ir(code, 1, dst_op.base, z80_size(inst));
 		if (z80_size(inst) == SZ_B) {
-			dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
+			mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 			//TODO: Implement half-carry flag
-			dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV));
-			dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z));
-			dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
+			setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
+			setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+			setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		}
-		dst = z80_save_reg(dst, inst, opts);
-		dst = z80_save_ea(dst, inst, opts);
-		dst = z80_save_result(dst, inst);
+		z80_save_reg(inst, opts);
+		z80_save_ea(code, inst, opts);
+		z80_save_result(opts, inst);
 		break;
 	case Z80_DEC:
-		cycles = 4;
+		num_cycles = 4;
 		if (inst->reg == Z80_IX || inst->reg == Z80_IY) {
-			cycles += 6;
+			num_cycles += 6;
 		} else if(z80_size(inst) == SZ_W) {
-			cycles += 2;
+			num_cycles += 2;
 		} else if(inst->reg == Z80_IXH || inst->reg == Z80_IXL || inst->reg == Z80_IYH || inst->reg == Z80_IYL || inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
-			cycles += 4;
+			num_cycles += 4;
 		}
-		dst = zcycles(dst, cycles);
-		dst = translate_z80_reg(inst, &dst_op, dst, opts);
+		cycles(&opts->gen, num_cycles);
+		translate_z80_reg(inst, &dst_op, opts);
 		if (dst_op.mode == MODE_UNUSED) {
-			dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY);
+			translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
 		}
-		dst = sub_ir(dst, 1, dst_op.base, z80_size(inst));
+		sub_ir(code, 1, dst_op.base, z80_size(inst));
 		if (z80_size(inst) == SZ_B) {
-			dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_N), SZ_B);
+			mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 			//TODO: Implement half-carry flag
-			dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV));
-			dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z));
-			dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
+			setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
+			setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+			setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		}
-		dst = z80_save_reg(dst, inst, opts);
-		dst = z80_save_ea(dst, inst, opts);
-		dst = z80_save_result(dst, inst);
+		z80_save_reg(inst, opts);
+		z80_save_ea(code, inst, opts);
+		z80_save_result(opts, inst);
 		break;
 	//case Z80_DAA:
 	case Z80_CPL:
-		dst = zcycles(dst, 4);
-		dst = not_r(dst, opts->regs[Z80_A], SZ_B);
+		cycles(&opts->gen, 4);
+		not_r(code, opts->regs[Z80_A], SZ_B);
 		//TODO: Implement half-carry flag
-		dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_N), SZ_B);
+		mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		break;
 	case Z80_NEG:
-		dst = zcycles(dst, 8);
-		dst = neg_r(dst, opts->regs[Z80_A], SZ_B);
+		cycles(&opts->gen, 8);
+		neg_r(code, opts->regs[Z80_A], SZ_B);
 		//TODO: Implement half-carry flag
-		dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z));
-		dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
-		dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C));
-		dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV));
-		dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_N), SZ_B);
+		setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
+		mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		break;
 	case Z80_CCF:
-		dst = zcycles(dst, 4);
-		dst = xor_irdisp8(dst, 1, CONTEXT, zf_off(ZF_C), SZ_B);
-		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
+		cycles(&opts->gen, 4);
+		xor_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
+		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		//TODO: Implement half-carry flag
 		break;
 	case Z80_SCF:
-		dst = zcycles(dst, 4);
-		dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_C), SZ_B);
-		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
+		cycles(&opts->gen, 4);
+		mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
+		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		//TODO: Implement half-carry flag
 		break;
 	case Z80_NOP:
 		if (inst->immed == 42) {
-			dst = call(dst, (uint8_t *)z80_save_context);
-			dst = mov_rr(dst, CONTEXT, RDI, SZ_Q);
-			dst = jmp(dst, (uint8_t *)z80_print_regs_exit);
+			call(code, opts->gen.save_context);
+			mov_rr(code, opts->gen.context_reg, RDI, SZ_Q);
+			jmp(code, (uint8_t *)z80_print_regs_exit);
 		} else {
-			dst = zcycles(dst, 4 * inst->immed);
+			cycles(&opts->gen, 4 * inst->immed);
 		}
 		break;
-	case Z80_HALT:
-		dst = zcycles(dst, 4);
-		dst = mov_ir(dst, address, SCRATCH1, SZ_W);
-		uint8_t * call_inst = dst;
-		dst = call(dst, (uint8_t *)z80_halt);
-		dst = jmp(dst, call_inst);
+	case Z80_HALT: {
+		cycles(&opts->gen, 4);
+		mov_ir(code, address, opts->gen.scratch1, SZ_W);
+		uint8_t * call_inst = code->cur;
+		mov_rr(code, opts->gen.limit, opts->gen.scratch2, SZ_D);
+		sub_rr(code, opts->gen.cycles, opts->gen.scratch2, SZ_D);
+		and_ir(code, 0xFFFFFFFC, opts->gen.scratch2, SZ_D);
+		add_rr(code, opts->gen.scratch2, opts->gen.cycles, SZ_D);
+		cmp_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D);
+		code_ptr skip_last = code->cur+1;
+		jcc(code, CC_NB, code->cur+2);
+		cycles(&opts->gen, 4);
+		*skip_last = code->cur - (skip_last+1);
+		call(code, opts->gen.handle_cycle_limit_int);
+		jmp(code, call_inst);
 		break;
+	}
 	case Z80_DI:
-		dst = zcycles(dst, 4);
-		dst = mov_irdisp8(dst, 0, CONTEXT, offsetof(z80_context, iff1), SZ_B);
-		dst = mov_irdisp8(dst, 0, CONTEXT, offsetof(z80_context, iff2), SZ_B);
-		dst = mov_rdisp8r(dst, CONTEXT, offsetof(z80_context, sync_cycle), ZLIMIT, SZ_D);
-		dst = mov_irdisp8(dst, 0xFFFFFFFF, CONTEXT, offsetof(z80_context, int_cycle), SZ_D);
+		cycles(&opts->gen, 4);
+		mov_irdisp(code, 0, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B);
+		mov_irdisp(code, 0, opts->gen.context_reg, offsetof(z80_context, iff2), SZ_B);
+		mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, sync_cycle), opts->gen.limit, SZ_D);
+		mov_irdisp(code, 0xFFFFFFFF, opts->gen.context_reg, offsetof(z80_context, int_cycle), SZ_D);
 		break;
 	case Z80_EI:
-		dst = zcycles(dst, 4);
-		dst = mov_rrdisp32(dst, ZCYCLES, CONTEXT, offsetof(z80_context, int_enable_cycle), SZ_D);
-		dst = mov_irdisp8(dst, 1, CONTEXT, offsetof(z80_context, iff1), SZ_B);
-		dst = mov_irdisp8(dst, 1, CONTEXT, offsetof(z80_context, iff2), SZ_B);
+		cycles(&opts->gen, 4);
+		mov_rrdisp(code, opts->gen.cycles, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D);
+		mov_irdisp(code, 1, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B);
+		mov_irdisp(code, 1, opts->gen.context_reg, offsetof(z80_context, iff2), SZ_B);
 		//interrupt enable has a one-instruction latency, minimum instruction duration is 4 cycles
-		dst = add_irdisp32(dst, 4, CONTEXT, offsetof(z80_context, int_enable_cycle), SZ_D);
-		dst = call(dst, (uint8_t *)z80_do_sync);
+		add_irdisp(code, 4, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D);
+		call(code, opts->do_sync);
 		break;
 	case Z80_IM:
-		dst = zcycles(dst, 4);
-		dst = mov_irdisp8(dst, inst->immed, CONTEXT, offsetof(z80_context, im), SZ_B);
+		cycles(&opts->gen, 4);
+		mov_irdisp(code, inst->immed, opts->gen.context_reg, offsetof(z80_context, im), SZ_B);
 		break;
 	case Z80_RLC:
-		cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8);
-		dst = zcycles(dst, cycles);
+		num_cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8);
+		cycles(&opts->gen, num_cycles);
 		if (inst->addr_mode != Z80_UNUSED) {
-			dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY);
-			dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register
-			dst = zcycles(dst, 1);
+			translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
+			translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register
+			cycles(&opts->gen, 1);
 		} else {
 			src_op.mode = MODE_UNUSED;
-			dst = translate_z80_reg(inst, &dst_op, dst, opts);
+			translate_z80_reg(inst, &dst_op, opts);
 		}
-		dst = rol_ir(dst, 1, dst_op.base, SZ_B);
+		rol_ir(code, 1, dst_op.base, SZ_B);
 		if (src_op.mode != MODE_UNUSED) {
-			dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B);
+			mov_rr(code, dst_op.base, src_op.base, SZ_B);
 		}
-		dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C));
-		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		//TODO: Implement half-carry flag
 		if (inst->immed) {
 			//rlca does not set these flags
-			dst = cmp_ir(dst, 0, dst_op.base, SZ_B);
-			dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV));
-			dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z));
-			dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
+		cmp_ir(code, 0, dst_op.base, SZ_B);
+		setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
+		setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		}
 		if (inst->addr_mode != Z80_UNUSED) {
-			dst = z80_save_result(dst, inst);
+			z80_save_result(opts, inst);
 			if (src_op.mode != MODE_UNUSED) {
-				dst = z80_save_reg(dst, inst, opts);
+				z80_save_reg(inst, opts);
 			}
 		} else {
-			dst = z80_save_reg(dst, inst, opts);
+			z80_save_reg(inst, opts);
 		}
 		break;
 	case Z80_RL:
-		cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8);
-		dst = zcycles(dst, cycles);
+		num_cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8);
+		cycles(&opts->gen, num_cycles);
 		if (inst->addr_mode != Z80_UNUSED) {
-			dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY);
-			dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register
-			dst = zcycles(dst, 1);
+			translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
+			translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register
+			cycles(&opts->gen, 1);
 		} else {
 			src_op.mode = MODE_UNUSED;
-			dst = translate_z80_reg(inst, &dst_op, dst, opts);
+			translate_z80_reg(inst, &dst_op, opts);
 		}
-		dst = bt_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B);
-		dst = rcl_ir(dst, 1, dst_op.base, SZ_B);
+		bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
+		rcl_ir(code, 1, dst_op.base, SZ_B);
 		if (src_op.mode != MODE_UNUSED) {
-			dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B);
+			mov_rr(code, dst_op.base, src_op.base, SZ_B);
 		}
-		dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C));
-		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		//TODO: Implement half-carry flag
 		if (inst->immed) {
 			//rla does not set these flags
-			dst = cmp_ir(dst, 0, dst_op.base, SZ_B);
-			dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV));
-			dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z));
-			dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
+		cmp_ir(code, 0, dst_op.base, SZ_B);
+		setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
+		setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		}
 		if (inst->addr_mode != Z80_UNUSED) {
-			dst = z80_save_result(dst, inst);
+			z80_save_result(opts, inst);
 			if (src_op.mode != MODE_UNUSED) {
-				dst = z80_save_reg(dst, inst, opts);
+				z80_save_reg(inst, opts);
 			}
 		} else {
-			dst = z80_save_reg(dst, inst, opts);
+			z80_save_reg(inst, opts);
 		}
 		break;
 	case Z80_RRC:
-		cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8);
-		dst = zcycles(dst, cycles);
+		num_cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8);
+		cycles(&opts->gen, num_cycles);
 		if (inst->addr_mode != Z80_UNUSED) {
-			dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY);
-			dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register
-			dst = zcycles(dst, 1);
+			translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
+			translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register
+			cycles(&opts->gen, 1);
 		} else {
 			src_op.mode = MODE_UNUSED;
-			dst = translate_z80_reg(inst, &dst_op, dst, opts);
+			translate_z80_reg(inst, &dst_op, opts);
 		}
-		dst = ror_ir(dst, 1, dst_op.base, SZ_B);
+		ror_ir(code, 1, dst_op.base, SZ_B);
 		if (src_op.mode != MODE_UNUSED) {
-			dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B);
+			mov_rr(code, dst_op.base, src_op.base, SZ_B);
 		}
-		dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C));
-		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		//TODO: Implement half-carry flag
 		if (inst->immed) {
 			//rrca does not set these flags
-			dst = cmp_ir(dst, 0, dst_op.base, SZ_B);
-			dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV));
-			dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z));
-			dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
+		cmp_ir(code, 0, dst_op.base, SZ_B);
+		setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
+		setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		}
 		if (inst->addr_mode != Z80_UNUSED) {
-			dst = z80_save_result(dst, inst);
+			z80_save_result(opts, inst);
 			if (src_op.mode != MODE_UNUSED) {
-				dst = z80_save_reg(dst, inst, opts);
+				z80_save_reg(inst, opts);
 			}
 		} else {
-			dst = z80_save_reg(dst, inst, opts);
+			z80_save_reg(inst, opts);
 		}
 		break;
 	case Z80_RR:
-		cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8);
-		dst = zcycles(dst, cycles);
+		num_cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8);
+		cycles(&opts->gen, num_cycles);
 		if (inst->addr_mode != Z80_UNUSED) {
-			dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY);
-			dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register
-			dst = zcycles(dst, 1);
+			translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
+			translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register
+			cycles(&opts->gen, 1);
 		} else {
 			src_op.mode = MODE_UNUSED;
-			dst = translate_z80_reg(inst, &dst_op, dst, opts);
+			translate_z80_reg(inst, &dst_op, opts);
 		}
-		dst = bt_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B);
-		dst = rcr_ir(dst, 1, dst_op.base, SZ_B);
+		bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
+		rcr_ir(code, 1, dst_op.base, SZ_B);
 		if (src_op.mode != MODE_UNUSED) {
-			dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B);
+			mov_rr(code, dst_op.base, src_op.base, SZ_B);
 		}
-		dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C));
-		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		//TODO: Implement half-carry flag
 		if (inst->immed) {
 			//rra does not set these flags
-			dst = cmp_ir(dst, 0, dst_op.base, SZ_B);
-			dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV));
-			dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z));
-			dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
+		cmp_ir(code, 0, dst_op.base, SZ_B);
+		setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
+		setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		}
 		if (inst->addr_mode != Z80_UNUSED) {
-			dst = z80_save_result(dst, inst);
+			z80_save_result(opts, inst);
 			if (src_op.mode != MODE_UNUSED) {
-				dst = z80_save_reg(dst, inst, opts);
+				z80_save_reg(inst, opts);
 			}
 		} else {
-			dst = z80_save_reg(dst, inst, opts);
+			z80_save_reg(inst, opts);
 		}
 		break;
 	case Z80_SLA:
 	case Z80_SLL:
-		cycles = inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8;
-		dst = zcycles(dst, cycles);
+		num_cycles = inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8;
+		cycles(&opts->gen, num_cycles);
 		if (inst->addr_mode != Z80_UNUSED) {
-			dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY);
-			dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register
-			dst = zcycles(dst, 1);
+			translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
+			translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register
+			cycles(&opts->gen, 1);
 		} else {
 			src_op.mode = MODE_UNUSED;
-			dst = translate_z80_reg(inst, &dst_op, dst, opts);
+			translate_z80_reg(inst, &dst_op, opts);
 		}
-		dst = shl_ir(dst, 1, dst_op.base, SZ_B);
-		dst  = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C));
+		shl_ir(code, 1, dst_op.base, SZ_B);
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
 		if (inst->op == Z80_SLL) {
-			dst = or_ir(dst, 1, dst_op.base, SZ_B);
+			or_ir(code, 1, dst_op.base, SZ_B);
 		}
 		if (src_op.mode != MODE_UNUSED) {
-			dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B);
+			mov_rr(code, dst_op.base, src_op.base, SZ_B);
 		}
-		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
+		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		//TODO: Implement half-carry flag
-		dst = cmp_ir(dst, 0, dst_op.base, SZ_B);
-		dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV));
-		dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z));
-		dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
+		cmp_ir(code, 0, dst_op.base, SZ_B);
+		setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
+		setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		if (inst->addr_mode != Z80_UNUSED) {
-			dst = z80_save_result(dst, inst);
+			z80_save_result(opts, inst);
 			if (src_op.mode != MODE_UNUSED) {
-				dst = z80_save_reg(dst, inst, opts);
+				z80_save_reg(inst, opts);
 			}
 		} else {
-			dst = z80_save_reg(dst, inst, opts);
+			z80_save_reg(inst, opts);
 		}
 		break;
 	case Z80_SRA:
-		cycles = inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8;
-		dst = zcycles(dst, cycles);
+		num_cycles = inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8;
+		cycles(&opts->gen, num_cycles);
 		if (inst->addr_mode != Z80_UNUSED) {
-			dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY);
-			dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register
-			dst = zcycles(dst, 1);
+			translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
+			translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register
+			cycles(&opts->gen, 1);
 		} else {
 			src_op.mode = MODE_UNUSED;
-			dst = translate_z80_reg(inst, &dst_op, dst, opts);
+			translate_z80_reg(inst, &dst_op, opts);
 		}
-		dst = sar_ir(dst, 1, dst_op.base, SZ_B);
+		sar_ir(code, 1, dst_op.base, SZ_B);
 		if (src_op.mode != MODE_UNUSED) {
-			dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B);
+			mov_rr(code, dst_op.base, src_op.base, SZ_B);
 		}
-		dst  = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C));
-		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		//TODO: Implement half-carry flag
-		dst = cmp_ir(dst, 0, dst_op.base, SZ_B);
-		dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV));
-		dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z));
-		dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
+		cmp_ir(code, 0, dst_op.base, SZ_B);
+		setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
+		setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		if (inst->addr_mode != Z80_UNUSED) {
-			dst = z80_save_result(dst, inst);
+			z80_save_result(opts, inst);
 			if (src_op.mode != MODE_UNUSED) {
-				dst = z80_save_reg(dst, inst, opts);
+				z80_save_reg(inst, opts);
 			}
 		} else {
-			dst = z80_save_reg(dst, inst, opts);
+			z80_save_reg(inst, opts);
 		}
 		break;
 	case Z80_SRL:
-		cycles = inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8;
-		dst = zcycles(dst, cycles);
+		num_cycles = inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8;
+		cycles(&opts->gen, num_cycles);
 		if (inst->addr_mode != Z80_UNUSED) {
-			dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY);
-			dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register
-			dst = zcycles(dst, 1);
+			translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
+			translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register
+			cycles(&opts->gen, 1);
 		} else {
 			src_op.mode = MODE_UNUSED;
-			dst = translate_z80_reg(inst, &dst_op, dst, opts);
+			translate_z80_reg(inst, &dst_op, opts);
 		}
-		dst = shr_ir(dst, 1, dst_op.base, SZ_B);
+		shr_ir(code, 1, dst_op.base, SZ_B);
 		if (src_op.mode != MODE_UNUSED) {
-			dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B);
+			mov_rr(code, dst_op.base, src_op.base, SZ_B);
 		}
-		dst  = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C));
-		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		//TODO: Implement half-carry flag
-		dst = cmp_ir(dst, 0, dst_op.base, SZ_B);
-		dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV));
-		dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z));
-		dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
+		cmp_ir(code, 0, dst_op.base, SZ_B);
+		setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
+		setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		if (inst->addr_mode != Z80_UNUSED) {
-			dst = z80_save_result(dst, inst);
+			z80_save_result(opts, inst);
 			if (src_op.mode != MODE_UNUSED) {
-				dst = z80_save_reg(dst, inst, opts);
+				z80_save_reg(inst, opts);
 			}
 		} else {
-			dst = z80_save_reg(dst, inst, opts);
+			z80_save_reg(inst, opts);
 		}
 		break;
 	case Z80_RLD:
-		dst = zcycles(dst, 8);
-		dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH1, SZ_W);
-		dst = call(dst, (uint8_t *)z80_read_byte);
+		cycles(&opts->gen, 8);
+		mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W);
+		call(code, opts->read_8);
 		//Before: (HL) = 0x12, A = 0x34
 		//After: (HL) = 0x24, A = 0x31
-		dst = mov_rr(dst, opts->regs[Z80_A], SCRATCH2, SZ_B);
-		dst = shl_ir(dst, 4, SCRATCH1, SZ_W);
-		dst = and_ir(dst, 0xF, SCRATCH2, SZ_W);
-		dst = and_ir(dst, 0xFFF, SCRATCH1, SZ_W);
-		dst = and_ir(dst, 0xF0, opts->regs[Z80_A], SZ_B);
-		dst = or_rr(dst, SCRATCH2, SCRATCH1, SZ_W);
-		//SCRATCH1 = 0x0124
-		dst = ror_ir(dst, 8, SCRATCH1, SZ_W);
-		dst = zcycles(dst, 4);
-		dst = or_rr(dst, SCRATCH1, opts->regs[Z80_A], SZ_B);
+		mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
+		shl_ir(code, 4, opts->gen.scratch1, SZ_W);
+		and_ir(code, 0xF, opts->gen.scratch2, SZ_W);
+		and_ir(code, 0xFFF, opts->gen.scratch1, SZ_W);
+		and_ir(code, 0xF0, opts->regs[Z80_A], SZ_B);
+		or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_W);
+		//opts->gen.scratch1 = 0x0124
+		ror_ir(code, 8, opts->gen.scratch1, SZ_W);
+		cycles(&opts->gen, 4);
+		or_rr(code, opts->gen.scratch1, opts->regs[Z80_A], SZ_B);
 		//set flags
 		//TODO: Implement half-carry flag
-		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
-		dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV));
-		dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z));
-		dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
+		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
+		setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
+		setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 
-		dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH2, SZ_W);
-		dst = ror_ir(dst, 8, SCRATCH1, SZ_W);
-		dst = call(dst, (uint8_t *)z80_write_byte);
+		mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W);
+		ror_ir(code, 8, opts->gen.scratch1, SZ_W);
+		call(code, opts->write_8);
 		break;
 	case Z80_RRD:
-		dst = zcycles(dst, 8);
-		dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH1, SZ_W);
-		dst = call(dst, (uint8_t *)z80_read_byte);
+		cycles(&opts->gen, 8);
+		mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W);
+		call(code, opts->read_8);
 		//Before: (HL) = 0x12, A = 0x34
 		//After: (HL) = 0x41, A = 0x32
-		dst = movzx_rr(dst, opts->regs[Z80_A], SCRATCH2, SZ_B, SZ_W);
-		dst = ror_ir(dst, 4, SCRATCH1, SZ_W);
-		dst = shl_ir(dst, 4, SCRATCH2, SZ_W);
-		dst = and_ir(dst, 0xF00F, SCRATCH1, SZ_W);
-		dst = and_ir(dst, 0xF0, opts->regs[Z80_A], SZ_B);
-		//SCRATCH1 = 0x2001
-		//SCRATCH2 = 0x0040
-		dst = or_rr(dst, SCRATCH2, SCRATCH1, SZ_W);
-		//SCRATCH1 = 0x2041
-		dst = ror_ir(dst, 8, SCRATCH1, SZ_W);
-		dst = zcycles(dst, 4);
-		dst = shr_ir(dst, 4, SCRATCH1, SZ_B);
-		dst = or_rr(dst, SCRATCH1, opts->regs[Z80_A], SZ_B);
+		movzx_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B, SZ_W);
+		ror_ir(code, 4, opts->gen.scratch1, SZ_W);
+		shl_ir(code, 4, opts->gen.scratch2, SZ_W);
+		and_ir(code, 0xF00F, opts->gen.scratch1, SZ_W);
+		and_ir(code, 0xF0, opts->regs[Z80_A], SZ_B);
+		//opts->gen.scratch1 = 0x2001
+		//opts->gen.scratch2 = 0x0040
+		or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_W);
+		//opts->gen.scratch1 = 0x2041
+		ror_ir(code, 8, opts->gen.scratch1, SZ_W);
+		cycles(&opts->gen, 4);
+		shr_ir(code, 4, opts->gen.scratch1, SZ_B);
+		or_rr(code, opts->gen.scratch1, opts->regs[Z80_A], SZ_B);
 		//set flags
 		//TODO: Implement half-carry flag
-		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
-		dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV));
-		dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z));
-		dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
+		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
+		setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
+		setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 
-		dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH2, SZ_W);
-		dst = ror_ir(dst, 8, SCRATCH1, SZ_W);
-		dst = call(dst, (uint8_t *)z80_write_byte);
+		mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W);
+		ror_ir(code, 8, opts->gen.scratch1, SZ_W);
+		call(code, opts->write_8);
 		break;
 	case Z80_BIT: {
-		cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16;
-		dst = zcycles(dst, cycles);
+		num_cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16;
+		cycles(&opts->gen, num_cycles);
 		uint8_t bit;
 		if ((inst->addr_mode & 0x1F) == Z80_REG && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) {
 			src_op.base = opts->regs[z80_word_reg(inst->ea_reg)];
@@ -1244,27 +1221,27 @@
 		} else {
 			size = SZ_B;
 			bit = inst->immed;
-			dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY);
+			translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
 		}
 		if (inst->addr_mode != Z80_REG) {
 			//Reads normally take 3 cycles, but the read at the end of a bit instruction takes 4
-			dst = zcycles(dst, 1);
+			cycles(&opts->gen, 1);
 		}
-		dst = bt_ir(dst, bit, src_op.base, size);
-		dst = setcc_rdisp8(dst, CC_NC, CONTEXT, zf_off(ZF_Z));
-		dst = setcc_rdisp8(dst, CC_NC, CONTEXT, zf_off(ZF_PV));
-		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
+		bt_ir(code, bit, src_op.base, size);
+		setcc_rdisp(code, CC_NC, opts->gen.context_reg, zf_off(ZF_Z));
+		setcc_rdisp(code, CC_NC, opts->gen.context_reg, zf_off(ZF_PV));
+		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		if (inst->immed == 7) {
-			dst = cmp_ir(dst, 0, src_op.base, size);
-			dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
+			cmp_ir(code, 0, src_op.base, size);
+			setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		} else {
-			dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_S), SZ_B);
+			mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B);
 		}
 		break;
 	}
 	case Z80_SET: {
-		cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16;
-		dst = zcycles(dst, cycles);
+		num_cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16;
+		cycles(&opts->gen, num_cycles);
 		uint8_t bit;
 		if ((inst->addr_mode & 0x1F) == Z80_REG && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) {
 			src_op.base = opts->regs[z80_word_reg(inst->ea_reg)];
@@ -1273,40 +1250,40 @@
 		} else {
 			size = SZ_B;
 			bit = inst->immed;
-			dst = translate_z80_ea(inst, &src_op, dst, opts, READ, MODIFY);
+			translate_z80_ea(inst, &src_op, opts, READ, MODIFY);
 		}
 		if (inst->reg != Z80_USE_IMMED) {
-			dst = translate_z80_reg(inst, &dst_op, dst, opts);
+			translate_z80_reg(inst, &dst_op, opts);
 		}
 		if (inst->addr_mode != Z80_REG) {
 			//Reads normally take 3 cycles, but the read in the middle of a set instruction takes 4
-			dst = zcycles(dst, 1);
+			cycles(&opts->gen, 1);
 		}
-		dst = bts_ir(dst, bit, src_op.base, size);
+		bts_ir(code, bit, src_op.base, size);
 		if (inst->reg != Z80_USE_IMMED) {
 			if (size == SZ_W) {
 				if (dst_op.base >= R8) {
-					dst = ror_ir(dst, 8, src_op.base, SZ_W);
-					dst = mov_rr(dst, opts->regs[z80_low_reg(inst->ea_reg)], dst_op.base, SZ_B);
-					dst = ror_ir(dst, 8, src_op.base, SZ_W);
+					ror_ir(code, 8, src_op.base, SZ_W);
+					mov_rr(code, opts->regs[z80_low_reg(inst->ea_reg)], dst_op.base, SZ_B);
+					ror_ir(code, 8, src_op.base, SZ_W);
 				} else {
-					dst = mov_rr(dst, opts->regs[inst->ea_reg], dst_op.base, SZ_B);
+					mov_rr(code, opts->regs[inst->ea_reg], dst_op.base, SZ_B);
 				}
 			} else {
-				dst = mov_rr(dst, src_op.base, dst_op.base, SZ_B);
+				mov_rr(code, src_op.base, dst_op.base, SZ_B);
 			}
 		}
 		if ((inst->addr_mode & 0x1F) != Z80_REG) {
-			dst = z80_save_result(dst, inst);
+			z80_save_result(opts, inst);
 			if (inst->reg != Z80_USE_IMMED) {
-				dst = z80_save_reg(dst, inst, opts);
+				z80_save_reg(inst, opts);
 			}
 		}
 		break;
 	}
 	case Z80_RES: {
-		cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16;
-		dst = zcycles(dst, cycles);
+		num_cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16;
+		cycles(&opts->gen, num_cycles);
 		uint8_t bit;
 		if ((inst->addr_mode & 0x1F) == Z80_REG && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) {
 			src_op.base = opts->regs[z80_word_reg(inst->ea_reg)];
@@ -1315,361 +1292,361 @@
 		} else {
 			size = SZ_B;
 			bit = inst->immed;
-			dst = translate_z80_ea(inst, &src_op, dst, opts, READ, MODIFY);
+			translate_z80_ea(inst, &src_op, opts, READ, MODIFY);
 		}
 		if (inst->reg != Z80_USE_IMMED) {
-			dst = translate_z80_reg(inst, &dst_op, dst, opts);
+			translate_z80_reg(inst, &dst_op, opts);
 		}
 		if (inst->addr_mode != Z80_REG) {
 			//Reads normally take 3 cycles, but the read in the middle of a set instruction takes 4
-			dst = zcycles(dst, 1);
+			cycles(&opts->gen, 1);
 		}
-		dst = btr_ir(dst, bit, src_op.base, size);
+		btr_ir(code, bit, src_op.base, size);
 		if (inst->reg != Z80_USE_IMMED) {
 			if (size == SZ_W) {
 				if (dst_op.base >= R8) {
-					dst = ror_ir(dst, 8, src_op.base, SZ_W);
-					dst = mov_rr(dst, opts->regs[z80_low_reg(inst->ea_reg)], dst_op.base, SZ_B);
-					dst = ror_ir(dst, 8, src_op.base, SZ_W);
+					ror_ir(code, 8, src_op.base, SZ_W);
+					mov_rr(code, opts->regs[z80_low_reg(inst->ea_reg)], dst_op.base, SZ_B);
+					ror_ir(code, 8, src_op.base, SZ_W);
 				} else {
-					dst = mov_rr(dst, opts->regs[inst->ea_reg], dst_op.base, SZ_B);
+					mov_rr(code, opts->regs[inst->ea_reg], dst_op.base, SZ_B);
 				}
 			} else {
-				dst = mov_rr(dst, src_op.base, dst_op.base, SZ_B);
+				mov_rr(code, src_op.base, dst_op.base, SZ_B);
 			}
 		}
 		if (inst->addr_mode != Z80_REG) {
-			dst = z80_save_result(dst, inst);
+			z80_save_result(opts, inst);
 			if (inst->reg != Z80_USE_IMMED) {
-				dst = z80_save_reg(dst, inst, opts);
+				z80_save_reg(inst, opts);
 			}
 		}
 		break;
 	}
 	case Z80_JP: {
-		cycles = 4;
+		num_cycles = 4;
 		if (inst->addr_mode != Z80_REG_INDIRECT) {
-			cycles += 6;
+			num_cycles += 6;
 		} else if(inst->ea_reg == Z80_IX || inst->ea_reg == Z80_IY) {
-			cycles += 4;
+			num_cycles += 4;
 		}
-		dst = zcycles(dst, cycles);
+		cycles(&opts->gen, num_cycles);
 		if (inst->addr_mode != Z80_REG_INDIRECT && inst->immed < 0x4000) {
-			uint8_t * call_dst = z80_get_native_address(context, inst->immed);
+			code_ptr call_dst = z80_get_native_address(context, inst->immed);
 			if (!call_dst) {
-				opts->deferred = defer_address(opts->deferred, inst->immed, dst + 1);
+				opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1);
 				//fake address to force large displacement
-				call_dst = dst + 256;
+				call_dst = code->cur + 256;
 			}
-			dst = jmp(dst, call_dst);
+			jmp(code, call_dst);
 		} else {
 			if (inst->addr_mode == Z80_REG_INDIRECT) {
-				dst = mov_rr(dst, opts->regs[inst->ea_reg], SCRATCH1, SZ_W);
+				mov_rr(code, opts->regs[inst->ea_reg], opts->gen.scratch1, SZ_W);
 			} else {
-				dst = mov_ir(dst, inst->immed, SCRATCH1, SZ_W);
+				mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W);
 			}
-			dst = call(dst, (uint8_t *)z80_native_addr);
-			dst = jmp_r(dst, SCRATCH1);
+			call(code, opts->native_addr);
+			jmp_r(code, opts->gen.scratch1);
 		}
 		break;
 	}
 	case Z80_JPCC: {
-		dst = zcycles(dst, 7);//T States: 4,3
+		cycles(&opts->gen, 7);//T States: 4,3
 		uint8_t cond = CC_Z;
 		switch (inst->reg)
 		{
 		case Z80_CC_NZ:
 			cond = CC_NZ;
 		case Z80_CC_Z:
-			dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_Z), SZ_B);
+			cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B);
 			break;
 		case Z80_CC_NC:
 			cond = CC_NZ;
 		case Z80_CC_C:
-			dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B);
+			cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
 			break;
 		case Z80_CC_PO:
 			cond = CC_NZ;
 		case Z80_CC_PE:
-			dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_PV), SZ_B);
+			cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B);
 			break;
 		case Z80_CC_P:
 			cond = CC_NZ;
 		case Z80_CC_M:
-			dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_S), SZ_B);
+			cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B);
 			break;
 		}
-		uint8_t *no_jump_off = dst+1;
-		dst = jcc(dst, cond, dst+2);
-		dst = zcycles(dst, 5);//T States: 5
+		uint8_t *no_jump_off = code->cur+1;
+		jcc(code, cond, code->cur+2);
+		cycles(&opts->gen, 5);//T States: 5
 		uint16_t dest_addr = inst->immed;
 		if (dest_addr < 0x4000) {
-			uint8_t * call_dst = z80_get_native_address(context, dest_addr);
+			code_ptr call_dst = z80_get_native_address(context, dest_addr);
 			if (!call_dst) {
-				opts->deferred = defer_address(opts->deferred, dest_addr, dst + 1);
+				opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1);
 				//fake address to force large displacement
-				call_dst = dst + 256;
+				call_dst = code->cur + 256;
 			}
-			dst = jmp(dst, call_dst);
+			jmp(code, call_dst);
 		} else {
-			dst = mov_ir(dst, dest_addr, SCRATCH1, SZ_W);
-			dst = call(dst, (uint8_t *)z80_native_addr);
-			dst = jmp_r(dst, SCRATCH1);
+			mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W);
+			call(code, opts->native_addr);
+			jmp_r(code, opts->gen.scratch1);
 		}
-		*no_jump_off = dst - (no_jump_off+1);
+		*no_jump_off = code->cur - (no_jump_off+1);
 		break;
 	}
 	case Z80_JR: {
-		dst = zcycles(dst, 12);//T States: 4,3,5
+		cycles(&opts->gen, 12);//T States: 4,3,5
 		uint16_t dest_addr = address + inst->immed + 2;
 		if (dest_addr < 0x4000) {
-			uint8_t * call_dst = z80_get_native_address(context, dest_addr);
+			code_ptr call_dst = z80_get_native_address(context, dest_addr);
 			if (!call_dst) {
-				opts->deferred = defer_address(opts->deferred, dest_addr, dst + 1);
+				opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1);
 				//fake address to force large displacement
-				call_dst = dst + 256;
+				call_dst = code->cur + 256;
 			}
-			dst = jmp(dst, call_dst);
+			jmp(code, call_dst);
 		} else {
-			dst = mov_ir(dst, dest_addr, SCRATCH1, SZ_W);
-			dst = call(dst, (uint8_t *)z80_native_addr);
-			dst = jmp_r(dst, SCRATCH1);
+			mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W);
+			call(code, opts->native_addr);
+			jmp_r(code, opts->gen.scratch1);
 		}
 		break;
 	}
 	case Z80_JRCC: {
-		dst = zcycles(dst, 7);//T States: 4,3
+		cycles(&opts->gen, 7);//T States: 4,3
 		uint8_t cond = CC_Z;
 		switch (inst->reg)
 		{
 		case Z80_CC_NZ:
 			cond = CC_NZ;
 		case Z80_CC_Z:
-			dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_Z), SZ_B);
+			cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B);
 			break;
 		case Z80_CC_NC:
 			cond = CC_NZ;
 		case Z80_CC_C:
-			dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B);
+			cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
 			break;
 		}
-		uint8_t *no_jump_off = dst+1;
-		dst = jcc(dst, cond, dst+2);
-		dst = zcycles(dst, 5);//T States: 5
+		uint8_t *no_jump_off = code->cur+1;
+		jcc(code, cond, code->cur+2);
+		cycles(&opts->gen, 5);//T States: 5
 		uint16_t dest_addr = address + inst->immed + 2;
 		if (dest_addr < 0x4000) {
-			uint8_t * call_dst = z80_get_native_address(context, dest_addr);
+			code_ptr call_dst = z80_get_native_address(context, dest_addr);
 			if (!call_dst) {
-				opts->deferred = defer_address(opts->deferred, dest_addr, dst + 1);
+				opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1);
 				//fake address to force large displacement
-				call_dst = dst + 256;
+				call_dst = code->cur + 256;
 			}
-			dst = jmp(dst, call_dst);
+			jmp(code, call_dst);
 		} else {
-			dst = mov_ir(dst, dest_addr, SCRATCH1, SZ_W);
-			dst = call(dst, (uint8_t *)z80_native_addr);
-			dst = jmp_r(dst, SCRATCH1);
+			mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W);
+			call(code, opts->native_addr);
+			jmp_r(code, opts->gen.scratch1);
 		}
-		*no_jump_off = dst - (no_jump_off+1);
+		*no_jump_off = code->cur - (no_jump_off+1);
 		break;
 	}
 	case Z80_DJNZ:
-		dst = zcycles(dst, 8);//T States: 5,3
-		dst = sub_ir(dst, 1, opts->regs[Z80_B], SZ_B);
-		uint8_t *no_jump_off = dst+1;
-		dst = jcc(dst, CC_Z, dst+2);
-		dst = zcycles(dst, 5);//T States: 5
+		cycles(&opts->gen, 8);//T States: 5,3
+		sub_ir(code, 1, opts->regs[Z80_B], SZ_B);
+		uint8_t *no_jump_off = code->cur+1;
+		jcc(code, CC_Z, code->cur+2);
+		cycles(&opts->gen, 5);//T States: 5
 		uint16_t dest_addr = address + inst->immed + 2;
 		if (dest_addr < 0x4000) {
-			uint8_t * call_dst = z80_get_native_address(context, dest_addr);
+			code_ptr call_dst = z80_get_native_address(context, dest_addr);
 			if (!call_dst) {
-				opts->deferred = defer_address(opts->deferred, dest_addr, dst + 1);
+				opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1);
 				//fake address to force large displacement
-				call_dst = dst + 256;
+				call_dst = code->cur + 256;
 			}
-			dst = jmp(dst, call_dst);
+			jmp(code, call_dst);
 		} else {
-			dst = mov_ir(dst, dest_addr, SCRATCH1, SZ_W);
-			dst = call(dst, (uint8_t *)z80_native_addr);
-			dst = jmp_r(dst, SCRATCH1);
+			mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W);
+			call(code, opts->native_addr);
+			jmp_r(code, opts->gen.scratch1);
 		}
-		*no_jump_off = dst - (no_jump_off+1);
+		*no_jump_off = code->cur - (no_jump_off+1);
 		break;
 	case Z80_CALL: {
-		dst = zcycles(dst, 11);//T States: 4,3,4
-		dst = sub_ir(dst, 2, opts->regs[Z80_SP], SZ_W);
-		dst = mov_ir(dst, address + 3, SCRATCH1, SZ_W);
-		dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH2, SZ_W);
-		dst = call(dst, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3
+		cycles(&opts->gen, 11);//T States: 4,3,4
+		sub_ir(code, 2, opts->regs[Z80_SP], SZ_W);
+		mov_ir(code, address + 3, opts->gen.scratch1, SZ_W);
+		mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
+		call(code, opts->write_16_highfirst);//T States: 3, 3
 		if (inst->immed < 0x4000) {
-			uint8_t * call_dst = z80_get_native_address(context, inst->immed);
+			code_ptr call_dst = z80_get_native_address(context, inst->immed);
 			if (!call_dst) {
-				opts->deferred = defer_address(opts->deferred, inst->immed, dst + 1);
+				opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1);
 				//fake address to force large displacement
-				call_dst = dst + 256;
+				call_dst = code->cur + 256;
 			}
-			dst = jmp(dst, call_dst);
+			jmp(code, call_dst);
 		} else {
-			dst = mov_ir(dst, inst->immed, SCRATCH1, SZ_W);
-			dst = call(dst, (uint8_t *)z80_native_addr);
-			dst = jmp_r(dst, SCRATCH1);
+			mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W);
+			call(code, opts->native_addr);
+			jmp_r(code, opts->gen.scratch1);
 		}
 		break;
 	}
 	case Z80_CALLCC:
-		dst = zcycles(dst, 10);//T States: 4,3,3 (false case)
+		cycles(&opts->gen, 10);//T States: 4,3,3 (false case)
 		uint8_t cond = CC_Z;
 		switch (inst->reg)
 		{
 		case Z80_CC_NZ:
 			cond = CC_NZ;
 		case Z80_CC_Z:
-			dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_Z), SZ_B);
+			cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B);
 			break;
 		case Z80_CC_NC:
 			cond = CC_NZ;
 		case Z80_CC_C:
-			dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B);
+			cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
 			break;
 		case Z80_CC_PO:
 			cond = CC_NZ;
 		case Z80_CC_PE:
-			dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_PV), SZ_B);
+			cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B);
 			break;
 		case Z80_CC_P:
 			cond = CC_NZ;
 		case Z80_CC_M:
-			dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_S), SZ_B);
+			cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B);
 			break;
 		}
-		uint8_t *no_call_off = dst+1;
-		dst = jcc(dst, cond, dst+2);
-		dst = zcycles(dst, 1);//Last of the above T states takes an extra cycle in the true case
-		dst = sub_ir(dst, 2, opts->regs[Z80_SP], SZ_W);
-		dst = mov_ir(dst, address + 3, SCRATCH1, SZ_W);
-		dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH2, SZ_W);
-		dst = call(dst, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3
+		uint8_t *no_call_off = code->cur+1;
+		jcc(code, cond, code->cur+2);
+		cycles(&opts->gen, 1);//Last of the above T states takes an extra cycle in the true case
+		sub_ir(code, 2, opts->regs[Z80_SP], SZ_W);
+		mov_ir(code, address + 3, opts->gen.scratch1, SZ_W);
+		mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
+		call(code, opts->write_16_highfirst);//T States: 3, 3
 		if (inst->immed < 0x4000) {
-			uint8_t * call_dst = z80_get_native_address(context, inst->immed);
+			code_ptr call_dst = z80_get_native_address(context, inst->immed);
 			if (!call_dst) {
-				opts->deferred = defer_address(opts->deferred, inst->immed, dst + 1);
+				opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1);
 				//fake address to force large displacement
-				call_dst = dst + 256;
+				call_dst = code->cur + 256;
 			}
-			dst = jmp(dst, call_dst);
+			jmp(code, call_dst);
 		} else {
-			dst = mov_ir(dst, inst->immed, SCRATCH1, SZ_W);
-			dst = call(dst, (uint8_t *)z80_native_addr);
-			dst = jmp_r(dst, SCRATCH1);
+			mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W);
+			call(code, opts->native_addr);
+			jmp_r(code, opts->gen.scratch1);
 		}
-		*no_call_off = dst - (no_call_off+1);
+		*no_call_off = code->cur - (no_call_off+1);
 		break;
 	case Z80_RET:
-		dst = zcycles(dst, 4);//T States: 4
-		dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, SZ_W);
-		dst = call(dst, (uint8_t *)z80_read_word);//T STates: 3, 3
-		dst = add_ir(dst, 2, opts->regs[Z80_SP], SZ_W);
-		dst = call(dst, (uint8_t *)z80_native_addr);
-		dst = jmp_r(dst, SCRATCH1);
+		cycles(&opts->gen, 4);//T States: 4
+		mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
+		call(code, opts->read_16);//T STates: 3, 3
+		add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
+		call(code, opts->native_addr);
+		jmp_r(code, opts->gen.scratch1);
 		break;
 	case Z80_RETCC: {
-		dst = zcycles(dst, 5);//T States: 5
+		cycles(&opts->gen, 5);//T States: 5
 		uint8_t cond = CC_Z;
 		switch (inst->reg)
 		{
 		case Z80_CC_NZ:
 			cond = CC_NZ;
 		case Z80_CC_Z:
-			dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_Z), SZ_B);
+			cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B);
 			break;
 		case Z80_CC_NC:
 			cond = CC_NZ;
 		case Z80_CC_C:
-			dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B);
+			cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
 			break;
 		case Z80_CC_PO:
 			cond = CC_NZ;
 		case Z80_CC_PE:
-			dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_PV), SZ_B);
+			cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B);
 			break;
 		case Z80_CC_P:
 			cond = CC_NZ;
 		case Z80_CC_M:
-			dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_S), SZ_B);
+			cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B);
 			break;
 		}
-		uint8_t *no_call_off = dst+1;
-		dst = jcc(dst, cond, dst+2);
-		dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, SZ_W);
-		dst = call(dst, (uint8_t *)z80_read_word);//T STates: 3, 3
-		dst = add_ir(dst, 2, opts->regs[Z80_SP], SZ_W);
-		dst = call(dst, (uint8_t *)z80_native_addr);
-		dst = jmp_r(dst, SCRATCH1);
-		*no_call_off = dst - (no_call_off+1);
+		uint8_t *no_call_off = code->cur+1;
+		jcc(code, cond, code->cur+2);
+		mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
+		call(code, opts->read_16);//T STates: 3, 3
+		add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
+		call(code, opts->native_addr);
+		jmp_r(code, opts->gen.scratch1);
+		*no_call_off = code->cur - (no_call_off+1);
 		break;
 	}
 	case Z80_RETI:
 		//For some systems, this may need a callback for signalling interrupt routine completion
-		dst = zcycles(dst, 8);//T States: 4, 4
-		dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, SZ_W);
-		dst = call(dst, (uint8_t *)z80_read_word);//T STates: 3, 3
-		dst = add_ir(dst, 2, opts->regs[Z80_SP], SZ_W);
-		dst = call(dst, (uint8_t *)z80_native_addr);
-		dst = jmp_r(dst, SCRATCH1);
+		cycles(&opts->gen, 8);//T States: 4, 4
+		mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
+		call(code, opts->read_16);//T STates: 3, 3
+		add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
+		call(code, opts->native_addr);
+		jmp_r(code, opts->gen.scratch1);
 		break;
 	case Z80_RETN:
-		dst = zcycles(dst, 8);//T States: 4, 4
-		dst = mov_rdisp8r(dst, CONTEXT, offsetof(z80_context, iff2), SCRATCH2, SZ_B);
-		dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, SZ_W);
-		dst = mov_rrdisp8(dst, SCRATCH2, CONTEXT, offsetof(z80_context, iff1), SZ_B);
-		dst = call(dst, (uint8_t *)z80_read_word);//T STates: 3, 3
-		dst = add_ir(dst, 2, opts->regs[Z80_SP], SZ_W);
-		dst = call(dst, (uint8_t *)z80_native_addr);
-		dst = jmp_r(dst, SCRATCH1);
+		cycles(&opts->gen, 8);//T States: 4, 4
+		mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, iff2), opts->gen.scratch2, SZ_B);
+		mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
+		mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B);
+		call(code, opts->read_16);//T STates: 3, 3
+		add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
+		call(code, opts->native_addr);
+		jmp_r(code, opts->gen.scratch1);
 		break;
 	case Z80_RST: {
 		//RST is basically CALL to an address in page 0
-		dst = zcycles(dst, 5);//T States: 5
-		dst = sub_ir(dst, 2, opts->regs[Z80_SP], SZ_W);
-		dst = mov_ir(dst, address + 1, SCRATCH1, SZ_W);
-		dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH2, SZ_W);
-		dst = call(dst, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3
-		uint8_t * call_dst = z80_get_native_address(context, inst->immed);
+		cycles(&opts->gen, 5);//T States: 5
+		sub_ir(code, 2, opts->regs[Z80_SP], SZ_W);
+		mov_ir(code, address + 1, opts->gen.scratch1, SZ_W);
+		mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
+		call(code, opts->write_16_highfirst);//T States: 3, 3
+		code_ptr call_dst = z80_get_native_address(context, inst->immed);
 		if (!call_dst) {
-			opts->deferred = defer_address(opts->deferred, inst->immed, dst + 1);
+			opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1);
 			//fake address to force large displacement
-			call_dst = dst + 256;
+			call_dst = code->cur + 256;
 		}
-		dst = jmp(dst, call_dst);
+		jmp(code, call_dst);
 		break;
 	}
 	case Z80_IN:
-		dst = zcycles(dst, inst->reg == Z80_A ? 7 : 8);//T States: 4 3/4
+		cycles(&opts->gen, inst->reg == Z80_A ? 7 : 8);//T States: 4 3/4
 		if (inst->addr_mode == Z80_IMMED_INDIRECT) {
-			dst = mov_ir(dst, inst->immed, SCRATCH1, SZ_B);
+			mov_ir(code, inst->immed, opts->gen.scratch1, SZ_B);
 		} else {
-			dst = mov_rr(dst, opts->regs[Z80_C], SCRATCH1, SZ_B);
+			mov_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
 		}
-		dst = call(dst, (uint8_t *)z80_io_read);
-		translate_z80_reg(inst, &dst_op, dst, opts);
-		dst = mov_rr(dst, SCRATCH1, dst_op.base, SZ_B);
-		dst = z80_save_reg(dst, inst, opts);
+		call(code, opts->read_io);
+		translate_z80_reg(inst, &dst_op, opts);
+		mov_rr(code, opts->gen.scratch1, dst_op.base, SZ_B);
+		z80_save_reg(inst, opts);
 		break;
 	/*case Z80_INI:
 	case Z80_INIR:
 	case Z80_IND:
 	case Z80_INDR:*/
 	case Z80_OUT:
-		dst = zcycles(dst, inst->reg == Z80_A ? 7 : 8);//T States: 4 3/4
+		cycles(&opts->gen, inst->reg == Z80_A ? 7 : 8);//T States: 4 3/4
 		if ((inst->addr_mode & 0x1F) == Z80_IMMED_INDIRECT) {
-			dst = mov_ir(dst, inst->immed, SCRATCH2, SZ_B);
+			mov_ir(code, inst->immed, opts->gen.scratch2, SZ_B);
 		} else {
-			dst = mov_rr(dst, opts->regs[Z80_C], SCRATCH2, SZ_B);
+			mov_rr(code, opts->regs[Z80_C], opts->gen.scratch2, SZ_B);
 		}
-		translate_z80_reg(inst, &src_op, dst, opts);
-		dst = mov_rr(dst, dst_op.base, SCRATCH1, SZ_B);
-		dst = call(dst, (uint8_t *)z80_io_write);
-		dst = z80_save_reg(dst, inst, opts);
+		translate_z80_reg(inst, &src_op, opts);
+		mov_rr(code, dst_op.base, opts->gen.scratch1, SZ_B);
+		call(code, opts->write_io);
+		z80_save_reg(inst, opts);
 		break;
 	/*case Z80_OUTI:
 	case Z80_OTIR:
@@ -1685,7 +1662,6 @@
 		exit(1);
 	}
 	}
-	return dst;
 }
 
 uint8_t * z80_interp_handler(uint8_t opcode, z80_context * context)
@@ -1704,45 +1680,45 @@
 			fprintf(stderr, "Encountered multi-byte Z80 instruction at %X. Z80 interpeter doesn't support those yet.", context->pc);
 			exit(1);
 		}
-		x86_z80_options * opts = context->options;
-		if (opts->code_end - opts->cur_code < ZMAX_NATIVE_SIZE) {
-			size_t size = 1024*1024;
-			opts->cur_code = alloc_code(&size);
-			opts->code_end = opts->cur_code + size;
-		}
-		context->interp_code[opcode] = opts->cur_code;
-		opts->cur_code = translate_z80inst(&inst, opts->cur_code, context, 0, 1);
-		opts->cur_code = mov_rdisp8r(opts->cur_code, CONTEXT, offsetof(z80_context, pc), SCRATCH1, SZ_W);
-		opts->cur_code = add_ir(opts->cur_code, after - codebuf, SCRATCH1, SZ_W);
-		opts->cur_code = call(opts->cur_code, (uint8_t *)z80_native_addr);
-		opts->cur_code = jmp_r(opts->cur_code, SCRATCH1);
+
+		z80_options * opts = context->options;
+		code_info *code = &opts->gen.code;
+		check_alloc_code(code, ZMAX_NATIVE_SIZE);
+		context->interp_code[opcode] = code->cur;
+		translate_z80inst(&inst, context, 0, 1);
+		mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, pc), opts->gen.scratch1, SZ_W);
+		add_ir(code, after - codebuf, opts->gen.scratch1, SZ_W);
+		call(code, opts->native_addr);
+		jmp_r(code, opts->gen.scratch1);
 	}
 	return context->interp_code[opcode];
 }
 
-uint8_t * z80_make_interp_stub(z80_context * context, uint16_t address)
+code_info z80_make_interp_stub(z80_context * context, uint16_t address)
 {
-	x86_z80_options *opts = context->options;
-	uint8_t *dst = opts->cur_code;
+	z80_options *opts = context->options;
+	code_info * code = &opts->gen.code;
+	check_alloc_code(code, 32);
+	code_info stub = {code->cur, NULL};
 	//TODO: make this play well with the breakpoint code
-	dst = mov_ir(dst, address, SCRATCH1, SZ_W);
-	dst = call(dst, (uint8_t *)z80_read_byte);
+	mov_ir(code, address, opts->gen.scratch1, SZ_W);
+	call(code, opts->read_8);
 	//normal opcode fetch is already factored into instruction timing
 	//back out the base 3 cycles from a read here
 	//not quite perfect, but it will have to do for now
-	dst = sub_ir(dst, 3, ZCYCLES, SZ_D);
-	dst = z80_check_cycles_int(dst, address);
-	dst = call(dst, (uint8_t *)z80_save_context);
-	dst = mov_rr(dst, SCRATCH1, RDI, SZ_B);
-	dst = mov_irdisp8(dst, address, CONTEXT, offsetof(z80_context, pc), SZ_W);
-	dst = push_r(dst, CONTEXT);
-	dst = call(dst, (uint8_t *)z80_interp_handler);
-	dst = mov_rr(dst, RAX, SCRATCH1, SZ_Q);
-	dst = pop_r(dst, CONTEXT);
-	dst = call(dst, (uint8_t *)z80_load_context);
-	dst = jmp_r(dst, SCRATCH1);
-	opts->code_end = dst;
-	return dst;
+	cycles(&opts->gen, -3);
+	check_cycles_int(&opts->gen, address);
+	call(code, opts->gen.save_context);
+	mov_rr(code, opts->gen.scratch1, RDI, SZ_B);
+	mov_irdisp(code, address, opts->gen.context_reg, offsetof(z80_context, pc), SZ_W);
+	push_r(code, opts->gen.context_reg);
+	call(code, (code_ptr)z80_interp_handler);
+	mov_rr(code, RAX, opts->gen.scratch1, SZ_Q);
+	pop_r(code, opts->gen.context_reg);
+	call(code, opts->gen.load_context);
+	jmp_r(code, opts->gen.scratch1);
+	stub.last = code->cur;
+	return stub;
 }
 
 
@@ -1764,24 +1740,24 @@
 	return map->base + map->offsets[address];
 }
 
-uint8_t z80_get_native_inst_size(x86_z80_options * opts, uint32_t address)
+uint8_t z80_get_native_inst_size(z80_options * opts, uint32_t address)
 {
 	//TODO: Fix for addresses >= 0x4000
 	if (address >= 0x4000) {
 		return 0;
 	}
-	return opts->ram_inst_sizes[address & 0x1FFF];
+	return opts->gen.ram_inst_sizes[0][address & 0x1FFF];
 }
 
 void z80_map_native_address(z80_context * context, uint32_t address, uint8_t * native_address, uint8_t size, uint8_t native_size)
 {
 	uint32_t orig_address = address;
 	native_map_slot *map;
-	x86_z80_options * opts = context->options;
+	z80_options * opts = context->options;
 	if (address < 0x4000) {
 		address &= 0x1FFF;
 		map = context->static_code_map;
-		opts->ram_inst_sizes[address] = native_size;
+		opts->gen.ram_inst_sizes[0][address] = native_size;
 		context->ram_code_flags[(address & 0x1C00) >> 10] |= 1 << ((address & 0x380) >> 7);
 		context->ram_code_flags[((address + size) & 0x1C00) >> 10] |= 1 << (((address + size) & 0x380) >> 7);
 	} else {
@@ -1837,10 +1813,12 @@
 {
 	uint32_t inst_start = z80_get_instruction_start(context->static_code_map, address);
 	if (inst_start != INVALID_INSTRUCTION_START) {
-		uint8_t * dst = z80_get_native_address(context, inst_start);
-		dprintf("patching code at %p for Z80 instruction at %X due to write to %X\n", dst, inst_start, address);
-		dst = mov_ir(dst, inst_start, SCRATCH1, SZ_D);
-		dst = call(dst, (uint8_t *)z80_retrans_stub);
+		code_ptr dst = z80_get_native_address(context, inst_start);
+		code_info code = {dst, dst+16};
+		z80_options * opts = context->options;
+		dprintf("patching code at %p for Z80 instruction at %X due to write to %X\n", code, inst_start, address);
+		mov_ir(&code, inst_start, opts->gen.scratch1, SZ_D);
+		call(&code, opts->retrans_stub);
 	}
 	return context;
 }
@@ -1860,22 +1838,21 @@
 
 void z80_handle_deferred(z80_context * context)
 {
-	x86_z80_options * opts = context->options;
-	process_deferred(&opts->deferred, context, (native_addr_func)z80_get_native_address);
-	if (opts->deferred) {
-		translate_z80_stream(context, opts->deferred->address);
+	z80_options * opts = context->options;
+	process_deferred(&opts->gen.deferred, context, (native_addr_func)z80_get_native_address);
+	if (opts->gen.deferred) {
+		translate_z80_stream(context, opts->gen.deferred->address);
 	}
 }
 
 void * z80_retranslate_inst(uint32_t address, z80_context * context, uint8_t * orig_start)
 {
 	char disbuf[80];
-	x86_z80_options * opts = context->options;
+	z80_options * opts = context->options;
 	uint8_t orig_size = z80_get_native_inst_size(opts, address);
 	uint32_t orig = address;
 	address &= 0x1FFF;
-	uint8_t * dst = opts->cur_code;
-	uint8_t * dst_end = opts->code_end;
+	code_info *code = &opts->gen.code;
 	uint8_t *after, *inst = context->mem_pointers[0] + address;
 	z80inst instbuf;
 	dprintf("Retranslating code at Z80 address %X, native address %p\n", address, orig_start);
@@ -1889,19 +1866,15 @@
 	}
 	#endif
 	if (orig_size != ZMAX_NATIVE_SIZE) {
-		if (dst_end - dst < ZMAX_NATIVE_SIZE) {
-			size_t size = 1024*1024;
-			dst = alloc_code(&size);
-			opts->code_end = dst_end = dst + size;
-			opts->cur_code = dst;
-		}
-		deferred_addr * orig_deferred = opts->deferred;
-		uint8_t * native_end = translate_z80inst(&instbuf, dst, context, address, 0);
+		check_alloc_code(code, ZMAX_NATIVE_SIZE);
+		code_ptr start = code->cur;
+		deferred_addr * orig_deferred = opts->gen.deferred;
+		translate_z80inst(&instbuf, context, address, 0);
 		/*
 		if ((native_end - dst) <= orig_size) {
 			uint8_t * native_next = z80_get_native_address(context, address + after-inst);
 			if (native_next && ((native_next == orig_start + orig_size) || (orig_size - (native_end - dst)) > 5)) {
-				remove_deferred_until(&opts->deferred, orig_deferred);
+				remove_deferred_until(&opts->gen.deferred, orig_deferred);
 				native_end = translate_z80inst(&instbuf, orig_start, context, address, 0);
 				if (native_next == orig_start + orig_size && (native_next-native_end) < 2) {
 					while (native_end < orig_start + orig_size) {
@@ -1913,20 +1886,27 @@
 				z80_handle_deferred(context);
 				return orig_start;
 			}
-		}
-		*/
-		z80_map_native_address(context, address, dst, after-inst, ZMAX_NATIVE_SIZE);
-		opts->cur_code = dst+ZMAX_NATIVE_SIZE;
-		jmp(orig_start, dst);
+		}*/
+		z80_map_native_address(context, address, start, after-inst, ZMAX_NATIVE_SIZE);
+		code_info tmp_code = {orig_start, orig_start + 16};
+		jmp(&tmp_code, start);
+		tmp_code = *code;
+		code->cur = start + ZMAX_NATIVE_SIZE;
 		if (!z80_is_terminal(&instbuf)) {
-			jmp(native_end, z80_get_native_address_trans(context, address + after-inst));
+			jmp(&tmp_code, z80_get_native_address_trans(context, address + after-inst));
 		}
 		z80_handle_deferred(context);
-		return dst;
+		return start;
 	} else {
-		dst = translate_z80inst(&instbuf, orig_start, context, address, 0);
+		code_info tmp_code = *code;
+		code->cur = orig_start;
+		code->last = orig_start + ZMAX_NATIVE_SIZE;
+		translate_z80inst(&instbuf, context, address, 0);
+		code_info tmp2 = *code;
+		*code = tmp_code;
 		if (!z80_is_terminal(&instbuf)) {
-			dst = jmp(dst, z80_get_native_address_trans(context, address + after-inst));
+
+			jmp(&tmp2, z80_get_native_address_trans(context, address + after-inst));
 		}
 		z80_handle_deferred(context);
 		return orig_start;
@@ -1939,7 +1919,7 @@
 	if (z80_get_native_address(context, address)) {
 		return;
 	}
-	x86_z80_options * opts = context->options;
+	z80_options * opts = context->options;
 	uint32_t start_address = address;
 	uint8_t * encoded = NULL, *next;
 	if (address < 0x4000) {
@@ -1951,27 +1931,18 @@
 		z80inst inst;
 		dprintf("translating Z80 code at address %X\n", address);
 		do {
-			if (opts->code_end-opts->cur_code < ZMAX_NATIVE_SIZE) {
-				if (opts->code_end-opts->cur_code < 5) {
-					puts("out of code memory, not enough space for jmp to next chunk");
-					exit(1);
-				}
-				size_t size = 1024*1024;
-				opts->cur_code = alloc_code(&size);
-				opts->code_end = opts->cur_code + size;
-				jmp(opts->cur_code, opts->cur_code);
-			}
 			if (address >= 0x4000) {
-				uint8_t *native_start = opts->cur_code;
-				uint8_t *after = z80_make_interp_stub(context, address);
-				z80_map_native_address(context, address, opts->cur_code, 1, after - native_start);
+				code_info stub = z80_make_interp_stub(context, address);
+				z80_map_native_address(context, address, stub.cur, 1, stub.last - stub.cur);
 				break;
 			}
 			uint8_t * existing = z80_get_native_address(context, address);
 			if (existing) {
-				opts->cur_code = jmp(opts->cur_code, existing);
+				jmp(&opts->gen.code, existing);
 				break;
 			}
+			//make sure prologue is in a contiguous chunk of code
+			check_code_prologue(&opts->gen.code);
 			next = z80_decode(encoded, &inst);
 			#ifdef DO_DEBUG_PRINT
 			z80_disasm(&inst, disbuf, address);
@@ -1981,9 +1952,9 @@
 				printf("%X\t%s\n", address, disbuf);
 			}
 			#endif
-			uint8_t *after = translate_z80inst(&inst, opts->cur_code, context, address, 0);
-			z80_map_native_address(context, address, opts->cur_code, next-encoded, after - opts->cur_code);
-			opts->cur_code = after;
+			code_ptr start = opts->gen.code.cur;
+			translate_z80inst(&inst, context, address, 0);
+			z80_map_native_address(context, address, start, next-encoded, opts->gen.code.cur - start);
 			address += next-encoded;
 			if (address > 0xFFFF) {
 				address &= 0xFFFF;
@@ -1992,9 +1963,9 @@
 				encoded = next;
 			}
 		} while (!z80_is_terminal(&inst));
-		process_deferred(&opts->deferred, context, (native_addr_func)z80_get_native_address);
-		if (opts->deferred) {
-			address = opts->deferred->address;
+		process_deferred(&opts->gen.deferred, context, (native_addr_func)z80_get_native_address);
+		if (opts->gen.deferred) {
+			address = opts->gen.deferred->address;
 			dprintf("defferred address: %X\n", address);
 			if (address < 0x4000) {
 				encoded = context->mem_pointers[0] + (address & 0x1FFF);
@@ -2008,8 +1979,18 @@
 	}
 }
 
-void init_x86_z80_opts(x86_z80_options * options)
+void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t num_chunks)
 {
+	memset(options, 0, sizeof(*options));
+
+	options->gen.address_size = SZ_W;
+	options->gen.address_mask = 0xFFFF;
+	options->gen.max_address = 0x10000;
+	options->gen.bus_cycles = 3;
+	options->gen.mem_ptr_off = offsetof(z80_context, mem_pointers);
+	options->gen.ram_flags_off = offsetof(z80_context, ram_code_flags);
+	options->gen.ram_flags_shift = 7;
+
 	options->flags = 0;
 	options->regs[Z80_B] = BH;
 	options->regs[Z80_C] = RBX;
@@ -2031,15 +2012,285 @@
 	options->regs[Z80_AF] = -1;
 	options->regs[Z80_IX] = RDX;
 	options->regs[Z80_IY] = R8;
-	size_t size = 1024 * 1024;
-	options->cur_code = alloc_code(&size);
-	options->code_end = options->cur_code + size;
-	options->ram_inst_sizes = malloc(sizeof(uint8_t) * 0x2000);
-	memset(options->ram_inst_sizes, 0, sizeof(uint8_t) * 0x2000);
-	options->deferred = NULL;
+
+	options->bank_reg = R15;
+	options->bank_pointer = R12;
+
+	options->gen.context_reg = RSI;
+	options->gen.cycles = RBP;
+	options->gen.limit = RDI;
+	options->gen.scratch1 = R13;
+	options->gen.scratch2 = R14;
+
+	options->gen.native_code_map = malloc(sizeof(native_map_slot));
+	memset(options->gen.native_code_map, 0, sizeof(native_map_slot));
+	options->gen.deferred = NULL;
+	options->gen.ram_inst_sizes = malloc(sizeof(uint8_t) * 0x2000 + sizeof(uint8_t *));
+	options->gen.ram_inst_sizes[0] = (uint8_t *)(options->gen.ram_inst_sizes + 1);
+	memset(options->gen.ram_inst_sizes[0], 0, sizeof(uint8_t) * 0x2000);
+
+	code_info *code = &options->gen.code;
+	init_code_info(code);
+
+	options->save_context_scratch = code->cur;
+	mov_rrdisp(code, options->gen.scratch1, options->gen.context_reg, offsetof(z80_context, scratch1), SZ_W);
+	mov_rrdisp(code, options->gen.scratch2, options->gen.context_reg, offsetof(z80_context, scratch2), SZ_W);
+
+	options->gen.save_context = code->cur;
+	for (int i = 0; i <= Z80_A; i++)
+	{
+		int reg;
+		uint8_t size;
+		if (i < Z80_I) {
+			reg = i /2 + Z80_BC + (i > Z80_H ? 2 : 0);
+			size = SZ_W;
+		} else {
+			reg = i;
+			size = SZ_B;
+}
+		if (options->regs[reg] >= 0) {
+			mov_rrdisp(code, options->regs[reg], options->gen.context_reg, offsetof(z80_context, regs) + i, size);
+		}
+		if (size == SZ_W) {
+			i++;
+		}
+	}
+	if (options->regs[Z80_SP] >= 0) {
+		mov_rrdisp(code, options->regs[Z80_SP], options->gen.context_reg, offsetof(z80_context, sp), SZ_W);
+	}
+	mov_rrdisp(code, options->gen.limit, options->gen.context_reg, offsetof(z80_context, target_cycle), SZ_D);
+	mov_rrdisp(code, options->gen.cycles, options->gen.context_reg, offsetof(z80_context, current_cycle), SZ_D);
+	mov_rrdisp(code, options->bank_reg, options->gen.context_reg, offsetof(z80_context, bank_reg), SZ_W);
+	mov_rrdisp(code, options->bank_pointer, options->gen.context_reg, offsetof(z80_context, mem_pointers) + sizeof(uint8_t *) * 1, SZ_PTR);
+	retn(code);
+
+	options->load_context_scratch = code->cur;
+	mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, scratch1), options->gen.scratch1, SZ_W);
+	mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, scratch2), options->gen.scratch2, SZ_W);
+	options->gen.load_context = code->cur;
+	for (int i = 0; i <= Z80_A; i++)
+	{
+		int reg;
+		uint8_t size;
+		if (i < Z80_I) {
+			reg = i /2 + Z80_BC + (i > Z80_H ? 2 : 0);
+			size = SZ_W;
+		} else {
+			reg = i;
+			size = SZ_B;
+		}
+		if (options->regs[reg] >= 0) {
+			mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, regs) + i, options->regs[reg], size);
+		}
+		if (size == SZ_W) {
+			i++;
+		}
+	}
+	if (options->regs[Z80_SP] >= 0) {
+		mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, sp), options->regs[Z80_SP], SZ_W);
+	}
+	mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, target_cycle), options->gen.limit, SZ_D);
+	mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, current_cycle), options->gen.cycles, SZ_D);
+	mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, bank_reg), options->bank_reg, SZ_W);
+	mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, mem_pointers) + sizeof(uint8_t *) * 1, options->bank_pointer, SZ_PTR);
+	retn(code);
+
+	options->native_addr = code->cur;
+	call(code, options->gen.save_context);
+	push_r(code, options->gen.context_reg);
+	mov_rr(code, options->gen.context_reg, RDI, SZ_PTR);
+	movzx_rr(code, options->gen.scratch1, RSI, SZ_W, SZ_D);
+	call(code, (code_ptr)z80_get_native_address_trans);
+	mov_rr(code, RAX, options->gen.scratch1, SZ_PTR);
+	pop_r(code, options->gen.context_reg);
+	call(code, options->gen.load_context);
+	retn(code);
+
+	options->gen.handle_cycle_limit = code->cur;
+	cmp_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.cycles, SZ_D);
+	code_ptr no_sync = code->cur+1;
+	jcc(code, CC_B, no_sync);
+	mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, pc), SZ_W);
+	call(code, options->save_context_scratch);
+	pop_r(code, RAX); //return address in read/write func
+	pop_r(code, RBX); //return address in translated code
+	sub_ir(code, 5, RAX, SZ_PTR); //adjust return address to point to the call that got us here
+	mov_rrdisp(code, RBX, options->gen.context_reg, offsetof(z80_context, extra_pc), SZ_PTR);
+	mov_rrind(code, RAX, options->gen.context_reg, SZ_PTR);
+	//restore callee saved registers
+	pop_r(code, R15);
+	pop_r(code, R14);
+	pop_r(code, R13);
+	pop_r(code, R12);
+	pop_r(code, RBP);
+	pop_r(code, RBX);
+	*no_sync = code->cur - (no_sync + 1);
+	//return to caller of z80_run
+	retn(code);
+
+	options->gen.handle_code_write = (code_ptr)z80_handle_code_write;
+
+	options->read_8 = gen_mem_fun(&options->gen, chunks, num_chunks, READ_8, &options->read_8_noinc);
+	options->write_8 = gen_mem_fun(&options->gen, chunks, num_chunks, WRITE_8, &options->write_8_noinc);
+
+	options->gen.handle_cycle_limit_int = code->cur;
+	cmp_rdispr(code, options->gen.context_reg, offsetof(z80_context, int_cycle), options->gen.cycles, SZ_D);
+	code_ptr skip_int = code->cur+1;
+	jcc(code, CC_B, skip_int);
+	//set limit to the cycle limit
+	mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.limit, SZ_D);
+	//disable interrupts
+	mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff1), SZ_B);
+	mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff2), SZ_B);
+	cycles(&options->gen, 7);
+	//save return address (in scratch1) to Z80 stack
+	sub_ir(code, 2, options->regs[Z80_SP], SZ_W);
+	mov_rr(code, options->regs[Z80_SP], options->gen.scratch2, SZ_W);
+	//we need to do check_cycles and cycles outside of the write_8 call
+	//so that the stack has the correct depth if we need to return to C
+	//for a synchronization
+	check_cycles(&options->gen);
+	cycles(&options->gen, 3);
+	//save word to write before call to write_8_noinc
+	push_r(code, options->gen.scratch1);
+	call(code, options->write_8_noinc);
+	//restore word to write
+	pop_r(code, options->gen.scratch1);
+	//write high byte to SP+1
+	mov_rr(code, options->regs[Z80_SP], options->gen.scratch2, SZ_W);
+	add_ir(code, 1, options->gen.scratch2, SZ_W);
+	shr_ir(code, 8, options->gen.scratch1, SZ_W);
+	check_cycles(&options->gen);
+	cycles(&options->gen, 3);
+	call(code, options->write_8_noinc);
+	//dispose of return address as we'll be jumping somewhere else
+	pop_r(code, options->gen.scratch2);
+	//TODO: Support interrupt mode 0 and 2
+	mov_ir(code, 0x38, options->gen.scratch1, SZ_W);
+	call(code, options->native_addr);
+	jmp_r(code, options->gen.scratch1);
+	*skip_int = code->cur - (skip_int+1);
+	cmp_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.cycles, SZ_D);
+	code_ptr skip_sync = code->cur + 1;
+	jcc(code, CC_B, skip_sync);
+	options->do_sync = code->cur;
+	call(code, options->gen.save_context);
+	pop_rind(code, options->gen.context_reg);
+	//restore callee saved registers
+	pop_r(code, R15);
+	pop_r(code, R14);
+	pop_r(code, R13);
+	pop_r(code, R12);
+	pop_r(code, RBP);
+	pop_r(code, RBX);
+	//return to caller of z80_run
+	*skip_sync = code->cur - (skip_sync+1);
+	retn(code);
+
+	options->read_io = code->cur;
+	check_cycles(&options->gen);
+	cycles(&options->gen, 4);
+	//Genesis has no IO hardware and always returns FF
+	//eventually this should use a second memory map array
+	mov_ir(code, 0xFF, options->gen.scratch1, SZ_B);
+	retn(code);
+
+	options->write_io = code->cur;
+	check_cycles(&options->gen);
+	cycles(&options->gen, 4);
+	retn(code);
+
+	options->read_16 = code->cur;
+	cycles(&options->gen, 3);
+	check_cycles(&options->gen);
+	//TODO: figure out how to handle the extra wait state for word reads to bank area
+	//may also need special handling to avoid too much stack depth when acces is blocked
+	push_r(code, options->gen.scratch1);
+	call(code, options->read_8_noinc);
+	mov_rr(code, options->gen.scratch1, options->gen.scratch2, SZ_B);
+	pop_r(code, options->gen.scratch1);
+	add_ir(code, 1, options->gen.scratch1, SZ_W);
+	cycles(&options->gen, 3);
+	check_cycles(&options->gen);
+	call(code, options->read_8_noinc);
+	shl_ir(code, 8, options->gen.scratch1, SZ_W);
+	mov_rr(code, options->gen.scratch2, options->gen.scratch1, SZ_B);
+	retn(code);
+
+	options->write_16_highfirst = code->cur;
+	cycles(&options->gen, 3);
+	check_cycles(&options->gen);
+	push_r(code, options->gen.scratch2);
+	push_r(code, options->gen.scratch1);
+	add_ir(code, 1, options->gen.scratch2, SZ_W);
+	shr_ir(code, 8, options->gen.scratch1, SZ_W);
+	call(code, options->write_8_noinc);
+	pop_r(code, options->gen.scratch1);
+	pop_r(code, options->gen.scratch2);
+	cycles(&options->gen, 3);
+	check_cycles(&options->gen);
+	//TODO: Check if we can get away with TCO here
+	call(code, options->write_8_noinc);
+	retn(code);
+
+	options->write_16_lowfirst = code->cur;
+	cycles(&options->gen, 3);
+	check_cycles(&options->gen);
+	push_r(code, options->gen.scratch2);
+	push_r(code, options->gen.scratch1);
+	call(code, options->write_8_noinc);
+	pop_r(code, options->gen.scratch1);
+	pop_r(code, options->gen.scratch2);
+	add_ir(code, 1, options->gen.scratch2, SZ_W);
+	shr_ir(code, 8, options->gen.scratch1, SZ_W);
+	cycles(&options->gen, 3);
+	check_cycles(&options->gen);
+	//TODO: Check if we can get away with TCO here
+	call(code, options->write_8_noinc);
+	retn(code);
+
+	options->retrans_stub = code->cur;
+	//pop return address
+	pop_r(code, options->gen.scratch2);
+	call(code, options->gen.save_context);
+	//adjust pointer before move and call instructions that got us here
+	sub_ir(code, 11, options->gen.scratch2, SZ_PTR);
+	mov_rr(code, options->gen.scratch1, RDI, SZ_D);
+	mov_rr(code, options->gen.scratch2, RDX, SZ_PTR);
+	push_r(code, options->gen.context_reg);
+	call(code, (code_ptr)z80_retranslate_inst);
+	pop_r(code, options->gen.context_reg);
+	mov_rr(code, RAX, options->gen.scratch1, SZ_PTR);
+	call(code, options->gen.load_context);
+	jmp_r(code, options->gen.scratch1);
+
+	options->run = (z80_run_fun)code->cur;
+	//save callee save registers
+	push_r(code, RBX);
+	push_r(code, RBP);
+	push_r(code, R12);
+	push_r(code, R13);
+	push_r(code, R14);
+	push_r(code, R15);
+	mov_rr(code, RDI, options->gen.context_reg, SZ_PTR);
+	call(code, options->load_context_scratch);
+	cmp_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, extra_pc), SZ_PTR);
+	code_ptr no_extra = code->cur+1;
+	jcc(code, CC_Z, no_extra);
+	push_rdisp(code, options->gen.context_reg, offsetof(z80_context, extra_pc));
+	mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, extra_pc), SZ_PTR);
+	*no_extra = code->cur - (no_extra + 1);
+	jmp_rind(code, options->gen.context_reg);
 }
 
-void init_z80_context(z80_context * context, x86_z80_options * options)
+void * z80_gen_bank_write(uint32_t start_address, void * voptions)
+{
+	z80_options * options = voptions;
+	//TODO: Handle writes to bank register
+	return options;
+}
+
+void init_z80_context(z80_context * context, z80_options * options)
 {
 	memset(context, 0, sizeof(*context));
 	context->static_code_map = malloc(sizeof(*context->static_code_map));
@@ -2052,6 +2303,7 @@
 	context->int_cycle = 0xFFFFFFFF;
 	context->int_pulse_start = 0xFFFFFFFF;
 	context->int_pulse_end = 0xFFFFFFFF;
+	context->run = options->run;
 }
 
 void z80_reset(z80_context * context)
@@ -2062,55 +2314,52 @@
 	context->extra_pc = NULL;
 }
 
-uint8_t * zbreakpoint_patch(z80_context * context, uint16_t address, uint8_t * native)
+uint32_t zbreakpoint_patch(z80_context * context, uint16_t address, code_ptr dst)
 {
-	native = mov_ir(native, address, SCRATCH1, SZ_W);
-	native = call(native, context->bp_stub);
-	return native;
+	code_info code = {dst, dst+16};
+	mov_ir(&code, address, SCRATCH1, SZ_W);
+	call(&code, context->bp_stub);
+	return code.cur-dst;
 }
 
 void zcreate_stub(z80_context * context)
 {
-	x86_z80_options * opts = context->options;
-	uint8_t * dst = opts->cur_code;
-	uint8_t * dst_end = opts->code_end;
-	if (dst_end - dst < 128) {
-		size_t size = 1024*1024;
-		dst = alloc_code(&size);
-		opts->code_end = dst_end = dst + size;
-	}
-	context->bp_stub = dst;
+	z80_options * opts = context->options;
+	code_info *code = &opts->gen.code;
+	check_code_prologue(code);
+	context->bp_stub = code->cur;
 
 	//Calculate length of prologue
-	int check_int_size = z80_check_cycles_int(dst, 0) - dst;
+	check_cycles_int(&opts->gen, 0);
+	int check_int_size = code->cur-context->bp_stub;
+	code->cur = context->bp_stub;
 
 	//Calculate length of patch
-	int patch_size = zbreakpoint_patch(context, 0, dst) - dst;
+	int patch_size = zbreakpoint_patch(context, 0, code->cur);
 
 	//Save context and call breakpoint handler
-	dst = call(dst, (uint8_t *)z80_save_context);
-	dst = push_r(dst, SCRATCH1);
-	dst = mov_rr(dst, CONTEXT, RDI, SZ_Q);
-	dst = mov_rr(dst, SCRATCH1, RSI, SZ_W);
-	dst = call(dst, context->bp_handler);
-	dst = mov_rr(dst, RAX, CONTEXT, SZ_Q);
+	call(code, opts->gen.save_context);
+	push_r(code, opts->gen.scratch1);
+	mov_rr(code, opts->gen.context_reg, RDI, SZ_Q);
+	mov_rr(code, opts->gen.scratch1, RSI, SZ_W);
+	call(code, context->bp_handler);
+	mov_rr(code, RAX, opts->gen.context_reg, SZ_Q);
 	//Restore context
-	dst = call(dst, (uint8_t *)z80_load_context);
-	dst = pop_r(dst, SCRATCH1);
+	call(code, opts->gen.load_context);
+	pop_r(code, opts->gen.scratch1);
 	//do prologue stuff
-	dst = cmp_rr(dst, ZCYCLES, ZLIMIT, SZ_D);
-	uint8_t * jmp_off = dst+1;
-	dst = jcc(dst, CC_NC, dst + 7);
-	dst = pop_r(dst, SCRATCH1);
-	dst = add_ir(dst, check_int_size - patch_size, SCRATCH1, SZ_Q);
-	dst = push_r(dst, SCRATCH1);
-	dst = jmp(dst, (uint8_t *)z80_handle_cycle_limit_int);
-	*jmp_off = dst - (jmp_off+1);
+	cmp_rr(code, opts->gen.cycles, opts->gen.limit, SZ_D);
+	uint8_t * jmp_off = code->cur+1;
+	jcc(code, CC_NC, code->cur + 7);
+	pop_r(code, opts->gen.scratch1);
+	add_ir(code, check_int_size - patch_size, opts->gen.scratch1, SZ_Q);
+	push_r(code, opts->gen.scratch1);
+	jmp(code, opts->gen.handle_cycle_limit_int);
+	*jmp_off = code->cur - (jmp_off+1);
 	//jump back to body of translated instruction
-	dst = pop_r(dst, SCRATCH1);
-	dst = add_ir(dst, check_int_size - patch_size, SCRATCH1, SZ_Q);
-	dst = jmp_r(dst, SCRATCH1);
-	opts->cur_code = dst;
+	pop_r(code, opts->gen.scratch1);
+	add_ir(code, check_int_size - patch_size, opts->gen.scratch1, SZ_Q);
+	jmp_r(code, opts->gen.scratch1);
 }
 
 void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler)
@@ -2134,8 +2383,12 @@
 	context->breakpoint_flags[address / sizeof(uint8_t)] &= ~(1 << (address % sizeof(uint8_t)));
 	uint8_t * native = z80_get_native_address(context, address);
 	if (native) {
-		z80_check_cycles_int(native, address);
+		z80_options * opts = context->options;
+		code_info tmp_code = opts->gen.code;
+		opts->gen.code.cur = native;
+		opts->gen.code.last = native + 16;
+		check_cycles_int(&opts->gen, address);
+		opts->gen.code = tmp_code;
 	}
 }
 
-
--- a/z80_to_x86.h	Tue Dec 16 01:10:54 2014 -0800
+++ b/z80_to_x86.h	Tue Dec 30 19:11:34 2014 -0800
@@ -1,12 +1,12 @@
 /*
  Copyright 2013 Michael Pavone
- This file is part of BlastEm.
+ This file is part of BlastEm. 
  BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
 */
 #ifndef Z80_TO_X86_H_
 #define Z80_TO_X86_H_
 #include "z80inst.h"
-#include "x86_backend.h"
+#include "backend.h"
 
 #define ZNUM_MEM_AREAS 4
 #define ZMAX_NATIVE_SIZE 128
@@ -21,14 +21,31 @@
 	ZF_NUM
 };
 
+typedef void (*z80_run_fun)(void * context);
+
 typedef struct {
-	uint8_t *       cur_code;
-	uint8_t *       code_end;
-	uint8_t         *ram_inst_sizes;
-	deferred_addr * deferred;
+	cpu_options     gen;
+	code_ptr        save_context_scratch;
+	code_ptr        load_context_scratch;
+	code_ptr        native_addr;
+	code_ptr        retrans_stub;
+	code_ptr        do_sync;
+	code_ptr        read_8;
+	code_ptr        write_8;
+	code_ptr        read_8_noinc;
+	code_ptr        write_8_noinc;
+	code_ptr        read_16;
+	code_ptr        write_16_highfirst;
+	code_ptr        write_16_lowfirst;
+	code_ptr		read_io;
+	code_ptr		write_io;
+
 	uint32_t        flags;
 	int8_t          regs[Z80_UNUSED];
-} x86_z80_options;
+	int8_t          bank_reg;
+	int8_t          bank_pointer;
+	z80_run_fun     run;
+} z80_options;
 
 typedef struct {
 	void *            native_pc;
@@ -51,11 +68,12 @@
 	uint32_t          int_cycle;
 	native_map_slot * static_code_map;
 	native_map_slot * banked_code_map;
-	void *            options;
+	z80_options *     options;
 	void *            system;
 	uint8_t           ram_code_flags[(8 * 1024)/128/8];
 	uint32_t          int_enable_cycle;
-	uint16_t          pc;
+	z80_run_fun       run;
+  uint16_t          pc;
 	uint32_t          int_pulse_start;
 	uint32_t          int_pulse_end;
 	uint8_t           breakpoint_flags[(16 * 1024)/sizeof(uint8_t)];
@@ -66,15 +84,16 @@
 } z80_context;
 
 void translate_z80_stream(z80_context * context, uint32_t address);
-void init_x86_z80_opts(x86_z80_options * options);
-void init_z80_context(z80_context * context, x86_z80_options * options);
-uint8_t * z80_get_native_address(z80_context * context, uint32_t address);
-uint8_t * z80_get_native_address_trans(z80_context * context, uint32_t address);
+void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t num_chunks);
+void init_z80_context(z80_context * context, z80_options * options);
+code_ptr z80_get_native_address(z80_context * context, uint32_t address);
+code_ptr z80_get_native_address_trans(z80_context * context, uint32_t address);
 z80_context * z80_handle_code_write(uint32_t address, z80_context * context);
 void z80_run(z80_context * context);
 void z80_reset(z80_context * context);
 void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler);
 void zremove_breakpoint(z80_context * context, uint16_t address);
+void * z80_gen_bank_write(uint32_t start_address, void * voptions);
 
 #endif //Z80_TO_X86_H_
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zcompare.py	Tue Dec 30 19:11:34 2014 -0800
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+from glob import glob
+import subprocess
+from sys import exit,argv
+
+prefixes = []
+skip = set()
+for i in range(1, len(argv)):
+	if '.' in argv[i]:
+		f = open(argv[i])
+		for line in f:
+			parts = line.split()
+			for part in parts:
+				if part.endswith('.bin'):
+					skip.add(part)
+		f.close()
+		print 'Skipping',len(skip),'entries from previous report.'
+	else:
+		prefixes.append(argv[i])
+
+for path in glob('ztests/*/*.bin'):
+	if path in skip:
+		continue
+	if prefixes:
+		good = False
+		fname = path.split('/')[-1]
+		for prefix in prefixes:
+			if fname.startswith(prefix):
+				good = True
+				break
+		if not good:
+			continue
+	try:
+		b = subprocess.check_output(['./ztestrun', path])
+		try:
+			m = subprocess.check_output(['gxz80/gxzrun', path])
+			#_,_,b = b.partition('\n')
+			if b != m:
+				print '-----------------------------'
+				print 'Mismatch in ' + path
+				print 'blastem output:'
+				print b
+				print 'gxz80 output:'
+				print m
+				print '-----------------------------'
+			else:
+				print path, 'passed'
+		except subprocess.CalledProcessError as e:
+			print '-----------------------------'
+			print 'gxz80 exited with code', e.returncode, 'for test', path
+			print 'blastem output:'
+			print b
+			print '-----------------------------'
+	except subprocess.CalledProcessError as e:
+		print '-----------------------------'
+		print 'blastem exited with code', e.returncode, 'for test', path
+		print '-----------------------------'
+
--- a/ztestgen.c	Tue Dec 16 01:10:54 2014 -0800
+++ b/ztestgen.c	Tue Dec 30 19:11:34 2014 -0800
@@ -24,6 +24,7 @@
 #define PRE_IX  0xDD
 #define PRE_IY  0xFD
 #define LD_IR16 0x01
+#define INC_R8  0x04
 #define LD_IR8  0x06
 #define LD_RR8  0x40
 #define AND_R   0xA0
@@ -143,6 +144,43 @@
 	}
 }
 
+uint8_t * inc_r(uint8_t *dst, uint8_t reg)
+{
+	if (reg == Z80_IXH || reg == Z80_IXL) {
+		*(dst++) = PRE_IX;
+		return inc_r(dst, reg - (Z80_IXL - Z80_L));
+	} else if(reg == Z80_IYH || reg == Z80_IYL) {
+		*(dst++) = PRE_IY;
+		return inc_r(dst, reg - (Z80_IYL - Z80_L));
+	} else {
+		*(dst++) = INC_R8 | reg << 3;
+		return dst;
+	}
+}
+
+void mark_used8(uint8_t *reg_usage, uint16_t *reg_values, uint8_t reg, uint8_t init_value)
+{
+	reg_usage[reg] = 1;
+	reg_values[reg] = init_value;
+	uint8_t word_reg = z80_word_reg(reg);
+	if (word_reg != Z80_UNUSED) {
+		reg_usage[word_reg] = 1;
+		reg_values[word_reg] = (reg_values[z80_high_reg(word_reg)] << 8) | (reg_values[z80_low_reg(word_reg)] & 0xFF);
+	}
+}
+
+uint8_t alloc_reg8(uint8_t *reg_usage, uint16_t *reg_values, uint8_t init_value)
+{
+	for (uint8_t reg = 0; reg < Z80_BC; reg++)
+	{
+		if (!reg_usage[reg]) {
+			mark_used8(reg_usage, reg_values, reg, init_value);
+			return reg;
+		}
+	}
+	return Z80_UNUSED;
+}
+
 void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen)
 {
 	z80inst copy;
@@ -184,12 +222,7 @@
 			reg_values[z80_low_reg(inst->ea_reg)] = reg_values[inst->ea_reg] & 0xFF;
 			reg_usage[z80_low_reg(inst->ea_reg)] = 1;
 		} else {
-			reg_values[inst->ea_reg] = rand() % 256;
-			uint8_t word_reg = z80_word_reg(inst->ea_reg);
-			if (word_reg != Z80_UNUSED) {
-				reg_usage[word_reg] = 1;
-				reg_values[word_reg] = (reg_values[z80_high_reg(word_reg)] << 8) | (reg_values[z80_low_reg(word_reg)] & 0xFF);
-			}
+			mark_used8(reg_usage, reg_values, inst->ea_reg, rand() % 256);
 		}
 		break;
 	case Z80_REG_INDIRECT:
@@ -255,6 +288,10 @@
 		}
 		reg_usage[inst->reg] = 1;
 	}
+	uint8_t counter_reg = Z80_UNUSED;
+	if (inst->op >= Z80_JP && inst->op <= Z80_JRCC) {
+		counter_reg = alloc_reg8(reg_usage, reg_values, 0);
+	}
 	puts("--------------");
 	for (uint8_t reg = 0; reg < Z80_UNUSED; reg++) {
 		if (reg_values[reg]) {
@@ -293,11 +330,26 @@
 
 		//setup other regs
 		for (uint8_t reg = Z80_BC; reg <= Z80_IY; reg++) {
-			if (reg != Z80_AF && reg != Z80_SP) {
-				cur = ld_ir16(cur, reg, reg_values[reg]);
+			if (reg != Z80_AF && reg != Z80_SP && (inst->op != Z80_JP || addr_mode != Z80_REG_INDIRECT || inst->ea_reg != reg)) {
+				if (i == 1 && (z80_high_reg(reg) == counter_reg || z80_low_reg(reg) == counter_reg)) {
+					if (z80_high_reg(reg) == counter_reg) {
+						if (reg_usage[z80_low_reg(reg)]) {
+							cur = ld_ir8(cur, z80_low_reg(reg), reg_values[z80_low_reg(reg)]);
+						}
+					} else if (reg_usage[z80_high_reg(reg)]) {
+						cur = ld_ir8(cur, z80_high_reg(reg), reg_values[z80_high_reg(reg)]);
+					}
+				} else {
+					cur = ld_ir16(cur, reg, reg_values[reg]);
+				}
 			}
 		}
 
+		if (inst->op == Z80_JP && addr_mode == Z80_REG_INDIRECT) {
+			uint16_t address = cur - prog + (inst->ea_reg == Z80_HL ? 3 : 4) + instlen + 1 + i;
+			cur = ld_ir16(cur, inst->ea_reg, address);
+		}
+
 		//copy instruction
 		if (instlen == 3) {
 			memcpy(cur, instbuf, 2);
@@ -310,6 +362,12 @@
 		//immed/displacement byte(s)
 		if (addr_mode == Z80_IX_DISPLACE || addr_mode == Z80_IY_DISPLACE) {
 			*(cur++) = inst->ea_reg;
+		} else if ((inst->op == Z80_JP || inst->op == Z80_JPCC) && addr_mode == Z80_IMMED) {
+			uint16_t address = cur - prog + 3 + i; //2 for immed address, 1/2 for instruction(s) to skip
+			*(cur++) = address;
+			*(cur++) = address >> 8;
+		} else if(inst->op == Z80_JR || inst->op == Z80_JRCC) {
+			*(cur++) = 1 + i; //skip one or 2 instructions based on value of i
 		} else if (addr_mode == Z80_IMMED & inst->op != Z80_IM) {
 			*(cur++) = inst->immed & 0xFF;
 			if (word_sized) {
@@ -325,6 +383,13 @@
 		if (instlen == 3) {
 			*(cur++) = instbuf[2];
 		}
+		if (inst->op >= Z80_JP && inst->op <= Z80_JRCC) {
+			cur = inc_r(cur, counter_reg);
+			if (i) {
+				//inc twice on second iteration so we can differentiate the two
+				cur = inc_r(cur, counter_reg);
+			}
+		}
 		if (!i) {
 			//Save AF from first run
 			cur = push(cur, Z80_AF);
@@ -399,7 +464,7 @@
 
 uint8_t should_skip(z80inst * inst)
 {
-	return inst->op >= Z80_JP || (inst->op >= Z80_LDI && inst->op <= Z80_CPDR) || inst->op == Z80_HALT
+	return inst->op >= Z80_DJNZ || (inst->op >= Z80_LDI && inst->op <= Z80_CPDR) || inst->op == Z80_HALT
 		|| inst->op == Z80_DAA || inst->op == Z80_RLD || inst->op == Z80_RRD || inst->op == Z80_NOP
 		|| inst->op == Z80_DI || inst->op == Z80_EI;
 }
--- a/ztestrun.c	Tue Dec 16 01:10:54 2014 -0800
+++ b/ztestrun.c	Tue Dec 30 19:11:34 2014 -0800
@@ -1,6 +1,6 @@
 /*
  Copyright 2013 Michael Pavone
- This file is part of BlastEm. 
+ This file is part of BlastEm.
  BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
 */
 #include "z80inst.h"
@@ -11,7 +11,6 @@
 #include <stdlib.h>
 
 uint8_t z80_ram[0x2000];
-uint16_t cart[0x200000];
 
 #define MCLKS_PER_Z80 15
 //TODO: Figure out the exact value for this
@@ -19,26 +18,26 @@
 #define VINT_CYCLE ((MCLKS_LINE * 226)/MCLKS_PER_Z80)
 #define CYCLE_NEVER 0xFFFFFFFF
 
-uint8_t z80_read_ym(uint16_t location, z80_context * context)
+uint8_t z80_unmapped_read(uint32_t location, void * context)
 {
 	return 0xFF;
 }
 
-z80_context * z80_write_ym(uint16_t location, z80_context * context, uint8_t value)
+void * z80_unmapped_write(uint32_t location, void * context, uint8_t value)
 {
 	return context;
 }
 
-z80_context * z80_vdp_port_write(uint16_t location, z80_context * context, uint8_t value)
-{
-	return context;
-}
+const memmap_chunk z80_map[] = {
+	{ 0x0000, 0x4000,  0x1FFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, z80_ram, NULL, NULL, NULL,              NULL },
+	{ 0x4000, 0x10000, 0xFFFF, 0, 0,                                  NULL,    NULL, NULL, z80_unmapped_read, z80_unmapped_write}
+};
 
 int main(int argc, char ** argv)
 {
 	long filesize;
 	uint8_t *filebuf;
-	x86_z80_options opts;
+	z80_options opts;
 	z80_context context;
 	if (argc < 2) {
 		fputs("usage: transz80 zrom [cartrom]\n", stderr);
@@ -54,47 +53,29 @@
 	fseek(f, 0, SEEK_SET);
 	fread(z80_ram, 1, filesize < sizeof(z80_ram) ? filesize : sizeof(z80_ram), f);
 	fclose(f);
-	if (argc > 2) {
-		f = fopen(argv[2], "rb");
-		if (!f) {
-			fprintf(stderr, "unable to open file %s\n", argv[2]);
-			exit(1);
-		}
-		fseek(f, 0, SEEK_END);
-		filesize = ftell(f);
-		fseek(f, 0, SEEK_SET);
-		fread(cart, 1, filesize < sizeof(cart) ? filesize : sizeof(cart), f);
-		fclose(f);
-		for(unsigned short * cur = cart; cur - cart < (filesize/2); ++cur)
-		{
-			*cur = (*cur >> 8) | (*cur << 8);
-		}
-	}
-	init_x86_z80_opts(&opts);
+	init_x86_z80_opts(&opts, z80_map, 2);
 	init_z80_context(&context, &opts);
 	//Z80 RAM
 	context.mem_pointers[0] = z80_ram;
 	context.sync_cycle = context.target_cycle = 1000;
 	context.int_cycle = CYCLE_NEVER;
-	//cartridge/bank
-	context.mem_pointers[1] = context.mem_pointers[2] = (uint8_t *)cart;
 	z80_reset(&context);
 	while (context.current_cycle < 1000) {
-		z80_run(&context);
+		context.run(&context);
 	}
-	printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\nIX: %X\nIY: %X\nSP: %X\n\nIM: %d, IFF1: %d, IFF2: %d\n", 
+	printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\nIX: %X\nIY: %X\nSP: %X\n\nIM: %d, IFF1: %d, IFF2: %d\n",
 		context.regs[Z80_A], context.regs[Z80_B], context.regs[Z80_C],
-		context.regs[Z80_D], context.regs[Z80_E], 
-		(context.regs[Z80_H] << 8) | context.regs[Z80_L], 
-		(context.regs[Z80_IXH] << 8) | context.regs[Z80_IXL], 
-		(context.regs[Z80_IYH] << 8) | context.regs[Z80_IYL], 
+		context.regs[Z80_D], context.regs[Z80_E],
+		(context.regs[Z80_H] << 8) | context.regs[Z80_L],
+		(context.regs[Z80_IXH] << 8) | context.regs[Z80_IXL],
+		(context.regs[Z80_IYH] << 8) | context.regs[Z80_IYL],
 		context.sp, context.im, context.iff1, context.iff2);
 	printf("Flags: SZVNC\n"
 	       "       %d%d%d%d%d\n", context.flags[ZF_S], context.flags[ZF_Z], context.flags[ZF_PV], context.flags[ZF_N], context.flags[ZF_C]);
 	puts("--Alternate Regs--");
-	printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\n", 
+	printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\n",
 		context.alt_regs[Z80_A], context.alt_regs[Z80_B], context.alt_regs[Z80_C],
-		context.alt_regs[Z80_D], context.alt_regs[Z80_E], 
+		context.alt_regs[Z80_D], context.alt_regs[Z80_E],
 		(context.alt_regs[Z80_H] << 8) | context.alt_regs[Z80_L]);
 	return 0;
 }