Mercurial > repos > blastem
diff m68k_to_x86.c @ 18:3e7bfde7606e
M68K to x86 translation works for a limited subset of instructions and addressing modes
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 04 Dec 2012 19:13:12 -0800 |
parents | 2bdad0f52f42 |
children | 4717146a7606 |
line wrap: on
line diff
--- a/m68k_to_x86.c Tue Nov 27 22:54:38 2012 -0800 +++ b/m68k_to_x86.c Tue Dec 04 19:13:12 2012 -0800 @@ -1,11 +1,16 @@ #include "gen_x86.h" #include "m68k_to_x86.h" - +#include <stdio.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> #define BUS 4 +#define PREDEC_PENALTY 2 #define CYCLES RAX #define LIMIT RBP -#define SCRATCH RCX +#define SCRATCH1 RCX +#define SCRATCH2 RDI #define CONTEXT RSI #define FLAG_N RBX @@ -22,16 +27,26 @@ } x86_ea; void handle_cycle_limit(); +void m68k_read_word_scratch1(); +void m68k_read_long_scratch1(); +void m68k_read_byte_scratch1(); +void m68k_write_word(); +void m68k_write_long_lowfirst(); +void m68k_write_long_highfirst(); +void m68k_write_byte(); +void m68k_save_context(); +void m68k_modified_ret_addr(); +void m68k_start_context(uint8_t * addr, m68k_context * context); uint8_t * cycles(uint8_t * dst, uint32_t num) { - dst = add_i32r(dst, num, CYCLES); + dst = add_ir(dst, num, CYCLES, SZ_D); } -uint8_t * check_cycles(uint8_t * dst) Ivds +uint8_t * check_cycles(uint8_t * dst) { dst = cmp_rr(dst, CYCLES, LIMIT, SZ_D); - dst = jcc(dst, CC_G, 5); + dst = jcc(dst, CC_G, dst+7); dst = call(dst, (char *)handle_cycle_limit); } @@ -46,37 +61,551 @@ return -1; } -uint8_t * translate_m68k_ea(m68k_op_info * op, x86_ea * dst, uint8_t * out, x86_68k_options * opts) +void print_regs_exit(m68k_context * context) { - int8_t reg = native_reg(op, opts); + for (int i = 0; i < 8; i++) { + printf("d%d: %X\n", i, context->dregs[i]); + } + for (int i = 0; i < 8; i++) { + printf("a%d: %X\n", i, context->aregs[i]); + } + exit(0); +} + +uint8_t * translate_m68k_src(m68kinst * inst, x86_ea * ea, uint8_t * out, x86_68k_options * opts) +{ + int8_t reg = native_reg(&(inst->src), opts); + int32_t dec_amount,inc_amount; if (reg >= 0) { - dst->mode = MODE_REG_DIRECT; - dst->base = reg; - return; + ea->mode = MODE_REG_DIRECT; + ea->base = reg; + return out; } - switch (op->addr_mode) + switch (inst->src.addr_mode) + { + case MODE_REG: + case MODE_AREG: + //We only get one memory parameter, so if the dst operand is a register in memory, + //we need to copy this to a temp register first + reg = native_reg(&(inst->dst), opts); + if (reg >= 0 || inst->dst.addr_mode == MODE_UNUSED || (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode == MODE_AREG) + || inst->op == M68K_EXG) { + + ea->mode = MODE_REG_DISPLACE8; + ea->base = CONTEXT; + ea->disp = (inst->src.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * inst->src.params.regs.pri; + } else { + out = mov_rdisp8r(out, CONTEXT, (inst->src.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * inst->src.params.regs.pri, SCRATCH1, inst->extra.size); + ea->mode = MODE_REG_DIRECT; + ea->base = SCRATCH1; + } + break; + case MODE_AREG_PREDEC: + dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1); + out = cycles(out, PREDEC_PENALTY); + if (opts->aregs[inst->src.params.regs.pri] >= 0) { + out = sub_ir(out, inc_amount, opts->aregs[inst->src.params.regs.pri], SZ_D); + } else { + out = sub_irdisp8(out, inc_amount, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SZ_D); + } + out = check_cycles(out); + case MODE_AREG_INDIRECT: + case MODE_AREG_POSTINC: + if (opts->aregs[inst->src.params.regs.pri] >= 0) { + out = mov_rr(out, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D); + } else { + out = mov_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SCRATCH1, SZ_D); + } + switch (inst->extra.size) + { + case OPSIZE_BYTE: + out = call(out, (char *)m68k_read_byte_scratch1); + break; + case OPSIZE_WORD: + out = call(out, (char *)m68k_read_word_scratch1); + break; + case OPSIZE_LONG: + out = call(out, (char *)m68k_read_long_scratch1); + break; + } + + if (inst->src.addr_mode == MODE_AREG_POSTINC) { + inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1); + if (opts->aregs[inst->src.params.regs.pri] >= 0) { + out = add_ir(out, inc_amount, opts->aregs[inst->src.params.regs.pri], SZ_D); + } else { + out = add_irdisp8(out, inc_amount, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SZ_D); + } + } + ea->mode = MODE_REG_DIRECT; + ea->base = SCRATCH1; + break; + case MODE_IMMEDIATE: + if (inst->variant != VAR_QUICK) { + if (inst->extra.size == OPSIZE_LONG) { + out = cycles(out, BUS); + out = check_cycles(out); + } + out = cycles(out, BUS); + out = check_cycles(out); + } + ea->mode = MODE_IMMED; + ea->disp = inst->src.params.immed; + break; + default: + printf("address mode %d not implemented (src)\n", inst->src.addr_mode); + exit(1); + } + return out; +} + +uint8_t * translate_m68k_dst(m68kinst * inst, x86_ea * ea, uint8_t * out, x86_68k_options * opts) +{ + int8_t reg = native_reg(&(inst->dst), opts); + int32_t dec_amount, inc_amount; + if (reg >= 0) { + ea->mode = MODE_REG_DIRECT; + ea->base = reg; + return out; + } + switch (inst->dst.addr_mode) { case MODE_REG: case MODE_AREG: - dst->mode = MODE_DISPLACE8; - dst->base = CONTEXT; - dst->disp = (op->addr_mode = MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * op->params.regs.pri; + ea->mode = MODE_REG_DISPLACE8; + ea->base = CONTEXT; + ea->disp = (inst->dst.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * inst->dst.params.regs.pri; + break; + case MODE_AREG_PREDEC: + dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1); + if (opts->aregs[inst->dst.params.regs.pri] >= 0) { + out = sub_ir(out, dec_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D); + } else { + out = sub_irdisp8(out, dec_amount, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D); + } + case MODE_AREG_INDIRECT: + case MODE_AREG_POSTINC: + if (opts->aregs[inst->dst.params.regs.pri] >= 0) { + out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], SCRATCH1, SZ_D); + } else { + out = mov_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SCRATCH1, SZ_D); + } + switch (inst->extra.size) + { + case OPSIZE_BYTE: + out = call(out, (char *)m68k_read_byte_scratch1); + break; + case OPSIZE_WORD: + out = call(out, (char *)m68k_read_word_scratch1); + break; + case OPSIZE_LONG: + out = call(out, (char *)m68k_read_long_scratch1); + break; + } + //save reg value in SCRATCH2 so we can use it to save the result in memory later + if (opts->aregs[inst->dst.params.regs.pri] >= 0) { + out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D); + } else { + out = mov_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SCRATCH2, SZ_D); + } + + if (inst->src.addr_mode == MODE_AREG_POSTINC) { + inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1); + if (opts->aregs[inst->dst.params.regs.pri] >= 0) { + out = add_ir(out, inc_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D); + } else { + out = add_irdisp8(out, inc_amount, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D); + } + } + ea->mode = MODE_REG_DIRECT; + ea->base = SCRATCH1; + break; + default: + printf("address mode %d not implemented (dst)\n", inst->dst.addr_mode); + exit(1); + } + return out; +} + +uint8_t * m68k_save_result(m68kinst * inst, uint8_t * out, x86_68k_options * opts) +{ + if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG) { + switch (inst->extra.size) + { + case OPSIZE_BYTE: + out = call(out, (char *)m68k_write_byte); + break; + case OPSIZE_WORD: + out = call(out, (char *)m68k_write_word); + break; + case OPSIZE_LONG: + out = call(out, (char *)m68k_write_long_lowfirst); + break; + } + } + return out; +} + +uint8_t * get_native_address(native_map_slot * native_code_map, uint32_t address) +{ + address &= 0xFFFFFF; + uint32_t chunk = address / NATIVE_CHUNK_SIZE; + if (!native_code_map[chunk].base) { + return NULL; + } + uint32_t offset = address % NATIVE_CHUNK_SIZE; + if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET) { + return NULL; + } + return native_code_map[chunk].base + native_code_map[chunk].offsets[offset]; +} + +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); + printf("Native dest: %p, Offset address: %p, displacement: %X\n", native, cur->dest, disp); + 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(native_map_slot * native_code_map, uint32_t address, uint8_t * native_addr) +{ + //FIXME: This probably isn't going to work with real code in a lot of cases, no guarantee that + //all the code in 1KB block is going to be translated at the same time + address &= 0xFFFFFF; + uint32_t chunk = address / NATIVE_CHUNK_SIZE; + if (!native_code_map[chunk].base) { + native_code_map[chunk].base = native_addr; + native_code_map[chunk].offsets = malloc(sizeof(uint16_t) * NATIVE_CHUNK_SIZE); + memset(native_code_map[chunk].offsets, 0xFF, sizeof(uint16_t) * NATIVE_CHUNK_SIZE); + } + uint32_t offset = address % NATIVE_CHUNK_SIZE; + native_code_map[chunk].offsets[offset] = native_addr-native_code_map[chunk].base; +} + +uint8_t * translate_m68k_move(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) +{ + int8_t reg, flags_reg; + uint8_t dir = 0; + int32_t offset; + int32_t inc_amount, dec_amount; + x86_ea src; + dst = translate_m68k_src(inst, &src, dst, opts); + reg = native_reg(&(inst->dst), opts); + if (src.mode == MODE_REG_DIRECT) { + flags_reg = src.base; + } else { + if (reg >= 0) { + flags_reg = reg; + } else { + printf("moving %d to temp register %d\n", src.disp, SCRATCH1); + dst = mov_ir(dst, src.disp, SCRATCH1, SZ_D); + src.mode = MODE_REG_DIRECT; + flags_reg = src.base = SCRATCH1; + } + } + switch(inst->dst.addr_mode) + { + case MODE_REG: + case MODE_AREG: + if (reg >= 0) { + if (src.mode == MODE_REG_DIRECT) { + dst = mov_rr(dst, src.base, reg, inst->extra.size); + } else if (src.mode == MODE_REG_DISPLACE8) { + dst = mov_rdisp8r(dst, src.base, src.disp, reg, inst->extra.size); + } else { + dst = mov_ir(dst, src.disp, reg, inst->extra.size); + } + } else if(src.mode == MODE_REG_DIRECT) { + printf("mov_rrdisp8 from reg %d to offset %d from reg %d (%d)\n", src.base, (inst->dst.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * inst->dst.params.regs.pri, CONTEXT, inst->dst.params.regs.pri); + dst = mov_rrdisp8(dst, src.base, CONTEXT, (inst->dst.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * inst->dst.params.regs.pri, inst->extra.size); + } else { + dst = mov_irdisp8(dst, src.disp, CONTEXT, (inst->dst.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * inst->dst.params.regs.pri, inst->extra.size); + } break; + case MODE_AREG_PREDEC: + dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1); + if (opts->aregs[inst->dst.params.regs.pri] >= 0) { + dst = sub_ir(dst, dec_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D); + } else { + dst = sub_irdisp8(dst, dec_amount, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D); + } case MODE_AREG_INDIRECT: - + case MODE_AREG_POSTINC: + if (opts->aregs[inst->dst.params.regs.pri] >= 0) { + dst = mov_rr(dst, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D); + } else { + dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SCRATCH2, SZ_D); + } + if (src.mode == MODE_REG_DIRECT) { + if (src.base != SCRATCH1) { + dst = mov_rr(dst, src.base, SCRATCH1, inst->extra.size); + } + } else if (src.mode == MODE_REG_DISPLACE8) { + dst = mov_rdisp8r(dst, src.base, src.disp, SCRATCH1, inst->extra.size); + } else { + dst = mov_ir(dst, src.disp, SCRATCH1, inst->extra.size); + } + switch (inst->extra.size) + { + case OPSIZE_BYTE: + dst = call(dst, (char *)m68k_write_byte); + break; + case OPSIZE_WORD: + dst = call(dst, (char *)m68k_write_word); + break; + case OPSIZE_LONG: + dst = call(dst, (char *)m68k_write_long_highfirst); + break; + } + if (inst->dst.addr_mode == MODE_AREG_POSTINC) { + inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1); + if (opts->aregs[inst->dst.params.regs.pri] >= 0) { + dst = add_ir(dst, inc_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D); + } else { + dst = add_irdisp8(dst, inc_amount, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D); + } + } break; + default: + printf("address mode %d not implemented (move dst)\n", inst->dst.addr_mode); + exit(1); } + + //add cycles for prefetch + dst = cycles(dst, BUS); + //update flags + dst = mov_ir(dst, 0, FLAG_V, SZ_B); + dst = mov_ir(dst, 0, FLAG_C, SZ_B); + dst = cmp_ir(dst, 0, flags_reg, inst->extra.size); + dst = setcc_r(dst, CC_Z, FLAG_Z); + dst = setcc_r(dst, CC_S, FLAG_N); + dst = check_cycles(dst); + return dst; +} + +uint8_t * translate_m68k_lea(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) +{ + int8_t dst_reg = native_reg(&(inst->dst), opts); + switch(inst->src.addr_mode) + { + case MODE_AREG_INDIRECT: + dst = cycles(dst, BUS); + if (opts->aregs[inst->src.params.regs.pri] >= 0) { + if (dst_reg >= 0) { + dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], dst_reg, SZ_D); + } else { + dst = mov_rrdisp8(dst, opts->aregs[inst->src.params.regs.pri], CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D); + } + } else { + if (dst_reg >= 0) { + dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, dst_reg, SZ_D); + } else { + dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SCRATCH1, SZ_D); + dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D); + } + } + dst = check_cycles(dst); + break; + case MODE_ABSOLUTE: + dst = cycles(dst, BUS); + dst = check_cycles(dst); + case MODE_ABSOLUTE_SHORT: + dst = cycles(dst, BUS); + dst = check_cycles(dst); + dst = cycles(dst, BUS); + if (dst_reg >= 0) { + dst = mov_ir(dst, inst->src.params.immed, dst_reg, SZ_D); + } else { + dst = mov_irdisp8(dst, inst->src.params.immed, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D); + } + dst = check_cycles(dst); + break; + } + return dst; +} + +uint8_t * translate_m68k_bsr(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) +{ + //TODO: Add cycles + int32_t disp = inst->src.params.immed; + uint32_t after = inst->address + (inst->variant == VAR_BYTE ? 2 : (inst->variant == VAR_WORD ? 4 : 6)); + dst = mov_ir(dst, after, SCRATCH1, SZ_D); + dst = push_r(dst, SCRATCH1); + dst = sub_ir(dst, 4, opts->aregs[7], SZ_D); + dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D); + dst = call(dst, (char *)m68k_write_long_highfirst); + printf("bsr@%X: after=%X, disp=%X, dest=%X\n", inst->address, after, disp, after+disp); + uint8_t * dest_addr = get_native_address(opts->native_code_map, after + disp); + if (!dest_addr) { + opts->deferred = defer_address(opts->deferred, after + disp, dst + 1); + //dummy address to be replaced later + dest_addr = dst + 5; + } + dst = call(dst, (char *)dest_addr); + //would add_ir(dst, 8, RSP, SZ_Q) be faster here? + dst = pop_r(dst, SCRATCH1); + return dst; +} + +uint8_t * translate_m68k_bcc(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) +{ + //TODO: Add cycles + int32_t disp = inst->src.params.immed; + uint32_t after = inst->address + (inst->variant == VAR_BYTE ? 2 : (inst->variant == VAR_WORD ? 4 : 6)); + printf("bcc@%X: after=%X, disp=%X, dest=%X\n", inst->address, after, disp, after+disp); + uint8_t * dest_addr = get_native_address(opts->native_code_map, after + disp); + if (inst->extra.cond == COND_TRUE) { + if (!dest_addr) { + opts->deferred = defer_address(opts->deferred, after + disp, dst + 1); + //dummy address to be replaced later, make sure it generates a 4-byte displacement + dest_addr = dst + 256; + } + dst = jmp(dst, dest_addr); + } else { + uint8_t cond = CC_NZ; + switch (inst->extra.cond) + { + case COND_HIGH: + cond = CC_Z; + case COND_LOW_SAME: + dst = mov_rr(dst, FLAG_Z, SCRATCH1, SZ_B); + dst = or_rr(dst, FLAG_C, SCRATCH1, SZ_B); + break; + case COND_CARRY_CLR: + cond = CC_Z; + case COND_CARRY_SET: + dst = cmp_ir(dst, 0, FLAG_C, SZ_B); + break; + case COND_NOT_EQ: + cond = CC_Z; + case COND_EQ: + dst = cmp_ir(dst, 0, FLAG_Z, SZ_B); + break; + case COND_OVERF_CLR: + cond = CC_Z; + case COND_OVERF_SET: + dst = cmp_ir(dst, 0, FLAG_V, SZ_B); + break; + case COND_PLUS: + cond = CC_Z; + case COND_MINUS: + dst = cmp_ir(dst, 0, FLAG_N, SZ_B); + break; + case COND_GREATER_EQ: + cond = CC_Z; + case COND_LESS: + dst = cmp_rr(dst, FLAG_N, FLAG_V, SZ_B); + break; + case COND_GREATER: + cond = CC_Z; + case COND_LESS_EQ: + dst = mov_rr(dst, FLAG_V, SCRATCH1, SZ_B); + dst = xor_rr(dst, FLAG_N, SCRATCH1, SZ_B); + dst = or_rr(dst, FLAG_Z, SCRATCH1, SZ_B); + break; + } + if (!dest_addr) { + opts->deferred = defer_address(opts->deferred, after + disp, dst + 2); + //dummy address to be replaced later, make sure it generates a 4-byte displacement + dest_addr = dst + 256; + } + dst = jcc(dst, cond, dest_addr); + } + return dst; +} + +uint8_t * translate_m68k_rts(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) +{ + //TODO: Add cycles + dst = mov_rr(dst, opts->aregs[7], SCRATCH1, SZ_D); + dst = add_ir(dst, 4, opts->aregs[7], SZ_D); + dst = call(dst, (char *)m68k_read_long_scratch1); + dst = cmp_rdisp8r(dst, RSP, 8, SCRATCH1, SZ_D); + dst = jcc(dst, CC_NZ, dst+3); + dst = retn(dst); + dst = jmp(dst, (char *)m68k_modified_ret_addr); + return dst; } uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) { - int8_t reg_a, reg_b, flags_reg; - uint8_t dir = 0; - int32_t offset; + map_native_address(opts->native_code_map, inst->address, dst); + if (inst->op == M68K_MOVE) { + return translate_m68k_move(dst, inst, opts); + } else if(inst->op == M68K_LEA) { + return translate_m68k_lea(dst, inst, opts); + } else if(inst->op == M68K_BSR) { + return translate_m68k_bsr(dst, inst, opts); + } else if(inst->op == M68K_BCC) { + return translate_m68k_bcc(dst, inst, opts); + } else if(inst->op == M68K_RTS) { + return translate_m68k_rts(dst, inst, opts); + } + x86_ea src_op, dst_op; + if (inst->src.addr_mode != MODE_UNUSED) { + dst = translate_m68k_src(inst, &src_op, dst, opts); + } + if (inst->dst.addr_mode != MODE_UNUSED) { + dst = translate_m68k_dst(inst, &dst_op, dst, opts); + } switch(inst->op) { case M68K_ABCD: + break; case M68K_ADD: + dst = cycles(dst, BUS); + if (src_op.mode == MODE_REG_DIRECT) { + if (dst_op.mode == MODE_REG_DIRECT) { + dst = add_rr(dst, src_op.base, dst_op.base, inst->extra.size); + } else { + dst = add_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, inst->extra.size); + } + } else if (src_op.mode == MODE_REG_DISPLACE8) { + dst = add_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, inst->extra.size); + } else { + if (dst_op.mode == MODE_REG_DIRECT) { + dst = add_ir(dst, src_op.disp, dst_op.base, inst->extra.size); + } else { + dst = add_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); + } + } + dst = setcc_r(dst, CC_C, FLAG_C); + dst = setcc_r(dst, CC_Z, FLAG_Z); + dst = setcc_r(dst, CC_S, FLAG_N); + dst = setcc_r(dst, CC_O, FLAG_V); + dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); + dst = check_cycles(dst); + break; case M68K_ADDX: case M68K_AND: case M68K_ANDI_CCR: @@ -92,6 +621,28 @@ case M68K_CHK: case M68K_CLR: case M68K_CMP: + dst = cycles(dst, BUS); + if (src_op.mode == MODE_REG_DIRECT) { + if (dst_op.mode == MODE_REG_DIRECT) { + dst = cmp_rr(dst, src_op.base, dst_op.base, inst->extra.size); + } else { + dst = cmp_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, inst->extra.size); + } + } else if (src_op.mode == MODE_REG_DISPLACE8) { + dst = cmp_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, inst->extra.size); + } else { + if (dst_op.mode == MODE_REG_DIRECT) { + dst = cmp_ir(dst, src_op.disp, dst_op.base, inst->extra.size); + } else { + dst = cmp_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); + } + } + dst = setcc_r(dst, CC_C, FLAG_C); + dst = setcc_r(dst, CC_Z, FLAG_Z); + dst = setcc_r(dst, CC_S, FLAG_N); + dst = setcc_r(dst, CC_O, FLAG_V); + dst = check_cycles(dst); + break; case M68K_DBCC: case M68K_DIVS: case M68K_DIVU: @@ -99,95 +650,41 @@ case M68K_EORI_CCR: case M68K_EORI_SR: case M68K_EXG: + dst = cycles(dst, 6); + if (dst_op.mode == MODE_REG_DIRECT) { + dst = mov_rr(dst, dst_op.base, SCRATCH2, SZ_D); + if (src_op.mode == MODE_REG_DIRECT) { + dst = mov_rr(dst, src_op.base, dst_op.base, SZ_D); + dst = mov_rr(dst, SCRATCH2, src_op.base, SZ_D); + } else { + dst = mov_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, SZ_D); + dst = mov_rrdisp8(dst, SCRATCH2, src_op.base, src_op.disp, SZ_D); + } + } else { + dst = mov_rdisp8r(dst, dst_op.base, dst_op.disp, SCRATCH2, SZ_D); + if (src_op.mode == MODE_REG_DIRECT) { + dst = mov_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, SZ_D); + dst = mov_rr(dst, SCRATCH2, src_op.base, SZ_D); + } else { + dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_D); + dst = mov_rrdisp8(dst, SCRATCH1, dst_op.base, dst_op.disp, SZ_D); + dst = mov_rrdisp8(dst, SCRATCH2, src_op.base, src_op.disp, SZ_D); + } + } + dst = check_cycles(dst); + break; case M68K_EXT: case M68K_ILLEGAL: + dst = call(dst, (uint8_t *)m68k_save_context); + dst = mov_rr(dst, CONTEXT, RDI, SZ_Q); + dst = call(dst, (uint8_t *)print_regs_exit); + break; case M68K_JMP: case M68K_JSR: case M68K_LEA: case M68K_LINK: case M68K_LSL: case M68K_LSR: - case M68K_MOVE: - - if ((inst->src.addr_mode == MODE_REG || inst->src.addr_mode == MODE_AREG || (inst->src.addr_mode == MODE_IMMEDIATE && inst->src.variant == VAR_QUICK)) && (inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG)) { - dst = cycles(dst, BUS); - reg_a = native_reg(&(inst->src), opts); - reg_b = native_reg(&(inst->dst), opts); - dst = cycles(dst, BUS); - if (reg_a >= 0 && reg_b >= 0) { - dst = mov_rr(dst, reg_a, reg_b, inst->extra.size); - flags_reg = reg_b; - } else if(reg_a >= 0) { - offset = inst->dst.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs); - dst = mov_rrdisp8(dst, reg_a, CONTEXT, offset + 4 * inst->dst.params.regs.pri, inst->extra.size); - flags_reg = reg_a; - } else if(reg_b >= 0) { - if (inst->src.addr_mode == MODE_REG) { - dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + 4 * inst->src.params.regs.pri, reg_b, inst->extra.size); - } else if(inst->src.addr_mode == MODE_AREG) { - dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, reg_b, inst->extra.size); - } else { - dst = mov_i32r(dst, inst->src.params.u32, reg_b); - } - flags_reg = reg_b; - } else { - - } - dst = mov_i8r(dst, 0, FLAG_V); - dst = mov_i8r(dst, 0, FLAG_C); - switch (inst->extra.size) - { - case OPSIZE_BYTE: - dst = cmp_i8r(dst, 0, reg_b, SZ_B); - break; - case OPSIZE_WORD: - dst = cmp_i8r(dst, 0, reg_b, SZ_W); - break; - case OPSIZE_LONG: - dst = cmp_i8r(dst, 0, reg_b, SZ_D); - break; - } - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - dst = check_cycles(dst); - } - - if (reg_a >= 0 && reg_b >= 0) { - dst = cycles(dst, BUS); - dst = mov_rr(dst, reg_a, reg_b, inst->extra.size); - dst = mov_i8r(dst, 0, FLAG_V); - dst = mov_i8r(dst, 0, FLAG_C); - switch (inst->extra.size) - { - case OPSIZE_BYTE: - dst = cmp_i8r(dst, 0, reg_b, SZ_B); - break; - case OPSIZE_WORD: - dst = cmp_i8r(dst, 0, reg_b, SZ_W); - break; - case OPSIZE_LONG: - dst = cmp_i8r(dst, 0, reg_b, SZ_D); - break; - } - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - dst = check_cycles(dst); - } else if(reg_a >= 0 || reg_b >= 0) { - if (reg_a >= 0) { - switch (inst->dst.addr_mode) - { - case MODE_REG: - dst = cycles(dst, BUS); - dst = mov_rr(dst, reg_a, reg_b, inst->extra.size); - dst = check_cycles(dst); - break; - case MODE_AREG: - break; - } - } else { - } - } - break; case M68K_MOVE_CCR: case M68K_MOVE_FROM_SR: case M68K_MOVE_SR: @@ -217,6 +714,29 @@ case M68K_SCC: case M68K_STOP: case M68K_SUB: + dst = cycles(dst, BUS); + if (src_op.mode == MODE_REG_DIRECT) { + if (dst_op.mode == MODE_REG_DIRECT) { + dst = sub_rr(dst, src_op.base, dst_op.base, inst->extra.size); + } else { + dst = sub_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, inst->extra.size); + } + } else if (src_op.mode == MODE_REG_DISPLACE8) { + dst = sub_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, inst->extra.size); + } else { + if (dst_op.mode == MODE_REG_DIRECT) { + dst = sub_ir(dst, src_op.disp, dst_op.base, inst->extra.size); + } else { + dst = sub_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); + } + } + dst = setcc_r(dst, CC_C, FLAG_C); + dst = setcc_r(dst, CC_Z, FLAG_Z); + dst = setcc_r(dst, CC_S, FLAG_N); + dst = setcc_r(dst, CC_O, FLAG_V); + dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); + dst = check_cycles(dst); + break; case M68K_SUBX: case M68K_SWAP: case M68K_TAS: @@ -227,5 +747,65 @@ case M68K_INVALID: break; } + return dst; } +uint8_t * translate_m68k_stream(uint8_t * dst, uint8_t * dst_end, uint32_t address, m68k_context * context) +{ + m68kinst instbuf; + x86_68k_options * opts = context->options; + char disbuf[1024]; + uint16_t *encoded = context->mem_pointers[0] + address/2, *next; + do { + do { + if (dst_end-dst < 128) { + puts("out of code memory"); + exit(1); + } + next = m68k_decode(encoded, &instbuf, address); + address += (next-encoded)*2; + encoded = next; + m68k_disasm(&instbuf, disbuf); + printf("%X: %s\n", instbuf.address, disbuf); + dst = translate_m68k(dst, &instbuf, opts); + } while(instbuf.op != M68K_ILLEGAL && instbuf.op != M68K_RTS && instbuf.op != M68K_RTE && !(instbuf.op == M68K_BCC && instbuf.extra.cond == COND_TRUE) && instbuf.op != M68K_JMP); + process_deferred(opts); + if (opts->deferred) { + address = opts->deferred->address; + encoded = context->mem_pointers[0] + address/2; + } else { + encoded = NULL; + } + } while(encoded != NULL); + return dst; +} + +void start_68k_context(m68k_context * context, uint32_t address) +{ + uint8_t * addr = get_native_address(context->native_code_map, address); + m68k_start_context(addr, context); +} + +void init_x86_68k_opts(x86_68k_options * opts) +{ + opts->flags = 0; + for (int i = 0; i < 8; i++) + opts->dregs[i] = opts->aregs[i] = -1; + opts->dregs[0] = R10; + opts->dregs[1] = R11; + opts->dregs[2] = R12; + opts->aregs[0] = R13; + opts->aregs[1] = R14; + opts->aregs[7] = R15; + opts->native_code_map = malloc(sizeof(native_map_slot) * NATIVE_MAP_CHUNKS); + memset(opts->native_code_map, 0, sizeof(native_map_slot) * NATIVE_MAP_CHUNKS); + opts->deferred = NULL; +} + +void init_68k_context(m68k_context * context, native_map_slot * native_code_map, void * opts) +{ + memset(context, 0, sizeof(m68k_context)); + context->native_code_map = native_code_map; + context->options = opts; +} +