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:
commit
2a1823456c
5
.mailmap
5
.mailmap
@ -87,8 +87,9 @@ Huacai Chen <chenhuacai@kernel.org> <chenhc@lemote.com>
|
|||||||
Huacai Chen <chenhuacai@kernel.org> <chenhuacai@loongson.cn>
|
Huacai Chen <chenhuacai@kernel.org> <chenhuacai@loongson.cn>
|
||||||
James Hogan <jhogan@kernel.org> <james.hogan@imgtec.com>
|
James Hogan <jhogan@kernel.org> <james.hogan@imgtec.com>
|
||||||
Juan Quintela <quintela@trasno.org> <quintela@redhat.com>
|
Juan Quintela <quintela@trasno.org> <quintela@redhat.com>
|
||||||
Leif Lindholm <quic_llindhol@quicinc.com> <leif.lindholm@linaro.org>
|
Leif Lindholm <leif.lindholm@oss.qualcomm.com> <quic_llindhol@quicinc.com>
|
||||||
Leif Lindholm <quic_llindhol@quicinc.com> <leif@nuviainc.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@git.antfield.fr>
|
||||||
Luc Michel <luc@lmichel.fr> <luc.michel@greensocs.com>
|
Luc Michel <luc@lmichel.fr> <luc.michel@greensocs.com>
|
||||||
Luc Michel <luc@lmichel.fr> <lmichel@kalray.eu>
|
Luc Michel <luc@lmichel.fr> <lmichel@kalray.eu>
|
||||||
|
@ -917,7 +917,7 @@ F: include/hw/ssi/imx_spi.h
|
|||||||
SBSA-REF
|
SBSA-REF
|
||||||
M: Radoslaw Biernacki <rad@semihalf.com>
|
M: Radoslaw Biernacki <rad@semihalf.com>
|
||||||
M: Peter Maydell <peter.maydell@linaro.org>
|
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>
|
R: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
|
||||||
L: qemu-arm@nongnu.org
|
L: qemu-arm@nongnu.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
@ -1918,6 +1918,7 @@ F: tests/qtest/fuzz-sb16-test.c
|
|||||||
|
|
||||||
Xilinx CAN
|
Xilinx CAN
|
||||||
M: Francisco Iglesias <francisco.iglesias@amd.com>
|
M: Francisco Iglesias <francisco.iglesias@amd.com>
|
||||||
|
M: Vikram Garhwal <vikram.garhwal@bytedance.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/net/can/xlnx-*
|
F: hw/net/can/xlnx-*
|
||||||
F: include/hw/net/xlnx-*
|
F: include/hw/net/xlnx-*
|
||||||
@ -2677,6 +2678,7 @@ F: include/hw/rx/
|
|||||||
CAN bus subsystem and hardware
|
CAN bus subsystem and hardware
|
||||||
M: Pavel Pisa <pisa@cmp.felk.cvut.cz>
|
M: Pavel Pisa <pisa@cmp.felk.cvut.cz>
|
||||||
M: Francisco Iglesias <francisco.iglesias@amd.com>
|
M: Francisco Iglesias <francisco.iglesias@amd.com>
|
||||||
|
M: Vikram Garhwal <vikram.garhwal@bytedance.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
W: https://canbus.pages.fel.cvut.cz/
|
W: https://canbus.pages.fel.cvut.cz/
|
||||||
F: net/can/*
|
F: net/can/*
|
||||||
|
@ -39,65 +39,151 @@ static void partsN(return_nan)(FloatPartsN *a, float_status *s)
|
|||||||
static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b,
|
static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b,
|
||||||
float_status *s)
|
float_status *s)
|
||||||
{
|
{
|
||||||
|
bool have_snan = false;
|
||||||
|
FloatPartsN *ret;
|
||||||
|
int cmp;
|
||||||
|
|
||||||
if (is_snan(a->cls) || is_snan(b->cls)) {
|
if (is_snan(a->cls) || is_snan(b->cls)) {
|
||||||
float_raise(float_flag_invalid | float_flag_invalid_snan, s);
|
float_raise(float_flag_invalid | float_flag_invalid_snan, s);
|
||||||
|
have_snan = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->default_nan_mode) {
|
if (s->default_nan_mode) {
|
||||||
parts_default_nan(a, s);
|
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 {
|
} else {
|
||||||
int cmp = frac_cmp(a, b);
|
ret = b;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cmp = frac_cmp(a, b);
|
||||||
if (cmp == 0) {
|
if (cmp == 0) {
|
||||||
cmp = a->sign < b->sign;
|
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)) {
|
if (is_snan(ret->cls)) {
|
||||||
a = b;
|
parts_silence_nan(ret, s);
|
||||||
}
|
}
|
||||||
if (is_snan(a->cls)) {
|
return ret;
|
||||||
parts_silence_nan(a, s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return a;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
|
static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
|
||||||
FloatPartsN *c, float_status *s,
|
FloatPartsN *c, float_status *s,
|
||||||
int ab_mask, int abc_mask)
|
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);
|
float_raise(float_flag_invalid | float_flag_invalid_snan, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
which = pickNaNMulAdd(a->cls, b->cls, c->cls,
|
if (infzero) {
|
||||||
ab_mask == float_cmask_infzero, s);
|
/* 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) {
|
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (which) {
|
if (s->default_nan_mode) {
|
||||||
case 0:
|
/*
|
||||||
|
* 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;
|
break;
|
||||||
case 1:
|
case float_infzeronan_dnan_always:
|
||||||
a = b;
|
goto default_nan;
|
||||||
break;
|
case float_infzeronan_dnan_if_qnan:
|
||||||
case 2:
|
if (is_qnan(c->cls)) {
|
||||||
a = c;
|
goto default_nan;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
if (is_snan(a->cls)) {
|
ret = c;
|
||||||
parts_silence_nan(a, s);
|
} 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;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,35 +133,17 @@ static void parts64_default_nan(FloatParts64 *p, float_status *status)
|
|||||||
{
|
{
|
||||||
bool sign = 0;
|
bool sign = 0;
|
||||||
uint64_t frac;
|
uint64_t frac;
|
||||||
|
uint8_t dnan_pattern = status->default_nan_pattern;
|
||||||
|
|
||||||
#if defined(TARGET_SPARC) || defined(TARGET_M68K)
|
assert(dnan_pattern != 0);
|
||||||
/* !snan_bit_is_one, set all bits */
|
|
||||||
frac = (1ULL << DECOMPOSED_BINARY_POINT) - 1;
|
sign = dnan_pattern >> 7;
|
||||||
#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
|
|
||||||
/*
|
/*
|
||||||
* This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V,
|
* Place default_nan_pattern [6:0] into bits [62:56],
|
||||||
* S390, SH4, TriCore, and Xtensa. Our other supported targets
|
* and replecate bit [0] down into [55:0]
|
||||||
* do not have floating-point.
|
|
||||||
*/
|
*/
|
||||||
if (snan_bit_is_one(status)) {
|
frac = deposit64(0, DECOMPOSED_BINARY_POINT - 7, 7, dnan_pattern);
|
||||||
/* set all bits other than msb */
|
frac = deposit64(frac, 0, DECOMPOSED_BINARY_POINT - 7, -(dnan_pattern & 1));
|
||||||
frac = (1ULL << (DECOMPOSED_BINARY_POINT - 1)) - 1;
|
|
||||||
} else {
|
|
||||||
/* set msb */
|
|
||||||
frac = 1ULL << (DECOMPOSED_BINARY_POINT - 1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
*p = (FloatParts64) {
|
*p = (FloatParts64) {
|
||||||
.cls = float_class_qnan,
|
.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 floatx80_default_nan(float_status *status)
|
||||||
{
|
{
|
||||||
floatx80 r;
|
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. */
|
r.high = 0x7FFF | (p64.sign << 15);
|
||||||
assert(!snan_bit_is_one(status));
|
r.low = (1ULL << DECOMPOSED_BINARY_POINT) | p64.frac;
|
||||||
#if defined(TARGET_M68K)
|
|
||||||
r.low = UINT64_C(0xFFFFFFFFFFFFFFFF);
|
|
||||||
r.high = 0x7FFF;
|
|
||||||
#else
|
|
||||||
/* X86 */
|
|
||||||
r.low = UINT64_C(0xC000000000000000);
|
|
||||||
r.high = 0xFFFF;
|
|
||||||
#endif
|
|
||||||
return r;
|
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
|
| Returns 1 if the double-precision floating-point value `a' is a quiet
|
||||||
| NaN; otherwise returns 0.
|
| NaN; otherwise returns 0.
|
||||||
@ -779,58 +455,6 @@ floatx80 floatx80_silence_nan(floatx80 a, float_status *status)
|
|||||||
return a;
|
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
|
| Returns 1 if the quadruple-precision floating-point value `a' is a quiet
|
||||||
| NaN; otherwise returns 0.
|
| NaN; otherwise returns 0.
|
||||||
|
@ -4920,6 +4920,25 @@ void normalizeFloatx80Subnormal(uint64_t aSig, int32_t *zExpPtr,
|
|||||||
*zExpPtr = 1 - shiftCount;
|
*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',
|
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
|
||||||
| and extended significand formed by the concatenation of `zSig0' and `zSig1',
|
| and extended significand formed by the concatenation of `zSig0' and `zSig1',
|
||||||
|
@ -62,8 +62,12 @@ config VMXNET3_PCI
|
|||||||
config SMC91C111
|
config SMC91C111
|
||||||
bool
|
bool
|
||||||
|
|
||||||
|
config LAN9118_PHY
|
||||||
|
bool
|
||||||
|
|
||||||
config LAN9118
|
config LAN9118
|
||||||
bool
|
bool
|
||||||
|
select LAN9118_PHY
|
||||||
select PTIMER
|
select PTIMER
|
||||||
|
|
||||||
config NE2000_ISA
|
config NE2000_ISA
|
||||||
@ -89,6 +93,7 @@ config ALLWINNER_SUN8I_EMAC
|
|||||||
|
|
||||||
config IMX_FEC
|
config IMX_FEC
|
||||||
bool
|
bool
|
||||||
|
select LAN9118_PHY
|
||||||
|
|
||||||
config CADENCE
|
config CADENCE
|
||||||
bool
|
bool
|
||||||
|
146
hw/net/imx_fec.c
146
hw/net/imx_fec.c
@ -203,17 +203,12 @@ static const VMStateDescription vmstate_imx_eth_txdescs = {
|
|||||||
|
|
||||||
static const VMStateDescription vmstate_imx_eth = {
|
static const VMStateDescription vmstate_imx_eth = {
|
||||||
.name = TYPE_IMX_FEC,
|
.name = TYPE_IMX_FEC,
|
||||||
.version_id = 2,
|
.version_id = 3,
|
||||||
.minimum_version_id = 2,
|
.minimum_version_id = 3,
|
||||||
.fields = (const VMStateField[]) {
|
.fields = (const VMStateField[]) {
|
||||||
VMSTATE_UINT32_ARRAY(regs, IMXFECState, ENET_MAX),
|
VMSTATE_UINT32_ARRAY(regs, IMXFECState, ENET_MAX),
|
||||||
VMSTATE_UINT32(rx_descriptor, IMXFECState),
|
VMSTATE_UINT32(rx_descriptor, IMXFECState),
|
||||||
VMSTATE_UINT32(tx_descriptor[0], 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()
|
VMSTATE_END_OF_LIST()
|
||||||
},
|
},
|
||||||
.subsections = (const VMStateDescription * const []) {
|
.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);
|
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
|
* For now we don't handle any GPIO/interrupt line, so the OS will
|
||||||
* have to poll for the PHY status.
|
* 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);
|
imx_eth_update(opaque);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void imx_eth_set_link(NetClientState *nc)
|
static void imx_eth_set_link(NetClientState *nc)
|
||||||
{
|
{
|
||||||
imx_phy_update_link(IMX_FEC(qemu_get_nic_opaque(nc)));
|
lan9118_phy_update_link(&IMX_FEC(qemu_get_nic_opaque(nc))->mii,
|
||||||
}
|
nc->link_down);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t imx_phy_read(IMXFECState *s, int reg)
|
static uint32_t imx_phy_read(IMXFECState *s, int reg)
|
||||||
{
|
{
|
||||||
uint32_t val;
|
|
||||||
uint32_t phy = reg / 32;
|
uint32_t phy = reg / 32;
|
||||||
|
|
||||||
if (!s->phy_connected) {
|
if (!s->phy_connected) {
|
||||||
@ -296,54 +255,7 @@ static uint32_t imx_phy_read(IMXFECState *s, int reg)
|
|||||||
|
|
||||||
reg %= 32;
|
reg %= 32;
|
||||||
|
|
||||||
switch (reg) {
|
return lan9118_phy_read(&s->mii, 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void imx_phy_write(IMXFECState *s, int reg, uint32_t val)
|
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;
|
reg %= 32;
|
||||||
|
|
||||||
trace_imx_phy_write(val, phy, reg);
|
lan9118_phy_write(&s->mii, reg, val);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void imx_fec_read_bd(IMXFECBufDesc *bd, dma_addr_t addr)
|
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;
|
s->rx_descriptor = 0;
|
||||||
memset(s->tx_descriptor, 0, sizeof(s->tx_descriptor));
|
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)
|
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[0]);
|
||||||
sysbus_init_irq(sbd, &s->irq[1]);
|
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);
|
qemu_macaddr_default_if_unset(&s->conf.macaddr);
|
||||||
|
|
||||||
s->nic = qemu_new_nic(&imx_eth_net_info, &s->conf,
|
s->nic = qemu_new_nic(&imx_eth_net_info, &s->conf,
|
||||||
|
137
hw/net/lan9118.c
137
hw/net/lan9118.c
@ -16,6 +16,7 @@
|
|||||||
#include "net/net.h"
|
#include "net/net.h"
|
||||||
#include "net/eth.h"
|
#include "net/eth.h"
|
||||||
#include "hw/irq.h"
|
#include "hw/irq.h"
|
||||||
|
#include "hw/net/lan9118_phy.h"
|
||||||
#include "hw/net/lan9118.h"
|
#include "hw/net/lan9118.h"
|
||||||
#include "hw/ptimer.h"
|
#include "hw/ptimer.h"
|
||||||
#include "hw/qdev-properties.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_RXEN 0x00000004
|
||||||
#define MAC_CR_RESERVED 0x7f404213
|
#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
|
#define GPT_TIMER_EN 0x20000000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -228,11 +221,8 @@ struct lan9118_state {
|
|||||||
uint32_t mac_mii_data;
|
uint32_t mac_mii_data;
|
||||||
uint32_t mac_flow;
|
uint32_t mac_flow;
|
||||||
|
|
||||||
uint32_t phy_status;
|
Lan9118PhyState mii;
|
||||||
uint32_t phy_control;
|
IRQState mii_irq;
|
||||||
uint32_t phy_advertise;
|
|
||||||
uint32_t phy_int;
|
|
||||||
uint32_t phy_int_mask;
|
|
||||||
|
|
||||||
int32_t eeprom_writable;
|
int32_t eeprom_writable;
|
||||||
uint8_t eeprom[128];
|
uint8_t eeprom[128];
|
||||||
@ -274,8 +264,8 @@ struct lan9118_state {
|
|||||||
|
|
||||||
static const VMStateDescription vmstate_lan9118 = {
|
static const VMStateDescription vmstate_lan9118 = {
|
||||||
.name = "lan9118",
|
.name = "lan9118",
|
||||||
.version_id = 2,
|
.version_id = 3,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 3,
|
||||||
.fields = (const VMStateField[]) {
|
.fields = (const VMStateField[]) {
|
||||||
VMSTATE_PTIMER(timer, lan9118_state),
|
VMSTATE_PTIMER(timer, lan9118_state),
|
||||||
VMSTATE_UINT32(irq_cfg, 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_acc, lan9118_state),
|
||||||
VMSTATE_UINT32(mac_mii_data, lan9118_state),
|
VMSTATE_UINT32(mac_mii_data, lan9118_state),
|
||||||
VMSTATE_UINT32(mac_flow, 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_INT32(eeprom_writable, lan9118_state),
|
||||||
VMSTATE_UINT8_ARRAY(eeprom, lan9118_state, 128),
|
VMSTATE_UINT8_ARRAY(eeprom, lan9118_state, 128),
|
||||||
VMSTATE_INT32(tx_fifo_size, lan9118_state),
|
VMSTATE_INT32(tx_fifo_size, lan9118_state),
|
||||||
@ -385,9 +370,11 @@ static void lan9118_reload_eeprom(lan9118_state *s)
|
|||||||
lan9118_mac_changed(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;
|
s->int_sts |= PHY_INT;
|
||||||
} else {
|
} else {
|
||||||
s->int_sts &= ~PHY_INT;
|
s->int_sts &= ~PHY_INT;
|
||||||
@ -395,33 +382,10 @@ static void phy_update_irq(lan9118_state *s)
|
|||||||
lan9118_update(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)
|
static void lan9118_set_link(NetClientState *nc)
|
||||||
{
|
{
|
||||||
phy_update_link(qemu_get_nic_opaque(nc));
|
lan9118_phy_update_link(&LAN9118(qemu_get_nic_opaque(nc))->mii,
|
||||||
}
|
nc->link_down);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lan9118_reset(DeviceState *d)
|
static void lan9118_reset(DeviceState *d)
|
||||||
@ -478,8 +442,6 @@ static void lan9118_reset(DeviceState *d)
|
|||||||
s->read_word_n = 0;
|
s->read_word_n = 0;
|
||||||
s->write_word_n = 0;
|
s->write_word_n = 0;
|
||||||
|
|
||||||
phy_reset(s);
|
|
||||||
|
|
||||||
s->eeprom_writable = 0;
|
s->eeprom_writable = 0;
|
||||||
lan9118_reload_eeprom(s);
|
lan9118_reload_eeprom(s);
|
||||||
}
|
}
|
||||||
@ -678,7 +640,7 @@ static void do_tx_packet(lan9118_state *s)
|
|||||||
uint32_t status;
|
uint32_t status;
|
||||||
|
|
||||||
/* FIXME: Honor TX disable, and allow queueing of packets. */
|
/* 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. */
|
/* This assumes the receive routine doesn't touch the VLANClient. */
|
||||||
qemu_receive_packet(qemu_get_queue(s->nic), s->txp->data, s->txp->len);
|
qemu_receive_packet(qemu_get_queue(s->nic), s->txp->data, s->txp->len);
|
||||||
} else {
|
} 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)
|
static void do_mac_write(lan9118_state *s, int reg, uint32_t val)
|
||||||
{
|
{
|
||||||
switch (reg) {
|
switch (reg) {
|
||||||
@ -929,9 +829,9 @@ static void do_mac_write(lan9118_state *s, int reg, uint32_t val)
|
|||||||
if (val & 2) {
|
if (val & 2) {
|
||||||
DPRINTF("PHY write %d = 0x%04x\n",
|
DPRINTF("PHY write %d = 0x%04x\n",
|
||||||
(val >> 6) & 0x1f, s->mac_mii_data);
|
(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 {
|
} 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",
|
DPRINTF("PHY read %d = 0x%04x\n",
|
||||||
(val >> 6) & 0x1f, s->mac_mii_data);
|
(val >> 6) & 0x1f, s->mac_mii_data);
|
||||||
}
|
}
|
||||||
@ -1126,7 +1026,7 @@ static void lan9118_writel(void *opaque, hwaddr offset,
|
|||||||
break;
|
break;
|
||||||
case CSR_PMT_CTRL:
|
case CSR_PMT_CTRL:
|
||||||
if (val & 0x400) {
|
if (val & 0x400) {
|
||||||
phy_reset(s);
|
lan9118_phy_reset(&s->mii);
|
||||||
}
|
}
|
||||||
s->pmt_ctrl &= ~0x34e;
|
s->pmt_ctrl &= ~0x34e;
|
||||||
s->pmt_ctrl |= (val & 0x34e);
|
s->pmt_ctrl |= (val & 0x34e);
|
||||||
@ -1373,6 +1273,13 @@ static void lan9118_realize(DeviceState *dev, Error **errp)
|
|||||||
const MemoryRegionOps *mem_ops =
|
const MemoryRegionOps *mem_ops =
|
||||||
s->mode_16bit ? &lan9118_16bit_mem_ops : &lan9118_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,
|
memory_region_init_io(&s->mmio, OBJECT(dev), mem_ops, s,
|
||||||
"lan9118-mmio", 0x100);
|
"lan9118-mmio", 0x100);
|
||||||
sysbus_init_mmio(sbd, &s->mmio);
|
sysbus_init_mmio(sbd, &s->mmio);
|
||||||
|
222
hw/net/lan9118_phy.c
Normal file
222
hw/net/lan9118_phy.c
Normal 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)
|
@ -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_SMC91C111', if_true: files('smc91c111.c'))
|
||||||
system_ss.add(when: 'CONFIG_LAN9118', if_true: files('lan9118.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_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_OPENCORES_ETH', if_true: files('opencores_eth.c'))
|
||||||
system_ss.add(when: 'CONFIG_XGMAC', if_true: files('xgmac.c'))
|
system_ss.add(when: 'CONFIG_XGMAC', if_true: files('xgmac.c'))
|
||||||
|
@ -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_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
|
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.c
|
||||||
lance_mem_readw(uint64_t addr, uint32_t ret) "addr=0x%"PRIx64"val=0x%04x"
|
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"
|
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"
|
i82596_channel_attention(void *s) "%p: Received CHANNEL ATTENTION"
|
||||||
|
|
||||||
# imx_fec.c
|
# 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_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_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_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_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"
|
imx_eth_tx_bd_busy(void) "tx_bd ran out of descriptors to transmit"
|
||||||
|
@ -81,6 +81,24 @@ static inline void set_float_2nan_prop_rule(Float2NaNPropRule rule,
|
|||||||
status->float_2nan_prop_rule = 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)
|
static inline void set_flush_to_zero(bool val, float_status *status)
|
||||||
{
|
{
|
||||||
status->flush_to_zero = val;
|
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;
|
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)
|
static inline void set_no_signaling_nans(bool val, float_status *status)
|
||||||
{
|
{
|
||||||
status->no_signaling_nans = val;
|
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;
|
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)
|
static inline bool get_flush_to_zero(float_status *status)
|
||||||
{
|
{
|
||||||
return status->flush_to_zero;
|
return status->flush_to_zero;
|
||||||
|
@ -80,6 +80,8 @@ this code that are retained.
|
|||||||
#ifndef SOFTFLOAT_TYPES_H
|
#ifndef SOFTFLOAT_TYPES_H
|
||||||
#define SOFTFLOAT_TYPES_H
|
#define SOFTFLOAT_TYPES_H
|
||||||
|
|
||||||
|
#include "hw/registerfields.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Software IEC/IEEE floating-point types.
|
* Software IEC/IEEE floating-point types.
|
||||||
*/
|
*/
|
||||||
@ -207,6 +209,80 @@ typedef enum __attribute__((__packed__)) {
|
|||||||
float_2nan_prop_x87,
|
float_2nan_prop_x87,
|
||||||
} Float2NaNPropRule;
|
} 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
|
* Floating Point Status. Individual architectures may maintain
|
||||||
* several versions of float_status for different functions. The
|
* several versions of float_status for different functions. The
|
||||||
@ -219,19 +295,30 @@ typedef struct float_status {
|
|||||||
FloatRoundMode float_rounding_mode;
|
FloatRoundMode float_rounding_mode;
|
||||||
FloatX80RoundPrec floatx80_rounding_precision;
|
FloatX80RoundPrec floatx80_rounding_precision;
|
||||||
Float2NaNPropRule float_2nan_prop_rule;
|
Float2NaNPropRule float_2nan_prop_rule;
|
||||||
|
Float3NaNPropRule float_3nan_prop_rule;
|
||||||
|
FloatInfZeroNaNRule float_infzeronan_rule;
|
||||||
bool tininess_before_rounding;
|
bool tininess_before_rounding;
|
||||||
/* should denormalised results go to zero and set the inexact flag? */
|
/* should denormalised results go to zero and set the inexact flag? */
|
||||||
bool flush_to_zero;
|
bool flush_to_zero;
|
||||||
/* should denormalised inputs go to zero and set the input_denormal flag? */
|
/* should denormalised inputs go to zero and set the input_denormal flag? */
|
||||||
bool flush_inputs_to_zero;
|
bool flush_inputs_to_zero;
|
||||||
bool default_nan_mode;
|
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
|
* The flags below are not used on all specializations and may
|
||||||
* constant fold away (see snan_bit_is_one()/no_signalling_nans() in
|
* constant fold away (see snan_bit_is_one()/no_signalling_nans() in
|
||||||
* softfloat-specialize.inc.c)
|
* softfloat-specialize.inc.c)
|
||||||
*/
|
*/
|
||||||
bool snan_bit_is_one;
|
bool snan_bit_is_one;
|
||||||
bool use_first_nan;
|
|
||||||
bool no_signaling_nans;
|
bool no_signaling_nans;
|
||||||
/* should overflowed results subtract re_bias to its exponent? */
|
/* should overflowed results subtract re_bias to its exponent? */
|
||||||
bool rebias_overflow;
|
bool rebias_overflow;
|
||||||
|
@ -31,6 +31,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(IMXFECState, IMX_FEC)
|
|||||||
#define TYPE_IMX_ENET "imx.enet"
|
#define TYPE_IMX_ENET "imx.enet"
|
||||||
|
|
||||||
#include "hw/sysbus.h"
|
#include "hw/sysbus.h"
|
||||||
|
#include "hw/net/lan9118_phy.h"
|
||||||
|
#include "hw/irq.h"
|
||||||
#include "net/net.h"
|
#include "net/net.h"
|
||||||
|
|
||||||
#define ENET_EIR 1
|
#define ENET_EIR 1
|
||||||
@ -264,11 +266,8 @@ struct IMXFECState {
|
|||||||
uint32_t tx_descriptor[ENET_TX_RING_NUM];
|
uint32_t tx_descriptor[ENET_TX_RING_NUM];
|
||||||
uint32_t tx_ring_num;
|
uint32_t tx_ring_num;
|
||||||
|
|
||||||
uint32_t phy_status;
|
Lan9118PhyState mii;
|
||||||
uint32_t phy_control;
|
IRQState mii_irq;
|
||||||
uint32_t phy_advertise;
|
|
||||||
uint32_t phy_int;
|
|
||||||
uint32_t phy_int_mask;
|
|
||||||
uint32_t phy_num;
|
uint32_t phy_num;
|
||||||
bool phy_connected;
|
bool phy_connected;
|
||||||
struct IMXFECState *phy_consumer;
|
struct IMXFECState *phy_consumer;
|
||||||
|
37
include/hw/net/lan9118_phy.h
Normal file
37
include/hw/net/lan9118_phy.h
Normal 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
|
@ -71,6 +71,7 @@
|
|||||||
#define MII_BMSR_JABBER (1 << 1) /* Jabber detected */
|
#define MII_BMSR_JABBER (1 << 1) /* Jabber detected */
|
||||||
#define MII_BMSR_EXTCAP (1 << 0) /* Ext-reg capability */
|
#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_ASYM (1 << 11) /* Try for asymmetric pause */
|
||||||
#define MII_ANAR_PAUSE (1 << 10) /* Try for pause */
|
#define MII_ANAR_PAUSE (1 << 10) /* Try for pause */
|
||||||
#define MII_ANAR_TXFD (1 << 8)
|
#define MII_ANAR_TXFD (1 << 8)
|
||||||
@ -78,6 +79,7 @@
|
|||||||
#define MII_ANAR_10FD (1 << 6)
|
#define MII_ANAR_10FD (1 << 6)
|
||||||
#define MII_ANAR_10 (1 << 5)
|
#define MII_ANAR_10 (1 << 5)
|
||||||
#define MII_ANAR_CSMACD (1 << 0)
|
#define MII_ANAR_CSMACD (1 << 0)
|
||||||
|
#define MII_ANAR_SELECT (0x001f) /* Selector bits */
|
||||||
|
|
||||||
#define MII_ANLPAR_ACK (1 << 14)
|
#define MII_ANLPAR_ACK (1 << 14)
|
||||||
#define MII_ANLPAR_PAUSEASY (1 << 11) /* can pause asymmetrically */
|
#define MII_ANLPAR_PAUSEASY (1 << 11) /* can pause asymmetrically */
|
||||||
@ -112,6 +114,10 @@
|
|||||||
#define RTL8201CP_PHYID1 0x0000
|
#define RTL8201CP_PHYID1 0x0000
|
||||||
#define RTL8201CP_PHYID2 0x8201
|
#define RTL8201CP_PHYID2 0x8201
|
||||||
|
|
||||||
|
/* SMSC LAN9118 */
|
||||||
|
#define SMSCLAN9118_PHYID1 0x0007
|
||||||
|
#define SMSCLAN9118_PHYID2 0xc0d1
|
||||||
|
|
||||||
/* RealTek 8211E */
|
/* RealTek 8211E */
|
||||||
#define RTL8211E_PHYID1 0x001c
|
#define RTL8211E_PHYID1 0x001c
|
||||||
#define RTL8211E_PHYID2 0xc915
|
#define RTL8211E_PHYID2 0xc915
|
||||||
|
@ -69,6 +69,11 @@ void resetFPA11(void)
|
|||||||
* this late date.
|
* this late date.
|
||||||
*/
|
*/
|
||||||
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &fpa11->fp_status);
|
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)
|
void SetRoundingMode(const unsigned int opcode)
|
||||||
|
@ -199,6 +199,8 @@ static void alpha_cpu_initfn(Object *obj)
|
|||||||
* operand in Fa. That is float_2nan_prop_ba.
|
* operand in Fa. That is float_2nan_prop_ba.
|
||||||
*/
|
*/
|
||||||
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status);
|
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)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
env->flags = ENV_FLAG_PS_USER | ENV_FLAG_FEN;
|
env->flags = ENV_FLAG_PS_USER | ENV_FLAG_FEN;
|
||||||
cpu_alpha_store_fpcr(env, (uint64_t)(FPCR_INVD | FPCR_DZED | FPCR_OVFD
|
cpu_alpha_store_fpcr(env, (uint64_t)(FPCR_INVD | FPCR_DZED | FPCR_OVFD
|
||||||
|
@ -173,11 +173,21 @@ void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook,
|
|||||||
* * tininess-before-rounding
|
* * tininess-before-rounding
|
||||||
* * 2-input NaN propagation prefers SNaN over QNaN, and then
|
* * 2-input NaN propagation prefers SNaN over QNaN, and then
|
||||||
* operand A over operand B (see FPProcessNaNs() pseudocode)
|
* 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)
|
static void arm_set_default_fp_behaviours(float_status *s)
|
||||||
{
|
{
|
||||||
set_float_detect_tininess(float_tininess_before_rounding, s);
|
set_float_detect_tininess(float_tininess_before_rounding, s);
|
||||||
set_float_2nan_prop_rule(float_2nan_prop_s_ab, 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)
|
static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
|
||||||
|
@ -2813,25 +2813,19 @@ bool is_ebf(CPUARMState *env, float_status *statusp, float_status *oddstatusp)
|
|||||||
* no effect on AArch32 instructions.
|
* no effect on AArch32 instructions.
|
||||||
*/
|
*/
|
||||||
bool ebf = is_a64(env) && env->vfp.fpcr & FPCR_EBF;
|
bool ebf = is_a64(env) && env->vfp.fpcr & FPCR_EBF;
|
||||||
*statusp = (float_status){
|
|
||||||
.tininess_before_rounding = float_tininess_before_rounding,
|
*statusp = env->vfp.fp_status;
|
||||||
.float_rounding_mode = float_round_to_odd_inf,
|
set_default_nan_mode(true, statusp);
|
||||||
.flush_to_zero = true,
|
|
||||||
.flush_inputs_to_zero = true,
|
|
||||||
.default_nan_mode = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (ebf) {
|
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 */
|
/* EBF=1 needs to do a step with round-to-odd semantics */
|
||||||
*oddstatusp = *statusp;
|
*oddstatusp = *statusp;
|
||||||
set_float_rounding_mode(float_round_to_odd, oddstatusp);
|
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;
|
return ebf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,6 +286,8 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type)
|
|||||||
|
|
||||||
set_default_nan_mode(1, &env->fp_status);
|
set_default_nan_mode(1, &env->fp_status);
|
||||||
set_float_detect_tininess(float_tininess_before_rounding, &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)
|
static void hexagon_cpu_disas_set_info(CPUState *s, disassemble_info *info)
|
||||||
|
@ -55,6 +55,18 @@ void HELPER(loaded_fr0)(CPUHPPAState *env)
|
|||||||
* HPPA does note implement a CPU reset method at all...
|
* HPPA does note implement a CPU reset method at all...
|
||||||
*/
|
*/
|
||||||
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fp_status);
|
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)
|
void cpu_hppa_loaded_fr0(CPUHPPAState *env)
|
||||||
|
@ -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->mmx_status);
|
||||||
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->sse_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)
|
static inline uint8_t save_exception_flags(CPUX86State *env)
|
||||||
|
@ -32,6 +32,14 @@ void restore_fp_status(CPULoongArchState *env)
|
|||||||
&env->fp_status);
|
&env->fp_status);
|
||||||
set_flush_to_zero(0, &env->fp_status);
|
set_flush_to_zero(0, &env->fp_status);
|
||||||
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &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)
|
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)) {
|
} else if (float32_is_zero_or_denormal(f)) {
|
||||||
return sign ? 1 << 4 : 1 << 8;
|
return sign ? 1 << 4 : 1 << 8;
|
||||||
} else if (float32_is_any_nan(f)) {
|
} else if (float32_is_any_nan(f)) {
|
||||||
float_status s = { }; /* for snan_bit_is_one */
|
return float32_is_quiet_nan(f, &env->fp_status) ? 1 << 1 : 1 << 0;
|
||||||
return float32_is_quiet_nan(f, &s) ? 1 << 1 : 1 << 0;
|
|
||||||
} else {
|
} else {
|
||||||
return sign ? 1 << 3 : 1 << 7;
|
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)) {
|
} else if (float64_is_zero_or_denormal(f)) {
|
||||||
return sign ? 1 << 4 : 1 << 8;
|
return sign ? 1 << 4 : 1 << 8;
|
||||||
} else if (float64_is_any_nan(f)) {
|
} else if (float64_is_any_nan(f)) {
|
||||||
float_status s = { }; /* for snan_bit_is_one */
|
return float64_is_quiet_nan(f, &env->fp_status) ? 1 << 1 : 1 << 0;
|
||||||
return float64_is_quiet_nan(f, &s) ? 1 << 1 : 1 << 0;
|
|
||||||
} else {
|
} else {
|
||||||
return sign ? 1 << 3 : 1 << 7;
|
return sign ? 1 << 3 : 1 << 7;
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type)
|
|||||||
CPUState *cs = CPU(obj);
|
CPUState *cs = CPU(obj);
|
||||||
M68kCPUClass *mcc = M68K_CPU_GET_CLASS(obj);
|
M68kCPUClass *mcc = M68K_CPU_GET_CLASS(obj);
|
||||||
CPUM68KState *env = cpu_env(cs);
|
CPUM68KState *env = cpu_env(cs);
|
||||||
floatx80 nan = floatx80_default_nan(NULL);
|
floatx80 nan;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (mcc->parent_phases.hold) {
|
if (mcc->parent_phases.hold) {
|
||||||
@ -89,10 +89,6 @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type)
|
|||||||
#else
|
#else
|
||||||
cpu_m68k_set_sr(env, SR_S | SR_I);
|
cpu_m68k_set_sr(env, SR_S | SR_I);
|
||||||
#endif
|
#endif
|
||||||
for (i = 0; i < 8; i++) {
|
|
||||||
env->fregs[i].d = nan;
|
|
||||||
}
|
|
||||||
cpu_m68k_set_fpcr(env, 0);
|
|
||||||
/*
|
/*
|
||||||
* M68000 FAMILY PROGRAMMER'S REFERENCE MANUAL
|
* M68000 FAMILY PROGRAMMER'S REFERENCE MANUAL
|
||||||
* 3.4 FLOATING-POINT INSTRUCTION DETAILS
|
* 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.
|
* preceding paragraph for nonsignaling NaNs.
|
||||||
*/
|
*/
|
||||||
set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status);
|
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;
|
env->fpsr = 0;
|
||||||
|
|
||||||
/* TODO: We should set PC from the interrupt vector. */
|
/* TODO: We should set PC from the interrupt vector. */
|
||||||
|
@ -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);
|
fp_rem = floatx80_rem(val1->d, val0->d, &env->fp_status);
|
||||||
if (!floatx80_is_any_nan(fp_rem)) {
|
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;
|
uint32_t quotient;
|
||||||
int sign;
|
int sign;
|
||||||
|
|
||||||
/* Calculate quotient directly using round to nearest mode */
|
/* 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_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);
|
fp_quot.d = floatx80_div(val1->d, val0->d, &fp_status);
|
||||||
|
|
||||||
sign = extractFloatx80Sign(fp_quot.d);
|
sign = extractFloatx80Sign(fp_quot.d);
|
||||||
|
@ -36,7 +36,8 @@ static int cf_fpu_gdb_get_reg(CPUState *cs, GByteArray *mem_buf, int n)
|
|||||||
CPUM68KState *env = &cpu->env;
|
CPUM68KState *env = &cpu->env;
|
||||||
|
|
||||||
if (n < 8) {
|
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));
|
return gdb_get_reg64(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
|
||||||
}
|
}
|
||||||
switch (n) {
|
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;
|
CPUM68KState *env = &cpu->env;
|
||||||
|
|
||||||
if (n < 8) {
|
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);
|
env->fregs[n].d = float64_to_floatx80(ldq_be_p(mem_buf), &s);
|
||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
|
@ -207,6 +207,8 @@ static void mb_cpu_reset_hold(Object *obj, ResetType type)
|
|||||||
* this architecture.
|
* this architecture.
|
||||||
*/
|
*/
|
||||||
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status);
|
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)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
/* start in user mode with interrupts enabled. */
|
/* start in user mode with interrupts enabled. */
|
||||||
|
@ -28,6 +28,8 @@ static inline void restore_flush_mode(CPUMIPSState *env)
|
|||||||
static inline void restore_snan_bit_mode(CPUMIPSState *env)
|
static inline void restore_snan_bit_mode(CPUMIPSState *env)
|
||||||
{
|
{
|
||||||
bool nan2008 = env->active_fpu.fcr31 & (1 << FCR31_NAN2008);
|
bool nan2008 = env->active_fpu.fcr31 & (1 << FCR31_NAN2008);
|
||||||
|
FloatInfZeroNaNRule izn_rule;
|
||||||
|
Float3NaNPropRule nan3_rule;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* With nan2008, SNaNs are silenced in the usual way.
|
* 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_snan_bit_is_one(!nan2008, &env->active_fpu.fp_status);
|
||||||
set_default_nan_mode(!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)
|
static inline void restore_fp_status(CPUMIPSState *env)
|
||||||
|
@ -66,6 +66,9 @@ void msa_reset(CPUMIPSState *env)
|
|||||||
set_float_2nan_prop_rule(float_2nan_prop_s_ab,
|
set_float_2nan_prop_rule(float_2nan_prop_s_ab,
|
||||||
&env->active_tc.msa_fp_status);
|
&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 */
|
/* clear float_status exception flags */
|
||||||
set_float_exception_flags(0, &env->active_tc.msa_fp_status);
|
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 proper signanling bit meaning ("1" means "quiet") */
|
||||||
set_snan_bit_is_one(0, &env->active_tc.msa_fp_status);
|
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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
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
|
#ifndef CONFIG_USER_ONLY
|
||||||
cpu->env.picmr = 0x00000000;
|
cpu->env.picmr = 0x00000000;
|
||||||
|
@ -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->fp_status);
|
||||||
set_float_2nan_prop_rule(float_2nan_prop_ab, &env->vec_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++) {
|
for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) {
|
||||||
ppc_spr_t *spr = &env->spr_cb[i];
|
ppc_spr_t *spr = &env->spr_cb[i];
|
||||||
|
@ -155,8 +155,7 @@ void helper_compute_fprf_##tp(CPUPPCState *env, tp arg) \
|
|||||||
} else if (tp##_is_infinity(arg)) { \
|
} else if (tp##_is_infinity(arg)) { \
|
||||||
fprf = neg ? 0x09 << FPSCR_FPRF : 0x05 << FPSCR_FPRF; \
|
fprf = neg ? 0x09 << FPSCR_FPRF : 0x05 << FPSCR_FPRF; \
|
||||||
} else { \
|
} else { \
|
||||||
float_status dummy = { }; /* snan_bit_is_one = 0 */ \
|
if (tp##_is_signaling_nan(arg, &env->fp_status)) { \
|
||||||
if (tp##_is_signaling_nan(arg, &dummy)) { \
|
|
||||||
fprf = 0x00 << FPSCR_FPRF; \
|
fprf = 0x00 << FPSCR_FPRF; \
|
||||||
} else { \
|
} else { \
|
||||||
fprf = 0x11 << FPSCR_FPRF; \
|
fprf = 0x11 << FPSCR_FPRF; \
|
||||||
|
@ -1022,6 +1022,8 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type)
|
|||||||
cs->exception_index = RISCV_EXCP_NONE;
|
cs->exception_index = RISCV_EXCP_NONE;
|
||||||
env->load_res = -1;
|
env->load_res = -1;
|
||||||
set_default_nan_mode(1, &env->fp_status);
|
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;
|
env->vill = true;
|
||||||
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
@ -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.
|
* then prefer dest over source", which is float_2nan_prop_s_ab.
|
||||||
*/
|
*/
|
||||||
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status);
|
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)
|
static ObjectClass *rx_cpu_class_by_name(const char *cpu_model)
|
||||||
|
@ -206,6 +206,11 @@ static void s390_cpu_reset_hold(Object *obj, ResetType type)
|
|||||||
set_float_detect_tininess(float_tininess_before_rounding,
|
set_float_detect_tininess(float_tininess_before_rounding,
|
||||||
&env->fpu_status);
|
&env->fpu_status);
|
||||||
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &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 */
|
/* fall through */
|
||||||
case RESET_TYPE_S390_CPU_NORMAL:
|
case RESET_TYPE_S390_CPU_NORMAL:
|
||||||
env->psw.mask &= ~PSW_MASK_RI;
|
env->psw.mask &= ~PSW_MASK_RI;
|
||||||
|
@ -127,6 +127,8 @@ static void superh_cpu_reset_hold(Object *obj, ResetType type)
|
|||||||
set_flush_to_zero(1, &env->fp_status);
|
set_flush_to_zero(1, &env->fp_status);
|
||||||
#endif
|
#endif
|
||||||
set_default_nan_mode(1, &env->fp_status);
|
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)
|
static void superh_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
|
||||||
|
@ -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.
|
* 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);
|
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);
|
cpu_exec_realizefn(cs, &local_err);
|
||||||
if (local_err != NULL) {
|
if (local_err != NULL) {
|
||||||
|
@ -490,13 +490,13 @@ uint32_t helper_fcmpeq(CPUSPARCState *env, Int128 src1, Int128 src2)
|
|||||||
return finish_fcmp(env, r, GETPC());
|
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.
|
* FLCMP never raises an exception nor modifies any FSR fields.
|
||||||
* Perform the comparison with a dummy fp environment.
|
* Perform the comparison with a dummy fp environment.
|
||||||
*/
|
*/
|
||||||
float_status discard = { };
|
float_status discard = env->fp_status;
|
||||||
FloatRelation r;
|
FloatRelation r;
|
||||||
|
|
||||||
set_float_2nan_prop_rule(float_2nan_prop_s_ba, &discard);
|
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();
|
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;
|
FloatRelation r;
|
||||||
|
|
||||||
set_float_2nan_prop_rule(float_2nan_prop_s_ba, &discard);
|
set_float_2nan_prop_rule(float_2nan_prop_s_ba, &discard);
|
||||||
|
@ -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(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(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_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_3(flcmps, TCG_CALL_NO_RWG_SE, i32, env, f32, f32)
|
||||||
DEF_HELPER_FLAGS_2(flcmpd, TCG_CALL_NO_RWG_SE, i32, f64, f64)
|
DEF_HELPER_FLAGS_3(flcmpd, TCG_CALL_NO_RWG_SE, i32, env, f64, f64)
|
||||||
DEF_HELPER_2(raise_exception, noreturn, env, int)
|
DEF_HELPER_2(raise_exception, noreturn, env, int)
|
||||||
|
|
||||||
DEF_HELPER_FLAGS_3(faddd, TCG_CALL_NO_WG, f64, env, f64, f64)
|
DEF_HELPER_FLAGS_3(faddd, TCG_CALL_NO_WG, f64, env, f64, f64)
|
||||||
|
@ -5584,7 +5584,7 @@ static bool trans_FLCMPs(DisasContext *dc, arg_FLCMPs *a)
|
|||||||
|
|
||||||
src1 = gen_load_fpr_F(dc, a->rs1);
|
src1 = gen_load_fpr_F(dc, a->rs1);
|
||||||
src2 = gen_load_fpr_F(dc, a->rs2);
|
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);
|
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);
|
src1 = gen_load_fpr_D(dc, a->rs1);
|
||||||
src2 = gen_load_fpr_D(dc, a->rs2);
|
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);
|
return advance_pc(dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,6 +117,8 @@ void fpu_set_state(CPUTriCoreState *env)
|
|||||||
set_flush_to_zero(1, &env->fp_status);
|
set_flush_to_zero(1, &env->fp_status);
|
||||||
set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status);
|
set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status);
|
||||||
set_default_nan_mode(1, &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)
|
uint32_t psw_read(CPUTriCoreState *env)
|
||||||
|
@ -133,7 +133,11 @@ static void xtensa_cpu_reset_hold(Object *obj, ResetType type)
|
|||||||
reset_mmu(env);
|
reset_mmu(env);
|
||||||
cs->halted = env->runstall;
|
cs->halted = env->runstall;
|
||||||
#endif
|
#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);
|
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);
|
xtensa_use_first_nan(env, !dfpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,9 +59,10 @@ static const struct {
|
|||||||
|
|
||||||
void xtensa_use_first_nan(CPUXtensaState *env, bool use_first)
|
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,
|
set_float_2nan_prop_rule(use_first ? float_2nan_prop_ab : float_2nan_prop_ba,
|
||||||
&env->fp_status);
|
&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)
|
void HELPER(wur_fpu2k_fcr)(CPUXtensaState *env, uint32_t v)
|
||||||
|
@ -488,7 +488,14 @@ static void run_bench(void)
|
|||||||
{
|
{
|
||||||
bench_func_t f;
|
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_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];
|
f = bench_funcs[operation][precision];
|
||||||
g_assert(f);
|
g_assert(f);
|
||||||
|
@ -71,6 +71,7 @@ int main(int ac, char **av)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf);
|
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);
|
set_float_rounding_mode(float_round_nearest_even, &qsf);
|
||||||
|
|
||||||
test.d = 0.0;
|
test.d = 0.0;
|
||||||
|
@ -935,7 +935,14 @@ void run_test(void)
|
|||||||
{
|
{
|
||||||
unsigned int i;
|
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_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);
|
genCases_setLevel(test_level);
|
||||||
verCases_maxErrorCount = n_max_errors;
|
verCases_maxErrorCount = n_max_errors;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user