When FPCR.AH is set, various behaviours of AArch64 floating point operations which are controlled by softfloat config settings change: * tininess and ftz detection before/after rounding * NaN propagation order * result of 0 * Inf + NaN * default NaN value
When the guest changes the value of the AH bit, switch these config settings on the fp_status_a64 and fp_status_f16_a64 float_status fields. This requires us to make the arm_set_default_fp_behaviours() function global, since we now need to call it from cpu.c and vfp_helper.c; we move it to vfp_helper.c so it can be next to the new arm_set_ah_fp_behaviours(). Signed-off-by: Peter Maydell <peter.mayd...@linaro.org> --- target/arm/internals.h | 4 +++ target/arm/cpu.c | 23 ----------------- target/arm/vfp_helper.c | 56 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 23 deletions(-) diff --git a/target/arm/internals.h b/target/arm/internals.h index 863a84edf81..98073acc276 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1828,4 +1828,8 @@ uint64_t gt_virt_cnt_offset(CPUARMState *env); * all EL1" scope; this covers stage 1 and stage 2. */ int alle1_tlbmask(CPUARMState *env); + +/* Set the float_status behaviour to match the Arm defaults */ +void arm_set_default_fp_behaviours(float_status *s); + #endif diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 0b4cd872d27..1ba22c4c7aa 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -169,29 +169,6 @@ void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook, QLIST_INSERT_HEAD(&cpu->el_change_hooks, entry, node); } -/* - * Set the float_status behaviour to match the Arm defaults: - * * tininess-before-rounding - * * 2-input NaN propagation prefers SNaN over QNaN, and then - * operand A over operand B (see FPProcessNaNs() pseudocode) - * * 3-input NaN propagation prefers SNaN over QNaN, and then - * operand C over A over B (see FPProcessNaNs3() pseudocode, - * but note that for QEMU muladd is a * b + c, whereas for - * the pseudocode function the arguments are in the order c, a, b. - * * 0 * Inf + NaN returns the default NaN if the input NaN is quiet, - * and the input NaN if it is signalling - * * Default NaN has sign bit clear, msb frac bit set - */ -static void arm_set_default_fp_behaviours(float_status *s) -{ - set_float_detect_tininess(float_tininess_before_rounding, s); - set_float_detect_ftz(detect_ftz_before_rounding, s); - set_float_2nan_prop_rule(float_2nan_prop_s_ab, s); - set_float_3nan_prop_rule(float_3nan_prop_s_cab, s); - set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, s); - set_float_default_nan_pattern(0b01000000, s); -} - static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque) { /* Reset a single ARMCPRegInfo register */ diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c index 5a0b389f7a3..7507ff24bc0 100644 --- a/target/arm/vfp_helper.c +++ b/target/arm/vfp_helper.c @@ -31,6 +31,50 @@ Single precision routines have a "s" suffix, double precision a "d" suffix. */ +/* + * Set the float_status behaviour to match the Arm defaults: + * * tininess-before-rounding + * * 2-input NaN propagation prefers SNaN over QNaN, and then + * operand A over operand B (see FPProcessNaNs() pseudocode) + * * 3-input NaN propagation prefers SNaN over QNaN, and then + * operand C over A over B (see FPProcessNaNs3() pseudocode, + * but note that for QEMU muladd is a * b + c, whereas for + * the pseudocode function the arguments are in the order c, a, b. + * * 0 * Inf + NaN returns the default NaN if the input NaN is quiet, + * and the input NaN if it is signalling + * * Default NaN has sign bit clear, msb frac bit set + */ +void arm_set_default_fp_behaviours(float_status *s) +{ + set_float_detect_tininess(float_tininess_before_rounding, s); + set_float_detect_ftz(detect_ftz_before_rounding, s); + set_float_2nan_prop_rule(float_2nan_prop_s_ab, s); + set_float_3nan_prop_rule(float_3nan_prop_s_cab, s); + set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, s); + set_float_default_nan_pattern(0b01000000, s); +} + +/* + * Set the float_status behaviour to match the FEAT_AFP + * FPCR.AH=1 requirements: + * * tininess-after-rounding + * * 2-input NaN propagation prefers the first NaN + * * 3-input NaN propagation prefers a over b over c + * * 0 * Inf + NaN always returns the input NaN and doesn't + * set Invalid for a QNaN + * * default NaN has sign bit set, msb frac bit set + */ +static void arm_set_ah_fp_behaviours(float_status *s) +{ + set_float_detect_tininess(float_tininess_after_rounding, s); + set_float_detect_ftz(detect_ftz_after_rounding, s); + set_float_2nan_prop_rule(float_2nan_prop_ab, s); + set_float_3nan_prop_rule(float_3nan_prop_abc, s); + set_float_infzeronan_rule(float_infzeronan_dnan_never | + float_infzeronan_suppress_invalid, s); + set_float_default_nan_pattern(0b11000000, s); +} + #ifdef CONFIG_TCG /* Convert host exception flags to vfp form. */ @@ -171,6 +215,18 @@ static void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask) set_default_nan_mode(dnan_enabled, &env->vfp.fp_status_f16_a32); set_default_nan_mode(dnan_enabled, &env->vfp.fp_status_f16_a64); } + if (changed & FPCR_AH) { + bool ah_enabled = val & FPCR_AH; + + if (ah_enabled) { + /* Change behaviours for A64 FP operations */ + arm_set_ah_fp_behaviours(&env->vfp.fp_status_a64); + arm_set_ah_fp_behaviours(&env->vfp.fp_status_f16_a64); + } else { + arm_set_default_fp_behaviours(&env->vfp.fp_status_a64); + arm_set_default_fp_behaviours(&env->vfp.fp_status_f16_a64); + } + } /* * If any bits changed that we look at in vfp_get_fpsr_from_host(), * we must sync the float_status flags into vfp.fpsr now (under the -- 2.34.1