changeset 235:d9bf8e61c33c

Get Z80 core working for simple programs
author Mike Pavone <pavone@retrodev.com>
date Thu, 25 Apr 2013 21:01:11 -0700
parents f456ee23d372
children 19fb3523a9e5
files Makefile gen_x86.c m68k_to_x86.c m68k_to_x86.h transz80.c x86_backend.c x86_backend.h z80_to_x86.c z80_to_x86.h z80inst.c z80inst.h
diffstat 11 files changed, 513 insertions(+), 125 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Mon Apr 22 23:56:13 2013 -0700
+++ b/Makefile	Thu Apr 25 21:01:11 2013 -0700
@@ -7,8 +7,8 @@
 
 all : dis trans stateview blastem
 
-blastem : blastem.o 68kinst.o gen_x86.o m68k_to_x86.o runtime.o mem.o vdp.o render_sdl.o
-	$(CC) -o blastem blastem.o 68kinst.o gen_x86.o m68k_to_x86.o runtime.o mem.o vdp.o render_sdl.o `pkg-config --libs $(LIBS)`
+blastem : blastem.o 68kinst.o gen_x86.o m68k_to_x86.o x86_backend.o runtime.o mem.o vdp.o render_sdl.o
+	$(CC) -o blastem blastem.o 68kinst.o gen_x86.o m68k_to_x86.o x86_backend.o runtime.o mem.o vdp.o render_sdl.o `pkg-config --libs $(LIBS)`
 
 dis : dis.o 68kinst.o
 	$(CC) -o dis dis.o 68kinst.o
@@ -16,11 +16,14 @@
 zdis : zdis.o z80inst.o
 	$(CC) -o zdis zdis.o z80inst.o
 	
-libemu68k.a : 68kinst.o gen_x86.o m68k_to_x86.o runtime.o mem.o
-	ar rcs libemu68k.a 68kinst.o gen_x86.o m68k_to_x86.o runtime.o mem.o
+libemu68k.a : 68kinst.o gen_x86.o m68k_to_x86.o x86_backend.o runtime.o mem.o
+	ar rcs libemu68k.a 68kinst.o gen_x86.o m68k_to_x86.o x86_backend.o runtime.o mem.o
 	
-trans : trans.o 68kinst.o gen_x86.o m68k_to_x86.o runtime.o mem.o
-	$(CC) -o trans trans.o 68kinst.o gen_x86.o m68k_to_x86.o runtime.o mem.o
+trans : trans.o 68kinst.o gen_x86.o m68k_to_x86.o x86_backend.o runtime.o mem.o
+	$(CC) -o trans trans.o 68kinst.o gen_x86.o m68k_to_x86.o x86_backend.o runtime.o mem.o
+
+transz80 : transz80.o z80inst.o gen_x86.o z80_to_x86.o x86_backend.o zruntime.o mem.o
+	$(CC) -o transz80 transz80.o z80inst.o gen_x86.o z80_to_x86.o x86_backend.o zruntime.o mem.o
 
 stateview : stateview.o vdp.o render_sdl.o
 	$(CC) -o stateview stateview.o vdp.o render_sdl.o `pkg-config --libs $(LIBS)`
--- a/gen_x86.c	Mon Apr 22 23:56:13 2013 -0700
+++ b/gen_x86.c	Thu Apr 25 21:01:11 2013 -0700
@@ -1490,6 +1490,10 @@
 
 uint8_t * jmp_r(uint8_t * out, uint8_t dst)
 {
+	if (dst >= R8) {
+		dst -= R8 - X86_R8;
+		*(out++) = PRE_REX | REX_RM_FIELD;
+	}
 	*(out++) = OP_SINGLE_EA;
 	*(out++) = MODE_REG_DIRECT | dst | (OP_EX_JMP_EA << 3);
 	return out;
--- a/m68k_to_x86.c	Mon Apr 22 23:56:13 2013 -0700
+++ b/m68k_to_x86.c	Thu Apr 25 21:01:11 2013 -0700
@@ -691,6 +691,11 @@
 	return native_code_map[chunk].base + native_code_map[chunk].offsets[offset];
 }
 
+uint8_t * get_native_from_context(m68k_context * context, uint32_t address)
+{
+	return get_native_address(context->native_code_map, address);
+}
+
 uint32_t get_instruction_start(native_map_slot * native_code_map, uint32_t address)
 {
 	address &= 0xFFFFFF;
@@ -711,42 +716,6 @@
 	return address*2;
 }
 
-deferred_addr * defer_address(deferred_addr * old_head, uint32_t address, uint8_t *dest)
-{
-	deferred_addr * new_head = malloc(sizeof(deferred_addr));
-	new_head->next = old_head;
-	new_head->address = address & 0xFFFFFF;
-	new_head->dest = dest;
-	return new_head;
-}
-
-void process_deferred(x86_68k_options * opts)
-{
-	deferred_addr * cur = opts->deferred;
-	deferred_addr **last_next = &(opts->deferred);
-	while(cur)
-	{
-		uint8_t * native = get_native_address(opts->native_code_map, cur->address);
-		if (native) {
-			int32_t disp = native - (cur->dest + 4);
-			uint8_t * out = cur->dest;
-			*(out++) = disp;
-			disp >>= 8;
-			*(out++) = disp;
-			disp >>= 8;
-			*(out++) = disp;
-			disp >>= 8;
-			*out = disp;
-			*last_next = cur->next;
-			free(cur);
-			cur = *last_next;
-		} else {
-			last_next = &(cur->next);
-			cur = cur->next;
-		}
-	}
-}
-
 void map_native_address(m68k_context * context, uint32_t address, uint8_t * native_addr, uint8_t size, uint8_t native_size)
 {
 	native_map_slot * native_code_map = context->native_code_map;
@@ -3956,7 +3925,7 @@
 			map_native_address(context, instbuf.address, dst, m68k_size, after-dst);
 			dst = after;
 		} while(instbuf.op != M68K_ILLEGAL && instbuf.op != M68K_RESET && instbuf.op != M68K_INVALID && instbuf.op != M68K_TRAP && instbuf.op != M68K_RTS && instbuf.op != M68K_RTR && instbuf.op != M68K_RTE && !(instbuf.op == M68K_BCC && instbuf.extra.cond == COND_TRUE) && instbuf.op != M68K_JMP);
-		process_deferred(opts);
+		process_deferred(&opts->deferred, context, (native_addr_func)get_native_from_context);
 		if (opts->deferred) {
 			address = opts->deferred->address;
 			if ((address & 0xFFFFFF) < 0x400000) {
--- a/m68k_to_x86.h	Mon Apr 22 23:56:13 2013 -0700
+++ b/m68k_to_x86.h	Thu Apr 25 21:01:11 2013 -0700
@@ -9,18 +9,11 @@
 #define NUM_MEM_AREAS 4
 #define NATIVE_MAP_CHUNKS (64*1024)
 #define NATIVE_CHUNK_SIZE ((16 * 1024 * 1024 / NATIVE_MAP_CHUNKS)/2)
-#define INVALID_OFFSET 0xFFFFFFFF
 #define EXTENSION_WORD 0xFFFFFFFE
 #define MAX_NATIVE_SIZE 255
 
 #define OPT_NATIVE_CALL_STACK 0x1
 
-typedef struct deferred_addr {
-	struct deferred_addr *next;
-	uint8_t              *dest;
-	uint32_t             address;
-} deferred_addr;
-
 typedef struct {
 	uint32_t        flags;
 	int8_t          dregs[8];
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/transz80.c	Thu Apr 25 21:01:11 2013 -0700
@@ -0,0 +1,31 @@
+#include "z80inst.h"
+#include "z80_to_x86.h"
+#include "mem.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+uint8_t z80_ram[0x2000];
+
+int main(int argc, char ** argv)
+{
+	long filesize;
+	uint8_t *filebuf;
+	x86_z80_options opts;
+	z80_context context;
+	FILE * f = fopen(argv[1], "rb");
+	fseek(f, 0, SEEK_END);
+	filesize = ftell(f);
+	fseek(f, 0, SEEK_SET);
+	fread(z80_ram, 1, filesize < sizeof(z80_ram) ? filesize : sizeof(z80_ram), f);
+	fclose(f);
+	init_x86_z80_opts(&opts);
+	init_z80_context(&context, &opts);
+	//cartridge ROM
+	context.mem_pointers[0] = z80_ram;
+	context.target_cycle = 0x7FFFFFFF;
+	//work RAM
+	context.mem_pointers[1] = context.mem_pointers[2] = NULL;
+	z80_reset(&context);
+	z80_run(&context);
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/x86_backend.c	Thu Apr 25 21:01:11 2013 -0700
@@ -0,0 +1,39 @@
+#include "x86_backend.h"
+#include <stdlib.h>
+
+deferred_addr * defer_address(deferred_addr * old_head, uint32_t address, uint8_t *dest)
+{
+	deferred_addr * new_head = malloc(sizeof(deferred_addr));
+	new_head->next = old_head;
+	new_head->address = address & 0xFFFFFF;
+	new_head->dest = dest;
+	return new_head;
+}
+
+void process_deferred(deferred_addr ** head_ptr, void * context, native_addr_func get_native)
+{
+	deferred_addr * cur = *head_ptr;
+	deferred_addr **last_next = head_ptr;
+	while(cur)
+	{
+		uint8_t * native = get_native(context, cur->address);//get_native_address(opts->native_code_map, cur->address);
+		if (native) {
+			int32_t disp = native - (cur->dest + 4);
+			uint8_t * out = cur->dest;
+			*(out++) = disp;
+			disp >>= 8;
+			*(out++) = disp;
+			disp >>= 8;
+			*(out++) = disp;
+			disp >>= 8;
+			*out = disp;
+			*last_next = cur->next;
+			free(cur);
+			cur = *last_next;
+		} else {
+			last_next = &(cur->next);
+			cur = cur->next;
+		}
+	}
+}
+
--- a/x86_backend.h	Mon Apr 22 23:56:13 2013 -0700
+++ b/x86_backend.h	Thu Apr 25 21:01:11 2013 -0700
@@ -1,6 +1,10 @@
 #ifndef X86_BACKEND_H_
 #define X86_BACKEND_H_
 
+#include <stdint.h>
+
+#define INVALID_OFFSET 0xFFFFFFFF
+
 typedef struct {
 	int32_t disp;
 	uint8_t mode;
@@ -14,5 +18,16 @@
 	int32_t  *offsets;
 } native_map_slot;
 
+typedef struct deferred_addr {
+	struct deferred_addr *next;
+	uint8_t              *dest;
+	uint32_t             address;
+} deferred_addr;
+
+typedef uint8_t * (*native_addr_func)(void * context, uint32_t address);
+
+deferred_addr * defer_address(deferred_addr * old_head, uint32_t address, uint8_t *dest);
+void process_deferred(deferred_addr ** head_ptr, void * context, native_addr_func get_native);
+
 #endif //X86_BACKEND_H_
 
--- a/z80_to_x86.c	Mon Apr 22 23:56:13 2013 -0700
+++ b/z80_to_x86.c	Thu Apr 25 21:01:11 2013 -0700
@@ -1,31 +1,46 @@
+#include "z80inst.h"
 #include "z80_to_x86.h"
 #include "gen_x86.h"
+#include "mem.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
 
 #define MODE_UNUSED (MODE_IMMED-1)
 
 #define ZCYCLES RBP
 #define SCRATCH1 R13
 #define SCRATCH2 R14
+#define CONTEXT RSI
+
+//TODO: Find out the actual value for this
+#define MAX_NATIVE_SIZE 128
 
 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();
 
-uint8_t z80_size(z80_inst * inst)
+uint8_t z80_size(z80inst * inst)
 {
 	uint8_t reg = (inst->reg & 0x1F);
-	if (reg != Z80_UNUSED &&) {
+	if (reg != Z80_UNUSED && reg != Z80_USE_IMMED) {
 		return reg < Z80_BC ? SZ_B : SZ_W;
 	}
 	//TODO: Handle any necessary special cases
 	return SZ_B;
 }
 
-uint8_t * zcylces(dst, uint32_t num_cycles)
+uint8_t * zcycles(uint8_t * dst, uint32_t num_cycles)
 {
 	return add_ir(dst, num_cycles, ZCYCLES, SZ_D);
 }
 
-uint8_t * translate_z80_reg(z80_inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_options * opts)
+uint8_t * translate_z80_reg(z80inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_options * opts)
 {
 	if (inst->reg == Z80_USE_IMMED) {
 		ea->mode = MODE_IMMED;
@@ -33,18 +48,18 @@
 	} else if ((inst->reg & 0x1F) == Z80_UNUSED) {
 		ea->mode = MODE_UNUSED;
 	} else {
-		ea->mode = MODE_REG;
+		ea->mode = MODE_REG_DIRECT;
 		if (inst->reg == Z80_IYH) {
 			ea->base = opts->regs[Z80_IYL];
 			dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W);
 		} else {
-			ea->base = opts->regs[inst->reg]
+			ea->base = opts->regs[inst->reg];
 		}
 	}
 	return dst;
 }
 
-uint8_t * save_z80_reg(uint8_t * dst, z80_inst * inst, x86_z80_options * opts)
+uint8_t * z80_save_reg(uint8_t * dst, z80inst * inst, x86_z80_options * opts)
 {
 	if (inst->reg == Z80_IYH) {
 		dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W);
@@ -52,10 +67,10 @@
 	return dst;
 }
 
-uint8_t * translate_z80_ea(z80_inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_options * opts, uint8_t read, uint8_t modify)
+uint8_t * translate_z80_ea(z80inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_options * opts, uint8_t read, uint8_t modify)
 {
 	uint8_t size, reg, areg;
-	ea->mode = MODE_REG;
+	ea->mode = MODE_REG_DIRECT;
 	areg = read ? SCRATCH1 : SCRATCH2;
 	switch(inst->addr_mode & 0x1F)
 	{
@@ -107,9 +122,9 @@
 		}
 		ea->base = SCRATCH1;
 		break;
-	case Z80_IX_INDEXED:
-	case Z80_IY_INDEXED:
-		reg = opts->regs[inst->addr_mode == Z80_IX_INDEXED ? Z80_IX : Z80_IY];
+	case Z80_IX_DISPLACE:
+	case Z80_IY_DISPLACE:
+		reg = opts->regs[inst->addr_mode == Z80_IX_DISPLACE ? Z80_IX : Z80_IY];
 		dst = mov_rr(dst, reg, areg, SZ_W);
 		dst = add_ir(dst, inst->immed, areg, SZ_W);
 		size = z80_size(inst);
@@ -128,7 +143,7 @@
 		}
 		break;
 	case Z80_UNUSED:
-		ea->mode = MODE_UNUSED:
+		ea->mode = MODE_UNUSED;
 		break;
 	default:
 		fprintf(stderr, "Unrecognized Z80 addressing mode %d\n", inst->addr_mode);
@@ -137,20 +152,20 @@
 	return dst;
 }
 
-uint8_t * z80_save_ea(uint8_t * dst, z80_inst * inst, x86_z80_options * opts)
+uint8_t * z80_save_ea(uint8_t * dst, z80inst * inst, x86_z80_options * opts)
 {
-	if (inst->addr_mode == Z80_REG_DIRECT && inst->ea_reg == Z80_IYH) {
+	if (inst->addr_mode == Z80_REG && inst->ea_reg == Z80_IYH) {
 		dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W);
 	}
 	return dst;
 }
 
-uint8_t * z80_save_result(uint8_t * dst, z80_inst * inst)
+uint8_t * z80_save_result(uint8_t * dst, z80inst * inst)
 {
-	if (z80_size(inst). == SZ_B) {
+	if (z80_size(inst) == SZ_B) {
 		dst = call(dst, (uint8_t *)z80_write_byte);
 	} else {
-		dst = call(dst, (uint8_t *)z80_write_word);
+		dst = call(dst, (uint8_t *)z80_write_word_lowfirst);
 	}
 	return dst;
 }
@@ -170,44 +185,121 @@
 	return offsetof(z80_context, flags) + flag;
 }
 
-uint8_t * translate_z80_inst(z80_inst * inst, uint8_t * dst, x86_z80_options * opts)
+void z80_print_regs_exit(z80_context * context)
+{
+	printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\nIX: %X\nIY: %X\nSP: %X\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->sp);
+	exit(0);
+}
+
+uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context, uint16_t address)
 {
 	uint32_t cycles;
 	x86_ea src_op, dst_op;
+	uint8_t size;
+	x86_z80_options *opts = context->options;
 	switch(inst->op)
 	{
 	case Z80_LD:
+		size = z80_size(inst);
+		switch (inst->addr_mode & 0x1F)
+		{
+		case Z80_REG:
+		case Z80_REG_INDIRECT:
+ 			cycles = size == SZ_B ? 4 : 6;
+			if (inst->ea_reg == Z80_IX || inst->ea_reg == Z80_IY) {
+				cycles += 4;
+			}
+			break;
+		case Z80_IMMED:
+			cycles = size == SZ_B ? 7 : 10;
+			break;
+		case Z80_IMMED_INDIRECT:
+			cycles = 10;
+			break;
+		case Z80_IX_DISPLACE:
+		case Z80_IY_DISPLACE:
+			cycles = 12;
+			break;
+		}
+		if ((inst->reg >= Z80_IXL && inst->reg <= Z80_IYH) || inst->reg == Z80_IX || inst->reg == Z80_IY) {
+			cycles += 4;
+		}
+		dst = zcycles(dst, cycles);
 		if (inst->addr_mode & Z80_DIR) {
-			dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY);
-			dst = translate_z80_reg(inst, &dst_op, dst, opts);
-		} else {
 			dst = translate_z80_reg(inst, &src_op, dst, opts);
 			dst = translate_z80_ea(inst, &dst_op, dst, opts, DONT_READ, MODIFY);
+		} else {
+			dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY);
+			dst = translate_z80_reg(inst, &dst_op, dst, opts);
 		}
-		if (ea_op.mode == MODE_REG_DIRECT) {
-			dst = mov_rr(dst, ea_op.base, reg_op.base, z80_size(inst));
+		if (src_op.mode == MODE_REG_DIRECT) {
+			dst = mov_rr(dst, src_op.base, dst_op.base, size);
 		} else {
-			dst = mov_ir(dst, ea_op.disp, reg_op.base, z80_size(inst));
+			dst = mov_ir(dst, src_op.disp, dst_op.base, size);
 		}
 		dst = z80_save_reg(dst, inst, opts);
 		dst = z80_save_ea(dst, inst, opts);
-		if (!(inst->addr_mode & Z80_DIR)) {
-			dst = z80_save_result(dst, inst, opts);
+		if (inst->addr_mode & Z80_DIR) {
+			dst = z80_save_result(dst, inst);
 		}
 		break;
 	case Z80_PUSH:
 		dst = zcycles(dst, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 9 : 5);
-		dst = sub_ir(dst, opts->regs[Z80_SP], SZ_W);
-		dst = translate_z80_reg(inst, &src_op, dst, opts);
-		dst = mov_rr(dst, src_op.base, SCRATCH1, SZ_W);
-		dst = call(dst, z80_write_word);
+		dst = sub_ir(dst, 2, opts->regs[Z80_SP], SZ_W);
+		if (inst->reg == Z80_AF) {
+			dst = mov_rdisp8r(dst, CONTEXT, zf_off(ZF_S), SCRATCH2, SZ_B);
+			dst = shl_ir(dst, 1, SCRATCH2, SZ_B);
+			dst = or_rdisp8r(dst, CONTEXT, zf_off(ZF_Z), SCRATCH2, SZ_B);
+			dst = shl_ir(dst, 2, SCRATCH2, SZ_B);
+			dst = or_rdisp8r(dst, CONTEXT, zf_off(ZF_H), SCRATCH2, SZ_B);
+			dst = shl_ir(dst, 2, SCRATCH2, SZ_B);
+			dst = or_rdisp8r(dst, CONTEXT, zf_off(ZF_PV), SCRATCH2, SZ_B);
+			dst = shl_ir(dst, 1, SCRATCH2, SZ_B);
+			dst = or_rdisp8r(dst, CONTEXT, zf_off(ZF_N), SCRATCH2, SZ_B);
+			dst = shl_ir(dst, 1, SCRATCH2, SZ_B);
+			dst = or_rdisp8r(dst, CONTEXT, zf_off(ZF_C), SCRATCH2, SZ_B);
+			dst = shl_ir(dst, 8, SCRATCH2, SZ_W);
+			dst = mov_rr(dst, opts->regs[Z80_A], SCRATCH2, SZ_B);
+		} else {
+			dst = translate_z80_reg(inst, &src_op, dst, opts);
+			dst = mov_rr(dst, src_op.base, SCRATCH2, SZ_W);
+		}
+		dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, 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 = sub_ir(dst, opts->regs[Z80_SP], SZ_W);
-		dst = translate_z80_reg(inst, &src_op, dst, opts);
-		dst = mov_rr(dst, src_op.base, SCRATCH1, SZ_W);
-		dst = call(dst, z80_write_word);
+		dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, SZ_W);
+		dst = call(dst, (uint8_t *)z80_read_word);
+		dst = add_ir(dst, 2, opts->regs[Z80_SP], SZ_W);
+		if (inst->reg == Z80_AF) {
+			dst = mov_rr(dst, SCRATCH1, opts->regs[Z80_A], SZ_B);
+			dst = bt_ir(dst, 8, SCRATCH1, SZ_W);
+			dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C));
+			dst = bt_ir(dst, 9, SCRATCH1, SZ_W);
+			dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_N));
+			dst = bt_ir(dst, 10, SCRATCH1, SZ_W);
+			dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_PV));
+			dst = bt_ir(dst, 12, SCRATCH1, SZ_W);
+			dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_H));
+			dst = bt_ir(dst, 14, SCRATCH1, SZ_W);
+			dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_Z));
+			dst = bt_ir(dst, 15, SCRATCH1, SZ_W);
+			dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_S));
+		} else {
+			dst = translate_z80_reg(inst, &src_op, dst, opts);
+			dst = mov_rr(dst, SCRATCH1, src_op.base, SZ_W);
+		}
+		//no call to save_z80_reg needed since there's no chance we'll use the only
+		//the upper half of a register pair
 		break;
 	/*case Z80_EX:
 	case Z80_EXX:
@@ -222,7 +314,7 @@
 		break;*/
 	case Z80_ADD:
 		cycles = 4;
-		if (inst->addr_mode == Z80_IX_INDIRECT || inst->addr_mdoe == Z80_IY_INDIRECT) {
+		if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
 			cycles += 12;
 		} else if(inst->addr_mode == Z80_IMMED) {
 			cycles += 3;
@@ -238,12 +330,12 @@
 			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));
+		dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
 		//TODO: Implement half-carry flag
 		if (z80_size(inst) == SZ_B) {
-			dst = setcc_rdisp8(dst, CC_O, zf_off(ZF_PV));
-			dst = setcc_rdisp8(dst, CC_Z, zf_off(ZF_Z));
-			dst = setcc_rdisp8(dst, CC_S, zf_off(ZF_S));
+			dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV));
+			dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z));
+			dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
 		}
 		dst = z80_save_reg(dst, inst, opts);
 		dst = z80_save_ea(dst, inst, opts);
@@ -252,7 +344,7 @@
 		break;*/
 	case Z80_SUB:
 		cycles = 4;
-		if (inst->addr_mode == Z80_IX_INDIRECT || inst->addr_mdoe == Z80_IY_INDIRECT) {
+		if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
 			cycles += 12;
 		} else if(inst->addr_mode == Z80_IMMED) {
 			cycles += 3;
@@ -266,11 +358,11 @@
 			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));
-		dst = setcc_rdisp8(dst, CC_O, zf_off(ZF_PV));
+		dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_N), SZ_B);
+		dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV));
 		//TODO: Implement half-carry flag
-		dst = setcc_rdisp8(dst, CC_Z, zf_off(ZF_Z));
-		dst = setcc_rdisp8(dst, CC_S, zf_off(ZF_S)
+		dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z));
+		dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
 		dst = z80_save_reg(dst, inst, opts);
 		dst = z80_save_ea(dst, inst, opts);
 		break;
@@ -294,11 +386,11 @@
 		}
 		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));
+			dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);
 			//TODO: Implement half-carry flag
-			dst = setcc_rdisp8(dst, CC_O, zf_off(ZF_PV));
-			dst = setcc_rdisp8(dst, CC_Z, zf_off(ZF_Z));
-			dst = setcc_rdisp8(dst, CC_S, zf_off(ZF_S));
+			dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV));
+			dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z));
+			dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S));
 		}
 		dst = z80_save_reg(dst, inst, opts);
 		dst = z80_save_ea(dst, inst, opts);
@@ -338,13 +430,75 @@
 	case Z80_RES:
 	case Z80_JP:
 	case Z80_JPCC:
-	case Z80_JR:
-	case Z80_JRCC:
-	case Z80_DJNZ:
-	case Z80_CALL:
-	case Z80_CALLCC:
+	case Z80_JR:*/
+	case Z80_JRCC: {
+		dst = zcycles(dst, 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);
+			break;
+		case Z80_CC_NC:
+			cond = CC_NZ;
+		case Z80_CC_C:
+			dst = cmp_irdisp8(dst, 0, CONTEXT, 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
+		uint16_t dest_addr = address + inst->immed + 2;
+		if (dest_addr < 0x4000) {
+			uint8_t * call_dst = z80_get_native_address(context, dest_addr);
+			if (!call_dst) {
+				opts->deferred = defer_address(opts->deferred, dest_addr, dst + 1);
+				//fake address to force large displacement
+				call_dst = dst + 256;
+			}
+			dst = jmp(dst, call_dst);
+		} else {
+			dst = mov_ir(dst, dest_addr, SCRATCH1, SZ_W);
+			dst = call(dst, (uint8_t *)z80_native_addr);
+			dst = jmp_r(dst, SCRATCH1);
+		}
+		*no_jump_off = dst - (no_jump_off+1);
+		break;
+	}
+	//case Z80_DJNZ:*/
+	case Z80_CALL: {
+		dst = zcycles(dst, 11);//T States: 4,3,4
+		dst = sub_ir(dst, 2, opts->regs[Z80_SP], SZ_W);
+		dst = mov_ir(dst, address + 3, SCRATCH2, SZ_W);
+		dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, 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);
+			if (!call_dst) {
+				opts->deferred = defer_address(opts->deferred, inst->immed, dst + 1);
+				//fake address to force large displacement
+				call_dst = dst + 256;
+			}
+			dst = jmp(dst, call_dst);
+		} else {
+			dst = mov_ir(dst, inst->immed, SCRATCH1, SZ_W);
+			dst = call(dst, (uint8_t *)z80_native_addr);
+			dst = jmp_r(dst, SCRATCH1);
+		}
+		break;
+	}
+	//case Z80_CALLCC:
 	case Z80_RET:
-	case Z80_RETCC:
+		dst = zcycles(dst, 4);//T States: 4
+		dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, SZ_W);
+		dst = call(dst, (uint8_t *)z80_read_word);//T STates: 3, 3
+		dst = add_ir(dst, 2, opts->regs[Z80_SP], SZ_W);
+		dst = call(dst, (uint8_t *)z80_native_addr);
+		dst = jmp_r(dst, SCRATCH1);
+		break;
+	/*case Z80_RETCC:
 	case Z80_RETI:
 	case Z80_RETN:
 	case Z80_RST:
@@ -358,12 +512,177 @@
 	case Z80_OTIR:
 	case Z80_OUTD:
 	case Z80_OTDR:*/
-	default:
-		fprintf(stderr, "unimplemented instruction: %d\n", inst->op);
+	default: {
+		char disbuf[80];
+		z80_disasm(inst, disbuf);
+		fprintf(stderr, "unimplemented instruction: %s\n", disbuf);
 		exit(1);
 	}
+	}
+	return dst;
+}
+
+uint8_t * z80_get_native_address(z80_context * context, uint32_t address)
+{
+	native_map_slot *map;
+	if (address < 0x4000) {
+		address &= 0x1FFF;
+		map = context->static_code_map;
+	} else if (address >= 0x8000) {
+		address &= 0x7FFF;
+		map = context->banked_code_map + context->bank_reg;
+	} else {
+		return NULL;
+	}
+	if (!map->base || !map->offsets || map->offsets[address] == INVALID_OFFSET) {
+		return NULL;
+	}
+	return map->base + map->offsets[address];
+}
+
+//TODO: Record z80 instruction size and code size for addresses to support modification of translated code
+void z80_map_native_address(z80_context * context, uint32_t address, uint8_t * native_address)
+{
+	native_map_slot *map;
+	if (address < 0x4000) {
+		address &= 0x1FFF;
+		map = context->static_code_map;
+	} else if (address >= 0x8000) {
+		address &= 0x7FFF;
+		map = context->banked_code_map + context->bank_reg;
+		if (!map->offsets) {
+			map->offsets = malloc(sizeof(int32_t) * 0x8000);
+			memset(map->offsets, 0xFF, sizeof(int32_t) * 0x8000);
+		}
+	} else {
+		return;
+	}
+	if (!map->base) {
+		map->base = native_address;
+	}
+	map->offsets[address] = native_address - map->base;
+}
+
+uint8_t * z80_get_native_address_trans(z80_context * context, uint32_t address)
+{
+	uint8_t * addr = z80_get_native_address(context, address);
+	if (!addr) {
+		translate_z80_stream(context, address);
+		addr = z80_get_native_address(context, address);
+	}
+	return addr;
+}
+
+void translate_z80_stream(z80_context * context, uint32_t address)
+{
+	char disbuf[80];
+	if (z80_get_native_address(context, address)) {
+		return;
+	}
+	x86_z80_options * opts = context->options;
+	uint8_t * encoded = NULL, *next;
+	if (address < 0x4000) {
+		encoded = context->mem_pointers[0] + (address & 0x1FFF);
+	} else if(address >= 0x8000 && context->mem_pointers[1]) {
+		encoded = context->mem_pointers[1] + (address & 0x7FFF);
+	}
+	while (encoded != NULL)
+	{
+		z80inst inst;
+		printf("translating Z80 code at address %X\n", address);
+		do {
+			if (opts->code_end-opts->cur_code < MAX_NATIVE_SIZE) {
+				if (opts->code_end-opts->cur_code < 5) {
+					puts("out of code memory, not enough space for jmp to next chunk");
+					exit(1);
+				}
+				size_t size = 1024*1024;
+				opts->cur_code = alloc_code(&size);
+				opts->code_end = opts->cur_code + size;
+				jmp(opts->cur_code, opts->cur_code);
+			}
+			if (address > 0x4000 & address < 0x8000) {
+				opts->cur_code = xor_rr(opts->cur_code, RDI, RDI, SZ_D);
+				opts->cur_code = call(opts->cur_code, (uint8_t *)exit);
+				break;
+			}
+			uint8_t * existing = z80_get_native_address(context, address);
+			if (existing) {
+				opts->cur_code = jmp(opts->cur_code, existing);
+				break;
+			}
+			next = z80_decode(encoded, &inst);
+			z80_disasm(&inst, disbuf);
+			if (inst.op == Z80_NOP) {
+				printf("%X\t%s(%d)\n", address, disbuf, inst.immed);
+			} else {
+				printf("%X\t%s\n", address, disbuf);
+			}
+			z80_map_native_address(context, address, opts->cur_code);
+			opts->cur_code = translate_z80inst(&inst, opts->cur_code, context, address);
+			address += next-encoded;
+			encoded = next;
+		} while (!(inst.op == Z80_RET || inst.op == Z80_RETI || inst.op == Z80_RETN || (inst.op = Z80_NOP && inst.immed == 42)));
+		process_deferred(&opts->deferred, context, (native_addr_func)z80_get_native_address);
+		if (opts->deferred) {
+			address = opts->deferred->address;
+			printf("defferred address: %X\n", address);
+			if (address < 0x4000) {
+				encoded = context->mem_pointers[0] + (address & 0x1FFF);
+			} else if (address > 0x8000 && context->mem_pointers[1]) {
+				encoded = context->mem_pointers[1] + (address  & 0x7FFF);
+			} else {
+				printf("attempt to translate non-memory address: %X\n", address);
+				exit(1);
+			}
+		} else {
+			encoded = NULL;
+		}
+	}
 }
 
-void translate_z80_stream(z80_context * context, uint16_t address)
+void init_x86_z80_opts(x86_z80_options * options)
 {
+	options->flags = 0;
+	options->regs[Z80_B] = BH;
+	options->regs[Z80_C] = RBX;
+	options->regs[Z80_D] = CH;
+	options->regs[Z80_E] = RCX;
+	options->regs[Z80_H] = AH;
+	options->regs[Z80_L] = RAX;
+	options->regs[Z80_IXH] = DH;
+	options->regs[Z80_IXL] = RDX;
+	options->regs[Z80_IYH] = -1;
+	options->regs[Z80_IYL] = -1;
+	options->regs[Z80_I] = -1;
+	options->regs[Z80_R] = -1;
+	options->regs[Z80_A] = R10;
+	options->regs[Z80_BC] = RBX;
+	options->regs[Z80_DE] = RCX;
+	options->regs[Z80_HL] = RAX;
+	options->regs[Z80_SP] = R9;
+	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->deferred = NULL;
 }
+
+void init_z80_context(z80_context * context, x86_z80_options * options)
+{
+	memset(context, 0, sizeof(*context));
+	context->static_code_map = malloc(sizeof(context->static_code_map));
+	context->static_code_map->offsets = malloc(sizeof(int32_t) * 0x2000);
+	memset(context->static_code_map->offsets, 0xFF, sizeof(int32_t) * 0x2000);
+	context->banked_code_map = malloc(sizeof(native_map_slot) * (1 << 9));
+	context->options = options;
+}
+
+void z80_reset(z80_context * context)
+{
+	context->native_pc = z80_get_native_address_trans(context, 0);
+}
+
+
--- a/z80_to_x86.h	Mon Apr 22 23:56:13 2013 -0700
+++ b/z80_to_x86.h	Thu Apr 25 21:01:11 2013 -0700
@@ -16,8 +16,11 @@
 };
 
 typedef struct {
-	uint32_t flags;
-	int8_t   regs[Z80_UNUSED];
+	uint8_t *       cur_code;
+	uint8_t *       code_end;
+	deferred_addr * deferred;
+	uint32_t        flags;
+	int8_t          regs[Z80_UNUSED];
 } x86_z80_options;
 
 typedef struct {
@@ -27,13 +30,21 @@
 	uint16_t          bank_reg;
 	uint8_t           regs[Z80_A+1];
 	uint8_t           alt_regs[Z80_A+1];
+	uint32_t          target_cycle;
+	uint32_t          current_cycle;
 	uint8_t *         mem_pointers[ZNUM_MEM_AREAS];
-	native_map_slot * native_code_map;
-	void *            options
+	native_map_slot * static_code_map;
+	native_map_slot * banked_code_map;
+	void *            options;
 	void *            next_context;
 } z80_context;
 
-void translate_z80_stream(z80_context * context, uint16_t address);
+void translate_z80_stream(z80_context * context, uint32_t address);
+void init_x86_z80_opts(x86_z80_options * options);
+void init_z80_context(z80_context * context, x86_z80_options * options);
+uint8_t * z80_get_native_address(z80_context * context, uint32_t address);
+void z80_run(z80_context * context);
+void z80_reset(z80_context * context);
 
 #endif //Z80_TO_X86_H_
 
--- a/z80inst.c	Mon Apr 22 23:56:13 2013 -0700
+++ b/z80inst.c	Thu Apr 25 21:01:11 2013 -0700
@@ -1249,7 +1249,7 @@
 	}
 	if ((decoded->addr_mode & 0x1F) == Z80_IMMED && decoded->op != Z80_RST && decoded->op != Z80_IM) {
 		decoded->immed = *(++istream);
-		if (decoded->reg >= Z80_BC && decoded->reg < Z80_UNUSED) {
+		if ((decoded->reg >= Z80_BC && decoded->reg < Z80_UNUSED) || decoded->op == Z80_CALL || decoded->op == Z80_CALLCC) {
 			decoded->immed |= *(++istream) << 8;
 		} else if (decoded->immed & 0x80) {
 			decoded->immed |= 0xFF00;
@@ -1338,16 +1338,16 @@
 };
 
 char * z80_regs[Z80_USE_IMMED] = {
+	"c",
 	"b",
-	"c",
+	"e",
 	"d",
-	"e",
+	"l",
 	"h",
-	"l",
+	"ixl",
 	"ixh",
-	"ixl",
+	"iyl",
 	"iyh",
-	"iyl",
 	"i",
 	"r",
 	"a",
--- a/z80inst.h	Mon Apr 22 23:56:13 2013 -0700
+++ b/z80inst.h	Thu Apr 25 21:01:11 2013 -0700
@@ -1,3 +1,6 @@
+#ifndef Z80INST_H_
+#define Z80INST_H_
+
 #include <stdint.h>
 
 enum {
@@ -72,16 +75,16 @@
 };
 
 enum {
-	Z80_B=0,
-	Z80_C,
+	Z80_C=0,
+	Z80_B,
+	Z80_E,
 	Z80_D,
-	Z80_E,
+	Z80_L,
 	Z80_H,
-	Z80_L,
+	Z80_IXL,
 	Z80_IXH,
-	Z80_IXL,
+	Z80_IYL,
 	Z80_IYH,
-	Z80_IYL,
 	Z80_I,
 	Z80_R,
 	Z80_A,
@@ -130,4 +133,5 @@
 uint8_t * z80_decode(uint8_t * istream, z80inst * decoded);
 int z80_disasm(z80inst * decoded, char * dst);
 
+#endif //Z80INST_H_