From beee4ad7f3124f7103eb33e8f92aff9f29d9e907 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Sun, 28 Feb 2021 05:18:06 -0500 Subject: [PATCH] target/arm: Implement VFP vp16 VCVT-with-specified-rounding-mode Implement the fp16 versions of the VFP VCVT instruction forms which convert between floating point and integer with a specified rounding mode. Backports c505bc6a9d50a48f9d89d6cf930e863838a5b367 --- qemu/target/arm/translate-vfp.inc.c | 32 +++++++++++++++++++++-------- qemu/target/arm/vfp-uncond.decode | 6 ++++-- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/qemu/target/arm/translate-vfp.inc.c b/qemu/target/arm/translate-vfp.inc.c index 3054c012..c1083380 100644 --- a/qemu/target/arm/translate-vfp.inc.c +++ b/qemu/target/arm/translate-vfp.inc.c @@ -402,7 +402,7 @@ static bool trans_VCVT(DisasContext *s, arg_VCVT *a) { TCGContext *tcg_ctx = s->uc->tcg_ctx; uint32_t rd, rm; - bool dp = a->dp; + int sz = a->sz; TCGv_ptr fpst; TCGv_i32 tcg_rmode, tcg_shift; int rounding = fp_decode_rm[a->rm]; @@ -412,12 +412,16 @@ static bool trans_VCVT(DisasContext *s, arg_VCVT *a) return false; } - if (dp && !dc_isar_feature(aa32_fpdp_v2, s)) { + if (sz == 3 && !dc_isar_feature(aa32_fpdp_v2, s)) { + return false; + } + + if (sz == 1 && !dc_isar_feature(aa32_fp16_arith, s)) { return false; } /* UNDEF accesses to D16-D31 if they don't exist */ - if (dp && !dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) { + if (sz == 3 && !dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) { return false; } @@ -428,14 +432,18 @@ static bool trans_VCVT(DisasContext *s, arg_VCVT *a) return true; } - fpst = fpstatus_ptr(tcg_ctx, FPST_FPCR); + if (sz == 1) { + fpst = fpstatus_ptr(tcg_ctx, FPST_FPCR_F16); + } else { + fpst = fpstatus_ptr(tcg_ctx, FPST_FPCR); + } tcg_shift = tcg_const_i32(tcg_ctx, 0); tcg_rmode = tcg_const_i32(tcg_ctx, arm_rmode_to_sf(rounding)); gen_helper_set_rmode(tcg_ctx, tcg_rmode, tcg_rmode, fpst); - if (dp) { + if (sz == 3) { TCGv_i64 tcg_double, tcg_res; TCGv_i32 tcg_tmp; tcg_double = tcg_temp_new_i64(tcg_ctx); @@ -457,10 +465,18 @@ static bool trans_VCVT(DisasContext *s, arg_VCVT *a) tcg_single = tcg_temp_new_i32(tcg_ctx); tcg_res = tcg_temp_new_i32(tcg_ctx); neon_load_reg32(s, tcg_single, rm); - if (is_signed) { - gen_helper_vfp_tosls(tcg_ctx, tcg_res, tcg_single, tcg_shift, fpst); + if (sz == 1) { + if (is_signed) { + gen_helper_vfp_toslh(tcg_ctx, tcg_res, tcg_single, tcg_shift, fpst); + } else { + gen_helper_vfp_toulh(tcg_ctx, tcg_res, tcg_single, tcg_shift, fpst); + } } else { - gen_helper_vfp_touls(tcg_ctx, tcg_res, tcg_single, tcg_shift, fpst); + if (is_signed) { + gen_helper_vfp_tosls(tcg_ctx, tcg_res, tcg_single, tcg_shift, fpst); + } else { + gen_helper_vfp_touls(tcg_ctx, tcg_res, tcg_single, tcg_shift, fpst); + } } neon_store_reg32(s, tcg_res, rd); tcg_temp_free_i32(tcg_ctx, tcg_res); diff --git a/qemu/target/arm/vfp-uncond.decode b/qemu/target/arm/vfp-uncond.decode index ee700e51..b7cd9d11 100644 --- a/qemu/target/arm/vfp-uncond.decode +++ b/qemu/target/arm/vfp-uncond.decode @@ -64,7 +64,9 @@ VRINT 1111 1110 1.11 10 rm:2 .... 1011 01.0 .... \ vm=%vm_dp vd=%vd_dp dp=1 # VCVT float to int with specified rounding mode; Vd is always single-precision +VCVT 1111 1110 1.11 11 rm:2 .... 1001 op:1 1.0 .... \ + vm=%vm_sp vd=%vd_sp sz=1 VCVT 1111 1110 1.11 11 rm:2 .... 1010 op:1 1.0 .... \ - vm=%vm_sp vd=%vd_sp dp=0 + vm=%vm_sp vd=%vd_sp sz=2 VCVT 1111 1110 1.11 11 rm:2 .... 1011 op:1 1.0 .... \ - vm=%vm_dp vd=%vd_sp dp=1 + vm=%vm_dp vd=%vd_sp sz=3