changeset 593:5ef3fe516da9

Z80 core is sort of working again
author Michael Pavone <pavone@retrodev.com>
date Mon, 22 Dec 2014 20:55:10 -0800
parents 4ff7bbb3943b
children 086de8692932
files Makefile backend.h backend_x86.c blastem.c gen_x86.c gen_x86.h z80_to_x86.c z80_to_x86.h ztestrun.c
diffstat 9 files changed, 228 insertions(+), 130 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Wed Dec 17 23:03:19 2014 -0800
+++ b/Makefile	Mon Dec 22 20:55:10 2014 -0800
@@ -38,7 +38,7 @@
 endif
 endif
 
-Z80OBJS=z80inst.o z80_to_x86.o zruntime.o
+Z80OBJS=z80inst.o z80_to_x86.o
 AUDIOOBJS=ym2612.o psg.o wave.o
 CONFIGOBJS=config.o tern.o util.o
 
--- a/backend.h	Wed Dec 17 23:03:19 2014 -0800
+++ b/backend.h	Mon Dec 22 20:55:10 2014 -0800
@@ -109,7 +109,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 *after_inc);
+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_
 
--- a/backend_x86.c	Wed Dec 17 23:03:19 2014 -0800
+++ b/backend_x86.c	Mon Dec 22 20:55:10 2014 -0800
@@ -28,7 +28,7 @@
 	*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 *after_inc)
+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;
--- a/blastem.c	Wed Dec 17 23:03:19 2014 -0800
+++ b/blastem.c	Mon Dec 22 20:55:10 2014 -0800
@@ -198,7 +198,7 @@
 				}
 				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. Native PC: %p\n", z_context->current_cycle, z_context->sync_cycle, z_context->native_pc);
-				z80_run(z_context);
+				z_context->run(z_context);
 				dprintf("Z80 ran to cycle %d\n", z_context->current_cycle);
 			}
 		}
--- a/gen_x86.c	Wed Dec 17 23:03:19 2014 -0800
+++ b/gen_x86.c	Mon Dec 22 20:55:10 2014 -0800
@@ -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
@@ -1516,6 +1517,13 @@
 	code->cur = out;
 }
 
+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);
@@ -1528,6 +1536,19 @@
 	code->cur = out;
 }
 
+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);
@@ -1855,6 +1876,19 @@
 	code->cur = out;
 }
 
+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);
--- a/gen_x86.h	Wed Dec 17 23:03:19 2014 -0800
+++ b/gen_x86.h	Mon Dec 22 20:55:10 2014 -0800
@@ -187,7 +187,9 @@
 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);
@@ -208,6 +210,7 @@
 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);
--- a/z80_to_x86.c	Wed Dec 17 23:03:19 2014 -0800
+++ b/z80_to_x86.c	Mon Dec 22 20:55:10 2014 -0800
@@ -28,22 +28,6 @@
 #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 z80_size(z80inst * inst)
 {
 	uint8_t reg = (inst->reg & 0x1F);
@@ -184,9 +168,9 @@
 				push_r(code, opts->gen.scratch1);
 			}*/
 			if (size == SZ_B) {
-				call(code, (uint8_t *)z80_read_byte);
+				call(code, opts->read_8);
 			} else {
-				call(code, (uint8_t *)z80_read_word);
+				call(code, opts->read_16);
 			}
 			if (modify) {
 				//pop_r(code, opts->gen.scratch2);
@@ -207,9 +191,9 @@
 				mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_W);
 			}
 			if (size == SZ_B) {
-				call(code, (uint8_t *)z80_read_byte);
+				call(code, opts->read_8);
 			} else {
-				call(code, (uint8_t *)z80_read_word);
+				call(code, opts->read_16);
 			}
 			if (modify) {
 				//pop_r(code, opts->gen.scratch2);
@@ -248,7 +232,7 @@
 	}
 }
 
-void z80_save_result(code_info *code, z80inst * inst)
+void z80_save_result(z80_options *opts, z80inst * inst)
 {
 	switch(inst->addr_mode & 0x1f)
 	{
@@ -257,9 +241,9 @@
 	case Z80_IX_DISPLACE:
 	case Z80_IY_DISPLACE:
 		if (z80_size(inst) == SZ_B) {
-			call(code, (uint8_t *)z80_write_byte);
+			call(&opts->gen.code, opts->write_8);
 		} else {
-			call(code, (uint8_t *)z80_write_word_lowfirst);
+			call(&opts->gen.code, opts->write_16_lowfirst);
 		}
 	}
 }
@@ -369,7 +353,7 @@
 		z80_save_reg(inst, opts);
 		z80_save_ea(code, inst, opts);
 		if (inst->addr_mode & Z80_DIR) {
-			z80_save_result(code, inst);
+			z80_save_result(opts, inst);
 		}
 		break;
 	case Z80_PUSH:
@@ -394,14 +378,14 @@
 			mov_rr(code, src_op.base, opts->gen.scratch1, SZ_W);
 		}
 		mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
-		call(code, (uint8_t *)z80_write_word_highfirst);
+		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:
 		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, (uint8_t *)z80_read_word);
+		call(code, opts->read_16);
 		add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
 		if (inst->reg == Z80_AF) {
 
@@ -452,10 +436,10 @@
 			}
 		} else {
 			mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
-			call(code, (uint8_t *)z80_read_byte);
+			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, (uint8_t *)z80_write_byte);
+			call(code, opts->write_8);
 			cycles(&opts->gen, 1);
 			uint8_t high_reg = z80_high_reg(inst->reg);
 			uint8_t use_reg;
@@ -466,11 +450,11 @@
 			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, (uint8_t *)z80_read_byte);
+			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, (uint8_t *)z80_write_byte);
+			call(code, opts->write_8);
 			//restore reg to normal rotation
 			ror_ir(code, 8, use_reg, SZ_W);
 			cycles(&opts->gen, 2);
@@ -491,9 +475,9 @@
 	case Z80_LDI: {
 		cycles(&opts->gen, 8);
 		mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W);
-		call(code, (uint8_t *)z80_read_byte);
+		call(code, opts->read_8);
 		mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W);
-		call(code, (uint8_t *)z80_write_byte);
+		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);
@@ -506,9 +490,9 @@
 	case Z80_LDIR: {
 		cycles(&opts->gen, 8);
 		mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W);
-		call(code, (uint8_t *)z80_read_byte);
+		call(code, opts->read_8);
 		mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W);
-		call(code, (uint8_t *)z80_write_byte);
+		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);
 
@@ -529,9 +513,9 @@
 	case Z80_LDD: {
 		cycles(&opts->gen, 8);
 		mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W);
-		call(code, (uint8_t *)z80_read_byte);
+		call(code, opts->read_8);
 		mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W);
-		call(code, (uint8_t *)z80_write_byte);
+		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);
@@ -544,9 +528,9 @@
 	case Z80_LDDR: {
 		cycles(&opts->gen, 8);
 		mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W);
-		call(code, (uint8_t *)z80_read_byte);
+		call(code, opts->read_8);
 		mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W);
-		call(code, (uint8_t *)z80_write_byte);
+		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);
 
@@ -810,7 +794,7 @@
 		}
 		z80_save_reg(inst, opts);
 		z80_save_ea(code, inst, opts);
-		z80_save_result(code, inst);
+		z80_save_result(opts, inst);
 		break;
 	case Z80_DEC:
 		num_cycles = 4;
@@ -836,7 +820,7 @@
 		}
 		z80_save_reg(inst, opts);
 		z80_save_ea(code, inst, opts);
-		z80_save_result(code, inst);
+		z80_save_result(opts, inst);
 		break;
 	//case Z80_DAA:
 	case Z80_CPL:
@@ -869,20 +853,30 @@
 		break;
 	case Z80_NOP:
 		if (inst->immed == 42) {
-			call(code, (uint8_t *)z80_save_context);
+			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 {
 			cycles(&opts->gen, 4 * inst->immed);
 		}
 		break;
-	case Z80_HALT:
+	case Z80_HALT: {
 		cycles(&opts->gen, 4);
 		mov_ir(code, address, opts->gen.scratch1, SZ_W);
 		uint8_t * call_inst = code->cur;
-		call(code, (uint8_t *)z80_halt);
+		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_B, opts->gen.handle_cycle_limit_int);
+		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:
 		cycles(&opts->gen, 4);
 		mov_irdisp(code, 0, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B);
@@ -897,7 +891,7 @@
 		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
 		add_irdisp(code, 4, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D);
-		call(code, (uint8_t *)z80_do_sync);
+		call(code, opts->do_sync);
 		break;
 	case Z80_IM:
 		cycles(&opts->gen, 4);
@@ -926,7 +920,7 @@
 		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) {
-			z80_save_result(code, inst);
+			z80_save_result(opts, inst);
 			if (src_op.mode != MODE_UNUSED) {
 				z80_save_reg(inst, opts);
 			}
@@ -958,7 +952,7 @@
 		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) {
-			z80_save_result(code, inst);
+			z80_save_result(opts, inst);
 			if (src_op.mode != MODE_UNUSED) {
 				z80_save_reg(inst, opts);
 			}
@@ -989,7 +983,7 @@
 		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) {
-			z80_save_result(code, inst);
+			z80_save_result(opts, inst);
 			if (src_op.mode != MODE_UNUSED) {
 				z80_save_reg(inst, opts);
 			}
@@ -1021,7 +1015,7 @@
 		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) {
-			z80_save_result(code, inst);
+			z80_save_result(opts, inst);
 			if (src_op.mode != MODE_UNUSED) {
 				z80_save_reg(inst, opts);
 			}
@@ -1056,7 +1050,7 @@
 		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) {
-			z80_save_result(code, inst);
+			z80_save_result(opts, inst);
 			if (src_op.mode != MODE_UNUSED) {
 				z80_save_reg(inst, opts);
 			}
@@ -1087,7 +1081,7 @@
 		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) {
-			z80_save_result(code, inst);
+			z80_save_result(opts, inst);
 			if (src_op.mode != MODE_UNUSED) {
 				z80_save_reg(inst, opts);
 			}
@@ -1118,7 +1112,7 @@
 		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) {
-			z80_save_result(code, inst);
+			z80_save_result(opts, inst);
 			if (src_op.mode != MODE_UNUSED) {
 				z80_save_reg(inst, opts);
 			}
@@ -1129,7 +1123,7 @@
 	case Z80_RLD:
 		cycles(&opts->gen, 8);
 		mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W);
-		call(code, (uint8_t *)z80_read_byte);
+		call(code, opts->read_8);
 		//Before: (HL) = 0x12, A = 0x34
 		//After: (HL) = 0x24, A = 0x31
 		mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
@@ -1151,12 +1145,12 @@
 
 		mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W);
 		ror_ir(code, 8, opts->gen.scratch1, SZ_W);
-		call(code, (uint8_t *)z80_write_byte);
+		call(code, opts->write_8);
 		break;
 	case Z80_RRD:
 		cycles(&opts->gen, 8);
 		mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W);
-		call(code, (uint8_t *)z80_read_byte);
+		call(code, opts->read_8);
 		//Before: (HL) = 0x12, A = 0x34
 		//After: (HL) = 0x41, A = 0x32
 		movzx_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B, SZ_W);
@@ -1181,7 +1175,7 @@
 
 		mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W);
 		ror_ir(code, 8, opts->gen.scratch1, SZ_W);
-		call(code, (uint8_t *)z80_write_byte);
+		call(code, opts->write_8);
 		break;
 	case Z80_BIT: {
 		num_cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16;
@@ -1247,7 +1241,7 @@
 			}
 		}
 		if ((inst->addr_mode & 0x1F) != Z80_REG) {
-			z80_save_result(code, inst);
+			z80_save_result(opts, inst);
 			if (inst->reg != Z80_USE_IMMED) {
 				z80_save_reg(inst, opts);
 			}
@@ -1289,7 +1283,7 @@
 			}
 		}
 		if (inst->addr_mode != Z80_REG) {
-			z80_save_result(code, inst);
+			z80_save_result(opts, inst);
 			if (inst->reg != Z80_USE_IMMED) {
 				z80_save_reg(inst, opts);
 			}
@@ -1318,7 +1312,7 @@
 			} else {
 				mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W);
 			}
-			call(code, (uint8_t *)z80_native_addr);
+			call(code, opts->native_addr);
 			jmp_r(code, opts->gen.scratch1);
 		}
 		break;
@@ -1363,7 +1357,7 @@
 			jmp(code, call_dst);
 		} else {
 			mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W);
-			call(code, (uint8_t *)z80_native_addr);
+			call(code, opts->native_addr);
 			jmp_r(code, opts->gen.scratch1);
 		}
 		*no_jump_off = code->cur - (no_jump_off+1);
@@ -1382,7 +1376,7 @@
 			jmp(code, call_dst);
 		} else {
 			mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W);
-			call(code, (uint8_t *)z80_native_addr);
+			call(code, opts->native_addr);
 			jmp_r(code, opts->gen.scratch1);
 		}
 		break;
@@ -1417,7 +1411,7 @@
 			jmp(code, call_dst);
 		} else {
 			mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W);
-			call(code, (uint8_t *)z80_native_addr);
+			call(code, opts->native_addr);
 			jmp_r(code, opts->gen.scratch1);
 		}
 		*no_jump_off = code->cur - (no_jump_off+1);
@@ -1440,7 +1434,7 @@
 			jmp(code, call_dst);
 		} else {
 			mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W);
-			call(code, (uint8_t *)z80_native_addr);
+			call(code, opts->native_addr);
 			jmp_r(code, opts->gen.scratch1);
 		}
 		*no_jump_off = code->cur - (no_jump_off+1);
@@ -1450,7 +1444,7 @@
 		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, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3
+		call(code, opts->write_16_highfirst);//T States: 3, 3
 		if (inst->immed < 0x4000) {
 			code_ptr call_dst = z80_get_native_address(context, inst->immed);
 			if (!call_dst) {
@@ -1461,7 +1455,7 @@
 			jmp(code, call_dst);
 		} else {
 			mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W);
-			call(code, (uint8_t *)z80_native_addr);
+			call(code, opts->native_addr);
 			jmp_r(code, opts->gen.scratch1);
 		}
 		break;
@@ -1498,7 +1492,7 @@
 		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, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3
+		call(code, opts->write_16_highfirst);//T States: 3, 3
 		if (inst->immed < 0x4000) {
 			code_ptr call_dst = z80_get_native_address(context, inst->immed);
 			if (!call_dst) {
@@ -1509,7 +1503,7 @@
 			jmp(code, call_dst);
 		} else {
 			mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W);
-			call(code, (uint8_t *)z80_native_addr);
+			call(code, opts->native_addr);
 			jmp_r(code, opts->gen.scratch1);
 		}
 		*no_call_off = code->cur - (no_call_off+1);
@@ -1517,9 +1511,9 @@
 	case Z80_RET:
 		cycles(&opts->gen, 4);//T States: 4
 		mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
-		call(code, (uint8_t *)z80_read_word);//T STates: 3, 3
+		call(code, opts->read_16);//T STates: 3, 3
 		add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
-		call(code, (uint8_t *)z80_native_addr);
+		call(code, opts->native_addr);
 		jmp_r(code, opts->gen.scratch1);
 		break;
 	case Z80_RETCC: {
@@ -1551,9 +1545,9 @@
 		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, (uint8_t *)z80_read_word);//T STates: 3, 3
+		call(code, opts->read_16);//T STates: 3, 3
 		add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
-		call(code, (uint8_t *)z80_native_addr);
+		call(code, opts->native_addr);
 		jmp_r(code, opts->gen.scratch1);
 		*no_call_off = code->cur - (no_call_off+1);
 		break;
@@ -1562,9 +1556,9 @@
 		//For some systems, this may need a callback for signalling interrupt routine completion
 		cycles(&opts->gen, 8);//T States: 4, 4
 		mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
-		call(code, (uint8_t *)z80_read_word);//T STates: 3, 3
+		call(code, opts->read_16);//T STates: 3, 3
 		add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
-		call(code, (uint8_t *)z80_native_addr);
+		call(code, opts->native_addr);
 		jmp_r(code, opts->gen.scratch1);
 		break;
 	case Z80_RETN:
@@ -1572,9 +1566,9 @@
 		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, (uint8_t *)z80_read_word);//T STates: 3, 3
+		call(code, opts->read_16);//T STates: 3, 3
 		add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
-		call(code, (uint8_t *)z80_native_addr);
+		call(code, opts->native_addr);
 		jmp_r(code, opts->gen.scratch1);
 		break;
 	case Z80_RST: {
@@ -1583,7 +1577,7 @@
 		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, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3
+		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->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1);
@@ -1600,7 +1594,7 @@
 		} else {
 			mov_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
 		}
-		call(code, (uint8_t *)z80_io_read);
+		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);
@@ -1618,7 +1612,7 @@
 		}
 		translate_z80_reg(inst, &src_op, opts);
 		mov_rr(code, dst_op.base, opts->gen.scratch1, SZ_B);
-		call(code, (uint8_t *)z80_io_write);
+		call(code, opts->write_io);
 		z80_save_reg(inst, opts);
 		break;
 	/*case Z80_OUTI:
@@ -1737,7 +1731,7 @@
 		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, (uint8_t *)z80_retrans_stub);
+		call(&code, opts->retrans_stub);
 	}
 	return context;
 }
@@ -1959,8 +1953,9 @@
 		int reg;
 		uint8_t size;
 		if (i < Z80_I) {
-			int reg = i /2 + Z80_BC;
+			reg = i /2 + Z80_BC;
 			size = SZ_W;
+			i++;
 
 		} else {
 			reg = i;
@@ -1977,6 +1972,7 @@
 	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);
@@ -2005,6 +2001,18 @@
 	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);
@@ -2065,8 +2073,70 @@
 	pop_r(code, 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);
+	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->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);
+	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 * z80_gen_bank_write(uint32_t start_address, void * voptions)
@@ -2086,6 +2156,7 @@
 	context->banked_code_map = malloc(sizeof(native_map_slot) * (1 << 9));
 	memset(context->banked_code_map, 0, sizeof(native_map_slot) * (1 << 9));
 	context->options = options;
+	context->run = options->run;
 }
 
 void z80_reset(z80_context * context)
@@ -2115,14 +2186,14 @@
 		code->cur = bp_stub;
 
 		//Save context and call breakpoint handler
-		call(code, (uint8_t *)z80_save_context);
+		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, bp_handler);
 		mov_rr(code, RAX, opts->gen.context_reg, SZ_Q);
 		//Restore context
-		call(code, (uint8_t *)z80_load_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);
@@ -2131,7 +2202,7 @@
 		pop_r(code, opts->gen.scratch1);
 		add_ir(code, check_int_size - (code->cur-native), opts->gen.scratch1, SZ_Q);
 		push_r(code, opts->gen.scratch1);
-		jmp(code, (uint8_t *)z80_handle_cycle_limit_int);
+		jmp(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);
--- a/z80_to_x86.h	Wed Dec 17 23:03:19 2014 -0800
+++ b/z80_to_x86.h	Mon Dec 22 20:55:10 2014 -0800
@@ -21,21 +21,29 @@
 	ZF_NUM
 };
 
+typedef void (*z80_run_fun)(void * context);
+
 typedef struct {
 	cpu_options     gen;
 	code_ptr        save_context_scratch;
 	code_ptr        load_context_scratch;
-	code_ptr		read_8;
-	code_ptr		write_8;
+	code_ptr        native_addr;
+	code_ptr        retrans_stub;
+	code_ptr        do_sync;
+	code_ptr        read_8;
+	code_ptr        write_8;
 	code_ptr        write_8_noinc;
-	code_ptr		read_16;
-	code_ptr		write_16_highfirst;
-	code_ptr		write_16_lowfirst;
+	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];
-	int8_t			bank_reg;
-	int8_t			bank_pointer;
+	int8_t          bank_reg;
+	int8_t          bank_pointer;
+	z80_run_fun     run;
 } z80_options;
 
 typedef struct {
@@ -63,6 +71,7 @@
 	void *            system;
 	uint8_t           ram_code_flags[(8 * 1024)/128/8];
 	uint32_t          int_enable_cycle;
+	z80_run_fun       run;
   uint16_t          pc;
 } z80_context;
 
--- a/ztestrun.c	Wed Dec 17 23:03:19 2014 -0800
+++ b/ztestrun.c	Mon Dec 22 20:55:10 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, MMAP_READ | MMAP_WRITE,             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;
 }