11deb15c8SPeter Maydell /* 21deb15c8SPeter Maydell * ARM VFP floating-point operations 31deb15c8SPeter Maydell * 41deb15c8SPeter Maydell * Copyright (c) 2003 Fabrice Bellard 51deb15c8SPeter Maydell * 61deb15c8SPeter Maydell * This library is free software; you can redistribute it and/or 71deb15c8SPeter Maydell * modify it under the terms of the GNU Lesser General Public 81deb15c8SPeter Maydell * License as published by the Free Software Foundation; either 91deb15c8SPeter Maydell * version 2.1 of the License, or (at your option) any later version. 101deb15c8SPeter Maydell * 111deb15c8SPeter Maydell * This library is distributed in the hope that it will be useful, 121deb15c8SPeter Maydell * but WITHOUT ANY WARRANTY; without even the implied warranty of 131deb15c8SPeter Maydell * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 141deb15c8SPeter Maydell * Lesser General Public License for more details. 151deb15c8SPeter Maydell * 161deb15c8SPeter Maydell * You should have received a copy of the GNU Lesser General Public 171deb15c8SPeter Maydell * License along with this library; if not, see <http://www.gnu.org/licenses/>. 181deb15c8SPeter Maydell */ 191deb15c8SPeter Maydell 201deb15c8SPeter Maydell #include "qemu/osdep.h" 211deb15c8SPeter Maydell #include "cpu.h" 221deb15c8SPeter Maydell #include "exec/helper-proto.h" 231deb15c8SPeter Maydell #include "internals.h" 241deb15c8SPeter Maydell #include "cpu-features.h" 251deb15c8SPeter Maydell #include "fpu/softfloat.h" 261deb15c8SPeter Maydell #include "qemu/log.h" 271deb15c8SPeter Maydell 281deb15c8SPeter Maydell /* 29*b9d3dc45SPeter Maydell * Set the float_status behaviour to match the Arm defaults: 30*b9d3dc45SPeter Maydell * * tininess-before-rounding 31*b9d3dc45SPeter Maydell * * 2-input NaN propagation prefers SNaN over QNaN, and then 32*b9d3dc45SPeter Maydell * operand A over operand B (see FPProcessNaNs() pseudocode) 33*b9d3dc45SPeter Maydell * * 3-input NaN propagation prefers SNaN over QNaN, and then 34*b9d3dc45SPeter Maydell * operand C over A over B (see FPProcessNaNs3() pseudocode, 35*b9d3dc45SPeter Maydell * but note that for QEMU muladd is a * b + c, whereas for 36*b9d3dc45SPeter Maydell * the pseudocode function the arguments are in the order c, a, b. 37*b9d3dc45SPeter Maydell * * 0 * Inf + NaN returns the default NaN if the input NaN is quiet, 38*b9d3dc45SPeter Maydell * and the input NaN if it is signalling 39*b9d3dc45SPeter Maydell * * Default NaN has sign bit clear, msb frac bit set 40*b9d3dc45SPeter Maydell */ 41*b9d3dc45SPeter Maydell void arm_set_default_fp_behaviours(float_status *s) 42*b9d3dc45SPeter Maydell { 43*b9d3dc45SPeter Maydell set_float_detect_tininess(float_tininess_before_rounding, s); 44*b9d3dc45SPeter Maydell set_float_ftz_detection(float_ftz_before_rounding, s); 45*b9d3dc45SPeter Maydell set_float_2nan_prop_rule(float_2nan_prop_s_ab, s); 46*b9d3dc45SPeter Maydell set_float_3nan_prop_rule(float_3nan_prop_s_cab, s); 47*b9d3dc45SPeter Maydell set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, s); 48*b9d3dc45SPeter Maydell set_float_default_nan_pattern(0b01000000, s); 49*b9d3dc45SPeter Maydell } 50*b9d3dc45SPeter Maydell 51*b9d3dc45SPeter Maydell /* 52*b9d3dc45SPeter Maydell * Set the float_status behaviour to match the FEAT_AFP 53*b9d3dc45SPeter Maydell * FPCR.AH=1 requirements: 54*b9d3dc45SPeter Maydell * * tininess-after-rounding 55*b9d3dc45SPeter Maydell * * 2-input NaN propagation prefers the first NaN 56*b9d3dc45SPeter Maydell * * 3-input NaN propagation prefers a over b over c 57*b9d3dc45SPeter Maydell * * 0 * Inf + NaN always returns the input NaN and doesn't 58*b9d3dc45SPeter Maydell * set Invalid for a QNaN 59*b9d3dc45SPeter Maydell * * default NaN has sign bit set, msb frac bit set 60*b9d3dc45SPeter Maydell */ 61*b9d3dc45SPeter Maydell void arm_set_ah_fp_behaviours(float_status *s) 62*b9d3dc45SPeter Maydell { 63*b9d3dc45SPeter Maydell set_float_detect_tininess(float_tininess_after_rounding, s); 64*b9d3dc45SPeter Maydell set_float_ftz_detection(float_ftz_after_rounding, s); 65*b9d3dc45SPeter Maydell set_float_2nan_prop_rule(float_2nan_prop_ab, s); 66*b9d3dc45SPeter Maydell set_float_3nan_prop_rule(float_3nan_prop_abc, s); 67*b9d3dc45SPeter Maydell set_float_infzeronan_rule(float_infzeronan_dnan_never | 68*b9d3dc45SPeter Maydell float_infzeronan_suppress_invalid, s); 69*b9d3dc45SPeter Maydell set_float_default_nan_pattern(0b11000000, s); 70*b9d3dc45SPeter Maydell } 71*b9d3dc45SPeter Maydell 72*b9d3dc45SPeter Maydell /* Convert host exception flags to vfp form. */ 73*b9d3dc45SPeter Maydell static inline uint32_t vfp_exceptbits_from_host(int host_bits, bool ah) 74*b9d3dc45SPeter Maydell { 75*b9d3dc45SPeter Maydell uint32_t target_bits = 0; 76*b9d3dc45SPeter Maydell 77*b9d3dc45SPeter Maydell if (host_bits & float_flag_invalid) { 78*b9d3dc45SPeter Maydell target_bits |= FPSR_IOC; 79*b9d3dc45SPeter Maydell } 80*b9d3dc45SPeter Maydell if (host_bits & float_flag_divbyzero) { 81*b9d3dc45SPeter Maydell target_bits |= FPSR_DZC; 82*b9d3dc45SPeter Maydell } 83*b9d3dc45SPeter Maydell if (host_bits & float_flag_overflow) { 84*b9d3dc45SPeter Maydell target_bits |= FPSR_OFC; 85*b9d3dc45SPeter Maydell } 86*b9d3dc45SPeter Maydell if (host_bits & (float_flag_underflow | float_flag_output_denormal_flushed)) { 87*b9d3dc45SPeter Maydell target_bits |= FPSR_UFC; 88*b9d3dc45SPeter Maydell } 89*b9d3dc45SPeter Maydell if (host_bits & float_flag_inexact) { 90*b9d3dc45SPeter Maydell target_bits |= FPSR_IXC; 91*b9d3dc45SPeter Maydell } 92*b9d3dc45SPeter Maydell if (host_bits & float_flag_input_denormal_flushed) { 93*b9d3dc45SPeter Maydell target_bits |= FPSR_IDC; 94*b9d3dc45SPeter Maydell } 95*b9d3dc45SPeter Maydell /* 96*b9d3dc45SPeter Maydell * With FPCR.AH, IDC is set when an input denormal is used, 97*b9d3dc45SPeter Maydell * and flushing an output denormal to zero sets both IXC and UFC. 98*b9d3dc45SPeter Maydell */ 99*b9d3dc45SPeter Maydell if (ah && (host_bits & float_flag_input_denormal_used)) { 100*b9d3dc45SPeter Maydell target_bits |= FPSR_IDC; 101*b9d3dc45SPeter Maydell } 102*b9d3dc45SPeter Maydell if (ah && (host_bits & float_flag_output_denormal_flushed)) { 103*b9d3dc45SPeter Maydell target_bits |= FPSR_IXC; 104*b9d3dc45SPeter Maydell } 105*b9d3dc45SPeter Maydell return target_bits; 106*b9d3dc45SPeter Maydell } 107*b9d3dc45SPeter Maydell 108*b9d3dc45SPeter Maydell uint32_t vfp_get_fpsr_from_host(CPUARMState *env) 109*b9d3dc45SPeter Maydell { 110*b9d3dc45SPeter Maydell uint32_t a32_flags = 0, a64_flags = 0; 111*b9d3dc45SPeter Maydell 112*b9d3dc45SPeter Maydell a32_flags |= get_float_exception_flags(&env->vfp.fp_status[FPST_A32]); 113*b9d3dc45SPeter Maydell a32_flags |= get_float_exception_flags(&env->vfp.fp_status[FPST_STD]); 114*b9d3dc45SPeter Maydell /* FZ16 does not generate an input denormal exception. */ 115*b9d3dc45SPeter Maydell a32_flags |= (get_float_exception_flags(&env->vfp.fp_status[FPST_A32_F16]) 116*b9d3dc45SPeter Maydell & ~float_flag_input_denormal_flushed); 117*b9d3dc45SPeter Maydell a32_flags |= (get_float_exception_flags(&env->vfp.fp_status[FPST_STD_F16]) 118*b9d3dc45SPeter Maydell & ~float_flag_input_denormal_flushed); 119*b9d3dc45SPeter Maydell 120*b9d3dc45SPeter Maydell a64_flags |= get_float_exception_flags(&env->vfp.fp_status[FPST_A64]); 121*b9d3dc45SPeter Maydell a64_flags |= (get_float_exception_flags(&env->vfp.fp_status[FPST_A64_F16]) 122*b9d3dc45SPeter Maydell & ~(float_flag_input_denormal_flushed | float_flag_input_denormal_used)); 123*b9d3dc45SPeter Maydell /* 124*b9d3dc45SPeter Maydell * We do not merge in flags from FPST_AH or FPST_AH_F16, because 125*b9d3dc45SPeter Maydell * they are used for insns that must not set the cumulative exception bits. 126*b9d3dc45SPeter Maydell */ 127*b9d3dc45SPeter Maydell 128*b9d3dc45SPeter Maydell /* 129*b9d3dc45SPeter Maydell * Flushing an input denormal *only* because FPCR.FIZ == 1 does 130*b9d3dc45SPeter Maydell * not set FPSR.IDC; if FPCR.FZ is also set then this takes 131*b9d3dc45SPeter Maydell * precedence and IDC is set (see the FPUnpackBase pseudocode). 132*b9d3dc45SPeter Maydell * So squash it unless (FPCR.AH == 0 && FPCR.FZ == 1). 133*b9d3dc45SPeter Maydell * We only do this for the a64 flags because FIZ has no effect 134*b9d3dc45SPeter Maydell * on AArch32 even if it is set. 135*b9d3dc45SPeter Maydell */ 136*b9d3dc45SPeter Maydell if ((env->vfp.fpcr & (FPCR_FZ | FPCR_AH)) != FPCR_FZ) { 137*b9d3dc45SPeter Maydell a64_flags &= ~float_flag_input_denormal_flushed; 138*b9d3dc45SPeter Maydell } 139*b9d3dc45SPeter Maydell return vfp_exceptbits_from_host(a64_flags, env->vfp.fpcr & FPCR_AH) | 140*b9d3dc45SPeter Maydell vfp_exceptbits_from_host(a32_flags, false); 141*b9d3dc45SPeter Maydell } 142*b9d3dc45SPeter Maydell 143*b9d3dc45SPeter Maydell void vfp_clear_float_status_exc_flags(CPUARMState *env) 144*b9d3dc45SPeter Maydell { 145*b9d3dc45SPeter Maydell /* 146*b9d3dc45SPeter Maydell * Clear out all the exception-flag information in the float_status 147*b9d3dc45SPeter Maydell * values. The caller should have arranged for env->vfp.fpsr to 148*b9d3dc45SPeter Maydell * be the architecturally up-to-date exception flag information first. 149*b9d3dc45SPeter Maydell */ 150*b9d3dc45SPeter Maydell set_float_exception_flags(0, &env->vfp.fp_status[FPST_A32]); 151*b9d3dc45SPeter Maydell set_float_exception_flags(0, &env->vfp.fp_status[FPST_A64]); 152*b9d3dc45SPeter Maydell set_float_exception_flags(0, &env->vfp.fp_status[FPST_A32_F16]); 153*b9d3dc45SPeter Maydell set_float_exception_flags(0, &env->vfp.fp_status[FPST_A64_F16]); 154*b9d3dc45SPeter Maydell set_float_exception_flags(0, &env->vfp.fp_status[FPST_STD]); 155*b9d3dc45SPeter Maydell set_float_exception_flags(0, &env->vfp.fp_status[FPST_STD_F16]); 156*b9d3dc45SPeter Maydell set_float_exception_flags(0, &env->vfp.fp_status[FPST_AH]); 157*b9d3dc45SPeter Maydell set_float_exception_flags(0, &env->vfp.fp_status[FPST_AH_F16]); 158*b9d3dc45SPeter Maydell } 159*b9d3dc45SPeter Maydell 160*b9d3dc45SPeter Maydell static void vfp_sync_and_clear_float_status_exc_flags(CPUARMState *env) 161*b9d3dc45SPeter Maydell { 162*b9d3dc45SPeter Maydell /* 163*b9d3dc45SPeter Maydell * Synchronize any pending exception-flag information in the 164*b9d3dc45SPeter Maydell * float_status values into env->vfp.fpsr, and then clear out 165*b9d3dc45SPeter Maydell * the float_status data. 166*b9d3dc45SPeter Maydell */ 167*b9d3dc45SPeter Maydell env->vfp.fpsr |= vfp_get_fpsr_from_host(env); 168*b9d3dc45SPeter Maydell vfp_clear_float_status_exc_flags(env); 169*b9d3dc45SPeter Maydell } 170*b9d3dc45SPeter Maydell 171*b9d3dc45SPeter Maydell void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask) 172*b9d3dc45SPeter Maydell { 173*b9d3dc45SPeter Maydell uint64_t changed = env->vfp.fpcr; 174*b9d3dc45SPeter Maydell 175*b9d3dc45SPeter Maydell changed ^= val; 176*b9d3dc45SPeter Maydell changed &= mask; 177*b9d3dc45SPeter Maydell if (changed & (3 << 22)) { 178*b9d3dc45SPeter Maydell int i = (val >> 22) & 3; 179*b9d3dc45SPeter Maydell switch (i) { 180*b9d3dc45SPeter Maydell case FPROUNDING_TIEEVEN: 181*b9d3dc45SPeter Maydell i = float_round_nearest_even; 182*b9d3dc45SPeter Maydell break; 183*b9d3dc45SPeter Maydell case FPROUNDING_POSINF: 184*b9d3dc45SPeter Maydell i = float_round_up; 185*b9d3dc45SPeter Maydell break; 186*b9d3dc45SPeter Maydell case FPROUNDING_NEGINF: 187*b9d3dc45SPeter Maydell i = float_round_down; 188*b9d3dc45SPeter Maydell break; 189*b9d3dc45SPeter Maydell case FPROUNDING_ZERO: 190*b9d3dc45SPeter Maydell i = float_round_to_zero; 191*b9d3dc45SPeter Maydell break; 192*b9d3dc45SPeter Maydell } 193*b9d3dc45SPeter Maydell set_float_rounding_mode(i, &env->vfp.fp_status[FPST_A32]); 194*b9d3dc45SPeter Maydell set_float_rounding_mode(i, &env->vfp.fp_status[FPST_A64]); 195*b9d3dc45SPeter Maydell set_float_rounding_mode(i, &env->vfp.fp_status[FPST_A32_F16]); 196*b9d3dc45SPeter Maydell set_float_rounding_mode(i, &env->vfp.fp_status[FPST_A64_F16]); 197*b9d3dc45SPeter Maydell } 198*b9d3dc45SPeter Maydell if (changed & FPCR_FZ16) { 199*b9d3dc45SPeter Maydell bool ftz_enabled = val & FPCR_FZ16; 200*b9d3dc45SPeter Maydell set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A32_F16]); 201*b9d3dc45SPeter Maydell set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A64_F16]); 202*b9d3dc45SPeter Maydell set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_STD_F16]); 203*b9d3dc45SPeter Maydell set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_AH_F16]); 204*b9d3dc45SPeter Maydell set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A32_F16]); 205*b9d3dc45SPeter Maydell set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A64_F16]); 206*b9d3dc45SPeter Maydell set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_STD_F16]); 207*b9d3dc45SPeter Maydell set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_AH_F16]); 208*b9d3dc45SPeter Maydell } 209*b9d3dc45SPeter Maydell if (changed & FPCR_FZ) { 210*b9d3dc45SPeter Maydell bool ftz_enabled = val & FPCR_FZ; 211*b9d3dc45SPeter Maydell set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A32]); 212*b9d3dc45SPeter Maydell set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A64]); 213*b9d3dc45SPeter Maydell /* FIZ is A64 only so FZ always makes A32 code flush inputs to zero */ 214*b9d3dc45SPeter Maydell set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A32]); 215*b9d3dc45SPeter Maydell } 216*b9d3dc45SPeter Maydell if (changed & (FPCR_FZ | FPCR_AH | FPCR_FIZ)) { 217*b9d3dc45SPeter Maydell /* 218*b9d3dc45SPeter Maydell * A64: Flush denormalized inputs to zero if FPCR.FIZ = 1, or 219*b9d3dc45SPeter Maydell * both FPCR.AH = 0 and FPCR.FZ = 1. 220*b9d3dc45SPeter Maydell */ 221*b9d3dc45SPeter Maydell bool fitz_enabled = (val & FPCR_FIZ) || 222*b9d3dc45SPeter Maydell (val & (FPCR_FZ | FPCR_AH)) == FPCR_FZ; 223*b9d3dc45SPeter Maydell set_flush_inputs_to_zero(fitz_enabled, &env->vfp.fp_status[FPST_A64]); 224*b9d3dc45SPeter Maydell } 225*b9d3dc45SPeter Maydell if (changed & FPCR_DN) { 226*b9d3dc45SPeter Maydell bool dnan_enabled = val & FPCR_DN; 227*b9d3dc45SPeter Maydell set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_A32]); 228*b9d3dc45SPeter Maydell set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_A64]); 229*b9d3dc45SPeter Maydell set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_A32_F16]); 230*b9d3dc45SPeter Maydell set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_A64_F16]); 231*b9d3dc45SPeter Maydell set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_AH]); 232*b9d3dc45SPeter Maydell set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_AH_F16]); 233*b9d3dc45SPeter Maydell } 234*b9d3dc45SPeter Maydell if (changed & FPCR_AH) { 235*b9d3dc45SPeter Maydell bool ah_enabled = val & FPCR_AH; 236*b9d3dc45SPeter Maydell 237*b9d3dc45SPeter Maydell if (ah_enabled) { 238*b9d3dc45SPeter Maydell /* Change behaviours for A64 FP operations */ 239*b9d3dc45SPeter Maydell arm_set_ah_fp_behaviours(&env->vfp.fp_status[FPST_A64]); 240*b9d3dc45SPeter Maydell arm_set_ah_fp_behaviours(&env->vfp.fp_status[FPST_A64_F16]); 241*b9d3dc45SPeter Maydell } else { 242*b9d3dc45SPeter Maydell arm_set_default_fp_behaviours(&env->vfp.fp_status[FPST_A64]); 243*b9d3dc45SPeter Maydell arm_set_default_fp_behaviours(&env->vfp.fp_status[FPST_A64_F16]); 244*b9d3dc45SPeter Maydell } 245*b9d3dc45SPeter Maydell } 246*b9d3dc45SPeter Maydell /* 247*b9d3dc45SPeter Maydell * If any bits changed that we look at in vfp_get_fpsr_from_host(), 248*b9d3dc45SPeter Maydell * we must sync the float_status flags into vfp.fpsr now (under the 249*b9d3dc45SPeter Maydell * old regime) before we update vfp.fpcr. 250*b9d3dc45SPeter Maydell */ 251*b9d3dc45SPeter Maydell if (changed & (FPCR_FZ | FPCR_AH | FPCR_FIZ)) { 252*b9d3dc45SPeter Maydell vfp_sync_and_clear_float_status_exc_flags(env); 253*b9d3dc45SPeter Maydell } 254*b9d3dc45SPeter Maydell } 255*b9d3dc45SPeter Maydell 256*b9d3dc45SPeter Maydell /* 2571deb15c8SPeter Maydell * VFP support. We follow the convention used for VFP instructions: 2581deb15c8SPeter Maydell * Single precision routines have a "s" suffix, double precision a 2591deb15c8SPeter Maydell * "d" suffix. 2601deb15c8SPeter Maydell */ 2611deb15c8SPeter Maydell 2621deb15c8SPeter Maydell #define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p)) 2631deb15c8SPeter Maydell 2641deb15c8SPeter Maydell #define VFP_BINOP(name) \ 2651deb15c8SPeter Maydell dh_ctype_f16 VFP_HELPER(name, h)(dh_ctype_f16 a, dh_ctype_f16 b, float_status *fpst) \ 2661deb15c8SPeter Maydell { \ 2671deb15c8SPeter Maydell return float16_ ## name(a, b, fpst); \ 2681deb15c8SPeter Maydell } \ 2691deb15c8SPeter Maydell float32 VFP_HELPER(name, s)(float32 a, float32 b, float_status *fpst) \ 2701deb15c8SPeter Maydell { \ 2711deb15c8SPeter Maydell return float32_ ## name(a, b, fpst); \ 2721deb15c8SPeter Maydell } \ 2731deb15c8SPeter Maydell float64 VFP_HELPER(name, d)(float64 a, float64 b, float_status *fpst) \ 2741deb15c8SPeter Maydell { \ 2751deb15c8SPeter Maydell return float64_ ## name(a, b, fpst); \ 2761deb15c8SPeter Maydell } 2771deb15c8SPeter Maydell VFP_BINOP(add) 2781deb15c8SPeter Maydell VFP_BINOP(sub) 2791deb15c8SPeter Maydell VFP_BINOP(mul) 2801deb15c8SPeter Maydell VFP_BINOP(div) 2811deb15c8SPeter Maydell VFP_BINOP(min) 2821deb15c8SPeter Maydell VFP_BINOP(max) 2831deb15c8SPeter Maydell VFP_BINOP(minnum) 2841deb15c8SPeter Maydell VFP_BINOP(maxnum) 2851deb15c8SPeter Maydell #undef VFP_BINOP 2861deb15c8SPeter Maydell 2871deb15c8SPeter Maydell dh_ctype_f16 VFP_HELPER(sqrt, h)(dh_ctype_f16 a, float_status *fpst) 2881deb15c8SPeter Maydell { 2891deb15c8SPeter Maydell return float16_sqrt(a, fpst); 2901deb15c8SPeter Maydell } 2911deb15c8SPeter Maydell 2921deb15c8SPeter Maydell float32 VFP_HELPER(sqrt, s)(float32 a, float_status *fpst) 2931deb15c8SPeter Maydell { 2941deb15c8SPeter Maydell return float32_sqrt(a, fpst); 2951deb15c8SPeter Maydell } 2961deb15c8SPeter Maydell 2971deb15c8SPeter Maydell float64 VFP_HELPER(sqrt, d)(float64 a, float_status *fpst) 2981deb15c8SPeter Maydell { 2991deb15c8SPeter Maydell return float64_sqrt(a, fpst); 3001deb15c8SPeter Maydell } 3011deb15c8SPeter Maydell 3021deb15c8SPeter Maydell static void softfloat_to_vfp_compare(CPUARMState *env, FloatRelation cmp) 3031deb15c8SPeter Maydell { 3041deb15c8SPeter Maydell uint32_t flags; 3051deb15c8SPeter Maydell switch (cmp) { 3061deb15c8SPeter Maydell case float_relation_equal: 3071deb15c8SPeter Maydell flags = 0x6; 3081deb15c8SPeter Maydell break; 3091deb15c8SPeter Maydell case float_relation_less: 3101deb15c8SPeter Maydell flags = 0x8; 3111deb15c8SPeter Maydell break; 3121deb15c8SPeter Maydell case float_relation_greater: 3131deb15c8SPeter Maydell flags = 0x2; 3141deb15c8SPeter Maydell break; 3151deb15c8SPeter Maydell case float_relation_unordered: 3161deb15c8SPeter Maydell flags = 0x3; 3171deb15c8SPeter Maydell break; 3181deb15c8SPeter Maydell default: 3191deb15c8SPeter Maydell g_assert_not_reached(); 3201deb15c8SPeter Maydell } 3211deb15c8SPeter Maydell env->vfp.fpsr = deposit64(env->vfp.fpsr, 28, 4, flags); /* NZCV */ 3221deb15c8SPeter Maydell } 3231deb15c8SPeter Maydell 3241deb15c8SPeter Maydell /* XXX: check quiet/signaling case */ 3251deb15c8SPeter Maydell #define DO_VFP_cmp(P, FLOATTYPE, ARGTYPE, FPST) \ 3261deb15c8SPeter Maydell void VFP_HELPER(cmp, P)(ARGTYPE a, ARGTYPE b, CPUARMState *env) \ 3271deb15c8SPeter Maydell { \ 3281deb15c8SPeter Maydell softfloat_to_vfp_compare(env, \ 3291deb15c8SPeter Maydell FLOATTYPE ## _compare_quiet(a, b, &env->vfp.fp_status[FPST])); \ 3301deb15c8SPeter Maydell } \ 3311deb15c8SPeter Maydell void VFP_HELPER(cmpe, P)(ARGTYPE a, ARGTYPE b, CPUARMState *env) \ 3321deb15c8SPeter Maydell { \ 3331deb15c8SPeter Maydell softfloat_to_vfp_compare(env, \ 3341deb15c8SPeter Maydell FLOATTYPE ## _compare(a, b, &env->vfp.fp_status[FPST])); \ 3351deb15c8SPeter Maydell } 3361deb15c8SPeter Maydell DO_VFP_cmp(h, float16, dh_ctype_f16, FPST_A32_F16) 3371deb15c8SPeter Maydell DO_VFP_cmp(s, float32, float32, FPST_A32) 3381deb15c8SPeter Maydell DO_VFP_cmp(d, float64, float64, FPST_A32) 3391deb15c8SPeter Maydell #undef DO_VFP_cmp 3401deb15c8SPeter Maydell 3411deb15c8SPeter Maydell /* Integer to float and float to integer conversions */ 3421deb15c8SPeter Maydell 3431deb15c8SPeter Maydell #define CONV_ITOF(name, ftype, fsz, sign) \ 3441deb15c8SPeter Maydell ftype HELPER(name)(uint32_t x, float_status *fpst) \ 3451deb15c8SPeter Maydell { \ 3461deb15c8SPeter Maydell return sign##int32_to_##float##fsz((sign##int32_t)x, fpst); \ 3471deb15c8SPeter Maydell } 3481deb15c8SPeter Maydell 3491deb15c8SPeter Maydell #define CONV_FTOI(name, ftype, fsz, sign, round) \ 3501deb15c8SPeter Maydell sign##int32_t HELPER(name)(ftype x, float_status *fpst) \ 3511deb15c8SPeter Maydell { \ 3521deb15c8SPeter Maydell if (float##fsz##_is_any_nan(x)) { \ 3531deb15c8SPeter Maydell float_raise(float_flag_invalid, fpst); \ 3541deb15c8SPeter Maydell return 0; \ 3551deb15c8SPeter Maydell } \ 3561deb15c8SPeter Maydell return float##fsz##_to_##sign##int32##round(x, fpst); \ 3571deb15c8SPeter Maydell } 3581deb15c8SPeter Maydell 3591deb15c8SPeter Maydell #define FLOAT_CONVS(name, p, ftype, fsz, sign) \ 3601deb15c8SPeter Maydell CONV_ITOF(vfp_##name##to##p, ftype, fsz, sign) \ 3611deb15c8SPeter Maydell CONV_FTOI(vfp_to##name##p, ftype, fsz, sign, ) \ 3621deb15c8SPeter Maydell CONV_FTOI(vfp_to##name##z##p, ftype, fsz, sign, _round_to_zero) 3631deb15c8SPeter Maydell 3641deb15c8SPeter Maydell FLOAT_CONVS(si, h, uint32_t, 16, ) 3651deb15c8SPeter Maydell FLOAT_CONVS(si, s, float32, 32, ) 3661deb15c8SPeter Maydell FLOAT_CONVS(si, d, float64, 64, ) 3671deb15c8SPeter Maydell FLOAT_CONVS(ui, h, uint32_t, 16, u) 3681deb15c8SPeter Maydell FLOAT_CONVS(ui, s, float32, 32, u) 3691deb15c8SPeter Maydell FLOAT_CONVS(ui, d, float64, 64, u) 3701deb15c8SPeter Maydell 3711deb15c8SPeter Maydell #undef CONV_ITOF 3721deb15c8SPeter Maydell #undef CONV_FTOI 3731deb15c8SPeter Maydell #undef FLOAT_CONVS 3741deb15c8SPeter Maydell 3751deb15c8SPeter Maydell /* floating point conversion */ 3761deb15c8SPeter Maydell float64 VFP_HELPER(fcvtd, s)(float32 x, float_status *status) 3771deb15c8SPeter Maydell { 3781deb15c8SPeter Maydell return float32_to_float64(x, status); 3791deb15c8SPeter Maydell } 3801deb15c8SPeter Maydell 3811deb15c8SPeter Maydell float32 VFP_HELPER(fcvts, d)(float64 x, float_status *status) 3821deb15c8SPeter Maydell { 3831deb15c8SPeter Maydell return float64_to_float32(x, status); 3841deb15c8SPeter Maydell } 3851deb15c8SPeter Maydell 3861deb15c8SPeter Maydell uint32_t HELPER(bfcvt)(float32 x, float_status *status) 3871deb15c8SPeter Maydell { 3881deb15c8SPeter Maydell return float32_to_bfloat16(x, status); 3891deb15c8SPeter Maydell } 3901deb15c8SPeter Maydell 3911deb15c8SPeter Maydell uint32_t HELPER(bfcvt_pair)(uint64_t pair, float_status *status) 3921deb15c8SPeter Maydell { 3931deb15c8SPeter Maydell bfloat16 lo = float32_to_bfloat16(extract64(pair, 0, 32), status); 3941deb15c8SPeter Maydell bfloat16 hi = float32_to_bfloat16(extract64(pair, 32, 32), status); 3951deb15c8SPeter Maydell return deposit32(lo, 16, 16, hi); 3961deb15c8SPeter Maydell } 3971deb15c8SPeter Maydell 3981deb15c8SPeter Maydell /* 3991deb15c8SPeter Maydell * VFP3 fixed point conversion. The AArch32 versions of fix-to-float 4001deb15c8SPeter Maydell * must always round-to-nearest; the AArch64 ones honour the FPSCR 4011deb15c8SPeter Maydell * rounding mode. (For AArch32 Neon the standard-FPSCR is set to 4021deb15c8SPeter Maydell * round-to-nearest so either helper will work.) AArch32 float-to-fix 4031deb15c8SPeter Maydell * must round-to-zero. 4041deb15c8SPeter Maydell */ 4051deb15c8SPeter Maydell #define VFP_CONV_FIX_FLOAT(name, p, fsz, ftype, isz, itype) \ 4061deb15c8SPeter Maydell ftype HELPER(vfp_##name##to##p)(uint##isz##_t x, uint32_t shift, \ 4071deb15c8SPeter Maydell float_status *fpst) \ 4081deb15c8SPeter Maydell { return itype##_to_##float##fsz##_scalbn(x, -shift, fpst); } 4091deb15c8SPeter Maydell 4101deb15c8SPeter Maydell #define VFP_CONV_FIX_FLOAT_ROUND(name, p, fsz, ftype, isz, itype) \ 4111deb15c8SPeter Maydell ftype HELPER(vfp_##name##to##p##_round_to_nearest)(uint##isz##_t x, \ 4121deb15c8SPeter Maydell uint32_t shift, \ 4131deb15c8SPeter Maydell float_status *fpst) \ 4141deb15c8SPeter Maydell { \ 4151deb15c8SPeter Maydell ftype ret; \ 4161deb15c8SPeter Maydell FloatRoundMode oldmode = fpst->float_rounding_mode; \ 4171deb15c8SPeter Maydell fpst->float_rounding_mode = float_round_nearest_even; \ 4181deb15c8SPeter Maydell ret = itype##_to_##float##fsz##_scalbn(x, -shift, fpst); \ 4191deb15c8SPeter Maydell fpst->float_rounding_mode = oldmode; \ 4201deb15c8SPeter Maydell return ret; \ 4211deb15c8SPeter Maydell } 4221deb15c8SPeter Maydell 4231deb15c8SPeter Maydell #define VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, ftype, isz, itype, ROUND, suff) \ 4241deb15c8SPeter Maydell uint##isz##_t HELPER(vfp_to##name##p##suff)(ftype x, uint32_t shift, \ 4251deb15c8SPeter Maydell float_status *fpst) \ 4261deb15c8SPeter Maydell { \ 4271deb15c8SPeter Maydell if (unlikely(float##fsz##_is_any_nan(x))) { \ 4281deb15c8SPeter Maydell float_raise(float_flag_invalid, fpst); \ 4291deb15c8SPeter Maydell return 0; \ 4301deb15c8SPeter Maydell } \ 4311deb15c8SPeter Maydell return float##fsz##_to_##itype##_scalbn(x, ROUND, shift, fpst); \ 4321deb15c8SPeter Maydell } 4331deb15c8SPeter Maydell 4341deb15c8SPeter Maydell #define VFP_CONV_FIX(name, p, fsz, ftype, isz, itype) \ 4351deb15c8SPeter Maydell VFP_CONV_FIX_FLOAT(name, p, fsz, ftype, isz, itype) \ 4361deb15c8SPeter Maydell VFP_CONV_FIX_FLOAT_ROUND(name, p, fsz, ftype, isz, itype) \ 4371deb15c8SPeter Maydell VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, ftype, isz, itype, \ 4381deb15c8SPeter Maydell float_round_to_zero, _round_to_zero) \ 4391deb15c8SPeter Maydell VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, ftype, isz, itype, \ 4401deb15c8SPeter Maydell get_float_rounding_mode(fpst), ) 4411deb15c8SPeter Maydell 4421deb15c8SPeter Maydell #define VFP_CONV_FIX_A64(name, p, fsz, ftype, isz, itype) \ 4431deb15c8SPeter Maydell VFP_CONV_FIX_FLOAT(name, p, fsz, ftype, isz, itype) \ 4441deb15c8SPeter Maydell VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, ftype, isz, itype, \ 4451deb15c8SPeter Maydell get_float_rounding_mode(fpst), ) 4461deb15c8SPeter Maydell 4471deb15c8SPeter Maydell VFP_CONV_FIX(sh, d, 64, float64, 64, int16) 4481deb15c8SPeter Maydell VFP_CONV_FIX(sl, d, 64, float64, 64, int32) 4491deb15c8SPeter Maydell VFP_CONV_FIX_A64(sq, d, 64, float64, 64, int64) 4501deb15c8SPeter Maydell VFP_CONV_FIX(uh, d, 64, float64, 64, uint16) 4511deb15c8SPeter Maydell VFP_CONV_FIX(ul, d, 64, float64, 64, uint32) 4521deb15c8SPeter Maydell VFP_CONV_FIX_A64(uq, d, 64, float64, 64, uint64) 4531deb15c8SPeter Maydell VFP_CONV_FIX(sh, s, 32, float32, 32, int16) 4541deb15c8SPeter Maydell VFP_CONV_FIX(sl, s, 32, float32, 32, int32) 4551deb15c8SPeter Maydell VFP_CONV_FIX_A64(sq, s, 32, float32, 64, int64) 4561deb15c8SPeter Maydell VFP_CONV_FIX(uh, s, 32, float32, 32, uint16) 4571deb15c8SPeter Maydell VFP_CONV_FIX(ul, s, 32, float32, 32, uint32) 4581deb15c8SPeter Maydell VFP_CONV_FIX_A64(uq, s, 32, float32, 64, uint64) 4591deb15c8SPeter Maydell VFP_CONV_FIX(sh, h, 16, dh_ctype_f16, 32, int16) 4601deb15c8SPeter Maydell VFP_CONV_FIX(sl, h, 16, dh_ctype_f16, 32, int32) 4611deb15c8SPeter Maydell VFP_CONV_FIX_A64(sq, h, 16, dh_ctype_f16, 64, int64) 4621deb15c8SPeter Maydell VFP_CONV_FIX(uh, h, 16, dh_ctype_f16, 32, uint16) 4631deb15c8SPeter Maydell VFP_CONV_FIX(ul, h, 16, dh_ctype_f16, 32, uint32) 4641deb15c8SPeter Maydell VFP_CONV_FIX_A64(uq, h, 16, dh_ctype_f16, 64, uint64) 4651deb15c8SPeter Maydell VFP_CONV_FLOAT_FIX_ROUND(sq, d, 64, float64, 64, int64, 4661deb15c8SPeter Maydell float_round_to_zero, _round_to_zero) 4671deb15c8SPeter Maydell VFP_CONV_FLOAT_FIX_ROUND(uq, d, 64, float64, 64, uint64, 4681deb15c8SPeter Maydell float_round_to_zero, _round_to_zero) 4691deb15c8SPeter Maydell 4701deb15c8SPeter Maydell #undef VFP_CONV_FIX 4711deb15c8SPeter Maydell #undef VFP_CONV_FIX_FLOAT 4721deb15c8SPeter Maydell #undef VFP_CONV_FLOAT_FIX_ROUND 4731deb15c8SPeter Maydell #undef VFP_CONV_FIX_A64 4741deb15c8SPeter Maydell 4751deb15c8SPeter Maydell /* Set the current fp rounding mode and return the old one. 4761deb15c8SPeter Maydell * The argument is a softfloat float_round_ value. 4771deb15c8SPeter Maydell */ 4781deb15c8SPeter Maydell uint32_t HELPER(set_rmode)(uint32_t rmode, float_status *fp_status) 4791deb15c8SPeter Maydell { 4801deb15c8SPeter Maydell uint32_t prev_rmode = get_float_rounding_mode(fp_status); 4811deb15c8SPeter Maydell set_float_rounding_mode(rmode, fp_status); 4821deb15c8SPeter Maydell 4831deb15c8SPeter Maydell return prev_rmode; 4841deb15c8SPeter Maydell } 4851deb15c8SPeter Maydell 4861deb15c8SPeter Maydell /* Half precision conversions. */ 4871deb15c8SPeter Maydell float32 HELPER(vfp_fcvt_f16_to_f32)(uint32_t a, float_status *fpst, 4881deb15c8SPeter Maydell uint32_t ahp_mode) 4891deb15c8SPeter Maydell { 4901deb15c8SPeter Maydell /* Squash FZ16 to 0 for the duration of conversion. In this case, 4911deb15c8SPeter Maydell * it would affect flushing input denormals. 4921deb15c8SPeter Maydell */ 4931deb15c8SPeter Maydell bool save = get_flush_inputs_to_zero(fpst); 4941deb15c8SPeter Maydell set_flush_inputs_to_zero(false, fpst); 4951deb15c8SPeter Maydell float32 r = float16_to_float32(a, !ahp_mode, fpst); 4961deb15c8SPeter Maydell set_flush_inputs_to_zero(save, fpst); 4971deb15c8SPeter Maydell return r; 4981deb15c8SPeter Maydell } 4991deb15c8SPeter Maydell 5001deb15c8SPeter Maydell uint32_t HELPER(vfp_fcvt_f32_to_f16)(float32 a, float_status *fpst, 5011deb15c8SPeter Maydell uint32_t ahp_mode) 5021deb15c8SPeter Maydell { 5031deb15c8SPeter Maydell /* Squash FZ16 to 0 for the duration of conversion. In this case, 5041deb15c8SPeter Maydell * it would affect flushing output denormals. 5051deb15c8SPeter Maydell */ 5061deb15c8SPeter Maydell bool save = get_flush_to_zero(fpst); 5071deb15c8SPeter Maydell set_flush_to_zero(false, fpst); 5081deb15c8SPeter Maydell float16 r = float32_to_float16(a, !ahp_mode, fpst); 5091deb15c8SPeter Maydell set_flush_to_zero(save, fpst); 5101deb15c8SPeter Maydell return r; 5111deb15c8SPeter Maydell } 5121deb15c8SPeter Maydell 5131deb15c8SPeter Maydell float64 HELPER(vfp_fcvt_f16_to_f64)(uint32_t a, float_status *fpst, 5141deb15c8SPeter Maydell uint32_t ahp_mode) 5151deb15c8SPeter Maydell { 5161deb15c8SPeter Maydell /* Squash FZ16 to 0 for the duration of conversion. In this case, 5171deb15c8SPeter Maydell * it would affect flushing input denormals. 5181deb15c8SPeter Maydell */ 5191deb15c8SPeter Maydell bool save = get_flush_inputs_to_zero(fpst); 5201deb15c8SPeter Maydell set_flush_inputs_to_zero(false, fpst); 5211deb15c8SPeter Maydell float64 r = float16_to_float64(a, !ahp_mode, fpst); 5221deb15c8SPeter Maydell set_flush_inputs_to_zero(save, fpst); 5231deb15c8SPeter Maydell return r; 5241deb15c8SPeter Maydell } 5251deb15c8SPeter Maydell 5261deb15c8SPeter Maydell uint32_t HELPER(vfp_fcvt_f64_to_f16)(float64 a, float_status *fpst, 5271deb15c8SPeter Maydell uint32_t ahp_mode) 5281deb15c8SPeter Maydell { 5291deb15c8SPeter Maydell /* Squash FZ16 to 0 for the duration of conversion. In this case, 5301deb15c8SPeter Maydell * it would affect flushing output denormals. 5311deb15c8SPeter Maydell */ 5321deb15c8SPeter Maydell bool save = get_flush_to_zero(fpst); 5331deb15c8SPeter Maydell set_flush_to_zero(false, fpst); 5341deb15c8SPeter Maydell float16 r = float64_to_float16(a, !ahp_mode, fpst); 5351deb15c8SPeter Maydell set_flush_to_zero(save, fpst); 5361deb15c8SPeter Maydell return r; 5371deb15c8SPeter Maydell } 5381deb15c8SPeter Maydell 5391deb15c8SPeter Maydell /* NEON helpers. */ 5401deb15c8SPeter Maydell 5411deb15c8SPeter Maydell /* Constants 256 and 512 are used in some helpers; we avoid relying on 5421deb15c8SPeter Maydell * int->float conversions at run-time. */ 5431deb15c8SPeter Maydell #define float64_256 make_float64(0x4070000000000000LL) 5441deb15c8SPeter Maydell #define float64_512 make_float64(0x4080000000000000LL) 5451deb15c8SPeter Maydell #define float16_maxnorm make_float16(0x7bff) 5461deb15c8SPeter Maydell #define float32_maxnorm make_float32(0x7f7fffff) 5471deb15c8SPeter Maydell #define float64_maxnorm make_float64(0x7fefffffffffffffLL) 5481deb15c8SPeter Maydell 5491deb15c8SPeter Maydell /* Reciprocal functions 5501deb15c8SPeter Maydell * 5511deb15c8SPeter Maydell * The algorithm that must be used to calculate the estimate 5521deb15c8SPeter Maydell * is specified by the ARM ARM, see FPRecipEstimate()/RecipEstimate 5531deb15c8SPeter Maydell */ 5541deb15c8SPeter Maydell 5551deb15c8SPeter Maydell /* See RecipEstimate() 5561deb15c8SPeter Maydell * 5571deb15c8SPeter Maydell * input is a 9 bit fixed point number 5581deb15c8SPeter Maydell * input range 256 .. 511 for a number from 0.5 <= x < 1.0. 5591deb15c8SPeter Maydell * result range 256 .. 511 for a number from 1.0 to 511/256. 5601deb15c8SPeter Maydell */ 5611deb15c8SPeter Maydell 5621deb15c8SPeter Maydell static int recip_estimate(int input) 5631deb15c8SPeter Maydell { 5641deb15c8SPeter Maydell int a, b, r; 5651deb15c8SPeter Maydell assert(256 <= input && input < 512); 5661deb15c8SPeter Maydell a = (input * 2) + 1; 5671deb15c8SPeter Maydell b = (1 << 19) / a; 5681deb15c8SPeter Maydell r = (b + 1) >> 1; 5691deb15c8SPeter Maydell assert(256 <= r && r < 512); 5701deb15c8SPeter Maydell return r; 5711deb15c8SPeter Maydell } 5721deb15c8SPeter Maydell 5731deb15c8SPeter Maydell /* 5741deb15c8SPeter Maydell * Increased precision version: 5751deb15c8SPeter Maydell * input is a 13 bit fixed point number 5761deb15c8SPeter Maydell * input range 2048 .. 4095 for a number from 0.5 <= x < 1.0. 5771deb15c8SPeter Maydell * result range 4096 .. 8191 for a number from 1.0 to 2.0 5781deb15c8SPeter Maydell */ 5791deb15c8SPeter Maydell static int recip_estimate_incprec(int input) 5801deb15c8SPeter Maydell { 5811deb15c8SPeter Maydell int a, b, r; 5821deb15c8SPeter Maydell assert(2048 <= input && input < 4096); 5831deb15c8SPeter Maydell a = (input * 2) + 1; 5841deb15c8SPeter Maydell /* 5851deb15c8SPeter Maydell * The pseudocode expresses this as an operation on infinite 5861deb15c8SPeter Maydell * precision reals where it calculates 2^25 / a and then looks 5871deb15c8SPeter Maydell * at the error between that and the rounded-down-to-integer 5881deb15c8SPeter Maydell * value to see if it should instead round up. We instead 5891deb15c8SPeter Maydell * follow the same approach as the pseudocode for the 8-bit 5901deb15c8SPeter Maydell * precision version, and calculate (2 * (2^25 / a)) as an 5911deb15c8SPeter Maydell * integer so we can do the "add one and halve" to round it. 5921deb15c8SPeter Maydell * So the 1 << 26 here is correct. 5931deb15c8SPeter Maydell */ 5941deb15c8SPeter Maydell b = (1 << 26) / a; 5951deb15c8SPeter Maydell r = (b + 1) >> 1; 5961deb15c8SPeter Maydell assert(4096 <= r && r < 8192); 5971deb15c8SPeter Maydell return r; 5981deb15c8SPeter Maydell } 5991deb15c8SPeter Maydell 6001deb15c8SPeter Maydell /* 6011deb15c8SPeter Maydell * Common wrapper to call recip_estimate 6021deb15c8SPeter Maydell * 6031deb15c8SPeter Maydell * The parameters are exponent and 64 bit fraction (without implicit 6041deb15c8SPeter Maydell * bit) where the binary point is nominally at bit 52. Returns a 6051deb15c8SPeter Maydell * float64 which can then be rounded to the appropriate size by the 6061deb15c8SPeter Maydell * callee. 6071deb15c8SPeter Maydell */ 6081deb15c8SPeter Maydell 6091deb15c8SPeter Maydell static uint64_t call_recip_estimate(int *exp, int exp_off, uint64_t frac, 6101deb15c8SPeter Maydell bool increasedprecision) 6111deb15c8SPeter Maydell { 6121deb15c8SPeter Maydell uint32_t scaled, estimate; 6131deb15c8SPeter Maydell uint64_t result_frac; 6141deb15c8SPeter Maydell int result_exp; 6151deb15c8SPeter Maydell 6161deb15c8SPeter Maydell /* Handle sub-normals */ 6171deb15c8SPeter Maydell if (*exp == 0) { 6181deb15c8SPeter Maydell if (extract64(frac, 51, 1) == 0) { 6191deb15c8SPeter Maydell *exp = -1; 6201deb15c8SPeter Maydell frac <<= 2; 6211deb15c8SPeter Maydell } else { 6221deb15c8SPeter Maydell frac <<= 1; 6231deb15c8SPeter Maydell } 6241deb15c8SPeter Maydell } 6251deb15c8SPeter Maydell 6261deb15c8SPeter Maydell if (increasedprecision) { 6271deb15c8SPeter Maydell /* scaled = UInt('1':fraction<51:41>) */ 6281deb15c8SPeter Maydell scaled = deposit32(1 << 11, 0, 11, extract64(frac, 41, 11)); 6291deb15c8SPeter Maydell estimate = recip_estimate_incprec(scaled); 6301deb15c8SPeter Maydell } else { 6311deb15c8SPeter Maydell /* scaled = UInt('1':fraction<51:44>) */ 6321deb15c8SPeter Maydell scaled = deposit32(1 << 8, 0, 8, extract64(frac, 44, 8)); 6331deb15c8SPeter Maydell estimate = recip_estimate(scaled); 6341deb15c8SPeter Maydell } 6351deb15c8SPeter Maydell 6361deb15c8SPeter Maydell result_exp = exp_off - *exp; 6371deb15c8SPeter Maydell if (increasedprecision) { 6381deb15c8SPeter Maydell result_frac = deposit64(0, 40, 12, estimate); 6391deb15c8SPeter Maydell } else { 6401deb15c8SPeter Maydell result_frac = deposit64(0, 44, 8, estimate); 6411deb15c8SPeter Maydell } 6421deb15c8SPeter Maydell if (result_exp == 0) { 6431deb15c8SPeter Maydell result_frac = deposit64(result_frac >> 1, 51, 1, 1); 6441deb15c8SPeter Maydell } else if (result_exp == -1) { 6451deb15c8SPeter Maydell result_frac = deposit64(result_frac >> 2, 50, 2, 1); 6461deb15c8SPeter Maydell result_exp = 0; 6471deb15c8SPeter Maydell } 6481deb15c8SPeter Maydell 6491deb15c8SPeter Maydell *exp = result_exp; 6501deb15c8SPeter Maydell 6511deb15c8SPeter Maydell return result_frac; 6521deb15c8SPeter Maydell } 6531deb15c8SPeter Maydell 6541deb15c8SPeter Maydell static bool round_to_inf(float_status *fpst, bool sign_bit) 6551deb15c8SPeter Maydell { 6561deb15c8SPeter Maydell switch (fpst->float_rounding_mode) { 6571deb15c8SPeter Maydell case float_round_nearest_even: /* Round to Nearest */ 6581deb15c8SPeter Maydell return true; 6591deb15c8SPeter Maydell case float_round_up: /* Round to +Inf */ 6601deb15c8SPeter Maydell return !sign_bit; 6611deb15c8SPeter Maydell case float_round_down: /* Round to -Inf */ 6621deb15c8SPeter Maydell return sign_bit; 6631deb15c8SPeter Maydell case float_round_to_zero: /* Round to Zero */ 6641deb15c8SPeter Maydell return false; 6651deb15c8SPeter Maydell default: 6661deb15c8SPeter Maydell g_assert_not_reached(); 6671deb15c8SPeter Maydell } 6681deb15c8SPeter Maydell } 6691deb15c8SPeter Maydell 6701deb15c8SPeter Maydell uint32_t HELPER(recpe_f16)(uint32_t input, float_status *fpst) 6711deb15c8SPeter Maydell { 6721deb15c8SPeter Maydell float16 f16 = float16_squash_input_denormal(input, fpst); 6731deb15c8SPeter Maydell uint32_t f16_val = float16_val(f16); 6741deb15c8SPeter Maydell uint32_t f16_sign = float16_is_neg(f16); 6751deb15c8SPeter Maydell int f16_exp = extract32(f16_val, 10, 5); 6761deb15c8SPeter Maydell uint32_t f16_frac = extract32(f16_val, 0, 10); 6771deb15c8SPeter Maydell uint64_t f64_frac; 6781deb15c8SPeter Maydell 6791deb15c8SPeter Maydell if (float16_is_any_nan(f16)) { 6801deb15c8SPeter Maydell float16 nan = f16; 6811deb15c8SPeter Maydell if (float16_is_signaling_nan(f16, fpst)) { 6821deb15c8SPeter Maydell float_raise(float_flag_invalid, fpst); 6831deb15c8SPeter Maydell if (!fpst->default_nan_mode) { 6841deb15c8SPeter Maydell nan = float16_silence_nan(f16, fpst); 6851deb15c8SPeter Maydell } 6861deb15c8SPeter Maydell } 6871deb15c8SPeter Maydell if (fpst->default_nan_mode) { 6881deb15c8SPeter Maydell nan = float16_default_nan(fpst); 6891deb15c8SPeter Maydell } 6901deb15c8SPeter Maydell return nan; 6911deb15c8SPeter Maydell } else if (float16_is_infinity(f16)) { 6921deb15c8SPeter Maydell return float16_set_sign(float16_zero, float16_is_neg(f16)); 6931deb15c8SPeter Maydell } else if (float16_is_zero(f16)) { 6941deb15c8SPeter Maydell float_raise(float_flag_divbyzero, fpst); 6951deb15c8SPeter Maydell return float16_set_sign(float16_infinity, float16_is_neg(f16)); 6961deb15c8SPeter Maydell } else if (float16_abs(f16) < (1 << 8)) { 6971deb15c8SPeter Maydell /* Abs(value) < 2.0^-16 */ 6981deb15c8SPeter Maydell float_raise(float_flag_overflow | float_flag_inexact, fpst); 6991deb15c8SPeter Maydell if (round_to_inf(fpst, f16_sign)) { 7001deb15c8SPeter Maydell return float16_set_sign(float16_infinity, f16_sign); 7011deb15c8SPeter Maydell } else { 7021deb15c8SPeter Maydell return float16_set_sign(float16_maxnorm, f16_sign); 7031deb15c8SPeter Maydell } 7041deb15c8SPeter Maydell } else if (f16_exp >= 29 && fpst->flush_to_zero) { 7051deb15c8SPeter Maydell float_raise(float_flag_underflow, fpst); 7061deb15c8SPeter Maydell return float16_set_sign(float16_zero, float16_is_neg(f16)); 7071deb15c8SPeter Maydell } 7081deb15c8SPeter Maydell 7091deb15c8SPeter Maydell f64_frac = call_recip_estimate(&f16_exp, 29, 7101deb15c8SPeter Maydell ((uint64_t) f16_frac) << (52 - 10), false); 7111deb15c8SPeter Maydell 7121deb15c8SPeter Maydell /* result = sign : result_exp<4:0> : fraction<51:42> */ 7131deb15c8SPeter Maydell f16_val = deposit32(0, 15, 1, f16_sign); 7141deb15c8SPeter Maydell f16_val = deposit32(f16_val, 10, 5, f16_exp); 7151deb15c8SPeter Maydell f16_val = deposit32(f16_val, 0, 10, extract64(f64_frac, 52 - 10, 10)); 7161deb15c8SPeter Maydell return make_float16(f16_val); 7171deb15c8SPeter Maydell } 7181deb15c8SPeter Maydell 7191deb15c8SPeter Maydell /* 7201deb15c8SPeter Maydell * FEAT_RPRES means the f32 FRECPE has an "increased precision" variant 7211deb15c8SPeter Maydell * which is used when FPCR.AH == 1. 7221deb15c8SPeter Maydell */ 7231deb15c8SPeter Maydell static float32 do_recpe_f32(float32 input, float_status *fpst, bool rpres) 7241deb15c8SPeter Maydell { 7251deb15c8SPeter Maydell float32 f32 = float32_squash_input_denormal(input, fpst); 7261deb15c8SPeter Maydell uint32_t f32_val = float32_val(f32); 7271deb15c8SPeter Maydell bool f32_sign = float32_is_neg(f32); 7281deb15c8SPeter Maydell int f32_exp = extract32(f32_val, 23, 8); 7291deb15c8SPeter Maydell uint32_t f32_frac = extract32(f32_val, 0, 23); 7301deb15c8SPeter Maydell uint64_t f64_frac; 7311deb15c8SPeter Maydell 7321deb15c8SPeter Maydell if (float32_is_any_nan(f32)) { 7331deb15c8SPeter Maydell float32 nan = f32; 7341deb15c8SPeter Maydell if (float32_is_signaling_nan(f32, fpst)) { 7351deb15c8SPeter Maydell float_raise(float_flag_invalid, fpst); 7361deb15c8SPeter Maydell if (!fpst->default_nan_mode) { 7371deb15c8SPeter Maydell nan = float32_silence_nan(f32, fpst); 7381deb15c8SPeter Maydell } 7391deb15c8SPeter Maydell } 7401deb15c8SPeter Maydell if (fpst->default_nan_mode) { 7411deb15c8SPeter Maydell nan = float32_default_nan(fpst); 7421deb15c8SPeter Maydell } 7431deb15c8SPeter Maydell return nan; 7441deb15c8SPeter Maydell } else if (float32_is_infinity(f32)) { 7451deb15c8SPeter Maydell return float32_set_sign(float32_zero, float32_is_neg(f32)); 7461deb15c8SPeter Maydell } else if (float32_is_zero(f32)) { 7471deb15c8SPeter Maydell float_raise(float_flag_divbyzero, fpst); 7481deb15c8SPeter Maydell return float32_set_sign(float32_infinity, float32_is_neg(f32)); 7491deb15c8SPeter Maydell } else if (float32_abs(f32) < (1ULL << 21)) { 7501deb15c8SPeter Maydell /* Abs(value) < 2.0^-128 */ 7511deb15c8SPeter Maydell float_raise(float_flag_overflow | float_flag_inexact, fpst); 7521deb15c8SPeter Maydell if (round_to_inf(fpst, f32_sign)) { 7531deb15c8SPeter Maydell return float32_set_sign(float32_infinity, f32_sign); 7541deb15c8SPeter Maydell } else { 7551deb15c8SPeter Maydell return float32_set_sign(float32_maxnorm, f32_sign); 7561deb15c8SPeter Maydell } 7571deb15c8SPeter Maydell } else if (f32_exp >= 253 && fpst->flush_to_zero) { 7581deb15c8SPeter Maydell float_raise(float_flag_underflow, fpst); 7591deb15c8SPeter Maydell return float32_set_sign(float32_zero, float32_is_neg(f32)); 7601deb15c8SPeter Maydell } 7611deb15c8SPeter Maydell 7621deb15c8SPeter Maydell f64_frac = call_recip_estimate(&f32_exp, 253, 7631deb15c8SPeter Maydell ((uint64_t) f32_frac) << (52 - 23), rpres); 7641deb15c8SPeter Maydell 7651deb15c8SPeter Maydell /* result = sign : result_exp<7:0> : fraction<51:29> */ 7661deb15c8SPeter Maydell f32_val = deposit32(0, 31, 1, f32_sign); 7671deb15c8SPeter Maydell f32_val = deposit32(f32_val, 23, 8, f32_exp); 7681deb15c8SPeter Maydell f32_val = deposit32(f32_val, 0, 23, extract64(f64_frac, 52 - 23, 23)); 7691deb15c8SPeter Maydell return make_float32(f32_val); 7701deb15c8SPeter Maydell } 7711deb15c8SPeter Maydell 7721deb15c8SPeter Maydell float32 HELPER(recpe_f32)(float32 input, float_status *fpst) 7731deb15c8SPeter Maydell { 7741deb15c8SPeter Maydell return do_recpe_f32(input, fpst, false); 7751deb15c8SPeter Maydell } 7761deb15c8SPeter Maydell 7771deb15c8SPeter Maydell float32 HELPER(recpe_rpres_f32)(float32 input, float_status *fpst) 7781deb15c8SPeter Maydell { 7791deb15c8SPeter Maydell return do_recpe_f32(input, fpst, true); 7801deb15c8SPeter Maydell } 7811deb15c8SPeter Maydell 7821deb15c8SPeter Maydell float64 HELPER(recpe_f64)(float64 input, float_status *fpst) 7831deb15c8SPeter Maydell { 7841deb15c8SPeter Maydell float64 f64 = float64_squash_input_denormal(input, fpst); 7851deb15c8SPeter Maydell uint64_t f64_val = float64_val(f64); 7861deb15c8SPeter Maydell bool f64_sign = float64_is_neg(f64); 7871deb15c8SPeter Maydell int f64_exp = extract64(f64_val, 52, 11); 7881deb15c8SPeter Maydell uint64_t f64_frac = extract64(f64_val, 0, 52); 7891deb15c8SPeter Maydell 7901deb15c8SPeter Maydell /* Deal with any special cases */ 7911deb15c8SPeter Maydell if (float64_is_any_nan(f64)) { 7921deb15c8SPeter Maydell float64 nan = f64; 7931deb15c8SPeter Maydell if (float64_is_signaling_nan(f64, fpst)) { 7941deb15c8SPeter Maydell float_raise(float_flag_invalid, fpst); 7951deb15c8SPeter Maydell if (!fpst->default_nan_mode) { 7961deb15c8SPeter Maydell nan = float64_silence_nan(f64, fpst); 7971deb15c8SPeter Maydell } 7981deb15c8SPeter Maydell } 7991deb15c8SPeter Maydell if (fpst->default_nan_mode) { 8001deb15c8SPeter Maydell nan = float64_default_nan(fpst); 8011deb15c8SPeter Maydell } 8021deb15c8SPeter Maydell return nan; 8031deb15c8SPeter Maydell } else if (float64_is_infinity(f64)) { 8041deb15c8SPeter Maydell return float64_set_sign(float64_zero, float64_is_neg(f64)); 8051deb15c8SPeter Maydell } else if (float64_is_zero(f64)) { 8061deb15c8SPeter Maydell float_raise(float_flag_divbyzero, fpst); 8071deb15c8SPeter Maydell return float64_set_sign(float64_infinity, float64_is_neg(f64)); 8081deb15c8SPeter Maydell } else if ((f64_val & ~(1ULL << 63)) < (1ULL << 50)) { 8091deb15c8SPeter Maydell /* Abs(value) < 2.0^-1024 */ 8101deb15c8SPeter Maydell float_raise(float_flag_overflow | float_flag_inexact, fpst); 8111deb15c8SPeter Maydell if (round_to_inf(fpst, f64_sign)) { 8121deb15c8SPeter Maydell return float64_set_sign(float64_infinity, f64_sign); 8131deb15c8SPeter Maydell } else { 8141deb15c8SPeter Maydell return float64_set_sign(float64_maxnorm, f64_sign); 8151deb15c8SPeter Maydell } 8161deb15c8SPeter Maydell } else if (f64_exp >= 2045 && fpst->flush_to_zero) { 8171deb15c8SPeter Maydell float_raise(float_flag_underflow, fpst); 8181deb15c8SPeter Maydell return float64_set_sign(float64_zero, float64_is_neg(f64)); 8191deb15c8SPeter Maydell } 8201deb15c8SPeter Maydell 8211deb15c8SPeter Maydell f64_frac = call_recip_estimate(&f64_exp, 2045, f64_frac, false); 8221deb15c8SPeter Maydell 8231deb15c8SPeter Maydell /* result = sign : result_exp<10:0> : fraction<51:0>; */ 8241deb15c8SPeter Maydell f64_val = deposit64(0, 63, 1, f64_sign); 8251deb15c8SPeter Maydell f64_val = deposit64(f64_val, 52, 11, f64_exp); 8261deb15c8SPeter Maydell f64_val = deposit64(f64_val, 0, 52, f64_frac); 8271deb15c8SPeter Maydell return make_float64(f64_val); 8281deb15c8SPeter Maydell } 8291deb15c8SPeter Maydell 8301deb15c8SPeter Maydell /* The algorithm that must be used to calculate the estimate 8311deb15c8SPeter Maydell * is specified by the ARM ARM. 8321deb15c8SPeter Maydell */ 8331deb15c8SPeter Maydell 8341deb15c8SPeter Maydell static int do_recip_sqrt_estimate(int a) 8351deb15c8SPeter Maydell { 8361deb15c8SPeter Maydell int b, estimate; 8371deb15c8SPeter Maydell 8381deb15c8SPeter Maydell assert(128 <= a && a < 512); 8391deb15c8SPeter Maydell if (a < 256) { 8401deb15c8SPeter Maydell a = a * 2 + 1; 8411deb15c8SPeter Maydell } else { 8421deb15c8SPeter Maydell a = (a >> 1) << 1; 8431deb15c8SPeter Maydell a = (a + 1) * 2; 8441deb15c8SPeter Maydell } 8451deb15c8SPeter Maydell b = 512; 8461deb15c8SPeter Maydell while (a * (b + 1) * (b + 1) < (1 << 28)) { 8471deb15c8SPeter Maydell b += 1; 8481deb15c8SPeter Maydell } 8491deb15c8SPeter Maydell estimate = (b + 1) / 2; 8501deb15c8SPeter Maydell assert(256 <= estimate && estimate < 512); 8511deb15c8SPeter Maydell 8521deb15c8SPeter Maydell return estimate; 8531deb15c8SPeter Maydell } 8541deb15c8SPeter Maydell 8551deb15c8SPeter Maydell static int do_recip_sqrt_estimate_incprec(int a) 8561deb15c8SPeter Maydell { 8571deb15c8SPeter Maydell /* 8581deb15c8SPeter Maydell * The Arm ARM describes the 12-bit precision version of RecipSqrtEstimate 8591deb15c8SPeter Maydell * in terms of an infinite-precision floating point calculation of a 8601deb15c8SPeter Maydell * square root. We implement this using the same kind of pure integer 8611deb15c8SPeter Maydell * algorithm as the 8-bit mantissa, to get the same bit-for-bit result. 8621deb15c8SPeter Maydell */ 8631deb15c8SPeter Maydell int64_t b, estimate; 8641deb15c8SPeter Maydell 8651deb15c8SPeter Maydell assert(1024 <= a && a < 4096); 8661deb15c8SPeter Maydell if (a < 2048) { 8671deb15c8SPeter Maydell a = a * 2 + 1; 8681deb15c8SPeter Maydell } else { 8691deb15c8SPeter Maydell a = (a >> 1) << 1; 8701deb15c8SPeter Maydell a = (a + 1) * 2; 8711deb15c8SPeter Maydell } 8721deb15c8SPeter Maydell b = 8192; 8731deb15c8SPeter Maydell while (a * (b + 1) * (b + 1) < (1ULL << 39)) { 8741deb15c8SPeter Maydell b += 1; 8751deb15c8SPeter Maydell } 8761deb15c8SPeter Maydell estimate = (b + 1) / 2; 8771deb15c8SPeter Maydell 8781deb15c8SPeter Maydell assert(4096 <= estimate && estimate < 8192); 8791deb15c8SPeter Maydell 8801deb15c8SPeter Maydell return estimate; 8811deb15c8SPeter Maydell } 8821deb15c8SPeter Maydell 8831deb15c8SPeter Maydell static uint64_t recip_sqrt_estimate(int *exp , int exp_off, uint64_t frac, 8841deb15c8SPeter Maydell bool increasedprecision) 8851deb15c8SPeter Maydell { 8861deb15c8SPeter Maydell int estimate; 8871deb15c8SPeter Maydell uint32_t scaled; 8881deb15c8SPeter Maydell 8891deb15c8SPeter Maydell if (*exp == 0) { 8901deb15c8SPeter Maydell while (extract64(frac, 51, 1) == 0) { 8911deb15c8SPeter Maydell frac = frac << 1; 8921deb15c8SPeter Maydell *exp -= 1; 8931deb15c8SPeter Maydell } 8941deb15c8SPeter Maydell frac = extract64(frac, 0, 51) << 1; 8951deb15c8SPeter Maydell } 8961deb15c8SPeter Maydell 8971deb15c8SPeter Maydell if (increasedprecision) { 8981deb15c8SPeter Maydell if (*exp & 1) { 8991deb15c8SPeter Maydell /* scaled = UInt('01':fraction<51:42>) */ 9001deb15c8SPeter Maydell scaled = deposit32(1 << 10, 0, 10, extract64(frac, 42, 10)); 9011deb15c8SPeter Maydell } else { 9021deb15c8SPeter Maydell /* scaled = UInt('1':fraction<51:41>) */ 9031deb15c8SPeter Maydell scaled = deposit32(1 << 11, 0, 11, extract64(frac, 41, 11)); 9041deb15c8SPeter Maydell } 9051deb15c8SPeter Maydell estimate = do_recip_sqrt_estimate_incprec(scaled); 9061deb15c8SPeter Maydell } else { 9071deb15c8SPeter Maydell if (*exp & 1) { 9081deb15c8SPeter Maydell /* scaled = UInt('01':fraction<51:45>) */ 9091deb15c8SPeter Maydell scaled = deposit32(1 << 7, 0, 7, extract64(frac, 45, 7)); 9101deb15c8SPeter Maydell } else { 9111deb15c8SPeter Maydell /* scaled = UInt('1':fraction<51:44>) */ 9121deb15c8SPeter Maydell scaled = deposit32(1 << 8, 0, 8, extract64(frac, 44, 8)); 9131deb15c8SPeter Maydell } 9141deb15c8SPeter Maydell estimate = do_recip_sqrt_estimate(scaled); 9151deb15c8SPeter Maydell } 9161deb15c8SPeter Maydell 9171deb15c8SPeter Maydell *exp = (exp_off - *exp) / 2; 9181deb15c8SPeter Maydell if (increasedprecision) { 9191deb15c8SPeter Maydell return extract64(estimate, 0, 12) << 40; 9201deb15c8SPeter Maydell } else { 9211deb15c8SPeter Maydell return extract64(estimate, 0, 8) << 44; 9221deb15c8SPeter Maydell } 9231deb15c8SPeter Maydell } 9241deb15c8SPeter Maydell 9251deb15c8SPeter Maydell uint32_t HELPER(rsqrte_f16)(uint32_t input, float_status *s) 9261deb15c8SPeter Maydell { 9271deb15c8SPeter Maydell float16 f16 = float16_squash_input_denormal(input, s); 9281deb15c8SPeter Maydell uint16_t val = float16_val(f16); 9291deb15c8SPeter Maydell bool f16_sign = float16_is_neg(f16); 9301deb15c8SPeter Maydell int f16_exp = extract32(val, 10, 5); 9311deb15c8SPeter Maydell uint16_t f16_frac = extract32(val, 0, 10); 9321deb15c8SPeter Maydell uint64_t f64_frac; 9331deb15c8SPeter Maydell 9341deb15c8SPeter Maydell if (float16_is_any_nan(f16)) { 9351deb15c8SPeter Maydell float16 nan = f16; 9361deb15c8SPeter Maydell if (float16_is_signaling_nan(f16, s)) { 9371deb15c8SPeter Maydell float_raise(float_flag_invalid, s); 9381deb15c8SPeter Maydell if (!s->default_nan_mode) { 9391deb15c8SPeter Maydell nan = float16_silence_nan(f16, s); 9401deb15c8SPeter Maydell } 9411deb15c8SPeter Maydell } 9421deb15c8SPeter Maydell if (s->default_nan_mode) { 9431deb15c8SPeter Maydell nan = float16_default_nan(s); 9441deb15c8SPeter Maydell } 9451deb15c8SPeter Maydell return nan; 9461deb15c8SPeter Maydell } else if (float16_is_zero(f16)) { 9471deb15c8SPeter Maydell float_raise(float_flag_divbyzero, s); 9481deb15c8SPeter Maydell return float16_set_sign(float16_infinity, f16_sign); 9491deb15c8SPeter Maydell } else if (f16_sign) { 9501deb15c8SPeter Maydell float_raise(float_flag_invalid, s); 9511deb15c8SPeter Maydell return float16_default_nan(s); 9521deb15c8SPeter Maydell } else if (float16_is_infinity(f16)) { 9531deb15c8SPeter Maydell return float16_zero; 9541deb15c8SPeter Maydell } 9551deb15c8SPeter Maydell 9561deb15c8SPeter Maydell /* Scale and normalize to a double-precision value between 0.25 and 1.0, 9571deb15c8SPeter Maydell * preserving the parity of the exponent. */ 9581deb15c8SPeter Maydell 9591deb15c8SPeter Maydell f64_frac = ((uint64_t) f16_frac) << (52 - 10); 9601deb15c8SPeter Maydell 9611deb15c8SPeter Maydell f64_frac = recip_sqrt_estimate(&f16_exp, 44, f64_frac, false); 9621deb15c8SPeter Maydell 9631deb15c8SPeter Maydell /* result = sign : result_exp<4:0> : estimate<7:0> : Zeros(2) */ 9641deb15c8SPeter Maydell val = deposit32(0, 15, 1, f16_sign); 9651deb15c8SPeter Maydell val = deposit32(val, 10, 5, f16_exp); 9661deb15c8SPeter Maydell val = deposit32(val, 2, 8, extract64(f64_frac, 52 - 8, 8)); 9671deb15c8SPeter Maydell return make_float16(val); 9681deb15c8SPeter Maydell } 9691deb15c8SPeter Maydell 9701deb15c8SPeter Maydell /* 9711deb15c8SPeter Maydell * FEAT_RPRES means the f32 FRSQRTE has an "increased precision" variant 9721deb15c8SPeter Maydell * which is used when FPCR.AH == 1. 9731deb15c8SPeter Maydell */ 9741deb15c8SPeter Maydell static float32 do_rsqrte_f32(float32 input, float_status *s, bool rpres) 9751deb15c8SPeter Maydell { 9761deb15c8SPeter Maydell float32 f32 = float32_squash_input_denormal(input, s); 9771deb15c8SPeter Maydell uint32_t val = float32_val(f32); 9781deb15c8SPeter Maydell uint32_t f32_sign = float32_is_neg(f32); 9791deb15c8SPeter Maydell int f32_exp = extract32(val, 23, 8); 9801deb15c8SPeter Maydell uint32_t f32_frac = extract32(val, 0, 23); 9811deb15c8SPeter Maydell uint64_t f64_frac; 9821deb15c8SPeter Maydell 9831deb15c8SPeter Maydell if (float32_is_any_nan(f32)) { 9841deb15c8SPeter Maydell float32 nan = f32; 9851deb15c8SPeter Maydell if (float32_is_signaling_nan(f32, s)) { 9861deb15c8SPeter Maydell float_raise(float_flag_invalid, s); 9871deb15c8SPeter Maydell if (!s->default_nan_mode) { 9881deb15c8SPeter Maydell nan = float32_silence_nan(f32, s); 9891deb15c8SPeter Maydell } 9901deb15c8SPeter Maydell } 9911deb15c8SPeter Maydell if (s->default_nan_mode) { 9921deb15c8SPeter Maydell nan = float32_default_nan(s); 9931deb15c8SPeter Maydell } 9941deb15c8SPeter Maydell return nan; 9951deb15c8SPeter Maydell } else if (float32_is_zero(f32)) { 9961deb15c8SPeter Maydell float_raise(float_flag_divbyzero, s); 9971deb15c8SPeter Maydell return float32_set_sign(float32_infinity, float32_is_neg(f32)); 9981deb15c8SPeter Maydell } else if (float32_is_neg(f32)) { 9991deb15c8SPeter Maydell float_raise(float_flag_invalid, s); 10001deb15c8SPeter Maydell return float32_default_nan(s); 10011deb15c8SPeter Maydell } else if (float32_is_infinity(f32)) { 10021deb15c8SPeter Maydell return float32_zero; 10031deb15c8SPeter Maydell } 10041deb15c8SPeter Maydell 10051deb15c8SPeter Maydell /* Scale and normalize to a double-precision value between 0.25 and 1.0, 10061deb15c8SPeter Maydell * preserving the parity of the exponent. */ 10071deb15c8SPeter Maydell 10081deb15c8SPeter Maydell f64_frac = ((uint64_t) f32_frac) << 29; 10091deb15c8SPeter Maydell 10101deb15c8SPeter Maydell f64_frac = recip_sqrt_estimate(&f32_exp, 380, f64_frac, rpres); 10111deb15c8SPeter Maydell 10121deb15c8SPeter Maydell /* 10131deb15c8SPeter Maydell * result = sign : result_exp<7:0> : estimate<7:0> : Zeros(15) 10141deb15c8SPeter Maydell * or for increased precision 10151deb15c8SPeter Maydell * result = sign : result_exp<7:0> : estimate<11:0> : Zeros(11) 10161deb15c8SPeter Maydell */ 10171deb15c8SPeter Maydell val = deposit32(0, 31, 1, f32_sign); 10181deb15c8SPeter Maydell val = deposit32(val, 23, 8, f32_exp); 10191deb15c8SPeter Maydell if (rpres) { 10201deb15c8SPeter Maydell val = deposit32(val, 11, 12, extract64(f64_frac, 52 - 12, 12)); 10211deb15c8SPeter Maydell } else { 10221deb15c8SPeter Maydell val = deposit32(val, 15, 8, extract64(f64_frac, 52 - 8, 8)); 10231deb15c8SPeter Maydell } 10241deb15c8SPeter Maydell return make_float32(val); 10251deb15c8SPeter Maydell } 10261deb15c8SPeter Maydell 10271deb15c8SPeter Maydell float32 HELPER(rsqrte_f32)(float32 input, float_status *s) 10281deb15c8SPeter Maydell { 10291deb15c8SPeter Maydell return do_rsqrte_f32(input, s, false); 10301deb15c8SPeter Maydell } 10311deb15c8SPeter Maydell 10321deb15c8SPeter Maydell float32 HELPER(rsqrte_rpres_f32)(float32 input, float_status *s) 10331deb15c8SPeter Maydell { 10341deb15c8SPeter Maydell return do_rsqrte_f32(input, s, true); 10351deb15c8SPeter Maydell } 10361deb15c8SPeter Maydell 10371deb15c8SPeter Maydell float64 HELPER(rsqrte_f64)(float64 input, float_status *s) 10381deb15c8SPeter Maydell { 10391deb15c8SPeter Maydell float64 f64 = float64_squash_input_denormal(input, s); 10401deb15c8SPeter Maydell uint64_t val = float64_val(f64); 10411deb15c8SPeter Maydell bool f64_sign = float64_is_neg(f64); 10421deb15c8SPeter Maydell int f64_exp = extract64(val, 52, 11); 10431deb15c8SPeter Maydell uint64_t f64_frac = extract64(val, 0, 52); 10441deb15c8SPeter Maydell 10451deb15c8SPeter Maydell if (float64_is_any_nan(f64)) { 10461deb15c8SPeter Maydell float64 nan = f64; 10471deb15c8SPeter Maydell if (float64_is_signaling_nan(f64, s)) { 10481deb15c8SPeter Maydell float_raise(float_flag_invalid, s); 10491deb15c8SPeter Maydell if (!s->default_nan_mode) { 10501deb15c8SPeter Maydell nan = float64_silence_nan(f64, s); 10511deb15c8SPeter Maydell } 10521deb15c8SPeter Maydell } 10531deb15c8SPeter Maydell if (s->default_nan_mode) { 10541deb15c8SPeter Maydell nan = float64_default_nan(s); 10551deb15c8SPeter Maydell } 10561deb15c8SPeter Maydell return nan; 10571deb15c8SPeter Maydell } else if (float64_is_zero(f64)) { 10581deb15c8SPeter Maydell float_raise(float_flag_divbyzero, s); 10591deb15c8SPeter Maydell return float64_set_sign(float64_infinity, float64_is_neg(f64)); 10601deb15c8SPeter Maydell } else if (float64_is_neg(f64)) { 10611deb15c8SPeter Maydell float_raise(float_flag_invalid, s); 10621deb15c8SPeter Maydell return float64_default_nan(s); 10631deb15c8SPeter Maydell } else if (float64_is_infinity(f64)) { 10641deb15c8SPeter Maydell return float64_zero; 10651deb15c8SPeter Maydell } 10661deb15c8SPeter Maydell 10671deb15c8SPeter Maydell f64_frac = recip_sqrt_estimate(&f64_exp, 3068, f64_frac, false); 10681deb15c8SPeter Maydell 10691deb15c8SPeter Maydell /* result = sign : result_exp<4:0> : estimate<7:0> : Zeros(44) */ 10701deb15c8SPeter Maydell val = deposit64(0, 61, 1, f64_sign); 10711deb15c8SPeter Maydell val = deposit64(val, 52, 11, f64_exp); 10721deb15c8SPeter Maydell val = deposit64(val, 44, 8, extract64(f64_frac, 52 - 8, 8)); 10731deb15c8SPeter Maydell return make_float64(val); 10741deb15c8SPeter Maydell } 10751deb15c8SPeter Maydell 10761deb15c8SPeter Maydell uint32_t HELPER(recpe_u32)(uint32_t a) 10771deb15c8SPeter Maydell { 10781deb15c8SPeter Maydell int input, estimate; 10791deb15c8SPeter Maydell 10801deb15c8SPeter Maydell if ((a & 0x80000000) == 0) { 10811deb15c8SPeter Maydell return 0xffffffff; 10821deb15c8SPeter Maydell } 10831deb15c8SPeter Maydell 10841deb15c8SPeter Maydell input = extract32(a, 23, 9); 10851deb15c8SPeter Maydell estimate = recip_estimate(input); 10861deb15c8SPeter Maydell 10871deb15c8SPeter Maydell return deposit32(0, (32 - 9), 9, estimate); 10881deb15c8SPeter Maydell } 10891deb15c8SPeter Maydell 10901deb15c8SPeter Maydell uint32_t HELPER(rsqrte_u32)(uint32_t a) 10911deb15c8SPeter Maydell { 10921deb15c8SPeter Maydell int estimate; 10931deb15c8SPeter Maydell 10941deb15c8SPeter Maydell if ((a & 0xc0000000) == 0) { 10951deb15c8SPeter Maydell return 0xffffffff; 10961deb15c8SPeter Maydell } 10971deb15c8SPeter Maydell 10981deb15c8SPeter Maydell estimate = do_recip_sqrt_estimate(extract32(a, 23, 9)); 10991deb15c8SPeter Maydell 11001deb15c8SPeter Maydell return deposit32(0, 23, 9, estimate); 11011deb15c8SPeter Maydell } 11021deb15c8SPeter Maydell 11031deb15c8SPeter Maydell /* VFPv4 fused multiply-accumulate */ 11041deb15c8SPeter Maydell dh_ctype_f16 VFP_HELPER(muladd, h)(dh_ctype_f16 a, dh_ctype_f16 b, 11051deb15c8SPeter Maydell dh_ctype_f16 c, float_status *fpst) 11061deb15c8SPeter Maydell { 11071deb15c8SPeter Maydell return float16_muladd(a, b, c, 0, fpst); 11081deb15c8SPeter Maydell } 11091deb15c8SPeter Maydell 11101deb15c8SPeter Maydell float32 VFP_HELPER(muladd, s)(float32 a, float32 b, float32 c, 11111deb15c8SPeter Maydell float_status *fpst) 11121deb15c8SPeter Maydell { 11131deb15c8SPeter Maydell return float32_muladd(a, b, c, 0, fpst); 11141deb15c8SPeter Maydell } 11151deb15c8SPeter Maydell 11161deb15c8SPeter Maydell float64 VFP_HELPER(muladd, d)(float64 a, float64 b, float64 c, 11171deb15c8SPeter Maydell float_status *fpst) 11181deb15c8SPeter Maydell { 11191deb15c8SPeter Maydell return float64_muladd(a, b, c, 0, fpst); 11201deb15c8SPeter Maydell } 11211deb15c8SPeter Maydell 11221deb15c8SPeter Maydell /* ARMv8 round to integral */ 11231deb15c8SPeter Maydell dh_ctype_f16 HELPER(rinth_exact)(dh_ctype_f16 x, float_status *fp_status) 11241deb15c8SPeter Maydell { 11251deb15c8SPeter Maydell return float16_round_to_int(x, fp_status); 11261deb15c8SPeter Maydell } 11271deb15c8SPeter Maydell 11281deb15c8SPeter Maydell float32 HELPER(rints_exact)(float32 x, float_status *fp_status) 11291deb15c8SPeter Maydell { 11301deb15c8SPeter Maydell return float32_round_to_int(x, fp_status); 11311deb15c8SPeter Maydell } 11321deb15c8SPeter Maydell 11331deb15c8SPeter Maydell float64 HELPER(rintd_exact)(float64 x, float_status *fp_status) 11341deb15c8SPeter Maydell { 11351deb15c8SPeter Maydell return float64_round_to_int(x, fp_status); 11361deb15c8SPeter Maydell } 11371deb15c8SPeter Maydell 11381deb15c8SPeter Maydell dh_ctype_f16 HELPER(rinth)(dh_ctype_f16 x, float_status *fp_status) 11391deb15c8SPeter Maydell { 11401deb15c8SPeter Maydell int old_flags = get_float_exception_flags(fp_status), new_flags; 11411deb15c8SPeter Maydell float16 ret; 11421deb15c8SPeter Maydell 11431deb15c8SPeter Maydell ret = float16_round_to_int(x, fp_status); 11441deb15c8SPeter Maydell 11451deb15c8SPeter Maydell /* Suppress any inexact exceptions the conversion produced */ 11461deb15c8SPeter Maydell if (!(old_flags & float_flag_inexact)) { 11471deb15c8SPeter Maydell new_flags = get_float_exception_flags(fp_status); 11481deb15c8SPeter Maydell set_float_exception_flags(new_flags & ~float_flag_inexact, fp_status); 11491deb15c8SPeter Maydell } 11501deb15c8SPeter Maydell 11511deb15c8SPeter Maydell return ret; 11521deb15c8SPeter Maydell } 11531deb15c8SPeter Maydell 11541deb15c8SPeter Maydell float32 HELPER(rints)(float32 x, float_status *fp_status) 11551deb15c8SPeter Maydell { 11561deb15c8SPeter Maydell int old_flags = get_float_exception_flags(fp_status), new_flags; 11571deb15c8SPeter Maydell float32 ret; 11581deb15c8SPeter Maydell 11591deb15c8SPeter Maydell ret = float32_round_to_int(x, fp_status); 11601deb15c8SPeter Maydell 11611deb15c8SPeter Maydell /* Suppress any inexact exceptions the conversion produced */ 11621deb15c8SPeter Maydell if (!(old_flags & float_flag_inexact)) { 11631deb15c8SPeter Maydell new_flags = get_float_exception_flags(fp_status); 11641deb15c8SPeter Maydell set_float_exception_flags(new_flags & ~float_flag_inexact, fp_status); 11651deb15c8SPeter Maydell } 11661deb15c8SPeter Maydell 11671deb15c8SPeter Maydell return ret; 11681deb15c8SPeter Maydell } 11691deb15c8SPeter Maydell 11701deb15c8SPeter Maydell float64 HELPER(rintd)(float64 x, float_status *fp_status) 11711deb15c8SPeter Maydell { 11721deb15c8SPeter Maydell int old_flags = get_float_exception_flags(fp_status), new_flags; 11731deb15c8SPeter Maydell float64 ret; 11741deb15c8SPeter Maydell 11751deb15c8SPeter Maydell ret = float64_round_to_int(x, fp_status); 11761deb15c8SPeter Maydell 11771deb15c8SPeter Maydell /* Suppress any inexact exceptions the conversion produced */ 11781deb15c8SPeter Maydell if (!(old_flags & float_flag_inexact)) { 11791deb15c8SPeter Maydell new_flags = get_float_exception_flags(fp_status); 11801deb15c8SPeter Maydell set_float_exception_flags(new_flags & ~float_flag_inexact, fp_status); 11811deb15c8SPeter Maydell } 11821deb15c8SPeter Maydell 11831deb15c8SPeter Maydell return ret; 11841deb15c8SPeter Maydell } 11851deb15c8SPeter Maydell 11861deb15c8SPeter Maydell /* Convert ARM rounding mode to softfloat */ 11871deb15c8SPeter Maydell const FloatRoundMode arm_rmode_to_sf_map[] = { 11881deb15c8SPeter Maydell [FPROUNDING_TIEEVEN] = float_round_nearest_even, 11891deb15c8SPeter Maydell [FPROUNDING_POSINF] = float_round_up, 11901deb15c8SPeter Maydell [FPROUNDING_NEGINF] = float_round_down, 11911deb15c8SPeter Maydell [FPROUNDING_ZERO] = float_round_to_zero, 11921deb15c8SPeter Maydell [FPROUNDING_TIEAWAY] = float_round_ties_away, 11931deb15c8SPeter Maydell [FPROUNDING_ODD] = float_round_to_odd, 11941deb15c8SPeter Maydell }; 11951deb15c8SPeter Maydell 11961deb15c8SPeter Maydell /* 11971deb15c8SPeter Maydell * Implement float64 to int32_t conversion without saturation; 11981deb15c8SPeter Maydell * the result is supplied modulo 2^32. 11991deb15c8SPeter Maydell */ 12001deb15c8SPeter Maydell uint64_t HELPER(fjcvtzs)(float64 value, float_status *status) 12011deb15c8SPeter Maydell { 12021deb15c8SPeter Maydell uint32_t frac, e_old, e_new; 12031deb15c8SPeter Maydell bool inexact; 12041deb15c8SPeter Maydell 12051deb15c8SPeter Maydell e_old = get_float_exception_flags(status); 12061deb15c8SPeter Maydell set_float_exception_flags(0, status); 12071deb15c8SPeter Maydell frac = float64_to_int32_modulo(value, float_round_to_zero, status); 12081deb15c8SPeter Maydell e_new = get_float_exception_flags(status); 12091deb15c8SPeter Maydell set_float_exception_flags(e_old | e_new, status); 12101deb15c8SPeter Maydell 12111deb15c8SPeter Maydell /* Normal inexact, denormal with flush-to-zero, or overflow or NaN */ 12121deb15c8SPeter Maydell inexact = e_new & (float_flag_inexact | 12131deb15c8SPeter Maydell float_flag_input_denormal_flushed | 12141deb15c8SPeter Maydell float_flag_invalid); 12151deb15c8SPeter Maydell 12161deb15c8SPeter Maydell /* While not inexact for IEEE FP, -0.0 is inexact for JavaScript. */ 12171deb15c8SPeter Maydell inexact |= value == float64_chs(float64_zero); 12181deb15c8SPeter Maydell 12191deb15c8SPeter Maydell /* Pack the result and the env->ZF representation of Z together. */ 12201deb15c8SPeter Maydell return deposit64(frac, 32, 32, inexact); 12211deb15c8SPeter Maydell } 12221deb15c8SPeter Maydell 12231deb15c8SPeter Maydell uint32_t HELPER(vjcvt)(float64 value, CPUARMState *env) 12241deb15c8SPeter Maydell { 12251deb15c8SPeter Maydell uint64_t pair = HELPER(fjcvtzs)(value, &env->vfp.fp_status[FPST_A32]); 12261deb15c8SPeter Maydell uint32_t result = pair; 12271deb15c8SPeter Maydell uint32_t z = (pair >> 32) == 0; 12281deb15c8SPeter Maydell 12291deb15c8SPeter Maydell /* Store Z, clear NCV, in FPSCR.NZCV. */ 12301deb15c8SPeter Maydell env->vfp.fpsr = (env->vfp.fpsr & ~FPSR_NZCV_MASK) | (z * FPSR_Z); 12311deb15c8SPeter Maydell 12321deb15c8SPeter Maydell return result; 12331deb15c8SPeter Maydell } 12341deb15c8SPeter Maydell 12351deb15c8SPeter Maydell /* Round a float32 to an integer that fits in int32_t or int64_t. */ 12361deb15c8SPeter Maydell static float32 frint_s(float32 f, float_status *fpst, int intsize) 12371deb15c8SPeter Maydell { 12381deb15c8SPeter Maydell int old_flags = get_float_exception_flags(fpst); 12391deb15c8SPeter Maydell uint32_t exp = extract32(f, 23, 8); 12401deb15c8SPeter Maydell 12411deb15c8SPeter Maydell if (unlikely(exp == 0xff)) { 12421deb15c8SPeter Maydell /* NaN or Inf. */ 12431deb15c8SPeter Maydell goto overflow; 12441deb15c8SPeter Maydell } 12451deb15c8SPeter Maydell 12461deb15c8SPeter Maydell /* Round and re-extract the exponent. */ 12471deb15c8SPeter Maydell f = float32_round_to_int(f, fpst); 12481deb15c8SPeter Maydell exp = extract32(f, 23, 8); 12491deb15c8SPeter Maydell 12501deb15c8SPeter Maydell /* Validate the range of the result. */ 12511deb15c8SPeter Maydell if (exp < 126 + intsize) { 12521deb15c8SPeter Maydell /* abs(F) <= INT{N}_MAX */ 12531deb15c8SPeter Maydell return f; 12541deb15c8SPeter Maydell } 12551deb15c8SPeter Maydell if (exp == 126 + intsize) { 12561deb15c8SPeter Maydell uint32_t sign = extract32(f, 31, 1); 12571deb15c8SPeter Maydell uint32_t frac = extract32(f, 0, 23); 12581deb15c8SPeter Maydell if (sign && frac == 0) { 12591deb15c8SPeter Maydell /* F == INT{N}_MIN */ 12601deb15c8SPeter Maydell return f; 12611deb15c8SPeter Maydell } 12621deb15c8SPeter Maydell } 12631deb15c8SPeter Maydell 12641deb15c8SPeter Maydell overflow: 12651deb15c8SPeter Maydell /* 12661deb15c8SPeter Maydell * Raise Invalid and return INT{N}_MIN as a float. Revert any 12671deb15c8SPeter Maydell * inexact exception float32_round_to_int may have raised. 12681deb15c8SPeter Maydell */ 12691deb15c8SPeter Maydell set_float_exception_flags(old_flags | float_flag_invalid, fpst); 12701deb15c8SPeter Maydell return (0x100u + 126u + intsize) << 23; 12711deb15c8SPeter Maydell } 12721deb15c8SPeter Maydell 12731deb15c8SPeter Maydell float32 HELPER(frint32_s)(float32 f, float_status *fpst) 12741deb15c8SPeter Maydell { 12751deb15c8SPeter Maydell return frint_s(f, fpst, 32); 12761deb15c8SPeter Maydell } 12771deb15c8SPeter Maydell 12781deb15c8SPeter Maydell float32 HELPER(frint64_s)(float32 f, float_status *fpst) 12791deb15c8SPeter Maydell { 12801deb15c8SPeter Maydell return frint_s(f, fpst, 64); 12811deb15c8SPeter Maydell } 12821deb15c8SPeter Maydell 12831deb15c8SPeter Maydell /* Round a float64 to an integer that fits in int32_t or int64_t. */ 12841deb15c8SPeter Maydell static float64 frint_d(float64 f, float_status *fpst, int intsize) 12851deb15c8SPeter Maydell { 12861deb15c8SPeter Maydell int old_flags = get_float_exception_flags(fpst); 12871deb15c8SPeter Maydell uint32_t exp = extract64(f, 52, 11); 12881deb15c8SPeter Maydell 12891deb15c8SPeter Maydell if (unlikely(exp == 0x7ff)) { 12901deb15c8SPeter Maydell /* NaN or Inf. */ 12911deb15c8SPeter Maydell goto overflow; 12921deb15c8SPeter Maydell } 12931deb15c8SPeter Maydell 12941deb15c8SPeter Maydell /* Round and re-extract the exponent. */ 12951deb15c8SPeter Maydell f = float64_round_to_int(f, fpst); 12961deb15c8SPeter Maydell exp = extract64(f, 52, 11); 12971deb15c8SPeter Maydell 12981deb15c8SPeter Maydell /* Validate the range of the result. */ 12991deb15c8SPeter Maydell if (exp < 1022 + intsize) { 13001deb15c8SPeter Maydell /* abs(F) <= INT{N}_MAX */ 13011deb15c8SPeter Maydell return f; 13021deb15c8SPeter Maydell } 13031deb15c8SPeter Maydell if (exp == 1022 + intsize) { 13041deb15c8SPeter Maydell uint64_t sign = extract64(f, 63, 1); 13051deb15c8SPeter Maydell uint64_t frac = extract64(f, 0, 52); 13061deb15c8SPeter Maydell if (sign && frac == 0) { 13071deb15c8SPeter Maydell /* F == INT{N}_MIN */ 13081deb15c8SPeter Maydell return f; 13091deb15c8SPeter Maydell } 13101deb15c8SPeter Maydell } 13111deb15c8SPeter Maydell 13121deb15c8SPeter Maydell overflow: 13131deb15c8SPeter Maydell /* 13141deb15c8SPeter Maydell * Raise Invalid and return INT{N}_MIN as a float. Revert any 13151deb15c8SPeter Maydell * inexact exception float64_round_to_int may have raised. 13161deb15c8SPeter Maydell */ 13171deb15c8SPeter Maydell set_float_exception_flags(old_flags | float_flag_invalid, fpst); 13181deb15c8SPeter Maydell return (uint64_t)(0x800 + 1022 + intsize) << 52; 13191deb15c8SPeter Maydell } 13201deb15c8SPeter Maydell 13211deb15c8SPeter Maydell float64 HELPER(frint32_d)(float64 f, float_status *fpst) 13221deb15c8SPeter Maydell { 13231deb15c8SPeter Maydell return frint_d(f, fpst, 32); 13241deb15c8SPeter Maydell } 13251deb15c8SPeter Maydell 13261deb15c8SPeter Maydell float64 HELPER(frint64_d)(float64 f, float_status *fpst) 13271deb15c8SPeter Maydell { 13281deb15c8SPeter Maydell return frint_d(f, fpst, 64); 13291deb15c8SPeter Maydell } 13301deb15c8SPeter Maydell 13311deb15c8SPeter Maydell void HELPER(check_hcr_el2_trap)(CPUARMState *env, uint32_t rt, uint32_t reg) 13321deb15c8SPeter Maydell { 13331deb15c8SPeter Maydell uint32_t syndrome; 13341deb15c8SPeter Maydell 13351deb15c8SPeter Maydell switch (reg) { 13361deb15c8SPeter Maydell case ARM_VFP_MVFR0: 13371deb15c8SPeter Maydell case ARM_VFP_MVFR1: 13381deb15c8SPeter Maydell case ARM_VFP_MVFR2: 13391deb15c8SPeter Maydell if (!(arm_hcr_el2_eff(env) & HCR_TID3)) { 13401deb15c8SPeter Maydell return; 13411deb15c8SPeter Maydell } 13421deb15c8SPeter Maydell break; 13431deb15c8SPeter Maydell case ARM_VFP_FPSID: 13441deb15c8SPeter Maydell if (!(arm_hcr_el2_eff(env) & HCR_TID0)) { 13451deb15c8SPeter Maydell return; 13461deb15c8SPeter Maydell } 13471deb15c8SPeter Maydell break; 13481deb15c8SPeter Maydell default: 13491deb15c8SPeter Maydell g_assert_not_reached(); 13501deb15c8SPeter Maydell } 13511deb15c8SPeter Maydell 13521deb15c8SPeter Maydell syndrome = ((EC_FPIDTRAP << ARM_EL_EC_SHIFT) 13531deb15c8SPeter Maydell | ARM_EL_IL 13541deb15c8SPeter Maydell | (1 << 24) | (0xe << 20) | (7 << 14) 13551deb15c8SPeter Maydell | (reg << 10) | (rt << 5) | 1); 13561deb15c8SPeter Maydell 13571deb15c8SPeter Maydell raise_exception(env, EXCP_HYP_TRAP, syndrome, 2); 13581deb15c8SPeter Maydell } 1359e34cfba5SPeter Maydell 1360e34cfba5SPeter Maydell uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env) 1361e34cfba5SPeter Maydell { 1362e34cfba5SPeter Maydell return vfp_get_fpscr(env); 1363e34cfba5SPeter Maydell } 1364e34cfba5SPeter Maydell 1365e34cfba5SPeter Maydell void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val) 1366e34cfba5SPeter Maydell { 1367e34cfba5SPeter Maydell vfp_set_fpscr(env, val); 1368e34cfba5SPeter Maydell } 1369