This patch adds the Divide Doubleword Extended Unsigned instructions. This instruction requires dividing a 128-bit value by a 64 bit value. Since 128 bit integer division is not supported in TCG, a helper is used, providing a repeated difference algorithm.
Signed-off-by: Tom Musta <tommu...@gmail.com> --- target-ppc/helper.h | 1 + target-ppc/int_helper.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ target-ppc/translate.c | 20 ++++++++++++++++++++ 3 files changed, 68 insertions(+), 0 deletions(-) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 1ec9c65..3eff4df 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -31,6 +31,7 @@ DEF_HELPER_5(lscbx, tl, env, tl, i32, i32, i32) #if defined(TARGET_PPC64) DEF_HELPER_3(mulldo, i64, env, i64, i64) +DEF_HELPER_4(divdeu, i64, env, i64, i64, i32) #endif DEF_HELPER_FLAGS_1(cntlzw, TCG_CALL_NO_RWG_SE, tl, tl) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index c140a0d..94a54d2 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -41,6 +41,53 @@ uint64_t helper_mulldo(CPUPPCState *env, uint64_t arg1, uint64_t arg2) } #endif +#if defined(TARGET_PPC64) + +static void _divide_u64_extended(uint64_t ra, uint64_t rb, uint64_t *quotient, int *overflow) +{ + int i; + uint64_t carry = 0; + + *quotient = 0; + *overflow = 0; + + if ((ra >= rb) || (rb == 0)) { + *overflow = 1; + return; + } + + for (i = 0; i <= 64; i++) { + *quotient = (*quotient) << 1; + if ((rb <= ra) || carry) { + *quotient |= 1; + ra -= rb; + } + carry = ra & 0x8000000000000000ul; + ra <<= 1; + } +} + +uint64_t helper_divdeu(CPUPPCState *env, uint64_t ra, uint64_t rb, uint32_t oe) +{ + uint64_t rt = 0; + int overflow = 0; + + _divide_u64_extended(ra, rb, &rt, &overflow); + + if (oe) { + if (unlikely(overflow)) { + env->so = env->ov = 1; + } else { + env->ov = 0; + } + } + + return rt; +} + +#endif + + target_ulong helper_cntlzw(target_ulong t) { return clz32(t); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 0d39de2..7a51c6d 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1032,6 +1032,23 @@ GEN_INT_ARITH_DIVD(divduo, 0x1E, 0, 1); /* divw divw. divwo divwo. */ GEN_INT_ARITH_DIVD(divd, 0x0F, 1, 0); GEN_INT_ARITH_DIVD(divdo, 0x1F, 1, 1); + +/* divdeu[o][.] */ +#define GEN_DIVDE(name, hlpr, compute_ov) \ +static void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_i32 t0 = tcg_const_i32(compute_ov); \ + gen_helper_##hlpr(cpu_gpr[rD(ctx->opcode)], cpu_env, \ + cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0); \ + tcg_temp_free_i32(t0); \ + if (unlikely(Rc(ctx->opcode) != 0)) { \ + gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); \ + } \ +} + +GEN_DIVDE(divdeu, divdeu, 0); +GEN_DIVDE(divdeuo, divdeu, 1); + #endif /* mulhw mulhw. */ @@ -9594,6 +9611,9 @@ GEN_INT_ARITH_DIVD(divduo, 0x1E, 0, 1), GEN_INT_ARITH_DIVD(divd, 0x0F, 1, 0), GEN_INT_ARITH_DIVD(divdo, 0x1F, 1, 1), +GEN_HANDLER_E(divdeu, 0x1F, 0x09, 0x0C, 0x00000000, PPC_NONE, PPC2_ISA206), +GEN_HANDLER_E(divdeuo, 0x1F, 0x09, 0x1C, 0x00000000, PPC_NONE, PPC2_ISA206), + #undef GEN_INT_ARITH_MUL_HELPER #define GEN_INT_ARITH_MUL_HELPER(name, opc3) \ GEN_HANDLER(name, 0x1F, 0x09, opc3, 0x00000000, PPC_64B) -- 1.7.1