Signed-off-by: Laurent Vivier <laur...@vivier.eu> --- target-m68k/helper.c | 196 ++++++++++++++++++++++++++++++++---------------- target-m68k/helper.h | 15 +++- target-m68k/translate.c | 183 ++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 317 insertions(+), 77 deletions(-)
diff --git a/target-m68k/helper.c b/target-m68k/helper.c index 1360b2c..16fca70 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -498,78 +498,142 @@ void HELPER(set_sr)(CPUM68KState *env, uint32_t val) m68k_switch_sp(env); } -uint32_t HELPER(shl_cc)(CPUM68KState *env, uint32_t val, uint32_t shift) -{ - uint32_t result; - uint32_t cf; - - shift &= 63; - if (shift == 0) { - result = val; - cf = env->cc_src & CCF_C; - } else if (shift < 32) { - result = val << shift; - cf = (val >> (32 - shift)) & 1; - } else if (shift == 32) { - result = 0; - cf = val & 1; - } else /* shift > 32 */ { - result = 0; - cf = 0; - } - env->cc_src = cf; - env->cc_x = (cf != 0); - env->cc_dest = result; - return result; +#define HELPER_SHL(type, bits) \ +uint32_t HELPER(glue(glue(shl, bits), _cc))(CPUM68KState *env, \ + uint32_t val, uint32_t shift) \ +{ \ + type result; \ + uint32_t cf; \ + shift &= 63; \ + if (shift == 0) { \ + result = (type)val; \ + cf = 0; \ + } else if (shift < bits) { \ + result = (type)val << shift; \ + cf = ((type)val >> (bits - shift)) & 1; \ + } else if (shift == bits) { \ + result = 0; \ + cf = val & 1; \ + } else { \ + result = 0; \ + cf = 0; \ + } \ + env->cc_src = cf ? CCF_C : 0; \ + if (shift) { \ + env->cc_x = (cf != 0); \ + } \ + env->cc_dest = result; \ + return result; \ } -uint32_t HELPER(shr_cc)(CPUM68KState *env, uint32_t val, uint32_t shift) -{ - uint32_t result; - uint32_t cf; - - shift &= 63; - if (shift == 0) { - result = val; - cf = env->cc_src & CCF_C; - } else if (shift < 32) { - result = val >> shift; - cf = (val >> (shift - 1)) & 1; - } else if (shift == 32) { - result = 0; - cf = val >> 31; - } else /* shift > 32 */ { - result = 0; - cf = 0; - } - env->cc_src = cf; - env->cc_x = (cf != 0); - env->cc_dest = result; - return result; +HELPER_SHL(uint8_t, 8) +HELPER_SHL(uint16_t, 16) +HELPER_SHL(uint32_t, 32) + +#define HELPER_SHR(type, bits) \ +uint32_t HELPER(glue(glue(shr, bits), _cc))(CPUM68KState *env, \ + uint32_t val, uint32_t shift) \ +{ \ + type result; \ + uint32_t cf; \ + shift &= 63; \ + if (shift == 0) { \ + result = (type)val; \ + cf = 0; \ + } else if (shift < bits) { \ + result = (type)val >> shift; \ + cf = ((type)val >> (shift - 1)) & 1; \ + } else if (shift == bits) { \ + result = 0; \ + cf = (type)val >> (bits - 1); \ + } else { \ + result = 0; \ + cf = 0; \ + } \ + env->cc_src = cf ? CCF_C : 0; \ + if (shift) { \ + env->cc_x = (cf != 0); \ + } \ + env->cc_dest = result; \ + return result; \ } -uint32_t HELPER(sar_cc)(CPUM68KState *env, uint32_t val, uint32_t shift) -{ - uint32_t result; - uint32_t cf; - - shift &= 63; - if (shift == 0) { - result = val; - cf = (env->cc_src & CCF_C) != 0; - } else if (shift < 32) { - result = (int32_t)val >> shift; - cf = (val >> (shift - 1)) & 1; - } else /* shift >= 32 */ { - result = (int32_t)val >> 31; - cf = val >> 31; - } - env->cc_src = cf; - env->cc_x = cf; - env->cc_dest = result; - return result; +HELPER_SHR(uint8_t, 8) +HELPER_SHR(uint16_t, 16) +HELPER_SHR(uint32_t, 32) + +#define HELPER_SAL(type, bits) \ +uint32_t HELPER(glue(glue(sal, bits), _cc))(CPUM68KState *env, \ + uint32_t val, uint32_t shift) \ +{ \ + type result; \ + uint32_t cf; \ + uint32_t vf; \ + uint32_t m; \ + shift &= 63; \ + if (shift == 0) { \ + vf = 0; \ + } else if (shift < bits) { \ + m = ((1llu << (shift + 1)) - 1) << (bits - shift - 1); \ + vf = (val & m) != m && (val & m) != 0; \ + } else { \ + m = (1llu << bits) - 1; \ + vf = (val & m) != 0; \ + } \ + if (shift == 0) { \ + result = (type)val; \ + cf = 0; \ + } else if (shift < bits) { \ + result = (type)val << shift; \ + cf = ((type)val >> (bits - shift)) & 1; \ + } else if (shift == bits) { \ + result = 0; \ + cf = val & 1; \ + } else { \ + result = 0; \ + cf = 0; \ + } \ + env->cc_src = (cf ? CCF_C : 0) | (vf ? CCF_V : 0); \ + if (shift) { \ + env->cc_x = (cf != 0); \ + } \ + env->cc_dest = result; \ + return result; \ } +HELPER_SAL(int8_t, 8) +HELPER_SAL(int16_t, 16) +HELPER_SAL(int32_t, 32) + +#define HELPER_SAR(type, bits) \ +uint32_t HELPER(glue(glue(sar, bits), _cc))(CPUM68KState *env, \ + uint32_t val, uint32_t shift) \ +{ \ + type result; \ + uint32_t cf; \ + shift &= 63; \ + if (shift == 0) { \ + result = (type)val; \ + cf = 0; \ + } else if (shift < bits) { \ + result = (type)val >> shift; \ + cf = ((type)val >> (shift - 1)) & 1; \ + } else { \ + result = (type)val >> (bits - 1); \ + cf = (type)val >> (bits - 1); \ + } \ + env->cc_src = cf ? CCF_C : 0; \ + if (shift) { \ + env->cc_x = (cf != 0); \ + } \ + env->cc_dest = result; \ + return result; \ +} + +HELPER_SAR(int8_t, 8) +HELPER_SAR(int16_t, 16) +HELPER_SAR(int32_t, 32) + /* FPU helpers. */ uint32_t HELPER(f64_to_i32)(CPUM68KState *env, float64 val) { diff --git a/target-m68k/helper.h b/target-m68k/helper.h index 61e335d..a39ee7d 100644 --- a/target-m68k/helper.h +++ b/target-m68k/helper.h @@ -15,9 +15,18 @@ DEF_HELPER_3(addx32_cc, i32, env, i32, i32) DEF_HELPER_3(subx8_cc, i32, env, i32, i32) DEF_HELPER_3(subx16_cc, i32, env, i32, i32) DEF_HELPER_3(subx32_cc, i32, env, i32, i32) -DEF_HELPER_3(shl_cc, i32, env, i32, i32) -DEF_HELPER_3(shr_cc, i32, env, i32, i32) -DEF_HELPER_3(sar_cc, i32, env, i32, i32) +DEF_HELPER_3(shl8_cc, i32, env, i32, i32) +DEF_HELPER_3(shl16_cc, i32, env, i32, i32) +DEF_HELPER_3(shl32_cc, i32, env, i32, i32) +DEF_HELPER_3(shr8_cc, i32, env, i32, i32) +DEF_HELPER_3(shr16_cc, i32, env, i32, i32) +DEF_HELPER_3(shr32_cc, i32, env, i32, i32) +DEF_HELPER_3(sal8_cc, i32, env, i32, i32) +DEF_HELPER_3(sal16_cc, i32, env, i32, i32) +DEF_HELPER_3(sal32_cc, i32, env, i32, i32) +DEF_HELPER_3(sar8_cc, i32, env, i32, i32) +DEF_HELPER_3(sar16_cc, i32, env, i32, i32) +DEF_HELPER_3(sar32_cc, i32, env, i32, i32) DEF_HELPER_2(xflag_lt_i8, i32, i32, i32) DEF_HELPER_2(xflag_lt_i16, i32, i32, i32) DEF_HELPER_2(xflag_lt_i32, i32, i32, i32) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index bac33ef..22d4296 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -2473,6 +2473,74 @@ DISAS_INSN(addx_mem) } /* TODO: This could be implemented without helper functions. */ +DISAS_INSN(shift8_im) +{ + TCGv reg; + int tmp; + TCGv shift; + TCGv dest; + + reg = DREG(insn, 0); + tmp = (insn >> 9) & 7; + if (tmp == 0) { + tmp = 8; + } + shift = tcg_const_i32(tmp); + dest = tcg_temp_new_i32(); + /* No need to flush flags becuse we know we will set C flag. */ + if (insn & 0x100) { + if (insn & 8) { + gen_helper_shl8_cc(dest, cpu_env, reg, shift); + } else { + gen_helper_sal8_cc(dest, cpu_env, reg, shift); + } + } else { + if (insn & 8) { + gen_helper_shr8_cc(dest, cpu_env, reg, shift); + } else { + gen_helper_sar8_cc(dest, cpu_env, reg, shift); + } + } + gen_partset_reg(OS_BYTE, reg, dest); + set_cc_op(s, CC_OP_SHIFTB); +} + +/* TODO: This could be implemented without helper functions. */ +DISAS_INSN(shift16_im) +{ + TCGv reg; + int tmp; + TCGv shift; + TCGv dest; + + reg = DREG(insn, 0); + tmp = (insn >> 9) & 7; + if (tmp == 0) { + tmp = 8; + } + shift = tcg_const_i32(tmp); + dest = tcg_temp_new_i32(); + /* No need to flush flags becuse we know we will set C flag. */ + if (insn & 0x100) { + if (insn & 8) { + gen_helper_shl16_cc(dest, cpu_env, reg, shift); + } else { + gen_helper_sal16_cc(dest, cpu_env, reg, shift); + } + } else { + if (insn & 8) { + gen_helper_shr16_cc(dest, cpu_env, reg, shift); + } else { + gen_helper_sar16_cc(dest, cpu_env, reg, shift); + } + } + gen_partset_reg(OS_WORD, reg, dest); + set_cc_op(s, CC_OP_SHIFTW); +} + + +/* TODO: This could be implemented without helper functions. */ + DISAS_INSN(shift_im) { TCGv reg; @@ -2481,22 +2549,87 @@ DISAS_INSN(shift_im) reg = DREG(insn, 0); tmp = (insn >> 9) & 7; - if (tmp == 0) + if (tmp == 0) { tmp = 8; + } shift = tcg_const_i32(tmp); /* No need to flush flags becuse we know we will set C flag. */ if (insn & 0x100) { - gen_helper_shl_cc(reg, cpu_env, reg, shift); + if (insn & 8) { + gen_helper_shl32_cc(reg, cpu_env, reg, shift); + } else { + gen_helper_sal32_cc(reg, cpu_env, reg, shift); + } } else { if (insn & 8) { - gen_helper_shr_cc(reg, cpu_env, reg, shift); + gen_helper_shr32_cc(reg, cpu_env, reg, shift); } else { - gen_helper_sar_cc(reg, cpu_env, reg, shift); + gen_helper_sar32_cc(reg, cpu_env, reg, shift); } } set_cc_op(s, CC_OP_SHIFT); } +DISAS_INSN(shift8_reg) +{ + TCGv reg; + TCGv shift; + TCGv dest; + TCGv tmp; + + reg = DREG(insn, 0); + shift = DREG(insn, 9); + tmp = tcg_temp_new_i32(); + tcg_gen_andi_i32(tmp, shift, 63); + dest = tcg_temp_new_i32(); + /* Shift by zero leaves C flag unmodified. */ + if (insn & 0x100) { + if (insn & 8) { + gen_helper_shl8_cc(dest, cpu_env, reg, tmp); + } else { + gen_helper_sal8_cc(dest, cpu_env, reg, tmp); + } + } else { + if (insn & 8) { + gen_helper_shr8_cc(dest, cpu_env, reg, tmp); + } else { + gen_helper_sar8_cc(dest, cpu_env, reg, tmp); + } + } + gen_partset_reg(OS_BYTE, reg, dest); + set_cc_op(s, CC_OP_SHIFTB); +} + +DISAS_INSN(shift16_reg) +{ + TCGv reg; + TCGv shift; + TCGv dest; + TCGv tmp; + + reg = DREG(insn, 0); + shift = DREG(insn, 9); + tmp = tcg_temp_new_i32(); + tcg_gen_andi_i32(tmp, shift, 63); + dest = tcg_temp_new_i32(); + /* Shift by zero leaves C flag unmodified. */ + if (insn & 0x100) { + if (insn & 8) { + gen_helper_shl16_cc(dest, cpu_env, reg, tmp); + } else { + gen_helper_sal16_cc(dest, cpu_env, reg, tmp); + } + } else { + if (insn & 8) { + gen_helper_shr16_cc(dest, cpu_env, reg, tmp); + } else { + gen_helper_sar16_cc(dest, cpu_env, reg, tmp); + } + } + gen_partset_reg(OS_WORD, reg, dest); + set_cc_op(s, CC_OP_SHIFTW); +} + DISAS_INSN(shift_reg) { TCGv reg; @@ -2505,19 +2638,46 @@ DISAS_INSN(shift_reg) reg = DREG(insn, 0); shift = DREG(insn, 9); /* Shift by zero leaves C flag unmodified. */ - gen_flush_flags(s); if (insn & 0x100) { - gen_helper_shl_cc(reg, cpu_env, reg, shift); + if (insn & 8) { + gen_helper_shl32_cc(reg, cpu_env, reg, shift); + } else { + gen_helper_sal32_cc(reg, cpu_env, reg, shift); + } } else { if (insn & 8) { - gen_helper_shr_cc(reg, cpu_env, reg, shift); + gen_helper_shr32_cc(reg, cpu_env, reg, shift); } else { - gen_helper_sar_cc(reg, cpu_env, reg, shift); + gen_helper_sar32_cc(reg, cpu_env, reg, shift); } } set_cc_op(s, CC_OP_SHIFT); } +DISAS_INSN(shift_mem) +{ + TCGv src; + TCGv dest; + TCGv addr; + TCGv shift; + + SRC_EA(env, src, OS_WORD, 0, &addr); + dest = tcg_temp_new_i32(); + shift = tcg_const_i32(1); + if (insn & 0x100) { + gen_helper_shl16_cc(dest, cpu_env, src, shift); + } else { + if (insn & 8) { + gen_helper_shr16_cc(dest, cpu_env, src, shift); + } else { + gen_helper_sar16_cc(dest, cpu_env, src, shift); + } + } + DEST_EA(env, insn, OS_WORD, dest, &addr); + set_cc_op(s, CC_OP_SHIFTW); +} + + DISAS_INSN(ff1) { TCGv reg; @@ -3605,6 +3765,13 @@ void register_m68k_insns (CPUM68KState *env) INSN(adda, d0c0, f0c0, M68000); INSN(shift_im, e080, f0f0, CF_ISA_A); INSN(shift_reg, e0a0, f0f0, CF_ISA_A); + INSN(shift8_im, e000, f0f0, M68000); + INSN(shift16_im, e040, f0f0, M68000); + INSN(shift_im, e080, f0f0, M68000); + INSN(shift8_reg, e020, f0f0, M68000); + INSN(shift16_reg, e060, f0f0, M68000); + INSN(shift_reg, e0a0, f0f0, M68000); + INSN(shift_mem, e0c0, fcc0, M68000); INSN(undef_fpu, f000, f000, CF_ISA_A); INSN(fpu, f200, ffc0, CF_FPU); INSN(fbcc, f280, ffc0, CF_FPU); -- 2.4.3