aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.mailmap5
-rw-r--r--MAINTAINERS4
-rw-r--r--fpu/softfloat-parts.c.inc150
-rw-r--r--fpu/softfloat-specialize.c.inc412
-rw-r--r--fpu/softfloat.c19
-rw-r--r--hw/net/Kconfig5
-rw-r--r--hw/net/imx_fec.c146
-rw-r--r--hw/net/lan9118.c137
-rw-r--r--hw/net/lan9118_phy.c222
-rw-r--r--hw/net/meson.build1
-rw-r--r--hw/net/trace-events10
-rw-r--r--include/fpu/softfloat-helpers.h38
-rw-r--r--include/fpu/softfloat-types.h89
-rw-r--r--include/hw/net/imx_fec.h9
-rw-r--r--include/hw/net/lan9118_phy.h37
-rw-r--r--include/hw/net/mii.h6
-rw-r--r--linux-user/arm/nwfpe/fpa11.c5
-rw-r--r--target/alpha/cpu.c2
-rw-r--r--target/arm/cpu.c10
-rw-r--r--target/arm/tcg/vec_helper.c20
-rw-r--r--target/hexagon/cpu.c2
-rw-r--r--target/hppa/fpu_helper.c12
-rw-r--r--target/i386/tcg/fpu_helper.c12
-rw-r--r--target/loongarch/tcg/fpu_helper.c14
-rw-r--r--target/m68k/cpu.c14
-rw-r--r--target/m68k/fpu_helper.c6
-rw-r--r--target/m68k/helper.c6
-rw-r--r--target/microblaze/cpu.c2
-rw-r--r--target/mips/fpu_helper.h20
-rw-r--r--target/mips/msa.c10
-rw-r--r--target/openrisc/cpu.c2
-rw-r--r--target/ppc/cpu_init.c19
-rw-r--r--target/ppc/fpu_helper.c3
-rw-r--r--target/riscv/cpu.c2
-rw-r--r--target/rx/cpu.c2
-rw-r--r--target/s390x/cpu.c5
-rw-r--r--target/sh4/cpu.c2
-rw-r--r--target/sparc/cpu.c6
-rw-r--r--target/sparc/fop_helper.c8
-rw-r--r--target/sparc/helper.h4
-rw-r--r--target/sparc/translate.c4
-rw-r--r--target/tricore/helper.c2
-rw-r--r--target/xtensa/cpu.c4
-rw-r--r--target/xtensa/fpu_helper.c3
-rw-r--r--tests/fp/fp-bench.c7
-rw-r--r--tests/fp/fp-test-log2.c1
-rw-r--r--tests/fp/fp-test.c7
47 files changed, 777 insertions, 729 deletions
diff --git a/.mailmap b/.mailmap
index 727ce20..5f6df41 100644
--- a/.mailmap
+++ b/.mailmap
@@ -87,8 +87,9 @@ Huacai Chen <chenhuacai@kernel.org> <chenhc@lemote.com>
Huacai Chen <chenhuacai@kernel.org> <chenhuacai@loongson.cn>
James Hogan <jhogan@kernel.org> <james.hogan@imgtec.com>
Juan Quintela <quintela@trasno.org> <quintela@redhat.com>
-Leif Lindholm <quic_llindhol@quicinc.com> <leif.lindholm@linaro.org>
-Leif Lindholm <quic_llindhol@quicinc.com> <leif@nuviainc.com>
+Leif Lindholm <leif.lindholm@oss.qualcomm.com> <quic_llindhol@quicinc.com>
+Leif Lindholm <leif.lindholm@oss.qualcomm.com> <leif.lindholm@linaro.org>
+Leif Lindholm <leif.lindholm@oss.qualcomm.com> <leif@nuviainc.com>
Luc Michel <luc@lmichel.fr> <luc.michel@git.antfield.fr>
Luc Michel <luc@lmichel.fr> <luc.michel@greensocs.com>
Luc Michel <luc@lmichel.fr> <lmichel@kalray.eu>
diff --git a/MAINTAINERS b/MAINTAINERS
index dc583d5..025b5d2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -917,7 +917,7 @@ F: include/hw/ssi/imx_spi.h
SBSA-REF
M: Radoslaw Biernacki <rad@semihalf.com>
M: Peter Maydell <peter.maydell@linaro.org>
-R: Leif Lindholm <quic_llindhol@quicinc.com>
+R: Leif Lindholm <leif.lindholm@oss.qualcomm.com>
R: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
L: qemu-arm@nongnu.org
S: Maintained
@@ -1918,6 +1918,7 @@ F: tests/qtest/fuzz-sb16-test.c
Xilinx CAN
M: Francisco Iglesias <francisco.iglesias@amd.com>
+M: Vikram Garhwal <vikram.garhwal@bytedance.com>
S: Maintained
F: hw/net/can/xlnx-*
F: include/hw/net/xlnx-*
@@ -2677,6 +2678,7 @@ F: include/hw/rx/
CAN bus subsystem and hardware
M: Pavel Pisa <pisa@cmp.felk.cvut.cz>
M: Francisco Iglesias <francisco.iglesias@amd.com>
+M: Vikram Garhwal <vikram.garhwal@bytedance.com>
S: Maintained
W: https://canbus.pages.fel.cvut.cz/
F: net/can/*
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
index cc6e06b..ba8de7b 100644
--- a/fpu/softfloat-parts.c.inc
+++ b/fpu/softfloat-parts.c.inc
@@ -39,65 +39,151 @@ static void partsN(return_nan)(FloatPartsN *a, float_status *s)
static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b,
float_status *s)
{
+ bool have_snan = false;
+ FloatPartsN *ret;
+ int cmp;
+
if (is_snan(a->cls) || is_snan(b->cls)) {
float_raise(float_flag_invalid | float_flag_invalid_snan, s);
+ have_snan = true;
}
if (s->default_nan_mode) {
parts_default_nan(a, s);
- } else {
- int cmp = frac_cmp(a, b);
- if (cmp == 0) {
- cmp = a->sign < b->sign;
- }
+ return a;
+ }
- if (pickNaN(a->cls, b->cls, cmp > 0, s)) {
- a = b;
+ switch (s->float_2nan_prop_rule) {
+ case float_2nan_prop_s_ab:
+ if (have_snan) {
+ ret = is_snan(a->cls) ? a : b;
+ break;
}
+ /* fall through */
+ case float_2nan_prop_ab:
+ ret = is_nan(a->cls) ? a : b;
+ break;
+ case float_2nan_prop_s_ba:
+ if (have_snan) {
+ ret = is_snan(b->cls) ? b : a;
+ break;
+ }
+ /* fall through */
+ case float_2nan_prop_ba:
+ ret = is_nan(b->cls) ? b : a;
+ break;
+ case float_2nan_prop_x87:
+ /*
+ * This implements x87 NaN propagation rules:
+ * SNaN + QNaN => return the QNaN
+ * two SNaNs => return the one with the larger significand, silenced
+ * two QNaNs => return the one with the larger significand
+ * SNaN and a non-NaN => return the SNaN, silenced
+ * QNaN and a non-NaN => return the QNaN
+ *
+ * If we get down to comparing significands and they are the same,
+ * return the NaN with the positive sign bit (if any).
+ */
if (is_snan(a->cls)) {
- parts_silence_nan(a, s);
+ if (!is_snan(b->cls)) {
+ ret = is_qnan(b->cls) ? b : a;
+ break;
+ }
+ } else if (is_qnan(a->cls)) {
+ if (is_snan(b->cls) || !is_qnan(b->cls)) {
+ ret = a;
+ break;
+ }
+ } else {
+ ret = b;
+ break;
}
+ cmp = frac_cmp(a, b);
+ if (cmp == 0) {
+ cmp = a->sign < b->sign;
+ }
+ ret = cmp > 0 ? a : b;
+ break;
+ default:
+ g_assert_not_reached();
}
- return a;
+
+ if (is_snan(ret->cls)) {
+ parts_silence_nan(ret, s);
+ }
+ return ret;
}
static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
FloatPartsN *c, float_status *s,
int ab_mask, int abc_mask)
{
- int which;
+ bool infzero = (ab_mask == float_cmask_infzero);
+ bool have_snan = (abc_mask & float_cmask_snan);
+ FloatPartsN *ret;
- if (unlikely(abc_mask & float_cmask_snan)) {
+ if (unlikely(have_snan)) {
float_raise(float_flag_invalid | float_flag_invalid_snan, s);
}
- which = pickNaNMulAdd(a->cls, b->cls, c->cls,
- ab_mask == float_cmask_infzero, s);
+ if (infzero) {
+ /* This is (0 * inf) + NaN or (inf * 0) + NaN */
+ float_raise(float_flag_invalid | float_flag_invalid_imz, s);
+ }
- if (s->default_nan_mode || which == 3) {
+ if (s->default_nan_mode) {
/*
- * Note that this check is after pickNaNMulAdd so that function
- * has an opportunity to set the Invalid flag for infzero.
+ * We guarantee not to require the target to tell us how to
+ * pick a NaN if we're always returning the default NaN.
+ * But if we're not in default-NaN mode then the target must
+ * specify.
*/
- parts_default_nan(a, s);
- return a;
+ goto default_nan;
+ } else if (infzero) {
+ /*
+ * Inf * 0 + NaN -- some implementations return the
+ * default NaN here, and some return the input NaN.
+ */
+ switch (s->float_infzeronan_rule) {
+ case float_infzeronan_dnan_never:
+ break;
+ case float_infzeronan_dnan_always:
+ goto default_nan;
+ case float_infzeronan_dnan_if_qnan:
+ if (is_qnan(c->cls)) {
+ goto default_nan;
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ ret = c;
+ } else {
+ FloatPartsN *val[R_3NAN_1ST_MASK + 1] = { a, b, c };
+ Float3NaNPropRule rule = s->float_3nan_prop_rule;
+
+ assert(rule != float_3nan_prop_none);
+ if (have_snan && (rule & R_3NAN_SNAN_MASK)) {
+ /* We have at least one SNaN input and should prefer it */
+ do {
+ ret = val[rule & R_3NAN_1ST_MASK];
+ rule >>= R_3NAN_1ST_LENGTH;
+ } while (!is_snan(ret->cls));
+ } else {
+ do {
+ ret = val[rule & R_3NAN_1ST_MASK];
+ rule >>= R_3NAN_1ST_LENGTH;
+ } while (!is_nan(ret->cls));
+ }
}
- switch (which) {
- case 0:
- break;
- case 1:
- a = b;
- break;
- case 2:
- a = c;
- break;
- default:
- g_assert_not_reached();
- }
- if (is_snan(a->cls)) {
- parts_silence_nan(a, s);
+ if (is_snan(ret->cls)) {
+ parts_silence_nan(ret, s);
}
+ return ret;
+
+ default_nan:
+ parts_default_nan(a, s);
return a;
}
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
index 9bca03c..cbbbab5 100644
--- a/fpu/softfloat-specialize.c.inc
+++ b/fpu/softfloat-specialize.c.inc
@@ -133,35 +133,17 @@ static void parts64_default_nan(FloatParts64 *p, float_status *status)
{
bool sign = 0;
uint64_t frac;
+ uint8_t dnan_pattern = status->default_nan_pattern;
-#if defined(TARGET_SPARC) || defined(TARGET_M68K)
- /* !snan_bit_is_one, set all bits */
- frac = (1ULL << DECOMPOSED_BINARY_POINT) - 1;
-#elif defined(TARGET_I386) || defined(TARGET_X86_64) \
- || defined(TARGET_MICROBLAZE)
- /* !snan_bit_is_one, set sign and msb */
- frac = 1ULL << (DECOMPOSED_BINARY_POINT - 1);
- sign = 1;
-#elif defined(TARGET_HPPA)
- /* snan_bit_is_one, set msb-1. */
- frac = 1ULL << (DECOMPOSED_BINARY_POINT - 2);
-#elif defined(TARGET_HEXAGON)
- sign = 1;
- frac = ~0ULL;
-#else
+ assert(dnan_pattern != 0);
+
+ sign = dnan_pattern >> 7;
/*
- * This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V,
- * S390, SH4, TriCore, and Xtensa. Our other supported targets
- * do not have floating-point.
+ * Place default_nan_pattern [6:0] into bits [62:56],
+ * and replecate bit [0] down into [55:0]
*/
- if (snan_bit_is_one(status)) {
- /* set all bits other than msb */
- frac = (1ULL << (DECOMPOSED_BINARY_POINT - 1)) - 1;
- } else {
- /* set msb */
- frac = 1ULL << (DECOMPOSED_BINARY_POINT - 1);
- }
-#endif
+ frac = deposit64(0, DECOMPOSED_BINARY_POINT - 7, 7, dnan_pattern);
+ frac = deposit64(frac, 0, DECOMPOSED_BINARY_POINT - 7, -(dnan_pattern & 1));
*p = (FloatParts64) {
.cls = float_class_qnan,
@@ -227,17 +209,17 @@ static void parts128_silence_nan(FloatParts128 *p, float_status *status)
floatx80 floatx80_default_nan(float_status *status)
{
floatx80 r;
+ /*
+ * Extrapolate from the choices made by parts64_default_nan to fill
+ * in the floatx80 format. We assume that floatx80's explicit
+ * integer bit is always set (this is true for i386 and m68k,
+ * which are the only real users of this format).
+ */
+ FloatParts64 p64;
+ parts64_default_nan(&p64, status);
- /* None of the targets that have snan_bit_is_one use floatx80. */
- assert(!snan_bit_is_one(status));
-#if defined(TARGET_M68K)
- r.low = UINT64_C(0xFFFFFFFFFFFFFFFF);
- r.high = 0x7FFF;
-#else
- /* X86 */
- r.low = UINT64_C(0xC000000000000000);
- r.high = 0xFFFF;
-#endif
+ r.high = 0x7FFF | (p64.sign << 15);
+ r.low = (1ULL << DECOMPOSED_BINARY_POINT) | p64.frac;
return r;
}
@@ -371,312 +353,6 @@ bool float32_is_signaling_nan(float32 a_, float_status *status)
}
/*----------------------------------------------------------------------------
-| Select which NaN to propagate for a two-input operation.
-| IEEE754 doesn't specify all the details of this, so the
-| algorithm is target-specific.
-| The routine is passed various bits of information about the
-| two NaNs and should return 0 to select NaN a and 1 for NaN b.
-| Note that signalling NaNs are always squashed to quiet NaNs
-| by the caller, by calling floatXX_silence_nan() before
-| returning them.
-|
-| aIsLargerSignificand is only valid if both a and b are NaNs
-| of some kind, and is true if a has the larger significand,
-| or if both a and b have the same significand but a is
-| positive but b is negative. It is only needed for the x87
-| tie-break rule.
-*----------------------------------------------------------------------------*/
-
-static int pickNaN(FloatClass a_cls, FloatClass b_cls,
- bool aIsLargerSignificand, float_status *status)
-{
- /*
- * We guarantee not to require the target to tell us how to
- * pick a NaN if we're always returning the default NaN.
- * But if we're not in default-NaN mode then the target must
- * specify via set_float_2nan_prop_rule().
- */
- assert(!status->default_nan_mode);
-
- switch (status->float_2nan_prop_rule) {
- case float_2nan_prop_s_ab:
- if (is_snan(a_cls)) {
- return 0;
- } else if (is_snan(b_cls)) {
- return 1;
- } else if (is_qnan(a_cls)) {
- return 0;
- } else {
- return 1;
- }
- break;
- case float_2nan_prop_s_ba:
- if (is_snan(b_cls)) {
- return 1;
- } else if (is_snan(a_cls)) {
- return 0;
- } else if (is_qnan(b_cls)) {
- return 1;
- } else {
- return 0;
- }
- break;
- case float_2nan_prop_ab:
- if (is_nan(a_cls)) {
- return 0;
- } else {
- return 1;
- }
- break;
- case float_2nan_prop_ba:
- if (is_nan(b_cls)) {
- return 1;
- } else {
- return 0;
- }
- break;
- case float_2nan_prop_x87:
- /*
- * This implements x87 NaN propagation rules:
- * SNaN + QNaN => return the QNaN
- * two SNaNs => return the one with the larger significand, silenced
- * two QNaNs => return the one with the larger significand
- * SNaN and a non-NaN => return the SNaN, silenced
- * QNaN and a non-NaN => return the QNaN
- *
- * If we get down to comparing significands and they are the same,
- * return the NaN with the positive sign bit (if any).
- */
- if (is_snan(a_cls)) {
- if (is_snan(b_cls)) {
- return aIsLargerSignificand ? 0 : 1;
- }
- return is_qnan(b_cls) ? 1 : 0;
- } else if (is_qnan(a_cls)) {
- if (is_snan(b_cls) || !is_qnan(b_cls)) {
- return 0;
- } else {
- return aIsLargerSignificand ? 0 : 1;
- }
- } else {
- return 1;
- }
- default:
- g_assert_not_reached();
- }
-}
-
-/*----------------------------------------------------------------------------
-| Select which NaN to propagate for a three-input operation.
-| For the moment we assume that no CPU needs the 'larger significand'
-| information.
-| Return values : 0 : a; 1 : b; 2 : c; 3 : default-NaN
-*----------------------------------------------------------------------------*/
-static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
- bool infzero, float_status *status)
-{
-#if defined(TARGET_ARM)
- /* For ARM, the (inf,zero,qnan) case sets InvalidOp and returns
- * the default NaN
- */
- if (infzero && is_qnan(c_cls)) {
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
- return 3;
- }
-
- /* This looks different from the ARM ARM pseudocode, because the ARM ARM
- * puts the operands to a fused mac operation (a*b)+c in the order c,a,b.
- */
- if (is_snan(c_cls)) {
- return 2;
- } else if (is_snan(a_cls)) {
- return 0;
- } else if (is_snan(b_cls)) {
- return 1;
- } else if (is_qnan(c_cls)) {
- return 2;
- } else if (is_qnan(a_cls)) {
- return 0;
- } else {
- return 1;
- }
-#elif defined(TARGET_MIPS)
- if (snan_bit_is_one(status)) {
- /*
- * For MIPS systems that conform to IEEE754-1985, the (inf,zero,nan)
- * case sets InvalidOp and returns the default NaN
- */
- if (infzero) {
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
- return 3;
- }
- /* Prefer sNaN over qNaN, in the a, b, c order. */
- if (is_snan(a_cls)) {
- return 0;
- } else if (is_snan(b_cls)) {
- return 1;
- } else if (is_snan(c_cls)) {
- return 2;
- } else if (is_qnan(a_cls)) {
- return 0;
- } else if (is_qnan(b_cls)) {
- return 1;
- } else {
- return 2;
- }
- } else {
- /*
- * For MIPS systems that conform to IEEE754-2008, the (inf,zero,nan)
- * case sets InvalidOp and returns the input value 'c'
- */
- if (infzero) {
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
- return 2;
- }
- /* Prefer sNaN over qNaN, in the c, a, b order. */
- if (is_snan(c_cls)) {
- return 2;
- } else if (is_snan(a_cls)) {
- return 0;
- } else if (is_snan(b_cls)) {
- return 1;
- } else if (is_qnan(c_cls)) {
- return 2;
- } else if (is_qnan(a_cls)) {
- return 0;
- } else {
- return 1;
- }
- }
-#elif defined(TARGET_LOONGARCH64)
- /*
- * For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan)
- * case sets InvalidOp and returns the input value 'c'
- */
- if (infzero) {
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
- return 2;
- }
- /* Prefer sNaN over qNaN, in the c, a, b order. */
- if (is_snan(c_cls)) {
- return 2;
- } else if (is_snan(a_cls)) {
- return 0;
- } else if (is_snan(b_cls)) {
- return 1;
- } else if (is_qnan(c_cls)) {
- return 2;
- } else if (is_qnan(a_cls)) {
- return 0;
- } else {
- return 1;
- }
-#elif defined(TARGET_PPC)
- /* For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer
- * to return an input NaN if we have one (ie c) rather than generating
- * a default NaN
- */
- if (infzero) {
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
- return 2;
- }
-
- /* If fRA is a NaN return it; otherwise if fRB is a NaN return it;
- * otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB
- */
- if (is_nan(a_cls)) {
- return 0;
- } else if (is_nan(c_cls)) {
- return 2;
- } else {
- return 1;
- }
-#elif defined(TARGET_RISCV)
- /* For RISC-V, InvalidOp is set when multiplicands are Inf and zero */
- if (infzero) {
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
- }
- return 3; /* default NaN */
-#elif defined(TARGET_S390X)
- if (infzero) {
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
- return 3;
- }
-
- if (is_snan(a_cls)) {
- return 0;
- } else if (is_snan(b_cls)) {
- return 1;
- } else if (is_snan(c_cls)) {
- return 2;
- } else if (is_qnan(a_cls)) {
- return 0;
- } else if (is_qnan(b_cls)) {
- return 1;
- } else {
- return 2;
- }
-#elif defined(TARGET_SPARC)
- /* For (inf,0,nan) return c. */
- if (infzero) {
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
- return 2;
- }
- /* Prefer SNaN over QNaN, order C, B, A. */
- if (is_snan(c_cls)) {
- return 2;
- } else if (is_snan(b_cls)) {
- return 1;
- } else if (is_snan(a_cls)) {
- return 0;
- } else if (is_qnan(c_cls)) {
- return 2;
- } else if (is_qnan(b_cls)) {
- return 1;
- } else {
- return 0;
- }
-#elif defined(TARGET_XTENSA)
- /*
- * For Xtensa, the (inf,zero,nan) case sets InvalidOp and returns
- * an input NaN if we have one (ie c).
- */
- if (infzero) {
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
- return 2;
- }
- if (status->use_first_nan) {
- if (is_nan(a_cls)) {
- return 0;
- } else if (is_nan(b_cls)) {
- return 1;
- } else {
- return 2;
- }
- } else {
- if (is_nan(c_cls)) {
- return 2;
- } else if (is_nan(b_cls)) {
- return 1;
- } else {
- return 0;
- }
- }
-#else
- /* A default implementation: prefer a to b to c.
- * This is unlikely to actually match any real implementation.
- */
- if (is_nan(a_cls)) {
- return 0;
- } else if (is_nan(b_cls)) {
- return 1;
- } else {
- return 2;
- }
-#endif
-}
-
-/*----------------------------------------------------------------------------
| Returns 1 if the double-precision floating-point value `a' is a quiet
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
@@ -780,58 +456,6 @@ floatx80 floatx80_silence_nan(floatx80 a, float_status *status)
}
/*----------------------------------------------------------------------------
-| Takes two extended double-precision floating-point values `a' and `b', one
-| of which is a NaN, and returns the appropriate NaN result. If either `a' or
-| `b' is a signaling NaN, the invalid exception is raised.
-*----------------------------------------------------------------------------*/
-
-floatx80 propagateFloatx80NaN(floatx80 a, floatx80 b, float_status *status)
-{
- bool aIsLargerSignificand;
- FloatClass a_cls, b_cls;
-
- /* This is not complete, but is good enough for pickNaN. */
- a_cls = (!floatx80_is_any_nan(a)
- ? float_class_normal
- : floatx80_is_signaling_nan(a, status)
- ? float_class_snan
- : float_class_qnan);
- b_cls = (!floatx80_is_any_nan(b)
- ? float_class_normal
- : floatx80_is_signaling_nan(b, status)
- ? float_class_snan
- : float_class_qnan);
-
- if (is_snan(a_cls) || is_snan(b_cls)) {
- float_raise(float_flag_invalid, status);
- }
-
- if (status->default_nan_mode) {
- return floatx80_default_nan(status);
- }
-
- if (a.low < b.low) {
- aIsLargerSignificand = 0;
- } else if (b.low < a.low) {
- aIsLargerSignificand = 1;
- } else {
- aIsLargerSignificand = (a.high < b.high) ? 1 : 0;
- }
-
- if (pickNaN(a_cls, b_cls, aIsLargerSignificand, status)) {
- if (is_snan(b_cls)) {
- return floatx80_silence_nan(b, status);
- }
- return b;
- } else {
- if (is_snan(a_cls)) {
- return floatx80_silence_nan(a, status);
- }
- return a;
- }
-}
-
-/*----------------------------------------------------------------------------
| Returns 1 if the quadruple-precision floating-point value `a' is a quiet
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 027a8e5..8de8d5f 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -4921,6 +4921,25 @@ void normalizeFloatx80Subnormal(uint64_t aSig, int32_t *zExpPtr,
}
/*----------------------------------------------------------------------------
+| Takes two extended double-precision floating-point values `a' and `b', one
+| of which is a NaN, and returns the appropriate NaN result. If either `a' or
+| `b' is a signaling NaN, the invalid exception is raised.
+*----------------------------------------------------------------------------*/
+
+floatx80 propagateFloatx80NaN(floatx80 a, floatx80 b, float_status *status)
+{
+ FloatParts128 pa, pb, *pr;
+
+ if (!floatx80_unpack_canonical(&pa, a, status) ||
+ !floatx80_unpack_canonical(&pb, b, status)) {
+ return floatx80_default_nan(status);
+ }
+
+ pr = parts_pick_nan(&pa, &pb, status);
+ return floatx80_round_pack_canonical(pr, status);
+}
+
+/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and extended significand formed by the concatenation of `zSig0' and `zSig1',
| and returns the proper extended double-precision floating-point value
diff --git a/hw/net/Kconfig b/hw/net/Kconfig
index 7fcc0d7..7f80218 100644
--- a/hw/net/Kconfig
+++ b/hw/net/Kconfig
@@ -62,8 +62,12 @@ config VMXNET3_PCI
config SMC91C111
bool
+config LAN9118_PHY
+ bool
+
config LAN9118
bool
+ select LAN9118_PHY
select PTIMER
config NE2000_ISA
@@ -89,6 +93,7 @@ config ALLWINNER_SUN8I_EMAC
config IMX_FEC
bool
+ select LAN9118_PHY
config CADENCE
bool
diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c
index 6294d29..4ee6f74 100644
--- a/hw/net/imx_fec.c
+++ b/hw/net/imx_fec.c
@@ -203,17 +203,12 @@ static const VMStateDescription vmstate_imx_eth_txdescs = {
static const VMStateDescription vmstate_imx_eth = {
.name = TYPE_IMX_FEC,
- .version_id = 2,
- .minimum_version_id = 2,
+ .version_id = 3,
+ .minimum_version_id = 3,
.fields = (const VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, IMXFECState, ENET_MAX),
VMSTATE_UINT32(rx_descriptor, IMXFECState),
VMSTATE_UINT32(tx_descriptor[0], IMXFECState),
- VMSTATE_UINT32(phy_status, IMXFECState),
- VMSTATE_UINT32(phy_control, IMXFECState),
- VMSTATE_UINT32(phy_advertise, IMXFECState),
- VMSTATE_UINT32(phy_int, IMXFECState),
- VMSTATE_UINT32(phy_int_mask, IMXFECState),
VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription * const []) {
@@ -222,14 +217,6 @@ static const VMStateDescription vmstate_imx_eth = {
},
};
-#define PHY_INT_ENERGYON (1 << 7)
-#define PHY_INT_AUTONEG_COMPLETE (1 << 6)
-#define PHY_INT_FAULT (1 << 5)
-#define PHY_INT_DOWN (1 << 4)
-#define PHY_INT_AUTONEG_LP (1 << 3)
-#define PHY_INT_PARFAULT (1 << 2)
-#define PHY_INT_AUTONEG_PAGE (1 << 1)
-
static void imx_eth_update(IMXFECState *s);
/*
@@ -238,47 +225,19 @@ static void imx_eth_update(IMXFECState *s);
* For now we don't handle any GPIO/interrupt line, so the OS will
* have to poll for the PHY status.
*/
-static void imx_phy_update_irq(IMXFECState *s)
-{
- imx_eth_update(s);
-}
-
-static void imx_phy_update_link(IMXFECState *s)
+static void imx_phy_update_irq(void *opaque, int n, int level)
{
- /* Autonegotiation status mirrors link status. */
- if (qemu_get_queue(s->nic)->link_down) {
- trace_imx_phy_update_link("down");
- s->phy_status &= ~0x0024;
- s->phy_int |= PHY_INT_DOWN;
- } else {
- trace_imx_phy_update_link("up");
- s->phy_status |= 0x0024;
- s->phy_int |= PHY_INT_ENERGYON;
- s->phy_int |= PHY_INT_AUTONEG_COMPLETE;
- }
- imx_phy_update_irq(s);
+ imx_eth_update(opaque);
}
static void imx_eth_set_link(NetClientState *nc)
{
- imx_phy_update_link(IMX_FEC(qemu_get_nic_opaque(nc)));
-}
-
-static void imx_phy_reset(IMXFECState *s)
-{
- trace_imx_phy_reset();
-
- s->phy_status = 0x7809;
- s->phy_control = 0x3000;
- s->phy_advertise = 0x01e1;
- s->phy_int_mask = 0;
- s->phy_int = 0;
- imx_phy_update_link(s);
+ lan9118_phy_update_link(&IMX_FEC(qemu_get_nic_opaque(nc))->mii,
+ nc->link_down);
}
static uint32_t imx_phy_read(IMXFECState *s, int reg)
{
- uint32_t val;
uint32_t phy = reg / 32;
if (!s->phy_connected) {
@@ -296,54 +255,7 @@ static uint32_t imx_phy_read(IMXFECState *s, int reg)
reg %= 32;
- switch (reg) {
- case 0: /* Basic Control */
- val = s->phy_control;
- break;
- case 1: /* Basic Status */
- val = s->phy_status;
- break;
- case 2: /* ID1 */
- val = 0x0007;
- break;
- case 3: /* ID2 */
- val = 0xc0d1;
- break;
- case 4: /* Auto-neg advertisement */
- val = s->phy_advertise;
- break;
- case 5: /* Auto-neg Link Partner Ability */
- val = 0x0f71;
- break;
- case 6: /* Auto-neg Expansion */
- val = 1;
- break;
- case 29: /* Interrupt source. */
- val = s->phy_int;
- s->phy_int = 0;
- imx_phy_update_irq(s);
- break;
- case 30: /* Interrupt mask */
- val = s->phy_int_mask;
- break;
- case 17:
- case 18:
- case 27:
- case 31:
- qemu_log_mask(LOG_UNIMP, "[%s.phy]%s: reg %d not implemented\n",
- TYPE_IMX_FEC, __func__, reg);
- val = 0;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad address at offset %d\n",
- TYPE_IMX_FEC, __func__, reg);
- val = 0;
- break;
- }
-
- trace_imx_phy_read(val, phy, reg);
-
- return val;
+ return lan9118_phy_read(&s->mii, reg);
}
static void imx_phy_write(IMXFECState *s, int reg, uint32_t val)
@@ -365,39 +277,7 @@ static void imx_phy_write(IMXFECState *s, int reg, uint32_t val)
reg %= 32;
- trace_imx_phy_write(val, phy, reg);
-
- switch (reg) {
- case 0: /* Basic Control */
- if (val & 0x8000) {
- imx_phy_reset(s);
- } else {
- s->phy_control = val & 0x7980;
- /* Complete autonegotiation immediately. */
- if (val & 0x1000) {
- s->phy_status |= 0x0020;
- }
- }
- break;
- case 4: /* Auto-neg advertisement */
- s->phy_advertise = (val & 0x2d7f) | 0x80;
- break;
- case 30: /* Interrupt mask */
- s->phy_int_mask = val & 0xff;
- imx_phy_update_irq(s);
- break;
- case 17:
- case 18:
- case 27:
- case 31:
- qemu_log_mask(LOG_UNIMP, "[%s.phy)%s: reg %d not implemented\n",
- TYPE_IMX_FEC, __func__, reg);
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad address at offset %d\n",
- TYPE_IMX_FEC, __func__, reg);
- break;
- }
+ lan9118_phy_write(&s->mii, reg, val);
}
static void imx_fec_read_bd(IMXFECBufDesc *bd, dma_addr_t addr)
@@ -682,9 +562,6 @@ static void imx_eth_reset(DeviceState *d)
s->rx_descriptor = 0;
memset(s->tx_descriptor, 0, sizeof(s->tx_descriptor));
-
- /* We also reset the PHY */
- imx_phy_reset(s);
}
static uint32_t imx_default_read(IMXFECState *s, uint32_t index)
@@ -1329,6 +1206,13 @@ static void imx_eth_realize(DeviceState *dev, Error **errp)
sysbus_init_irq(sbd, &s->irq[0]);
sysbus_init_irq(sbd, &s->irq[1]);
+ qemu_init_irq(&s->mii_irq, imx_phy_update_irq, s, 0);
+ object_initialize_child(OBJECT(s), "mii", &s->mii, TYPE_LAN9118_PHY);
+ if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(&s->mii), errp)) {
+ return;
+ }
+ qdev_connect_gpio_out(DEVICE(&s->mii), 0, &s->mii_irq);
+
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->nic = qemu_new_nic(&imx_eth_net_info, &s->conf,
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
index db28a0e..99e87b7 100644
--- a/hw/net/lan9118.c
+++ b/hw/net/lan9118.c
@@ -16,6 +16,7 @@
#include "net/net.h"
#include "net/eth.h"
#include "hw/irq.h"
+#include "hw/net/lan9118_phy.h"
#include "hw/net/lan9118.h"
#include "hw/ptimer.h"
#include "hw/qdev-properties.h"
@@ -139,14 +140,6 @@ do { printf("lan9118: " fmt , ## __VA_ARGS__); } while (0)
#define MAC_CR_RXEN 0x00000004
#define MAC_CR_RESERVED 0x7f404213
-#define PHY_INT_ENERGYON 0x80
-#define PHY_INT_AUTONEG_COMPLETE 0x40
-#define PHY_INT_FAULT 0x20
-#define PHY_INT_DOWN 0x10
-#define PHY_INT_AUTONEG_LP 0x08
-#define PHY_INT_PARFAULT 0x04
-#define PHY_INT_AUTONEG_PAGE 0x02
-
#define GPT_TIMER_EN 0x20000000
/*
@@ -228,11 +221,8 @@ struct lan9118_state {
uint32_t mac_mii_data;
uint32_t mac_flow;
- uint32_t phy_status;
- uint32_t phy_control;
- uint32_t phy_advertise;
- uint32_t phy_int;
- uint32_t phy_int_mask;
+ Lan9118PhyState mii;
+ IRQState mii_irq;
int32_t eeprom_writable;
uint8_t eeprom[128];
@@ -274,8 +264,8 @@ struct lan9118_state {
static const VMStateDescription vmstate_lan9118 = {
.name = "lan9118",
- .version_id = 2,
- .minimum_version_id = 1,
+ .version_id = 3,
+ .minimum_version_id = 3,
.fields = (const VMStateField[]) {
VMSTATE_PTIMER(timer, lan9118_state),
VMSTATE_UINT32(irq_cfg, lan9118_state),
@@ -301,11 +291,6 @@ static const VMStateDescription vmstate_lan9118 = {
VMSTATE_UINT32(mac_mii_acc, lan9118_state),
VMSTATE_UINT32(mac_mii_data, lan9118_state),
VMSTATE_UINT32(mac_flow, lan9118_state),
- VMSTATE_UINT32(phy_status, lan9118_state),
- VMSTATE_UINT32(phy_control, lan9118_state),
- VMSTATE_UINT32(phy_advertise, lan9118_state),
- VMSTATE_UINT32(phy_int, lan9118_state),
- VMSTATE_UINT32(phy_int_mask, lan9118_state),
VMSTATE_INT32(eeprom_writable, lan9118_state),
VMSTATE_UINT8_ARRAY(eeprom, lan9118_state, 128),
VMSTATE_INT32(tx_fifo_size, lan9118_state),
@@ -385,9 +370,11 @@ static void lan9118_reload_eeprom(lan9118_state *s)
lan9118_mac_changed(s);
}
-static void phy_update_irq(lan9118_state *s)
+static void lan9118_update_irq(void *opaque, int n, int level)
{
- if (s->phy_int & s->phy_int_mask) {
+ lan9118_state *s = opaque;
+
+ if (level) {
s->int_sts |= PHY_INT;
} else {
s->int_sts &= ~PHY_INT;
@@ -395,33 +382,10 @@ static void phy_update_irq(lan9118_state *s)
lan9118_update(s);
}
-static void phy_update_link(lan9118_state *s)
-{
- /* Autonegotiation status mirrors link status. */
- if (qemu_get_queue(s->nic)->link_down) {
- s->phy_status &= ~0x0024;
- s->phy_int |= PHY_INT_DOWN;
- } else {
- s->phy_status |= 0x0024;
- s->phy_int |= PHY_INT_ENERGYON;
- s->phy_int |= PHY_INT_AUTONEG_COMPLETE;
- }
- phy_update_irq(s);
-}
-
static void lan9118_set_link(NetClientState *nc)
{
- phy_update_link(qemu_get_nic_opaque(nc));
-}
-
-static void phy_reset(lan9118_state *s)
-{
- s->phy_status = 0x7809;
- s->phy_control = 0x3000;
- s->phy_advertise = 0x01e1;
- s->phy_int_mask = 0;
- s->phy_int = 0;
- phy_update_link(s);
+ lan9118_phy_update_link(&LAN9118(qemu_get_nic_opaque(nc))->mii,
+ nc->link_down);
}
static void lan9118_reset(DeviceState *d)
@@ -478,8 +442,6 @@ static void lan9118_reset(DeviceState *d)
s->read_word_n = 0;
s->write_word_n = 0;
- phy_reset(s);
-
s->eeprom_writable = 0;
lan9118_reload_eeprom(s);
}
@@ -678,7 +640,7 @@ static void do_tx_packet(lan9118_state *s)
uint32_t status;
/* FIXME: Honor TX disable, and allow queueing of packets. */
- if (s->phy_control & 0x4000) {
+ if (s->mii.control & 0x4000) {
/* This assumes the receive routine doesn't touch the VLANClient. */
qemu_receive_packet(qemu_get_queue(s->nic), s->txp->data, s->txp->len);
} else {
@@ -834,68 +796,6 @@ static void tx_fifo_push(lan9118_state *s, uint32_t val)
}
}
-static uint32_t do_phy_read(lan9118_state *s, int reg)
-{
- uint32_t val;
-
- switch (reg) {
- case 0: /* Basic Control */
- return s->phy_control;
- case 1: /* Basic Status */
- return s->phy_status;
- case 2: /* ID1 */
- return 0x0007;
- case 3: /* ID2 */
- return 0xc0d1;
- case 4: /* Auto-neg advertisement */
- return s->phy_advertise;
- case 5: /* Auto-neg Link Partner Ability */
- return 0x0f71;
- case 6: /* Auto-neg Expansion */
- return 1;
- /* TODO 17, 18, 27, 29, 30, 31 */
- case 29: /* Interrupt source. */
- val = s->phy_int;
- s->phy_int = 0;
- phy_update_irq(s);
- return val;
- case 30: /* Interrupt mask */
- return s->phy_int_mask;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "do_phy_read: PHY read reg %d\n", reg);
- return 0;
- }
-}
-
-static void do_phy_write(lan9118_state *s, int reg, uint32_t val)
-{
- switch (reg) {
- case 0: /* Basic Control */
- if (val & 0x8000) {
- phy_reset(s);
- break;
- }
- s->phy_control = val & 0x7980;
- /* Complete autonegotiation immediately. */
- if (val & 0x1000) {
- s->phy_status |= 0x0020;
- }
- break;
- case 4: /* Auto-neg advertisement */
- s->phy_advertise = (val & 0x2d7f) | 0x80;
- break;
- /* TODO 17, 18, 27, 31 */
- case 30: /* Interrupt mask */
- s->phy_int_mask = val & 0xff;
- phy_update_irq(s);
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "do_phy_write: PHY write reg %d = 0x%04x\n", reg, val);
- }
-}
-
static void do_mac_write(lan9118_state *s, int reg, uint32_t val)
{
switch (reg) {
@@ -929,9 +829,9 @@ static void do_mac_write(lan9118_state *s, int reg, uint32_t val)
if (val & 2) {
DPRINTF("PHY write %d = 0x%04x\n",
(val >> 6) & 0x1f, s->mac_mii_data);
- do_phy_write(s, (val >> 6) & 0x1f, s->mac_mii_data);
+ lan9118_phy_write(&s->mii, (val >> 6) & 0x1f, s->mac_mii_data);
} else {
- s->mac_mii_data = do_phy_read(s, (val >> 6) & 0x1f);
+ s->mac_mii_data = lan9118_phy_read(&s->mii, (val >> 6) & 0x1f);
DPRINTF("PHY read %d = 0x%04x\n",
(val >> 6) & 0x1f, s->mac_mii_data);
}
@@ -1126,7 +1026,7 @@ static void lan9118_writel(void *opaque, hwaddr offset,
break;
case CSR_PMT_CTRL:
if (val & 0x400) {
- phy_reset(s);
+ lan9118_phy_reset(&s->mii);
}
s->pmt_ctrl &= ~0x34e;
s->pmt_ctrl |= (val & 0x34e);
@@ -1373,6 +1273,13 @@ static void lan9118_realize(DeviceState *dev, Error **errp)
const MemoryRegionOps *mem_ops =
s->mode_16bit ? &lan9118_16bit_mem_ops : &lan9118_mem_ops;
+ qemu_init_irq(&s->mii_irq, lan9118_update_irq, s, 0);
+ object_initialize_child(OBJECT(s), "mii", &s->mii, TYPE_LAN9118_PHY);
+ if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(&s->mii), errp)) {
+ return;
+ }
+ qdev_connect_gpio_out(DEVICE(&s->mii), 0, &s->mii_irq);
+
memory_region_init_io(&s->mmio, OBJECT(dev), mem_ops, s,
"lan9118-mmio", 0x100);
sysbus_init_mmio(sbd, &s->mmio);
diff --git a/hw/net/lan9118_phy.c b/hw/net/lan9118_phy.c
new file mode 100644
index 0000000..5c53a4a
--- /dev/null
+++ b/hw/net/lan9118_phy.c
@@ -0,0 +1,222 @@
+/*
+ * SMSC LAN9118 PHY emulation
+ *
+ * Copyright (c) 2009 CodeSourcery, LLC.
+ * Written by Paul Brook
+ *
+ * Copyright (c) 2013 Jean-Christophe Dubois. <jcd@tribudubois.net>
+ *
+ * This code is licensed under the GNU GPL v2
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/net/lan9118_phy.h"
+#include "hw/net/mii.h"
+#include "hw/irq.h"
+#include "hw/resettable.h"
+#include "migration/vmstate.h"
+#include "qemu/log.h"
+#include "trace.h"
+
+#define PHY_INT_ENERGYON (1 << 7)
+#define PHY_INT_AUTONEG_COMPLETE (1 << 6)
+#define PHY_INT_FAULT (1 << 5)
+#define PHY_INT_DOWN (1 << 4)
+#define PHY_INT_AUTONEG_LP (1 << 3)
+#define PHY_INT_PARFAULT (1 << 2)
+#define PHY_INT_AUTONEG_PAGE (1 << 1)
+
+static void lan9118_phy_update_irq(Lan9118PhyState *s)
+{
+ qemu_set_irq(s->irq, !!(s->ints & s->int_mask));
+}
+
+uint16_t lan9118_phy_read(Lan9118PhyState *s, int reg)
+{
+ uint16_t val;
+
+ switch (reg) {
+ case MII_BMCR:
+ val = s->control;
+ break;
+ case MII_BMSR:
+ val = s->status;
+ break;
+ case MII_PHYID1:
+ val = SMSCLAN9118_PHYID1;
+ break;
+ case MII_PHYID2:
+ val = SMSCLAN9118_PHYID2;
+ break;
+ case MII_ANAR:
+ val = s->advertise;
+ break;
+ case MII_ANLPAR:
+ val = MII_ANLPAR_PAUSEASY | MII_ANLPAR_PAUSE | MII_ANLPAR_T4 |
+ MII_ANLPAR_TXFD | MII_ANLPAR_TX | MII_ANLPAR_10FD |
+ MII_ANLPAR_10 | MII_ANLPAR_CSMACD;
+ break;
+ case MII_ANER:
+ val = MII_ANER_NWAY;
+ break;
+ case 29: /* Interrupt source. */
+ val = s->ints;
+ s->ints = 0;
+ lan9118_phy_update_irq(s);
+ break;
+ case 30: /* Interrupt mask */
+ val = s->int_mask;
+ break;
+ case 17:
+ case 18:
+ case 27:
+ case 31:
+ qemu_log_mask(LOG_UNIMP, "%s: reg %d not implemented\n",
+ __func__, reg);
+ val = 0;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address at offset %d\n",
+ __func__, reg);
+ val = 0;
+ break;
+ }
+
+ trace_lan9118_phy_read(val, reg);
+
+ return val;
+}
+
+void lan9118_phy_write(Lan9118PhyState *s, int reg, uint16_t val)
+{
+ trace_lan9118_phy_write(val, reg);
+
+ switch (reg) {
+ case MII_BMCR:
+ if (val & MII_BMCR_RESET) {
+ lan9118_phy_reset(s);
+ } else {
+ s->control = val & (MII_BMCR_LOOPBACK | MII_BMCR_SPEED100 |
+ MII_BMCR_AUTOEN | MII_BMCR_PDOWN | MII_BMCR_FD |
+ MII_BMCR_CTST);
+ /* Complete autonegotiation immediately. */
+ if (val & MII_BMCR_AUTOEN) {
+ s->status |= MII_BMSR_AN_COMP;
+ }
+ }
+ break;
+ case MII_ANAR:
+ s->advertise = (val & (MII_ANAR_RFAULT | MII_ANAR_PAUSE_ASYM |
+ MII_ANAR_PAUSE | MII_ANAR_TXFD | MII_ANAR_10FD |
+ MII_ANAR_10 | MII_ANAR_SELECT))
+ | MII_ANAR_TX;
+ break;
+ case 30: /* Interrupt mask */
+ s->int_mask = val & 0xff;
+ lan9118_phy_update_irq(s);
+ break;
+ case 17:
+ case 18:
+ case 27:
+ case 31:
+ qemu_log_mask(LOG_UNIMP, "%s: reg %d not implemented\n",
+ __func__, reg);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address at offset %d\n",
+ __func__, reg);
+ break;
+ }
+}
+
+void lan9118_phy_update_link(Lan9118PhyState *s, bool link_down)
+{
+ s->link_down = link_down;
+
+ /* Autonegotiation status mirrors link status. */
+ if (link_down) {
+ trace_lan9118_phy_update_link("down");
+ s->status &= ~(MII_BMSR_AN_COMP | MII_BMSR_LINK_ST);
+ s->ints |= PHY_INT_DOWN;
+ } else {
+ trace_lan9118_phy_update_link("up");
+ s->status |= MII_BMSR_AN_COMP | MII_BMSR_LINK_ST;
+ s->ints |= PHY_INT_ENERGYON;
+ s->ints |= PHY_INT_AUTONEG_COMPLETE;
+ }
+ lan9118_phy_update_irq(s);
+}
+
+void lan9118_phy_reset(Lan9118PhyState *s)
+{
+ trace_lan9118_phy_reset();
+
+ s->control = MII_BMCR_AUTOEN | MII_BMCR_SPEED100;
+ s->status = MII_BMSR_100TX_FD
+ | MII_BMSR_100TX_HD
+ | MII_BMSR_10T_FD
+ | MII_BMSR_10T_HD
+ | MII_BMSR_AUTONEG
+ | MII_BMSR_EXTCAP;
+ s->advertise = MII_ANAR_TXFD
+ | MII_ANAR_TX
+ | MII_ANAR_10FD
+ | MII_ANAR_10
+ | MII_ANAR_CSMACD;
+ s->int_mask = 0;
+ s->ints = 0;
+ lan9118_phy_update_link(s, s->link_down);
+}
+
+static void lan9118_phy_reset_hold(Object *obj, ResetType type)
+{
+ Lan9118PhyState *s = LAN9118_PHY(obj);
+
+ lan9118_phy_reset(s);
+}
+
+static void lan9118_phy_init(Object *obj)
+{
+ Lan9118PhyState *s = LAN9118_PHY(obj);
+
+ qdev_init_gpio_out(DEVICE(s), &s->irq, 1);
+}
+
+static const VMStateDescription vmstate_lan9118_phy = {
+ .name = "lan9118-phy",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT16(status, Lan9118PhyState),
+ VMSTATE_UINT16(control, Lan9118PhyState),
+ VMSTATE_UINT16(advertise, Lan9118PhyState),
+ VMSTATE_UINT16(ints, Lan9118PhyState),
+ VMSTATE_UINT16(int_mask, Lan9118PhyState),
+ VMSTATE_BOOL(link_down, Lan9118PhyState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void lan9118_phy_class_init(ObjectClass *klass, void *data)
+{
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ rc->phases.hold = lan9118_phy_reset_hold;
+ dc->vmsd = &vmstate_lan9118_phy;
+}
+
+static const TypeInfo types[] = {
+ {
+ .name = TYPE_LAN9118_PHY,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(Lan9118PhyState),
+ .instance_init = lan9118_phy_init,
+ .class_init = lan9118_phy_class_init,
+ }
+};
+
+DEFINE_TYPES(types)
diff --git a/hw/net/meson.build b/hw/net/meson.build
index 00a9e9d..3bb5d74 100644
--- a/hw/net/meson.build
+++ b/hw/net/meson.build
@@ -19,6 +19,7 @@ system_ss.add(when: 'CONFIG_VMXNET3_PCI', if_true: files('vmxnet3.c'))
system_ss.add(when: 'CONFIG_SMC91C111', if_true: files('smc91c111.c'))
system_ss.add(when: 'CONFIG_LAN9118', if_true: files('lan9118.c'))
+system_ss.add(when: 'CONFIG_LAN9118_PHY', if_true: files('lan9118_phy.c'))
system_ss.add(when: 'CONFIG_NE2000_ISA', if_true: files('ne2000-isa.c'))
system_ss.add(when: 'CONFIG_OPENCORES_ETH', if_true: files('opencores_eth.c'))
system_ss.add(when: 'CONFIG_XGMAC', if_true: files('xgmac.c'))
diff --git a/hw/net/trace-events b/hw/net/trace-events
index d0f1d8c..6100ec3 100644
--- a/hw/net/trace-events
+++ b/hw/net/trace-events
@@ -10,6 +10,12 @@ allwinner_sun8i_emac_set_link(bool active) "Set link: active=%u"
allwinner_sun8i_emac_read(uint64_t offset, uint64_t val) "MMIO read: offset=0x%" PRIx64 " value=0x%" PRIx64
allwinner_sun8i_emac_write(uint64_t offset, uint64_t val) "MMIO write: offset=0x%" PRIx64 " value=0x%" PRIx64
+# lan9118_phy.c
+lan9118_phy_read(uint16_t val, int reg) "[0x%02x] -> 0x%04" PRIx16
+lan9118_phy_write(uint16_t val, int reg) "[0x%02x] <- 0x%04" PRIx16
+lan9118_phy_update_link(const char *s) "%s"
+lan9118_phy_reset(void) ""
+
# lance.c
lance_mem_readw(uint64_t addr, uint32_t ret) "addr=0x%"PRIx64"val=0x%04x"
lance_mem_writew(uint64_t addr, uint32_t val) "addr=0x%"PRIx64"val=0x%04x"
@@ -428,12 +434,8 @@ i82596_set_multicast(uint16_t count) "Added %d multicast entries"
i82596_channel_attention(void *s) "%p: Received CHANNEL ATTENTION"
# imx_fec.c
-imx_phy_read(uint32_t val, int phy, int reg) "0x%04"PRIx32" <= phy[%d].reg[%d]"
imx_phy_read_num(int phy, int configured) "read request from unconfigured phy %d (configured %d)"
-imx_phy_write(uint32_t val, int phy, int reg) "0x%04"PRIx32" => phy[%d].reg[%d]"
imx_phy_write_num(int phy, int configured) "write request to unconfigured phy %d (configured %d)"
-imx_phy_update_link(const char *s) "%s"
-imx_phy_reset(void) ""
imx_fec_read_bd(uint64_t addr, int flags, int len, int data) "tx_bd 0x%"PRIx64" flags 0x%04x len %d data 0x%08x"
imx_enet_read_bd(uint64_t addr, int flags, int len, int data, int options, int status) "tx_bd 0x%"PRIx64" flags 0x%04x len %d data 0x%08x option 0x%04x status 0x%04x"
imx_eth_tx_bd_busy(void) "tx_bd ran out of descriptors to transmit"
diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h
index 453188d..dceee23 100644
--- a/include/fpu/softfloat-helpers.h
+++ b/include/fpu/softfloat-helpers.h
@@ -81,6 +81,24 @@ static inline void set_float_2nan_prop_rule(Float2NaNPropRule rule,
status->float_2nan_prop_rule = rule;
}
+static inline void set_float_3nan_prop_rule(Float3NaNPropRule rule,
+ float_status *status)
+{
+ status->float_3nan_prop_rule = rule;
+}
+
+static inline void set_float_infzeronan_rule(FloatInfZeroNaNRule rule,
+ float_status *status)
+{
+ status->float_infzeronan_rule = rule;
+}
+
+static inline void set_float_default_nan_pattern(uint8_t dnan_pattern,
+ float_status *status)
+{
+ status->default_nan_pattern = dnan_pattern;
+}
+
static inline void set_flush_to_zero(bool val, float_status *status)
{
status->flush_to_zero = val;
@@ -101,11 +119,6 @@ static inline void set_snan_bit_is_one(bool val, float_status *status)
status->snan_bit_is_one = val;
}
-static inline void set_use_first_nan(bool val, float_status *status)
-{
- status->use_first_nan = val;
-}
-
static inline void set_no_signaling_nans(bool val, float_status *status)
{
status->no_signaling_nans = val;
@@ -137,6 +150,21 @@ static inline Float2NaNPropRule get_float_2nan_prop_rule(float_status *status)
return status->float_2nan_prop_rule;
}
+static inline Float3NaNPropRule get_float_3nan_prop_rule(float_status *status)
+{
+ return status->float_3nan_prop_rule;
+}
+
+static inline FloatInfZeroNaNRule get_float_infzeronan_rule(float_status *status)
+{
+ return status->float_infzeronan_rule;
+}
+
+static inline uint8_t get_float_default_nan_pattern(float_status *status)
+{
+ return status->default_nan_pattern;
+}
+
static inline bool get_flush_to_zero(float_status *status)
{
return status->flush_to_zero;
diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h
index 8f39691..79ca44d 100644
--- a/include/fpu/softfloat-types.h
+++ b/include/fpu/softfloat-types.h
@@ -80,6 +80,8 @@ this code that are retained.
#ifndef SOFTFLOAT_TYPES_H
#define SOFTFLOAT_TYPES_H
+#include "hw/registerfields.h"
+
/*
* Software IEC/IEEE floating-point types.
*/
@@ -208,6 +210,80 @@ typedef enum __attribute__((__packed__)) {
} Float2NaNPropRule;
/*
+ * 3-input NaN propagation rule, for fused multiply-add. Individual
+ * architectures have different rules for which input NaN is
+ * propagated to the output when there is more than one NaN on the
+ * input.
+ *
+ * If default_nan_mode is enabled then it is valid not to set a NaN
+ * propagation rule, because the softfloat code guarantees not to try
+ * to pick a NaN to propagate in default NaN mode. When not in
+ * default-NaN mode, it is an error for the target not to set the rule
+ * in float_status if it uses a muladd, and we will assert if we need
+ * to handle an input NaN and no rule was selected.
+ *
+ * The naming scheme for Float3NaNPropRule values is:
+ * float_3nan_prop_s_abc:
+ * = "Prefer SNaN over QNaN, then operand A over B over C"
+ * float_3nan_prop_abc:
+ * = "Prefer A over B over C regardless of SNaN vs QNAN"
+ *
+ * For QEMU, the multiply-add operation is A * B + C.
+ */
+
+/*
+ * We set the Float3NaNPropRule enum values up so we can select the
+ * right value in pickNaNMulAdd in a data driven way.
+ */
+FIELD(3NAN, 1ST, 0, 2) /* which operand is most preferred ? */
+FIELD(3NAN, 2ND, 2, 2) /* which operand is next most preferred ? */
+FIELD(3NAN, 3RD, 4, 2) /* which operand is least preferred ? */
+FIELD(3NAN, SNAN, 6, 1) /* do we prefer SNaN over QNaN ? */
+
+#define PROPRULE(X, Y, Z) \
+ ((X << R_3NAN_1ST_SHIFT) | (Y << R_3NAN_2ND_SHIFT) | (Z << R_3NAN_3RD_SHIFT))
+
+typedef enum __attribute__((__packed__)) {
+ float_3nan_prop_none = 0, /* No propagation rule specified */
+ float_3nan_prop_abc = PROPRULE(0, 1, 2),
+ float_3nan_prop_acb = PROPRULE(0, 2, 1),
+ float_3nan_prop_bac = PROPRULE(1, 0, 2),
+ float_3nan_prop_bca = PROPRULE(1, 2, 0),
+ float_3nan_prop_cab = PROPRULE(2, 0, 1),
+ float_3nan_prop_cba = PROPRULE(2, 1, 0),
+ float_3nan_prop_s_abc = float_3nan_prop_abc | R_3NAN_SNAN_MASK,
+ float_3nan_prop_s_acb = float_3nan_prop_acb | R_3NAN_SNAN_MASK,
+ float_3nan_prop_s_bac = float_3nan_prop_bac | R_3NAN_SNAN_MASK,
+ float_3nan_prop_s_bca = float_3nan_prop_bca | R_3NAN_SNAN_MASK,
+ float_3nan_prop_s_cab = float_3nan_prop_cab | R_3NAN_SNAN_MASK,
+ float_3nan_prop_s_cba = float_3nan_prop_cba | R_3NAN_SNAN_MASK,
+} Float3NaNPropRule;
+
+#undef PROPRULE
+
+/*
+ * Rule for result of fused multiply-add 0 * Inf + NaN.
+ * This must be a NaN, but implementations differ on whether this
+ * is the input NaN or the default NaN.
+ *
+ * You don't need to set this if default_nan_mode is enabled.
+ * When not in default-NaN mode, it is an error for the target
+ * not to set the rule in float_status if it uses muladd, and we
+ * will assert if we need to handle an input NaN and no rule was
+ * selected.
+ */
+typedef enum __attribute__((__packed__)) {
+ /* No propagation rule specified */
+ float_infzeronan_none = 0,
+ /* Result is never the default NaN (so always the input NaN) */
+ float_infzeronan_dnan_never,
+ /* Result is always the default NaN */
+ float_infzeronan_dnan_always,
+ /* Result is the default NaN if the input NaN is quiet */
+ float_infzeronan_dnan_if_qnan,
+} FloatInfZeroNaNRule;
+
+/*
* Floating Point Status. Individual architectures may maintain
* several versions of float_status for different functions. The
* correct status for the operation is then passed by reference to
@@ -219,6 +295,8 @@ typedef struct float_status {
FloatRoundMode float_rounding_mode;
FloatX80RoundPrec floatx80_rounding_precision;
Float2NaNPropRule float_2nan_prop_rule;
+ Float3NaNPropRule float_3nan_prop_rule;
+ FloatInfZeroNaNRule float_infzeronan_rule;
bool tininess_before_rounding;
/* should denormalised results go to zero and set the inexact flag? */
bool flush_to_zero;
@@ -226,12 +304,21 @@ typedef struct float_status {
bool flush_inputs_to_zero;
bool default_nan_mode;
/*
+ * The pattern to use for the default NaN. Here the high bit specifies
+ * the default NaN's sign bit, and bits 6..0 specify the high bits of the
+ * fractional part. The low bits of the fractional part are copies of bit 0.
+ * The exponent of the default NaN is (as for any NaN) always all 1s.
+ * Note that a value of 0 here is not a valid NaN. The target must set
+ * this to the correct non-zero value, or we will assert when trying to
+ * create a default NaN.
+ */
+ uint8_t default_nan_pattern;
+ /*
* The flags below are not used on all specializations and may
* constant fold away (see snan_bit_is_one()/no_signalling_nans() in
* softfloat-specialize.inc.c)
*/
bool snan_bit_is_one;
- bool use_first_nan;
bool no_signaling_nans;
/* should overflowed results subtract re_bias to its exponent? */
bool rebias_overflow;
diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h
index 2d13290..83b2163 100644
--- a/include/hw/net/imx_fec.h
+++ b/include/hw/net/imx_fec.h
@@ -31,6 +31,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(IMXFECState, IMX_FEC)
#define TYPE_IMX_ENET "imx.enet"
#include "hw/sysbus.h"
+#include "hw/net/lan9118_phy.h"
+#include "hw/irq.h"
#include "net/net.h"
#define ENET_EIR 1
@@ -264,11 +266,8 @@ struct IMXFECState {
uint32_t tx_descriptor[ENET_TX_RING_NUM];
uint32_t tx_ring_num;
- uint32_t phy_status;
- uint32_t phy_control;
- uint32_t phy_advertise;
- uint32_t phy_int;
- uint32_t phy_int_mask;
+ Lan9118PhyState mii;
+ IRQState mii_irq;
uint32_t phy_num;
bool phy_connected;
struct IMXFECState *phy_consumer;
diff --git a/include/hw/net/lan9118_phy.h b/include/hw/net/lan9118_phy.h
new file mode 100644
index 0000000..af12fc3
--- /dev/null
+++ b/include/hw/net/lan9118_phy.h
@@ -0,0 +1,37 @@
+/*
+ * SMSC LAN9118 PHY emulation
+ *
+ * Copyright (c) 2009 CodeSourcery, LLC.
+ * Written by Paul Brook
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef HW_NET_LAN9118_PHY_H
+#define HW_NET_LAN9118_PHY_H
+
+#include "qom/object.h"
+#include "hw/sysbus.h"
+
+#define TYPE_LAN9118_PHY "lan9118-phy"
+OBJECT_DECLARE_SIMPLE_TYPE(Lan9118PhyState, LAN9118_PHY)
+
+typedef struct Lan9118PhyState {
+ SysBusDevice parent_obj;
+
+ uint16_t status;
+ uint16_t control;
+ uint16_t advertise;
+ uint16_t ints;
+ uint16_t int_mask;
+ qemu_irq irq;
+ bool link_down;
+} Lan9118PhyState;
+
+void lan9118_phy_update_link(Lan9118PhyState *s, bool link_down);
+void lan9118_phy_reset(Lan9118PhyState *s);
+uint16_t lan9118_phy_read(Lan9118PhyState *s, int reg);
+void lan9118_phy_write(Lan9118PhyState *s, int reg, uint16_t val);
+
+#endif
diff --git a/include/hw/net/mii.h b/include/hw/net/mii.h
index f7feddac..55bf7c9 100644
--- a/include/hw/net/mii.h
+++ b/include/hw/net/mii.h
@@ -71,6 +71,7 @@
#define MII_BMSR_JABBER (1 << 1) /* Jabber detected */
#define MII_BMSR_EXTCAP (1 << 0) /* Ext-reg capability */
+#define MII_ANAR_RFAULT (1 << 13) /* Say we can detect faults */
#define MII_ANAR_PAUSE_ASYM (1 << 11) /* Try for asymmetric pause */
#define MII_ANAR_PAUSE (1 << 10) /* Try for pause */
#define MII_ANAR_TXFD (1 << 8)
@@ -78,6 +79,7 @@
#define MII_ANAR_10FD (1 << 6)
#define MII_ANAR_10 (1 << 5)
#define MII_ANAR_CSMACD (1 << 0)
+#define MII_ANAR_SELECT (0x001f) /* Selector bits */
#define MII_ANLPAR_ACK (1 << 14)
#define MII_ANLPAR_PAUSEASY (1 << 11) /* can pause asymmetrically */
@@ -112,6 +114,10 @@
#define RTL8201CP_PHYID1 0x0000
#define RTL8201CP_PHYID2 0x8201
+/* SMSC LAN9118 */
+#define SMSCLAN9118_PHYID1 0x0007
+#define SMSCLAN9118_PHYID2 0xc0d1
+
/* RealTek 8211E */
#define RTL8211E_PHYID1 0x001c
#define RTL8211E_PHYID2 0xc915
diff --git a/linux-user/arm/nwfpe/fpa11.c b/linux-user/arm/nwfpe/fpa11.c
index 8356beb..0f1afbd 100644
--- a/linux-user/arm/nwfpe/fpa11.c
+++ b/linux-user/arm/nwfpe/fpa11.c
@@ -69,6 +69,11 @@ void resetFPA11(void)
* this late date.
*/
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &fpa11->fp_status);
+ /*
+ * Use the same default NaN value as Arm VFP. This doesn't match
+ * the Linux kernel's nwfpe emulation, which uses an all-1s value.
+ */
+ set_float_default_nan_pattern(0b01000000, &fpa11->fp_status);
}
void SetRoundingMode(const unsigned int opcode)
diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c
index 5d75c94..70f67e6 100644
--- a/target/alpha/cpu.c
+++ b/target/alpha/cpu.c
@@ -199,6 +199,8 @@ static void alpha_cpu_initfn(Object *obj)
* operand in Fa. That is float_2nan_prop_ba.
*/
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status);
+ /* Default NaN: sign bit clear, msb frac bit set */
+ set_float_default_nan_pattern(0b01000000, &env->fp_status);
#if defined(CONFIG_USER_ONLY)
env->flags = ENV_FLAG_PS_USER | ENV_FLAG_FEN;
cpu_alpha_store_fpcr(env, (uint64_t)(FPCR_INVD | FPCR_DZED | FPCR_OVFD
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 6938161..4f7e18e 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -173,11 +173,21 @@ void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook,
* * 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_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)
diff --git a/target/arm/tcg/vec_helper.c b/target/arm/tcg/vec_helper.c
index e825d50..ad6f265 100644
--- a/target/arm/tcg/vec_helper.c
+++ b/target/arm/tcg/vec_helper.c
@@ -2813,25 +2813,19 @@ bool is_ebf(CPUARMState *env, float_status *statusp, float_status *oddstatusp)
* no effect on AArch32 instructions.
*/
bool ebf = is_a64(env) && env->vfp.fpcr & FPCR_EBF;
- *statusp = (float_status){
- .tininess_before_rounding = float_tininess_before_rounding,
- .float_rounding_mode = float_round_to_odd_inf,
- .flush_to_zero = true,
- .flush_inputs_to_zero = true,
- .default_nan_mode = true,
- };
- if (ebf) {
- float_status *fpst = &env->vfp.fp_status;
- set_flush_to_zero(get_flush_to_zero(fpst), statusp);
- set_flush_inputs_to_zero(get_flush_inputs_to_zero(fpst), statusp);
- set_float_rounding_mode(get_float_rounding_mode(fpst), statusp);
+ *statusp = env->vfp.fp_status;
+ set_default_nan_mode(true, statusp);
+ if (ebf) {
/* EBF=1 needs to do a step with round-to-odd semantics */
*oddstatusp = *statusp;
set_float_rounding_mode(float_round_to_odd, oddstatusp);
+ } else {
+ set_flush_to_zero(true, statusp);
+ set_flush_inputs_to_zero(true, statusp);
+ set_float_rounding_mode(float_round_to_odd_inf, statusp);
}
-
return ebf;
}
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 020038f..c9aa940 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -286,6 +286,8 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type)
set_default_nan_mode(1, &env->fp_status);
set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status);
+ /* Default NaN value: sign bit set, all frac bits set */
+ set_float_default_nan_pattern(0b11111111, &env->fp_status);
}
static void hexagon_cpu_disas_set_info(CPUState *s, disassemble_info *info)
diff --git a/target/hppa/fpu_helper.c b/target/hppa/fpu_helper.c
index 0e44074..239c027 100644
--- a/target/hppa/fpu_helper.c
+++ b/target/hppa/fpu_helper.c
@@ -55,6 +55,18 @@ void HELPER(loaded_fr0)(CPUHPPAState *env)
* HPPA does note implement a CPU reset method at all...
*/
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fp_status);
+ /*
+ * TODO: The HPPA architecture reference only documents its NaN
+ * propagation rule for 2-operand operations. Testing on real hardware
+ * might be necessary to confirm whether this order for muladd is correct.
+ * Not preferring the SNaN is almost certainly incorrect as it diverges
+ * from the documented rules for 2-operand operations.
+ */
+ set_float_3nan_prop_rule(float_3nan_prop_abc, &env->fp_status);
+ /* For inf * 0 + NaN, return the input NaN */
+ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
+ /* Default NaN: sign bit clear, msb-1 frac bit set */
+ set_float_default_nan_pattern(0b00100000, &env->fp_status);
}
void cpu_hppa_loaded_fr0(CPUHPPAState *env)
diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c
index 53b49bb..d0a1e2f 100644
--- a/target/i386/tcg/fpu_helper.c
+++ b/target/i386/tcg/fpu_helper.c
@@ -173,6 +173,18 @@ void cpu_init_fp_statuses(CPUX86State *env)
*/
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->mmx_status);
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->sse_status);
+ /*
+ * Only SSE has multiply-add instructions. In the SDM Section 14.5.2
+ * "Fused-Multiply-ADD (FMA) Numeric Behavior" the NaN handling is
+ * specified -- for 0 * inf + NaN the input NaN is selected, and if
+ * there are multiple input NaNs they are selected in the order a, b, c.
+ */
+ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->sse_status);
+ set_float_3nan_prop_rule(float_3nan_prop_abc, &env->sse_status);
+ /* Default NaN: sign bit set, most significant frac bit set */
+ set_float_default_nan_pattern(0b11000000, &env->fp_status);
+ set_float_default_nan_pattern(0b11000000, &env->mmx_status);
+ set_float_default_nan_pattern(0b11000000, &env->sse_status);
}
static inline uint8_t save_exception_flags(CPUX86State *env)
diff --git a/target/loongarch/tcg/fpu_helper.c b/target/loongarch/tcg/fpu_helper.c
index 21bc3b0..a83acf6 100644
--- a/target/loongarch/tcg/fpu_helper.c
+++ b/target/loongarch/tcg/fpu_helper.c
@@ -32,6 +32,14 @@ void restore_fp_status(CPULoongArchState *env)
&env->fp_status);
set_flush_to_zero(0, &env->fp_status);
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fp_status);
+ /*
+ * For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan)
+ * case sets InvalidOp and returns the input value 'c'
+ */
+ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
+ set_float_3nan_prop_rule(float_3nan_prop_s_cab, &env->fp_status);
+ /* Default NaN: sign bit clear, msb frac bit set */
+ set_float_default_nan_pattern(0b01000000, &env->fp_status);
}
int ieee_ex_to_loongarch(int xcpt)
@@ -353,8 +361,7 @@ uint64_t helper_fclass_s(CPULoongArchState *env, uint64_t fj)
} else if (float32_is_zero_or_denormal(f)) {
return sign ? 1 << 4 : 1 << 8;
} else if (float32_is_any_nan(f)) {
- float_status s = { }; /* for snan_bit_is_one */
- return float32_is_quiet_nan(f, &s) ? 1 << 1 : 1 << 0;
+ return float32_is_quiet_nan(f, &env->fp_status) ? 1 << 1 : 1 << 0;
} else {
return sign ? 1 << 3 : 1 << 7;
}
@@ -372,8 +379,7 @@ uint64_t helper_fclass_d(CPULoongArchState *env, uint64_t fj)
} else if (float64_is_zero_or_denormal(f)) {
return sign ? 1 << 4 : 1 << 8;
} else if (float64_is_any_nan(f)) {
- float_status s = { }; /* for snan_bit_is_one */
- return float64_is_quiet_nan(f, &s) ? 1 << 1 : 1 << 0;
+ return float64_is_quiet_nan(f, &env->fp_status) ? 1 << 1 : 1 << 0;
} else {
return sign ? 1 << 3 : 1 << 7;
}
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
index 5fe3355..9de8ce6 100644
--- a/target/m68k/cpu.c
+++ b/target/m68k/cpu.c
@@ -76,7 +76,7 @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type)
CPUState *cs = CPU(obj);
M68kCPUClass *mcc = M68K_CPU_GET_CLASS(obj);
CPUM68KState *env = cpu_env(cs);
- floatx80 nan = floatx80_default_nan(NULL);
+ floatx80 nan;
int i;
if (mcc->parent_phases.hold) {
@@ -89,10 +89,6 @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type)
#else
cpu_m68k_set_sr(env, SR_S | SR_I);
#endif
- for (i = 0; i < 8; i++) {
- env->fregs[i].d = nan;
- }
- cpu_m68k_set_fpcr(env, 0);
/*
* M68000 FAMILY PROGRAMMER'S REFERENCE MANUAL
* 3.4 FLOATING-POINT INSTRUCTION DETAILS
@@ -109,6 +105,14 @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type)
* preceding paragraph for nonsignaling NaNs.
*/
set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status);
+ /* Default NaN: sign bit clear, all frac bits set */
+ set_float_default_nan_pattern(0b01111111, &env->fp_status);
+
+ nan = floatx80_default_nan(&env->fp_status);
+ for (i = 0; i < 8; i++) {
+ env->fregs[i].d = nan;
+ }
+ cpu_m68k_set_fpcr(env, 0);
env->fpsr = 0;
/* TODO: We should set PC from the interrupt vector. */
diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
index a605162..e3f4a18 100644
--- a/target/m68k/fpu_helper.c
+++ b/target/m68k/fpu_helper.c
@@ -615,15 +615,13 @@ void HELPER(frem)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1)
fp_rem = floatx80_rem(val1->d, val0->d, &env->fp_status);
if (!floatx80_is_any_nan(fp_rem)) {
- float_status fp_status = { };
+ /* Use local temporary fp_status to set different rounding mode */
+ float_status fp_status = env->fp_status;
uint32_t quotient;
int sign;
/* Calculate quotient directly using round to nearest mode */
- set_float_2nan_prop_rule(float_2nan_prop_ab, &fp_status);
set_float_rounding_mode(float_round_nearest_even, &fp_status);
- set_floatx80_rounding_precision(
- get_floatx80_rounding_precision(&env->fp_status), &fp_status);
fp_quot.d = floatx80_div(val1->d, val0->d, &fp_status);
sign = extractFloatx80Sign(fp_quot.d);
diff --git a/target/m68k/helper.c b/target/m68k/helper.c
index 9bfc6ae..beefeb7 100644
--- a/target/m68k/helper.c
+++ b/target/m68k/helper.c
@@ -36,7 +36,8 @@ static int cf_fpu_gdb_get_reg(CPUState *cs, GByteArray *mem_buf, int n)
CPUM68KState *env = &cpu->env;
if (n < 8) {
- float_status s = {};
+ /* Use scratch float_status so any exceptions don't change CPU state */
+ float_status s = env->fp_status;
return gdb_get_reg64(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
}
switch (n) {
@@ -56,7 +57,8 @@ static int cf_fpu_gdb_set_reg(CPUState *cs, uint8_t *mem_buf, int n)
CPUM68KState *env = &cpu->env;
if (n < 8) {
- float_status s = {};
+ /* Use scratch float_status so any exceptions don't change CPU state */
+ float_status s = env->fp_status;
env->fregs[n].d = float64_to_floatx80(ldq_be_p(mem_buf), &s);
return 8;
}
diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c
index 710eb11..0e1e22d 100644
--- a/target/microblaze/cpu.c
+++ b/target/microblaze/cpu.c
@@ -207,6 +207,8 @@ static void mb_cpu_reset_hold(Object *obj, ResetType type)
* this architecture.
*/
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status);
+ /* Default NaN: sign bit set, most significant frac bit set */
+ set_float_default_nan_pattern(0b11000000, &env->fp_status);
#if defined(CONFIG_USER_ONLY)
/* start in user mode with interrupts enabled. */
diff --git a/target/mips/fpu_helper.h b/target/mips/fpu_helper.h
index 7c3c789..6ad1e46 100644
--- a/target/mips/fpu_helper.h
+++ b/target/mips/fpu_helper.h
@@ -28,6 +28,8 @@ static inline void restore_flush_mode(CPUMIPSState *env)
static inline void restore_snan_bit_mode(CPUMIPSState *env)
{
bool nan2008 = env->active_fpu.fcr31 & (1 << FCR31_NAN2008);
+ FloatInfZeroNaNRule izn_rule;
+ Float3NaNPropRule nan3_rule;
/*
* With nan2008, SNaNs are silenced in the usual way.
@@ -35,6 +37,24 @@ static inline void restore_snan_bit_mode(CPUMIPSState *env)
*/
set_snan_bit_is_one(!nan2008, &env->active_fpu.fp_status);
set_default_nan_mode(!nan2008, &env->active_fpu.fp_status);
+ /*
+ * For MIPS systems that conform to IEEE754-1985, the (inf,zero,nan)
+ * case sets InvalidOp and returns the default NaN.
+ * For MIPS systems that conform to IEEE754-2008, the (inf,zero,nan)
+ * case sets InvalidOp and returns the input value 'c'.
+ */
+ izn_rule = nan2008 ? float_infzeronan_dnan_never : float_infzeronan_dnan_always;
+ set_float_infzeronan_rule(izn_rule, &env->active_fpu.fp_status);
+ nan3_rule = nan2008 ? float_3nan_prop_s_cab : float_3nan_prop_s_abc;
+ set_float_3nan_prop_rule(nan3_rule, &env->active_fpu.fp_status);
+ /*
+ * With nan2008, the default NaN value has the sign bit clear and the
+ * frac msb set; with the older mode, the sign bit is clear, and all
+ * frac bits except the msb are set.
+ */
+ set_float_default_nan_pattern(nan2008 ? 0b01000000 : 0b00111111,
+ &env->active_fpu.fp_status);
+
}
static inline void restore_fp_status(CPUMIPSState *env)
diff --git a/target/mips/msa.c b/target/mips/msa.c
index 9dffc42..fc77bfc 100644
--- a/target/mips/msa.c
+++ b/target/mips/msa.c
@@ -66,6 +66,9 @@ void msa_reset(CPUMIPSState *env)
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);
@@ -74,4 +77,11 @@ void msa_reset(CPUMIPSState *env)
/* 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);
}
diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c
index b96561d..3ccf85e 100644
--- a/target/openrisc/cpu.c
+++ b/target/openrisc/cpu.c
@@ -111,6 +111,8 @@ static void openrisc_cpu_reset_hold(Object *obj, ResetType type)
*/
set_float_2nan_prop_rule(float_2nan_prop_x87, &cpu->env.fp_status);
+ /* Default NaN: sign bit clear, frac msb set */
+ set_float_default_nan_pattern(0b01000000, &cpu->env.fp_status);
#ifndef CONFIG_USER_ONLY
cpu->env.picmr = 0x00000000;
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index efcb80d..1253dbf 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -7270,6 +7270,25 @@ static void ppc_cpu_reset_hold(Object *obj, ResetType type)
*/
set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status);
set_float_2nan_prop_rule(float_2nan_prop_ab, &env->vec_status);
+ /*
+ * NaN propagation for fused multiply-add:
+ * if fRA is a NaN return it; otherwise if fRB is a NaN return it;
+ * otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB
+ * whereas QEMU labels the operands as (a * b) + c.
+ */
+ set_float_3nan_prop_rule(float_3nan_prop_acb, &env->fp_status);
+ set_float_3nan_prop_rule(float_3nan_prop_acb, &env->vec_status);
+ /*
+ * For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer
+ * to return an input NaN if we have one (ie c) rather than generating
+ * a default NaN
+ */
+ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
+ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->vec_status);
+
+ /* Default NaN: sign bit clear, set frac msb */
+ set_float_default_nan_pattern(0b01000000, &env->fp_status);
+ set_float_default_nan_pattern(0b01000000, &env->vec_status);
for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) {
ppc_spr_t *spr = &env->spr_cb[i];
diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c
index 230466a..d93cfed 100644
--- a/target/ppc/fpu_helper.c
+++ b/target/ppc/fpu_helper.c
@@ -155,8 +155,7 @@ void helper_compute_fprf_##tp(CPUPPCState *env, tp arg) \
} else if (tp##_is_infinity(arg)) { \
fprf = neg ? 0x09 << FPSCR_FPRF : 0x05 << FPSCR_FPRF; \
} else { \
- float_status dummy = { }; /* snan_bit_is_one = 0 */ \
- if (tp##_is_signaling_nan(arg, &dummy)) { \
+ if (tp##_is_signaling_nan(arg, &env->fp_status)) { \
fprf = 0x00 << FPSCR_FPRF; \
} else { \
fprf = 0x11 << FPSCR_FPRF; \
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index f219f0c..80b0995 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1022,6 +1022,8 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type)
cs->exception_index = RISCV_EXCP_NONE;
env->load_res = -1;
set_default_nan_mode(1, &env->fp_status);
+ /* Default NaN value: sign bit clear, frac msb set */
+ set_float_default_nan_pattern(0b01000000, &env->fp_status);
env->vill = true;
#ifndef CONFIG_USER_ONLY
diff --git a/target/rx/cpu.c b/target/rx/cpu.c
index 65a74ce..69ec0bc 100644
--- a/target/rx/cpu.c
+++ b/target/rx/cpu.c
@@ -100,6 +100,8 @@ static void rx_cpu_reset_hold(Object *obj, ResetType type)
* then prefer dest over source", which is float_2nan_prop_s_ab.
*/
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status);
+ /* Default NaN value: sign bit clear, set frac msb */
+ set_float_default_nan_pattern(0b01000000, &env->fp_status);
}
static ObjectClass *rx_cpu_class_by_name(const char *cpu_model)
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
index 514c70f..adb2750 100644
--- a/target/s390x/cpu.c
+++ b/target/s390x/cpu.c
@@ -206,6 +206,11 @@ static void s390_cpu_reset_hold(Object *obj, ResetType type)
set_float_detect_tininess(float_tininess_before_rounding,
&env->fpu_status);
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fpu_status);
+ set_float_3nan_prop_rule(float_3nan_prop_s_abc, &env->fpu_status);
+ set_float_infzeronan_rule(float_infzeronan_dnan_always,
+ &env->fpu_status);
+ /* Default NaN value: sign bit clear, frac msb set */
+ set_float_default_nan_pattern(0b01000000, &env->fpu_status);
/* fall through */
case RESET_TYPE_S390_CPU_NORMAL:
env->psw.mask &= ~PSW_MASK_RI;
diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c
index 8f07261..d5008859 100644
--- a/target/sh4/cpu.c
+++ b/target/sh4/cpu.c
@@ -127,6 +127,8 @@ static void superh_cpu_reset_hold(Object *obj, ResetType type)
set_flush_to_zero(1, &env->fp_status);
#endif
set_default_nan_mode(1, &env->fp_status);
+ /* sign bit clear, set all frac bits other than msb */
+ set_float_default_nan_pattern(0b00111111, &env->fp_status);
}
static void superh_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c
index dd7af86..6b66ecb 100644
--- a/target/sparc/cpu.c
+++ b/target/sparc/cpu.c
@@ -814,6 +814,12 @@ static void sparc_cpu_realizefn(DeviceState *dev, Error **errp)
* the CPU state struct so it won't get zeroed on reset.
*/
set_float_2nan_prop_rule(float_2nan_prop_s_ba, &env->fp_status);
+ /* For fused-multiply add, prefer SNaN over QNaN, then C->B->A */
+ set_float_3nan_prop_rule(float_3nan_prop_s_cba, &env->fp_status);
+ /* For inf * 0 + NaN, return the input NaN */
+ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
+ /* Default NaN value: sign bit clear, all frac bits set */
+ set_float_default_nan_pattern(0b01111111, &env->fp_status);
cpu_exec_realizefn(cs, &local_err);
if (local_err != NULL) {
diff --git a/target/sparc/fop_helper.c b/target/sparc/fop_helper.c
index 6f9ccc0..236d27b 100644
--- a/target/sparc/fop_helper.c
+++ b/target/sparc/fop_helper.c
@@ -490,13 +490,13 @@ uint32_t helper_fcmpeq(CPUSPARCState *env, Int128 src1, Int128 src2)
return finish_fcmp(env, r, GETPC());
}
-uint32_t helper_flcmps(float32 src1, float32 src2)
+uint32_t helper_flcmps(CPUSPARCState *env, float32 src1, float32 src2)
{
/*
* FLCMP never raises an exception nor modifies any FSR fields.
* Perform the comparison with a dummy fp environment.
*/
- float_status discard = { };
+ float_status discard = env->fp_status;
FloatRelation r;
set_float_2nan_prop_rule(float_2nan_prop_s_ba, &discard);
@@ -518,9 +518,9 @@ uint32_t helper_flcmps(float32 src1, float32 src2)
g_assert_not_reached();
}
-uint32_t helper_flcmpd(float64 src1, float64 src2)
+uint32_t helper_flcmpd(CPUSPARCState *env, float64 src1, float64 src2)
{
- float_status discard = { };
+ float_status discard = env->fp_status;
FloatRelation r;
set_float_2nan_prop_rule(float_2nan_prop_s_ba, &discard);
diff --git a/target/sparc/helper.h b/target/sparc/helper.h
index 134e519..1ae3f0c 100644
--- a/target/sparc/helper.h
+++ b/target/sparc/helper.h
@@ -51,8 +51,8 @@ DEF_HELPER_FLAGS_3(fcmpd, TCG_CALL_NO_WG, i32, env, f64, f64)
DEF_HELPER_FLAGS_3(fcmped, TCG_CALL_NO_WG, i32, env, f64, f64)
DEF_HELPER_FLAGS_3(fcmpq, TCG_CALL_NO_WG, i32, env, i128, i128)
DEF_HELPER_FLAGS_3(fcmpeq, TCG_CALL_NO_WG, i32, env, i128, i128)
-DEF_HELPER_FLAGS_2(flcmps, TCG_CALL_NO_RWG_SE, i32, f32, f32)
-DEF_HELPER_FLAGS_2(flcmpd, TCG_CALL_NO_RWG_SE, i32, f64, f64)
+DEF_HELPER_FLAGS_3(flcmps, TCG_CALL_NO_RWG_SE, i32, env, f32, f32)
+DEF_HELPER_FLAGS_3(flcmpd, TCG_CALL_NO_RWG_SE, i32, env, f64, f64)
DEF_HELPER_2(raise_exception, noreturn, env, int)
DEF_HELPER_FLAGS_3(faddd, TCG_CALL_NO_WG, f64, env, f64, f64)
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index cdd0a95..322319a 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -5584,7 +5584,7 @@ static bool trans_FLCMPs(DisasContext *dc, arg_FLCMPs *a)
src1 = gen_load_fpr_F(dc, a->rs1);
src2 = gen_load_fpr_F(dc, a->rs2);
- gen_helper_flcmps(cpu_fcc[a->cc], src1, src2);
+ gen_helper_flcmps(cpu_fcc[a->cc], tcg_env, src1, src2);
return advance_pc(dc);
}
@@ -5601,7 +5601,7 @@ static bool trans_FLCMPd(DisasContext *dc, arg_FLCMPd *a)
src1 = gen_load_fpr_D(dc, a->rs1);
src2 = gen_load_fpr_D(dc, a->rs2);
- gen_helper_flcmpd(cpu_fcc[a->cc], src1, src2);
+ gen_helper_flcmpd(cpu_fcc[a->cc], tcg_env, src1, src2);
return advance_pc(dc);
}
diff --git a/target/tricore/helper.c b/target/tricore/helper.c
index 7014255..e8b0ec5 100644
--- a/target/tricore/helper.c
+++ b/target/tricore/helper.c
@@ -117,6 +117,8 @@ void fpu_set_state(CPUTriCoreState *env)
set_flush_to_zero(1, &env->fp_status);
set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status);
set_default_nan_mode(1, &env->fp_status);
+ /* Default NaN pattern: sign bit clear, frac msb set */
+ set_float_default_nan_pattern(0b01000000, &env->fp_status);
}
uint32_t psw_read(CPUTriCoreState *env)
diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c
index 6f9039a..0d4d79b 100644
--- a/target/xtensa/cpu.c
+++ b/target/xtensa/cpu.c
@@ -133,7 +133,11 @@ static void xtensa_cpu_reset_hold(Object *obj, ResetType type)
reset_mmu(env);
cs->halted = env->runstall;
#endif
+ /* For inf * 0 + NaN, return the input NaN */
+ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
set_no_signaling_nans(!dfpu, &env->fp_status);
+ /* Default NaN value: sign bit clear, set frac msb */
+ set_float_default_nan_pattern(0b01000000, &env->fp_status);
xtensa_use_first_nan(env, !dfpu);
}
diff --git a/target/xtensa/fpu_helper.c b/target/xtensa/fpu_helper.c
index f2d212d..53fc7cf 100644
--- a/target/xtensa/fpu_helper.c
+++ b/target/xtensa/fpu_helper.c
@@ -59,9 +59,10 @@ static const struct {
void xtensa_use_first_nan(CPUXtensaState *env, bool use_first)
{
- set_use_first_nan(use_first, &env->fp_status);
set_float_2nan_prop_rule(use_first ? float_2nan_prop_ab : float_2nan_prop_ba,
&env->fp_status);
+ set_float_3nan_prop_rule(use_first ? float_3nan_prop_abc : float_3nan_prop_cba,
+ &env->fp_status);
}
void HELPER(wur_fpu2k_fcr)(CPUXtensaState *env, uint32_t v)
diff --git a/tests/fp/fp-bench.c b/tests/fp/fp-bench.c
index 75c07d5..eacb39b 100644
--- a/tests/fp/fp-bench.c
+++ b/tests/fp/fp-bench.c
@@ -488,7 +488,14 @@ static void run_bench(void)
{
bench_func_t f;
+ /*
+ * These implementation-defined choices for various things IEEE
+ * doesn't specify match those used by the Arm architecture.
+ */
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &soft_status);
+ set_float_3nan_prop_rule(float_3nan_prop_s_cab, &soft_status);
+ set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, &soft_status);
+ set_float_default_nan_pattern(0b01000000, &soft_status);
f = bench_funcs[operation][precision];
g_assert(f);
diff --git a/tests/fp/fp-test-log2.c b/tests/fp/fp-test-log2.c
index de702c4..79f619c 100644
--- a/tests/fp/fp-test-log2.c
+++ b/tests/fp/fp-test-log2.c
@@ -71,6 +71,7 @@ int main(int ac, char **av)
int i;
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf);
+ set_float_default_nan_pattern(0b01000000, &qsf);
set_float_rounding_mode(float_round_nearest_even, &qsf);
test.d = 0.0;
diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c
index 5f6f25c..c619e5d 100644
--- a/tests/fp/fp-test.c
+++ b/tests/fp/fp-test.c
@@ -935,7 +935,14 @@ void run_test(void)
{
unsigned int i;
+ /*
+ * These implementation-defined choices for various things IEEE
+ * doesn't specify match those used by the Arm architecture.
+ */
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf);
+ set_float_3nan_prop_rule(float_3nan_prop_s_cab, &qsf);
+ set_float_default_nan_pattern(0b01000000, &qsf);
+ set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, &qsf);
genCases_setLevel(test_level);
verCases_maxErrorCount = n_max_errors;