# HG changeset patch # User Michael Pavone # Date 1419310510 28800 # Node ID 5ef3fe516da9242dd7019539cbc8fee3eb94f243 # Parent 4ff7bbb3943b403de5b94cfc34663f3ac7f16caa Z80 core is sort of working again diff -r 4ff7bbb3943b -r 5ef3fe516da9 Makefile --- 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 diff -r 4ff7bbb3943b -r 5ef3fe516da9 backend.h --- 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_ diff -r 4ff7bbb3943b -r 5ef3fe516da9 backend_x86.c --- 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; diff -r 4ff7bbb3943b -r 5ef3fe516da9 blastem.c --- 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); } } diff -r 4ff7bbb3943b -r 5ef3fe516da9 gen_x86.c --- 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); diff -r 4ff7bbb3943b -r 5ef3fe516da9 gen_x86.h --- 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); diff -r 4ff7bbb3943b -r 5ef3fe516da9 z80_to_x86.c --- 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); diff -r 4ff7bbb3943b -r 5ef3fe516da9 z80_to_x86.h --- 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; diff -r 4ff7bbb3943b -r 5ef3fe516da9 ztestrun.c --- 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 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; }