target/arm: Explicitly set 2-NaN propagation rule

Set the 2-NaN propagation rule explicitly in the float_status words
we use.  We wrap this plus the pre-existing setting of the
tininess-before-rounding flag in a new function
arm_set_default_fp_behaviours() to avoid repetition, since we have a
lot of float_status words at this point.

The situation with FPA11 emulation in linux-user is a little odd, and
arguably "correct" behaviour there would be to exactly match a real
Linux kernel's FPA11 emulation.  However FPA11 emulation is
essentially dead at this point and so it seems better to continue
with QEMU's current behaviour and leave a comment describing the
situation.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20241025141254.2141506-4-peter.maydell@linaro.org
This commit is contained in:
Peter Maydell 2024-11-05 10:09:53 +00:00
parent d22c9949d7
commit d1ff996788
3 changed files with 37 additions and 19 deletions

View file

@ -51,6 +51,24 @@ void resetFPA11(void)
#ifdef MAINTAIN_FPCR
fpa11->fpcr = MASK_RESET;
#endif
/*
* Real FPA11 hardware does not handle NaNs, but always takes an
* exception for them to be software-emulated (ARM7500FE datasheet
* section 10.4). There is no documented architectural requirement
* for NaN propagation rules and it will depend on how the OS
* level software emulation opted to do it. We here use prop_s_ab
* which matches the later VFP hardware choice and how QEMU's
* fpa11 emulation has worked in the past. The real Linux kernel
* does something slightly different: arch/arm/nwfpe/softfloat-specialize
* propagateFloat64NaN() has the curious behaviour that it prefers
* the QNaN over the SNaN, but if both are QNaN it picks A and
* if both are SNaN it picks B. In theory we could add this as
* a NaN propagation rule, but in practice FPA11 emulation is so
* close to totally dead that it's not worth trying to match it at
* this late date.
*/
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &fpa11->fp_status);
}
void SetRoundingMode(const unsigned int opcode)