changeset 590:ea80559c67cb

WIP effort to update z80 core for code gen changes
author Michael Pavone <pavone@retrodev.com>
date Sun, 14 Dec 2014 16:45:23 -0800
parents 2dde38c1744f
children 966b46c68942
files backend.h backend_x86.c blastem.c m68k_core_x86.c z80_to_x86.c z80_to_x86.h
diffstat 6 files changed, 592 insertions(+), 452 deletions(-) [+]
line wrap: on
line diff
--- a/backend.h	Tue Mar 11 09:44:47 2014 -0700
+++ b/backend.h	Sun Dec 14 16:45:23 2014 -0800
@@ -108,7 +108,7 @@
 void check_cycles_int(cpu_options *opts, uint32_t address);
 void check_cycles(cpu_options * opts);
 
-code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk * memmap, uint32_t num_chunks, ftype fun_type);
+code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk * memmap, uint32_t num_chunks, ftype fun_type, code_ptr *after_inc);
 
 #endif //BACKEND_H_
 
--- a/backend_x86.c	Tue Mar 11 09:44:47 2014 -0700
+++ b/backend_x86.c	Sun Dec 14 16:45:23 2014 -0800
@@ -28,12 +28,15 @@
 	*jmp_off = code->cur - (jmp_off+1);
 }
 
-code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk * memmap, uint32_t num_chunks, ftype fun_type)
+code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk * 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);
 	}
--- a/blastem.c	Tue Mar 11 09:44:47 2014 -0700
+++ b/blastem.c	Sun Dec 14 16:45:23 2014 -0800
@@ -1072,6 +1072,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, 0xFFFF, 1, MMAP_READ | MMAP_WRITE | MMAP_PTR_IDX | MMAP_FUNC_NULL, NULL,    NULL, NULL, z80_read_bank,     z80_write_bank},
+	{ 0x4000, 0x6000,  0x0003, 0, MMAP_READ | MMAP_WRITE,                                 NULL,    NULL, NULL, z80_read_ym,       z80_write_ym},
+	{ 0x6000, 0x6100,  0xFFFF, 0, MMAP_WRITE | MMAP_CUSTOM,                               NULL,    NULL, NULL, NULL,              (write_8_fun)z80_gen_bank_write},
+	{ 0x7F00, 0x8000,  0x00FF, 0, MMAP_READ | MMAP_WRITE,                                 NULL,    NULL, NULL, z80_vdp_port_read, z80_vdp_port_write}
+};
+#endif
 
 int main(int argc, char ** argv)
 {
@@ -1237,9 +1246,9 @@
 	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;
 #ifndef NO_Z80
-	init_x86_z80_opts(&z_opts);
+	z80_options z_opts;
+	init_x86_z80_opts(&z_opts, z80_map, 5);
 	init_z80_context(&z_context, &z_opts);
 #endif
 
--- a/m68k_core_x86.c	Tue Mar 11 09:44:47 2014 -0700
+++ b/m68k_core_x86.c	Sun Dec 14 16:45:23 2014 -0800
@@ -2390,10 +2390,12 @@
 	*skip_sync = code->cur - (skip_sync+1);
 	retn(code);
 
-	opts->read_16 = gen_mem_fun(&opts->gen, memmap, num_chunks, READ_16);
-	opts->read_8 = gen_mem_fun(&opts->gen, memmap, num_chunks, READ_8);
-	opts->write_16 = gen_mem_fun(&opts->gen, memmap, num_chunks, WRITE_16);
-	opts->write_8 = gen_mem_fun(&opts->gen, memmap, num_chunks, WRITE_8);
+	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);
--- a/z80_to_x86.c	Tue Mar 11 09:44:47 2014 -0700
+++ b/z80_to_x86.c	Sun Dec 14 16:45:23 2014 -0800
@@ -54,24 +54,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, x86_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;
@@ -81,12 +66,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];
@@ -96,64 +81,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, x86_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 {
 			ea->base = opts->regs[inst->ea_reg];
@@ -162,30 +147,30 @@
 				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);
 				}
 			}
 		}
 		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_rrdisp8(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);
+				dst = call(dst, 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_rdisp8r(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;
@@ -196,7 +181,7 @@
 		size = z80_size(inst);
 		if (read) {
 			/*if (modify) {
-				dst = push_r(dst, SCRATCH1);
+				dst = push_r(dst, opts->gen.scratch1);
 			}*/
 			if (size == SZ_B) {
 				dst = call(dst, (uint8_t *)z80_read_byte);
@@ -204,11 +189,11 @@
 				dst = call(dst, (uint8_t *)z80_read_word);
 			}
 			if (modify) {
-				//dst = pop_r(dst, SCRATCH2);
-				dst = mov_ir(dst, inst->immed, SCRATCH2, SZ_W);
+				//dst = pop_r(dst, opts->gen.scratch2);
+				dst = mov_ir(dst, inst->immed, opts->gen.scratch2, SZ_W);
 			}
 		}
-		ea->base = SCRATCH1;
+		ea->base = opts->gen.scratch1;
 		break;
 	case Z80_IX_DISPLACE:
 	case Z80_IY_DISPLACE:
@@ -218,8 +203,8 @@
 		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);
+				//dst = push_r(dst, opts->gen.scratch1);
+				dst = mov_rrdisp8(dst, 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);
@@ -227,11 +212,11 @@
 				dst = call(dst, (uint8_t *)z80_read_word);
 			}
 			if (modify) {
-				//dst = pop_r(dst, SCRATCH2);
-				dst = mov_rdisp8r(dst, CONTEXT, offsetof(z80_context, scratch1), SCRATCH2, SZ_W);
+				//dst = pop_r(dst, opts->gen.scratch2);
+				dst = mov_rdisp8r(dst, 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;
@@ -243,13 +228,13 @@
 	return dst;
 }
 
-uint8_t * z80_save_ea(uint8_t * dst, z80inst * inst, x86_z80_options * opts)
+uint8_t * z80_save_ea(uint8_t * dst, 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 = mov_rr(dst, opts->gen.scratch1, opts->regs[Z80_IYL], SZ_B);
 				dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W);
 			} else {
 				dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W);
@@ -326,14 +311,14 @@
 	exit(0);
 }
 
-uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context, uint16_t address)
+uint8_t * translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
 {
 	uint32_t cycles;
 	x86_ea src_op, dst_op;
 	uint8_t size;
-	x86_z80_options *opts = context->options;
-	uint8_t * start = dst;
-	dst = z80_check_cycles_int(dst, address);
+	z80_options *opts = context->options;
+	uint8_t * start = opts->code.cur;
+	check_cycles_int(&opts->gen, address);
 	switch(inst->op)
 	{
 	case Z80_LD:
@@ -364,7 +349,7 @@
 		if ((inst->reg >= Z80_IXL && inst->reg <= Z80_IYH) || inst->reg == Z80_IX || inst->reg == Z80_IY) {
 			cycles += 4;
 		}
-		dst = zcycles(dst, cycles);
+		dst = cycles(&opts->gen, 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);
@@ -390,55 +375,55 @@
 		}
 		break;
 	case Z80_PUSH:
-		dst = zcycles(dst, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 9 : 5);
+		dst = cycles(&opts->gen, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 9 : 5);
 		dst = sub_ir(dst, 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);
+			dst = mov_rr(dst, opts->regs[Z80_A], opts->gen.scratch1, SZ_B);
+			dst = shl_ir(dst, 8, opts->gen.scratch1, SZ_W);
+			dst = mov_rdisp8r(dst, opts->gen.context_reg, zf_off(ZF_S), opts->gen.scratch1, SZ_B);
+			dst = shl_ir(dst, 1, opts->gen.scratch1, SZ_B);
+			dst = or_rdisp8r(dst, opts->gen.context_reg, zf_off(ZF_Z), opts->gen.scratch1, SZ_B);
+			dst = shl_ir(dst, 2, opts->gen.scratch1, SZ_B);
+			dst = or_rdisp8r(dst, opts->gen.context_reg, zf_off(ZF_H), opts->gen.scratch1, SZ_B);
+			dst = shl_ir(dst, 2, opts->gen.scratch1, SZ_B);
+			dst = or_rdisp8r(dst, opts->gen.context_reg, zf_off(ZF_PV), opts->gen.scratch1, SZ_B);
+			dst = shl_ir(dst, 1, opts->gen.scratch1, SZ_B);
+			dst = or_rdisp8r(dst, opts->gen.context_reg, zf_off(ZF_N), opts->gen.scratch1, SZ_B);
+			dst = shl_ir(dst, 1, opts->gen.scratch1, SZ_B);
+			dst = or_rdisp8r(dst, 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);
+			dst = mov_rr(dst, src_op.base, opts->gen.scratch1, SZ_W);
 		}
-		dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH2, SZ_W);
+		dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
 		dst = call(dst, (uint8_t *)z80_write_word_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 = cycles(&opts->gen, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 8 : 4);
+		dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
 		dst = call(dst, (uint8_t *)z80_read_word);
 		dst = add_ir(dst, 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);
+			dst = bt_ir(dst, 0, opts->gen.scratch1, SZ_W);
+			dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+			dst = bt_ir(dst, 1, opts->gen.scratch1, SZ_W);
+			dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_N));
+			dst = bt_ir(dst, 2, opts->gen.scratch1, SZ_W);
+			dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_PV));
+			dst = bt_ir(dst, 4, opts->gen.scratch1, SZ_W);
+			dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_H));
+			dst = bt_ir(dst, 6, opts->gen.scratch1, SZ_W);
+			dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_Z));
+			dst = bt_ir(dst, 7, opts->gen.scratch1, SZ_W);
+			dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_S));
+			dst = shr_ir(dst, 8, opts->gen.scratch1, SZ_W);
+			dst = mov_rr(dst, 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);
+			dst = mov_rr(dst, 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
@@ -449,31 +434,31 @@
 		} else {
 			cycles = 8;
 		}
-		dst = zcycles(dst, cycles);
+		dst = cycles(&opts->gen, 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);
+				dst = mov_rr(dst, opts->regs[Z80_A], opts->gen.scratch1, SZ_B);
+				dst = mov_rdisp8r(dst, opts->gen.context_reg, zar_off(Z80_A), opts->regs[Z80_A], SZ_B);
+				dst = mov_rrdisp8(dst, 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);
+					dst = mov_rdisp8r(dst, opts->gen.context_reg, zf_off(f), opts->gen.scratch1, SZ_W);
+					dst = mov_rdisp8r(dst, opts->gen.context_reg, zaf_off(f), opts->gen.scratch2, SZ_W);
+					dst = mov_rrdisp8(dst, opts->gen.scratch1, opts->gen.context_reg, zaf_off(f), SZ_W);
+					dst = mov_rrdisp8(dst, 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);
 			}
 		} else {
-			dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, SZ_W);
+			dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.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 = xchg_rr(dst, opts->regs[inst->reg], opts->gen.scratch1, SZ_B);
+			dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
 			dst = call(dst, (uint8_t *)z80_write_byte);
-			dst = zcycles(dst, 1);
+			dst = 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
@@ -481,50 +466,50 @@
 			//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 = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
+			dst = add_ir(dst, 1, opts->gen.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 = xchg_rr(dst, use_reg, opts->gen.scratch1, SZ_B);
+			dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
+			dst = add_ir(dst, 1, opts->gen.scratch2, SZ_W);
 			dst = call(dst, (uint8_t *)z80_write_byte);
 			//restore reg to normal rotation
 			dst = ror_ir(dst, 8, use_reg, SZ_W);
-			dst = zcycles(dst, 2);
+			dst = 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);
+		dst = cycles(&opts->gen, 4);
+		dst = mov_rr(dst, opts->regs[Z80_BC], opts->gen.scratch1, SZ_W);
+		dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W);
+		dst = mov_rdisp8r(dst, opts->gen.context_reg, zar_off(Z80_C), opts->regs[Z80_BC], SZ_W);
+		dst = mov_rdisp8r(dst, opts->gen.context_reg, zar_off(Z80_L), opts->regs[Z80_HL], SZ_W);
+		dst = mov_rrdisp8(dst, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_C), SZ_W);
+		dst = mov_rrdisp8(dst, opts->gen.scratch2, opts->gen.context_reg, zar_off(Z80_L), SZ_W);
+		dst = mov_rr(dst, opts->regs[Z80_DE], opts->gen.scratch1, SZ_W);
+		dst = mov_rdisp8r(dst, opts->gen.context_reg, zar_off(Z80_E), opts->regs[Z80_DE], SZ_W);
+		dst = mov_rrdisp8(dst, 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 = cycles(&opts->gen, 8);
+		dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W);
 		dst = call(dst, (uint8_t *)z80_read_byte);
-		dst = mov_rr(dst, opts->regs[Z80_DE], SCRATCH2, SZ_W);
+		dst = mov_rr(dst, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W);
 		dst = call(dst, (uint8_t *)z80_write_byte);
-		dst = zcycles(dst, 2);
+		dst = cycles(&opts->gen, 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);
 		//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));
+		dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
+		dst = setcc_rdisp8(dst, 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 = cycles(&opts->gen, 8);
+		dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W);
 		dst = call(dst, (uint8_t *)z80_read_byte);
-		dst = mov_rr(dst, opts->regs[Z80_DE], SCRATCH2, SZ_W);
+		dst = mov_rr(dst, opts->regs[Z80_DE], opts->gen.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);
@@ -532,37 +517,37 @@
 		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);
+		dst = 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);
+		dst = 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);
+		dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
+		dst = mov_irdisp8(dst, 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 = cycles(&opts->gen, 8);
+		dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W);
 		dst = call(dst, (uint8_t *)z80_read_byte);
-		dst = mov_rr(dst, opts->regs[Z80_DE], SCRATCH2, SZ_W);
+		dst = mov_rr(dst, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W);
 		dst = call(dst, (uint8_t *)z80_write_byte);
-		dst = zcycles(dst, 2);
+		dst = cycles(&opts->gen, 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);
 		//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));
+		dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
+		dst = setcc_rdisp8(dst, 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 = cycles(&opts->gen, 8);
+		dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W);
 		dst = call(dst, (uint8_t *)z80_read_byte);
-		dst = mov_rr(dst, opts->regs[Z80_DE], SCRATCH2, SZ_W);
+		dst = mov_rr(dst, opts->regs[Z80_DE], opts->gen.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);
@@ -570,15 +555,15 @@
 		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);
+		dst = 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);
+		dst = 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);
+		dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
+		dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B);
 		break;
 	}
 	/*case Z80_CPI:
@@ -595,7 +580,7 @@
 		} else if(z80_size(inst) == SZ_W) {
 			cycles += 4;
 		}
-		dst = zcycles(dst, cycles);
+		dst = cycles(&opts->gen, cycles);
 		dst = translate_z80_reg(inst, &dst_op, dst, opts);
 		dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY);
 		if (src_op.mode == MODE_REG_DIRECT) {
@@ -603,13 +588,13 @@
 		} else {
 			dst = add_ir(dst, 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);
+		dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		dst = mov_irdisp8(dst, 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));
+			dst = setcc_rdisp8(dst, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
+			dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+			dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		}
 		dst = z80_save_reg(dst, inst, opts);
 		dst = z80_save_ea(dst, inst, opts);
@@ -623,21 +608,21 @@
 		} else if(z80_size(inst) == SZ_W) {
 			cycles += 4;
 		}
-		dst = zcycles(dst, cycles);
+		dst = cycles(&opts->gen, 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);
+		dst = bt_irdisp8(dst, 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));
 		} else {
 			dst = adc_ir(dst, 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);
+		dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		dst = mov_irdisp8(dst, 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 = setcc_rdisp8(dst, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
+		dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		dst = z80_save_reg(dst, inst, opts);
 		dst = z80_save_ea(dst, inst, opts);
 		break;
@@ -648,7 +633,7 @@
 		} else if(inst->addr_mode == Z80_IMMED) {
 			cycles += 3;
 		}
-		dst = zcycles(dst, cycles);
+		dst = cycles(&opts->gen, cycles);
 		dst = translate_z80_reg(inst, &dst_op, dst, opts);
 		dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY);
 		if (src_op.mode == MODE_REG_DIRECT) {
@@ -656,12 +641,12 @@
 		} else {
 			dst = sub_ir(dst, 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));
+		dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		dst = mov_irdisp8(dst, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
+		dst = setcc_rdisp8(dst, 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 = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		dst = z80_save_reg(dst, inst, opts);
 		dst = z80_save_ea(dst, inst, opts);
 		break;
@@ -674,21 +659,21 @@
 		} else if(z80_size(inst) == SZ_W) {
 			cycles += 4;
 		}
-		dst = zcycles(dst, cycles);
+		dst = cycles(&opts->gen, 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);
+		dst = bt_irdisp8(dst, 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));
 		} else {
 			dst = sbb_ir(dst, 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_C, opts->gen.context_reg, zf_off(ZF_C));
+		dst = mov_irdisp8(dst, 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 = setcc_rdisp8(dst, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
+		dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		dst = z80_save_reg(dst, inst, opts);
 		dst = z80_save_ea(dst, inst, opts);
 		break;
@@ -701,7 +686,7 @@
 		} else if(z80_size(inst) == SZ_W) {
 			cycles += 4;
 		}
-		dst = zcycles(dst, cycles);
+		dst = cycles(&opts->gen, cycles);
 		dst = translate_z80_reg(inst, &dst_op, dst, opts);
 		dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY);
 		if (src_op.mode == MODE_REG_DIRECT) {
@@ -710,13 +695,13 @@
 			dst = and_ir(dst, 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);
+		dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		dst = mov_irdisp8(dst, 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));
+			dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
+			dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+			dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		}
 		dst = z80_save_reg(dst, inst, opts);
 		dst = z80_save_ea(dst, inst, opts);
@@ -730,7 +715,7 @@
 		} else if(z80_size(inst) == SZ_W) {
 			cycles += 4;
 		}
-		dst = zcycles(dst, cycles);
+		dst = cycles(&opts->gen, cycles);
 		dst = translate_z80_reg(inst, &dst_op, dst, opts);
 		dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY);
 		if (src_op.mode == MODE_REG_DIRECT) {
@@ -739,13 +724,13 @@
 			dst = or_ir(dst, 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);
+		dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		dst = mov_irdisp8(dst, 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));
+			dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
+			dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+			dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		}
 		dst = z80_save_reg(dst, inst, opts);
 		dst = z80_save_ea(dst, inst, opts);
@@ -759,7 +744,7 @@
 		} else if(z80_size(inst) == SZ_W) {
 			cycles += 4;
 		}
-		dst = zcycles(dst, cycles);
+		dst = cycles(&opts->gen, cycles);
 		dst = translate_z80_reg(inst, &dst_op, dst, opts);
 		dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY);
 		if (src_op.mode == MODE_REG_DIRECT) {
@@ -768,13 +753,13 @@
 			dst = xor_ir(dst, 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);
+		dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		dst = mov_irdisp8(dst, 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));
+			dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
+			dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+			dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		}
 		dst = z80_save_reg(dst, inst, opts);
 		dst = z80_save_ea(dst, inst, opts);
@@ -786,7 +771,7 @@
 		} else if(inst->addr_mode == Z80_IMMED) {
 			cycles += 3;
 		}
-		dst = zcycles(dst, cycles);
+		dst = cycles(&opts->gen, cycles);
 		dst = translate_z80_reg(inst, &dst_op, dst, opts);
 		dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY);
 		if (src_op.mode == MODE_REG_DIRECT) {
@@ -794,12 +779,12 @@
 		} else {
 			dst = cmp_ir(dst, 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));
+		dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		dst = mov_irdisp8(dst, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
+		dst = setcc_rdisp8(dst, 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 = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		dst = z80_save_reg(dst, inst, opts);
 		dst = z80_save_ea(dst, inst, opts);
 		break;
@@ -812,18 +797,18 @@
 		} 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;
 		}
-		dst = zcycles(dst, cycles);
+		dst = cycles(&opts->gen, cycles);
 		dst = translate_z80_reg(inst, &dst_op, dst, opts);
 		if (dst_op.mode == MODE_UNUSED) {
 			dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY);
 		}
 		dst = add_ir(dst, 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);
+			dst = mov_irdisp8(dst, 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 = setcc_rdisp8(dst, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
+			dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+			dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		}
 		dst = z80_save_reg(dst, inst, opts);
 		dst = z80_save_ea(dst, inst, opts);
@@ -838,18 +823,18 @@
 		} 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;
 		}
-		dst = zcycles(dst, cycles);
+		dst = cycles(&opts->gen, cycles);
 		dst = translate_z80_reg(inst, &dst_op, dst, opts);
 		if (dst_op.mode == MODE_UNUSED) {
 			dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY);
 		}
 		dst = sub_ir(dst, 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);
+			dst = mov_irdisp8(dst, 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 = setcc_rdisp8(dst, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
+			dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+			dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		}
 		dst = z80_save_reg(dst, inst, opts);
 		dst = z80_save_ea(dst, inst, opts);
@@ -857,76 +842,76 @@
 		break;
 	//case Z80_DAA:
 	case Z80_CPL:
-		dst = zcycles(dst, 4);
+		dst = cycles(&opts->gen, 4);
 		dst = not_r(dst, opts->regs[Z80_A], SZ_B);
 		//TODO: Implement half-carry flag
-		dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_N), SZ_B);
+		dst = mov_irdisp8(dst, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		break;
 	case Z80_NEG:
-		dst = zcycles(dst, 8);
+		dst = cycles(&opts->gen, 8);
 		dst = neg_r(dst, 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);
+		dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S));
+		dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		dst = setcc_rdisp8(dst, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
+		dst = mov_irdisp8(dst, 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);
+		dst = cycles(&opts->gen, 4);
+		dst = xor_irdisp8(dst, 1, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
+		dst = mov_irdisp8(dst, 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);
+		dst = cycles(&opts->gen, 4);
+		dst = mov_irdisp8(dst, 1, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
+		dst = mov_irdisp8(dst, 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 = mov_rr(dst, opts->gen.context_reg, RDI, SZ_Q);
 			dst = jmp(dst, (uint8_t *)z80_print_regs_exit);
 		} else {
-			dst = zcycles(dst, 4 * inst->immed);
+			dst = cycles(&opts->gen, 4 * inst->immed);
 		}
 		break;
 	case Z80_HALT:
-		dst = zcycles(dst, 4);
-		dst = mov_ir(dst, address, SCRATCH1, SZ_W);
+		dst = cycles(&opts->gen, 4);
+		dst = mov_ir(dst, address, opts->gen.scratch1, SZ_W);
 		uint8_t * call_inst = dst;
 		dst = call(dst, (uint8_t *)z80_halt);
 		dst = jmp(dst, 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);
+		dst = cycles(&opts->gen, 4);
+		dst = mov_irdisp8(dst, 0, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B);
+		dst = mov_irdisp8(dst, 0, opts->gen.context_reg, offsetof(z80_context, iff2), SZ_B);
+		dst = mov_rdisp8r(dst, opts->gen.context_reg, offsetof(z80_context, sync_cycle), opts->gen.limit, SZ_D);
+		dst = mov_irdisp8(dst, 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);
+		dst = cycles(&opts->gen, 4);
+		dst = mov_rrdisp32(dst, opts->gen.cycles, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D);
+		dst = mov_irdisp8(dst, 1, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B);
+		dst = mov_irdisp8(dst, 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 = add_irdisp32(dst, 4, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D);
 		dst = call(dst, (uint8_t *)z80_do_sync);
 		break;
 	case Z80_IM:
-		dst = zcycles(dst, 4);
-		dst = mov_irdisp8(dst, inst->immed, CONTEXT, offsetof(z80_context, im), SZ_B);
+		dst = cycles(&opts->gen, 4);
+		dst = mov_irdisp8(dst, 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);
+		dst = cycles(&opts->gen, 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);
+			dst = cycles(&opts->gen, 1);
 		} else {
 			src_op.mode = MODE_UNUSED;
 			dst = translate_z80_reg(inst, &dst_op, dst, opts);
@@ -935,13 +920,13 @@
 		if (src_op.mode != MODE_UNUSED) {
 			dst = mov_rr(dst, 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);
+		dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		dst = mov_irdisp8(dst, 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));
+		dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
+		dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		if (inst->addr_mode != Z80_UNUSED) {
 			dst = z80_save_result(dst, inst);
 			if (src_op.mode != MODE_UNUSED) {
@@ -953,27 +938,27 @@
 		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);
+		dst = cycles(&opts->gen, 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);
+			dst = cycles(&opts->gen, 1);
 		} else {
 			src_op.mode = MODE_UNUSED;
 			dst = translate_z80_reg(inst, &dst_op, dst, opts);
 		}
-		dst = bt_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B);
+		dst = bt_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
 		dst = rcl_ir(dst, 1, dst_op.base, SZ_B);
 		if (src_op.mode != MODE_UNUSED) {
 			dst = mov_rr(dst, 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);
+		dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		dst = mov_irdisp8(dst, 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));
+		dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
+		dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		if (inst->addr_mode != Z80_UNUSED) {
 			dst = z80_save_result(dst, inst);
 			if (src_op.mode != MODE_UNUSED) {
@@ -985,11 +970,11 @@
 		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);
+		dst = cycles(&opts->gen, 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);
+			dst = cycles(&opts->gen, 1);
 		} else {
 			src_op.mode = MODE_UNUSED;
 			dst = translate_z80_reg(inst, &dst_op, dst, opts);
@@ -998,13 +983,13 @@
 		if (src_op.mode != MODE_UNUSED) {
 			dst = mov_rr(dst, 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);
+		dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		dst = mov_irdisp8(dst, 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));
+		dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
+		dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		if (inst->addr_mode != Z80_UNUSED) {
 			dst = z80_save_result(dst, inst);
 			if (src_op.mode != MODE_UNUSED) {
@@ -1016,27 +1001,27 @@
 		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);
+		dst = cycles(&opts->gen, 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);
+			dst = cycles(&opts->gen, 1);
 		} else {
 			src_op.mode = MODE_UNUSED;
 			dst = translate_z80_reg(inst, &dst_op, dst, opts);
 		}
-		dst = bt_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B);
+		dst = bt_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
 		dst = rcr_ir(dst, 1, dst_op.base, SZ_B);
 		if (src_op.mode != MODE_UNUSED) {
 			dst = mov_rr(dst, 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);
+		dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		dst = mov_irdisp8(dst, 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));
+		dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
+		dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		if (inst->addr_mode != Z80_UNUSED) {
 			dst = z80_save_result(dst, inst);
 			if (src_op.mode != MODE_UNUSED) {
@@ -1049,29 +1034,29 @@
 	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);
+		dst = cycles(&opts->gen, 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);
+			dst = cycles(&opts->gen, 1);
 		} else {
 			src_op.mode = MODE_UNUSED;
 			dst = translate_z80_reg(inst, &dst_op, dst, opts);
 		}
 		dst = shl_ir(dst, 1, dst_op.base, SZ_B);
-		dst  = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C));
+		dst  = setcc_rdisp8(dst, 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);
 		}
 		if (src_op.mode != MODE_UNUSED) {
 			dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B);
 		}
-		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
+		dst = mov_irdisp8(dst, 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));
+		dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
+		dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		if (inst->addr_mode != Z80_UNUSED) {
 			dst = z80_save_result(dst, inst);
 			if (src_op.mode != MODE_UNUSED) {
@@ -1083,11 +1068,11 @@
 		break;
 	case Z80_SRA:
 		cycles = inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8;
-		dst = zcycles(dst, cycles);
+		dst = cycles(&opts->gen, 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);
+			dst = cycles(&opts->gen, 1);
 		} else {
 			src_op.mode = MODE_UNUSED;
 			dst = translate_z80_reg(inst, &dst_op, dst, opts);
@@ -1096,13 +1081,13 @@
 		if (src_op.mode != MODE_UNUSED) {
 			dst = mov_rr(dst, 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);
+		dst  = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		dst = mov_irdisp8(dst, 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));
+		dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
+		dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		if (inst->addr_mode != Z80_UNUSED) {
 			dst = z80_save_result(dst, inst);
 			if (src_op.mode != MODE_UNUSED) {
@@ -1114,11 +1099,11 @@
 		break;
 	case Z80_SRL:
 		cycles = inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8;
-		dst = zcycles(dst, cycles);
+		dst = cycles(&opts->gen, 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);
+			dst = cycles(&opts->gen, 1);
 		} else {
 			src_op.mode = MODE_UNUSED;
 			dst = translate_z80_reg(inst, &dst_op, dst, opts);
@@ -1127,13 +1112,13 @@
 		if (src_op.mode != MODE_UNUSED) {
 			dst = mov_rr(dst, 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);
+		dst  = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C));
+		dst = mov_irdisp8(dst, 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));
+		dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
+		dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		if (inst->addr_mode != Z80_UNUSED) {
 			dst = z80_save_result(dst, inst);
 			if (src_op.mode != MODE_UNUSED) {
@@ -1144,65 +1129,65 @@
 		}
 		break;
 	case Z80_RLD:
-		dst = zcycles(dst, 8);
-		dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH1, SZ_W);
+		dst = cycles(&opts->gen, 8);
+		dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W);
 		dst = call(dst, (uint8_t *)z80_read_byte);
 		//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 = mov_rr(dst, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
+		dst = shl_ir(dst, 4, opts->gen.scratch1, SZ_W);
+		dst = and_ir(dst, 0xF, opts->gen.scratch2, SZ_W);
+		dst = and_ir(dst, 0xFFF, opts->gen.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);
+		dst = or_rr(dst, opts->gen.scratch2, opts->gen.scratch1, SZ_W);
+		//opts->gen.scratch1 = 0x0124
+		dst = ror_ir(dst, 8, opts->gen.scratch1, SZ_W);
+		dst = cycles(&opts->gen, 4);
+		dst = or_rr(dst, 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));
+		dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
+		dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
+		dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		dst = setcc_rdisp8(dst, 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 = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W);
+		dst = ror_ir(dst, 8, opts->gen.scratch1, SZ_W);
 		dst = call(dst, (uint8_t *)z80_write_byte);
 		break;
 	case Z80_RRD:
-		dst = zcycles(dst, 8);
-		dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH1, SZ_W);
+		dst = cycles(&opts->gen, 8);
+		dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W);
 		dst = call(dst, (uint8_t *)z80_read_byte);
 		//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 = movzx_rr(dst, opts->regs[Z80_A], opts->gen.scratch2, SZ_B, SZ_W);
+		dst = ror_ir(dst, 4, opts->gen.scratch1, SZ_W);
+		dst = shl_ir(dst, 4, opts->gen.scratch2, SZ_W);
+		dst = and_ir(dst, 0xF00F, opts->gen.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);
+		//opts->gen.scratch1 = 0x2001
+		//opts->gen.scratch2 = 0x0040
+		dst = or_rr(dst, opts->gen.scratch2, opts->gen.scratch1, SZ_W);
+		//opts->gen.scratch1 = 0x2041
+		dst = ror_ir(dst, 8, opts->gen.scratch1, SZ_W);
+		dst = cycles(&opts->gen, 4);
+		dst = shr_ir(dst, 4, opts->gen.scratch1, SZ_B);
+		dst = or_rr(dst, 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));
+		dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
+		dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
+		dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
+		dst = setcc_rdisp8(dst, 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 = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W);
+		dst = ror_ir(dst, 8, opts->gen.scratch1, SZ_W);
 		dst = call(dst, (uint8_t *)z80_write_byte);
 		break;
 	case Z80_BIT: {
 		cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16;
-		dst = zcycles(dst, cycles);
+		dst = cycles(&opts->gen, 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)];
@@ -1215,23 +1200,23 @@
 		}
 		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);
+			dst = 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);
+		dst = setcc_rdisp8(dst, CC_NC, opts->gen.context_reg, zf_off(ZF_Z));
+		dst = setcc_rdisp8(dst, CC_NC, opts->gen.context_reg, zf_off(ZF_PV));
+		dst = mov_irdisp8(dst, 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));
+			dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		} else {
-			dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_S), SZ_B);
+			dst = mov_irdisp8(dst, 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);
+		dst = cycles(&opts->gen, 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)];
@@ -1247,7 +1232,7 @@
 		}
 		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);
+			dst = cycles(&opts->gen, 1);
 		}
 		dst = bts_ir(dst, bit, src_op.base, size);
 		if (inst->reg != Z80_USE_IMMED) {
@@ -1273,7 +1258,7 @@
 	}
 	case Z80_RES: {
 		cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16;
-		dst = zcycles(dst, cycles);
+		dst = cycles(&opts->gen, 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)];
@@ -1289,7 +1274,7 @@
 		}
 		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);
+			dst = cycles(&opts->gen, 1);
 		}
 		dst = btr_ir(dst, bit, src_op.base, size);
 		if (inst->reg != Z80_USE_IMMED) {
@@ -1320,7 +1305,7 @@
 		} else if(inst->ea_reg == Z80_IX || inst->ea_reg == Z80_IY) {
 			cycles += 4;
 		}
-		dst = zcycles(dst, cycles);
+		dst = cycles(&opts->gen, cycles);
 		if (inst->addr_mode != Z80_REG_INDIRECT && inst->immed < 0x4000) {
 			uint8_t * call_dst = z80_get_native_address(context, inst->immed);
 			if (!call_dst) {
@@ -1331,44 +1316,44 @@
 			dst = jmp(dst, call_dst);
 		} else {
 			if (inst->addr_mode == Z80_REG_INDIRECT) {
-				dst = mov_rr(dst, opts->regs[inst->ea_reg], SCRATCH1, SZ_W);
+				dst = mov_rr(dst, opts->regs[inst->ea_reg], opts->gen.scratch1, SZ_W);
 			} else {
-				dst = mov_ir(dst, inst->immed, SCRATCH1, SZ_W);
+				dst = mov_ir(dst, inst->immed, opts->gen.scratch1, SZ_W);
 			}
 			dst = call(dst, (uint8_t *)z80_native_addr);
-			dst = jmp_r(dst, SCRATCH1);
+			dst = jmp_r(dst, opts->gen.scratch1);
 		}
 		break;
 	}
 	case Z80_JPCC: {
-		dst = zcycles(dst, 7);//T States: 4,3
+		dst = 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);
+			dst = cmp_irdisp8(dst, 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);
+			dst = cmp_irdisp8(dst, 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);
+			dst = cmp_irdisp8(dst, 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);
+			dst = cmp_irdisp8(dst, 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
+		dst = 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);
@@ -1379,15 +1364,15 @@
 			}
 			dst = jmp(dst, call_dst);
 		} else {
-			dst = mov_ir(dst, dest_addr, SCRATCH1, SZ_W);
+			dst = mov_ir(dst, dest_addr, opts->gen.scratch1, SZ_W);
 			dst = call(dst, (uint8_t *)z80_native_addr);
-			dst = jmp_r(dst, SCRATCH1);
+			dst = jmp_r(dst, opts->gen.scratch1);
 		}
 		*no_jump_off = dst - (no_jump_off+1);
 		break;
 	}
 	case Z80_JR: {
-		dst = zcycles(dst, 12);//T States: 4,3,5
+		dst = 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);
@@ -1398,31 +1383,31 @@
 			}
 			dst = jmp(dst, call_dst);
 		} else {
-			dst = mov_ir(dst, dest_addr, SCRATCH1, SZ_W);
+			dst = mov_ir(dst, dest_addr, opts->gen.scratch1, SZ_W);
 			dst = call(dst, (uint8_t *)z80_native_addr);
-			dst = jmp_r(dst, SCRATCH1);
+			dst = jmp_r(dst, opts->gen.scratch1);
 		}
 		break;
 	}
 	case Z80_JRCC: {
-		dst = zcycles(dst, 7);//T States: 4,3
+		dst = 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);
+			dst = cmp_irdisp8(dst, 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);
+			dst = cmp_irdisp8(dst, 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
+		dst = 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);
@@ -1433,19 +1418,19 @@
 			}
 			dst = jmp(dst, call_dst);
 		} else {
-			dst = mov_ir(dst, dest_addr, SCRATCH1, SZ_W);
+			dst = mov_ir(dst, dest_addr, opts->gen.scratch1, SZ_W);
 			dst = call(dst, (uint8_t *)z80_native_addr);
-			dst = jmp_r(dst, SCRATCH1);
+			dst = jmp_r(dst, opts->gen.scratch1);
 		}
 		*no_jump_off = dst - (no_jump_off+1);
 		break;
 	}
 	case Z80_DJNZ:
-		dst = zcycles(dst, 8);//T States: 5,3
+		dst = cycles(&opts->gen, 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
+		dst = 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);
@@ -1456,17 +1441,17 @@
 			}
 			dst = jmp(dst, call_dst);
 		} else {
-			dst = mov_ir(dst, dest_addr, SCRATCH1, SZ_W);
+			dst = mov_ir(dst, dest_addr, opts->gen.scratch1, SZ_W);
 			dst = call(dst, (uint8_t *)z80_native_addr);
-			dst = jmp_r(dst, SCRATCH1);
+			dst = jmp_r(dst, opts->gen.scratch1);
 		}
 		*no_jump_off = dst - (no_jump_off+1);
 		break;
 	case Z80_CALL: {
-		dst = zcycles(dst, 11);//T States: 4,3,4
+		dst = cycles(&opts->gen, 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 = mov_ir(dst, address + 3, opts->gen.scratch1, SZ_W);
+		dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
 		dst = call(dst, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3
 		if (inst->immed < 0x4000) {
 			uint8_t * call_dst = z80_get_native_address(context, inst->immed);
@@ -1477,44 +1462,44 @@
 			}
 			dst = jmp(dst, call_dst);
 		} else {
-			dst = mov_ir(dst, inst->immed, SCRATCH1, SZ_W);
+			dst = mov_ir(dst, inst->immed, opts->gen.scratch1, SZ_W);
 			dst = call(dst, (uint8_t *)z80_native_addr);
-			dst = jmp_r(dst, SCRATCH1);
+			dst = jmp_r(dst, opts->gen.scratch1);
 		}
 		break;
 	}
 	case Z80_CALLCC:
-		dst = zcycles(dst, 10);//T States: 4,3,3 (false case)
+		dst = 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);
+			dst = cmp_irdisp8(dst, 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);
+			dst = cmp_irdisp8(dst, 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);
+			dst = cmp_irdisp8(dst, 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);
+			dst = cmp_irdisp8(dst, 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 = cycles(&opts->gen, 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 = mov_ir(dst, address + 3, opts->gen.scratch1, SZ_W);
+		dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
 		dst = call(dst, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3
 		if (inst->immed < 0x4000) {
 			uint8_t * call_dst = z80_get_native_address(context, inst->immed);
@@ -1525,81 +1510,81 @@
 			}
 			dst = jmp(dst, call_dst);
 		} else {
-			dst = mov_ir(dst, inst->immed, SCRATCH1, SZ_W);
+			dst = mov_ir(dst, inst->immed, opts->gen.scratch1, SZ_W);
 			dst = call(dst, (uint8_t *)z80_native_addr);
-			dst = jmp_r(dst, SCRATCH1);
+			dst = jmp_r(dst, opts->gen.scratch1);
 		}
 		*no_call_off = dst - (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 = cycles(&opts->gen, 4);//T States: 4
+		dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.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);
+		dst = jmp_r(dst, opts->gen.scratch1);
 		break;
 	case Z80_RETCC: {
-		dst = zcycles(dst, 5);//T States: 5
+		dst = 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);
+			dst = cmp_irdisp8(dst, 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);
+			dst = cmp_irdisp8(dst, 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);
+			dst = cmp_irdisp8(dst, 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);
+			dst = cmp_irdisp8(dst, 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 = mov_rr(dst, opts->regs[Z80_SP], opts->gen.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);
+		dst = jmp_r(dst, opts->gen.scratch1);
 		*no_call_off = dst - (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 = cycles(&opts->gen, 8);//T States: 4, 4
+		dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.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);
+		dst = jmp_r(dst, 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 = cycles(&opts->gen, 8);//T States: 4, 4
+		dst = mov_rdisp8r(dst, opts->gen.context_reg, offsetof(z80_context, iff2), opts->gen.scratch2, SZ_B);
+		dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
+		dst = mov_rrdisp8(dst, opts->gen.scratch2, opts->gen.context_reg, 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);
+		dst = jmp_r(dst, 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 = cycles(&opts->gen, 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 = mov_ir(dst, address + 1, opts->gen.scratch1, SZ_W);
+		dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.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);
 		if (!call_dst) {
@@ -1611,15 +1596,15 @@
 		break;
 	}
 	case Z80_IN:
-		dst = zcycles(dst, inst->reg == Z80_A ? 7 : 8);//T States: 4 3/4
+		dst = 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);
+			dst = mov_ir(dst, inst->immed, opts->gen.scratch1, SZ_B);
 		} else {
-			dst = mov_rr(dst, opts->regs[Z80_C], SCRATCH1, SZ_B);
+			dst = mov_rr(dst, 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 = mov_rr(dst, opts->gen.scratch1, dst_op.base, SZ_B);
 		dst = z80_save_reg(dst, inst, opts);
 		break;
 	/*case Z80_INI:
@@ -1627,14 +1612,14 @@
 	case Z80_IND:
 	case Z80_INDR:*/
 	case Z80_OUT:
-		dst = zcycles(dst, inst->reg == Z80_A ? 7 : 8);//T States: 4 3/4
+		dst = 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);
+			dst = mov_ir(dst, inst->immed, opts->gen.scratch2, SZ_B);
 		} else {
-			dst = mov_rr(dst, opts->regs[Z80_C], SCRATCH2, SZ_B);
+			dst = mov_rr(dst, 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 = mov_rr(dst, dst_op.base, opts->gen.scratch1, SZ_B);
 		dst = call(dst, (uint8_t *)z80_io_write);
 		dst = z80_save_reg(dst, inst, opts);
 		break;
@@ -1676,7 +1661,7 @@
 	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)
 {
 	if (address >= 0x4000) {
 		return 0;
@@ -1688,7 +1673,7 @@
 {
 	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;
@@ -1752,7 +1737,7 @@
 	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 = mov_ir(dst, inst_start, opts->gen.scratch1, SZ_D);
 		dst = call(dst, (uint8_t *)z80_retrans_stub);
 	}
 	return context;
@@ -1773,7 +1758,7 @@
 
 void z80_handle_deferred(z80_context * context)
 {
-	x86_z80_options * opts = context->options;
+	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);
@@ -1783,7 +1768,7 @@
 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;
@@ -1850,7 +1835,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) {
@@ -1923,8 +1908,17 @@
 	}
 }
 
-void init_x86_z80_opts(x86_z80_options * options)
+void init_x86_z80_opts(z80_options * options, memmap_chunk * 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->flags = 0;
 	options->regs[Z80_B] = BH;
 	options->regs[Z80_C] = RBX;
@@ -1946,15 +1940,146 @@
 	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);
+
+	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);
 	memset(options->ram_inst_sizes, 0, sizeof(uint8_t) * 0x2000);
-	options->deferred = NULL;
+
+	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) {
+			int reg = i /2 + Z80_BC;
+			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 (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);
+
+	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) {
+			int reg = i /2 + Z80_BC;
+			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 (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);
+
+	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;
+	//return to caller of z80_run
+	retn(code);
+
+	options->gen.read_8 = gen_mem_fun(&options->gen, chunks, num_chunks, READ_8, NULL);
+	options->gen.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
+	move_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff1), SZ_B);
+	move_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(options->gen.scratch2);
+	//TODO: Support interrupt mode 0 and 2
+	mov_ir(code, 0x38, options->gen.scratch1, SZ_W);
+	call(code, (code_ptr)z80_native_addr);
+	jmp_r(code, options->gen.scratch1);
 }
 
-void init_z80_context(z80_context * context, x86_z80_options * 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));
@@ -1979,9 +2104,9 @@
 	static uint8_t * bp_stub = NULL;
 	uint8_t * native = z80_get_native_address_trans(context, address);
 	uint8_t * start_native = native;
-	native = mov_ir(native, address, SCRATCH1, SZ_W);
+	native = mov_ir(native, address, opts->gen.scratch1, SZ_W);
 	if (!bp_stub) {
-		x86_z80_options * opts = context->options;
+		z80_options * opts = context->options;
 		uint8_t * dst = opts->cur_code;
 		uint8_t * dst_end = opts->code_end;
 		if (dst_end - dst < 128) {
@@ -1999,27 +2124,27 @@
 
 		//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 = push_r(dst, opts->gen.scratch1);
+		dst = mov_rr(dst, opts->gen.context_reg, RDI, SZ_Q);
+		dst = mov_rr(dst, opts->gen.scratch1, RSI, SZ_W);
 		dst = call(dst, bp_handler);
-		dst = mov_rr(dst, RAX, CONTEXT, SZ_Q);
+		dst = mov_rr(dst, RAX, opts->gen.context_reg, SZ_Q);
 		//Restore context
 		dst = call(dst, (uint8_t *)z80_load_context);
-		dst = pop_r(dst, SCRATCH1);
+		dst = pop_r(dst, opts->gen.scratch1);
 		//do prologue stuff
-		dst = cmp_rr(dst, ZCYCLES, ZLIMIT, SZ_D);
+		dst = cmp_rr(dst, opts->gen.cycles, opts->gen.limit, 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 - (native-start_native), SCRATCH1, SZ_Q);
-		dst = push_r(dst, SCRATCH1);
+		dst = pop_r(dst, opts->gen.scratch1);
+		dst = add_ir(dst, check_int_size - (native-start_native), opts->gen.scratch1, SZ_Q);
+		dst = push_r(dst, opts->gen.scratch1);
 		dst = jmp(dst, (uint8_t *)z80_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);
+		dst = pop_r(dst, opts->gen.scratch1);
+		dst = add_ir(dst, check_int_size - (native-start_native), opts->gen.scratch1, SZ_Q);
+		dst = jmp_r(dst, opts->gen.scratch1);
 		opts->cur_code = dst;
 	} else {
 		native = call(native, bp_stub);
--- a/z80_to_x86.h	Tue Mar 11 09:44:47 2014 -0700
+++ b/z80_to_x86.h	Sun Dec 14 16:45:23 2014 -0800
@@ -22,13 +22,14 @@
 };
 
 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        write_8_noinc;
+
 	uint32_t        flags;
 	int8_t          regs[Z80_UNUSED];
-} x86_z80_options;
+} z80_options;
 
 typedef struct {
 	void *            native_pc;
@@ -51,7 +52,7 @@
 	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;
@@ -59,8 +60,8 @@
 } 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);
+void init_x86_z80_opts(z80_options * options, memmap_chunk * chunks, uint32_t num_chunks);
+void init_z80_context(z80_context * context, 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);
 z80_context * z80_handle_code_write(uint32_t address, z80_context * context);