# HG changeset patch # User Mike Pavone # Date 1366948871 25200 # Node ID d9bf8e61c33c0633a303129aa21ca54a1a06603a # Parent f456ee23d372ac2e40f06be3a1e775471e58dc79 Get Z80 core working for simple programs diff -r f456ee23d372 -r d9bf8e61c33c Makefile --- 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)` diff -r f456ee23d372 -r d9bf8e61c33c gen_x86.c --- 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; diff -r f456ee23d372 -r d9bf8e61c33c m68k_to_x86.c --- 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) { diff -r f456ee23d372 -r d9bf8e61c33c m68k_to_x86.h --- 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]; diff -r f456ee23d372 -r d9bf8e61c33c transz80.c --- /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 +#include + +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; +} diff -r f456ee23d372 -r d9bf8e61c33c x86_backend.c --- /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 + +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; + } + } +} + diff -r f456ee23d372 -r d9bf8e61c33c x86_backend.h --- 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 + +#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_ diff -r f456ee23d372 -r d9bf8e61c33c z80_to_x86.c --- 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 +#include +#include +#include #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); +} + + diff -r f456ee23d372 -r d9bf8e61c33c z80_to_x86.h --- 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_ diff -r f456ee23d372 -r d9bf8e61c33c z80inst.c --- 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", diff -r f456ee23d372 -r d9bf8e61c33c z80inst.h --- 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 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_