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 <ag...@suse.de> > --- > 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