This patch adds emulation support for the udiv and sdiv instructions. Signed-off-by: Alexander Graf <ag...@suse.de> --- target-arm/helper-a64.c | 16 ++++++++++++++++ target-arm/helper-a64.h | 2 ++ target-arm/translate-a64.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+)
diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c index 3f055b6..a56ce75 100644 --- a/target-arm/helper-a64.c +++ b/target-arm/helper-a64.c @@ -221,3 +221,19 @@ out: return r; } + +uint64_t HELPER(udiv64)(uint64_t num, uint64_t den) +{ + if (den == 0) + return 0; + return num / den; +} + +int64_t HELPER(sdiv64)(int64_t num, int64_t den) +{ + if (den == 0) + return 0; + if (num == LLONG_MIN && den == -1) + return LLONG_MIN; + return num / den; +} diff --git a/target-arm/helper-a64.h b/target-arm/helper-a64.h index 8874518..ad1a94a 100644 --- a/target-arm/helper-a64.h +++ b/target-arm/helper-a64.h @@ -24,3 +24,5 @@ DEF_HELPER_FLAGS_4(pstate_sub32, TCG_CALL_NO_RWG_SE, i32, i32, i64, i64, i64) DEF_HELPER_FLAGS_3(sign_extend, TCG_CALL_NO_RWG_SE, i64, i64, i64, i64) DEF_HELPER_FLAGS_2(cond, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_4(cinc, TCG_CALL_NO_RWG_SE, i64, i32, i32, i64, i64) +DEF_HELPER_FLAGS_2(udiv64, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(sdiv64, TCG_CALL_NO_RWG_SE, s64, s64, s64) diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index cd2dfe6..6954ff7 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -1507,6 +1507,47 @@ static void handle_cinc(DisasContext *s, uint32_t insn) gen_helper_cinc(cpu_reg(rd), pstate, tcg_insn, cpu_reg(rn), cpu_reg(rm)); } +static void handle_div(DisasContext *s, uint32_t insn) +{ + int rd = get_reg(insn); + int rn = get_bits(insn, 5, 5); + int rm = get_bits(insn, 16, 5); + bool is_signed = get_bits(insn, 10, 1); + bool is_32bit = !get_bits(insn, 31, 1); + TCGv_i64 n = tcg_temp_new_i64(); + TCGv_i64 m = tcg_temp_new_i64(); + + if (is_32bit) { + if (is_signed) { + tcg_gen_ext32s_i64(n, cpu_reg(rn)); + tcg_gen_ext32s_i64(m, cpu_reg(rm)); + } else { + tcg_gen_ext32u_i64(n, cpu_reg(rn)); + tcg_gen_ext32u_i64(m, cpu_reg(rm)); + } + } else { + tcg_gen_mov_i64(n, cpu_reg(rn)); + tcg_gen_mov_i64(m, cpu_reg(rm)); + } + + if (is_signed) { + gen_helper_sdiv64(cpu_reg(rd), n, m); + } else { + gen_helper_udiv64(cpu_reg(rd), n, m); + } + + if (is_32bit) { + if (is_signed) { + tcg_gen_ext32s_i64(cpu_reg(rd), cpu_reg(rd)); + } else { + tcg_gen_ext32u_i64(cpu_reg(rd), cpu_reg(rd)); + } + } + + tcg_temp_free_i64(n); + tcg_temp_free_i64(m); +} + /* SIMD ORR */ static void handle_simdorr(DisasContext *s, uint32_t insn) { @@ -2069,6 +2110,8 @@ void disas_a64_insn(CPUARMState *env, DisasContext *s) case 0x1a: if ((insn & 0x3fe00800) == 0x1a800000) { handle_cinc(s, insn); + } else if ((insn & 0x7fe0f800) == 0x1ac00800) { + handle_div(s, insn); } else { unallocated_encoding(s); } -- 1.7.12.4