summaryrefslogtreecommitdiff
path: root/m68k_to_x86.c
diff options
context:
space:
mode:
Diffstat (limited to 'm68k_to_x86.c')
-rw-r--r--m68k_to_x86.c140
1 files changed, 105 insertions, 35 deletions
diff --git a/m68k_to_x86.c b/m68k_to_x86.c
index 6ebc96d..219d4c9 100644
--- a/m68k_to_x86.c
+++ b/m68k_to_x86.c
@@ -1,3 +1,8 @@
+/*
+ Copyright 2013 Michael Pavone
+ 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 "gen_x86.h"
#include "m68k_to_x86.h"
#include "68kinst.h"
@@ -123,9 +128,9 @@ uint8_t * translate_m68k_src(m68kinst * inst, x86_ea * ea, uint8_t * out, x86_68
//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)
+ 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 = reg_offset(&(inst->src));
@@ -150,7 +155,7 @@ uint8_t * translate_m68k_src(m68kinst * inst, x86_ea * ea, uint8_t * out, x86_68
out = sub_irdisp8(out, dec_amount, CONTEXT, reg_offset(&(inst->src)), SZ_D);
}
case MODE_AREG_INDIRECT:
- case MODE_AREG_POSTINC:
+ 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 {
@@ -168,7 +173,7 @@ uint8_t * translate_m68k_src(m68kinst * inst, x86_ea * ea, uint8_t * out, x86_68
out = call(out, opts->read_32);
break;
}
-
+
if (inst->src.addr_mode == MODE_AREG_POSTINC) {
inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->src.params.regs.pri == 7 ? 2 : 1));
if (opts->aregs[inst->src.params.regs.pri] >= 0) {
@@ -441,7 +446,7 @@ uint8_t * translate_m68k_dst(m68kinst * inst, x86_ea * ea, uint8_t * out, x86_68
out = mov_rdisp8r(out, CONTEXT, reg_offset(&(inst->dst)), SCRATCH2, SZ_D);
}
}
-
+
if (inst->dst.addr_mode == MODE_AREG_POSTINC) {
inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1));
if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
@@ -781,7 +786,7 @@ uint8_t * translate_m68k_move(uint8_t * dst, m68kinst * inst, x86_68k_options *
dst = mov_ir(dst, 0, FLAG_V, SZ_B);
dst = mov_ir(dst, 0, FLAG_C, SZ_B);
}
-
+
if (inst->dst.addr_mode != MODE_AREG) {
if (src.mode == MODE_REG_DIRECT) {
flags_reg = src.base;
@@ -2459,7 +2464,7 @@ uint8_t * translate_m68k_movep(uint8_t * dst, m68kinst * inst, x86_68k_options *
dst = pop_r(dst, SCRATCH2);
dst = mov_rr(dst, reg, SCRATCH1, SZ_D);
dst = shr_ir(dst, 16, SCRATCH1, SZ_D);
-
+
} else {
dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src))+3, SCRATCH1, SZ_B);
dst = push_r(dst, SCRATCH2);
@@ -2527,7 +2532,7 @@ uint8_t * translate_m68k_movep(uint8_t * dst, m68kinst * inst, x86_68k_options *
dst = push_r(dst, SCRATCH1);
dst = call(dst, opts->read_8);
if (reg >= 0) {
-
+
dst = shl_ir(dst, 8, SCRATCH1, SZ_W);
dst = mov_rr(dst, SCRATCH1, reg, SZ_W);
dst = pop_r(dst, SCRATCH1);
@@ -2628,7 +2633,7 @@ uint8_t * translate_shift(uint8_t * dst, m68kinst * inst, x86_ea *src_op, x86_ea
} else {
dst = mov_rdisp8r(dst, src_op->base, src_op->disp, RCX, SZ_B);
}
-
+
}
dst = and_ir(dst, 63, RCX, SZ_D);
nz_off = dst+1;
@@ -2676,7 +2681,7 @@ uint8_t * translate_shift(uint8_t * dst, m68kinst * inst, x86_ea *src_op, x86_ea
if (inst->extra.size == OPSIZE_LONG) {
uint8_t * neq_32_off = dst + 1;
dst = jcc(dst, CC_NZ, dst+2);
-
+
//set the carry bit to the lsb
if (dst_op->mode == MODE_REG_DIRECT) {
dst = special(dst, 1, dst_op->base, SZ_D);
@@ -2703,7 +2708,7 @@ uint8_t * translate_shift(uint8_t * dst, m68kinst * inst, x86_ea *src_op, x86_ea
dst = shift_irdisp8(dst, 31, dst_op->base, dst_op->disp, inst->extra.size);
dst = shift_irdisp8(dst, 1, dst_op->base, dst_op->disp, inst->extra.size);
}
-
+
}
end_off = dst+1;
dst = jmp(dst, dst+2);
@@ -2715,7 +2720,7 @@ uint8_t * translate_shift(uint8_t * dst, m68kinst * inst, x86_ea *src_op, x86_ea
}
}
}
-
+
}
if (!special && end_off) {
*end_off = dst - (end_off + 1);
@@ -2952,7 +2957,9 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
case M68K_BCLR:
case M68K_BSET:
case M68K_BTST:
- dst = cycles(dst, inst->extra.size == OPSIZE_BYTE ? 4 : 6);
+ dst = cycles(dst, inst->extra.size == OPSIZE_BYTE ? 4 : (
+ inst->op == M68K_BTST ? 6 : (inst->op == M68K_BCLR ? 10 : 8))
+ );
if (src_op.mode == MODE_IMMED) {
if (inst->extra.size == OPSIZE_BYTE) {
src_op.disp &= 0x7;
@@ -3084,7 +3091,7 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
default:
isize = 2;
}
- uint8_t * passed = dst+1;
+ uint8_t * passed = dst+1;
dst = jcc(dst, CC_GE, dst+2);
dst = mov_ir(dst, 1, FLAG_N, SZ_B);
dst = mov_ir(dst, VECTOR_CHK, SCRATCH2, SZ_D);
@@ -3322,7 +3329,7 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
}
dst = call(dst, (uint8_t *)(inst->op == M68K_MOVE_SR ? set_sr : set_ccr));
dst = cycles(dst, 12);
-
+
}
break;
case M68K_MOVE_USP:
@@ -3446,7 +3453,7 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
dst = not_rdisp8(dst, dst_op.base, dst_op.disp, inst->extra.size);
dst = cmp_irdisp8(dst, 0, dst_op.base, dst_op.disp, inst->extra.size);
}
-
+
dst = mov_ir(dst, 0, FLAG_C, SZ_B);
dst = setcc_r(dst, CC_Z, FLAG_Z);
dst = setcc_r(dst, CC_S, FLAG_N);
@@ -3557,6 +3564,7 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
dst = cmp_ir(dst, 32, SCRATCH1, SZ_B);
norm_off = dst+1;
dst = jcc(dst, CC_L, dst+2);
+ dst = sub_ir(dst, 32, SCRATCH1, SZ_B);
if (dst_op.mode == MODE_REG_DIRECT) {
if (inst->op == M68K_ROL) {
dst = rol_ir(dst, 31, dst_op.base, inst->extra.size);
@@ -3574,7 +3582,6 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
dst = ror_irdisp8(dst, 1, dst_op.base, dst_op.disp, inst->extra.size);
}
}
- dst = sub_ir(dst, 32, SCRATCH1, SZ_B);
*norm_off = dst - (norm_off+1);
if (dst_op.mode == MODE_REG_DIRECT) {
if (inst->op == M68K_ROL) {
@@ -3781,8 +3788,38 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
}
dst = m68k_save_result(inst, dst, opts);
break;
- /*case M68K_STOP:
- break;*/
+ case M68K_STOP: {
+ //TODO: Trap if not in system mode
+ //manual says 4 cycles, but it has to be at least 8 since it's a 2-word instruction
+ //possibly even 12 since that's how long MOVE to SR takes
+ dst = cycles(dst, BUS*2);
+ dst = mov_ir(dst, src_op.disp & 0x1, FLAG_C, SZ_B);
+ dst = mov_ir(dst, (src_op.disp >> 1) & 0x1, FLAG_V, SZ_B);
+ dst = mov_ir(dst, (src_op.disp >> 2) & 0x1, FLAG_Z, SZ_B);
+ dst = mov_ir(dst, (src_op.disp >> 3) & 0x1, FLAG_N, SZ_B);
+ dst = mov_irind(dst, (src_op.disp >> 4) & 0x1, CONTEXT, SZ_B);
+ dst = mov_irdisp8(dst, (src_op.disp >> 8), CONTEXT, offsetof(m68k_context, status), SZ_B);
+ if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) {
+ //leave supervisor mode
+ dst = mov_rr(dst, opts->aregs[7], SCRATCH1, SZ_D);
+ dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, opts->aregs[7], SZ_D);
+ dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D);
+ }
+ uint8_t * loop_top = dst;
+ dst = call(dst, (uint8_t *)do_sync);
+ dst = cmp_rr(dst, LIMIT, CYCLES, SZ_D);
+ uint8_t * normal_cycle_up = dst + 1;
+ dst = jcc(dst, CC_A, dst+2);
+ dst = cycles(dst, BUS);
+ uint8_t * after_cycle_up = dst + 1;
+ dst = jmp(dst, dst+2);
+ *normal_cycle_up = dst - (normal_cycle_up + 1);
+ dst = mov_rr(dst, LIMIT, CYCLES, SZ_D);
+ *after_cycle_up = dst - (after_cycle_up+1);
+ dst = cmp_rdisp8r(dst, CONTEXT, offsetof(m68k_context, int_cycle), CYCLES, SZ_D);
+ dst = jcc(dst, CC_C, loop_top);
+ break;
+ }
case M68K_SUB:
size = inst->dst.addr_mode == MODE_AREG ? OPSIZE_LONG : inst->extra.size;
dst = cycles(dst, BUS);
@@ -3840,9 +3877,12 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
dst = cycles(dst, BUS);
if (src_op.mode == MODE_REG_DIRECT) {
dst = rol_ir(dst, 16, src_op.base, SZ_D);
+ dst = cmp_ir(dst, 0, src_op.base, SZ_D);
} else{
dst = rol_irdisp8(dst, 16, src_op.base, src_op.disp, SZ_D);
+ dst = cmp_irdisp8(dst, 0, src_op.base, src_op.disp, SZ_D);
}
+
dst = mov_ir(dst, 0, FLAG_C, SZ_B);
dst = setcc_r(dst, CC_Z, FLAG_Z);
dst = setcc_r(dst, CC_S, FLAG_N);
@@ -3912,7 +3952,7 @@ uint8_t * translate_m68k_stream(uint32_t address, m68k_context * context)
m68kinst instbuf;
x86_68k_options * opts = context->options;
uint8_t * dst = opts->cur_code;
- uint8_t * dst_end = opts->code_end;
+ uint8_t * dst_end = opts->code_end;
address &= 0xFFFFFF;
if(get_native_address(opts->native_code_map, address)) {
return dst;
@@ -4040,7 +4080,7 @@ void * m68k_retranslate_inst(uint32_t address, m68k_context * context)
return orig_start;
}
}
-
+
map_native_address(context, instbuf.address, dst, (after-inst)*2, MAX_NATIVE_SIZE);
opts->cur_code = dst+MAX_NATIVE_SIZE;
jmp(orig_start, dst);
@@ -4087,12 +4127,12 @@ void insert_breakpoint(m68k_context * context, uint32_t address, uint8_t * bp_ha
}
bp_stub = dst;
native = call(native, bp_stub);
-
+
//Calculate length of prologue
dst = check_cycles_int(dst, address, opts);
int check_int_size = dst-bp_stub;
dst = bp_stub;
-
+
//Save context and call breakpoint handler
dst = call(dst, (uint8_t *)m68k_save_context);
dst = push_r(dst, SCRATCH1);
@@ -4170,7 +4210,7 @@ uint8_t * gen_mem_fun(x86_68k_options * opts, memmap_chunk * memmap, uint32_t nu
ub_jcc = dst + 1;
dst = jcc(dst, CC_NC, dst+2);
}
-
+
if (memmap[chunk].mask != 0xFFFFFF) {
dst = and_ir(dst, memmap[chunk].mask, adr_reg, SZ_D);
}
@@ -4206,7 +4246,17 @@ uint8_t * gen_mem_fun(x86_68k_options * opts, memmap_chunk * memmap, uint32_t nu
dst = push_r(dst, CONTEXT);
dst = mov_rr(dst, SCRATCH1, RDI, SZ_D);
}
+ dst = test_ir(dst, 8, RSP, SZ_D);
+ uint8_t *adjust_rsp = dst+1;
+ dst = jcc(dst, CC_NZ, dst+2);
dst = call(dst, cfun);
+ uint8_t *no_adjust = dst+1;
+ dst = jmp(dst, dst+2);
+ *adjust_rsp = dst - (adjust_rsp + 1);
+ dst = sub_ir(dst, 8, RSP, SZ_Q);
+ dst = call(dst, cfun);
+ dst = add_ir(dst, 8, RSP, SZ_Q);
+ *no_adjust = dst - (no_adjust + 1);
if (is_write) {
dst = mov_rr(dst, RAX, CONTEXT, SZ_Q);
} else {
@@ -4214,7 +4264,7 @@ uint8_t * gen_mem_fun(x86_68k_options * opts, memmap_chunk * memmap, uint32_t nu
dst = mov_rr(dst, RAX, SCRATCH1, size);
}
dst = jmp(dst, (uint8_t *)m68k_load_context);
-
+
*not_null = dst - (not_null + 1);
}
if (size == SZ_B) {
@@ -4223,7 +4273,7 @@ uint8_t * gen_mem_fun(x86_68k_options * opts, memmap_chunk * memmap, uint32_t nu
dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, mem_pointers) + sizeof(void*) * memmap[chunk].ptr_index, adr_reg, SZ_Q);
if (is_write) {
dst = mov_rrind(dst, SCRATCH1, SCRATCH2, size);
-
+
} else {
dst = mov_rindr(dst, SCRATCH1, SCRATCH1, size);
}
@@ -4299,7 +4349,17 @@ uint8_t * gen_mem_fun(x86_68k_options * opts, memmap_chunk * memmap, uint32_t nu
dst = push_r(dst, CONTEXT);
dst = mov_rr(dst, SCRATCH1, RDI, SZ_D);
}
+ dst = test_ir(dst, 8, RSP, SZ_D);
+ uint8_t *adjust_rsp = dst+1;
+ dst = jcc(dst, CC_NZ, dst+2);
+ dst = call(dst, cfun);
+ uint8_t *no_adjust = dst+1;
+ dst = jmp(dst, dst+2);
+ *adjust_rsp = dst - (adjust_rsp + 1);
+ dst = sub_ir(dst, 8, RSP, SZ_Q);
dst = call(dst, cfun);
+ dst = add_ir(dst, 8, RSP, SZ_Q);
+ *no_adjust = dst - (no_adjust+1);
if (is_write) {
dst = mov_rr(dst, RAX, CONTEXT, SZ_Q);
} else {
@@ -4333,7 +4393,7 @@ uint8_t * gen_mem_fun(x86_68k_options * opts, memmap_chunk * memmap, uint32_t nu
void init_x86_68k_opts(x86_68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks)
{
- opts->flags = 0;
+ memset(opts, 0, sizeof(*opts));
for (int i = 0; i < 8; i++)
opts->dregs[i] = opts->aregs[i] = -1;
opts->dregs[0] = R10;
@@ -4352,14 +4412,14 @@ void init_x86_68k_opts(x86_68k_options * opts, memmap_chunk * memmap, uint32_t n
opts->code_end = opts->cur_code + size;
opts->ram_inst_sizes = malloc(sizeof(uint8_t *) * 64);
memset(opts->ram_inst_sizes, 0, sizeof(uint8_t *) * 64);
-
+
opts->read_16 = gen_mem_fun(opts, memmap, num_chunks, READ_16);
opts->read_8 = gen_mem_fun(opts, memmap, num_chunks, READ_8);
opts->write_16 = gen_mem_fun(opts, memmap, num_chunks, WRITE_16);
opts->write_8 = gen_mem_fun(opts, memmap, num_chunks, WRITE_8);
-
+
uint8_t * dst = opts->cur_code;
-
+
opts->read_32 = dst;
dst = push_r(dst, SCRATCH1);
dst = call(dst, opts->read_16);
@@ -4373,7 +4433,7 @@ void init_x86_68k_opts(x86_68k_options * opts, memmap_chunk * memmap, uint32_t n
dst = shl_ir(dst, 16, SCRATCH2, SZ_D);
dst = or_rr(dst, SCRATCH2, SCRATCH1, SZ_D);
dst = retn(dst);
-
+
opts->write_32_lowfirst = dst;
dst = push_r(dst, SCRATCH2);
dst = push_r(dst, SCRATCH1);
@@ -4383,7 +4443,7 @@ void init_x86_68k_opts(x86_68k_options * opts, memmap_chunk * memmap, uint32_t n
dst = pop_r(dst, SCRATCH2);
dst = shr_ir(dst, 16, SCRATCH1, SZ_D);
dst = jmp(dst, opts->write_16);
-
+
opts->write_32_highfirst = dst;
dst = push_r(dst, SCRATCH1);
dst = push_r(dst, SCRATCH2);
@@ -4393,7 +4453,7 @@ void init_x86_68k_opts(x86_68k_options * opts, memmap_chunk * memmap, uint32_t n
dst = pop_r(dst, SCRATCH1);
dst = add_ir(dst, 2, SCRATCH2, SZ_D);
dst = jmp(dst, opts->write_16);
-
+
opts->handle_cycle_limit_int = dst;
dst = cmp_rdisp8r(dst, CONTEXT, offsetof(m68k_context, int_cycle), CYCLES, SZ_D);
uint8_t * do_int = dst+1;
@@ -4404,7 +4464,17 @@ void init_x86_68k_opts(x86_68k_options * opts, memmap_chunk * memmap, uint32_t n
dst = call(dst, (uint8_t *)m68k_save_context);
dst = mov_rr(dst, CONTEXT, RDI, SZ_Q);
dst = mov_rr(dst, SCRATCH1, RSI, SZ_D);
+ dst = test_ir(dst, 8, RSP, SZ_D);
+ uint8_t *adjust_rsp = dst+1;
+ dst = jcc(dst, CC_NZ, dst+2);
+ dst = call(dst, (uint8_t *)sync_components);
+ uint8_t *no_adjust = dst+1;
+ dst = jmp(dst, dst+2);
+ *adjust_rsp = dst - (adjust_rsp + 1);
+ dst = sub_ir(dst, 8, RSP, SZ_Q);
dst = call(dst, (uint8_t *)sync_components);
+ dst = add_ir(dst, 8, RSP, SZ_Q);
+ *no_adjust = dst - (no_adjust+1);
dst = mov_rr(dst, RAX, CONTEXT, SZ_Q);
dst = jmp(dst, (uint8_t *)m68k_load_context);
*skip_sync = dst - (skip_sync+1);
@@ -4445,7 +4515,7 @@ void init_x86_68k_opts(x86_68k_options * opts, memmap_chunk * memmap, uint32_t n
//discard function return address
dst = pop_r(dst, SCRATCH2);
dst = jmp_r(dst, SCRATCH1);
-
+
opts->trap = dst;
dst = push_r(dst, SCRATCH2);
//swap USP and SSP if not already in supervisor mode
@@ -4474,7 +4544,7 @@ void init_x86_68k_opts(x86_68k_options * opts, memmap_chunk * memmap, uint32_t n
dst = call(dst, (uint8_t *)m68k_native_addr_and_sync);
dst = cycles(dst, 18);
dst = jmp_r(dst, SCRATCH1);
-
+
opts->cur_code = dst;
}