On Wed, 2013-12-18 at 14:48 -0600, Tom Musta wrote:
> 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.
> 
> V2: Moved the 128-bit divide routine into host-utils per Richard
> Henderson's suggestion.
> 
> Signed-off-by: Tom Musta <tommu...@gmail.com>
> ---
>  include/qemu/host-utils.h |   14 ++++++++++++++
>  target-ppc/helper.h       |    1 +
>  target-ppc/int_helper.c   |   27 +++++++++++++++++++++++++++
>  target-ppc/translate.c    |   20 ++++++++++++++++++++
>  util/host-utils.c         |   38 ++++++++++++++++++++++++++++++++++++++
>  5 files changed, 100 insertions(+), 0 deletions(-)
> 
> diff --git a/include/qemu/host-utils.h b/include/qemu/host-utils.h
> index 0f688c1..0ca187d 100644
> --- a/include/qemu/host-utils.h
> +++ b/include/qemu/host-utils.h
> @@ -44,9 +44,23 @@ static inline void muls64(uint64_t *plow, uint64_t *phigh,
>      *plow = r;
>      *phigh = r >> 64;
>  }
> +
> +static inline int divu128(uint64_t *plow, uint64_t *phigh, uint64_t divisor)
> +{
> +    if (divisor == 0) {
> +        return 1;
> +    } else {
> +        __uint128_t dividend = ((__uint128_t)*phigh << 64) | *plow;
> +        __uint128_t result = dividend / divisor;
> +        *plow = result;
> +        *phigh = dividend % divisor;
> +        return result > UINT64_MAX;
> +    }
> +}
>  #else
>  void muls64(uint64_t *phigh, uint64_t *plow, int64_t a, int64_t b);
>  void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b);
> +int divu128(uint64_t *plow, uint64_t *phigh, uint64_t divisor);
>  #endif
>  
>  /**
> 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 abc69a7..d6dcac9 100644
> --- a/target-ppc/int_helper.c
> +++ b/target-ppc/int_helper.c
> @@ -41,6 +41,33 @@ uint64_t helper_mulldo(CPUPPCState *env, uint64_t arg1, 
> uint64_t arg2)
>  }
>  #endif
>  
> +#if defined(TARGET_PPC64)
> +
> +uint64_t helper_divdeu(CPUPPCState *env, uint64_t ra, uint64_t rb, uint32_t 
> oe)
> +{
> +    uint64_t rt = 0;
> +    int overflow = 0;
> +
> +    overflow = divu128(&rt, &ra, rb);
> +
> +    if (unlikely(overflow)) {
> +        rt = 0; /* Undefined */
> +    }
> +
> +    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),

These instructions are phased-in on embedded, and unlike bpermd are not
present on e5500/e6500 which are 64-bit ISA 2.06 implementations.
Wasn't the conclusion in a previous thread to use separate flags for
these instruction groups?

-Scott



Reply via email to