# HG changeset patch # User Michael Pavone # Date 1394242949 28800 # Node ID c05fcbfe1b1aaff0d4a96fea9167fcc06d0ec031 # Parent 9f40aa5243c248e4a172d0891ecca31cdb2b653e Refactored translate_m68k so that it contains no host-cpu specific code and moved it to m68k_core.c diff -r 9f40aa5243c2 -r c05fcbfe1b1a backend.h --- a/backend.h Wed Mar 05 19:26:53 2014 -0800 +++ b/backend.h Fri Mar 07 17:42:29 2014 -0800 @@ -13,13 +13,20 @@ #define INVALID_OFFSET 0xFFFFFFFF #define EXTENSION_WORD 0xFFFFFFFE +#if defined(X86_32) || defined(X86_64) typedef struct { int32_t disp; uint8_t mode; uint8_t base; uint8_t index; - uint8_t cycles; -} x86_ea; +} host_ea; +#else +typedef struct { + int32_t disp; + uint8_t mode; + uint8_t base; +} host_ea; +#endif typedef struct { uint8_t *base; diff -r 9f40aa5243c2 -r c05fcbfe1b1a m68k_core.c --- a/m68k_core.c Wed Mar 05 19:26:53 2014 -0800 +++ b/m68k_core.c Fri Mar 07 17:42:29 2014 -0800 @@ -326,6 +326,34 @@ jmp(code, opts->trap); } +void translate_m68k_move_usp(m68k_options *opts, m68kinst *inst) +{ + cycles(&opts->gen, BUS); + int8_t reg; + if (inst->src.addr_mode == MODE_UNUSED) { + reg = native_reg(&inst->dst, opts); + if (reg < 0) { + reg = opts->gen.scratch1; + } + areg_to_native(opts, 8, reg); + if (reg == opts->gen.scratch1) { + native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri); + } + } else { + reg = native_reg(&inst->src, opts); + if (reg < 0) { + reg = opts->gen.scratch1; + areg_to_native(opts, inst->src.params.regs.pri, reg); + } + native_to_areg(opts, reg, 8); + } +} + +void translate_m68k_nop(m68k_options *opts, m68kinst *inst) +{ + cycles(&opts->gen, BUS); +} + void swap_ssp_usp(m68k_options * opts) { areg_to_native(opts, 7, opts->gen.scratch2); @@ -435,6 +463,150 @@ } } +typedef enum { + RAW_FUNC = 1, + BINARY_ARITH, + UNARY_ARITH, + OP_FUNC +} impl_type; + +typedef void (*raw_fun)(m68k_options * opts, m68kinst *inst); +typedef void (*op_fun)(m68k_options * opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); + +typedef struct { + union { + raw_fun raw; + uint32_t flag_mask; + op_fun op; + } impl; + impl_type itype; +} impl_info; + +#define RAW_IMPL(inst, fun) [inst] = { .impl = { .raw = fun }, .itype = RAW_FUNC } +#define OP_IMPL(inst, fun) [inst] = { .impl = { .op = fun }, .itype = OP_FUNC } +#define UNARY_IMPL(inst, mask) [inst] = { .impl = { .flag_mask = mask }, .itype = UNARY_ARITH } +#define BINARY_IMPL(inst, mask) [inst] = { .impl = { .flag_mask = mask}, .itype = BINARY_ARITH } + +impl_info m68k_impls[] = { + //math + BINARY_IMPL(M68K_ADD, X|N|Z|V|C), + BINARY_IMPL(M68K_SUB, X|N|Z|V|C), + //z flag is special cased for ADDX/SUBX + BINARY_IMPL(M68K_ADDX, X|N|V|C), + BINARY_IMPL(M68K_SUBX, X|N|V|C), + OP_IMPL(M68K_ABCD, translate_m68k_abcd_sbcd), + OP_IMPL(M68K_SBCD, translate_m68k_abcd_sbcd), + BINARY_IMPL(M68K_AND, N|Z|V0|C0), + BINARY_IMPL(M68K_EOR, N|Z|V0|C0), + BINARY_IMPL(M68K_OR, N|Z|V0|C0), + RAW_IMPL(M68K_CMP, translate_m68k_cmp), + OP_IMPL(M68K_DIVS, translate_m68k_div), + OP_IMPL(M68K_DIVU, translate_m68k_div), + OP_IMPL(M68K_MULS, translate_m68k_mul), + OP_IMPL(M68K_MULU, translate_m68k_mul), + RAW_IMPL(M68K_EXT, translate_m68k_ext), + UNARY_IMPL(M68K_NEG, X|N|Z|V|C), + OP_IMPL(M68K_NEGX, translate_m68k_negx), + UNARY_IMPL(M68K_NOT, X|N|Z|V|C), + UNARY_IMPL(M68K_TST, N|Z|V0|C0), + + //shift/rotate + OP_IMPL(M68K_ASL, translate_m68k_sl), + OP_IMPL(M68K_LSL, translate_m68k_sl), + OP_IMPL(M68K_ASR, translate_m68k_asr), + OP_IMPL(M68K_LSR, translate_m68k_lsr), + OP_IMPL(M68K_ROL, translate_m68k_rot), + OP_IMPL(M68K_ROR, translate_m68k_rot), + OP_IMPL(M68K_ROXL, translate_m68k_rot), + OP_IMPL(M68K_ROXR, translate_m68k_rot), + UNARY_IMPL(M68K_SWAP, N|Z|V0|C0), + + //bit + OP_IMPL(M68K_BCHG, translate_m68k_bit), + OP_IMPL(M68K_BCLR, translate_m68k_bit), + OP_IMPL(M68K_BSET, translate_m68k_bit), + OP_IMPL(M68K_BTST, translate_m68k_bit), + + //data movement + RAW_IMPL(M68K_MOVE, translate_m68k_move), + RAW_IMPL(M68K_MOVEM, translate_m68k_movem), + RAW_IMPL(M68K_MOVEP, translate_m68k_movep), + RAW_IMPL(M68K_MOVE_USP, translate_m68k_move_usp), + RAW_IMPL(M68K_LEA, translate_m68k_lea_pea), + RAW_IMPL(M68K_PEA, translate_m68k_lea_pea), + RAW_IMPL(M68K_CLR, translate_m68k_clr), + OP_IMPL(M68K_EXG, translate_m68k_exg), + RAW_IMPL(M68K_SCC, translate_m68k_scc), + + //function calls and branches + RAW_IMPL(M68K_BCC, translate_m68k_bcc), + RAW_IMPL(M68K_BSR, translate_m68k_bsr), + RAW_IMPL(M68K_DBCC, translate_m68k_dbcc), + RAW_IMPL(M68K_JMP, translate_m68k_jmp_jsr), + RAW_IMPL(M68K_JSR, translate_m68k_jmp_jsr), + RAW_IMPL(M68K_RTS, translate_m68k_rts), + RAW_IMPL(M68K_RTE, translate_m68k_rte), + RAW_IMPL(M68K_RTR, translate_m68k_rtr), + RAW_IMPL(M68K_LINK, translate_m68k_link), + RAW_IMPL(M68K_UNLK, translate_m68k_unlk), + + //SR/CCR stuff + RAW_IMPL(M68K_ANDI_CCR, translate_m68k_andi_ccr_sr), + RAW_IMPL(M68K_ANDI_SR, translate_m68k_andi_ccr_sr), + RAW_IMPL(M68K_EORI_CCR, translate_m68k_eori_ccr_sr), + RAW_IMPL(M68K_EORI_SR, translate_m68k_eori_ccr_sr), + RAW_IMPL(M68K_ORI_CCR, translate_m68k_ori_ccr_sr), + RAW_IMPL(M68K_ORI_SR, translate_m68k_ori_ccr_sr), + OP_IMPL(M68K_MOVE_CCR, translate_m68k_move_ccr_sr), + OP_IMPL(M68K_MOVE_SR, translate_m68k_move_ccr_sr), + OP_IMPL(M68K_MOVE_FROM_SR, translate_m68k_move_from_sr), + RAW_IMPL(M68K_STOP, translate_m68k_stop), + + //traps + OP_IMPL(M68K_CHK, translate_m68k_chk), + RAW_IMPL(M68K_TRAP, translate_m68k_trap), + RAW_IMPL(M68K_ILLEGAL, translate_m68k_illegal), + RAW_IMPL(M68K_INVALID, translate_m68k_invalid), + + //misc + RAW_IMPL(M68K_NOP, translate_m68k_nop), + RAW_IMPL(M68K_RESET, translate_m68k_reset), + + //currently unimplemented + //M68K_NBCD + //M68K_TAS + //M68K_TRAPV +}; + +void translate_m68k(m68k_options * opts, m68kinst * inst) +{ + check_cycles_int(&opts->gen, inst->address); + impl_info * info = m68k_impls + inst->op; + if (info->itype == RAW_FUNC) { + info->impl.raw(opts, inst); + return; + } + + host_ea src_op, dst_op; + if (inst->src.addr_mode != MODE_UNUSED) { + translate_m68k_op(inst, &src_op, opts, 0); + } + if (inst->dst.addr_mode != MODE_UNUSED) { + translate_m68k_op(inst, &dst_op, opts, 1); + } + if (info->itype == OP_FUNC) { + info->impl.op(opts, inst, &src_op, &dst_op); + } else if (info->itype == BINARY_ARITH) { + translate_m68k_arith(opts, inst, info->impl.flag_mask, &src_op, &dst_op); + } else if (info->itype == UNARY_ARITH) { + translate_m68k_unary(opts, inst, info->impl.flag_mask, inst->dst.addr_mode != MODE_UNUSED ? &dst_op : &src_op); + } else { + m68k_disasm(inst, disasm_buf); + printf("%X: %s\ninstruction %d not yet implemented\n", inst->address, disasm_buf, inst->op); + exit(1); + } +} + void translate_m68k_stream(uint32_t address, m68k_context * context) { m68kinst instbuf; diff -r 9f40aa5243c2 -r c05fcbfe1b1a m68k_core_x86.c --- a/m68k_core_x86.c Wed Mar 05 19:26:53 2014 -0800 +++ b/m68k_core_x86.c Fri Mar 07 17:42:29 2014 -0800 @@ -335,7 +335,7 @@ calc_index_disp8(opts, op, native_reg); } -void translate_m68k_op(m68kinst * inst, x86_ea * ea, m68k_options * opts, uint8_t dst) +void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8_t dst) { code_info *code = &opts->gen.code; m68k_op_info *op = dst ? &inst->dst : &inst->src; @@ -536,7 +536,7 @@ uint8_t dir = 0; int32_t offset; int32_t inc_amount, dec_amount; - x86_ea src; + host_ea src; translate_m68k_op(inst, &src, opts, 0); reg = native_reg(&(inst->dst), opts); @@ -851,7 +851,7 @@ xor_rr(code, reg, reg, inst->extra.size); return; } - x86_ea dst_op; + host_ea dst_op; //TODO: fix timing translate_m68k_op(inst, &dst_op, opts, 1); if (dst_op.mode == MODE_REG_DIRECT) { @@ -865,7 +865,7 @@ void translate_m68k_ext(m68k_options * opts, m68kinst * inst) { code_info *code = &opts->gen.code; - x86_ea dst_op; + host_ea dst_op; uint8_t dst_size = inst->extra.size; inst->extra.size--; translate_m68k_op(inst, &dst_op, opts, 1); @@ -953,7 +953,7 @@ { code_info *code = &opts->gen.code; uint8_t cond = inst->extra.cond; - x86_ea dst_op; + host_ea dst_op; inst->extra.size = OPSIZE_BYTE; translate_m68k_op(inst, &dst_op, opts, 1); if (cond == COND_TRUE || cond == COND_FALSE) { @@ -1127,7 +1127,7 @@ typedef void (*shift_clr_t)(code_info *code, uint8_t dst, uint8_t size); typedef void (*shift_clrdisp_t)(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size); -void translate_shift(m68k_options * opts, m68kinst * inst, x86_ea *src_op, x86_ea * dst_op, shift_ir_t shift_ir, shift_irdisp_t shift_irdisp, shift_clr_t shift_clr, shift_clrdisp_t shift_clrdisp, shift_ir_t special, shift_irdisp_t special_disp) +void translate_shift(m68k_options * opts, m68kinst * inst, host_ea *src_op, host_ea * dst_op, shift_ir_t shift_ir, shift_irdisp_t shift_irdisp, shift_clr_t shift_clr, shift_clrdisp_t shift_clrdisp, shift_ir_t special, shift_irdisp_t special_disp) { code_info *code = &opts->gen.code; code_ptr end_off = NULL; @@ -1304,6 +1304,7 @@ case M68K_BSET: bts_ir(code, val, dst, size); break; case M68K_BCLR: btr_ir(code, val, dst, size); break; case M68K_BCHG: btc_ir(code, val, dst, size); break; + case M68K_CMP: cmp_ir(code, val, dst, size); break; case M68K_EOR: xor_ir(code, val, dst, size); break; case M68K_OR: or_ir(code, val, dst, size); break; case M68K_ROL: rol_ir(code, val, dst, size); break; @@ -1326,6 +1327,7 @@ case M68K_BSET: bts_irdisp(code, val, dst, disp, size); break; case M68K_BCLR: btr_irdisp(code, val, dst, disp, size); break; case M68K_BCHG: btc_irdisp(code, val, dst, disp, size); break; + case M68K_CMP: cmp_irdisp(code, val, dst, disp, size); break; case M68K_EOR: xor_irdisp(code, val, dst, disp, size); break; case M68K_OR: or_irdisp(code, val, dst, disp, size); break; case M68K_ROL: rol_irdisp(code, val, dst, disp, size); break; @@ -1348,6 +1350,7 @@ case M68K_BSET: bts_rr(code, src, dst, size); break; case M68K_BCLR: btr_rr(code, src, dst, size); break; case M68K_BCHG: btc_rr(code, src, dst, size); break; + case M68K_CMP: cmp_rr(code, src, dst, size); break; case M68K_EOR: xor_rr(code, src, dst, size); break; case M68K_OR: or_rr(code, src, dst, size); break; case M68K_SUB: sub_rr(code, src, dst, size); break; @@ -1366,6 +1369,7 @@ case M68K_BSET: bts_rrdisp(code, src, dst, disp, size); break; case M68K_BCLR: btr_rrdisp(code, src, dst, disp, size); break; case M68K_BCHG: btc_rrdisp(code, src, dst, disp, size); break; + case M68K_CMP: cmp_rrdisp(code, src, dst, disp, size); break; case M68K_EOR: xor_rrdisp(code, src, dst, disp, size); break; case M68K_OR: or_rrdisp(code, src, dst, disp, size); break; case M68K_SUB: sub_rrdisp(code, src, dst, disp, size); break; @@ -1380,6 +1384,7 @@ case M68K_ADD: add_rdispr(code, src, disp, dst, size); break; case M68K_ADDX: adc_rdispr(code, src, disp, dst, size); break; case M68K_AND: and_rdispr(code, src, disp, dst, size); break; + case M68K_CMP: cmp_rdispr(code, src, disp, dst, size); break; case M68K_EOR: xor_rdispr(code, src, disp, dst, size); break; case M68K_OR: or_rdispr(code, src, disp, dst, size); break; case M68K_SUB: sub_rdispr(code, src, disp, dst, size); break; @@ -1387,7 +1392,7 @@ } } -void translate_m68k_arith(m68k_options *opts, m68kinst * inst, uint32_t flag_mask, x86_ea *src_op, x86_ea *dst_op) +void translate_m68k_arith(m68k_options *opts, m68kinst * inst, uint32_t flag_mask, host_ea *src_op, host_ea *dst_op) { code_info *code = &opts->gen.code; cycles(&opts->gen, BUS); @@ -1429,7 +1434,7 @@ { code_info *code = &opts->gen.code; uint8_t size = inst->extra.size; - x86_ea src_op, dst_op; + host_ea src_op, dst_op; translate_m68k_op(inst, &src_op, opts, 0); if (inst->dst.addr_mode == MODE_AREG_POSTINC) { push_r(code, opts->gen.scratch1); @@ -1475,7 +1480,7 @@ } } -void translate_m68k_unary(m68k_options *opts, m68kinst *inst, uint32_t flag_mask, x86_ea *dst_op) +void translate_m68k_unary(m68k_options *opts, m68kinst *inst, uint32_t flag_mask, host_ea *dst_op) { code_info *code = &opts->gen.code; cycles(&opts->gen, BUS); @@ -1488,786 +1493,719 @@ m68k_save_result(inst, opts); } -#define BIT_SUPERVISOR 5 - -void translate_m68k(m68k_options * opts, m68kinst * inst) +void translate_m68k_invalid(m68k_options *opts, m68kinst *inst) { - code_ptr end_off, zero_off, norm_off; - uint8_t dst_reg; code_info *code = &opts->gen.code; - check_cycles_int(&opts->gen, inst->address); - if (inst->op == M68K_MOVE) { - return translate_m68k_move(opts, inst); - } else if(inst->op == M68K_LEA || inst->op == M68K_PEA) { - return translate_m68k_lea_pea(opts, inst); - } else if(inst->op == M68K_BSR) { - return translate_m68k_bsr(opts, inst); - } else if(inst->op == M68K_BCC) { - return translate_m68k_bcc(opts, inst); - } else if(inst->op == M68K_JMP) { - return translate_m68k_jmp_jsr(opts, inst); - } else if(inst->op == M68K_JSR) { - return translate_m68k_jmp_jsr(opts, inst); - } else if(inst->op == M68K_RTS) { - return translate_m68k_rts(opts, inst); - } else if(inst->op == M68K_DBCC) { - return translate_m68k_dbcc(opts, inst); - } else if(inst->op == M68K_CLR) { - return translate_m68k_clr(opts, inst); - } else if(inst->op == M68K_MOVEM) { - return translate_m68k_movem(opts, inst); - } else if(inst->op == M68K_LINK) { - return translate_m68k_link(opts, inst); - } else if(inst->op == M68K_UNLK) { - return translate_m68k_unlk(opts, inst); - } else if(inst->op == M68K_EXT) { - return translate_m68k_ext(opts, inst); - } else if(inst->op == M68K_SCC) { - return translate_m68k_scc(opts, inst); - } else if(inst->op == M68K_MOVEP) { - return translate_m68k_movep(opts, inst); - } else if(inst->op == M68K_INVALID) { - if (inst->src.params.immed == 0x7100) { - return retn(code); + if (inst->src.params.immed == 0x7100) { + retn(code); + return; + } + mov_ir(code, inst->address, opts->gen.scratch1, SZ_D); + call(code, (code_ptr)m68k_invalid); +} + +void translate_m68k_abcd_sbcd(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + code_info *code = &opts->gen.code; + if (src_op->base != opts->gen.scratch2) { + if (src_op->mode == MODE_REG_DIRECT) { + mov_rr(code, src_op->base, opts->gen.scratch2, SZ_B); + } else { + mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_B); } - mov_ir(code, inst->address, opts->gen.scratch1, SZ_D); - return call(code, (code_ptr)m68k_invalid); - } else if(inst->op == M68K_CMP) { - return translate_m68k_cmp(opts, inst); - } - x86_ea src_op, dst_op; - if (inst->src.addr_mode != MODE_UNUSED) { - translate_m68k_op(inst, &src_op, opts, 0); - } - if (inst->dst.addr_mode != MODE_UNUSED) { - translate_m68k_op(inst, &dst_op, opts, 1); } - uint8_t size; - switch(inst->op) - { - case M68K_ABCD: - case M68K_SBCD: - if (src_op.base != opts->gen.scratch2) { - if (src_op.mode == MODE_REG_DIRECT) { - mov_rr(code, src_op.base, opts->gen.scratch2, SZ_B); - } else { - mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, SZ_B); - } - } - if (dst_op.base != opts->gen.scratch1) { - if (dst_op.mode == MODE_REG_DIRECT) { - mov_rr(code, dst_op.base, opts->gen.scratch1, SZ_B); - } else { - mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, SZ_B); - } - } - flag_to_carry(opts, FLAG_X); - jcc(code, CC_NC, code->cur + 5); - if (inst->op == M68K_ABCD) { - add_ir(code, 1, opts->gen.scratch1, SZ_B); + if (dst_op->base != opts->gen.scratch1) { + if (dst_op->mode == MODE_REG_DIRECT) { + mov_rr(code, dst_op->base, opts->gen.scratch1, SZ_B); } else { - sub_ir(code, 1, opts->gen.scratch1, SZ_B); + mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch1, SZ_B); } - call(code, (code_ptr) (inst->op == M68K_ABCD ? bcd_add : bcd_sub)); - reg_to_flag(opts, CH, FLAG_C); - reg_to_flag(opts, CH, FLAG_X); - cmp_ir(code, 0, opts->gen.scratch1, SZ_B); - jcc(code, CC_Z, code->cur + 4); - set_flag(opts, 0, FLAG_Z); - if (dst_op.base != opts->gen.scratch1) { - if (dst_op.mode == MODE_REG_DIRECT) { - mov_rr(code, opts->gen.scratch1, dst_op.base, SZ_B); - } else { - mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_B); - } - } - m68k_save_result(inst, opts); - break; - case M68K_ADD: - case M68K_SUB: - translate_m68k_arith(opts, inst, X|N|Z|V|C, &src_op, &dst_op); - break; - case M68K_ADDX: - case M68K_SUBX: - //z flag is special cased in translate_m68k_arith - translate_m68k_arith(opts, inst, X|N|V|C, &src_op, &dst_op); - break; - case M68K_AND: - case M68K_EOR: - case M68K_OR: - translate_m68k_arith(opts, inst, N|Z|V0|C0, &src_op, &dst_op); - break; - case M68K_ANDI_CCR: - case M68K_ANDI_SR: { - cycles(&opts->gen, 20); - //TODO: If ANDI to SR, trap if not in supervisor mode - uint32_t flag_mask = 0; - if (!(inst->src.params.immed & 0x1)) { - flag_mask |= C0; - } - if (!(inst->src.params.immed & 0x2)) { - flag_mask |= V0; - } - if (!(inst->src.params.immed & 0x4)) { - flag_mask |= Z0; - } - if (!(inst->src.params.immed & 0x8)) { - flag_mask |= N0; - } - if (!(inst->src.params.immed & 0x10)) { - flag_mask |= X0; + } + flag_to_carry(opts, FLAG_X); + jcc(code, CC_NC, code->cur + 5); + if (inst->op == M68K_ABCD) { + add_ir(code, 1, opts->gen.scratch1, SZ_B); + } else { + sub_ir(code, 1, opts->gen.scratch1, SZ_B); + } + call(code, (code_ptr) (inst->op == M68K_ABCD ? bcd_add : bcd_sub)); + reg_to_flag(opts, CH, FLAG_C); + reg_to_flag(opts, CH, FLAG_X); + cmp_ir(code, 0, opts->gen.scratch1, SZ_B); + jcc(code, CC_Z, code->cur + 4); + set_flag(opts, 0, FLAG_Z); + if (dst_op->base != opts->gen.scratch1) { + if (dst_op->mode == MODE_REG_DIRECT) { + mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_B); + } else { + mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_B); } - update_flags(opts, flag_mask); - if (inst->op == M68K_ANDI_SR) { - and_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); - if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) { - //leave supervisor mode - swap_ssp_usp(opts); - } - if (inst->src.params.immed & 0x700) { - call(code, opts->do_sync); - } + } + m68k_save_result(inst, opts); +} + +void translate_m68k_sl(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + translate_shift(opts, inst, src_op, dst_op, shl_ir, shl_irdisp, shl_clr, shl_clrdisp, shr_ir, shr_irdisp); +} + +void translate_m68k_asr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + translate_shift(opts, inst, src_op, dst_op, sar_ir, sar_irdisp, sar_clr, sar_clrdisp, NULL, NULL); +} + +void translate_m68k_lsr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + translate_shift(opts, inst, src_op, dst_op, shr_ir, shr_irdisp, shr_clr, shr_clrdisp, shl_ir, shl_irdisp); +} + +void translate_m68k_bit(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + code_info *code = &opts->gen.code; + cycles(&opts->gen, 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; } - break; - } - case M68K_ASL: - case M68K_LSL: - translate_shift(opts, inst, &src_op, &dst_op, shl_ir, shl_irdisp, shl_clr, shl_clrdisp, shr_ir, shr_irdisp); - break; - case M68K_ASR: - translate_shift(opts, inst, &src_op, &dst_op, sar_ir, sar_irdisp, sar_clr, sar_clrdisp, NULL, NULL); - break; - case M68K_LSR: - translate_shift(opts, inst, &src_op, &dst_op, shr_ir, shr_irdisp, shr_clr, shr_clrdisp, shl_ir, shl_irdisp); - break; - case M68K_BCHG: - case M68K_BCLR: - case M68K_BSET: - case M68K_BTST: - cycles(&opts->gen, 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; - } - if (dst_op.mode == MODE_REG_DIRECT) { - op_ir(code, inst, src_op.disp, dst_op.base, inst->extra.size); - } else { - op_irdisp(code, inst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); - } + if (dst_op->mode == MODE_REG_DIRECT) { + op_ir(code, inst, src_op->disp, dst_op->base, inst->extra.size); } else { - if (src_op.mode == MODE_REG_DISPLACE8 || (inst->dst.addr_mode != MODE_REG && src_op.base != opts->gen.scratch1 && src_op.base != opts->gen.scratch2)) { - if (dst_op.base == opts->gen.scratch1) { - push_r(code, opts->gen.scratch2); - if (src_op.mode == MODE_REG_DIRECT) { - mov_rr(code, src_op.base, opts->gen.scratch2, SZ_B); - } else { - mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, SZ_B); - } - src_op.base = opts->gen.scratch2; + op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size); + } + } else { + if (src_op->mode == MODE_REG_DISPLACE8 || (inst->dst.addr_mode != MODE_REG && src_op->base != opts->gen.scratch1 && src_op->base != opts->gen.scratch2)) { + if (dst_op->base == opts->gen.scratch1) { + push_r(code, opts->gen.scratch2); + if (src_op->mode == MODE_REG_DIRECT) { + mov_rr(code, src_op->base, opts->gen.scratch2, SZ_B); } else { - if (src_op.mode == MODE_REG_DIRECT) { - mov_rr(code, src_op.base, opts->gen.scratch1, SZ_B); - } else { - mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_B); - } - src_op.base = opts->gen.scratch1; - } - } - uint8_t size = inst->extra.size; - if (dst_op.mode == MODE_REG_DISPLACE8) { - if (src_op.base != opts->gen.scratch1 && src_op.base != opts->gen.scratch2) { - if (src_op.mode == MODE_REG_DIRECT) { - mov_rr(code, src_op.base, opts->gen.scratch1, SZ_D); - } else { - mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_D); - src_op.mode = MODE_REG_DIRECT; - } - src_op.base = opts->gen.scratch1; + mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_B); } - //b### with register destination is modulo 32 - //x86 with a memory destination isn't modulo anything - //so use an and here to force the value to be modulo 32 - and_ir(code, 31, opts->gen.scratch1, SZ_D); - } else if(inst->dst.addr_mode != MODE_REG) { - //b### with memory destination is modulo 8 - //x86-64 doesn't support 8-bit bit operations - //so we fake it by forcing the bit number to be modulo 8 - and_ir(code, 7, src_op.base, SZ_D); - size = SZ_D; - } - if (dst_op.mode == MODE_REG_DIRECT) { - op_rr(code, inst, src_op.base, dst_op.base, size); + src_op->base = opts->gen.scratch2; } else { - op_rrdisp(code, inst, src_op.base, dst_op.base, dst_op.disp, size); - } - if (src_op.base == opts->gen.scratch2) { - pop_r(code, opts->gen.scratch2); - } - } - //x86 sets the carry flag to the value of the bit tested - //68K sets the zero flag to the complement of the bit tested - set_flag_cond(opts, CC_NC, FLAG_Z); - if (inst->op != M68K_BTST) { - m68k_save_result(inst, opts); - } - break; - case M68K_CHK: - { - cycles(&opts->gen, 6); - if (dst_op.mode == MODE_REG_DIRECT) { - cmp_ir(code, 0, dst_op.base, inst->extra.size); - } else { - cmp_irdisp(code, 0, dst_op.base, dst_op.disp, inst->extra.size); - } - uint32_t isize; - switch(inst->src.addr_mode) - { - case MODE_AREG_DISPLACE: - case MODE_AREG_INDEX_DISP8: - case MODE_ABSOLUTE_SHORT: - case MODE_PC_INDEX_DISP8: - case MODE_PC_DISPLACE: - case MODE_IMMEDIATE: - isize = 4; - break; - case MODE_ABSOLUTE: - isize = 6; - break; - default: - isize = 2; - } - //make sure we won't start a new chunk in the middle of these branches - check_alloc_code(code, MAX_INST_LEN * 11); - code_ptr passed = code->cur + 1; - jcc(code, CC_GE, code->cur + 2); - set_flag(opts, 1, FLAG_N); - mov_ir(code, VECTOR_CHK, opts->gen.scratch2, SZ_D); - mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D); - jmp(code, opts->trap); - *passed = code->cur - (passed+1); - if (dst_op.mode == MODE_REG_DIRECT) { - if (src_op.mode == MODE_REG_DIRECT) { - cmp_rr(code, src_op.base, dst_op.base, inst->extra.size); - } else if(src_op.mode == MODE_REG_DISPLACE8) { - cmp_rdispr(code, src_op.base, src_op.disp, dst_op.base, inst->extra.size); - } else { - cmp_ir(code, src_op.disp, dst_op.base, inst->extra.size); - } - } else if(dst_op.mode == MODE_REG_DISPLACE8) { - if (src_op.mode == MODE_REG_DIRECT) { - cmp_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, inst->extra.size); - } else { - cmp_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); + if (src_op->mode == MODE_REG_DIRECT) { + mov_rr(code, src_op->base, opts->gen.scratch1, SZ_B); + } else { + mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_B); + } + src_op->base = opts->gen.scratch1; } } - passed = code->cur + 1; - jcc(code, CC_LE, code->cur + 2); - set_flag(opts, 0, FLAG_N); - mov_ir(code, VECTOR_CHK, opts->gen.scratch2, SZ_D); - mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D); - jmp(code, opts->trap); - *passed = code->cur - (passed+1); - cycles(&opts->gen, 4); - break; - } - case M68K_DIVS: - case M68K_DIVU: - { - check_alloc_code(code, MAX_NATIVE_SIZE); - //TODO: cycle exact division - cycles(&opts->gen, inst->op == M68K_DIVS ? 158 : 140); - set_flag(opts, 0, FLAG_C); - push_r(code, RDX); - push_r(code, RAX); - if (dst_op.mode == MODE_REG_DIRECT) { - mov_rr(code, dst_op.base, RAX, SZ_D); - } else { - mov_rdispr(code, dst_op.base, dst_op.disp, RAX, SZ_D); - } - if (src_op.mode == MODE_IMMED) { - mov_ir(code, (src_op.disp & 0x8000) && inst->op == M68K_DIVS ? src_op.disp | 0xFFFF0000 : src_op.disp, opts->gen.scratch2, SZ_D); - } else if (src_op.mode == MODE_REG_DIRECT) { - if (inst->op == M68K_DIVS) { - movsx_rr(code, src_op.base, opts->gen.scratch2, SZ_W, SZ_D); - } else { - movzx_rr(code, src_op.base, opts->gen.scratch2, SZ_W, SZ_D); + uint8_t size = inst->extra.size; + if (dst_op->mode == MODE_REG_DISPLACE8) { + if (src_op->base != opts->gen.scratch1 && src_op->base != opts->gen.scratch2) { + if (src_op->mode == MODE_REG_DIRECT) { + mov_rr(code, src_op->base, opts->gen.scratch1, SZ_D); + } else { + mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_D); + src_op->mode = MODE_REG_DIRECT; + } + src_op->base = opts->gen.scratch1; } - } else if (src_op.mode == MODE_REG_DISPLACE8) { - if (inst->op == M68K_DIVS) { - movsx_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, SZ_W, SZ_D); - } else { - movzx_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, SZ_W, SZ_D); - } + //b### with register destination is modulo 32 + //x86 with a memory destination isn't modulo anything + //so use an and here to force the value to be modulo 32 + and_ir(code, 31, opts->gen.scratch1, SZ_D); + } else if(inst->dst.addr_mode != MODE_REG) { + //b### with memory destination is modulo 8 + //x86-64 doesn't support 8-bit bit operations + //so we fake it by forcing the bit number to be modulo 8 + and_ir(code, 7, src_op->base, SZ_D); + size = SZ_D; } - cmp_ir(code, 0, opts->gen.scratch2, SZ_D); - check_alloc_code(code, 6*MAX_INST_LEN); - code_ptr not_zero = code->cur + 1; - jcc(code, CC_NZ, code->cur + 2); - pop_r(code, RAX); - pop_r(code, RDX); - mov_ir(code, VECTOR_INT_DIV_ZERO, opts->gen.scratch2, SZ_D); - mov_ir(code, inst->address+2, opts->gen.scratch1, SZ_D); - jmp(code, opts->trap); - *not_zero = code->cur - (not_zero+1); - if (inst->op == M68K_DIVS) { - cdq(code); - } else { - xor_rr(code, RDX, RDX, SZ_D); - } - if (inst->op == M68K_DIVS) { - idiv_r(code, opts->gen.scratch2, SZ_D); - } else { - div_r(code, opts->gen.scratch2, SZ_D); - } - code_ptr skip_sec_check; - if (inst->op == M68K_DIVS) { - cmp_ir(code, 0x8000, RAX, SZ_D); - skip_sec_check = code->cur + 1; - jcc(code, CC_GE, code->cur + 2); - cmp_ir(code, -0x8000, RAX, SZ_D); - norm_off = code->cur + 1; - jcc(code, CC_L, code->cur + 2); + if (dst_op->mode == MODE_REG_DIRECT) { + op_rr(code, inst, src_op->base, dst_op->base, size); } else { - cmp_ir(code, 0x10000, RAX, SZ_D); - norm_off = code->cur + 1; - jcc(code, CC_NC, code->cur + 2); + op_rrdisp(code, inst, src_op->base, dst_op->base, dst_op->disp, size); } - if (dst_op.mode == MODE_REG_DIRECT) { - mov_rr(code, RDX, dst_op.base, SZ_W); - shl_ir(code, 16, dst_op.base, SZ_D); - mov_rr(code, RAX, dst_op.base, SZ_W); - } else { - mov_rrdisp(code, RDX, dst_op.base, dst_op.disp, SZ_W); - shl_irdisp(code, 16, dst_op.base, dst_op.disp, SZ_D); - mov_rrdisp(code, RAX, dst_op.base, dst_op.disp, SZ_W); + if (src_op->base == opts->gen.scratch2) { + pop_r(code, opts->gen.scratch2); } - cmp_ir(code, 0, RAX, SZ_W); - pop_r(code, RAX); - pop_r(code, RDX); - set_flag(opts, 0, FLAG_V); - set_flag_cond(opts, CC_Z, FLAG_Z); - set_flag_cond(opts, CC_S, FLAG_N); - end_off = code->cur + 1; - jmp(code, code->cur + 2); - *norm_off = code->cur - (norm_off + 1); - if (inst->op == M68K_DIVS) { - *skip_sec_check = code->cur - (skip_sec_check+1); - } - pop_r(code, RAX); - pop_r(code, RDX); - set_flag(opts, 1, FLAG_V); - *end_off = code->cur - (end_off + 1); + } + //x86 sets the carry flag to the value of the bit tested + //68K sets the zero flag to the complement of the bit tested + set_flag_cond(opts, CC_NC, FLAG_Z); + if (inst->op != M68K_BTST) { + m68k_save_result(inst, opts); + } +} + +void translate_m68k_chk(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + code_info *code = &opts->gen.code; + cycles(&opts->gen, 6); + if (dst_op->mode == MODE_REG_DIRECT) { + cmp_ir(code, 0, dst_op->base, inst->extra.size); + } else { + cmp_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size); + } + uint32_t isize; + switch(inst->src.addr_mode) + { + case MODE_AREG_DISPLACE: + case MODE_AREG_INDEX_DISP8: + case MODE_ABSOLUTE_SHORT: + case MODE_PC_INDEX_DISP8: + case MODE_PC_DISPLACE: + case MODE_IMMEDIATE: + isize = 4; break; + case MODE_ABSOLUTE: + isize = 6; + break; + default: + isize = 2; } - case M68K_EORI_CCR: - case M68K_EORI_SR: - cycles(&opts->gen, 20); - //TODO: If ANDI to SR, trap if not in supervisor mode - if (inst->src.params.immed & 0x1) { - xor_flag(opts, 1, FLAG_C); + //make sure we won't start a new chunk in the middle of these branches + check_alloc_code(code, MAX_INST_LEN * 11); + code_ptr passed = code->cur + 1; + jcc(code, CC_GE, code->cur + 2); + set_flag(opts, 1, FLAG_N); + mov_ir(code, VECTOR_CHK, opts->gen.scratch2, SZ_D); + mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D); + jmp(code, opts->trap); + *passed = code->cur - (passed+1); + if (dst_op->mode == MODE_REG_DIRECT) { + if (src_op->mode == MODE_REG_DIRECT) { + cmp_rr(code, src_op->base, dst_op->base, inst->extra.size); + } else if(src_op->mode == MODE_REG_DISPLACE8) { + cmp_rdispr(code, src_op->base, src_op->disp, dst_op->base, inst->extra.size); + } else { + cmp_ir(code, src_op->disp, dst_op->base, inst->extra.size); } - if (inst->src.params.immed & 0x2) { - xor_flag(opts, 1, FLAG_V); - } - if (inst->src.params.immed & 0x4) { - xor_flag(opts, 1, FLAG_Z); - } - if (inst->src.params.immed & 0x8) { - xor_flag(opts, 1, FLAG_N); - } - if (inst->src.params.immed & 0x10) { - xor_flag(opts, 1, FLAG_X); + } else if(dst_op->mode == MODE_REG_DISPLACE8) { + if (src_op->mode == MODE_REG_DIRECT) { + cmp_rrdisp(code, src_op->base, dst_op->base, dst_op->disp, inst->extra.size); + } else { + cmp_irdisp(code, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size); } - if (inst->op == M68K_ORI_SR) { - xor_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); - if (inst->src.params.immed & 0x700) { - call(code, opts->do_sync); - } + } + passed = code->cur + 1; + jcc(code, CC_LE, code->cur + 2); + set_flag(opts, 0, FLAG_N); + mov_ir(code, VECTOR_CHK, opts->gen.scratch2, SZ_D); + mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D); + jmp(code, opts->trap); + *passed = code->cur - (passed+1); + cycles(&opts->gen, 4); +} + +void translate_m68k_div(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + code_info *code = &opts->gen.code; + check_alloc_code(code, MAX_NATIVE_SIZE); + //TODO: cycle exact division + cycles(&opts->gen, inst->op == M68K_DIVS ? 158 : 140); + set_flag(opts, 0, FLAG_C); + push_r(code, RDX); + push_r(code, RAX); + if (dst_op->mode == MODE_REG_DIRECT) { + mov_rr(code, dst_op->base, RAX, SZ_D); + } else { + mov_rdispr(code, dst_op->base, dst_op->disp, RAX, SZ_D); + } + if (src_op->mode == MODE_IMMED) { + mov_ir(code, (src_op->disp & 0x8000) && inst->op == M68K_DIVS ? src_op->disp | 0xFFFF0000 : src_op->disp, opts->gen.scratch2, SZ_D); + } else if (src_op->mode == MODE_REG_DIRECT) { + if (inst->op == M68K_DIVS) { + movsx_rr(code, src_op->base, opts->gen.scratch2, SZ_W, SZ_D); + } else { + movzx_rr(code, src_op->base, opts->gen.scratch2, SZ_W, SZ_D); } - break; - case M68K_EXG: - cycles(&opts->gen, 6); - if (dst_op.mode == MODE_REG_DIRECT) { - mov_rr(code, dst_op.base, opts->gen.scratch2, SZ_D); - if (src_op.mode == MODE_REG_DIRECT) { - mov_rr(code, src_op.base, dst_op.base, SZ_D); - mov_rr(code, opts->gen.scratch2, src_op.base, SZ_D); - } else { - mov_rdispr(code, src_op.base, src_op.disp, dst_op.base, SZ_D); - mov_rrdisp(code, opts->gen.scratch2, src_op.base, src_op.disp, SZ_D); - } + } else if (src_op->mode == MODE_REG_DISPLACE8) { + if (inst->op == M68K_DIVS) { + movsx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_W, SZ_D); } else { - mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, SZ_D); - if (src_op.mode == MODE_REG_DIRECT) { - mov_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, SZ_D); - mov_rr(code, opts->gen.scratch2, src_op.base, SZ_D); - } else { - mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_D); - mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_D); - mov_rrdisp(code, opts->gen.scratch2, src_op.base, src_op.disp, SZ_D); - } - } - break; - case M68K_ILLEGAL: - call(code, opts->gen.save_context); -#ifdef X86_64 - mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR); -#else - push_r(code, opts->gen.context_reg); -#endif - call(code, (code_ptr)print_regs_exit); - break; - case M68K_MOVE_FROM_SR: - //TODO: Trap if not in system mode - call(code, opts->get_sr); - if (dst_op.mode == MODE_REG_DIRECT) { - mov_rr(code, opts->gen.scratch1, dst_op.base, SZ_W); - } else { - mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_W); - } - m68k_save_result(inst, opts); - break; - case M68K_MOVE_CCR: - case M68K_MOVE_SR: - //TODO: Privilege check for MOVE to SR - if (src_op.mode == MODE_IMMED) { - uint32_t flag_mask = src_op.disp & 0x10 ? X1 : X0; - flag_mask |= src_op.disp & 0x8 ? N1 : N0; - flag_mask |= src_op.disp & 0x4 ? Z1 : Z0; - flag_mask |= src_op.disp & 0x2 ? V1 : V0; - flag_mask |= src_op.disp & 0x1 ? C1 : C0; - update_flags(opts, flag_mask); - if (inst->op == M68K_MOVE_SR) { - mov_irdisp(code, (src_op.disp >> 8), opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); - if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) { - //leave supervisor mode - mov_rr(code, opts->aregs[7], opts->gen.scratch1, SZ_D); - mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, opts->aregs[7], SZ_D); - mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D); - } - call(code, opts->do_sync); - } - cycles(&opts->gen, 12); - } else { - if (src_op.base != opts->gen.scratch1) { - if (src_op.mode == MODE_REG_DIRECT) { - mov_rr(code, src_op.base, opts->gen.scratch1, SZ_W); - } else { - mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_W); - } - } - call(code, inst->op == M68K_MOVE_SR ? opts->set_sr : opts->set_ccr); - cycles(&opts->gen, 12); - + movzx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_W, SZ_D); } - break; - case M68K_MOVE_USP: - cycles(&opts->gen, BUS); - //TODO: Trap if not in supervisor mode - //bt_irdisp(code, BIT_SUPERVISOR, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); - if (inst->src.addr_mode == MODE_UNUSED) { - areg_to_native(opts, 8, dst_op.mode == MODE_REG_DIRECT ? dst_op.base : opts->gen.scratch1); - if (dst_op.mode != MODE_REG_DIRECT) { - mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_D); - } + } + cmp_ir(code, 0, opts->gen.scratch2, SZ_D); + check_alloc_code(code, 6*MAX_INST_LEN); + code_ptr not_zero = code->cur + 1; + jcc(code, CC_NZ, code->cur + 2); + pop_r(code, RAX); + pop_r(code, RDX); + mov_ir(code, VECTOR_INT_DIV_ZERO, opts->gen.scratch2, SZ_D); + mov_ir(code, inst->address+2, opts->gen.scratch1, SZ_D); + jmp(code, opts->trap); + *not_zero = code->cur - (not_zero+1); + if (inst->op == M68K_DIVS) { + cdq(code); + } else { + xor_rr(code, RDX, RDX, SZ_D); + } + if (inst->op == M68K_DIVS) { + idiv_r(code, opts->gen.scratch2, SZ_D); + } else { + div_r(code, opts->gen.scratch2, SZ_D); + } + code_ptr skip_sec_check, norm_off; + if (inst->op == M68K_DIVS) { + cmp_ir(code, 0x8000, RAX, SZ_D); + skip_sec_check = code->cur + 1; + jcc(code, CC_GE, code->cur + 2); + cmp_ir(code, -0x8000, RAX, SZ_D); + norm_off = code->cur + 1; + jcc(code, CC_L, code->cur + 2); + } else { + cmp_ir(code, 0x10000, RAX, SZ_D); + norm_off = code->cur + 1; + jcc(code, CC_NC, code->cur + 2); + } + if (dst_op->mode == MODE_REG_DIRECT) { + mov_rr(code, RDX, dst_op->base, SZ_W); + shl_ir(code, 16, dst_op->base, SZ_D); + mov_rr(code, RAX, dst_op->base, SZ_W); + } else { + mov_rrdisp(code, RDX, dst_op->base, dst_op->disp, SZ_W); + shl_irdisp(code, 16, dst_op->base, dst_op->disp, SZ_D); + mov_rrdisp(code, RAX, dst_op->base, dst_op->disp, SZ_W); + } + cmp_ir(code, 0, RAX, SZ_W); + pop_r(code, RAX); + pop_r(code, RDX); + set_flag(opts, 0, FLAG_V); + set_flag_cond(opts, CC_Z, FLAG_Z); + set_flag_cond(opts, CC_S, FLAG_N); + code_ptr end_off = code->cur + 1; + jmp(code, code->cur + 2); + *norm_off = code->cur - (norm_off + 1); + if (inst->op == M68K_DIVS) { + *skip_sec_check = code->cur - (skip_sec_check+1); + } + pop_r(code, RAX); + pop_r(code, RDX); + set_flag(opts, 1, FLAG_V); + *end_off = code->cur - (end_off + 1); +} + +void translate_m68k_exg(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + code_info *code = &opts->gen.code; + cycles(&opts->gen, 6); + if (dst_op->mode == MODE_REG_DIRECT) { + mov_rr(code, dst_op->base, opts->gen.scratch2, SZ_D); + if (src_op->mode == MODE_REG_DIRECT) { + mov_rr(code, src_op->base, dst_op->base, SZ_D); + mov_rr(code, opts->gen.scratch2, src_op->base, SZ_D); } else { - if (src_op.mode != MODE_REG_DIRECT) { - mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_D); - src_op.base = opts->gen.scratch1; - } - native_to_areg(opts, src_op.base, 8); - } - break; - //case M68K_MOVEP: - case M68K_MULS: - case M68K_MULU: - cycles(&opts->gen, 70); //TODO: Calculate the actual value based on the value of the parameter - if (src_op.mode == MODE_IMMED) { - mov_ir(code, inst->op == M68K_MULU ? (src_op.disp & 0xFFFF) : ((src_op.disp & 0x8000) ? src_op.disp | 0xFFFF0000 : src_op.disp), opts->gen.scratch1, SZ_D); - } else if (src_op.mode == MODE_REG_DIRECT) { - if (inst->op == M68K_MULS) { - movsx_rr(code, src_op.base, opts->gen.scratch1, SZ_W, SZ_D); - } else { - movzx_rr(code, src_op.base, opts->gen.scratch1, SZ_W, SZ_D); - } - } else { - if (inst->op == M68K_MULS) { - movsx_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_W, SZ_D); - } else { - movzx_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_W, SZ_D); - } + mov_rdispr(code, src_op->base, src_op->disp, dst_op->base, SZ_D); + mov_rrdisp(code, opts->gen.scratch2, src_op->base, src_op->disp, SZ_D); } - if (dst_op.mode == MODE_REG_DIRECT) { - dst_reg = dst_op.base; - if (inst->op == M68K_MULS) { - movsx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D); - } else { - movzx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D); - } + } else { + mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_D); + if (src_op->mode == MODE_REG_DIRECT) { + mov_rrdisp(code, src_op->base, dst_op->base, dst_op->disp, SZ_D); + mov_rr(code, opts->gen.scratch2, src_op->base, SZ_D); } else { - dst_reg = opts->gen.scratch2; - if (inst->op == M68K_MULS) { - movsx_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, SZ_W, SZ_D); - } else { - movzx_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, SZ_W, SZ_D); - } + mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_D); + mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_D); + mov_rrdisp(code, opts->gen.scratch2, src_op->base, src_op->disp, SZ_D); } - imul_rr(code, opts->gen.scratch1, dst_reg, SZ_D); - if (dst_op.mode == MODE_REG_DISPLACE8) { - mov_rrdisp(code, dst_reg, dst_op.base, dst_op.disp, SZ_D); + } +} + +void translate_m68k_mul(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + code_info *code = &opts->gen.code; + cycles(&opts->gen, 70); //TODO: Calculate the actual value based on the value of the parameter + if (src_op->mode == MODE_IMMED) { + mov_ir(code, inst->op == M68K_MULU ? (src_op->disp & 0xFFFF) : ((src_op->disp & 0x8000) ? src_op->disp | 0xFFFF0000 : src_op->disp), opts->gen.scratch1, SZ_D); + } else if (src_op->mode == MODE_REG_DIRECT) { + if (inst->op == M68K_MULS) { + movsx_rr(code, src_op->base, opts->gen.scratch1, SZ_W, SZ_D); + } else { + movzx_rr(code, src_op->base, opts->gen.scratch1, SZ_W, SZ_D); + } + } else { + if (inst->op == M68K_MULS) { + movsx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D); + } else { + movzx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D); } - cmp_ir(code, 0, dst_reg, SZ_D); - update_flags(opts, N|Z|V0|C0); - break; - //case M68K_NBCD: - case M68K_NEG: - translate_m68k_unary(opts, inst, X|N|Z|V|C, &dst_op); - break; - case M68K_NEGX: { - cycles(&opts->gen, BUS); - if (dst_op.mode == MODE_REG_DIRECT) { - if (dst_op.base == opts->gen.scratch1) { - push_r(code, opts->gen.scratch2); - xor_rr(code, opts->gen.scratch2, opts->gen.scratch2, inst->extra.size); - flag_to_carry(opts, FLAG_X); - sbb_rr(code, dst_op.base, opts->gen.scratch2, inst->extra.size); - mov_rr(code, opts->gen.scratch2, dst_op.base, inst->extra.size); - pop_r(code, opts->gen.scratch2); - } else { - xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, inst->extra.size); - flag_to_carry(opts, FLAG_X); - sbb_rr(code, dst_op.base, opts->gen.scratch1, inst->extra.size); - mov_rr(code, opts->gen.scratch1, dst_op.base, inst->extra.size); - } + } + uint8_t dst_reg; + if (dst_op->mode == MODE_REG_DIRECT) { + dst_reg = dst_op->base; + if (inst->op == M68K_MULS) { + movsx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D); + } else { + movzx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D); + } + } else { + dst_reg = opts->gen.scratch2; + if (inst->op == M68K_MULS) { + movsx_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_W, SZ_D); + } else { + movzx_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_W, SZ_D); + } + } + imul_rr(code, opts->gen.scratch1, dst_reg, SZ_D); + if (dst_op->mode == MODE_REG_DISPLACE8) { + mov_rrdisp(code, dst_reg, dst_op->base, dst_op->disp, SZ_D); + } + cmp_ir(code, 0, dst_reg, SZ_D); + update_flags(opts, N|Z|V0|C0); +} + +void translate_m68k_negx(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + code_info *code = &opts->gen.code; + cycles(&opts->gen, BUS); + if (dst_op->mode == MODE_REG_DIRECT) { + if (dst_op->base == opts->gen.scratch1) { + push_r(code, opts->gen.scratch2); + xor_rr(code, opts->gen.scratch2, opts->gen.scratch2, inst->extra.size); + flag_to_carry(opts, FLAG_X); + sbb_rr(code, dst_op->base, opts->gen.scratch2, inst->extra.size); + mov_rr(code, opts->gen.scratch2, dst_op->base, inst->extra.size); + pop_r(code, opts->gen.scratch2); } else { xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, inst->extra.size); flag_to_carry(opts, FLAG_X); - sbb_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, inst->extra.size); - mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, inst->extra.size); - } - set_flag_cond(opts, CC_C, FLAG_C); - code_ptr after_flag_set = code->cur + 1; - jcc(code, CC_Z, code->cur + 2); - set_flag(opts, 0, FLAG_Z); - *after_flag_set = code->cur - (after_flag_set+1); - set_flag_cond(opts, CC_S, FLAG_N); - set_flag_cond(opts, CC_O, FLAG_V); - if (opts->flag_regs[FLAG_C] >= 0) { - flag_to_flag(opts, FLAG_C, FLAG_X); - } else { - set_flag_cond(opts, CC_C, FLAG_X); - } - m68k_save_result(inst, opts); - break; - } - case M68K_NOP: - cycles(&opts->gen, BUS); - break; - case M68K_NOT: - translate_m68k_unary(opts, inst, N|Z|V0|C0, &dst_op); - break; - case M68K_ORI_CCR: - case M68K_ORI_SR: - cycles(&opts->gen, 20); - //TODO: If ORI to SR, trap if not in supervisor mode - uint32_t flag_mask = 0; - if (inst->src.params.immed & 0x1) { - flag_mask |= C1; - } - if (inst->src.params.immed & 0x2) { - flag_mask |= V1; + sbb_rr(code, dst_op->base, opts->gen.scratch1, inst->extra.size); + mov_rr(code, opts->gen.scratch1, dst_op->base, inst->extra.size); } - if (inst->src.params.immed & 0x4) { - flag_mask |= Z1; - } - if (inst->src.params.immed & 0x8) { - flag_mask |= N1; - } - if (inst->src.params.immed & 0x10) { - flag_mask |= X1; - } - update_flags(opts, flag_mask); - if (inst->op == M68K_ORI_SR) { - or_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); - if (inst->src.params.immed & 0x700) { - call(code, opts->do_sync); - } + } else { + xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, inst->extra.size); + flag_to_carry(opts, FLAG_X); + sbb_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch1, inst->extra.size); + mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, inst->extra.size); + } + set_flag_cond(opts, CC_C, FLAG_C); + code_ptr after_flag_set = code->cur + 1; + jcc(code, CC_Z, code->cur + 2); + set_flag(opts, 0, FLAG_Z); + *after_flag_set = code->cur - (after_flag_set+1); + set_flag_cond(opts, CC_S, FLAG_N); + set_flag_cond(opts, CC_O, FLAG_V); + if (opts->flag_regs[FLAG_C] >= 0) { + flag_to_flag(opts, FLAG_C, FLAG_X); + } else { + set_flag_cond(opts, CC_C, FLAG_X); + } + m68k_save_result(inst, opts); +} + +void translate_m68k_rot(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + code_info *code = &opts->gen.code; + int32_t init_flags = C|V0; + if (inst->src.addr_mode == MODE_UNUSED) { + cycles(&opts->gen, BUS); + //Memory rotate + if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { + flag_to_carry(opts, FLAG_X); + init_flags |= X; } - break; - case M68K_RESET: - call(code, opts->gen.save_context); -#ifdef X86_64 - mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR); -#else - push_r(code, opts->gen.context_reg); -#endif - call(code, (code_ptr)print_regs_exit); - break; - case M68K_ROL: - case M68K_ROR: - case M68K_ROXL: - case M68K_ROXR: { - int32_t init_flags = C|V0; - if (inst->src.addr_mode == MODE_UNUSED) { - cycles(&opts->gen, BUS); - //Memory rotate + op_ir(code, inst, 1, dst_op->base, inst->extra.size); + update_flags(opts, init_flags); + cmp_ir(code, 0, dst_op->base, inst->extra.size); + update_flags(opts, Z|N); + m68k_save_result(inst, opts); + } else { + if (src_op->mode == MODE_IMMED) { + cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 8 : 6) + src_op->disp*2); if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { flag_to_carry(opts, FLAG_X); init_flags |= X; } - op_ir(code, inst, 1, dst_op.base, inst->extra.size); - update_flags(opts, init_flags); - cmp_ir(code, 0, dst_op.base, inst->extra.size); - update_flags(opts, Z|N); - m68k_save_result(inst, opts); - } else { - if (src_op.mode == MODE_IMMED) { - cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 8 : 6) + src_op.disp*2); - if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { - flag_to_carry(opts, FLAG_X); - init_flags |= X; - } - if (dst_op.mode == MODE_REG_DIRECT) { - op_ir(code, inst, src_op.disp, dst_op.base, inst->extra.size); - } else { - op_irdisp(code, inst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); - } - update_flags(opts, init_flags); + if (dst_op->mode == MODE_REG_DIRECT) { + op_ir(code, inst, src_op->disp, dst_op->base, inst->extra.size); } else { - if (src_op.mode == MODE_REG_DIRECT) { - if (src_op.base != opts->gen.scratch1) { - mov_rr(code, src_op.base, opts->gen.scratch1, SZ_B); - } - } else { - mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_B); - } - and_ir(code, 63, opts->gen.scratch1, SZ_D); - zero_off = code->cur + 1; - jcc(code, CC_Z, code->cur + 2); - add_rr(code, opts->gen.scratch1, CYCLES, SZ_D); - add_rr(code, opts->gen.scratch1, CYCLES, SZ_D); - cmp_ir(code, 32, opts->gen.scratch1, SZ_B); - norm_off = code->cur + 1; - jcc(code, CC_L, code->cur + 2); - if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { - flag_to_carry(opts, FLAG_X); - init_flags |= X; - } else { - sub_ir(code, 32, opts->gen.scratch1, SZ_B); - } - if (dst_op.mode == MODE_REG_DIRECT) { - op_ir(code, inst, 31, dst_op.base, inst->extra.size); - op_ir(code, inst, 1, dst_op.base, inst->extra.size); - } else { - op_irdisp(code, inst, 31, dst_op.base, dst_op.disp, inst->extra.size); - op_irdisp(code, inst, 1, dst_op.base, dst_op.disp, inst->extra.size); - } - - if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { - set_flag_cond(opts, CC_C, FLAG_X); - sub_ir(code, 32, opts->gen.scratch1, SZ_B); - *norm_off = code->cur - (norm_off+1); - flag_to_carry(opts, FLAG_X); - } else { - *norm_off = code->cur - (norm_off+1); + op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size); + } + update_flags(opts, init_flags); + } else { + if (src_op->mode == MODE_REG_DIRECT) { + if (src_op->base != opts->gen.scratch1) { + mov_rr(code, src_op->base, opts->gen.scratch1, SZ_B); } - if (dst_op.mode == MODE_REG_DIRECT) { - op_r(code, inst, dst_op.base, inst->extra.size); - } else { - op_rdisp(code, inst, dst_op.base, dst_op.disp, inst->extra.size); - } - update_flags(opts, init_flags); - end_off = code->cur + 1; - jmp(code, code->cur + 2); - *zero_off = code->cur - (zero_off+1); - if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { - //Carry flag is set to X flag when count is 0, this is different from ROR/ROL - flag_to_flag(opts, FLAG_X, FLAG_C); - } else { - set_flag(opts, 0, FLAG_C); - } - *end_off = code->cur - (end_off+1); + } else { + mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_B); + } + and_ir(code, 63, opts->gen.scratch1, SZ_D); + code_ptr zero_off = code->cur + 1; + jcc(code, CC_Z, code->cur + 2); + add_rr(code, opts->gen.scratch1, CYCLES, SZ_D); + add_rr(code, opts->gen.scratch1, CYCLES, SZ_D); + cmp_ir(code, 32, opts->gen.scratch1, SZ_B); + code_ptr norm_off = code->cur + 1; + jcc(code, CC_L, code->cur + 2); + if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { + flag_to_carry(opts, FLAG_X); + init_flags |= X; + } else { + sub_ir(code, 32, opts->gen.scratch1, SZ_B); + } + if (dst_op->mode == MODE_REG_DIRECT) { + op_ir(code, inst, 31, dst_op->base, inst->extra.size); + op_ir(code, inst, 1, dst_op->base, inst->extra.size); + } else { + op_irdisp(code, inst, 31, dst_op->base, dst_op->disp, inst->extra.size); + op_irdisp(code, inst, 1, dst_op->base, dst_op->disp, inst->extra.size); } - if (dst_op.mode == MODE_REG_DIRECT) { - cmp_ir(code, 0, dst_op.base, inst->extra.size); + + if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { + set_flag_cond(opts, CC_C, FLAG_X); + sub_ir(code, 32, opts->gen.scratch1, SZ_B); + *norm_off = code->cur - (norm_off+1); + flag_to_carry(opts, FLAG_X); + } else { + *norm_off = code->cur - (norm_off+1); + } + if (dst_op->mode == MODE_REG_DIRECT) { + op_r(code, inst, dst_op->base, inst->extra.size); } else { - cmp_irdisp(code, 0, dst_op.base, dst_op.disp, inst->extra.size); + op_rdisp(code, inst, dst_op->base, dst_op->disp, inst->extra.size); } - update_flags(opts, Z|N); + update_flags(opts, init_flags); + code_ptr end_off = code->cur + 1; + jmp(code, code->cur + 2); + *zero_off = code->cur - (zero_off+1); + if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { + //Carry flag is set to X flag when count is 0, this is different from ROR/ROL + flag_to_flag(opts, FLAG_X, FLAG_C); + } else { + set_flag(opts, 0, FLAG_C); + } + *end_off = code->cur - (end_off+1); } - break; + if (dst_op->mode == MODE_REG_DIRECT) { + cmp_ir(code, 0, dst_op->base, inst->extra.size); + } else { + cmp_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size); + } + update_flags(opts, Z|N); } - case M68K_RTE: - //TODO: Trap if not in system mode - //Read saved SR - areg_to_native(opts, 7, opts->gen.scratch1); - call(code, opts->read_16); - addi_areg(opts, 2, 7); - call(code, opts->set_sr); - //Read saved PC - areg_to_native(opts, 7, opts->gen.scratch1); - call(code, opts->read_32); - addi_areg(opts, 4, 7); - //Check if we've switched to user mode and swap stack pointers if needed - bt_irdisp(code, 5, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); - end_off = code->cur + 1; - jcc(code, CC_C, code->cur + 2); - swap_ssp_usp(opts); - *end_off = code->cur - (end_off+1); - //Get native address, sync components, recalculate integer points and jump to returned address - call(code, opts->native_addr_and_sync); - jmp_r(code, opts->gen.scratch1); - break; - case M68K_RTR: - translate_m68k_rtr(opts, inst); - 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 - cycles(&opts->gen, BUS*2); - uint32_t flag_mask = src_op.disp & 0x10 ? X1 : X0; - flag_mask |= src_op.disp & 0x8 ? N1 : N0; - flag_mask |= src_op.disp & 0x4 ? Z1 : Z0; - flag_mask |= src_op.disp & 0x2 ? V1 : V0; - flag_mask |= src_op.disp & 0x1 ? C1 : C0; - update_flags(opts, flag_mask); - mov_irdisp(code, (src_op.disp >> 8), opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); +} + +void translate_m68k_illegal(m68k_options *opts, m68kinst *inst) +{ + code_info *code = &opts->gen.code; + call(code, opts->gen.save_context); +#ifdef X86_64 + mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR); +#else + push_r(code, opts->gen.context_reg); +#endif + call(code, (code_ptr)print_regs_exit); +} + +#define BIT_SUPERVISOR 5 + +void translate_m68k_andi_ccr_sr(m68k_options *opts, m68kinst *inst) +{ + code_info *code = &opts->gen.code; + cycles(&opts->gen, 20); + //TODO: If ANDI to SR, trap if not in supervisor mode + uint32_t flag_mask = 0; + if (!(inst->src.params.immed & 0x1)) { + flag_mask |= C0; + } + if (!(inst->src.params.immed & 0x2)) { + flag_mask |= V0; + } + if (!(inst->src.params.immed & 0x4)) { + flag_mask |= Z0; + } + if (!(inst->src.params.immed & 0x8)) { + flag_mask |= N0; + } + if (!(inst->src.params.immed & 0x10)) { + flag_mask |= X0; + } + update_flags(opts, flag_mask); + if (inst->op == M68K_ANDI_SR) { + and_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) { //leave supervisor mode swap_ssp_usp(opts); } - code_ptr loop_top = code->cur; - call(code, opts->do_sync); - cmp_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D); - code_ptr normal_cycle_up = code->cur + 1; - jcc(code, CC_A, code->cur + 2); - cycles(&opts->gen, BUS); - code_ptr after_cycle_up = code->cur + 1; - jmp(code, code->cur + 2); - *normal_cycle_up = code->cur - (normal_cycle_up + 1); - mov_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D); - *after_cycle_up = code->cur - (after_cycle_up+1); - cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), opts->gen.cycles, SZ_D); - jcc(code, CC_C, loop_top); - break; + if (inst->src.params.immed & 0x700) { + call(code, opts->do_sync); + } + } +} + +void translate_m68k_ori_ccr_sr(m68k_options *opts, m68kinst *inst) +{ + code_info *code = &opts->gen.code; + cycles(&opts->gen, 20); + //TODO: If ORI to SR, trap if not in supervisor mode + uint32_t flag_mask = 0; + if (inst->src.params.immed & 0x1) { + flag_mask |= C1; + } + if (inst->src.params.immed & 0x2) { + flag_mask |= V1; + } + if (inst->src.params.immed & 0x4) { + flag_mask |= Z1; + } + if (inst->src.params.immed & 0x8) { + flag_mask |= N1; + } + if (inst->src.params.immed & 0x10) { + flag_mask |= X1; + } + update_flags(opts, flag_mask); + if (inst->op == M68K_ORI_SR) { + or_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); + if (inst->src.params.immed & 0x700) { + call(code, opts->do_sync); + } + } +} + +void translate_m68k_eori_ccr_sr(m68k_options *opts, m68kinst *inst) +{ + code_info *code = &opts->gen.code; + cycles(&opts->gen, 20); + //TODO: If ANDI to SR, trap if not in supervisor mode + if (inst->src.params.immed & 0x1) { + xor_flag(opts, 1, FLAG_C); + } + if (inst->src.params.immed & 0x2) { + xor_flag(opts, 1, FLAG_V); + } + if (inst->src.params.immed & 0x4) { + xor_flag(opts, 1, FLAG_Z); + } + if (inst->src.params.immed & 0x8) { + xor_flag(opts, 1, FLAG_N); + } + if (inst->src.params.immed & 0x10) { + xor_flag(opts, 1, FLAG_X); + } + if (inst->op == M68K_ORI_SR) { + xor_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); + if (inst->src.params.immed & 0x700) { + call(code, opts->do_sync); + } } - //case M68K_TAS: - case M68K_TRAP: - translate_m68k_trap(opts, inst); - break; - //case M68K_TRAPV: - case M68K_TST: - case M68K_SWAP: - translate_m68k_unary(opts, inst, N|Z|V0|C0, &src_op); - break; - default: - m68k_disasm(inst, disasm_buf); - printf("%X: %s\ninstruction %d not yet implemented\n", inst->address, disasm_buf, inst->op); - exit(1); +} + +void translate_m68k_move_ccr_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + code_info *code = &opts->gen.code; + //TODO: Privilege check for MOVE to SR + if (src_op->mode == MODE_IMMED) { + uint32_t flag_mask = src_op->disp & 0x10 ? X1 : X0; + flag_mask |= src_op->disp & 0x8 ? N1 : N0; + flag_mask |= src_op->disp & 0x4 ? Z1 : Z0; + flag_mask |= src_op->disp & 0x2 ? V1 : V0; + flag_mask |= src_op->disp & 0x1 ? C1 : C0; + update_flags(opts, flag_mask); + if (inst->op == M68K_MOVE_SR) { + mov_irdisp(code, (src_op->disp >> 8), opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); + if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) { + //leave supervisor mode + mov_rr(code, opts->aregs[7], opts->gen.scratch1, SZ_D); + mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, opts->aregs[7], SZ_D); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D); + } + call(code, opts->do_sync); + } + cycles(&opts->gen, 12); + } else { + if (src_op->base != opts->gen.scratch1) { + if (src_op->mode == MODE_REG_DIRECT) { + mov_rr(code, src_op->base, opts->gen.scratch1, SZ_W); + } else { + mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W); + } + } + call(code, inst->op == M68K_MOVE_SR ? opts->set_sr : opts->set_ccr); + cycles(&opts->gen, 12); + + } +} + +void translate_m68k_stop(m68k_options *opts, m68kinst *inst) +{ + //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 + //On further thought prefetch + the fact that this stops the CPU may make + //Motorola's accounting make sense here + code_info *code = &opts->gen.code; + cycles(&opts->gen, BUS*2); + uint32_t flag_mask = inst->src.params.immed & 0x10 ? X1 : X0; + flag_mask |= inst->src.params.immed & 0x8 ? N1 : N0; + flag_mask |= inst->src.params.immed & 0x4 ? Z1 : Z0; + flag_mask |= inst->src.params.immed & 0x2 ? V1 : V0; + flag_mask |= inst->src.params.immed & 0x1 ? C1 : C0; + update_flags(opts, flag_mask); + mov_irdisp(code, (inst->src.params.immed >> 8), opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); + if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) { + //leave supervisor mode + swap_ssp_usp(opts); } + code_ptr loop_top = code->cur; + call(code, opts->do_sync); + cmp_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D); + code_ptr normal_cycle_up = code->cur + 1; + jcc(code, CC_A, code->cur + 2); + cycles(&opts->gen, BUS); + code_ptr after_cycle_up = code->cur + 1; + jmp(code, code->cur + 2); + *normal_cycle_up = code->cur - (normal_cycle_up + 1); + mov_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D); + *after_cycle_up = code->cur - (after_cycle_up+1); + cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), opts->gen.cycles, SZ_D); + jcc(code, CC_C, loop_top); +} + +void translate_m68k_move_from_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + code_info *code = &opts->gen.code; + //TODO: Trap if not in system mode + call(code, opts->get_sr); + if (dst_op->mode == MODE_REG_DIRECT) { + mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_W); + } else { + mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_W); + } + m68k_save_result(inst, opts); +} + +void translate_m68k_reset(m68k_options *opts, m68kinst *inst) +{ + code_info *code = &opts->gen.code; + call(code, opts->gen.save_context); +#ifdef X86_64 + mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR); +#else + push_r(code, opts->gen.context_reg); +#endif + call(code, (code_ptr)print_regs_exit); +} + +void translate_m68k_rte(m68k_options *opts, m68kinst *inst) +{ + code_info *code = &opts->gen.code; + //TODO: Trap if not in system mode + //Read saved SR + areg_to_native(opts, 7, opts->gen.scratch1); + call(code, opts->read_16); + addi_areg(opts, 2, 7); + call(code, opts->set_sr); + //Read saved PC + areg_to_native(opts, 7, opts->gen.scratch1); + call(code, opts->read_32); + addi_areg(opts, 4, 7); + //Check if we've switched to user mode and swap stack pointers if needed + bt_irdisp(code, 5, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); + code_ptr end_off = code->cur + 1; + jcc(code, CC_C, code->cur + 2); + swap_ssp_usp(opts); + *end_off = code->cur - (end_off+1); + //Get native address, sync components, recalculate integer points and jump to returned address + call(code, opts->native_addr_and_sync); + jmp_r(code, opts->gen.scratch1); } void translate_out_of_bounds(code_info *code) diff -r 9f40aa5243c2 -r c05fcbfe1b1a m68k_internal.h --- a/m68k_internal.h Wed Mar 05 19:26:53 2014 -0800 +++ b/m68k_internal.h Fri Mar 07 17:42:29 2014 -0800 @@ -32,6 +32,7 @@ size_t dreg_offset(uint8_t reg); size_t areg_offset(uint8_t reg); size_t reg_offset(m68k_op_info *op); +void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8_t dst); void print_regs_exit(m68k_context * context); void m68k_read_size(m68k_options *opts, uint8_t size); void m68k_write_size(m68k_options *opts, uint8_t size); @@ -49,11 +50,43 @@ void translate_m68k_lea_pea(m68k_options * opts, m68kinst * inst); void translate_m68k_bsr(m68k_options * opts, m68kinst * inst); void translate_m68k_jmp_jsr(m68k_options * opts, m68kinst * inst); +void translate_m68k_bcc(m68k_options * opts, m68kinst * inst); +void translate_m68k_scc(m68k_options * opts, m68kinst * inst); +void translate_m68k_dbcc(m68k_options * opts, m68kinst * inst); void translate_m68k_unlk(m68k_options * opts, m68kinst * inst); void translate_m68k_link(m68k_options * opts, m68kinst * inst); void translate_m68k_rts(m68k_options * opts, m68kinst * inst); void translate_m68k_rtr(m68k_options *opts, m68kinst * inst); void translate_m68k_trap(m68k_options *opts, m68kinst *inst); +void translate_m68k_move(m68k_options * opts, m68kinst * inst); +void translate_m68k_movep(m68k_options * opts, m68kinst * inst); +void translate_m68k_movem(m68k_options * opts, m68kinst * inst); +void translate_m68k_arith(m68k_options *opts, m68kinst * inst, uint32_t flag_mask, host_ea *src_op, host_ea *dst_op); +void translate_m68k_unary(m68k_options *opts, m68kinst *inst, uint32_t flag_mask, host_ea *dst_op); +void translate_m68k_invalid(m68k_options *opts, m68kinst *inst); +void translate_m68k_cmp(m68k_options * opts, m68kinst * inst); +void translate_m68k_clr(m68k_options * opts, m68kinst * inst); +void translate_m68k_ext(m68k_options * opts, m68kinst * inst); +void translate_m68k_abcd_sbcd(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_sl(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_asr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_lsr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_bit(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_chk(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_div(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_exg(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_mul(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_negx(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_rot(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_illegal(m68k_options *opts, m68kinst *inst); +void translate_m68k_andi_ccr_sr(m68k_options *opts, m68kinst *inst); +void translate_m68k_ori_ccr_sr(m68k_options *opts, m68kinst *inst); +void translate_m68k_eori_ccr_sr(m68k_options *opts, m68kinst *inst); +void translate_m68k_move_ccr_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_stop(m68k_options *opts, m68kinst *inst); +void translate_m68k_move_from_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_reset(m68k_options *opts, m68kinst *inst); +void translate_m68k_rte(m68k_options *opts, m68kinst *inst); //flag update bits #define X0 0x0001