target-arm queue:

* hw/net/lan9118: Extract PHY model, reuse with imx_fec, fix bugs
  * fpu: Make muladd NaN handling runtime-selected, not compile-time
  * fpu: Make default NaN pattern runtime-selected, not compile-time
  * fpu: Minor NaN-related cleanups
  * MAINTAINERS: email address updates
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmdZu14ZHHBldGVyLm1h
 eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3mgiD/98Q+m7/t54FdCd2bx1cr2k
 dw+7DYhp+60Vo3OjlGtKWwPD67oN8e0jhOoArmJNW0Fmkcsvfvd4wv6kCf8zftLm
 0/lPO687mvFNCAprTch+z2pGB7aS0HdIr126ytsyg5PlHtldd+OBA+yUUYafR3zo
 BECRSWZmMFxfl9uckJzntdntghTX5pnJDSGBYE9NEyRfo0Ntj1HvhaHSQJkqpf5B
 QwE8R965CXc4i34PqlOCju47AXwJc3x36ftdiNmpPvMS4odG9yb/OmhHSgVZlThb
 1x0HEX69KF5FQbtVNDMmFyYehDzqYFpqOSa1IKtaNLmDSZJ5P8fWw4eBdMdr/QyD
 QKssgHAO6Z13MLppK4B1PFtSVlsLYUURYddYUFz4RUNOxrS/pzAIT0KhClYFytQo
 x9xid4fng1PY9doYEM3v4vEQCU6S+2aj2gU4EOwdB8GmMhtjSl8YlcEs7cysqkoQ
 gbGX97i6Eh616q9VsRzUwcY6u4XP/lssn6I98k4AEqgRpyFCMTLyFodV89d6J4EJ
 IJKsJf10gctpe1JdMgtDxuleKOZc+O5nOMJLKYwc9siakCBZsH7zmgS6m8QVoUSD
 7R+4OtbaQwM0+GPbc0AhAlDtq3Q1QAtCYa94iICUixC4NjzfdC9B9yCz1XnA7sfS
 jPHU8INw6rz3psEnlFQdhA==
 =+ELh
 -----END PGP SIGNATURE-----

Merge tag 'pull-target-arm-20241211' of https://git.linaro.org/people/pmaydell/qemu-arm into staging

target-arm queue:
 * hw/net/lan9118: Extract PHY model, reuse with imx_fec, fix bugs
 * fpu: Make muladd NaN handling runtime-selected, not compile-time
 * fpu: Make default NaN pattern runtime-selected, not compile-time
 * fpu: Minor NaN-related cleanups
 * MAINTAINERS: email address updates

# -----BEGIN PGP SIGNATURE-----
#
# iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmdZu14ZHHBldGVyLm1h
# eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3mgiD/98Q+m7/t54FdCd2bx1cr2k
# dw+7DYhp+60Vo3OjlGtKWwPD67oN8e0jhOoArmJNW0Fmkcsvfvd4wv6kCf8zftLm
# 0/lPO687mvFNCAprTch+z2pGB7aS0HdIr126ytsyg5PlHtldd+OBA+yUUYafR3zo
# BECRSWZmMFxfl9uckJzntdntghTX5pnJDSGBYE9NEyRfo0Ntj1HvhaHSQJkqpf5B
# QwE8R965CXc4i34PqlOCju47AXwJc3x36ftdiNmpPvMS4odG9yb/OmhHSgVZlThb
# 1x0HEX69KF5FQbtVNDMmFyYehDzqYFpqOSa1IKtaNLmDSZJ5P8fWw4eBdMdr/QyD
# QKssgHAO6Z13MLppK4B1PFtSVlsLYUURYddYUFz4RUNOxrS/pzAIT0KhClYFytQo
# x9xid4fng1PY9doYEM3v4vEQCU6S+2aj2gU4EOwdB8GmMhtjSl8YlcEs7cysqkoQ
# gbGX97i6Eh616q9VsRzUwcY6u4XP/lssn6I98k4AEqgRpyFCMTLyFodV89d6J4EJ
# IJKsJf10gctpe1JdMgtDxuleKOZc+O5nOMJLKYwc9siakCBZsH7zmgS6m8QVoUSD
# 7R+4OtbaQwM0+GPbc0AhAlDtq3Q1QAtCYa94iICUixC4NjzfdC9B9yCz1XnA7sfS
# jPHU8INw6rz3psEnlFQdhA==
# =+ELh
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed 11 Dec 2024 11:18:38 EST
# gpg:                using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg:                issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [full]
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>" [full]
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [full]
# gpg:                 aka "Peter Maydell <peter@archaic.org.uk>" [unknown]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* tag 'pull-target-arm-20241211' of https://git.linaro.org/people/pmaydell/qemu-arm: (72 commits)
  MAINTAINERS: Add correct email address for Vikram Garhwal
  MAINTAINERS: update email address for Leif Lindholm
  softfloat: Replace WHICH with RET in parts_pick_nan
  softfloat: Sink frac_cmp in parts_pick_nan until needed
  softfloat: Share code between parts_pick_nan cases
  softfloat: Inline pickNaN
  softfloat: Use parts_pick_nan in propagateFloatx80NaN
  softfloat: Move propagateFloatx80NaN to softfloat.c
  softfloat: Pad array size in pick_nan_muladd
  softfloat: Remove which from parts_pick_nan_muladd
  softfloat: Use goto for default nan case in pick_nan_muladd
  softfloat: Inline pickNaNMulAdd
  fpu: Remove default handling for dnan_pattern
  target/tricore: Set default NaN pattern explicitly
  target/riscv: Set default NaN pattern explicitly
  target/hexagon: Set default NaN pattern explicitly
  target/xtensa: Set default NaN pattern explicitly
  target/sparc: Set default NaN pattern explicitly
  target/s390x: Set default NaN pattern explicitly
  target/rx: Set default NaN pattern explicitly
  ...

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2024-12-12 18:40:08 -05:00
commit 2a1823456c
47 changed files with 778 additions and 730 deletions

View File

@ -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>

View File

@ -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/*

View File

@ -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);
return a;
}
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)) {
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 {
int cmp = frac_cmp(a, b);
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();
}
if (pickNaN(a->cls, b->cls, cmp > 0, s)) {
a = b;
if (is_snan(ret->cls)) {
parts_silence_nan(ret, s);
}
if (is_snan(a->cls)) {
parts_silence_nan(a, s);
}
}
return a;
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 (s->default_nan_mode || which == 3) {
/*
* Note that this check is after pickNaNMulAdd so that function
* has an opportunity to set the Invalid flag for infzero.
*/
parts_default_nan(a, s);
return a;
if (infzero) {
/* This is (0 * inf) + NaN or (inf * 0) + NaN */
float_raise(float_flag_invalid | float_flag_invalid_imz, s);
}
switch (which) {
case 0:
if (s->default_nan_mode) {
/*
* 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.
*/
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 1:
a = b;
break;
case 2:
a = c;
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();
}
if (is_snan(a->cls)) {
parts_silence_nan(a, s);
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));
}
}
if (is_snan(ret->cls)) {
parts_silence_nan(ret, s);
}
return ret;
default_nan:
parts_default_nan(a, s);
return a;
}

View File

@ -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;
}
@ -370,312 +352,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.
@ -779,58 +455,6 @@ floatx80 floatx80_silence_nan(floatx80 a, float_status *status)
return a;
}
/*----------------------------------------------------------------------------
| 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.

View File

@ -4920,6 +4920,25 @@ void normalizeFloatx80Subnormal(uint64_t aSig, int32_t *zExpPtr,
*zExpPtr = 1 - shiftCount;
}
/*----------------------------------------------------------------------------
| 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',

View File

@ -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

View File

@ -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)
static void imx_phy_update_irq(void *opaque, int n, int level)
{
imx_eth_update(s);
}
static void imx_phy_update_link(IMXFECState *s)
{
/* 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,

View File

@ -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);

222
hw/net/lan9118_phy.c Normal file
View File

@ -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)

View File

@ -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'))

View File

@ -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"

View File

@ -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;

View File

@ -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.
*/
@ -207,6 +209,80 @@ typedef enum __attribute__((__packed__)) {
float_2nan_prop_x87,
} 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
@ -219,19 +295,30 @@ 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;
/* should denormalised inputs go to zero and set the input_denormal flag? */
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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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,
};
*statusp = env->vfp.fp_status;
set_default_nan_mode(true, statusp);
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);
/* 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;
}

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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;
}

View File

@ -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. */

View File

@ -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);

View File

@ -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;
}

View File

@ -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. */

View File

@ -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)

View File

@ -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);
}

View File

@ -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;

View File

@ -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];

View File

@ -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; \

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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)

View File

@ -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) {

View File

@ -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);

View File

@ -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)

View File

@ -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);
}

View File

@ -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)

View File

@ -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);
}

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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;