mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-07-27 04:13:53 -06:00

Currently we handle flushing of output denormals in uncanon_normal always before we deal with rounding. This works for architectures that detect tininess before rounding, but is usually not the right place when the architecture detects tininess after rounding. For example, for x86 the SDM states that the MXCSR FTZ control bit causes outputs to be flushed to zero "when it detects a floating-point underflow condition". This means that we mustn't flush to zero if the input is such that after rounding it is no longer tiny. At least one of our guest architectures does underflow detection after rounding but flushing of denormals before rounding (MIPS MSA); this means we need to have a config knob for this that is separate from our existing tininess_before_rounding setting. Add an ftz_detection flag. For consistency with tininess_before_rounding, we make it default to "detect ftz after rounding"; this means that we need to explicitly set the flag to "detect ftz before rounding" on every existing architecture that sets flush_to_zero, so that this commit has no behaviour change. (This means more code change here but for the long term a less confusing API.) For several architectures the current behaviour is either definitely or possibly wrong; annotate those with TODO comments. These architectures are definitely wrong (and should detect ftz after rounding): * x86 * Alpha For these architectures the spec is unclear: * MIPS (for non-MSA) * RX * SH4 PA-RISC makes ftz detection IMPDEF, but we aren't setting the "tininess before rounding" setting that we ought to. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
96 lines
3.5 KiB
C
96 lines
3.5 KiB
C
/*
|
|
* MIPS SIMD Architecture Module Instruction emulation helpers for QEMU.
|
|
*
|
|
* Copyright (c) 2014 Imagination Technologies
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "cpu.h"
|
|
#include "internal.h"
|
|
#include "fpu/softfloat.h"
|
|
#include "fpu_helper.h"
|
|
|
|
void msa_reset(CPUMIPSState *env)
|
|
{
|
|
if (!ase_msa_available(env)) {
|
|
return;
|
|
}
|
|
|
|
#ifdef CONFIG_USER_ONLY
|
|
/* MSA access enabled */
|
|
env->CP0_Config5 |= 1 << CP0C5_MSAEn;
|
|
env->CP0_Status |= (1 << CP0St_CU1) | (1 << CP0St_FR);
|
|
#endif
|
|
|
|
/*
|
|
* MSA CSR:
|
|
* - non-signaling floating point exception mode off (NX bit is 0)
|
|
* - Cause, Enables, and Flags are all 0
|
|
* - round to nearest / ties to even (RM bits are 0)
|
|
*/
|
|
env->active_tc.msacsr = 0;
|
|
|
|
restore_msa_fp_status(env);
|
|
|
|
/* tininess detected after rounding.*/
|
|
set_float_detect_tininess(float_tininess_after_rounding,
|
|
&env->active_tc.msa_fp_status);
|
|
/*
|
|
* MSACSR.FS detects tiny results to flush to zero before rounding
|
|
* (per "MIPS Architecture for Programmers Volume IV-j: The MIPS64 SIMD
|
|
* Architecture Module, Revision 1.1" section 3.5.4), even though it
|
|
* detects tininess after rounding for underflow purposes (section 3.4.2
|
|
* table 3.3).
|
|
*/
|
|
set_float_ftz_detection(float_ftz_before_rounding,
|
|
&env->active_tc.msa_fp_status);
|
|
|
|
/*
|
|
* According to MIPS specifications, if one of the two operands is
|
|
* a sNaN, a new qNaN has to be generated. This is done in
|
|
* floatXX_silence_nan(). For qNaN inputs the specifications
|
|
* says: "When possible, this QNaN result is one of the operand QNaN
|
|
* values." In practice it seems that most implementations choose
|
|
* the first operand if both operands are qNaN. In short this gives
|
|
* the following rules:
|
|
* 1. A if it is signaling
|
|
* 2. B if it is signaling
|
|
* 3. A (quiet)
|
|
* 4. B (quiet)
|
|
* A signaling NaN is always silenced before returning it.
|
|
*/
|
|
set_float_2nan_prop_rule(float_2nan_prop_s_ab,
|
|
&env->active_tc.msa_fp_status);
|
|
|
|
set_float_3nan_prop_rule(float_3nan_prop_s_cab,
|
|
&env->active_tc.msa_fp_status);
|
|
|
|
/* clear float_status exception flags */
|
|
set_float_exception_flags(0, &env->active_tc.msa_fp_status);
|
|
|
|
/* clear float_status nan mode */
|
|
set_default_nan_mode(0, &env->active_tc.msa_fp_status);
|
|
|
|
/* set proper signanling bit meaning ("1" means "quiet") */
|
|
set_snan_bit_is_one(0, &env->active_tc.msa_fp_status);
|
|
|
|
/* Inf * 0 + NaN returns the input NaN */
|
|
set_float_infzeronan_rule(float_infzeronan_dnan_never,
|
|
&env->active_tc.msa_fp_status);
|
|
/* Default NaN: sign bit clear, frac msb set */
|
|
set_float_default_nan_pattern(0b01000000,
|
|
&env->active_tc.msa_fp_status);
|
|
}
|