qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 50/60] AArch64: Add "Floating-point<->fixed-poin


From: Janne Grunau
Subject: Re: [Qemu-devel] [PATCH 50/60] AArch64: Add "Floating-point<->fixed-point
Date: Tue, 19 Nov 2013 21:41:53 +0100
User-agent: Mutt/1.5.21 (2010-09-15)

On 2013-09-27 02:48:44 +0200, Alexander Graf wrote:
> This patch adds emulation for the instruction group labeled
> "Floating-point <-> fixed-point conversions" in the ARM ARM.
> 
> Namely this includes the instructions SCVTF, UCVTF, FCVTZS, FCVTZU
> (scalar, fixed-point).
> 
> Signed-off-by: Alexander Graf <address@hidden>
> ---
>  target-arm/helper-a64.c    |  22 ++++++
>  target-arm/helper-a64.h    |   1 +
>  target-arm/translate-a64.c | 173 
> +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 196 insertions(+)
> 
> diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c
> index a46b00e..0b7aee1 100644
> --- a/target-arm/helper-a64.c
> +++ b/target-arm/helper-a64.c
> @@ -275,3 +275,25 @@ uint64_t HELPER(smulh)(uint64_t n, uint64_t m)
>      muls64(&rl, &rh, n, m);
>      return rh;
>  }
> +
> +void HELPER(set_rmode)(uint32_t rmode, void *fp_status)
> +{
> +    switch (rmode) {
> +    case ROUND_MODE_TIEEVEN:
> +    default:
> +        rmode = float_round_nearest_even;
> +        break;
> +    case ROUND_MODE_UP:
> +        rmode = float_round_up;
> +        break;
> +    case ROUND_MODE_DOWN:
> +        rmode = float_round_down;
> +        break;
> +    case ROUND_MODE_ZERO:
> +        rmode = float_round_to_zero;
> +        break;
> +    /* XXX add fpcr rounding (exact and not exact) */
> +    }
> +
> +    set_float_rounding_mode(rmode, fp_status);
> +}
> diff --git a/target-arm/helper-a64.h b/target-arm/helper-a64.h
> index 41dedd7..f42edf8 100644
> --- a/target-arm/helper-a64.h
> +++ b/target-arm/helper-a64.h
> @@ -30,3 +30,4 @@ DEF_HELPER_FLAGS_1(rbit64, TCG_CALL_NO_RWG_SE, i64, i64)
>  DEF_HELPER_FLAGS_1(clz64, TCG_CALL_NO_RWG_SE, i64, i64)
>  DEF_HELPER_FLAGS_2(umulh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
>  DEF_HELPER_FLAGS_2(smulh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
> +DEF_HELPER_2(set_rmode, void, i32, ptr)
> diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
> index 5985c01..654e011 100644
> --- a/target-arm/translate-a64.c
> +++ b/target-arm/translate-a64.c
> @@ -183,6 +183,17 @@ static void clear_fpreg(int dest)
>      tcg_gen_st_i64(tcg_zero, cpu_env, freg_offs + sizeof(float64));
>  }
>  
> +static TCGv_ptr get_fpstatus_ptr(void)
> +{
> +    TCGv_ptr statusptr = tcg_temp_new_ptr();
> +    int offset;
> +
> +    offset = offsetof(CPUARMState, vfp.standard_fp_status);
> +    tcg_gen_addi_ptr(statusptr, cpu_env, offset);
> +
> +    return statusptr;
> +}
> +
>  static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
>  {
>      TranslationBlock *tb;
> @@ -1718,6 +1729,161 @@ static void handle_dp3s(DisasContext *s, uint32_t 
> insn)
>      tcg_temp_free_i64(tcg_tmp);
>  }
>  
> +static void handle_fpfpcvt(DisasContext *s, uint32_t insn, bool direction,
> +                           int rmode)
> +{
> +    int rd = get_reg(insn);
> +    int rn = get_bits(insn, 5, 5);
> +    int scale = get_bits(insn, 10, 6);
> +    int opcode = get_bits(insn, 16, 3);
> +    int type = get_bits(insn, 22, 2);
> +    bool is_32bit = !get_bits(insn, 31, 1);
> +    bool is_double = get_bits(type, 0, 1);
> +    bool is_signed = !get_bits(opcode, 0, 1);
> +    int freg_offs;
> +    int fp_reg;
> +    TCGv_i64 tcg_int;
> +    TCGv_i64 tcg_single;
> +    TCGv_i64 tcg_double;
> +    TCGv_i64 tcg_fpstatus = get_fpstatus_ptr();
> +    TCGv_i32 tcg_shift = tcg_const_i32(scale);

shift/fractional bits are encoded encoded as 64 - scale for fixed point
to float conversion
feel free to grab
http://git.jannau.net/qemu.git/commit/?h=aarch64-tcg-batch1-v3-fixes&id=16ff73c6801c0c0b677216457dacb64a7d310ad1

> +    TCGv_i32 tcg_rmode = tcg_const_i32(rmode);
> +    TCGv_i64 tcg_tmp;
> +
> +    if (direction) {
> +        fp_reg = rn;
> +        tcg_int = cpu_reg(rd);
> +    } else {
> +        fp_reg = rd;
> +        tcg_int = cpu_reg(rn);
> +    }
> +    freg_offs = offsetof(CPUARMState, vfp.regs[fp_reg * 2]);
> +
> +    if (!direction) {
> +        clear_fpreg(fp_reg);
> +    }
> +
> +    if (is_32bit && !direction) {
> +        tcg_tmp = tcg_temp_new_i64();
> +        if (is_signed) {
> +            tcg_gen_ext32s_i64(tcg_tmp, tcg_int);
> +        } else {
> +            tcg_gen_ext32u_i64(tcg_tmp, tcg_int);
> +        }
> +        tcg_int = tcg_tmp;
> +    }
> +
> +    gen_helper_set_rmode(tcg_rmode, tcg_fpstatus);
> +
> +    switch ((direction ? 0x10 : 0)|
> +            (is_double ? 0x1 : 0) |
> +            (is_signed ? 0x2 : 0)) {
> +    case 0x0: /* unsigned scalar->single */
> +        tcg_single = tcg_temp_new_i32();
> +        tcg_tmp = tcg_temp_new_i64();
> +        gen_helper_vfp_uqtos(tcg_single, tcg_int, tcg_shift, tcg_fpstatus);
> +        tcg_gen_extu_i32_i64(tcg_tmp, tcg_single);
> +        tcg_gen_st32_i64(tcg_tmp, cpu_env, freg_offs);
> +        tcg_temp_free_i32(tcg_single);
> +        tcg_temp_free_i64(tcg_tmp);
> +        break;
> +    case 0x1: /* unsigned scalar->double */
> +        tcg_double = tcg_temp_new_i64();
> +        gen_helper_vfp_uqtod(tcg_double, tcg_int, tcg_shift, tcg_fpstatus);
> +        tcg_gen_st_i64(tcg_double, cpu_env, freg_offs);
> +        tcg_temp_free_i64(tcg_double);
> +        break;
> +    case 0x2: /* signed scalar->single */
> +        tcg_single = tcg_temp_new_i32();
> +        tcg_tmp = tcg_temp_new_i64();
> +        gen_helper_vfp_sqtos(tcg_single, tcg_int, tcg_shift, tcg_fpstatus);
> +        tcg_gen_extu_i32_i64(tcg_tmp, tcg_single);
> +        tcg_gen_st32_i64(tcg_tmp, cpu_env, freg_offs);
> +        tcg_temp_free_i32(tcg_single);
> +        tcg_temp_free_i64(tcg_tmp);
> +        break;
> +    case 0x3: /* signed scalar->double */
> +        tcg_double = tcg_temp_new_i64();
> +        gen_helper_vfp_sqtod(tcg_double, tcg_int, tcg_shift, tcg_fpstatus);
> +        tcg_gen_st_i64(tcg_double, cpu_env, freg_offs);
> +        tcg_temp_free_i64(tcg_double);
> +        break;
> +    case 0x10: /* unsigned single->scalar */
> +        tcg_single = tcg_temp_new_i32();
> +        tcg_tmp = tcg_temp_new_i64();
> +        tcg_gen_ld32u_i64(tcg_tmp, cpu_env, freg_offs);
> +        tcg_gen_trunc_i64_i32(tcg_single, tcg_tmp);
> +        gen_helper_vfp_touqs(tcg_int, tcg_single, tcg_shift, tcg_fpstatus);
> +        tcg_temp_free_i32(tcg_single);
> +        tcg_temp_free_i64(tcg_tmp);
> +        break;
> +    case 0x11: /* unsigned single->double */
> +        tcg_double = tcg_temp_new_i64();
> +        tcg_gen_ld_i64(tcg_double, cpu_env, freg_offs);
> +        gen_helper_vfp_touqd(tcg_int, tcg_double, tcg_shift, tcg_fpstatus);
> +        tcg_temp_free_i64(tcg_double);
> +        break;
> +    case 0x12: /* signed single->scalar */
> +        tcg_single = tcg_temp_new_i32();
> +        tcg_tmp = tcg_temp_new_i64();
> +        tcg_gen_ld32u_i64(tcg_tmp, cpu_env, freg_offs);
> +        tcg_gen_trunc_i64_i32(tcg_single, tcg_tmp);
> +        gen_helper_vfp_tosqs(tcg_int, tcg_single, tcg_shift, tcg_fpstatus);
> +        tcg_temp_free_i32(tcg_single);
> +        tcg_temp_free_i64(tcg_tmp);
> +        break;
> +    case 0x13: /* signed single->double */
> +        tcg_double = tcg_temp_new_i64();
> +        tcg_gen_ld_i64(tcg_double, cpu_env, freg_offs);
> +        gen_helper_vfp_tosqd(tcg_int, tcg_double, tcg_shift, tcg_fpstatus);
> +        tcg_temp_free_i64(tcg_double);
> +        break;
> +    default:
> +        unallocated_encoding(s);
> +    }
> +
> +    /* XXX use fpcr */
> +    tcg_gen_movi_i32(tcg_rmode, -1);
> +    gen_helper_set_rmode(tcg_rmode, tcg_fpstatus);
> +
> +    if (is_32bit && direction) {
> +        tcg_gen_ext32u_i64(tcg_int, tcg_int);
> +    }
> +
> +    tcg_temp_free_i64(tcg_fpstatus);
> +    tcg_temp_free_i32(tcg_shift);
> +    tcg_temp_free_i32(tcg_rmode);
> +}
> +
> +/* fixed <-> floating conversion */
> +static void handle_fpfpconv(DisasContext *s, uint32_t insn)
> +{
> +    int opcode = get_bits(insn, 16, 3);
> +    int rmode = get_bits(insn, 20, 2);

rmode is at 19

> +    int type = get_bits(insn, 22, 2);
> +    bool is_s = get_bits(insn, 29, 1);
> +    bool direction;
> +
> +    if (is_s || (type > 1) || (opcode > 1)) {
> +        unallocated_encoding(s);
> +        return;
> +    }
> +
> +    switch (rmode) {
> +    case 0x1: /* [S|U]CVTF (scalar->float) */

and it's case 0x0: for [S|U]CVTF
see
http://git.jannau.net/qemu.git/commit/?h=aarch64-tcg-batch1-v3-fixes&id=69cd918ae935e98dc5245f5d594a0e4162f65d59

> +        direction = 0;
> +        break;
> +    case 0x3: /* FCVTZ[S|U] (float->scalar) */

The comments don't make much sense it's scalar (opposed to vector) float
to fixed point conversion

Janne



reply via email to

[Prev in Thread] Current Thread [Next in Thread]