Mercurial > repos > blastem
diff z80_to_x86.c @ 652:f822d9216968
Merge
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 30 Dec 2014 19:11:34 -0800 |
parents | 9d6fed6501ba 103d5cabbe14 |
children | a18e3923481e |
line wrap: on
line diff
--- a/z80_to_x86.c Mon Dec 29 23:08:39 2014 -0800 +++ b/z80_to_x86.c Tue Dec 30 19:11:34 2014 -0800 @@ -28,6 +28,8 @@ #define dprintf #endif +uint32_t zbreakpoint_patch(z80_context * context, uint16_t address, code_ptr dst); + uint8_t z80_size(z80inst * inst) { uint8_t reg = (inst->reg & 0x1F); @@ -124,7 +126,7 @@ ea->base = opts->regs[Z80_IYL]; ror_ir(code, 8, opts->regs[Z80_IY], SZ_W); } - } else { + } else if(opts->regs[inst->ea_reg] >= 0) { ea->base = opts->regs[inst->ea_reg]; if (ea->base >= AH && ea->base <= BH && inst->reg != Z80_UNUSED && inst->reg != Z80_USE_IMMED) { uint8_t other_reg = opts->regs[inst->reg]; @@ -134,6 +136,10 @@ ror_ir(code, 8, ea->base, SZ_W); } } + } else { + ea->mode = MODE_REG_DISPLACE8; + ea->base = CONTEXT; + ea->disp = offsetof(z80_context, regs) + inst->ea_reg; } break; case Z80_REG_INDIRECT: @@ -292,7 +298,7 @@ exit(0); } -void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) +void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, uint8_t interp) { uint32_t num_cycles; host_ea src_op, dst_op; @@ -300,7 +306,12 @@ z80_options *opts = context->options; uint8_t * start = opts->gen.code.cur; code_info *code = &opts->gen.code; - check_cycles_int(&opts->gen, address); + if (!interp) { + check_cycles_int(&opts->gen, address); + if (context->breakpoint_flags[address / sizeof(uint8_t)] & (1 << (address % sizeof(uint8_t)))) { + zbreakpoint_patch(context, address, start); + } + } switch(inst->op) { case Z80_LD: @@ -350,6 +361,16 @@ } else { mov_rdispr(code, src_op.base, src_op.disp, dst_op.base, size); } + if (inst->ea_reg == Z80_I && inst->addr_mode == Z80_REG) { + //ld a, i sets some flags + //TODO: Implement half-carry flag + cmp_ir(code, 0, dst_op.base, SZ_B); + 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)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);; + mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, iff2), SCRATCH1, SZ_B); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_PV), SZ_B); + } z80_save_reg(inst, opts); z80_save_ea(code, inst, opts); if (inst->addr_mode & Z80_DIR) { @@ -915,10 +936,13 @@ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag + if (inst->immed) { + //rlca does not set these flags cmp_ir(code, 0, dst_op.base, SZ_B); setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); 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(opts, inst); if (src_op.mode != MODE_UNUSED) { @@ -947,10 +971,13 @@ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag + if (inst->immed) { + //rla does not set these flags cmp_ir(code, 0, dst_op.base, SZ_B); setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); 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(opts, inst); if (src_op.mode != MODE_UNUSED) { @@ -978,10 +1005,13 @@ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag + if (inst->immed) { + //rrca does not set these flags cmp_ir(code, 0, dst_op.base, SZ_B); setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); 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(opts, inst); if (src_op.mode != MODE_UNUSED) { @@ -1010,10 +1040,13 @@ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag + if (inst->immed) { + //rra does not set these flags cmp_ir(code, 0, dst_op.base, SZ_B); setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); 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(opts, inst); if (src_op.mode != MODE_UNUSED) { @@ -1631,18 +1664,73 @@ } } +uint8_t * z80_interp_handler(uint8_t opcode, z80_context * context) +{ + if (!context->interp_code[opcode]) { + if (opcode == 0xCB || (opcode >= 0xDD && opcode & 0xF == 0xD)) { + fprintf(stderr, "Encountered prefix byte %X at address %X. Z80 interpeter doesn't support those yet.", opcode, context->pc); + exit(1); + } + uint8_t codebuf[8]; + memset(codebuf, 0, sizeof(codebuf)); + codebuf[0] = opcode; + z80inst inst; + uint8_t * after = z80_decode(codebuf, &inst); + if (after - codebuf > 1) { + fprintf(stderr, "Encountered multi-byte Z80 instruction at %X. Z80 interpeter doesn't support those yet.", context->pc); + exit(1); + } + + z80_options * opts = context->options; + code_info *code = &opts->gen.code; + check_alloc_code(code, ZMAX_NATIVE_SIZE); + context->interp_code[opcode] = code->cur; + translate_z80inst(&inst, context, 0, 1); + mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, pc), opts->gen.scratch1, SZ_W); + add_ir(code, after - codebuf, opts->gen.scratch1, SZ_W); + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); + } + return context->interp_code[opcode]; +} + +code_info z80_make_interp_stub(z80_context * context, uint16_t address) +{ + z80_options *opts = context->options; + code_info * code = &opts->gen.code; + check_alloc_code(code, 32); + code_info stub = {code->cur, NULL}; + //TODO: make this play well with the breakpoint code + mov_ir(code, address, opts->gen.scratch1, SZ_W); + call(code, opts->read_8); + //normal opcode fetch is already factored into instruction timing + //back out the base 3 cycles from a read here + //not quite perfect, but it will have to do for now + cycles(&opts->gen, -3); + check_cycles_int(&opts->gen, address); + call(code, opts->gen.save_context); + mov_rr(code, opts->gen.scratch1, RDI, SZ_B); + mov_irdisp(code, address, opts->gen.context_reg, offsetof(z80_context, pc), SZ_W); + push_r(code, opts->gen.context_reg); + call(code, (code_ptr)z80_interp_handler); + mov_rr(code, RAX, opts->gen.scratch1, SZ_Q); + pop_r(code, opts->gen.context_reg); + call(code, opts->gen.load_context); + jmp_r(code, opts->gen.scratch1); + stub.last = code->cur; + return stub; +} + + 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 { - //dprintf("z80_get_native_address: %X NULL\n", address); - return NULL; + address -= 0x4000; + map = context->banked_code_map; } if (!map->base || !map->offsets || map->offsets[address] == INVALID_OFFSET || map->offsets[address] == EXTENSION_WORD) { //dprintf("z80_get_native_address: %X NULL\n", address); @@ -1654,6 +1742,7 @@ uint8_t z80_get_native_inst_size(z80_options * opts, uint32_t address) { + //TODO: Fix for addresses >= 0x4000 if (address >= 0x4000) { return 0; } @@ -1671,15 +1760,14 @@ opts->gen.ram_inst_sizes[0][address] = native_size; context->ram_code_flags[(address & 0x1C00) >> 10] |= 1 << ((address & 0x380) >> 7); context->ram_code_flags[((address + size) & 0x1C00) >> 10] |= 1 << (((address + size) & 0x380) >> 7); - } else if (address >= 0x8000) { - address &= 0x7FFF; - map = context->banked_code_map + context->bank_reg; + } else { + //HERE + address -= 0x4000; + map = context->banked_code_map; if (!map->offsets) { - map->offsets = malloc(sizeof(int32_t) * 0x8000); - memset(map->offsets, 0xFF, sizeof(int32_t) * 0x8000); + map->offsets = malloc(sizeof(int32_t) * 0xC000); + memset(map->offsets, 0xFF, sizeof(int32_t) * 0xC000); } - } else { - return; } if (!map->base) { map->base = native_address; @@ -1690,15 +1778,13 @@ 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; + address -= 0x4000; + map = context->banked_code_map; } if (!map->offsets) { - map->offsets = malloc(sizeof(int32_t) * 0x8000); - memset(map->offsets, 0xFF, sizeof(int32_t) * 0x8000); + map->offsets = malloc(sizeof(int32_t) * 0xC000); + memset(map->offsets, 0xFF, sizeof(int32_t) * 0xC000); } map->offsets[address] = EXTENSION_WORD; } @@ -1708,6 +1794,7 @@ uint32_t z80_get_instruction_start(native_map_slot * static_code_map, uint32_t address) { + //TODO: Fixme for address >= 0x4000 if (!static_code_map->base || address >= 0x4000) { return INVALID_INSTRUCTION_START; } @@ -1782,13 +1869,13 @@ check_alloc_code(code, ZMAX_NATIVE_SIZE); code_ptr start = code->cur; deferred_addr * orig_deferred = opts->gen.deferred; - translate_z80inst(&instbuf, context, address); + translate_z80inst(&instbuf, context, address, 0); /* if ((native_end - dst) <= orig_size) { uint8_t * native_next = z80_get_native_address(context, address + after-inst); if (native_next && ((native_next == orig_start + orig_size) || (orig_size - (native_end - dst)) > 5)) { remove_deferred_until(&opts->gen.deferred, orig_deferred); - native_end = translate_z80inst(&instbuf, orig_start, context, address); + native_end = translate_z80inst(&instbuf, orig_start, context, address, 0); if (native_next == orig_start + orig_size && (native_next-native_end) < 2) { while (native_end < orig_start + orig_size) { *(native_end++) = 0x90; //NOP @@ -1814,11 +1901,11 @@ code_info tmp_code = *code; code->cur = orig_start; code->last = orig_start + ZMAX_NATIVE_SIZE; - translate_z80inst(&instbuf, context, address); + translate_z80inst(&instbuf, context, address, 0); code_info tmp2 = *code; *code = tmp_code; if (!z80_is_terminal(&instbuf)) { - + jmp(&tmp2, z80_get_native_address_trans(context, address + after-inst)); } z80_handle_deferred(context); @@ -1837,19 +1924,16 @@ uint8_t * encoded = NULL, *next; if (address < 0x4000) { encoded = context->mem_pointers[0] + (address & 0x1FFF); - } else if(address >= 0x8000 && context->mem_pointers[1]) { - printf("attempt to translate Z80 code from banked area at address %X\n", address); - exit(1); - //encoded = context->mem_pointers[1] + (address & 0x7FFF); } - while (encoded != NULL) + + while (encoded != NULL || address >= 0x4000) { z80inst inst; dprintf("translating Z80 code at address %X\n", address); do { - if (address > 0x4000 && address < 0x8000) { - xor_rr(&opts->gen.code, RDI, RDI, SZ_D); - call(&opts->gen.code, (uint8_t *)exit); + if (address >= 0x4000) { + code_info stub = z80_make_interp_stub(context, address); + z80_map_native_address(context, address, stub.cur, 1, stub.last - stub.cur); break; } uint8_t * existing = z80_get_native_address(context, address); @@ -1869,7 +1953,7 @@ } #endif code_ptr start = opts->gen.code.cur; - translate_z80inst(&inst, context, address); + translate_z80inst(&inst, context, address, 0); z80_map_native_address(context, address, start, next-encoded, opts->gen.code.cur - start); address += next-encoded; if (address > 0xFFFF) { @@ -1885,14 +1969,12 @@ dprintf("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); + encoded = NULL; } } else { encoded = NULL; + address = 0; } } } @@ -1965,7 +2047,7 @@ } else { reg = i; size = SZ_B; - } +} if (options->regs[reg] >= 0) { mov_rrdisp(code, options->regs[reg], options->gen.context_reg, offsetof(z80_context, regs) + i, size); } @@ -2045,7 +2127,7 @@ *no_sync = code->cur - (no_sync + 1); //return to caller of z80_run retn(code); - + options->gen.handle_code_write = (code_ptr)z80_handle_code_write; options->read_8 = gen_mem_fun(&options->gen, chunks, num_chunks, READ_8, &options->read_8_noinc); @@ -2117,7 +2199,7 @@ check_cycles(&options->gen); cycles(&options->gen, 4); retn(code); - + options->read_16 = code->cur; cycles(&options->gen, 3); check_cycles(&options->gen); @@ -2134,7 +2216,7 @@ shl_ir(code, 8, options->gen.scratch1, SZ_W); mov_rr(code, options->gen.scratch2, options->gen.scratch1, SZ_B); retn(code); - + options->write_16_highfirst = code->cur; cycles(&options->gen, 3); check_cycles(&options->gen); @@ -2150,7 +2232,7 @@ //TODO: Check if we can get away with TCO here call(code, options->write_8_noinc); retn(code); - + options->write_16_lowfirst = code->cur; cycles(&options->gen, 3); check_cycles(&options->gen); @@ -2215,9 +2297,12 @@ context->static_code_map->base = NULL; 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)); - memset(context->banked_code_map, 0, sizeof(native_map_slot) * (1 << 9)); + context->banked_code_map = malloc(sizeof(native_map_slot)); + memset(context->banked_code_map, 0, sizeof(native_map_slot)); context->options = options; + context->int_cycle = 0xFFFFFFFF; + context->int_pulse_start = 0xFFFFFFFF; + context->int_pulse_end = 0xFFFFFFFF; context->run = options->run; } @@ -2229,61 +2314,81 @@ context->extra_pc = NULL; } +uint32_t zbreakpoint_patch(z80_context * context, uint16_t address, code_ptr dst) +{ + code_info code = {dst, dst+16}; + mov_ir(&code, address, SCRATCH1, SZ_W); + call(&code, context->bp_stub); + return code.cur-dst; +} + +void zcreate_stub(z80_context * context) +{ + z80_options * opts = context->options; + code_info *code = &opts->gen.code; + check_code_prologue(code); + context->bp_stub = code->cur; + + //Calculate length of prologue + check_cycles_int(&opts->gen, 0); + int check_int_size = code->cur-context->bp_stub; + code->cur = context->bp_stub; + + //Calculate length of patch + int patch_size = zbreakpoint_patch(context, 0, code->cur); + + //Save context and call breakpoint handler + 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, context->bp_handler); + mov_rr(code, RAX, opts->gen.context_reg, SZ_Q); + //Restore 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); + uint8_t * jmp_off = code->cur+1; + jcc(code, CC_NC, code->cur + 7); + pop_r(code, opts->gen.scratch1); + add_ir(code, check_int_size - patch_size, opts->gen.scratch1, SZ_Q); + push_r(code, opts->gen.scratch1); + 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); + add_ir(code, check_int_size - patch_size, opts->gen.scratch1, SZ_Q); + jmp_r(code, opts->gen.scratch1); +} + void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler) { - static uint8_t * bp_stub = NULL; - z80_options * opts = context->options; - code_ptr native = z80_get_native_address_trans(context, address); - code_info tmp_code = {native, native+16}; - mov_ir(&tmp_code, address, opts->gen.scratch1, SZ_W); - if (!bp_stub) { - code_info *code = &opts->gen.code; - check_code_prologue(code); - bp_stub = code->cur; - call(&tmp_code, bp_stub); - - //Calculate length of prologue - check_cycles_int(&opts->gen, address); - int check_int_size = code->cur-bp_stub; - code->cur = bp_stub; - - //Save context and call breakpoint handler - 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, opts->gen.load_context); - pop_r(code, opts->gen.scratch1); - //do prologue stuff - cmp_rr(code, opts->gen.cycles, opts->gen.limit, SZ_D); - uint8_t * jmp_off = code->cur+1; - jcc(code, CC_NC, code->cur + 7); - pop_r(code, opts->gen.scratch1); - add_ir(code, check_int_size - (tmp_code.cur-native), opts->gen.scratch1, SZ_Q); - push_r(code, opts->gen.scratch1); - 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); - add_ir(code, check_int_size - (tmp_code.cur-native), opts->gen.scratch1, SZ_Q); - jmp_r(code, opts->gen.scratch1); - } else { - call(&tmp_code, bp_stub); + context->bp_handler = bp_handler; + uint8_t bit = 1 << (address % sizeof(uint8_t)); + if (!(bit & context->breakpoint_flags[address / sizeof(uint8_t)])) { + context->breakpoint_flags[address / sizeof(uint8_t)] |= bit; + if (!context->bp_stub) { + zcreate_stub(context); + } + uint8_t * native = z80_get_native_address(context, address); + if (native) { + zbreakpoint_patch(context, address, native); + } } } void zremove_breakpoint(z80_context * context, uint16_t address) { + context->breakpoint_flags[address / sizeof(uint8_t)] &= ~(1 << (address % sizeof(uint8_t))); uint8_t * native = z80_get_native_address(context, address); - z80_options * opts = context->options; - code_info tmp_code = opts->gen.code; - opts->gen.code.cur = native; - opts->gen.code.last = native + 16; - check_cycles_int(&opts->gen, address); - opts->gen.code = tmp_code; + if (native) { + z80_options * opts = context->options; + code_info tmp_code = opts->gen.code; + opts->gen.code.cur = native; + opts->gen.code.last = native + 16; + check_cycles_int(&opts->gen, address); + opts->gen.code = tmp_code; + } } -