pavone@467: /* pavone@467: Copyright 2013 Michael Pavone pavone@485: This file is part of BlastEm. pavone@467: BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. pavone@467: */ pavone@14: #include "gen_x86.h" pavone@569: #include "m68k_core.h" pavone@570: #include "m68k_internal.h" pavone@208: #include "68kinst.h" pavone@95: #include "mem.h" pavone@557: #include "backend.h" pavone@792: #include "util.h" pavone@18: #include pavone@18: #include pavone@18: #include pavone@18: #include pavone@14: pavone@546: enum { pavone@546: FLAG_X, pavone@546: FLAG_N, pavone@546: FLAG_Z, pavone@546: FLAG_V, pavone@546: FLAG_C pavone@546: }; pavone@14: pavone@569: void set_flag(m68k_options * opts, uint8_t val, uint8_t flag) pavone@14: { pavone@567: if (opts->flag_regs[flag] >= 0) { pavone@567: mov_ir(&opts->gen.code, val, opts->flag_regs[flag], SZ_B); pavone@567: } else { pavone@567: int8_t offset = offsetof(m68k_context, flags) + flag; pavone@567: if (offset) { pavone@567: mov_irdisp(&opts->gen.code, val, opts->gen.context_reg, offset, SZ_B); pavone@567: } else { pavone@567: mov_irind(&opts->gen.code, val, opts->gen.context_reg, SZ_B); pavone@567: } pavone@567: } pavone@14: } pavone@14: pavone@569: void set_flag_cond(m68k_options *opts, uint8_t cond, uint8_t flag) pavone@546: { pavone@546: if (opts->flag_regs[flag] >= 0) { pavone@567: setcc_r(&opts->gen.code, cond, opts->flag_regs[flag]); pavone@546: } else { pavone@546: int8_t offset = offsetof(m68k_context, flags) + flag; pavone@546: if (offset) { pavone@567: setcc_rdisp(&opts->gen.code, cond, opts->gen.context_reg, offset); pavone@546: } else { pavone@567: setcc_rind(&opts->gen.code, cond, opts->gen.context_reg); pavone@546: } pavone@546: } pavone@546: } pavone@546: pavone@569: void check_flag(m68k_options *opts, uint8_t flag) pavone@546: { pavone@546: if (opts->flag_regs[flag] >= 0) { pavone@567: cmp_ir(&opts->gen.code, 0, opts->flag_regs[flag], SZ_B); pavone@567: } else { pavone@567: cmp_irdisp(&opts->gen.code, 0, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, SZ_B); pavone@567: } pavone@567: } pavone@567: pavone@569: void flag_to_reg(m68k_options *opts, uint8_t flag, uint8_t reg) pavone@567: { pavone@567: if (opts->flag_regs[flag] >= 0) { pavone@567: mov_rr(&opts->gen.code, opts->flag_regs[flag], reg, SZ_B); pavone@546: } else { pavone@546: int8_t offset = offsetof(m68k_context, flags) + flag; pavone@546: if (offset) { pavone@567: mov_rdispr(&opts->gen.code, opts->gen.context_reg, offset, reg, SZ_B); pavone@546: } else { pavone@567: mov_rindr(&opts->gen.code, opts->gen.context_reg, reg, SZ_B); pavone@546: } pavone@546: } pavone@546: } pavone@546: pavone@569: void reg_to_flag(m68k_options *opts, uint8_t reg, uint8_t flag) pavone@546: { pavone@546: if (opts->flag_regs[flag] >= 0) { pavone@567: mov_rr(&opts->gen.code, reg, opts->flag_regs[flag], SZ_B); pavone@546: } else { pavone@546: int8_t offset = offsetof(m68k_context, flags) + flag; pavone@546: if (offset) { pavone@567: mov_rrdisp(&opts->gen.code, reg, opts->gen.context_reg, offset, SZ_B); pavone@546: } else { pavone@567: mov_rrind(&opts->gen.code, reg, opts->gen.context_reg, SZ_B); pavone@546: } pavone@546: } pavone@546: } pavone@546: pavone@569: void flag_to_flag(m68k_options *opts, uint8_t flag1, uint8_t flag2) pavone@567: { pavone@567: code_info *code = &opts->gen.code; pavone@567: if (opts->flag_regs[flag1] >= 0 && opts->flag_regs[flag2] >= 0) { pavone@567: mov_rr(code, opts->flag_regs[flag1], opts->flag_regs[flag2], SZ_B); pavone@567: } else if(opts->flag_regs[flag1] >= 0) { pavone@567: mov_rrdisp(code, opts->flag_regs[flag1], opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B); pavone@567: } else if (opts->flag_regs[flag2] >= 0) { pavone@567: mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag1, opts->flag_regs[flag2], SZ_B); pavone@567: } else { pavone@567: push_r(code, opts->gen.scratch1); pavone@567: mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag1, opts->gen.scratch1, SZ_B); pavone@567: mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B); pavone@567: pop_r(code, opts->gen.scratch1); pavone@567: } pavone@567: } pavone@567: pavone@576: void update_flags(m68k_options *opts, uint32_t update_mask) pavone@576: { pavone@576: uint8_t native_flags[] = {0, CC_S, CC_Z, CC_O, CC_C}; pavone@576: for (int8_t flag = FLAG_C; flag >= FLAG_X; --flag) pavone@576: { pavone@576: if (update_mask & X0 << (flag*3)) { pavone@576: set_flag(opts, 0, flag); pavone@576: } else if(update_mask & X1 << (flag*3)) { pavone@576: set_flag(opts, 1, flag); pavone@576: } else if(update_mask & X << (flag*3)) { pavone@576: if (flag == FLAG_X) { pavone@576: if (opts->flag_regs[FLAG_C] >= 0 || !(update_mask & (C0|C1|C))) { pavone@576: flag_to_flag(opts, FLAG_C, FLAG_X); pavone@576: } else if(update_mask & C0) { pavone@576: set_flag(opts, 0, flag); pavone@576: } else if(update_mask & C1) { pavone@576: set_flag(opts, 1, flag); pavone@576: } else { pavone@576: set_flag_cond(opts, CC_C, flag); pavone@576: } pavone@576: } else { pavone@576: set_flag_cond(opts, native_flags[flag], flag); pavone@576: } pavone@576: } pavone@576: } pavone@576: } pavone@576: pavone@569: void flag_to_carry(m68k_options * opts, uint8_t flag) pavone@546: { pavone@546: if (opts->flag_regs[flag] >= 0) { pavone@567: bt_ir(&opts->gen.code, 0, opts->flag_regs[flag], SZ_B); pavone@546: } else { pavone@567: bt_irdisp(&opts->gen.code, 0, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, SZ_B); pavone@546: } pavone@546: } pavone@546: pavone@569: void or_flag_to_reg(m68k_options *opts, uint8_t flag, uint8_t reg) pavone@546: { pavone@546: if (opts->flag_regs[flag] >= 0) { pavone@567: or_rr(&opts->gen.code, opts->flag_regs[flag], reg, SZ_B); pavone@546: } else { pavone@567: or_rdispr(&opts->gen.code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, reg, SZ_B); pavone@546: } pavone@546: } pavone@546: pavone@569: void xor_flag_to_reg(m68k_options *opts, uint8_t flag, uint8_t reg) pavone@546: { pavone@546: if (opts->flag_regs[flag] >= 0) { pavone@567: xor_rr(&opts->gen.code, opts->flag_regs[flag], reg, SZ_B); pavone@546: } else { pavone@567: xor_rdispr(&opts->gen.code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, reg, SZ_B); pavone@546: } pavone@546: } pavone@546: pavone@569: void xor_flag(m68k_options *opts, uint8_t val, uint8_t flag) pavone@546: { pavone@546: if (opts->flag_regs[flag] >= 0) { pavone@567: xor_ir(&opts->gen.code, val, opts->flag_regs[flag], SZ_B); pavone@546: } else { pavone@567: xor_irdisp(&opts->gen.code, val, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, SZ_B); pavone@546: } pavone@546: } pavone@546: pavone@569: void cmp_flags(m68k_options *opts, uint8_t flag1, uint8_t flag2) pavone@546: { pavone@567: code_info *code = &opts->gen.code; pavone@546: if (opts->flag_regs[flag1] >= 0 && opts->flag_regs[flag2] >= 0) { pavone@567: cmp_rr(code, opts->flag_regs[flag1], opts->flag_regs[flag2], SZ_B); pavone@546: } else if(opts->flag_regs[flag1] >= 0 || opts->flag_regs[flag2] >= 0) { pavone@546: if (opts->flag_regs[flag2] >= 0) { pavone@546: uint8_t tmp = flag1; pavone@546: flag1 = flag2; pavone@546: flag2 = tmp; pavone@546: } pavone@567: cmp_rrdisp(code, opts->flag_regs[flag1], opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B); pavone@546: } else { pavone@567: mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag1, opts->gen.scratch1, SZ_B); pavone@567: cmp_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B); pavone@546: } pavone@546: } pavone@546: pavone@574: void areg_to_native(m68k_options *opts, uint8_t reg, uint8_t native_reg) pavone@574: { pavone@574: if (opts->aregs[reg] >= 0) { pavone@574: mov_rr(&opts->gen.code, opts->aregs[reg], native_reg, SZ_D); pavone@574: } else { pavone@574: mov_rdispr(&opts->gen.code, opts->gen.context_reg, areg_offset(reg), native_reg, SZ_D); pavone@574: } pavone@574: } pavone@574: pavone@574: void dreg_to_native(m68k_options *opts, uint8_t reg, uint8_t native_reg) pavone@574: { pavone@574: if (opts->dregs[reg] >= 0) { pavone@574: mov_rr(&opts->gen.code, opts->dregs[reg], native_reg, SZ_D); pavone@574: } else { pavone@574: mov_rdispr(&opts->gen.code, opts->gen.context_reg, dreg_offset(reg), native_reg, SZ_D); pavone@574: } pavone@574: } pavone@574: pavone@574: void areg_to_native_sx(m68k_options *opts, uint8_t reg, uint8_t native_reg) pavone@574: { pavone@574: if (opts->aregs[reg] >= 0) { pavone@574: movsx_rr(&opts->gen.code, opts->aregs[reg], native_reg, SZ_W, SZ_D); pavone@574: } else { pavone@574: movsx_rdispr(&opts->gen.code, opts->gen.context_reg, areg_offset(reg), native_reg, SZ_W, SZ_D); pavone@574: } pavone@574: } pavone@574: pavone@574: void dreg_to_native_sx(m68k_options *opts, uint8_t reg, uint8_t native_reg) pavone@574: { pavone@574: if (opts->dregs[reg] >= 0) { pavone@574: movsx_rr(&opts->gen.code, opts->dregs[reg], native_reg, SZ_W, SZ_D); pavone@686: } else { pavone@574: movsx_rdispr(&opts->gen.code, opts->gen.context_reg, dreg_offset(reg), native_reg, SZ_W, SZ_D); pavone@574: } pavone@686: } pavone@574: pavone@574: void native_to_areg(m68k_options *opts, uint8_t native_reg, uint8_t reg) pavone@682: { pavone@574: if (opts->aregs[reg] >= 0) { pavone@574: mov_rr(&opts->gen.code, native_reg, opts->aregs[reg], SZ_D); pavone@686: } else { pavone@574: mov_rrdisp(&opts->gen.code, native_reg, opts->gen.context_reg, areg_offset(reg), SZ_D); pavone@686: } pavone@686: } pavone@574: pavone@574: void native_to_dreg(m68k_options *opts, uint8_t native_reg, uint8_t reg) pavone@574: { pavone@574: if (opts->dregs[reg] >= 0) { pavone@574: mov_rr(&opts->gen.code, native_reg, opts->dregs[reg], SZ_D); pavone@686: } else { pavone@574: mov_rrdisp(&opts->gen.code, native_reg, opts->gen.context_reg, dreg_offset(reg), SZ_D); pavone@686: } pavone@574: } pavone@574: pavone@574: void ldi_areg(m68k_options *opts, int32_t value, uint8_t reg) pavone@574: { pavone@574: if (opts->aregs[reg] >= 0) { pavone@574: mov_ir(&opts->gen.code, value, opts->aregs[reg], SZ_D); pavone@686: } else { pavone@574: mov_irdisp(&opts->gen.code, value, opts->gen.context_reg, areg_offset(reg), SZ_D); pavone@686: } pavone@574: } pavone@574: pavone@574: void ldi_native(m68k_options *opts, int32_t value, uint8_t reg) pavone@686: { pavone@574: mov_ir(&opts->gen.code, value, reg, SZ_D); pavone@686: } pavone@574: pavone@588: void addi_native(m68k_options *opts, int32_t value, uint8_t reg) pavone@588: { pavone@588: add_ir(&opts->gen.code, value, reg, SZ_D); pavone@682: } pavone@588: pavone@588: void subi_native(m68k_options *opts, int32_t value, uint8_t reg) pavone@588: { pavone@588: sub_ir(&opts->gen.code, value, reg, SZ_D); pavone@686: } pavone@588: pavone@588: void push_native(m68k_options *opts, uint8_t reg) pavone@588: { pavone@588: push_r(&opts->gen.code, reg); pavone@686: } pavone@588: pavone@588: void pop_native(m68k_options *opts, uint8_t reg) pavone@686: { pavone@588: pop_r(&opts->gen.code, reg); pavone@686: } pavone@588: pavone@588: void sign_extend16_native(m68k_options *opts, uint8_t reg) pavone@588: { pavone@588: movsx_rr(&opts->gen.code, reg, reg, SZ_W, SZ_D); pavone@686: } pavone@588: pavone@574: void addi_areg(m68k_options *opts, int32_t val, uint8_t reg) pavone@574: { pavone@574: if (opts->aregs[reg] >= 0) { pavone@574: add_ir(&opts->gen.code, val, opts->aregs[reg], SZ_D); pavone@686: } else { pavone@574: add_irdisp(&opts->gen.code, val, opts->gen.context_reg, areg_offset(reg), SZ_D); pavone@686: } pavone@574: } pavone@574: pavone@574: void subi_areg(m68k_options *opts, int32_t val, uint8_t reg) pavone@574: { pavone@574: if (opts->aregs[reg] >= 0) { pavone@574: sub_ir(&opts->gen.code, val, opts->aregs[reg], SZ_D); pavone@686: } else { pavone@574: sub_irdisp(&opts->gen.code, val, opts->gen.context_reg, areg_offset(reg), SZ_D); pavone@686: } pavone@686: } pavone@574: pavone@574: void add_areg_native(m68k_options *opts, uint8_t reg, uint8_t native_reg) pavone@574: { pavone@574: if (opts->aregs[reg] >= 0) { pavone@574: add_rr(&opts->gen.code, opts->aregs[reg], native_reg, SZ_D); pavone@686: } else { pavone@574: add_rdispr(&opts->gen.code, opts->gen.context_reg, areg_offset(reg), native_reg, SZ_D); pavone@686: } pavone@574: } pavone@574: pavone@574: void add_dreg_native(m68k_options *opts, uint8_t reg, uint8_t native_reg) pavone@574: { pavone@574: if (opts->dregs[reg] >= 0) { pavone@574: add_rr(&opts->gen.code, opts->dregs[reg], native_reg, SZ_D); pavone@686: } else { pavone@574: add_rdispr(&opts->gen.code, opts->gen.context_reg, dreg_offset(reg), native_reg, SZ_D); pavone@686: } pavone@686: } pavone@574: pavone@574: void calc_areg_displace(m68k_options *opts, m68k_op_info *op, uint8_t native_reg) pavone@686: { pavone@574: areg_to_native(opts, op->params.regs.pri, native_reg); pavone@751: add_ir(&opts->gen.code, op->params.regs.displacement & 0x8000 ? op->params.regs.displacement | 0xFFFF0000 : op->params.regs.displacement, native_reg, SZ_D); pavone@686: } pavone@574: pavone@574: void calc_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_reg) pavone@686: { pavone@574: uint8_t sec_reg = (op->params.regs.sec >> 1) & 0x7; pavone@574: if (op->params.regs.sec & 1) { pavone@574: if (op->params.regs.sec & 0x10) { pavone@574: add_areg_native(opts, sec_reg, native_reg); pavone@686: } else { pavone@574: add_dreg_native(opts, sec_reg, native_reg); pavone@686: } pavone@686: } else { pavone@574: uint8_t other_reg = native_reg == opts->gen.scratch1 ? opts->gen.scratch2 : opts->gen.scratch1; pavone@574: if (op->params.regs.sec & 0x10) { pavone@574: areg_to_native_sx(opts, sec_reg, other_reg); pavone@686: } else { pavone@574: dreg_to_native_sx(opts, sec_reg, other_reg); pavone@686: } pavone@574: add_rr(&opts->gen.code, other_reg, native_reg, SZ_D); pavone@686: } pavone@574: if (op->params.regs.displacement) { pavone@574: add_ir(&opts->gen.code, op->params.regs.displacement, native_reg, SZ_D); pavone@686: } pavone@686: } pavone@574: pavone@574: void calc_areg_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_reg) pavone@686: { pavone@574: areg_to_native(opts, op->params.regs.pri, native_reg); pavone@574: calc_index_disp8(opts, op, native_reg); pavone@574: } pavone@574: pavone@582: void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8_t dst) pavone@567: { pavone@567: code_info *code = &opts->gen.code; pavone@571: m68k_op_info *op = dst ? &inst->dst : &inst->src; pavone@571: int8_t reg = native_reg(op, opts); pavone@81: uint8_t sec_reg; pavone@682: int32_t dec_amount, inc_amount; pavone@14: if (reg >= 0) { pavone@18: ea->mode = MODE_REG_DIRECT; pavone@571: if (!dst && inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) { pavone@567: movsx_rr(code, reg, opts->gen.scratch1, SZ_W, SZ_D); pavone@567: ea->base = opts->gen.scratch1; pavone@181: } else { pavone@686: ea->base = reg; pavone@686: } pavone@567: return; pavone@14: } pavone@571: switch (op->addr_mode) pavone@18: { pavone@18: case MODE_REG: pavone@18: case MODE_AREG: pavone@18: //We only get one memory parameter, so if the dst operand is a register in memory, pavone@571: //we need to copy this to a temp register first if we're translating the src operand pavone@571: if (dst || native_reg(&(inst->dst), opts) >= 0 || inst->dst.addr_mode == MODE_UNUSED || !(inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG) pavone@18: || inst->op == M68K_EXG) { pavone@447: pavone@686: ea->mode = MODE_REG_DISPLACE8; pavone@567: ea->base = opts->gen.context_reg; pavone@571: ea->disp = reg_offset(op); pavone@18: } else { pavone@181: if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) { pavone@571: movsx_rdispr(code, opts->gen.context_reg, reg_offset(op), opts->gen.scratch1, SZ_W, SZ_D); pavone@181: } else { pavone@571: mov_rdispr(code, opts->gen.context_reg, reg_offset(op), opts->gen.scratch1, inst->extra.size); pavone@181: } pavone@18: ea->mode = MODE_REG_DIRECT; pavone@567: ea->base = opts->gen.scratch1; pavone@181: //we're explicitly handling the areg dest here, so we exit immediately pavone@567: return; pavone@18: } pavone@18: break; pavone@18: case MODE_AREG_PREDEC: pavone@571: if (dst && inst->src.addr_mode == MODE_AREG_PREDEC) { pavone@571: push_r(code, opts->gen.scratch1); pavone@571: } pavone@571: dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (op->params.regs.pri == 7 ? 2 :1)); pavone@571: if (!dst) { pavone@571: cycles(&opts->gen, PREDEC_PENALTY); pavone@571: } pavone@574: subi_areg(opts, dec_amount, op->params.regs.pri); pavone@18: case MODE_AREG_INDIRECT: pavone@447: case MODE_AREG_POSTINC: pavone@574: areg_to_native(opts, op->params.regs.pri, opts->gen.scratch1); pavone@567: m68k_read_size(opts, inst->extra.size); pavone@447: pavone@571: if (dst) { pavone@686: if (inst->src.addr_mode == MODE_AREG_PREDEC) { pavone@571: //restore src operand to opts->gen.scratch2 pavone@571: pop_r(code, opts->gen.scratch2); pavone@686: } else { pavone@571: //save reg value in opts->gen.scratch2 so we can use it to save the result in memory later pavone@574: areg_to_native(opts, op->params.regs.pri, opts->gen.scratch2); pavone@571: } pavone@571: } pavone@571: pavone@571: if (op->addr_mode == MODE_AREG_POSTINC) { pavone@571: inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (op->params.regs.pri == 7 ? 2 : 1)); pavone@574: addi_areg(opts, inc_amount, op->params.regs.pri); pavone@18: } pavone@18: ea->mode = MODE_REG_DIRECT; pavone@571: ea->base = (!dst && inst->dst.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) ? opts->gen.scratch2 : opts->gen.scratch1; pavone@18: break; pavone@71: case MODE_AREG_DISPLACE: pavone@567: cycles(&opts->gen, BUS); pavone@574: calc_areg_displace(opts, op, opts->gen.scratch1); pavone@571: if (dst) { pavone@571: push_r(code, opts->gen.scratch1); pavone@571: } pavone@567: m68k_read_size(opts, inst->extra.size); pavone@571: if (dst) { pavone@571: pop_r(code, opts->gen.scratch2); pavone@686: } pavone@567: pavone@71: ea->mode = MODE_REG_DIRECT; pavone@567: ea->base = opts->gen.scratch1; pavone@71: break; pavone@81: case MODE_AREG_INDEX_DISP8: pavone@567: cycles(&opts->gen, 6); pavone@574: calc_areg_index_disp8(opts, op, opts->gen.scratch1); pavone@571: if (dst) { pavone@571: push_r(code, opts->gen.scratch1); pavone@81: } pavone@567: m68k_read_size(opts, inst->extra.size); pavone@571: if (dst) { pavone@571: pop_r(code, opts->gen.scratch2); pavone@686: } pavone@567: pavone@54: ea->mode = MODE_REG_DIRECT; pavone@567: ea->base = opts->gen.scratch1; pavone@54: break; pavone@571: case MODE_PC_DISPLACE: pavone@571: cycles(&opts->gen, BUS); pavone@571: mov_ir(code, op->params.regs.displacement + inst->address+2, opts->gen.scratch1, SZ_D); pavone@571: if (dst) { pavone@567: push_r(code, opts->gen.scratch1); pavone@686: } pavone@571: m68k_read_size(opts, inst->extra.size); pavone@571: if (dst) { pavone@567: pop_r(code, opts->gen.scratch2); pavone@18: } pavone@447: pavone@18: ea->mode = MODE_REG_DIRECT; pavone@567: ea->base = opts->gen.scratch1; pavone@18: break; pavone@571: case MODE_PC_INDEX_DISP8: pavone@571: cycles(&opts->gen, 6); pavone@571: mov_ir(code, inst->address+2, opts->gen.scratch1, SZ_D); pavone@574: calc_index_disp8(opts, op, opts->gen.scratch1); pavone@571: if (dst) { pavone@567: push_r(code, opts->gen.scratch1); pavone@686: } pavone@571: m68k_read_size(opts, inst->extra.size); pavone@571: if (dst) { pavone@567: pop_r(code, opts->gen.scratch2); pavone@686: } pavone@571: pavone@98: ea->mode = MODE_REG_DIRECT; pavone@567: ea->base = opts->gen.scratch1; pavone@98: break; pavone@61: case MODE_ABSOLUTE: pavone@61: case MODE_ABSOLUTE_SHORT: pavone@571: cycles(&opts->gen, op->addr_mode == MODE_ABSOLUTE ? BUS*2 : BUS); pavone@571: mov_ir(code, op->params.immed, opts->gen.scratch1, SZ_D); pavone@571: if (dst) { pavone@567: push_r(code, opts->gen.scratch1); pavone@686: } pavone@571: m68k_read_size(opts, inst->extra.size); pavone@571: if (dst) { pavone@567: pop_r(code, opts->gen.scratch2); pavone@61: } pavone@571: pavone@61: ea->mode = MODE_REG_DIRECT; pavone@567: ea->base = opts->gen.scratch1; pavone@61: break; pavone@571: case MODE_IMMEDIATE: pavone@571: case MODE_IMMEDIATE_WORD: pavone@571: if (inst->variant != VAR_QUICK) { pavone@571: cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG && op->addr_mode == MODE_IMMEDIATE) ? BUS*2 : BUS); pavone@571: } pavone@571: ea->mode = MODE_IMMED; pavone@571: ea->disp = op->params.immed; pavone@571: //sign extend value when the destination is an address register pavone@571: if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD && ea->disp & 0x8000) { pavone@571: ea->disp |= 0xFFFF0000; pavone@571: } pavone@571: return; pavone@18: default: pavone@151: m68k_disasm(inst, disasm_buf); pavone@792: fatal_error("%X: %s\naddress mode %d not implemented (%s)\n", inst->address, disasm_buf, op->addr_mode, dst ? "dst" : "src"); pavone@18: } pavone@571: if (!dst && inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) { pavone@571: if (ea->mode == MODE_REG_DIRECT) { pavone@571: movsx_rr(code, ea->base, opts->gen.scratch1, SZ_W, SZ_D); pavone@571: } else { pavone@571: movsx_rdispr(code, ea->base, ea->disp, opts->gen.scratch1, SZ_W, SZ_D); pavone@571: ea->mode = MODE_REG_DIRECT; pavone@571: } pavone@571: ea->base = opts->gen.scratch1; pavone@571: } pavone@18: } pavone@18: pavone@687: void check_user_mode_swap_ssp_usp(m68k_options *opts) pavone@687: { pavone@687: code_info * code = &opts->gen.code; pavone@687: //Check if we've switched to user mode and swap stack pointers if needed pavone@687: bt_irdisp(code, 5, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); pavone@687: code_ptr end_off = code->cur + 1; pavone@687: jcc(code, CC_C, code->cur + 2); pavone@687: swap_ssp_usp(opts); pavone@687: *end_off = code->cur - (end_off + 1); pavone@687: } pavone@687: pavone@569: void translate_m68k_move(m68k_options * opts, m68kinst * inst) pavone@18: { pavone@567: code_info *code = &opts->gen.code; pavone@99: int8_t reg, flags_reg, sec_reg; pavone@18: uint8_t dir = 0; pavone@18: int32_t offset; pavone@18: int32_t inc_amount, dec_amount; pavone@582: host_ea src; pavone@571: translate_m68k_op(inst, &src, opts, 0); pavone@18: reg = native_reg(&(inst->dst), opts); pavone@447: pavone@216: if (inst->dst.addr_mode != MODE_AREG) { pavone@216: if (src.mode == MODE_REG_DIRECT) { pavone@216: flags_reg = src.base; pavone@18: } else { pavone@216: if (reg >= 0) { pavone@216: flags_reg = reg; pavone@128: } else { pavone@216: if(src.mode == MODE_REG_DISPLACE8) { pavone@567: mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size); pavone@216: } else { pavone@567: mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size); pavone@216: } pavone@216: src.mode = MODE_REG_DIRECT; pavone@567: flags_reg = src.base = opts->gen.scratch1; pavone@128: } pavone@18: } pavone@18: } pavone@181: uint8_t size = inst->extra.size; pavone@18: switch(inst->dst.addr_mode) pavone@18: { pavone@181: case MODE_AREG: pavone@181: size = OPSIZE_LONG; pavone@18: case MODE_REG: pavone@18: if (reg >= 0) { pavone@18: if (src.mode == MODE_REG_DIRECT) { pavone@567: mov_rr(code, src.base, reg, size); pavone@18: } else if (src.mode == MODE_REG_DISPLACE8) { pavone@567: mov_rdispr(code, src.base, src.disp, reg, size); pavone@18: } else { pavone@567: mov_ir(code, src.disp, reg, size); pavone@18: } pavone@18: } else if(src.mode == MODE_REG_DIRECT) { pavone@567: mov_rrdisp(code, src.base, opts->gen.context_reg, reg_offset(&(inst->dst)), size); pavone@18: } else { pavone@567: mov_irdisp(code, src.disp, opts->gen.context_reg, reg_offset(&(inst->dst)), size); pavone@18: } pavone@14: break; pavone@18: case MODE_AREG_PREDEC: pavone@182: dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1)); pavone@14: case MODE_AREG_INDIRECT: pavone@18: case MODE_AREG_POSTINC: pavone@18: if (src.mode == MODE_REG_DIRECT) { pavone@567: if (src.base != opts->gen.scratch1) { pavone@567: mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size); pavone@18: } pavone@18: } else if (src.mode == MODE_REG_DISPLACE8) { pavone@567: mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size); pavone@18: } else { pavone@567: mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size); pavone@18: } pavone@610: if (inst->dst.addr_mode == MODE_AREG_PREDEC) { pavone@610: subi_areg(opts, dec_amount, inst->dst.params.regs.pri); pavone@610: } pavone@610: areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2); pavone@14: break; pavone@71: case MODE_AREG_DISPLACE: pavone@567: cycles(&opts->gen, BUS); pavone@574: calc_areg_displace(opts, &inst->dst, opts->gen.scratch2); pavone@71: if (src.mode == MODE_REG_DIRECT) { pavone@567: if (src.base != opts->gen.scratch1) { pavone@567: mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size); pavone@71: } pavone@71: } else if (src.mode == MODE_REG_DISPLACE8) { pavone@567: mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size); pavone@71: } else { pavone@567: mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size); pavone@71: } pavone@71: break; pavone@99: case MODE_AREG_INDEX_DISP8: pavone@567: cycles(&opts->gen, 6);//TODO: Check to make sure this is correct pavone@574: //calc_areg_index_disp8 will clober scratch1 when a 16-bit index is used pavone@574: if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) { pavone@574: push_r(code, opts->gen.scratch1); pavone@99: } pavone@574: calc_areg_index_disp8(opts, &inst->dst, opts->gen.scratch2); pavone@574: if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) { pavone@574: pop_r(code, opts->gen.scratch1); pavone@99: } pavone@184: if (src.mode == MODE_REG_DIRECT) { pavone@567: if (src.base != opts->gen.scratch1) { pavone@567: mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size); pavone@184: } pavone@184: } else if (src.mode == MODE_REG_DISPLACE8) { pavone@567: mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size); pavone@184: } else { pavone@567: mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size); pavone@184: } pavone@99: break; pavone@71: case MODE_PC_DISPLACE: pavone@567: cycles(&opts->gen, BUS); pavone@567: mov_ir(code, inst->dst.params.regs.displacement + inst->address+2, opts->gen.scratch2, SZ_D); pavone@71: if (src.mode == MODE_REG_DIRECT) { pavone@567: if (src.base != opts->gen.scratch1) { pavone@567: mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size); pavone@71: } pavone@71: } else if (src.mode == MODE_REG_DISPLACE8) { pavone@567: mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size); pavone@71: } else { pavone@567: mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size); pavone@71: } pavone@71: break; pavone@196: case MODE_PC_INDEX_DISP8: pavone@567: cycles(&opts->gen, 6);//TODO: Check to make sure this is correct pavone@567: mov_ir(code, inst->address, opts->gen.scratch2, SZ_D); pavone@574: if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) { pavone@574: push_r(code, opts->gen.scratch1); pavone@689: } pavone@574: calc_index_disp8(opts, &inst->dst, opts->gen.scratch2); pavone@574: if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) { pavone@574: pop_r(code, opts->gen.scratch1); pavone@196: } pavone@196: if (src.mode == MODE_REG_DIRECT) { pavone@567: if (src.base != opts->gen.scratch1) { pavone@567: mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size); pavone@196: } pavone@196: } else if (src.mode == MODE_REG_DISPLACE8) { pavone@567: mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size); pavone@196: } else { pavone@567: mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size); pavone@196: } pavone@196: break; pavone@54: case MODE_ABSOLUTE: pavone@54: case MODE_ABSOLUTE_SHORT: pavone@54: if (src.mode == MODE_REG_DIRECT) { pavone@567: if (src.base != opts->gen.scratch1) { pavone@567: mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size); pavone@54: } pavone@54: } else if (src.mode == MODE_REG_DISPLACE8) { pavone@567: mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size); pavone@54: } else { pavone@567: mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size); pavone@54: } pavone@54: if (inst->dst.addr_mode == MODE_ABSOLUTE) { pavone@567: cycles(&opts->gen, BUS*2); pavone@54: } else { pavone@567: cycles(&opts->gen, BUS); pavone@184: } pavone@567: mov_ir(code, inst->dst.params.immed, opts->gen.scratch2, SZ_D); pavone@54: break; pavone@18: default: pavone@151: m68k_disasm(inst, disasm_buf); pavone@792: fatal_error("%X: %s\naddress mode %d not implemented (move dst)\n", inst->address, disasm_buf, inst->dst.addr_mode); pavone@14: } pavone@18: pavone@576: if (inst->dst.addr_mode != MODE_AREG) { pavone@576: cmp_ir(code, 0, flags_reg, inst->extra.size); pavone@576: update_flags(opts, N|Z|V0|C0); pavone@689: } pavone@576: if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG) { pavone@979: m68k_write_size(opts, inst->extra.size, inst->dst.addr_mode == MODE_AREG_PREDEC); pavone@576: if (inst->dst.addr_mode == MODE_AREG_POSTINC) { pavone@576: inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1)); pavone@576: addi_areg(opts, inc_amount, inst->dst.params.regs.pri); pavone@686: } pavone@686: } pavone@576: pavone@18: //add cycles for prefetch pavone@567: cycles(&opts->gen, BUS); pavone@18: } pavone@18: pavone@569: void translate_m68k_clr(m68k_options * opts, m68kinst * inst) pavone@52: { pavone@567: code_info *code = &opts->gen.code; pavone@576: update_flags(opts, N0|V0|C0|Z1); pavone@92: int8_t reg = native_reg(&(inst->dst), opts); pavone@52: if (reg >= 0) { pavone@567: cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 6 : 4)); pavone@567: xor_rr(code, reg, reg, inst->extra.size); pavone@567: return; pavone@52: } pavone@582: host_ea dst_op; pavone@576: //TODO: fix timing pavone@571: translate_m68k_op(inst, &dst_op, opts, 1); pavone@92: if (dst_op.mode == MODE_REG_DIRECT) { pavone@567: xor_rr(code, dst_op.base, dst_op.base, inst->extra.size); pavone@92: } else { pavone@567: mov_irdisp(code, 0, dst_op.base, dst_op.disp, inst->extra.size); pavone@52: } pavone@567: m68k_save_result(inst, opts); pavone@52: } pavone@52: pavone@569: void translate_m68k_ext(m68k_options * opts, m68kinst * inst) pavone@93: { pavone@567: code_info *code = &opts->gen.code; pavone@582: host_ea dst_op; pavone@93: uint8_t dst_size = inst->extra.size; pavone@93: inst->extra.size--; pavone@571: translate_m68k_op(inst, &dst_op, opts, 1); pavone@93: if (dst_op.mode == MODE_REG_DIRECT) { pavone@567: movsx_rr(code, dst_op.base, dst_op.base, inst->extra.size, dst_size); pavone@567: cmp_ir(code, 0, dst_op.base, dst_size); pavone@93: } else { pavone@567: movsx_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, inst->extra.size, dst_size); pavone@567: cmp_ir(code, 0, opts->gen.scratch1, dst_size); pavone@567: mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, dst_size); pavone@93: } pavone@93: inst->extra.size = dst_size; pavone@576: update_flags(opts, N|V0|C0|Z); pavone@93: //M68K EXT only operates on registers so no need for a call to save result here pavone@93: } pavone@93: pavone@569: uint8_t m68k_eval_cond(m68k_options * opts, uint8_t cc) pavone@18: { pavone@686: uint8_t cond = CC_NZ; pavone@567: switch (cc) pavone@686: { pavone@686: case COND_HIGH: pavone@686: cond = CC_Z; pavone@686: case COND_LOW_SAME: pavone@567: flag_to_reg(opts, FLAG_Z, opts->gen.scratch1); pavone@567: or_flag_to_reg(opts, FLAG_C, opts->gen.scratch1); pavone@686: break; pavone@686: case COND_CARRY_CLR: pavone@686: cond = CC_Z; pavone@686: case COND_CARRY_SET: pavone@567: check_flag(opts, FLAG_C); pavone@686: break; pavone@686: case COND_NOT_EQ: pavone@686: cond = CC_Z; pavone@686: case COND_EQ: pavone@567: check_flag(opts, FLAG_Z); pavone@686: break; pavone@686: case COND_OVERF_CLR: pavone@686: cond = CC_Z; pavone@686: case COND_OVERF_SET: pavone@567: check_flag(opts, FLAG_V); pavone@686: break; pavone@686: case COND_PLUS: pavone@686: cond = CC_Z; pavone@686: case COND_MINUS: pavone@567: check_flag(opts, FLAG_N); pavone@686: break; pavone@686: case COND_GREATER_EQ: pavone@686: cond = CC_Z; pavone@686: case COND_LESS: pavone@567: cmp_flags(opts, FLAG_N, FLAG_V); pavone@686: break; pavone@686: case COND_GREATER: pavone@686: cond = CC_Z; pavone@686: case COND_LESS_EQ: pavone@567: flag_to_reg(opts, FLAG_V, opts->gen.scratch1); pavone@567: xor_flag_to_reg(opts, FLAG_N, opts->gen.scratch1); pavone@567: or_flag_to_reg(opts, FLAG_Z, opts->gen.scratch1); pavone@686: break; pavone@686: } pavone@567: return cond; pavone@567: } pavone@567: pavone@569: void translate_m68k_bcc(m68k_options * opts, m68kinst * inst) pavone@567: { pavone@567: code_info *code = &opts->gen.code; pavone@567: cycles(&opts->gen, 10);//TODO: Adjust this for branch not taken case pavone@18: int32_t disp = inst->src.params.immed; pavone@46: uint32_t after = inst->address + 2; pavone@18: if (inst->extra.cond == COND_TRUE) { pavone@574: jump_m68k_abs(opts, after + disp); pavone@18: } else { pavone@726: code_ptr dest_addr = get_native_address(opts, after + disp); pavone@567: uint8_t cond = m68k_eval_cond(opts, inst->extra.cond); pavone@567: if (!dest_addr) { pavone@567: opts->gen.deferred = defer_address(opts->gen.deferred, after + disp, code->cur + 2); pavone@567: //dummy address to be replaced later, make sure it generates a 4-byte displacement pavone@567: dest_addr = code->cur + 256; pavone@18: } pavone@567: jcc(code, cond, dest_addr); pavone@18: } pavone@18: } pavone@18: pavone@569: void translate_m68k_scc(m68k_options * opts, m68kinst * inst) pavone@112: { pavone@567: code_info *code = &opts->gen.code; pavone@112: uint8_t cond = inst->extra.cond; pavone@582: host_ea dst_op; pavone@112: inst->extra.size = OPSIZE_BYTE; pavone@571: translate_m68k_op(inst, &dst_op, opts, 1); pavone@112: if (cond == COND_TRUE || cond == COND_FALSE) { pavone@112: if ((inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG) && inst->extra.cond == COND_TRUE) { pavone@567: cycles(&opts->gen, 6); pavone@112: } else { pavone@567: cycles(&opts->gen, BUS); pavone@112: } pavone@112: if (dst_op.mode == MODE_REG_DIRECT) { pavone@567: mov_ir(code, cond == COND_TRUE ? 0xFF : 0, dst_op.base, SZ_B); pavone@112: } else { pavone@567: mov_irdisp(code, cond == COND_TRUE ? 0xFF : 0, dst_op.base, dst_op.disp, SZ_B); pavone@112: } pavone@112: } else { pavone@567: uint8_t cc = m68k_eval_cond(opts, cond); pavone@567: check_alloc_code(code, 6*MAX_INST_LEN); pavone@567: code_ptr true_off = code->cur + 1; pavone@567: jcc(code, cc, code->cur+2); pavone@567: cycles(&opts->gen, BUS); pavone@567: if (dst_op.mode == MODE_REG_DIRECT) { pavone@567: mov_ir(code, 0, dst_op.base, SZ_B); pavone@567: } else { pavone@567: mov_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B); pavone@112: } pavone@567: code_ptr end_off = code->cur+1; pavone@567: jmp(code, code->cur+2); pavone@567: *true_off = code->cur - (true_off+1); pavone@567: cycles(&opts->gen, 6); pavone@179: if (dst_op.mode == MODE_REG_DIRECT) { pavone@567: mov_ir(code, 0xFF, dst_op.base, SZ_B); pavone@112: } else { pavone@567: mov_irdisp(code, 0xFF, dst_op.base, dst_op.disp, SZ_B); pavone@112: } pavone@567: *end_off = code->cur - (end_off+1); pavone@112: } pavone@567: m68k_save_result(inst, opts); pavone@112: } pavone@112: pavone@569: void translate_m68k_dbcc(m68k_options * opts, m68kinst * inst) pavone@46: { pavone@567: code_info *code = &opts->gen.code; pavone@46: //best case duration pavone@567: cycles(&opts->gen, 10); pavone@558: code_ptr skip_loc = NULL; pavone@46: //TODO: Check if COND_TRUE technically valid here even though pavone@46: //it's basically a slow NOP pavone@46: if (inst->extra.cond != COND_FALSE) { pavone@567: uint8_t cond = m68k_eval_cond(opts, inst->extra.cond); pavone@567: check_alloc_code(code, 6*MAX_INST_LEN); pavone@567: skip_loc = code->cur + 1; pavone@567: jcc(code, cond, code->cur + 2); pavone@46: } pavone@46: if (opts->dregs[inst->dst.params.regs.pri] >= 0) { pavone@567: sub_ir(code, 1, opts->dregs[inst->dst.params.regs.pri], SZ_W); pavone@567: cmp_ir(code, -1, opts->dregs[inst->dst.params.regs.pri], SZ_W); pavone@46: } else { pavone@567: sub_irdisp(code, 1, opts->gen.context_reg, offsetof(m68k_context, dregs) + 4 * inst->dst.params.regs.pri, SZ_W); pavone@567: cmp_irdisp(code, -1, opts->gen.context_reg, offsetof(m68k_context, dregs) + 4 * inst->dst.params.regs.pri, SZ_W); pavone@46: } pavone@567: code_ptr loop_end_loc = code->cur + 1; pavone@567: jcc(code, CC_Z, code->cur + 2); pavone@46: uint32_t after = inst->address + 2; pavone@574: jump_m68k_abs(opts, after + inst->src.params.immed); pavone@567: *loop_end_loc = code->cur - (loop_end_loc+1); pavone@46: if (skip_loc) { pavone@567: cycles(&opts->gen, 2); pavone@567: *skip_loc = code->cur - (skip_loc+1); pavone@567: cycles(&opts->gen, 2); pavone@46: } else { pavone@567: cycles(&opts->gen, 4); pavone@46: } pavone@46: } pavone@46: pavone@569: void translate_m68k_movep(m68k_options * opts, m68kinst * inst) pavone@172: { pavone@567: code_info *code = &opts->gen.code; pavone@172: int8_t reg; pavone@567: cycles(&opts->gen, BUS*2); pavone@172: if (inst->src.addr_mode == MODE_REG) { pavone@574: calc_areg_displace(opts, &inst->dst, opts->gen.scratch2); pavone@172: reg = native_reg(&(inst->src), opts); pavone@172: if (inst->extra.size == OPSIZE_LONG) { pavone@172: if (reg >= 0) { pavone@567: mov_rr(code, reg, opts->gen.scratch1, SZ_D); pavone@567: shr_ir(code, 24, opts->gen.scratch1, SZ_D); pavone@567: push_r(code, opts->gen.scratch2); pavone@567: call(code, opts->write_8); pavone@567: pop_r(code, opts->gen.scratch2); pavone@567: mov_rr(code, reg, opts->gen.scratch1, SZ_D); pavone@567: shr_ir(code, 16, opts->gen.scratch1, SZ_D); pavone@447: pavone@172: } else { pavone@567: mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src))+3, opts->gen.scratch1, SZ_B); pavone@567: push_r(code, opts->gen.scratch2); pavone@567: call(code, opts->write_8); pavone@567: pop_r(code, opts->gen.scratch2); pavone@567: mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src))+2, opts->gen.scratch1, SZ_B); pavone@172: } pavone@567: add_ir(code, 2, opts->gen.scratch2, SZ_D); pavone@567: push_r(code, opts->gen.scratch2); pavone@567: call(code, opts->write_8); pavone@567: pop_r(code, opts->gen.scratch2); pavone@567: add_ir(code, 2, opts->gen.scratch2, SZ_D); pavone@172: } pavone@172: if (reg >= 0) { pavone@567: mov_rr(code, reg, opts->gen.scratch1, SZ_W); pavone@567: shr_ir(code, 8, opts->gen.scratch1, SZ_W); pavone@567: push_r(code, opts->gen.scratch2); pavone@567: call(code, opts->write_8); pavone@567: pop_r(code, opts->gen.scratch2); pavone@567: mov_rr(code, reg, opts->gen.scratch1, SZ_W); pavone@172: } else { pavone@567: mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src))+1, opts->gen.scratch1, SZ_B); pavone@567: push_r(code, opts->gen.scratch2); pavone@567: call(code, opts->write_8); pavone@567: pop_r(code, opts->gen.scratch2); pavone@567: mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src)), opts->gen.scratch1, SZ_B); pavone@172: } pavone@567: add_ir(code, 2, opts->gen.scratch2, SZ_D); pavone@567: call(code, opts->write_8); pavone@172: } else { pavone@574: calc_areg_displace(opts, &inst->src, opts->gen.scratch1); pavone@172: reg = native_reg(&(inst->dst), opts); pavone@172: if (inst->extra.size == OPSIZE_LONG) { pavone@172: if (reg >= 0) { pavone@567: push_r(code, opts->gen.scratch1); pavone@567: call(code, opts->read_8); pavone@567: shl_ir(code, 24, opts->gen.scratch1, SZ_D); pavone@567: mov_rr(code, opts->gen.scratch1, reg, SZ_D); pavone@567: pop_r(code, opts->gen.scratch1); pavone@567: add_ir(code, 2, opts->gen.scratch1, SZ_D); pavone@567: push_r(code, opts->gen.scratch1); pavone@567: call(code, opts->read_8); pavone@567: shl_ir(code, 16, opts->gen.scratch1, SZ_D); pavone@567: or_rr(code, opts->gen.scratch1, reg, SZ_D); pavone@172: } else { pavone@567: push_r(code, opts->gen.scratch1); pavone@567: call(code, opts->read_8); pavone@567: mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst))+3, SZ_B); pavone@567: pop_r(code, opts->gen.scratch1); pavone@567: add_ir(code, 2, opts->gen.scratch1, SZ_D); pavone@567: push_r(code, opts->gen.scratch1); pavone@567: call(code, opts->read_8); pavone@567: mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst))+2, SZ_B); pavone@172: } pavone@567: pop_r(code, opts->gen.scratch1); pavone@567: add_ir(code, 2, opts->gen.scratch1, SZ_D); pavone@172: } pavone@567: push_r(code, opts->gen.scratch1); pavone@567: call(code, opts->read_8); pavone@172: if (reg >= 0) { pavone@447: pavone@567: shl_ir(code, 8, opts->gen.scratch1, SZ_W); pavone@567: mov_rr(code, opts->gen.scratch1, reg, SZ_W); pavone@567: pop_r(code, opts->gen.scratch1); pavone@567: add_ir(code, 2, opts->gen.scratch1, SZ_D); pavone@567: call(code, opts->read_8); pavone@567: mov_rr(code, opts->gen.scratch1, reg, SZ_B); pavone@172: } else { pavone@567: mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst))+1, SZ_B); pavone@567: pop_r(code, opts->gen.scratch1); pavone@567: add_ir(code, 2, opts->gen.scratch1, SZ_D); pavone@567: call(code, opts->read_8); pavone@567: mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst)), SZ_B); pavone@172: } pavone@172: } pavone@172: } pavone@172: pavone@567: typedef void (*shift_ir_t)(code_info *code, uint8_t val, uint8_t dst, uint8_t size); pavone@567: typedef void (*shift_irdisp_t)(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size); pavone@567: typedef void (*shift_clr_t)(code_info *code, uint8_t dst, uint8_t size); pavone@567: typedef void (*shift_clrdisp_t)(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size); pavone@51: pavone@582: 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) pavone@51: { pavone@567: code_info *code = &opts->gen.code; pavone@558: code_ptr end_off = NULL; pavone@558: code_ptr nz_off = NULL; pavone@558: code_ptr z_off = NULL; pavone@51: if (inst->src.addr_mode == MODE_UNUSED) { pavone@567: cycles(&opts->gen, BUS); pavone@51: //Memory shift pavone@567: shift_ir(code, 1, dst_op->base, SZ_W); pavone@51: } else { pavone@51: if (src_op->mode == MODE_IMMED) { pavone@667: cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 8 : 6) + 2 * src_op->disp); pavone@207: if (src_op->disp != 1 && inst->op == M68K_ASL) { pavone@567: set_flag(opts, 0, FLAG_V); pavone@207: for (int i = 0; i < src_op->disp; i++) { pavone@207: if (dst_op->mode == MODE_REG_DIRECT) { pavone@567: shift_ir(code, 1, dst_op->base, inst->extra.size); pavone@207: } else { pavone@567: shift_irdisp(code, 1, dst_op->base, dst_op->disp, inst->extra.size); pavone@207: } pavone@567: check_alloc_code(code, 2*MAX_INST_LEN); pavone@567: code_ptr after_flag_set = code->cur + 1; pavone@567: jcc(code, CC_NO, code->cur + 2); pavone@567: set_flag(opts, 1, FLAG_V); pavone@567: *after_flag_set = code->cur - (after_flag_set+1); pavone@207: } pavone@51: } else { pavone@207: if (dst_op->mode == MODE_REG_DIRECT) { pavone@567: shift_ir(code, src_op->disp, dst_op->base, inst->extra.size); pavone@207: } else { pavone@567: shift_irdisp(code, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size); pavone@207: } pavone@567: set_flag_cond(opts, CC_O, FLAG_V); pavone@51: } pavone@51: } else { pavone@667: cycles(&opts->gen, inst->extra.size == OPSIZE_LONG ? 8 : 6); pavone@51: if (src_op->base != RCX) { pavone@51: if (src_op->mode == MODE_REG_DIRECT) { pavone@567: mov_rr(code, src_op->base, RCX, SZ_B); pavone@51: } else { pavone@567: mov_rdispr(code, src_op->base, src_op->disp, RCX, SZ_B); pavone@51: } pavone@447: pavone@51: } pavone@567: and_ir(code, 63, RCX, SZ_D); pavone@567: check_alloc_code(code, 7*MAX_INST_LEN); pavone@567: nz_off = code->cur + 1; pavone@567: jcc(code, CC_NZ, code->cur + 2); pavone@207: //Flag behavior for shift count of 0 is different for x86 than 68K pavone@207: if (dst_op->mode == MODE_REG_DIRECT) { pavone@567: cmp_ir(code, 0, dst_op->base, inst->extra.size); pavone@207: } else { pavone@567: cmp_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size); pavone@207: } pavone@567: set_flag_cond(opts, CC_Z, FLAG_Z); pavone@567: set_flag_cond(opts, CC_S, FLAG_N); pavone@567: set_flag(opts, 0, FLAG_C); pavone@207: //For other instructions, this flag will be set below pavone@207: if (inst->op == M68K_ASL) { pavone@567: set_flag(opts, 0, FLAG_V); pavone@207: } pavone@567: z_off = code->cur + 1; pavone@567: jmp(code, code->cur + 2); pavone@567: *nz_off = code->cur - (nz_off + 1); pavone@51: //add 2 cycles for every bit shifted pavone@667: mov_ir(code, 2 * opts->gen.clock_divider, opts->gen.scratch2, SZ_D); pavone@667: imul_rr(code, RCX, opts->gen.scratch2, SZ_D); pavone@667: add_rr(code, opts->gen.scratch2, opts->gen.cycles, SZ_D); pavone@207: if (inst->op == M68K_ASL) { pavone@207: //ASL has Overflow flag behavior that depends on all of the bits shifted through the MSB pavone@207: //Easiest way to deal with this is to shift one bit at a time pavone@567: set_flag(opts, 0, FLAG_V); pavone@567: check_alloc_code(code, 5*MAX_INST_LEN); pavone@567: code_ptr loop_start = code->cur; pavone@51: if (dst_op->mode == MODE_REG_DIRECT) { pavone@567: shift_ir(code, 1, dst_op->base, inst->extra.size); pavone@51: } else { pavone@567: shift_irdisp(code, 1, dst_op->base, dst_op->disp, inst->extra.size); pavone@51: } pavone@567: code_ptr after_flag_set = code->cur + 1; pavone@567: jcc(code, CC_NO, code->cur + 2); pavone@567: set_flag(opts, 1, FLAG_V); pavone@567: *after_flag_set = code->cur - (after_flag_set+1); pavone@567: loop(code, loop_start); pavone@207: } else { pavone@207: //x86 shifts modulo 32 for operand sizes less than 64-bits pavone@207: //but M68K shifts modulo 64, so we need to check for large shifts here pavone@567: cmp_ir(code, 32, RCX, SZ_B); pavone@567: check_alloc_code(code, 14*MAX_INST_LEN); pavone@567: code_ptr norm_shift_off = code->cur + 1; pavone@567: jcc(code, CC_L, code->cur + 2); pavone@207: if (special) { pavone@558: code_ptr after_flag_set = NULL; pavone@207: if (inst->extra.size == OPSIZE_LONG) { pavone@567: code_ptr neq_32_off = code->cur + 1; pavone@567: jcc(code, CC_NZ, code->cur + 2); pavone@447: pavone@207: //set the carry bit to the lsb pavone@207: if (dst_op->mode == MODE_REG_DIRECT) { pavone@567: special(code, 1, dst_op->base, SZ_D); pavone@207: } else { pavone@567: special_disp(code, 1, dst_op->base, dst_op->disp, SZ_D); pavone@207: } pavone@567: set_flag_cond(opts, CC_C, FLAG_C); pavone@567: after_flag_set = code->cur + 1; pavone@567: jmp(code, code->cur + 2); pavone@567: *neq_32_off = code->cur - (neq_32_off+1); pavone@207: } pavone@567: set_flag(opts, 0, FLAG_C); pavone@546: if (after_flag_set) { pavone@567: *after_flag_set = code->cur - (after_flag_set+1); pavone@546: } pavone@567: set_flag(opts, 1, FLAG_Z); pavone@567: set_flag(opts, 0, FLAG_N); pavone@207: if (dst_op->mode == MODE_REG_DIRECT) { pavone@567: xor_rr(code, dst_op->base, dst_op->base, inst->extra.size); pavone@207: } else { pavone@567: mov_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size); pavone@207: } pavone@207: } else { pavone@207: if (dst_op->mode == MODE_REG_DIRECT) { pavone@567: shift_ir(code, 31, dst_op->base, inst->extra.size); pavone@567: shift_ir(code, 1, dst_op->base, inst->extra.size); pavone@207: } else { pavone@567: shift_irdisp(code, 31, dst_op->base, dst_op->disp, inst->extra.size); pavone@567: shift_irdisp(code, 1, dst_op->base, dst_op->disp, inst->extra.size); pavone@207: } pavone@447: pavone@207: } pavone@567: end_off = code->cur + 1; pavone@567: jmp(code, code->cur + 2); pavone@567: *norm_shift_off = code->cur - (norm_shift_off+1); pavone@207: if (dst_op->mode == MODE_REG_DIRECT) { pavone@567: shift_clr(code, dst_op->base, inst->extra.size); pavone@207: } else { pavone@567: shift_clrdisp(code, dst_op->base, dst_op->disp, inst->extra.size); pavone@207: } pavone@51: } pavone@51: } pavone@447: pavone@51: } pavone@51: if (!special && end_off) { pavone@567: *end_off = code->cur - (end_off + 1); pavone@51: } pavone@583: update_flags(opts, C|Z|N); pavone@51: if (special && end_off) { pavone@567: *end_off = code->cur - (end_off + 1); pavone@51: } pavone@51: //set X flag to same as C flag pavone@546: if (opts->flag_regs[FLAG_C] >= 0) { pavone@567: flag_to_flag(opts, FLAG_C, FLAG_X); pavone@546: } else { pavone@567: set_flag_cond(opts, CC_C, FLAG_X); pavone@546: } pavone@207: if (z_off) { pavone@567: *z_off = code->cur - (z_off + 1); pavone@207: } pavone@219: if (inst->op != M68K_ASL) { pavone@567: set_flag(opts, 0, FLAG_V); pavone@207: } pavone@51: if (inst->src.addr_mode == MODE_UNUSED) { pavone@567: m68k_save_result(inst, opts); pavone@51: } pavone@51: } pavone@51: pavone@577: void op_ir(code_info *code, m68kinst *inst, int32_t val, uint8_t dst, uint8_t size) pavone@577: { pavone@577: switch (inst->op) pavone@577: { pavone@577: case M68K_ADD: add_ir(code, val, dst, size); break; pavone@577: case M68K_ADDX: adc_ir(code, val, dst, size); break; pavone@577: case M68K_AND: and_ir(code, val, dst, size); break; pavone@581: case M68K_BTST: bt_ir(code, val, dst, size); break; pavone@581: case M68K_BSET: bts_ir(code, val, dst, size); break; pavone@581: case M68K_BCLR: btr_ir(code, val, dst, size); break; pavone@581: case M68K_BCHG: btc_ir(code, val, dst, size); break; pavone@582: case M68K_CMP: cmp_ir(code, val, dst, size); break; pavone@577: case M68K_EOR: xor_ir(code, val, dst, size); break; pavone@577: case M68K_OR: or_ir(code, val, dst, size); break; pavone@577: case M68K_ROL: rol_ir(code, val, dst, size); break; pavone@577: case M68K_ROR: ror_ir(code, val, dst, size); break; pavone@577: case M68K_ROXL: rcl_ir(code, val, dst, size); break; pavone@577: case M68K_ROXR: rcr_ir(code, val, dst, size); break; pavone@577: case M68K_SUB: sub_ir(code, val, dst, size); break; pavone@577: case M68K_SUBX: sbb_ir(code, val, dst, size); break; pavone@577: } pavone@577: } pavone@577: pavone@577: void op_irdisp(code_info *code, m68kinst *inst, int32_t val, uint8_t dst, int32_t disp, uint8_t size) pavone@577: { pavone@577: switch (inst->op) pavone@577: { pavone@577: case M68K_ADD: add_irdisp(code, val, dst, disp, size); break; pavone@577: case M68K_ADDX: adc_irdisp(code, val, dst, disp, size); break; pavone@577: case M68K_AND: and_irdisp(code, val, dst, disp, size); break; pavone@581: case M68K_BTST: bt_irdisp(code, val, dst, disp, size); break; pavone@581: case M68K_BSET: bts_irdisp(code, val, dst, disp, size); break; pavone@581: case M68K_BCLR: btr_irdisp(code, val, dst, disp, size); break; pavone@581: case M68K_BCHG: btc_irdisp(code, val, dst, disp, size); break; pavone@582: case M68K_CMP: cmp_irdisp(code, val, dst, disp, size); break; pavone@577: case M68K_EOR: xor_irdisp(code, val, dst, disp, size); break; pavone@577: case M68K_OR: or_irdisp(code, val, dst, disp, size); break; pavone@577: case M68K_ROL: rol_irdisp(code, val, dst, disp, size); break; pavone@577: case M68K_ROR: ror_irdisp(code, val, dst, disp, size); break; pavone@577: case M68K_ROXL: rcl_irdisp(code, val, dst, disp, size); break; pavone@577: case M68K_ROXR: rcr_irdisp(code, val, dst, disp, size); break; pavone@577: case M68K_SUB: sub_irdisp(code, val, dst, disp, size); break; pavone@577: case M68K_SUBX: sbb_irdisp(code, val, dst, disp, size); break; pavone@577: } pavone@686: } pavone@577: pavone@577: void op_rr(code_info *code, m68kinst *inst, uint8_t src, uint8_t dst, uint8_t size) pavone@577: { pavone@577: switch (inst->op) pavone@577: { pavone@577: case M68K_ADD: add_rr(code, src, dst, size); break; pavone@577: case M68K_ADDX: adc_rr(code, src, dst, size); break; pavone@577: case M68K_AND: and_rr(code, src, dst, size); break; pavone@581: case M68K_BTST: bt_rr(code, src, dst, size); break; pavone@581: case M68K_BSET: bts_rr(code, src, dst, size); break; pavone@581: case M68K_BCLR: btr_rr(code, src, dst, size); break; pavone@581: case M68K_BCHG: btc_rr(code, src, dst, size); break; pavone@582: case M68K_CMP: cmp_rr(code, src, dst, size); break; pavone@577: case M68K_EOR: xor_rr(code, src, dst, size); break; pavone@577: case M68K_OR: or_rr(code, src, dst, size); break; pavone@577: case M68K_SUB: sub_rr(code, src, dst, size); break; pavone@577: case M68K_SUBX: sbb_rr(code, src, dst, size); break; pavone@577: } pavone@686: } pavone@577: pavone@577: void op_rrdisp(code_info *code, m68kinst *inst, uint8_t src, uint8_t dst, int32_t disp, uint8_t size) pavone@577: { pavone@14: switch(inst->op) pavone@577: { pavone@577: case M68K_ADD: add_rrdisp(code, src, dst, disp, size); break; pavone@577: case M68K_ADDX: adc_rrdisp(code, src, dst, disp, size); break; pavone@577: case M68K_AND: and_rrdisp(code, src, dst, disp, size); break; pavone@581: case M68K_BTST: bt_rrdisp(code, src, dst, disp, size); break; pavone@581: case M68K_BSET: bts_rrdisp(code, src, dst, disp, size); break; pavone@581: case M68K_BCLR: btr_rrdisp(code, src, dst, disp, size); break; pavone@581: case M68K_BCHG: btc_rrdisp(code, src, dst, disp, size); break; pavone@582: case M68K_CMP: cmp_rrdisp(code, src, dst, disp, size); break; pavone@577: case M68K_EOR: xor_rrdisp(code, src, dst, disp, size); break; pavone@577: case M68K_OR: or_rrdisp(code, src, dst, disp, size); break; pavone@577: case M68K_SUB: sub_rrdisp(code, src, dst, disp, size); break; pavone@577: case M68K_SUBX: sbb_rrdisp(code, src, dst, disp, size); break; pavone@686: } pavone@686: } pavone@577: pavone@577: void op_rdispr(code_info *code, m68kinst *inst, uint8_t src, int32_t disp, uint8_t dst, uint8_t size) pavone@577: { pavone@577: switch (inst->op) pavone@577: { pavone@577: case M68K_ADD: add_rdispr(code, src, disp, dst, size); break; pavone@577: case M68K_ADDX: adc_rdispr(code, src, disp, dst, size); break; pavone@577: case M68K_AND: and_rdispr(code, src, disp, dst, size); break; pavone@582: case M68K_CMP: cmp_rdispr(code, src, disp, dst, size); break; pavone@577: case M68K_EOR: xor_rdispr(code, src, disp, dst, size); break; pavone@577: case M68K_OR: or_rdispr(code, src, disp, dst, size); break; pavone@577: case M68K_SUB: sub_rdispr(code, src, disp, dst, size); break; pavone@577: case M68K_SUBX: sbb_rdispr(code, src, disp, dst, size); break; pavone@686: } pavone@686: } pavone@577: pavone@582: void translate_m68k_arith(m68k_options *opts, m68kinst * inst, uint32_t flag_mask, host_ea *src_op, host_ea *dst_op) pavone@577: { pavone@577: code_info *code = &opts->gen.code; pavone@577: cycles(&opts->gen, BUS); pavone@577: if (inst->op == M68K_ADDX || inst->op == M68K_SUBX) { pavone@577: flag_to_carry(opts, FLAG_X); pavone@686: } pavone@577: uint8_t size = inst->dst.addr_mode == MODE_AREG ? OPSIZE_LONG : inst->extra.size; pavone@577: if (src_op->mode == MODE_REG_DIRECT) { pavone@577: if (dst_op->mode == MODE_REG_DIRECT) { pavone@577: op_rr(code, inst, src_op->base, dst_op->base, size); pavone@686: } else { pavone@577: op_rrdisp(code, inst, src_op->base, dst_op->base, dst_op->disp, size); pavone@686: } pavone@577: } else if (src_op->mode == MODE_REG_DISPLACE8) { pavone@577: op_rdispr(code, inst, src_op->base, src_op->disp, dst_op->base, size); pavone@686: } else { pavone@577: if (dst_op->mode == MODE_REG_DIRECT) { pavone@577: op_ir(code, inst, src_op->disp, dst_op->base, size); pavone@686: } else { pavone@577: op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, size); pavone@577: } pavone@686: } pavone@580: if (inst->dst.addr_mode != MODE_AREG || inst->op == M68K_CMP) { pavone@577: update_flags(opts, flag_mask); pavone@577: if (inst->op == M68K_ADDX || inst->op == M68K_SUBX) { pavone@577: check_alloc_code(code, 2*MAX_INST_LEN); pavone@577: code_ptr after_flag_set = code->cur + 1; pavone@577: jcc(code, CC_Z, code->cur + 2); pavone@577: set_flag(opts, 0, FLAG_Z); pavone@577: *after_flag_set = code->cur - (after_flag_set+1); pavone@577: } pavone@686: } pavone@580: if (inst->op != M68K_CMP) { pavone@580: m68k_save_result(inst, opts); pavone@580: } pavone@580: } pavone@580: pavone@580: void translate_m68k_cmp(m68k_options * opts, m68kinst * inst) pavone@580: { pavone@580: code_info *code = &opts->gen.code; pavone@580: uint8_t size = inst->extra.size; pavone@582: host_ea src_op, dst_op; pavone@580: translate_m68k_op(inst, &src_op, opts, 0); pavone@580: if (inst->dst.addr_mode == MODE_AREG_POSTINC) { pavone@580: push_r(code, opts->gen.scratch1); pavone@580: translate_m68k_op(inst, &dst_op, opts, 1); pavone@580: pop_r(code, opts->gen.scratch2); pavone@580: src_op.base = opts->gen.scratch2; pavone@686: } else { pavone@580: translate_m68k_op(inst, &dst_op, opts, 1); pavone@580: if (inst->dst.addr_mode == MODE_AREG && size == OPSIZE_WORD) { pavone@580: size = OPSIZE_LONG; pavone@686: } pavone@580: } pavone@580: translate_m68k_arith(opts, inst, N|Z|V|C, &src_op, &dst_op); pavone@577: } pavone@577: pavone@837: void translate_m68k_tas(m68k_options *opts, m68kinst *inst) pavone@837: { pavone@837: code_info *code = &opts->gen.code; pavone@837: host_ea op; pavone@837: translate_m68k_op(inst, &op, opts, 1); pavone@837: if (op.mode == MODE_REG_DIRECT) { pavone@837: cmp_ir(code, 0, op.base, SZ_B); pavone@837: } else { pavone@837: cmp_irdisp(code, 0, op.base, op.disp, SZ_B); pavone@837: } pavone@837: update_flags(opts, N|Z|V0|C0); pavone@837: if (inst->dst.addr_mode == MODE_REG) { pavone@837: cycles(&opts->gen, BUS); pavone@837: if (op.mode == MODE_REG_DIRECT) { pavone@837: bts_ir(code, 7, op.base, SZ_B); pavone@837: } else { pavone@837: bts_irdisp(code, 7, op.base, op.disp, SZ_B); pavone@837: } pavone@837: } else { pavone@837: if (opts->gen.flags & M68K_OPT_BROKEN_READ_MODIFY) { pavone@837: //2 cycles for processing pavone@837: //4 for failed writeback pavone@837: //4 for prefetch pavone@837: cycles(&opts->gen, BUS * 2 + 2); pavone@837: } else { pavone@837: cycles(&opts->gen, 2); pavone@837: bts_ir(code, 7, op.base, SZ_B); pavone@837: m68k_save_result(inst, opts); pavone@837: cycles(&opts->gen, BUS); pavone@837: } pavone@837: } pavone@837: } pavone@837: pavone@577: void op_r(code_info *code, m68kinst *inst, uint8_t dst, uint8_t size) pavone@577: { pavone@577: switch(inst->op) pavone@577: { pavone@577: case M68K_NEG: neg_r(code, dst, size); break; pavone@577: case M68K_NOT: not_r(code, dst, size); cmp_ir(code, 0, dst, size); break; pavone@577: case M68K_ROL: rol_clr(code, dst, size); break; pavone@577: case M68K_ROR: ror_clr(code, dst, size); break; pavone@577: case M68K_ROXL: rcl_clr(code, dst, size); break; pavone@577: case M68K_ROXR: rcr_clr(code, dst, size); break; pavone@578: case M68K_SWAP: rol_ir(code, 16, dst, SZ_D); cmp_ir(code, 0, dst, SZ_D); break; pavone@577: case M68K_TST: cmp_ir(code, 0, dst, size); break; pavone@577: } pavone@577: } pavone@577: pavone@577: void op_rdisp(code_info *code, m68kinst *inst, uint8_t dst, int32_t disp, uint8_t size) pavone@577: { pavone@577: switch(inst->op) pavone@577: { pavone@577: case M68K_NEG: neg_rdisp(code, dst, disp, size); break; pavone@577: case M68K_NOT: not_rdisp(code, dst, disp, size); cmp_irdisp(code, 0, dst, disp, size); break; pavone@577: case M68K_ROL: rol_clrdisp(code, dst, disp, size); break; pavone@577: case M68K_ROR: ror_clrdisp(code, dst, disp, size); break; pavone@577: case M68K_ROXL: rcl_clrdisp(code, dst, disp, size); break; pavone@577: case M68K_ROXR: rcr_clrdisp(code, dst, disp, size); break; pavone@578: case M68K_SWAP: rol_irdisp(code, 16, dst, disp, SZ_D); cmp_irdisp(code, 0, dst, disp, SZ_D); break; pavone@577: case M68K_TST: cmp_irdisp(code, 0, dst, disp, size); break; pavone@577: } pavone@577: } pavone@577: pavone@582: void translate_m68k_unary(m68k_options *opts, m68kinst *inst, uint32_t flag_mask, host_ea *dst_op) pavone@577: { pavone@577: code_info *code = &opts->gen.code; pavone@577: cycles(&opts->gen, BUS); pavone@577: if (dst_op->mode == MODE_REG_DIRECT) { pavone@577: op_r(code, inst, dst_op->base, inst->extra.size); pavone@686: } else { pavone@577: op_rdisp(code, inst, dst_op->base, dst_op->disp, inst->extra.size); pavone@686: } pavone@577: update_flags(opts, flag_mask); pavone@577: m68k_save_result(inst, opts); pavone@686: } pavone@577: pavone@582: void translate_m68k_abcd_sbcd(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) pavone@582: { pavone@582: code_info *code = &opts->gen.code; pavone@834: if (inst->op == M68K_NBCD) { pavone@834: if (dst_op->base != opts->gen.scratch2) { pavone@834: if (dst_op->mode == MODE_REG_DIRECT) { pavone@834: mov_rr(code, dst_op->base, opts->gen.scratch2, SZ_B); pavone@834: } else { pavone@834: mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_B); pavone@834: } pavone@208: } pavone@834: xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_B); pavone@834: } else { pavone@834: if (src_op->base != opts->gen.scratch2) { pavone@834: if (src_op->mode == MODE_REG_DIRECT) { pavone@834: mov_rr(code, src_op->base, opts->gen.scratch2, SZ_B); pavone@834: } else { pavone@834: mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_B); pavone@834: } pavone@834: } pavone@834: if (dst_op->base != opts->gen.scratch1) { pavone@834: if (dst_op->mode == MODE_REG_DIRECT) { pavone@834: mov_rr(code, dst_op->base, opts->gen.scratch1, SZ_B); pavone@834: } else { pavone@834: mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch1, SZ_B); pavone@834: } pavone@686: } pavone@582: } pavone@612: uint8_t other_reg; pavone@612: //WARNING: This may need adjustment if register assignments change pavone@612: if (opts->gen.scratch2 > RBX) { pavone@612: other_reg = RAX; pavone@612: xchg_rr(code, opts->gen.scratch2, RAX, SZ_D); pavone@686: } else { pavone@612: other_reg = opts->gen.scratch2; pavone@612: } pavone@612: mov_rr(code, opts->gen.scratch1, opts->gen.scratch1 + (AH-RAX), SZ_B); pavone@612: mov_rr(code, other_reg, other_reg + (AH-RAX), SZ_B); pavone@612: and_ir(code, 0xF, opts->gen.scratch1 + (AH-RAX), SZ_B); pavone@612: and_ir(code, 0xF, other_reg + (AH-RAX), SZ_B); pavone@833: //do op on low nibble so we can determine if an adjustment is necessary pavone@582: flag_to_carry(opts, FLAG_X); pavone@582: if (inst->op == M68K_ABCD) { pavone@612: adc_rr(code, other_reg + (AH-RAX), opts->gen.scratch1 + (AH-RAX), SZ_B); pavone@686: } else { pavone@612: sbb_rr(code, other_reg + (AH-RAX), opts->gen.scratch1 + (AH-RAX), SZ_B); pavone@686: } pavone@612: cmp_ir(code, 0xA, opts->gen.scratch1 + (AH-RAX), SZ_B); pavone@833: mov_ir(code, 0xA0, other_reg + (AH-RAX), SZ_B); pavone@612: code_ptr no_adjust = code->cur+1; pavone@612: //add correction factor if necessary pavone@612: jcc(code, CC_B, no_adjust); pavone@833: mov_ir(code, 6, opts->gen.scratch1 + (AH-RAX), SZ_B); pavone@833: mov_ir(code, inst->op == M68K_ABCD ? 0x9A : 0xA6, other_reg + (AH-RAX), SZ_B); pavone@833: code_ptr after_adjust = code->cur+1; pavone@833: jmp(code, after_adjust); pavone@833: pavone@612: *no_adjust = code->cur - (no_adjust+1); pavone@833: xor_rr(code, opts->gen.scratch1 + (AH-RAX), opts->gen.scratch1 + (AH-RAX), SZ_B); pavone@833: *after_adjust = code->cur - (after_adjust+1); pavone@833: pavone@833: //do op on full byte pavone@833: flag_to_carry(opts, FLAG_X); pavone@612: if (inst->op == M68K_ABCD) { pavone@833: adc_rr(code, other_reg, opts->gen.scratch1, SZ_B); pavone@612: } else { pavone@833: sbb_rr(code, other_reg, opts->gen.scratch1, SZ_B); pavone@686: } pavone@612: set_flag(opts, 0, FLAG_C); pavone@833: //determine if we need a correction on the upper nibble pavone@612: code_ptr def_adjust = code->cur+1; pavone@612: jcc(code, CC_C, def_adjust); pavone@833: cmp_rr(code, other_reg + (AH-RAX), opts->gen.scratch1, SZ_B); pavone@612: no_adjust = code->cur+1; pavone@612: jcc(code, CC_B, no_adjust); pavone@612: *def_adjust = code->cur - (def_adjust + 1); pavone@612: set_flag(opts, 1, FLAG_C); pavone@833: or_ir(code, 0x60, opts->gen.scratch1 + (AH-RAX), SZ_B); pavone@833: *no_adjust = code->cur - (no_adjust+1); pavone@612: if (inst->op == M68K_ABCD) { pavone@833: add_rr(code, opts->gen.scratch1 + (AH-RAX), opts->gen.scratch1, SZ_B); pavone@612: } else { pavone@833: sub_rr(code, opts->gen.scratch1 + (AH-RAX), opts->gen.scratch1, SZ_B); pavone@686: } pavone@833: code_ptr no_ensure_carry = code->cur+1; pavone@833: jcc(code, CC_NC, no_ensure_carry); pavone@833: set_flag(opts, 1, FLAG_C); pavone@833: *no_ensure_carry = code->cur - (no_ensure_carry+1); pavone@833: //restore RAX if necessary pavone@833: if (opts->gen.scratch2 > RBX) { pavone@833: mov_rr(code, opts->gen.scratch2, RAX, SZ_D); pavone@833: } pavone@833: //V flag is set based on the result of the addition/subtraction of the pavone@612: //result and the correction factor pavone@612: set_flag_cond(opts, CC_O, FLAG_V); pavone@833: pavone@612: flag_to_flag(opts, FLAG_C, FLAG_X); pavone@653: pavone@582: cmp_ir(code, 0, opts->gen.scratch1, SZ_B); pavone@612: set_flag_cond(opts, CC_S, FLAG_N); pavone@733: code_ptr no_setz = code->cur+1; pavone@733: jcc(code, CC_Z, no_setz); pavone@582: set_flag(opts, 0, FLAG_Z); pavone@733: *no_setz = code->cur - (no_setz + 1); pavone@582: if (dst_op->base != opts->gen.scratch1) { pavone@582: if (dst_op->mode == MODE_REG_DIRECT) { pavone@582: mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_B); pavone@582: } else { pavone@582: mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_B); pavone@73: } pavone@686: } pavone@582: m68k_save_result(inst, opts); pavone@686: } pavone@582: pavone@582: void translate_m68k_sl(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) pavone@582: { pavone@582: translate_shift(opts, inst, src_op, dst_op, shl_ir, shl_irdisp, shl_clr, shl_clrdisp, shr_ir, shr_irdisp); pavone@686: } pavone@582: pavone@582: void translate_m68k_asr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) pavone@582: { pavone@582: translate_shift(opts, inst, src_op, dst_op, sar_ir, sar_irdisp, sar_clr, sar_clrdisp, NULL, NULL); pavone@686: } pavone@582: pavone@582: void translate_m68k_lsr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) pavone@582: { pavone@582: translate_shift(opts, inst, src_op, dst_op, shr_ir, shr_irdisp, shr_clr, shr_clrdisp, shl_ir, shl_irdisp); pavone@582: } pavone@582: pavone@582: void translate_m68k_bit(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) pavone@582: { pavone@582: code_info *code = &opts->gen.code; pavone@582: cycles(&opts->gen, inst->extra.size == OPSIZE_BYTE ? 4 : ( pavone@457: inst->op == M68K_BTST ? 6 : (inst->op == M68K_BCLR ? 10 : 8)) pavone@686: ); pavone@582: if (src_op->mode == MODE_IMMED) { pavone@686: if (inst->extra.size == OPSIZE_BYTE) { pavone@582: src_op->disp &= 0x7; pavone@686: } pavone@582: if (dst_op->mode == MODE_REG_DIRECT) { pavone@582: op_ir(code, inst, src_op->disp, dst_op->base, inst->extra.size); pavone@686: } else { pavone@582: op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size); pavone@686: } pavone@686: } else { pavone@582: 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)) { pavone@582: if (dst_op->base == opts->gen.scratch1) { pavone@582: push_r(code, opts->gen.scratch2); pavone@582: if (src_op->mode == MODE_REG_DIRECT) { pavone@582: mov_rr(code, src_op->base, opts->gen.scratch2, SZ_B); pavone@61: } else { pavone@582: mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_B); pavone@154: } pavone@582: src_op->base = opts->gen.scratch2; pavone@61: } else { pavone@582: if (src_op->mode == MODE_REG_DIRECT) { pavone@582: mov_rr(code, src_op->base, opts->gen.scratch1, SZ_B); pavone@582: } else { pavone@582: mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_B); pavone@582: } pavone@582: src_op->base = opts->gen.scratch1; pavone@61: } pavone@226: } pavone@221: uint8_t size = inst->extra.size; pavone@582: if (dst_op->mode == MODE_REG_DISPLACE8) { pavone@582: if (src_op->base != opts->gen.scratch1 && src_op->base != opts->gen.scratch2) { pavone@582: if (src_op->mode == MODE_REG_DIRECT) { pavone@582: mov_rr(code, src_op->base, opts->gen.scratch1, SZ_D); pavone@686: } else { pavone@582: mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_D); pavone@582: src_op->mode = MODE_REG_DIRECT; pavone@686: } pavone@582: src_op->base = opts->gen.scratch1; pavone@686: } pavone@686: //b### with register destination is modulo 32 pavone@686: //x86 with a memory destination isn't modulo anything pavone@686: //so use an and here to force the value to be modulo 32 pavone@582: and_ir(code, 31, opts->gen.scratch1, SZ_D); pavone@686: } else if(inst->dst.addr_mode != MODE_REG) { pavone@686: //b### with memory destination is modulo 8 pavone@686: //x86-64 doesn't support 8-bit bit operations pavone@686: //so we fake it by forcing the bit number to be modulo 8 pavone@582: and_ir(code, 7, src_op->base, SZ_D); pavone@686: size = SZ_D; pavone@686: } pavone@976: if (dst_op->mode == MODE_IMMED) { pavone@976: dst_op->base = src_op->base == opts->gen.scratch1 ? opts->gen.scratch2 : opts->gen.scratch1; pavone@976: mov_ir(code, dst_op->disp, dst_op->base, SZ_B); pavone@976: dst_op->mode = MODE_REG_DIRECT; pavone@976: } pavone@582: if (dst_op->mode == MODE_REG_DIRECT) { pavone@582: op_rr(code, inst, src_op->base, dst_op->base, size); pavone@686: } else { pavone@582: op_rrdisp(code, inst, src_op->base, dst_op->base, dst_op->disp, size); pavone@686: } pavone@582: if (src_op->base == opts->gen.scratch2) { pavone@582: pop_r(code, opts->gen.scratch2); pavone@151: } pavone@686: } pavone@686: //x86 sets the carry flag to the value of the bit tested pavone@686: //68K sets the zero flag to the complement of the bit tested pavone@582: set_flag_cond(opts, CC_NC, FLAG_Z); pavone@686: if (inst->op != M68K_BTST) { pavone@582: m68k_save_result(inst, opts); pavone@686: } pavone@582: } pavone@582: pavone@582: void translate_m68k_chk(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) pavone@226: { pavone@582: code_info *code = &opts->gen.code; pavone@582: cycles(&opts->gen, 6); pavone@582: if (dst_op->mode == MODE_REG_DIRECT) { pavone@582: cmp_ir(code, 0, dst_op->base, inst->extra.size); pavone@686: } else { pavone@582: cmp_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size); pavone@686: } pavone@686: uint32_t isize; pavone@686: switch(inst->src.addr_mode) pavone@686: { pavone@686: case MODE_AREG_DISPLACE: pavone@686: case MODE_AREG_INDEX_DISP8: pavone@686: case MODE_ABSOLUTE_SHORT: pavone@686: case MODE_PC_INDEX_DISP8: pavone@686: case MODE_PC_DISPLACE: pavone@686: case MODE_IMMEDIATE: pavone@686: isize = 4; pavone@686: break; pavone@686: case MODE_ABSOLUTE: pavone@686: isize = 6; pavone@686: break; pavone@686: default: pavone@686: isize = 2; pavone@686: } pavone@582: //make sure we won't start a new chunk in the middle of these branches pavone@582: check_alloc_code(code, MAX_INST_LEN * 11); pavone@582: code_ptr passed = code->cur + 1; pavone@582: jcc(code, CC_GE, code->cur + 2); pavone@582: set_flag(opts, 1, FLAG_N); pavone@582: mov_ir(code, VECTOR_CHK, opts->gen.scratch2, SZ_D); pavone@582: mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D); pavone@582: jmp(code, opts->trap); pavone@582: *passed = code->cur - (passed+1); pavone@582: if (dst_op->mode == MODE_REG_DIRECT) { pavone@582: if (src_op->mode == MODE_REG_DIRECT) { pavone@582: cmp_rr(code, src_op->base, dst_op->base, inst->extra.size); pavone@582: } else if(src_op->mode == MODE_REG_DISPLACE8) { pavone@582: cmp_rdispr(code, src_op->base, src_op->disp, dst_op->base, inst->extra.size); pavone@686: } else { pavone@582: cmp_ir(code, src_op->disp, dst_op->base, inst->extra.size); pavone@686: } pavone@582: } else if(dst_op->mode == MODE_REG_DISPLACE8) { pavone@582: if (src_op->mode == MODE_REG_DIRECT) { pavone@582: cmp_rrdisp(code, src_op->base, dst_op->base, dst_op->disp, inst->extra.size); pavone@686: } else { pavone@582: cmp_irdisp(code, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size); pavone@171: } pavone@686: } pavone@582: passed = code->cur + 1; pavone@582: jcc(code, CC_LE, code->cur + 2); pavone@582: set_flag(opts, 0, FLAG_N); pavone@582: mov_ir(code, VECTOR_CHK, opts->gen.scratch2, SZ_D); pavone@582: mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D); pavone@582: jmp(code, opts->trap); pavone@582: *passed = code->cur - (passed+1); pavone@582: cycles(&opts->gen, 4); pavone@686: } pavone@582: pavone@582: void translate_m68k_div(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) pavone@686: { pavone@582: code_info *code = &opts->gen.code; pavone@582: check_alloc_code(code, MAX_NATIVE_SIZE); pavone@686: //TODO: cycle exact division pavone@582: cycles(&opts->gen, inst->op == M68K_DIVS ? 158 : 140); pavone@582: set_flag(opts, 0, FLAG_C); pavone@582: push_r(code, RDX); pavone@582: push_r(code, RAX); pavone@894: uint32_t tmp_stack_off = code->stack_off; pavone@582: if (dst_op->mode == MODE_REG_DIRECT) { pavone@582: mov_rr(code, dst_op->base, RAX, SZ_D); pavone@686: } else { pavone@582: mov_rdispr(code, dst_op->base, dst_op->disp, RAX, SZ_D); pavone@686: } pavone@582: if (src_op->mode == MODE_IMMED) { pavone@582: mov_ir(code, (src_op->disp & 0x8000) && inst->op == M68K_DIVS ? src_op->disp | 0xFFFF0000 : src_op->disp, opts->gen.scratch2, SZ_D); pavone@582: } else if (src_op->mode == MODE_REG_DIRECT) { pavone@686: if (inst->op == M68K_DIVS) { pavone@582: movsx_rr(code, src_op->base, opts->gen.scratch2, SZ_W, SZ_D); pavone@686: } else { pavone@582: movzx_rr(code, src_op->base, opts->gen.scratch2, SZ_W, SZ_D); pavone@686: } pavone@582: } else if (src_op->mode == MODE_REG_DISPLACE8) { pavone@686: if (inst->op == M68K_DIVS) { pavone@582: movsx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_W, SZ_D); pavone@686: } else { pavone@582: movzx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_W, SZ_D); pavone@71: } pavone@686: } pavone@611: uint32_t isize = 2; pavone@611: switch(inst->src.addr_mode) pavone@611: { pavone@611: case MODE_AREG_DISPLACE: pavone@611: case MODE_AREG_INDEX_DISP8: pavone@611: case MODE_ABSOLUTE_SHORT: pavone@611: case MODE_PC_INDEX_DISP8: pavone@611: case MODE_IMMEDIATE: pavone@653: isize = 4; pavone@611: break; pavone@611: case MODE_ABSOLUTE: pavone@611: isize = 6; pavone@611: break; pavone@611: } pavone@582: cmp_ir(code, 0, opts->gen.scratch2, SZ_D); pavone@582: check_alloc_code(code, 6*MAX_INST_LEN); pavone@582: code_ptr not_zero = code->cur + 1; pavone@582: jcc(code, CC_NZ, code->cur + 2); pavone@582: pop_r(code, RAX); pavone@582: pop_r(code, RDX); pavone@582: mov_ir(code, VECTOR_INT_DIV_ZERO, opts->gen.scratch2, SZ_D); pavone@611: mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D); pavone@582: jmp(code, opts->trap); pavone@894: pavone@894: code->stack_off = tmp_stack_off; pavone@582: *not_zero = code->cur - (not_zero+1); pavone@686: if (inst->op == M68K_DIVS) { pavone@582: cdq(code); pavone@686: } else { pavone@582: xor_rr(code, RDX, RDX, SZ_D); pavone@686: } pavone@686: if (inst->op == M68K_DIVS) { pavone@582: idiv_r(code, opts->gen.scratch2, SZ_D); pavone@686: } else { pavone@582: div_r(code, opts->gen.scratch2, SZ_D); pavone@686: } pavone@582: code_ptr skip_sec_check, norm_off; pavone@686: if (inst->op == M68K_DIVS) { pavone@582: cmp_ir(code, 0x8000, RAX, SZ_D); pavone@582: skip_sec_check = code->cur + 1; pavone@582: jcc(code, CC_GE, code->cur + 2); pavone@582: cmp_ir(code, -0x8000, RAX, SZ_D); pavone@582: norm_off = code->cur + 1; pavone@582: jcc(code, CC_L, code->cur + 2); pavone@686: } else { pavone@582: cmp_ir(code, 0x10000, RAX, SZ_D); pavone@582: norm_off = code->cur + 1; pavone@582: jcc(code, CC_NC, code->cur + 2); pavone@686: } pavone@582: if (dst_op->mode == MODE_REG_DIRECT) { pavone@582: mov_rr(code, RDX, dst_op->base, SZ_W); pavone@582: shl_ir(code, 16, dst_op->base, SZ_D); pavone@582: mov_rr(code, RAX, dst_op->base, SZ_W); pavone@686: } else { pavone@582: mov_rrdisp(code, RDX, dst_op->base, dst_op->disp, SZ_W); pavone@582: shl_irdisp(code, 16, dst_op->base, dst_op->disp, SZ_D); pavone@582: mov_rrdisp(code, RAX, dst_op->base, dst_op->disp, SZ_W); pavone@686: } pavone@582: cmp_ir(code, 0, RAX, SZ_W); pavone@582: pop_r(code, RAX); pavone@732: if (dst_op->base == RDX) { pavone@732: update_flags(opts, V0|Z|N); pavone@732: add_ir(code, sizeof(void *), RSP, SZ_D); pavone@732: } else { pavone@732: pop_r(code, RDX); pavone@732: update_flags(opts, V0|Z|N); pavone@732: } pavone@582: code_ptr end_off = code->cur + 1; pavone@582: jmp(code, code->cur + 2); pavone@894: code->stack_off = tmp_stack_off; pavone@582: *norm_off = code->cur - (norm_off + 1); pavone@686: if (inst->op == M68K_DIVS) { pavone@582: *skip_sec_check = code->cur - (skip_sec_check+1); pavone@686: } pavone@582: pop_r(code, RAX); pavone@582: pop_r(code, RDX); pavone@582: set_flag(opts, 1, FLAG_V); pavone@582: *end_off = code->cur - (end_off + 1); pavone@686: } pavone@582: pavone@582: void translate_m68k_exg(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) pavone@582: { pavone@582: code_info *code = &opts->gen.code; pavone@582: cycles(&opts->gen, 6); pavone@582: if (dst_op->mode == MODE_REG_DIRECT) { pavone@582: mov_rr(code, dst_op->base, opts->gen.scratch2, SZ_D); pavone@582: if (src_op->mode == MODE_REG_DIRECT) { pavone@582: mov_rr(code, src_op->base, dst_op->base, SZ_D); pavone@582: mov_rr(code, opts->gen.scratch2, src_op->base, SZ_D); pavone@686: } else { pavone@582: mov_rdispr(code, src_op->base, src_op->disp, dst_op->base, SZ_D); pavone@582: mov_rrdisp(code, opts->gen.scratch2, src_op->base, src_op->disp, SZ_D); pavone@686: } pavone@686: } else { pavone@582: mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_D); pavone@582: if (src_op->mode == MODE_REG_DIRECT) { pavone@582: mov_rrdisp(code, src_op->base, dst_op->base, dst_op->disp, SZ_D); pavone@582: mov_rr(code, opts->gen.scratch2, src_op->base, SZ_D); pavone@686: } else { pavone@582: mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_D); pavone@582: mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_D); pavone@582: mov_rrdisp(code, opts->gen.scratch2, src_op->base, src_op->disp, SZ_D); pavone@151: } pavone@686: } pavone@686: } pavone@582: pavone@582: void translate_m68k_mul(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) pavone@582: { pavone@582: code_info *code = &opts->gen.code; pavone@582: cycles(&opts->gen, 70); //TODO: Calculate the actual value based on the value of the parameter pavone@582: if (src_op->mode == MODE_IMMED) { pavone@582: 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); pavone@582: } else if (src_op->mode == MODE_REG_DIRECT) { pavone@686: if (inst->op == M68K_MULS) { pavone@582: movsx_rr(code, src_op->base, opts->gen.scratch1, SZ_W, SZ_D); pavone@582: } else { pavone@686: movzx_rr(code, src_op->base, opts->gen.scratch1, SZ_W, SZ_D); pavone@686: } pavone@686: } else { pavone@686: if (inst->op == M68K_MULS) { pavone@682: movsx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D); pavone@686: } else { pavone@682: movzx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D); pavone@582: } pavone@686: } pavone@582: uint8_t dst_reg; pavone@582: if (dst_op->mode == MODE_REG_DIRECT) { pavone@582: dst_reg = dst_op->base; pavone@686: if (inst->op == M68K_MULS) { pavone@582: movsx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D); pavone@686: } else { pavone@682: movzx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D); pavone@686: } pavone@686: } else { pavone@582: dst_reg = opts->gen.scratch2; pavone@686: if (inst->op == M68K_MULS) { pavone@582: movsx_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_W, SZ_D); pavone@686: } else { pavone@582: movzx_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_W, SZ_D); pavone@582: } pavone@686: } pavone@582: imul_rr(code, opts->gen.scratch1, dst_reg, SZ_D); pavone@582: if (dst_op->mode == MODE_REG_DISPLACE8) { pavone@582: mov_rrdisp(code, dst_reg, dst_op->base, dst_op->disp, SZ_D); pavone@686: } pavone@582: cmp_ir(code, 0, dst_reg, SZ_D); pavone@582: update_flags(opts, N|Z|V0|C0); pavone@686: } pavone@582: pavone@582: void translate_m68k_negx(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) pavone@582: { pavone@582: code_info *code = &opts->gen.code; pavone@582: cycles(&opts->gen, BUS); pavone@582: if (dst_op->mode == MODE_REG_DIRECT) { pavone@582: if (dst_op->base == opts->gen.scratch1) { pavone@582: push_r(code, opts->gen.scratch2); pavone@582: xor_rr(code, opts->gen.scratch2, opts->gen.scratch2, inst->extra.size); pavone@582: flag_to_carry(opts, FLAG_X); pavone@582: sbb_rr(code, dst_op->base, opts->gen.scratch2, inst->extra.size); pavone@582: mov_rr(code, opts->gen.scratch2, dst_op->base, inst->extra.size); pavone@582: pop_r(code, opts->gen.scratch2); pavone@173: } else { pavone@567: xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, inst->extra.size); pavone@567: flag_to_carry(opts, FLAG_X); pavone@582: sbb_rr(code, dst_op->base, opts->gen.scratch1, inst->extra.size); pavone@582: mov_rr(code, opts->gen.scratch1, dst_op->base, inst->extra.size); pavone@106: } pavone@686: } else { pavone@582: xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, inst->extra.size); pavone@582: flag_to_carry(opts, FLAG_X); pavone@582: sbb_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch1, inst->extra.size); pavone@582: mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, inst->extra.size); pavone@686: } pavone@582: set_flag_cond(opts, CC_C, FLAG_C); pavone@582: code_ptr after_flag_set = code->cur + 1; pavone@582: jcc(code, CC_Z, code->cur + 2); pavone@582: set_flag(opts, 0, FLAG_Z); pavone@582: *after_flag_set = code->cur - (after_flag_set+1); pavone@582: set_flag_cond(opts, CC_S, FLAG_N); pavone@582: set_flag_cond(opts, CC_O, FLAG_V); pavone@686: if (opts->flag_regs[FLAG_C] >= 0) { pavone@582: flag_to_flag(opts, FLAG_C, FLAG_X); pavone@686: } else { pavone@582: set_flag_cond(opts, CC_C, FLAG_X); pavone@686: } pavone@582: m68k_save_result(inst, opts); pavone@686: } pavone@582: pavone@582: void translate_m68k_rot(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) pavone@582: { pavone@582: code_info *code = &opts->gen.code; pavone@582: int32_t init_flags = C|V0; pavone@686: if (inst->src.addr_mode == MODE_UNUSED) { pavone@582: cycles(&opts->gen, BUS); pavone@686: //Memory rotate pavone@582: if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { pavone@582: flag_to_carry(opts, FLAG_X); pavone@582: init_flags |= X; pavone@106: } pavone@582: op_ir(code, inst, 1, dst_op->base, inst->extra.size); pavone@582: update_flags(opts, init_flags); pavone@582: cmp_ir(code, 0, dst_op->base, inst->extra.size); pavone@582: update_flags(opts, Z|N); pavone@582: m68k_save_result(inst, opts); pavone@686: } else { pavone@582: if (src_op->mode == MODE_IMMED) { pavone@582: cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 8 : 6) + src_op->disp*2); pavone@577: if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { pavone@577: flag_to_carry(opts, FLAG_X); pavone@577: init_flags |= X; pavone@122: } pavone@582: if (dst_op->mode == MODE_REG_DIRECT) { pavone@582: op_ir(code, inst, src_op->disp, dst_op->base, inst->extra.size); pavone@686: } else { pavone@582: op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size); pavone@686: } pavone@582: update_flags(opts, init_flags); pavone@686: } else { pavone@582: if (src_op->mode == MODE_REG_DIRECT) { pavone@582: if (src_op->base != opts->gen.scratch1) { pavone@582: mov_rr(code, src_op->base, opts->gen.scratch1, SZ_B); pavone@686: } pavone@582: } else { pavone@582: mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_B); pavone@686: } pavone@582: and_ir(code, 63, opts->gen.scratch1, SZ_D); pavone@582: code_ptr zero_off = code->cur + 1; pavone@582: jcc(code, CC_Z, code->cur + 2); pavone@667: //add 2 cycles for every bit shifted pavone@667: mov_ir(code, 2 * opts->gen.clock_divider, opts->gen.scratch2, SZ_D); pavone@667: imul_rr(code, RCX, opts->gen.scratch2, SZ_D); pavone@667: add_rr(code, opts->gen.scratch2, opts->gen.cycles, SZ_D); pavone@582: cmp_ir(code, 32, opts->gen.scratch1, SZ_B); pavone@582: code_ptr norm_off = code->cur + 1; pavone@582: jcc(code, CC_L, code->cur + 2); pavone@582: if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { pavone@582: flag_to_carry(opts, FLAG_X); pavone@582: init_flags |= X; pavone@686: } else { pavone@582: sub_ir(code, 32, opts->gen.scratch1, SZ_B); pavone@686: } pavone@582: if (dst_op->mode == MODE_REG_DIRECT) { pavone@582: op_ir(code, inst, 31, dst_op->base, inst->extra.size); pavone@582: op_ir(code, inst, 1, dst_op->base, inst->extra.size); pavone@686: } else { pavone@582: op_irdisp(code, inst, 31, dst_op->base, dst_op->disp, inst->extra.size); pavone@582: op_irdisp(code, inst, 1, dst_op->base, dst_op->disp, inst->extra.size); pavone@686: } pavone@582: pavone@582: if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { pavone@582: set_flag_cond(opts, CC_C, FLAG_X); pavone@582: sub_ir(code, 32, opts->gen.scratch1, SZ_B); pavone@582: *norm_off = code->cur - (norm_off+1); pavone@582: flag_to_carry(opts, FLAG_X); pavone@686: } else { pavone@582: *norm_off = code->cur - (norm_off+1); pavone@686: } pavone@582: if (dst_op->mode == MODE_REG_DIRECT) { pavone@582: op_r(code, inst, dst_op->base, inst->extra.size); pavone@686: } else { pavone@582: op_rdisp(code, inst, dst_op->base, dst_op->disp, inst->extra.size); pavone@686: } pavone@582: update_flags(opts, init_flags); pavone@582: code_ptr end_off = code->cur + 1; pavone@582: jmp(code, code->cur + 2); pavone@582: *zero_off = code->cur - (zero_off+1); pavone@582: if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { pavone@582: //Carry flag is set to X flag when count is 0, this is different from ROR/ROL pavone@582: flag_to_flag(opts, FLAG_X, FLAG_C); pavone@686: } else { pavone@582: set_flag(opts, 0, FLAG_C); pavone@686: } pavone@582: *end_off = code->cur - (end_off+1); pavone@686: } pavone@582: if (dst_op->mode == MODE_REG_DIRECT) { pavone@582: cmp_ir(code, 0, dst_op->base, inst->extra.size); pavone@686: } else { pavone@582: cmp_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size); pavone@686: } pavone@682: update_flags(opts, Z|N); pavone@686: } pavone@686: } pavone@582: pavone@582: #define BIT_SUPERVISOR 5 pavone@582: pavone@990: void m68k_trap_if_not_supervisor(m68k_options *opts, m68kinst *inst) pavone@990: { pavone@990: code_info *code = &opts->gen.code; pavone@990: //check supervisor bit in SR and trap if not in supervisor mode pavone@990: bt_irdisp(code, BIT_SUPERVISOR, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); pavone@990: code_ptr in_sup_mode = code->cur + 1; pavone@990: jcc(code, CC_C, code->cur + 2); pavone@990: pavone@990: ldi_native(opts, VECTOR_PRIV_VIOLATION, opts->gen.scratch2); pavone@990: ldi_native(opts, inst->address, opts->gen.scratch1); pavone@990: jmp(code, opts->trap); pavone@990: pavone@990: *in_sup_mode = code->cur - (in_sup_mode + 1); pavone@990: } pavone@990: pavone@584: void translate_m68k_andi_ori_ccr_sr(m68k_options *opts, m68kinst *inst) pavone@582: { pavone@582: code_info *code = &opts->gen.code; pavone@990: if (inst->op == M68K_ANDI_SR || inst->op == M68K_ORI_SR) { pavone@990: m68k_trap_if_not_supervisor(opts, inst); pavone@990: } pavone@582: cycles(&opts->gen, 20); pavone@582: uint32_t flag_mask = 0; pavone@584: uint32_t base_flag = inst->op == M68K_ANDI_SR || inst->op == M68K_ANDI_CCR ? X0 : X1; pavone@584: for (int i = 0; i < 5; i++) pavone@584: { pavone@757: if ((base_flag == X0) ^ ((inst->src.params.immed & 1 << i) > 0)) pavone@584: { pavone@584: flag_mask |= base_flag << ((4 - i) * 3); pavone@686: } pavone@686: } pavone@582: update_flags(opts, flag_mask); pavone@584: if (inst->op == M68K_ANDI_SR || inst->op == M68K_ORI_SR) { pavone@584: if (inst->op == M68K_ANDI_SR) { pavone@584: and_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); pavone@686: } else { pavone@584: or_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); pavone@686: } pavone@605: if (inst->op == M68K_ANDI_SR && !(inst->src.params.immed & (1 << (BIT_SUPERVISOR + 8)))) { pavone@446: //leave supervisor mode pavone@574: swap_ssp_usp(opts); pavone@686: } pavone@584: if ((inst->op == M68K_ANDI_SR && (inst->src.params.immed & 0x700) != 0x700) pavone@584: || (inst->op == M68K_ORI_SR && inst->src.params.immed & 0x700)) { pavone@846: if (inst->op == M68K_ANDI_SR) { pavone@846: //set int pending flag in case we trigger an interrupt as a result of the mask change pavone@996: mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B); pavone@846: } pavone@582: call(code, opts->do_sync); pavone@686: } pavone@686: } pavone@686: } pavone@582: pavone@582: void translate_m68k_eori_ccr_sr(m68k_options *opts, m68kinst *inst) pavone@582: { pavone@582: code_info *code = &opts->gen.code; pavone@990: if (inst->op == M68K_EORI_SR) { pavone@990: m68k_trap_if_not_supervisor(opts, inst); pavone@990: } pavone@582: cycles(&opts->gen, 20); pavone@582: if (inst->src.params.immed & 0x1) { pavone@582: xor_flag(opts, 1, FLAG_C); pavone@686: } pavone@582: if (inst->src.params.immed & 0x2) { pavone@582: xor_flag(opts, 1, FLAG_V); pavone@686: } pavone@582: if (inst->src.params.immed & 0x4) { pavone@582: xor_flag(opts, 1, FLAG_Z); pavone@686: } pavone@582: if (inst->src.params.immed & 0x8) { pavone@582: xor_flag(opts, 1, FLAG_N); pavone@686: } pavone@582: if (inst->src.params.immed & 0x10) { pavone@582: xor_flag(opts, 1, FLAG_X); pavone@686: } pavone@846: if (inst->op == M68K_EORI_SR) { pavone@582: xor_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); pavone@582: if (inst->src.params.immed & 0x700) { pavone@846: //set int pending flag in case we trigger an interrupt as a result of the mask change pavone@996: mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B); pavone@582: call(code, opts->do_sync); pavone@686: } pavone@686: } pavone@686: } pavone@582: pavone@586: void set_all_flags(m68k_options *opts, uint8_t flags) pavone@586: { pavone@586: uint32_t flag_mask = flags & 0x10 ? X1 : X0; pavone@586: flag_mask |= flags & 0x8 ? N1 : N0; pavone@586: flag_mask |= flags & 0x4 ? Z1 : Z0; pavone@586: flag_mask |= flags & 0x2 ? V1 : V0; pavone@586: flag_mask |= flags & 0x1 ? C1 : C0; pavone@586: update_flags(opts, flag_mask); pavone@686: } pavone@586: pavone@582: void translate_m68k_move_ccr_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) pavone@582: { pavone@582: code_info *code = &opts->gen.code; pavone@990: if (inst->op == M68K_MOVE_SR) { pavone@990: m68k_trap_if_not_supervisor(opts, inst); pavone@990: } pavone@582: if (src_op->mode == MODE_IMMED) { pavone@586: set_all_flags(opts, src_op->disp); pavone@582: if (inst->op == M68K_MOVE_SR) { pavone@582: mov_irdisp(code, (src_op->disp >> 8), opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); pavone@582: if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) { pavone@582: //leave supervisor mode pavone@585: swap_ssp_usp(opts); pavone@686: } pavone@846: if (((src_op->disp >> 8) & 7) < 7) { pavone@846: //set int pending flag in case we trigger an interrupt as a result of the mask change pavone@996: mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B); pavone@846: } pavone@582: call(code, opts->do_sync); pavone@686: } pavone@582: cycles(&opts->gen, 12); pavone@686: } else { pavone@582: if (src_op->base != opts->gen.scratch1) { pavone@582: if (src_op->mode == MODE_REG_DIRECT) { pavone@582: mov_rr(code, src_op->base, opts->gen.scratch1, SZ_W); pavone@582: } else { pavone@582: mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W); pavone@582: } pavone@582: } pavone@698: if (inst->op == M68K_MOVE_SR) { pavone@698: call(code, opts->set_sr); pavone@698: call(code, opts->do_sync); pavone@698: } else { pavone@698: call(code, opts->set_ccr); pavone@698: } pavone@582: cycles(&opts->gen, 12); pavone@686: } pavone@686: } pavone@582: pavone@582: void translate_m68k_stop(m68k_options *opts, m68kinst *inst) pavone@582: { pavone@990: m68k_trap_if_not_supervisor(opts, inst); pavone@686: //manual says 4 cycles, but it has to be at least 8 since it's a 2-word instruction pavone@686: //possibly even 12 since that's how long MOVE to SR takes pavone@582: //On further thought prefetch + the fact that this stops the CPU may make pavone@582: //Motorola's accounting make sense here pavone@582: code_info *code = &opts->gen.code; pavone@582: cycles(&opts->gen, BUS*2); pavone@586: set_all_flags(opts, inst->src.params.immed); pavone@582: mov_irdisp(code, (inst->src.params.immed >> 8), opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); pavone@686: if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) { pavone@686: //leave supervisor mode pavone@582: swap_ssp_usp(opts); pavone@686: } pavone@582: code_ptr loop_top = code->cur; pavone@985: call(code, opts->do_sync); pavone@985: cmp_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D); pavone@985: code_ptr normal_cycle_up = code->cur + 1; pavone@985: jcc(code, CC_A, code->cur + 2); pavone@985: cycles(&opts->gen, BUS); pavone@985: code_ptr after_cycle_up = code->cur + 1; pavone@985: jmp(code, code->cur + 2); pavone@985: *normal_cycle_up = code->cur - (normal_cycle_up + 1); pavone@985: mov_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D); pavone@985: *after_cycle_up = code->cur - (after_cycle_up+1); pavone@985: cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), opts->gen.cycles, SZ_D); pavone@582: jcc(code, CC_C, loop_top); pavone@985: //set int pending flag so interrupt fires immediately after stop is done pavone@996: mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B); pavone@686: } pavone@582: pavone@839: void translate_m68k_trapv(m68k_options *opts, m68kinst *inst) pavone@839: { pavone@839: code_info *code = &opts->gen.code; pavone@839: cycles(&opts->gen, BUS); pavone@839: flag_to_carry(opts, FLAG_V); pavone@839: code_ptr no_trap = code->cur + 1; pavone@839: jcc(code, CC_NC, no_trap); pavone@839: ldi_native(opts, VECTOR_TRAPV, opts->gen.scratch2); pavone@839: ldi_native(opts, inst->address+2, opts->gen.scratch1); pavone@839: jmp(code, opts->trap); pavone@839: *no_trap = code->cur - (no_trap + 1); pavone@839: } pavone@839: pavone@987: void translate_m68k_odd(m68k_options *opts, m68kinst *inst) pavone@987: { pavone@987: code_info *code = &opts->gen.code; pavone@987: //swap USP and SSP if not already in supervisor mode pavone@987: check_user_mode_swap_ssp_usp(opts); pavone@987: //save PC pavone@987: subi_areg(opts, 4, 7); pavone@987: areg_to_native(opts, 7, opts->gen.scratch2); pavone@987: mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, last_prefetch_address), opts->gen.scratch1, SZ_D); pavone@987: call(code, opts->write_32_lowfirst); pavone@987: //save status register pavone@987: subi_areg(opts, 2, 7); pavone@987: call(code, opts->get_sr); pavone@987: areg_to_native(opts, 7, opts->gen.scratch2); pavone@987: call(code, opts->write_16); pavone@987: //save instruction register pavone@987: subi_areg(opts, 2, 7); pavone@989: //calculate IR pavone@989: push_r(code, opts->gen.context_reg); pavone@989: call(code, opts->gen.save_context); pavone@989: call_args_abi(code, (code_ptr)m68k_get_ir, 1, opts->gen.context_reg); pavone@989: mov_rr(code, RAX, opts->gen.scratch1, SZ_W); pavone@989: pop_r(code, opts->gen.context_reg); pavone@989: push_r(code, RAX); //save it for use in the "info" word pavone@989: call(code, opts->gen.load_context); pavone@989: //write it to the stack pavone@987: areg_to_native(opts, 7, opts->gen.scratch2); pavone@987: call(code, opts->write_16); pavone@987: //save access address pavone@987: subi_areg(opts, 4, 7); pavone@987: mov_ir(code, inst->address, opts->gen.scratch1, SZ_D); pavone@987: areg_to_native(opts, 7, opts->gen.scratch2); pavone@987: call(code, opts->write_32_lowfirst); pavone@987: //save FC, I/N and R/W word' pavone@987: xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_W); pavone@987: //FC3 is basically the same as the supervisor bit pavone@987: mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, status), opts->gen.scratch1, SZ_B); pavone@987: shr_ir(code, 3, opts->gen.scratch1, SZ_B); pavone@987: and_ir(code, 4, opts->gen.scratch1, SZ_B); pavone@987: //set FC1 to one to indicate instruction fetch, and R/W to indicate read pavone@987: or_ir(code, 0x12, opts->gen.scratch1, SZ_B); pavone@989: //set undefined bits to IR value pavone@989: pop_r(code, opts->gen.scratch2); pavone@989: and_ir(code, 0xFFE0, opts->gen.scratch2, SZ_W); pavone@989: or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_W); pavone@987: subi_areg(opts, 2, 7); pavone@987: areg_to_native(opts, 7, opts->gen.scratch2); pavone@987: call(code, opts->write_16); pavone@987: //set supervisor bit pavone@987: or_irdisp(code, 0x20, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); pavone@987: //load vector address pavone@987: mov_ir(code, 4 * VECTOR_ADDRESS_ERROR, opts->gen.scratch1, SZ_D); pavone@987: call(code, opts->read_32); pavone@987: call(code, opts->native_addr_and_sync); pavone@987: cycles(&opts->gen, 18); pavone@987: jmp_r(code, opts->gen.scratch1); pavone@987: } pavone@987: pavone@582: void translate_m68k_move_from_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) pavone@582: { pavone@582: code_info *code = &opts->gen.code; pavone@582: call(code, opts->get_sr); pavone@582: if (dst_op->mode == MODE_REG_DIRECT) { pavone@582: mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_W); pavone@686: } else { pavone@582: mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_W); pavone@686: } pavone@582: m68k_save_result(inst, opts); pavone@582: } pavone@582: pavone@570: void translate_out_of_bounds(code_info *code) pavone@319: { pavone@570: xor_rr(code, RDI, RDI, SZ_D); pavone@656: call_args(code, (code_ptr)exit, 1, RDI); pavone@319: } pavone@319: pavone@981: void m68k_set_last_prefetch(m68k_options *opts, uint32_t address) pavone@981: { pavone@981: mov_irdisp(&opts->gen.code, address, opts->gen.context_reg, offsetof(m68k_context, last_prefetch_address), SZ_D); pavone@981: } pavone@981: pavone@587: void nop_fill_or_jmp_next(code_info *code, code_ptr old_end, code_ptr next_inst) pavone@587: { pavone@587: if (next_inst == old_end && next_inst - code->cur < 2) { pavone@587: while (code->cur < old_end) { pavone@587: *(code->cur++) = 0x90; //NOP pavone@686: } pavone@686: } else { pavone@587: jmp(code, next_inst); pavone@193: } pavone@193: } pavone@193: pavone@193: m68k_context * m68k_handle_code_write(uint32_t address, m68k_context * context) pavone@193: { pavone@985: m68k_options * options = context->options; pavone@985: //TODO: Modify gen_mem_fun so that it passes the raw address instead of the masked one, then remove the OR below pavone@985: uint32_t inst_start = get_instruction_start(options, context->native_code_map, address | 0xE00000); pavone@193: if (inst_start) { pavone@567: code_info *code = &options->gen.code; pavone@726: code_ptr dst = get_native_address(context->options, inst_start); pavone@902: code_info orig = {dst, dst + 128, 0}; pavone@567: mov_ir(&orig, inst_start, options->gen.scratch2, SZ_D); pavone@567: pavone@543: if (!options->retrans_stub) { pavone@567: options->retrans_stub = code->cur; pavone@567: call(code, options->gen.save_context); pavone@567: push_r(code, options->gen.context_reg); pavone@656: call_args(code,(code_ptr)m68k_retranslate_inst, 2, options->gen.scratch2, options->gen.context_reg); pavone@567: pop_r(code, options->gen.context_reg); pavone@567: mov_rr(code, RAX, options->gen.scratch1, SZ_PTR); pavone@567: call(code, options->gen.load_context); pavone@567: jmp_r(code, options->gen.scratch1); pavone@686: } pavone@567: jmp(&orig, options->retrans_stub); pavone@193: } pavone@193: return context; pavone@193: } pavone@193: pavone@558: void insert_breakpoint(m68k_context * context, uint32_t address, code_ptr bp_handler) pavone@184: { pavone@558: static code_ptr bp_stub = NULL; pavone@569: m68k_options * opts = context->options; pavone@567: code_info native; pavone@567: native.cur = get_native_address_trans(context, address); pavone@567: native.last = native.cur + 128; pavone@908: native.stack_off = 0; pavone@567: code_ptr start_native = native.cur; pavone@567: mov_ir(&native, address, opts->gen.scratch1, SZ_D); pavone@184: if (!bp_stub) { pavone@567: code_info *code = &opts->gen.code; pavone@654: check_code_prologue(code); pavone@567: bp_stub = code->cur; pavone@567: call(&native, bp_stub); pavone@447: pavone@908: uint32_t tmp_stack_off = code->stack_off; pavone@184: //Calculate length of prologue pavone@567: check_cycles_int(&opts->gen, address); pavone@567: int check_int_size = code->cur-bp_stub; pavone@567: code->cur = bp_stub; pavone@908: code->stack_off = tmp_stack_off; pavone@447: pavone@184: //Save context and call breakpoint handler pavone@567: call(code, opts->gen.save_context); pavone@567: push_r(code, opts->gen.scratch1); pavone@657: call_args_abi(code, bp_handler, 2, opts->gen.context_reg, opts->gen.scratch1); pavone@567: mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR); pavone@184: //Restore context pavone@567: call(code, opts->gen.load_context); pavone@567: pop_r(code, opts->gen.scratch1); pavone@184: //do prologue stuff pavone@567: cmp_rr(code, opts->gen.cycles, opts->gen.limit, SZ_D); pavone@567: code_ptr jmp_off = code->cur + 1; pavone@567: jcc(code, CC_NC, code->cur + 7); pavone@567: call(code, opts->gen.handle_cycle_limit_int); pavone@567: *jmp_off = code->cur - (jmp_off+1); pavone@184: //jump back to body of translated instruction pavone@567: pop_r(code, opts->gen.scratch1); pavone@567: add_ir(code, check_int_size - (native.cur-start_native), opts->gen.scratch1, SZ_PTR); pavone@567: jmp_r(code, opts->gen.scratch1); pavone@908: code->stack_off = tmp_stack_off; pavone@184: } else { pavone@567: call(&native, bp_stub); pavone@184: } pavone@184: } pavone@184: pavone@667: void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks, uint32_t clock_divider) pavone@18: { pavone@440: memset(opts, 0, sizeof(*opts)); pavone@653: opts->gen.memmap = memmap; pavone@653: opts->gen.memmap_chunks = num_chunks; pavone@589: opts->gen.address_size = SZ_D; pavone@589: opts->gen.address_mask = 0xFFFFFF; pavone@596: opts->gen.byte_swap = 1; pavone@589: opts->gen.max_address = 0x1000000; pavone@589: opts->gen.bus_cycles = BUS; pavone@667: opts->gen.clock_divider = clock_divider; pavone@589: opts->gen.mem_ptr_off = offsetof(m68k_context, mem_pointers); pavone@589: opts->gen.ram_flags_off = offsetof(m68k_context, ram_code_flags); pavone@620: opts->gen.ram_flags_shift = 11; pavone@18: for (int i = 0; i < 8; i++) pavone@567: { pavone@18: opts->dregs[i] = opts->aregs[i] = -1; pavone@567: } pavone@548: #ifdef X86_64 pavone@18: opts->dregs[0] = R10; pavone@18: opts->dregs[1] = R11; pavone@18: opts->dregs[2] = R12; pavone@423: opts->dregs[3] = R8; pavone@18: opts->aregs[0] = R13; pavone@18: opts->aregs[1] = R14; pavone@423: opts->aregs[2] = R9; pavone@18: opts->aregs[7] = R15; pavone@539: pavone@539: opts->flag_regs[0] = -1; pavone@539: opts->flag_regs[1] = RBX; pavone@539: opts->flag_regs[2] = RDX; pavone@539: opts->flag_regs[3] = BH; pavone@539: opts->flag_regs[4] = DH; pavone@567: pavone@567: opts->gen.scratch2 = RDI; pavone@548: #else pavone@548: opts->dregs[0] = RDX; pavone@548: opts->aregs[7] = RDI; pavone@548: pavone@548: for (int i = 0; i < 5; i++) pavone@567: { pavone@548: opts->flag_regs[i] = -1; pavone@567: } pavone@567: opts->gen.scratch2 = RBX; pavone@548: #endif pavone@567: opts->gen.context_reg = RSI; pavone@567: opts->gen.cycles = RAX; pavone@567: opts->gen.limit = RBP; pavone@567: opts->gen.scratch1 = RCX; pavone@987: opts->gen.align_error_mask = 1; pavone@548: pavone@548: pavone@558: opts->gen.native_code_map = malloc(sizeof(native_map_slot) * NATIVE_MAP_CHUNKS); pavone@558: memset(opts->gen.native_code_map, 0, sizeof(native_map_slot) * NATIVE_MAP_CHUNKS); pavone@558: opts->gen.deferred = NULL; pavone@690: pavone@690: uint32_t inst_size_size = sizeof(uint8_t *) * ram_size(&opts->gen) / 1024; pavone@690: opts->gen.ram_inst_sizes = malloc(inst_size_size); pavone@690: memset(opts->gen.ram_inst_sizes, 0, inst_size_size); pavone@447: pavone@567: code_info *code = &opts->gen.code; pavone@567: init_code_info(code); pavone@539: pavone@567: opts->gen.save_context = code->cur; pavone@539: for (int i = 0; i < 5; i++) pavone@539: if (opts->flag_regs[i] >= 0) { pavone@567: mov_rrdisp(code, opts->flag_regs[i], opts->gen.context_reg, offsetof(m68k_context, flags) + i, SZ_B); pavone@539: } pavone@539: for (int i = 0; i < 8; i++) pavone@539: { pavone@539: if (opts->dregs[i] >= 0) { pavone@567: mov_rrdisp(code, opts->dregs[i], opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t) * i, SZ_D); pavone@539: } pavone@539: if (opts->aregs[i] >= 0) { pavone@567: mov_rrdisp(code, opts->aregs[i], opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * i, SZ_D); pavone@539: } pavone@539: } pavone@567: mov_rrdisp(code, opts->gen.cycles, opts->gen.context_reg, offsetof(m68k_context, current_cycle), SZ_D); pavone@567: retn(code); pavone@539: pavone@567: opts->gen.load_context = code->cur; pavone@539: for (int i = 0; i < 5; i++) pavone@690: { pavone@539: if (opts->flag_regs[i] >= 0) { pavone@567: mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + i, opts->flag_regs[i], SZ_B); pavone@539: } pavone@690: } pavone@539: for (int i = 0; i < 8; i++) pavone@539: { pavone@539: if (opts->dregs[i] >= 0) { pavone@567: mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t) * i, opts->dregs[i], SZ_D); pavone@539: } pavone@539: if (opts->aregs[i] >= 0) { pavone@567: mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * i, opts->aregs[i], SZ_D); pavone@539: } pavone@539: } pavone@656: mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, current_cycle), opts->gen.cycles, SZ_D); pavone@656: mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, target_cycle), opts->gen.limit, SZ_D); pavone@567: retn(code); pavone@539: pavone@567: opts->start_context = (start_fun)code->cur; pavone@665: save_callee_save_regs(code); pavone@550: #ifdef X86_64 pavone@567: if (opts->gen.scratch2 != RDI) { pavone@567: mov_rr(code, RDI, opts->gen.scratch2, SZ_PTR); pavone@548: } pavone@550: #else pavone@567: mov_rdispr(code, RSP, 20, opts->gen.scratch2, SZ_D); pavone@567: mov_rdispr(code, RSP, 24, opts->gen.context_reg, SZ_D); pavone@550: #endif pavone@567: call(code, opts->gen.load_context); pavone@567: call_r(code, opts->gen.scratch2); pavone@567: call(code, opts->gen.save_context); pavone@665: restore_callee_save_regs(code); pavone@567: retn(code); pavone@540: pavone@567: opts->native_addr = code->cur; pavone@567: call(code, opts->gen.save_context); pavone@567: push_r(code, opts->gen.context_reg); pavone@656: call_args(code, (code_ptr)get_native_address_trans, 2, opts->gen.context_reg, opts->gen.scratch1); pavone@567: mov_rr(code, RAX, opts->gen.scratch1, SZ_PTR); //move result to scratch reg pavone@567: pop_r(code, opts->gen.context_reg); pavone@567: call(code, opts->gen.load_context); pavone@567: retn(code); pavone@544: pavone@567: opts->native_addr_and_sync = code->cur; pavone@567: call(code, opts->gen.save_context); pavone@567: push_r(code, opts->gen.scratch1); pavone@667: pavone@656: xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_D); pavone@656: call_args_abi(code, (code_ptr)sync_components, 2, opts->gen.context_reg, opts->gen.scratch1); pavone@567: pop_r(code, RSI); //restore saved address from opts->gen.scratch1 pavone@567: push_r(code, RAX); //save context pointer for later pavone@656: call_args(code, (code_ptr)get_native_address_trans, 2, RAX, RSI); pavone@567: mov_rr(code, RAX, opts->gen.scratch1, SZ_PTR); //move result to scratch reg pavone@567: pop_r(code, opts->gen.context_reg); pavone@567: call(code, opts->gen.load_context); pavone@567: retn(code); pavone@544: pavone@567: opts->gen.handle_cycle_limit = code->cur; pavone@656: cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), opts->gen.cycles, SZ_D); pavone@567: code_ptr skip_sync = code->cur + 1; pavone@567: jcc(code, CC_C, code->cur + 2); pavone@567: opts->do_sync = code->cur; pavone@567: push_r(code, opts->gen.scratch1); pavone@567: push_r(code, opts->gen.scratch2); pavone@567: call(code, opts->gen.save_context); pavone@656: xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_D); pavone@656: call_args_abi(code, (code_ptr)sync_components, 2, opts->gen.context_reg, opts->gen.scratch1); pavone@567: mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR); pavone@567: call(code, opts->gen.load_context); pavone@567: pop_r(code, opts->gen.scratch2); pavone@567: pop_r(code, opts->gen.scratch1); pavone@567: *skip_sync = code->cur - (skip_sync+1); pavone@567: retn(code); pavone@539: pavone@590: opts->gen.handle_code_write = (code_ptr)m68k_handle_code_write; pavone@987: pavone@987: check_alloc_code(code, 256); pavone@987: opts->gen.handle_align_error_write = code->cur; pavone@987: code->cur += 256; pavone@987: check_alloc_code(code, 256); pavone@987: opts->gen.handle_align_error_read = code->cur; pavone@987: code->cur += 256; pavone@987: pavone@590: opts->read_16 = gen_mem_fun(&opts->gen, memmap, num_chunks, READ_16, NULL); pavone@590: opts->read_8 = gen_mem_fun(&opts->gen, memmap, num_chunks, READ_8, NULL); pavone@590: opts->write_16 = gen_mem_fun(&opts->gen, memmap, num_chunks, WRITE_16, NULL); pavone@590: opts->write_8 = gen_mem_fun(&opts->gen, memmap, num_chunks, WRITE_8, NULL); pavone@447: pavone@567: opts->read_32 = code->cur; pavone@567: push_r(code, opts->gen.scratch1); pavone@567: call(code, opts->read_16); pavone@567: mov_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_W); pavone@567: pop_r(code, opts->gen.scratch1); pavone@567: push_r(code, opts->gen.scratch2); pavone@567: add_ir(code, 2, opts->gen.scratch1, SZ_D); pavone@567: call(code, opts->read_16); pavone@567: pop_r(code, opts->gen.scratch2); pavone@567: movzx_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_W, SZ_D); pavone@567: shl_ir(code, 16, opts->gen.scratch2, SZ_D); pavone@567: or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_D); pavone@567: retn(code); pavone@447: pavone@567: opts->write_32_lowfirst = code->cur; pavone@567: push_r(code, opts->gen.scratch2); pavone@567: push_r(code, opts->gen.scratch1); pavone@567: add_ir(code, 2, opts->gen.scratch2, SZ_D); pavone@567: call(code, opts->write_16); pavone@567: pop_r(code, opts->gen.scratch1); pavone@567: pop_r(code, opts->gen.scratch2); pavone@567: shr_ir(code, 16, opts->gen.scratch1, SZ_D); pavone@567: jmp(code, opts->write_16); pavone@447: pavone@567: opts->write_32_highfirst = code->cur; pavone@567: push_r(code, opts->gen.scratch1); pavone@567: push_r(code, opts->gen.scratch2); pavone@567: shr_ir(code, 16, opts->gen.scratch1, SZ_D); pavone@567: call(code, opts->write_16); pavone@567: pop_r(code, opts->gen.scratch2); pavone@567: pop_r(code, opts->gen.scratch1); pavone@567: add_ir(code, 2, opts->gen.scratch2, SZ_D); pavone@567: jmp(code, opts->write_16); pavone@447: pavone@567: opts->get_sr = code->cur; pavone@567: mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, status), opts->gen.scratch1, SZ_B); pavone@567: shl_ir(code, 8, opts->gen.scratch1, SZ_W); pavone@547: if (opts->flag_regs[FLAG_X] >= 0) { pavone@567: mov_rr(code, opts->flag_regs[FLAG_X], opts->gen.scratch1, SZ_B); pavone@547: } else { pavone@547: int8_t offset = offsetof(m68k_context, flags); pavone@547: if (offset) { pavone@567: mov_rdispr(code, opts->gen.context_reg, offset, opts->gen.scratch1, SZ_B); pavone@547: } else { pavone@567: mov_rindr(code, opts->gen.context_reg, opts->gen.scratch1, SZ_B); pavone@547: } pavone@547: } pavone@547: for (int flag = FLAG_N; flag <= FLAG_C; flag++) pavone@547: { pavone@567: shl_ir(code, 1, opts->gen.scratch1, SZ_B); pavone@547: if (opts->flag_regs[flag] >= 0) { pavone@567: or_rr(code, opts->flag_regs[flag], opts->gen.scratch1, SZ_B); pavone@547: } else { pavone@567: or_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, opts->gen.scratch1, SZ_B); pavone@547: } pavone@547: } pavone@567: retn(code); pavone@547: pavone@567: opts->set_sr = code->cur; pavone@547: for (int flag = FLAG_C; flag >= FLAG_X; flag--) pavone@547: { pavone@567: rcr_ir(code, 1, opts->gen.scratch1, SZ_B); pavone@547: if (opts->flag_regs[flag] >= 0) { pavone@567: setcc_r(code, CC_C, opts->flag_regs[flag]); pavone@547: } else { pavone@547: int8_t offset = offsetof(m68k_context, flags) + flag; pavone@547: if (offset) { pavone@567: setcc_rdisp(code, CC_C, opts->gen.context_reg, offset); pavone@547: } else { pavone@567: setcc_rind(code, CC_C, opts->gen.context_reg); pavone@547: } pavone@547: } pavone@547: } pavone@567: shr_ir(code, 8, opts->gen.scratch1, SZ_W); pavone@567: mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); pavone@846: //set int pending flag in case we trigger an interrupt as a result of the mask change pavone@996: mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B); pavone@567: retn(code); pavone@547: pavone@567: opts->set_ccr = code->cur; pavone@547: for (int flag = FLAG_C; flag >= FLAG_X; flag--) pavone@547: { pavone@567: rcr_ir(code, 1, opts->gen.scratch1, SZ_B); pavone@547: if (opts->flag_regs[flag] >= 0) { pavone@567: setcc_r(code, CC_C, opts->flag_regs[flag]); pavone@547: } else { pavone@547: int8_t offset = offsetof(m68k_context, flags) + flag; pavone@547: if (offset) { pavone@567: setcc_rdisp(code, CC_C, opts->gen.context_reg, offset); pavone@547: } else { pavone@567: setcc_rind(code, CC_C, opts->gen.context_reg); pavone@547: } pavone@547: } pavone@547: } pavone@567: retn(code); pavone@987: pavone@987: code_info tmp_code = *code; pavone@987: code->cur = opts->gen.handle_align_error_write; pavone@987: code->last = code->cur + 256; pavone@987: //unwind the stack one functinon call pavone@987: add_ir(code, 16, RSP, SZ_PTR); pavone@987: //save address that triggered error so we can write it to the 68K stack at the appropriate place pavone@987: push_r(code, opts->gen.scratch2); pavone@987: //swap USP and SSP if not already in supervisor mode pavone@987: check_user_mode_swap_ssp_usp(opts); pavone@987: //save PC pavone@987: subi_areg(opts, 4, 7); pavone@987: areg_to_native(opts, 7, opts->gen.scratch2); pavone@987: mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, last_prefetch_address), opts->gen.scratch1, SZ_D); pavone@987: call(code, opts->write_32_lowfirst); pavone@987: //save status register pavone@987: subi_areg(opts, 2, 7); pavone@987: call(code, opts->get_sr); pavone@987: areg_to_native(opts, 7, opts->gen.scratch2); pavone@987: call(code, opts->write_16); pavone@987: //save instruction register pavone@987: subi_areg(opts, 2, 7); pavone@989: //calculate IR pavone@989: push_r(code, opts->gen.context_reg); pavone@989: call(code, opts->gen.save_context); pavone@989: call_args_abi(code, (code_ptr)m68k_get_ir, 1, opts->gen.context_reg); pavone@989: mov_rr(code, RAX, opts->gen.scratch1, SZ_W); pavone@989: pop_r(code, opts->gen.context_reg); pavone@989: pop_r(code, opts->gen.scratch2); //access address pavone@989: push_r(code, RAX); //save it for use in the "info" word pavone@989: push_r(code, opts->gen.scratch2); //access address pavone@989: call(code, opts->gen.load_context); pavone@989: //write it to the stack pavone@987: areg_to_native(opts, 7, opts->gen.scratch2); pavone@987: call(code, opts->write_16); pavone@987: //save access address pavone@987: subi_areg(opts, 4, 7); pavone@987: pop_r(code, opts->gen.scratch1); pavone@987: areg_to_native(opts, 7, opts->gen.scratch2); pavone@987: call(code, opts->write_32_lowfirst); pavone@987: //save FC, I/N and R/W word' pavone@987: xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_W); pavone@987: //FC3 is basically the same as the supervisor bit pavone@987: mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, status), opts->gen.scratch1, SZ_B); pavone@987: shr_ir(code, 3, opts->gen.scratch1, SZ_B); pavone@987: and_ir(code, 4, opts->gen.scratch1, SZ_B); pavone@987: //set FC0 to one to indicate data access pavone@987: or_ir(code, 1, opts->gen.scratch1, SZ_B); pavone@989: //set undefined bits to IR value pavone@989: pop_r(code, opts->gen.scratch2); pavone@989: and_ir(code, 0xFFE0, opts->gen.scratch2, SZ_W); pavone@989: or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_W); pavone@987: subi_areg(opts, 2, 7); pavone@987: areg_to_native(opts, 7, opts->gen.scratch2); pavone@987: call(code, opts->write_16); pavone@987: //set supervisor bit pavone@987: or_irdisp(code, 0x20, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); pavone@987: //load vector address pavone@987: mov_ir(code, 4 * VECTOR_ADDRESS_ERROR, opts->gen.scratch1, SZ_D); pavone@987: call(code, opts->read_32); pavone@987: call(code, opts->native_addr_and_sync); pavone@987: cycles(&opts->gen, 18); pavone@987: jmp_r(code, opts->gen.scratch1); pavone@987: pavone@987: code->cur = opts->gen.handle_align_error_read; pavone@987: code->last = code->cur + 256; pavone@987: //unwind the stack one functinon call pavone@987: add_ir(code, 16, RSP, SZ_PTR); pavone@987: //save address that triggered error so we can write it to the 68K stack at the appropriate place pavone@987: push_r(code, opts->gen.scratch1); pavone@987: //swap USP and SSP if not already in supervisor mode pavone@987: check_user_mode_swap_ssp_usp(opts); pavone@987: //save PC pavone@987: subi_areg(opts, 4, 7); pavone@987: areg_to_native(opts, 7, opts->gen.scratch2); pavone@987: mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, last_prefetch_address), opts->gen.scratch1, SZ_D); pavone@987: call(code, opts->write_32_lowfirst); pavone@987: //save status register pavone@987: subi_areg(opts, 2, 7); pavone@987: call(code, opts->get_sr); pavone@987: areg_to_native(opts, 7, opts->gen.scratch2); pavone@987: call(code, opts->write_16); pavone@987: //save instruction register pavone@987: subi_areg(opts, 2, 7); pavone@989: //calculate IR pavone@989: push_r(code, opts->gen.context_reg); pavone@989: call(code, opts->gen.save_context); pavone@989: call_args_abi(code, (code_ptr)m68k_get_ir, 1, opts->gen.context_reg); pavone@989: mov_rr(code, RAX, opts->gen.scratch1, SZ_W); pavone@989: pop_r(code, opts->gen.context_reg); pavone@989: pop_r(code, opts->gen.scratch2); //access address pavone@989: push_r(code, RAX); //save it for use in the "info" word pavone@989: push_r(code, opts->gen.scratch2); //access address pavone@989: call(code, opts->gen.load_context); pavone@989: //write it to the stack pavone@987: areg_to_native(opts, 7, opts->gen.scratch2); pavone@987: call(code, opts->write_16); pavone@987: //save access address pavone@987: subi_areg(opts, 4, 7); pavone@987: pop_r(code, opts->gen.scratch1); pavone@987: areg_to_native(opts, 7, opts->gen.scratch2); pavone@987: call(code, opts->write_32_lowfirst); pavone@987: //save FC, I/N and R/W word' pavone@987: xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_W); pavone@987: //FC3 is basically the same as the supervisor bit pavone@987: mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, status), opts->gen.scratch1, SZ_B); pavone@987: shr_ir(code, 3, opts->gen.scratch1, SZ_B); pavone@987: and_ir(code, 4, opts->gen.scratch1, SZ_B); pavone@987: //set FC0 to one to indicate data access, and R/W to indicate read pavone@987: or_ir(code, 0x11, opts->gen.scratch1, SZ_B); pavone@989: //set undefined bits to IR value pavone@989: pop_r(code, opts->gen.scratch2); pavone@989: and_ir(code, 0xFFE0, opts->gen.scratch2, SZ_W); pavone@989: or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_W); pavone@987: subi_areg(opts, 2, 7); pavone@987: areg_to_native(opts, 7, opts->gen.scratch2); pavone@987: call(code, opts->write_16); pavone@987: //set supervisor bit pavone@987: or_irdisp(code, 0x20, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); pavone@987: //load vector address pavone@987: mov_ir(code, 4 * VECTOR_ADDRESS_ERROR, opts->gen.scratch1, SZ_D); pavone@987: call(code, opts->read_32); pavone@987: call(code, opts->native_addr_and_sync); pavone@987: cycles(&opts->gen, 18); pavone@987: jmp_r(code, opts->gen.scratch1); pavone@987: pavone@987: *code = tmp_code; pavone@547: pavone@567: opts->gen.handle_cycle_limit_int = code->cur; pavone@902: //calculate stack adjust size pavone@902: add_ir(code, 16-sizeof(void*), RSP, SZ_PTR); pavone@902: uint32_t adjust_size = code->cur - opts->gen.handle_cycle_limit_int; pavone@902: code->cur = opts->gen.handle_cycle_limit_int; pavone@908: pavone@656: cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), opts->gen.cycles, SZ_D); pavone@567: code_ptr do_int = code->cur + 1; pavone@567: jcc(code, CC_NC, code->cur + 2); pavone@656: cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), opts->gen.cycles, SZ_D); pavone@567: skip_sync = code->cur + 1; pavone@567: jcc(code, CC_C, code->cur + 2); pavone@567: call(code, opts->gen.save_context); pavone@656: call_args_abi(code, (code_ptr)sync_components, 2, opts->gen.context_reg, opts->gen.scratch1); pavone@567: mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR); pavone@567: jmp(code, opts->gen.load_context); pavone@567: *skip_sync = code->cur - (skip_sync+1); pavone@872: cmp_irdisp(code, 0, opts->gen.context_reg, offsetof(m68k_context, should_return), SZ_B); pavone@872: code_ptr do_ret = code->cur + 1; pavone@872: jcc(code, CC_NZ, do_ret); pavone@567: retn(code); pavone@872: *do_ret = code->cur - (do_ret+1); pavone@894: uint32_t tmp_stack_off = code->stack_off; pavone@894: //fetch return address and adjust RSP pavone@872: pop_r(code, opts->gen.scratch1); pavone@894: add_ir(code, 16-sizeof(void *), RSP, SZ_PTR); pavone@902: add_ir(code, adjust_size, opts->gen.scratch1, SZ_PTR); pavone@894: //save return address for restoring later pavone@883: mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, resume_pc), SZ_PTR); pavone@872: retn(code); pavone@894: code->stack_off = tmp_stack_off; pavone@567: *do_int = code->cur - (do_int+1); pavone@846: //implement 1 instruction latency pavone@846: cmp_irdisp(code, 0, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B); pavone@846: do_int = code->cur + 1; pavone@846: jcc(code, CC_NZ, do_int); pavone@996: //store current interrupt number so it doesn't change before we start processing the vector pavone@996: mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch1, SZ_B); pavone@996: mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B); pavone@846: retn(code); pavone@846: *do_int = code->cur - (do_int + 1); pavone@996: //Check if int_pending has an actual interrupt priority in it pavone@996: cmp_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B); pavone@996: code_ptr already_int_num = code->cur + 1; pavone@996: jcc(code, CC_NZ, already_int_num); pavone@996: pavone@996: mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch2, SZ_B); pavone@996: mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B); pavone@996: pavone@996: *already_int_num = code->cur - (already_int_num + 1); pavone@847: //save PC as stored in scratch1 for later pavone@847: push_r(code, opts->gen.scratch1); pavone@347: //set target cycle to sync cycle pavone@656: mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), opts->gen.limit, SZ_D); pavone@347: //swap USP and SSP if not already in supervisor mode pavone@687: check_user_mode_swap_ssp_usp(opts); pavone@347: //save status register pavone@847: subi_areg(opts, 6, 7); pavone@567: call(code, opts->get_sr); pavone@847: //6 cycles before SR gets saved pavone@847: cycles(&opts->gen, 6); pavone@847: //save SR to stack pavone@574: areg_to_native(opts, 7, opts->gen.scratch2); pavone@567: call(code, opts->write_16); pavone@847: //interrupt ack cycle pavone@847: //the Genesis responds to these exclusively with !VPA which means its a slow pavone@847: //6800 operation. documentation says these can take between 10 and 19 cycles. pavone@847: //actual results measurements seem to suggest it's actually between 9 and 18 pavone@847: //WARNING: this code might break with register assignment changes pavone@847: //save RDX pavone@847: push_r(code, RDX); pavone@847: //save cycle count pavone@847: mov_rr(code, RAX, opts->gen.scratch1, SZ_D); pavone@847: //clear top doubleword of dividend pavone@847: xor_rr(code, RDX, RDX, SZ_D); pavone@847: //set divisor to clock divider pavone@847: mov_ir(code, opts->gen.clock_divider, opts->gen.scratch2, SZ_D); pavone@847: div_r(code, opts->gen.scratch2, SZ_D); pavone@847: //discard remainder pavone@847: xor_rr(code, RDX, RDX, SZ_D); pavone@847: //set divisor to 10, the period of E pavone@847: mov_ir(code, 10, opts->gen.scratch2, SZ_D); pavone@847: div_r(code, opts->gen.scratch2, SZ_D); pavone@847: //delay will be (9 + 4 + the remainder) * clock_divider pavone@847: //the extra 4 is to cover the idle bus period after the ack pavone@847: add_ir(code, 9 + 4, RDX, SZ_D); pavone@847: mov_ir(code, opts->gen.clock_divider, RAX, SZ_D); pavone@847: mul_r(code, RDX, SZ_D); pavone@847: pop_r(code, RDX); pavone@847: //add saved cycle count to result pavone@847: add_rr(code, opts->gen.scratch1, RAX, SZ_D); pavone@847: pavone@347: //update status register pavone@567: and_irdisp(code, 0xF8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); pavone@567: mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch1, SZ_B); pavone@567: or_ir(code, 0x20, opts->gen.scratch1, SZ_B); pavone@567: or_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); pavone@847: pavone@847: pop_r(code, opts->gen.scratch1); pavone@847: pavone@847: //save PC pavone@847: areg_to_native(opts, 7, opts->gen.scratch2); pavone@847: add_ir(code, 2, opts->gen.scratch2, SZ_D); pavone@847: call(code, opts->write_32_lowfirst); pavone@847: pavone@996: //grab saved interrupt number pavone@996: xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_D); pavone@996: mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_pending), opts->gen.scratch1, SZ_B); pavone@887: //ack the interrupt (happens earlier on hardware, but shouldn't be an observable difference) pavone@567: mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, int_ack), SZ_W); pavone@887: //calculate the vector address pavone@567: shl_ir(code, 2, opts->gen.scratch1, SZ_D); pavone@567: add_ir(code, 0x60, opts->gen.scratch1, SZ_D); pavone@996: //clear out pending flag pavone@996: mov_irdisp(code, 0, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B); pavone@996: //read vector pavone@567: call(code, opts->read_32); pavone@567: call(code, opts->native_addr_and_sync); pavone@847: //2 prefetch bus operations + 2 idle bus cycles pavone@847: cycles(&opts->gen, 10); pavone@894: tmp_stack_off = code->stack_off; pavone@347: //discard function return address pavone@567: pop_r(code, opts->gen.scratch2); pavone@894: add_ir(code, 16-sizeof(void *), RSP, SZ_PTR); pavone@567: jmp_r(code, opts->gen.scratch1); pavone@894: code->stack_off = tmp_stack_off; pavone@447: pavone@567: opts->trap = code->cur; pavone@567: push_r(code, opts->gen.scratch2); pavone@348: //swap USP and SSP if not already in supervisor mode pavone@687: check_user_mode_swap_ssp_usp(opts); pavone@348: //save PC pavone@574: subi_areg(opts, 4, 7); pavone@574: areg_to_native(opts, 7, opts->gen.scratch2); pavone@567: call(code, opts->write_32_lowfirst); pavone@348: //save status register pavone@574: subi_areg(opts, 2, 7); pavone@567: call(code, opts->get_sr); pavone@574: areg_to_native(opts, 7, opts->gen.scratch2); pavone@567: call(code, opts->write_16); pavone@348: //set supervisor bit pavone@567: or_irdisp(code, 0x20, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); pavone@348: //calculate vector address pavone@567: pop_r(code, opts->gen.scratch1); pavone@567: shl_ir(code, 2, opts->gen.scratch1, SZ_D); pavone@567: call(code, opts->read_32); pavone@567: call(code, opts->native_addr_and_sync); pavone@567: cycles(&opts->gen, 18); pavone@567: jmp_r(code, opts->gen.scratch1); pavone@18: }