target-arm queue:

* Fix MMU indexes for AArch32 Secure PL1&0 in a less complex and buggy way
  * Fix SVE SDOT/UDOT/USDOT (4-way, indexed)
  * softfloat: set 2-operand NaN propagation rule at runtime
  * disas: Fix build against Capstone v6 (again)
  * hw/rtc/ds1338: Trace send and receive operations
  * hw/timer/imx_gpt: Convert DPRINTF to trace events
  * hw/watchdog/wdt_imx2: Remove redundant assignment
  * hw/sensor/tmp105: Convert printf() to trace event, add tracing for read/write access
  * hw/net/npcm_gmac: Change error log to trace event
  * target/arm: Enable FEAT_CMOW for -cpu max
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmcp/yoZHHBldGVyLm1h
 eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3ucMD/9pWk2ETLjdviPxlacs5IoM
 HvGn8Ll2BSMbeb4YdJc7oZ4YJchGpgHhocEwZuaU9HheWjSg+ZEbyhZgN4DdkT8J
 pYr+Rl0MgDNN219kYnO/yqnqlgHbtUpE7y57Li3ApoGNbWAVxsH0xoT45Lpi7DOd
 uvJfIy/xdaT3zu/4uBjj7c2VrD8wntEayLM8hpqlgeQZKRG3Wtlk/xrQFKOHPDPO
 MDbsGoc2FyogRQoo6WH+J6gkkR9PhqXe6Hbf6WIr1/uffZUZU4M8leSw2DgxrYHo
 Zf36AzttwO4GHyML/5SR7uvzfXl7OkGyjedLGCUa7INc3br2+GvLMltdLGGPM9cc
 ckMHOWd9ZQuSxcpbtPkSYRG0McRE1GLT+KV3BNOLnN9AJl3qv5Qa55iPrtpB08vX
 3jN6H964w99+NoSB2tTHszpep+M7SRuw5QLsuk3tC/qnBMpzKRwZjGVUegNUtfi/
 Lg5ExF8B62K+xb5j5FmODbbXZmb5AD0rV2MGRIVHjiHdnf7J2FmWUJCe2sYFRnRm
 nzszhdOKw4PBhC2fb6Vb/DwCqdQy9vcITWpWBtcjkV5mAPhcBo/VNKNeKoc/tPNS
 H8FIFIJbtv5aIixqtKcUBUmrBCYy4EoiRMLkqfC09VW60wtWswAP4KBQxi1ogehV
 jJw8AgSLCl2MsVmyzgleZQ==
 =Woag
 -----END PGP SIGNATURE-----

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

target-arm queue:
 * Fix MMU indexes for AArch32 Secure PL1&0 in a less complex and buggy way
 * Fix SVE SDOT/UDOT/USDOT (4-way, indexed)
 * softfloat: set 2-operand NaN propagation rule at runtime
 * disas: Fix build against Capstone v6 (again)
 * hw/rtc/ds1338: Trace send and receive operations
 * hw/timer/imx_gpt: Convert DPRINTF to trace events
 * hw/watchdog/wdt_imx2: Remove redundant assignment
 * hw/sensor/tmp105: Convert printf() to trace event, add tracing for read/write access
 * hw/net/npcm_gmac: Change error log to trace event
 * target/arm: Enable FEAT_CMOW for -cpu max

# -----BEGIN PGP SIGNATURE-----
#
# iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmcp/yoZHHBldGVyLm1h
# eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3ucMD/9pWk2ETLjdviPxlacs5IoM
# HvGn8Ll2BSMbeb4YdJc7oZ4YJchGpgHhocEwZuaU9HheWjSg+ZEbyhZgN4DdkT8J
# pYr+Rl0MgDNN219kYnO/yqnqlgHbtUpE7y57Li3ApoGNbWAVxsH0xoT45Lpi7DOd
# uvJfIy/xdaT3zu/4uBjj7c2VrD8wntEayLM8hpqlgeQZKRG3Wtlk/xrQFKOHPDPO
# MDbsGoc2FyogRQoo6WH+J6gkkR9PhqXe6Hbf6WIr1/uffZUZU4M8leSw2DgxrYHo
# Zf36AzttwO4GHyML/5SR7uvzfXl7OkGyjedLGCUa7INc3br2+GvLMltdLGGPM9cc
# ckMHOWd9ZQuSxcpbtPkSYRG0McRE1GLT+KV3BNOLnN9AJl3qv5Qa55iPrtpB08vX
# 3jN6H964w99+NoSB2tTHszpep+M7SRuw5QLsuk3tC/qnBMpzKRwZjGVUegNUtfi/
# Lg5ExF8B62K+xb5j5FmODbbXZmb5AD0rV2MGRIVHjiHdnf7J2FmWUJCe2sYFRnRm
# nzszhdOKw4PBhC2fb6Vb/DwCqdQy9vcITWpWBtcjkV5mAPhcBo/VNKNeKoc/tPNS
# H8FIFIJbtv5aIixqtKcUBUmrBCYy4EoiRMLkqfC09VW60wtWswAP4KBQxi1ogehV
# jJw8AgSLCl2MsVmyzgleZQ==
# =Woag
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 05 Nov 2024 11:19:06 GMT
# gpg:                using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg:                issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate]
# gpg:                 aka "Peter Maydell <peter@archaic.org.uk>" [ultimate]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* tag 'pull-target-arm-20241105' of https://git.linaro.org/people/pmaydell/qemu-arm: (31 commits)
  target/arm: Enable FEAT_CMOW for -cpu max
  hw/net/npcm_gmac: Change error log to trace event
  hw/sensor/tmp105: Convert printf() to trace event, add tracing for read/write access
  hw/watchdog/wdt_imx2: Remove redundant assignment
  hw/timer/imx_gpt: Convert DPRINTF to trace events
  hw/rtc/ds1338: Trace send and receive operations
  disas: Fix build against Capstone v6 (again)
  target/arm: Fix SVE SDOT/UDOT/USDOT (4-way, indexed)
  target/arm: Add new MMU indexes for AArch32 Secure PL1&0
  Revert "target/arm: Fix usage of MMU indexes when EL3 is AArch32"
  softfloat: Remove fallback rule from pickNaN()
  target/rx: Explicitly set 2-NaN propagation rule
  target/openrisc: Explicitly set 2-NaN propagation rule
  target/microblaze: Explicitly set 2-NaN propagation rule
  target/microblaze: Move setting of float rounding mode to reset
  target/alpha: Explicitly set 2-NaN propagation rule
  target/i386: Set 2-NaN propagation rule explicitly
  target/xtensa: Explicitly set 2-NaN propagation rule
  target/xtensa: Factor out calls to set_use_first_nan()
  target/sparc: Explicitly set 2-NaN propagation rule
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2024-11-05 21:27:18 +00:00
commit f15f7273ea
55 changed files with 516 additions and 239 deletions

View File

@ -26,6 +26,7 @@ the following architecture extensions:
- FEAT_BF16 (AArch64 BFloat16 instructions) - FEAT_BF16 (AArch64 BFloat16 instructions)
- FEAT_BTI (Branch Target Identification) - FEAT_BTI (Branch Target Identification)
- FEAT_CCIDX (Extended cache index) - FEAT_CCIDX (Extended cache index)
- FEAT_CMOW (Control for cache maintenance permission)
- FEAT_CRC32 (CRC32 instructions) - FEAT_CRC32 (CRC32 instructions)
- FEAT_Crypto (Cryptographic Extension) - FEAT_Crypto (Cryptographic Extension)
- FEAT_CSV2 (Cache speculation variant 2) - FEAT_CSV2 (Cache speculation variant 2)

View File

@ -390,118 +390,80 @@ bool float32_is_signaling_nan(float32 a_, float_status *status)
static int pickNaN(FloatClass a_cls, FloatClass b_cls, static int pickNaN(FloatClass a_cls, FloatClass b_cls,
bool aIsLargerSignificand, float_status *status) bool aIsLargerSignificand, float_status *status)
{ {
#if defined(TARGET_ARM) || defined(TARGET_MIPS) || defined(TARGET_HPPA) || \
defined(TARGET_LOONGARCH64) || defined(TARGET_S390X)
/* ARM mandated NaN propagation rules (see FPProcessNaNs()), take
* the first of:
* 1. A if it is signaling
* 2. B if it is signaling
* 3. A (quiet)
* 4. B (quiet)
* A signaling NaN is always quietened before returning it.
*/
/* According to MIPS specifications, if one of the two operands is
* a sNaN, a new qNaN has to be generated. This is done in
* floatXX_silence_nan(). For qNaN inputs the specifications
* says: "When possible, this QNaN result is one of the operand QNaN
* values." In practice it seems that most implementations choose
* the first operand if both operands are qNaN. In short this gives
* the following rules:
* 1. A if it is signaling
* 2. B if it is signaling
* 3. A (quiet)
* 4. B (quiet)
* A signaling NaN is always silenced before returning it.
*/
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;
}
#elif defined(TARGET_PPC) || defined(TARGET_M68K)
/* PowerPC propagation rules:
* 1. A if it sNaN or qNaN
* 2. B if it sNaN or qNaN
* A signaling NaN is always silenced before returning it.
*/
/* M68000 FAMILY PROGRAMMER'S REFERENCE MANUAL
* 3.4 FLOATING-POINT INSTRUCTION DETAILS
* If either operand, but not both operands, of an operation is a
* nonsignaling NaN, then that NaN is returned as the result. If both
* operands are nonsignaling NaNs, then the destination operand
* nonsignaling NaN is returned as the result.
* If either operand to an operation is a signaling NaN (SNaN), then the
* SNaN bit is set in the FPSR EXC byte. If the SNaN exception enable bit
* is set in the FPCR ENABLE byte, then the exception is taken and the
* destination is not modified. If the SNaN exception enable bit is not
* set, setting the SNaN bit in the operand to a one converts the SNaN to
* a nonsignaling NaN. The operation then continues as described in the
* preceding paragraph for nonsignaling NaNs.
*/
if (is_nan(a_cls)) {
return 0;
} else {
return 1;
}
#elif defined(TARGET_SPARC)
/* Prefer SNaN over QNaN, order B then A. */
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;
}
#elif defined(TARGET_XTENSA)
/* /*
* Xtensa has two NaN propagation modes. * We guarantee not to require the target to tell us how to
* Which one is active is controlled by float_status::use_first_nan. * 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().
*/ */
if (status->use_first_nan) { 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)) { if (is_nan(a_cls)) {
return 0; return 0;
} else { } else {
return 1; return 1;
} }
} else { break;
case float_2nan_prop_ba:
if (is_nan(b_cls)) { if (is_nan(b_cls)) {
return 1; return 1;
} else { } else {
return 0; return 0;
} }
} break;
#else case float_2nan_prop_x87:
/* This implements x87 NaN propagation rules: /*
* SNaN + QNaN => return the QNaN * This implements x87 NaN propagation rules:
* two SNaNs => return the one with the larger significand, silenced * SNaN + QNaN => return the QNaN
* two QNaNs => return the one with the larger significand * two SNaNs => return the one with the larger significand, silenced
* SNaN and a non-NaN => return the SNaN, silenced * two QNaNs => return the one with the larger significand
* QNaN and a non-NaN => return the QNaN * 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 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)) { if (is_snan(a_cls)) {
return aIsLargerSignificand ? 0 : 1; if (is_snan(b_cls)) {
} return aIsLargerSignificand ? 0 : 1;
return is_qnan(b_cls) ? 1 : 0; }
} else if (is_qnan(a_cls)) { return is_qnan(b_cls) ? 1 : 0;
if (is_snan(b_cls) || !is_qnan(b_cls)) { } else if (is_qnan(a_cls)) {
return 0; if (is_snan(b_cls) || !is_qnan(b_cls)) {
return 0;
} else {
return aIsLargerSignificand ? 0 : 1;
}
} else { } else {
return aIsLargerSignificand ? 0 : 1; return 1;
} }
} else { default:
return 1; g_assert_not_reached();
} }
#endif
} }
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------

View File

@ -546,9 +546,8 @@ static void gmac_try_send_next_packet(NPCMGMACState *gmac)
/* 1 = DMA Owned, 0 = Software Owned */ /* 1 = DMA Owned, 0 = Software Owned */
if (!(tx_desc.tdes0 & TX_DESC_TDES0_OWN)) { if (!(tx_desc.tdes0 & TX_DESC_TDES0_OWN)) {
qemu_log_mask(LOG_GUEST_ERROR, trace_npcm_gmac_tx_desc_owner(DEVICE(gmac)->canonical_path,
"TX Descriptor @ 0x%x is owned by software\n", desc_addr);
desc_addr);
gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_TU; gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_TU;
gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT, gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT,
NPCM_DMA_STATUS_TX_SUSPENDED_STATE); NPCM_DMA_STATUS_TX_SUSPENDED_STATE);

View File

@ -478,6 +478,7 @@ npcm_gmac_packet_received(const char* name, uint32_t len) "%s: Reception finishe
npcm_gmac_packet_sent(const char* name, uint16_t len) "%s: TX packet sent!, length: 0x%04" PRIX16 npcm_gmac_packet_sent(const char* name, uint16_t len) "%s: TX packet sent!, length: 0x%04" PRIX16
npcm_gmac_debug_desc_data(const char* name, void* addr, uint32_t des0, uint32_t des1, uint32_t des2, uint32_t des3)"%s: Address: %p Descriptor 0: 0x%04" PRIX32 " Descriptor 1: 0x%04" PRIX32 "Descriptor 2: 0x%04" PRIX32 " Descriptor 3: 0x%04" PRIX32 npcm_gmac_debug_desc_data(const char* name, void* addr, uint32_t des0, uint32_t des1, uint32_t des2, uint32_t des3)"%s: Address: %p Descriptor 0: 0x%04" PRIX32 " Descriptor 1: 0x%04" PRIX32 "Descriptor 2: 0x%04" PRIX32 " Descriptor 3: 0x%04" PRIX32
npcm_gmac_packet_tx_desc_data(const char* name, uint32_t tdes0, uint32_t tdes1) "%s: Tdes0: 0x%04" PRIX32 " Tdes1: 0x%04" PRIX32 npcm_gmac_packet_tx_desc_data(const char* name, uint32_t tdes0, uint32_t tdes1) "%s: Tdes0: 0x%04" PRIX32 " Tdes1: 0x%04" PRIX32
npcm_gmac_tx_desc_owner(const char* name, uint32_t desc_addr) "%s: TX Descriptor @0x%04" PRIX32 " is owned by software"
# npcm_pcs.c # npcm_pcs.c
npcm_pcs_reg_read(const char *name, uint16_t indirect_access_baes, uint64_t offset, uint16_t value) "%s: IND: 0x%02" PRIx16 " offset: 0x%04" PRIx64 " value: 0x%04" PRIx16 npcm_pcs_reg_read(const char *name, uint16_t indirect_access_baes, uint64_t offset, uint16_t value) "%s: IND: 0x%02" PRIx16 " offset: 0x%04" PRIx64 " value: 0x%04" PRIx16

View File

@ -17,6 +17,7 @@
#include "qemu/module.h" #include "qemu/module.h"
#include "qom/object.h" #include "qom/object.h"
#include "sysemu/rtc.h" #include "sysemu/rtc.h"
#include "trace.h"
/* Size of NVRAM including both the user-accessible area and the /* Size of NVRAM including both the user-accessible area and the
* secondary register area. * secondary register area.
@ -126,6 +127,9 @@ static uint8_t ds1338_recv(I2CSlave *i2c)
uint8_t res; uint8_t res;
res = s->nvram[s->ptr]; res = s->nvram[s->ptr];
trace_ds1338_recv(s->ptr, res);
inc_regptr(s); inc_regptr(s);
return res; return res;
} }
@ -134,6 +138,8 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
{ {
DS1338State *s = DS1338(i2c); DS1338State *s = DS1338(i2c);
trace_ds1338_send(s->ptr, data);
if (s->addr_byte) { if (s->addr_byte) {
s->ptr = data & (NVRAM_SIZE - 1); s->ptr = data & (NVRAM_SIZE - 1);
s->addr_byte = false; s->addr_byte = false;

View File

@ -22,6 +22,10 @@ pl031_set_alarm(uint32_t ticks) "alarm set for %u ticks"
aspeed_rtc_read(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64 aspeed_rtc_read(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
aspeed_rtc_write(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64 aspeed_rtc_write(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
# ds1338.c
ds1338_recv(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] -> 0x%02" PRIx8
ds1338_send(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] <- 0x%02" PRIx8
# m48t59.c # m48t59.c
m48txx_nvram_io_read(uint64_t addr, uint64_t value) "io read addr:0x%04" PRIx64 " value:0x%02" PRIx64 m48txx_nvram_io_read(uint64_t addr, uint64_t value) "io read addr:0x%04" PRIx64 " value:0x%02" PRIx64
m48txx_nvram_io_write(uint64_t addr, uint64_t value) "io write addr:0x%04" PRIx64 " value:0x%02" PRIx64 m48txx_nvram_io_write(uint64_t addr, uint64_t value) "io write addr:0x%04" PRIx64 " value:0x%02" PRIx64

View File

@ -27,6 +27,7 @@
#include "qapi/visitor.h" #include "qapi/visitor.h"
#include "qemu/module.h" #include "qemu/module.h"
#include "hw/registerfields.h" #include "hw/registerfields.h"
#include "trace.h"
FIELD(CONFIG, SHUTDOWN_MODE, 0, 1) FIELD(CONFIG, SHUTDOWN_MODE, 0, 1)
FIELD(CONFIG, THERMOSTAT_MODE, 1, 1) FIELD(CONFIG, THERMOSTAT_MODE, 1, 1)
@ -150,17 +151,21 @@ static void tmp105_read(TMP105State *s)
s->buf[s->len++] = ((uint16_t) s->limit[1]) >> 0; s->buf[s->len++] = ((uint16_t) s->limit[1]) >> 0;
break; break;
} }
trace_tmp105_read(s->i2c.address, s->pointer);
} }
static void tmp105_write(TMP105State *s) static void tmp105_write(TMP105State *s)
{ {
trace_tmp105_write(s->i2c.address, s->pointer);
switch (s->pointer & 3) { switch (s->pointer & 3) {
case TMP105_REG_TEMPERATURE: case TMP105_REG_TEMPERATURE:
break; break;
case TMP105_REG_CONFIG: case TMP105_REG_CONFIG:
if (FIELD_EX8(s->buf[0] & ~s->config, CONFIG, SHUTDOWN_MODE)) { if (FIELD_EX8(s->buf[0] & ~s->config, CONFIG, SHUTDOWN_MODE)) {
printf("%s: TMP105 shutdown\n", __func__); trace_tmp105_write_shutdown(s->i2c.address);
} }
s->config = FIELD_DP8(s->buf[0], CONFIG, ONE_SHOT, 0); s->config = FIELD_DP8(s->buf[0], CONFIG, ONE_SHOT, 0);
s->faults = tmp105_faultq[FIELD_EX8(s->config, CONFIG, FAULT_QUEUE)]; s->faults = tmp105_faultq[FIELD_EX8(s->config, CONFIG, FAULT_QUEUE)];

6
hw/sensor/trace-events Normal file
View File

@ -0,0 +1,6 @@
# See docs/devel/tracing.rst for syntax documentation.
# tmp105.c
tmp105_read(uint8_t dev, uint8_t addr) "device: 0x%02x, addr: 0x%02x"
tmp105_write(uint8_t dev, uint8_t addr) "device: 0x%02x, addr 0x%02x"
tmp105_write_shutdown(uint8_t dev) "device: 0x%02x"

1
hw/sensor/trace.h Normal file
View File

@ -0,0 +1 @@
#include "trace/trace-hw_sensor.h"

View File

@ -18,19 +18,12 @@
#include "migration/vmstate.h" #include "migration/vmstate.h"
#include "qemu/module.h" #include "qemu/module.h"
#include "qemu/log.h" #include "qemu/log.h"
#include "trace.h"
#ifndef DEBUG_IMX_GPT #ifndef DEBUG_IMX_GPT
#define DEBUG_IMX_GPT 0 #define DEBUG_IMX_GPT 0
#endif #endif
#define DPRINTF(fmt, args...) \
do { \
if (DEBUG_IMX_GPT) { \
fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_GPT, \
__func__, ##args); \
} \
} while (0)
static const char *imx_gpt_reg_name(uint32_t reg) static const char *imx_gpt_reg_name(uint32_t reg)
{ {
switch (reg) { switch (reg) {
@ -145,7 +138,7 @@ static void imx_gpt_set_freq(IMXGPTState *s)
s->freq = imx_ccm_get_clock_frequency(s->ccm, s->freq = imx_ccm_get_clock_frequency(s->ccm,
s->clocks[clksrc]) / (1 + s->pr); s->clocks[clksrc]) / (1 + s->pr);
DPRINTF("Setting clksrc %d to frequency %d\n", clksrc, s->freq); trace_imx_gpt_set_freq(clksrc, s->freq);
if (s->freq) { if (s->freq) {
ptimer_set_freq(s->timer, s->freq); ptimer_set_freq(s->timer, s->freq);
@ -317,7 +310,7 @@ static uint64_t imx_gpt_read(void *opaque, hwaddr offset, unsigned size)
break; break;
} }
DPRINTF("(%s) = 0x%08x\n", imx_gpt_reg_name(offset >> 2), reg_value); trace_imx_gpt_read(imx_gpt_reg_name(offset >> 2), reg_value);
return reg_value; return reg_value;
} }
@ -384,8 +377,7 @@ static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value,
IMXGPTState *s = IMX_GPT(opaque); IMXGPTState *s = IMX_GPT(opaque);
uint32_t oldreg; uint32_t oldreg;
DPRINTF("(%s, value = 0x%08x)\n", imx_gpt_reg_name(offset >> 2), trace_imx_gpt_write(imx_gpt_reg_name(offset >> 2), (uint32_t)value);
(uint32_t)value);
switch (offset >> 2) { switch (offset >> 2) {
case 0: case 0:
@ -485,7 +477,7 @@ static void imx_gpt_timeout(void *opaque)
{ {
IMXGPTState *s = IMX_GPT(opaque); IMXGPTState *s = IMX_GPT(opaque);
DPRINTF("\n"); trace_imx_gpt_timeout();
s->sr |= s->next_int; s->sr |= s->next_int;
s->next_int = 0; s->next_int = 0;

View File

@ -49,6 +49,12 @@ cmsdk_apb_dualtimer_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK A
cmsdk_apb_dualtimer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB dualtimer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" cmsdk_apb_dualtimer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB dualtimer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
cmsdk_apb_dualtimer_reset(void) "CMSDK APB dualtimer: reset" cmsdk_apb_dualtimer_reset(void) "CMSDK APB dualtimer: reset"
# imx_gpt.c
imx_gpt_set_freq(uint32_t clksrc, uint32_t freq) "Setting clksrc %u to %u Hz"
imx_gpt_read(const char *name, uint64_t value) "%s -> 0x%08" PRIx64
imx_gpt_write(const char *name, uint64_t value) "%s <- 0x%08" PRIx64
imx_gpt_timeout(void) ""
# npcm7xx_timer.c # npcm7xx_timer.c
npcm7xx_timer_read(const char *id, uint64_t offset, uint64_t value) " %s offset: 0x%04" PRIx64 " value 0x%08" PRIx64 npcm7xx_timer_read(const char *id, uint64_t offset, uint64_t value) " %s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
npcm7xx_timer_write(const char *id, uint64_t offset, uint64_t value) "%s offset: 0x%04" PRIx64 " value 0x%08" PRIx64 npcm7xx_timer_write(const char *id, uint64_t offset, uint64_t value) "%s offset: 0x%04" PRIx64 " value 0x%08" PRIx64

View File

@ -39,7 +39,6 @@ static void imx2_wdt_expired(void *opaque)
/* Perform watchdog action if watchdog is enabled */ /* Perform watchdog action if watchdog is enabled */
if (s->wcr & IMX2_WDT_WCR_WDE) { if (s->wcr & IMX2_WDT_WCR_WDE) {
s->wrsr = IMX2_WDT_WRSR_TOUT;
watchdog_perform_action(); watchdog_perform_action();
} }
} }

View File

@ -4,6 +4,7 @@
#ifdef CONFIG_CAPSTONE #ifdef CONFIG_CAPSTONE
#define CAPSTONE_AARCH64_COMPAT_HEADER #define CAPSTONE_AARCH64_COMPAT_HEADER
#define CAPSTONE_SYSTEMZ_COMPAT_HEADER
#include <capstone.h> #include <capstone.h>
#else #else

View File

@ -75,6 +75,12 @@ static inline void set_floatx80_rounding_precision(FloatX80RoundPrec val,
status->floatx80_rounding_precision = val; status->floatx80_rounding_precision = val;
} }
static inline void set_float_2nan_prop_rule(Float2NaNPropRule rule,
float_status *status)
{
status->float_2nan_prop_rule = rule;
}
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;
@ -126,6 +132,11 @@ get_floatx80_rounding_precision(float_status *status)
return status->floatx80_rounding_precision; return status->floatx80_rounding_precision;
} }
static inline Float2NaNPropRule get_float_2nan_prop_rule(float_status *status)
{
return status->float_2nan_prop_rule;
}
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;

View File

@ -170,6 +170,43 @@ typedef enum __attribute__((__packed__)) {
floatx80_precision_s, floatx80_precision_s,
} FloatX80RoundPrec; } FloatX80RoundPrec;
/*
* 2-input NaN propagation rule. 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, 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_2nan_prop_none = 0,
/* Prefer SNaN over QNaN, then operand A over B */
float_2nan_prop_s_ab,
/* Prefer SNaN over QNaN, then operand B over A */
float_2nan_prop_s_ba,
/* Prefer A over B regardless of SNaN vs QNaN */
float_2nan_prop_ab,
/* Prefer B over A regardless of SNaN vs QNaN */
float_2nan_prop_ba,
/*
* 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).
*/
float_2nan_prop_x87,
} Float2NaNPropRule;
/* /*
* 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
@ -181,6 +218,7 @@ typedef struct float_status {
uint16_t float_exception_flags; uint16_t float_exception_flags;
FloatRoundMode float_rounding_mode; FloatRoundMode float_rounding_mode;
FloatX80RoundPrec floatx80_rounding_precision; FloatX80RoundPrec floatx80_rounding_precision;
Float2NaNPropRule float_2nan_prop_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;

View File

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

View File

@ -3484,6 +3484,7 @@ if have_system
'hw/s390x', 'hw/s390x',
'hw/scsi', 'hw/scsi',
'hw/sd', 'hw/sd',
'hw/sensor',
'hw/sh4', 'hw/sh4',
'hw/sparc', 'hw/sparc',
'hw/sparc64', 'hw/sparc64',

View File

@ -24,6 +24,7 @@
#include "qemu/qemu-print.h" #include "qemu/qemu-print.h"
#include "cpu.h" #include "cpu.h"
#include "exec/exec-all.h" #include "exec/exec-all.h"
#include "fpu/softfloat.h"
static void alpha_cpu_set_pc(CPUState *cs, vaddr value) static void alpha_cpu_set_pc(CPUState *cs, vaddr value)
@ -187,7 +188,17 @@ static void alpha_cpu_initfn(Object *obj)
{ {
CPUAlphaState *env = cpu_env(CPU(obj)); CPUAlphaState *env = cpu_env(CPU(obj));
/* TODO all this should be done in reset, not init */
env->lock_addr = -1; env->lock_addr = -1;
/*
* TODO: this is incorrect. The Alpha Architecture Handbook version 4
* describes NaN propagation in section 4.7.10.4. We should prefer
* the operand in Fb (whether it is a QNaN or an SNaN), then the
* operand in Fa. That is float_2nan_prop_ba.
*/
set_float_2nan_prop_rule(float_2nan_prop_x87, &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

View File

@ -802,6 +802,11 @@ static inline bool isar_feature_aa64_tidcp1(const ARMISARegisters *id)
return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, TIDCP1) != 0; return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, TIDCP1) != 0;
} }
static inline bool isar_feature_aa64_cmow(const ARMISARegisters *id)
{
return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, CMOW) != 0;
}
static inline bool isar_feature_aa64_hafs(const ARMISARegisters *id) static inline bool isar_feature_aa64_hafs(const ARMISARegisters *id)
{ {
return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, HAFDBS) != 0; return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, HAFDBS) != 0;

View File

@ -168,6 +168,18 @@ void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook,
QLIST_INSERT_HEAD(&cpu->el_change_hooks, entry, node); QLIST_INSERT_HEAD(&cpu->el_change_hooks, entry, node);
} }
/*
* Set the float_status behaviour to match the Arm defaults:
* * tininess-before-rounding
* * 2-input NaN propagation prefers SNaN over QNaN, and then
* operand A over operand B (see FPProcessNaNs() pseudocode)
*/
static void arm_set_default_fp_behaviours(float_status *s)
{
set_float_detect_tininess(float_tininess_before_rounding, s);
set_float_2nan_prop_rule(float_2nan_prop_s_ab, s);
}
static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque) static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
{ {
/* Reset a single ARMCPRegInfo register */ /* Reset a single ARMCPRegInfo register */
@ -549,14 +561,11 @@ static void arm_cpu_reset_hold(Object *obj, ResetType type)
set_flush_inputs_to_zero(1, &env->vfp.standard_fp_status); set_flush_inputs_to_zero(1, &env->vfp.standard_fp_status);
set_default_nan_mode(1, &env->vfp.standard_fp_status); set_default_nan_mode(1, &env->vfp.standard_fp_status);
set_default_nan_mode(1, &env->vfp.standard_fp_status_f16); set_default_nan_mode(1, &env->vfp.standard_fp_status_f16);
set_float_detect_tininess(float_tininess_before_rounding, arm_set_default_fp_behaviours(&env->vfp.fp_status);
&env->vfp.fp_status); arm_set_default_fp_behaviours(&env->vfp.standard_fp_status);
set_float_detect_tininess(float_tininess_before_rounding, arm_set_default_fp_behaviours(&env->vfp.fp_status_f16);
&env->vfp.standard_fp_status); arm_set_default_fp_behaviours(&env->vfp.standard_fp_status_f16);
set_float_detect_tininess(float_tininess_before_rounding,
&env->vfp.fp_status_f16);
set_float_detect_tininess(float_tininess_before_rounding,
&env->vfp.standard_fp_status_f16);
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
if (kvm_enabled()) { if (kvm_enabled()) {
kvm_arm_reset_vcpu(cpu); kvm_arm_reset_vcpu(cpu);

View File

@ -1367,6 +1367,7 @@ void pmu_init(ARMCPU *cpu);
#define SCTLR_EnIB (1U << 30) /* v8.3, AArch64 only */ #define SCTLR_EnIB (1U << 30) /* v8.3, AArch64 only */
#define SCTLR_EnIA (1U << 31) /* v8.3, AArch64 only */ #define SCTLR_EnIA (1U << 31) /* v8.3, AArch64 only */
#define SCTLR_DSSBS_32 (1U << 31) /* v8.5, AArch32 only */ #define SCTLR_DSSBS_32 (1U << 31) /* v8.5, AArch32 only */
#define SCTLR_CMOW (1ULL << 32) /* FEAT_CMOW */
#define SCTLR_MSCEN (1ULL << 33) /* FEAT_MOPS */ #define SCTLR_MSCEN (1ULL << 33) /* FEAT_MOPS */
#define SCTLR_BT0 (1ULL << 35) /* v8.5-BTI */ #define SCTLR_BT0 (1ULL << 35) /* v8.5-BTI */
#define SCTLR_BT1 (1ULL << 36) /* v8.5-BTI */ #define SCTLR_BT1 (1ULL << 36) /* v8.5-BTI */
@ -2805,38 +2806,38 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync);
* The only use of stage 2 translations is either as part of an s1+2 * The only use of stage 2 translations is either as part of an s1+2
* lookup or when loading the descriptors during a stage 1 page table walk, * lookup or when loading the descriptors during a stage 1 page table walk,
* and in both those cases we don't use the TLB. * and in both those cases we don't use the TLB.
* 4. we want to be able to use the TLB for accesses done as part of a * 4. we can also safely fold together the "32 bit EL3" and "64 bit EL3"
* translation regimes, because they map reasonably well to each other
* and they can't both be active at the same time.
* 5. we want to be able to use the TLB for accesses done as part of a
* stage1 page table walk, rather than having to walk the stage2 page * stage1 page table walk, rather than having to walk the stage2 page
* table over and over. * table over and over.
* 5. we need separate EL1/EL2 mmu_idx for handling the Privileged Access * 6. we need separate EL1/EL2 mmu_idx for handling the Privileged Access
* Never (PAN) bit within PSTATE. * Never (PAN) bit within PSTATE.
* 6. we fold together most secure and non-secure regimes for A-profile, * 7. we fold together most secure and non-secure regimes for A-profile,
* because there are no banked system registers for aarch64, so the * because there are no banked system registers for aarch64, so the
* process of switching between secure and non-secure is * process of switching between secure and non-secure is
* already heavyweight. * already heavyweight.
* 7. we cannot fold together Stage 2 Secure and Stage 2 NonSecure, * 8. we cannot fold together Stage 2 Secure and Stage 2 NonSecure,
* because both are in use simultaneously for Secure EL2. * because both are in use simultaneously for Secure EL2.
* *
* This gives us the following list of cases: * This gives us the following list of cases:
* *
* EL0 EL1&0 stage 1+2 (or AArch32 PL0 PL1&0 stage 1+2) * EL0 EL1&0 stage 1+2 (aka NS PL0 PL1&0 stage 1+2)
* EL1 EL1&0 stage 1+2 (or AArch32 PL1 PL1&0 stage 1+2) * EL1 EL1&0 stage 1+2 (aka NS PL1 PL1&0 stage 1+2)
* EL1 EL1&0 stage 1+2 +PAN (or AArch32 PL1 PL1&0 stage 1+2 +PAN) * EL1 EL1&0 stage 1+2 +PAN (aka NS PL1 P1&0 stage 1+2 +PAN)
* EL0 EL2&0 * EL0 EL2&0
* EL2 EL2&0 * EL2 EL2&0
* EL2 EL2&0 +PAN * EL2 EL2&0 +PAN
* EL2 (aka NS PL2) * EL2 (aka NS PL2)
* EL3 (not used when EL3 is AArch32) * EL3 (aka AArch32 S PL1 PL1&0)
* AArch32 S PL0 PL1&0 (we call this EL30_0)
* AArch32 S PL1 PL1&0 +PAN (we call this EL30_3_PAN)
* Stage2 Secure * Stage2 Secure
* Stage2 NonSecure * Stage2 NonSecure
* plus one TLB per Physical address space: S, NS, Realm, Root * plus one TLB per Physical address space: S, NS, Realm, Root
* *
* for a total of 14 different mmu_idx. * for a total of 16 different mmu_idx.
*
* Note that when EL3 is AArch32, the usage is potentially confusing
* because the MMU indexes are named for their AArch64 use, so code
* using the ARMMMUIdx_E10_1 might be at EL3, not EL1. This is because
* Secure PL1 is always at EL3.
* *
* R profile CPUs have an MPU, but can use the same set of MMU indexes * R profile CPUs have an MPU, but can use the same set of MMU indexes
* as A profile. They only need to distinguish EL0 and EL1 (and * as A profile. They only need to distinguish EL0 and EL1 (and
@ -2900,6 +2901,8 @@ typedef enum ARMMMUIdx {
ARMMMUIdx_E20_2_PAN = 5 | ARM_MMU_IDX_A, ARMMMUIdx_E20_2_PAN = 5 | ARM_MMU_IDX_A,
ARMMMUIdx_E2 = 6 | ARM_MMU_IDX_A, ARMMMUIdx_E2 = 6 | ARM_MMU_IDX_A,
ARMMMUIdx_E3 = 7 | ARM_MMU_IDX_A, ARMMMUIdx_E3 = 7 | ARM_MMU_IDX_A,
ARMMMUIdx_E30_0 = 8 | ARM_MMU_IDX_A,
ARMMMUIdx_E30_3_PAN = 9 | ARM_MMU_IDX_A,
/* /*
* Used for second stage of an S12 page table walk, or for descriptor * Used for second stage of an S12 page table walk, or for descriptor
@ -2907,14 +2910,14 @@ typedef enum ARMMMUIdx {
* are in use simultaneously for SecureEL2: the security state for * are in use simultaneously for SecureEL2: the security state for
* the S2 ptw is selected by the NS bit from the S1 ptw. * the S2 ptw is selected by the NS bit from the S1 ptw.
*/ */
ARMMMUIdx_Stage2_S = 8 | ARM_MMU_IDX_A, ARMMMUIdx_Stage2_S = 10 | ARM_MMU_IDX_A,
ARMMMUIdx_Stage2 = 9 | ARM_MMU_IDX_A, ARMMMUIdx_Stage2 = 11 | ARM_MMU_IDX_A,
/* TLBs with 1-1 mapping to the physical address spaces. */ /* TLBs with 1-1 mapping to the physical address spaces. */
ARMMMUIdx_Phys_S = 10 | ARM_MMU_IDX_A, ARMMMUIdx_Phys_S = 12 | ARM_MMU_IDX_A,
ARMMMUIdx_Phys_NS = 11 | ARM_MMU_IDX_A, ARMMMUIdx_Phys_NS = 13 | ARM_MMU_IDX_A,
ARMMMUIdx_Phys_Root = 12 | ARM_MMU_IDX_A, ARMMMUIdx_Phys_Root = 14 | ARM_MMU_IDX_A,
ARMMMUIdx_Phys_Realm = 13 | ARM_MMU_IDX_A, ARMMMUIdx_Phys_Realm = 15 | ARM_MMU_IDX_A,
/* /*
* These are not allocated TLBs and are used only for AT system * These are not allocated TLBs and are used only for AT system
@ -2953,6 +2956,8 @@ typedef enum ARMMMUIdxBit {
TO_CORE_BIT(E20_2), TO_CORE_BIT(E20_2),
TO_CORE_BIT(E20_2_PAN), TO_CORE_BIT(E20_2_PAN),
TO_CORE_BIT(E3), TO_CORE_BIT(E3),
TO_CORE_BIT(E30_0),
TO_CORE_BIT(E30_3_PAN),
TO_CORE_BIT(Stage2), TO_CORE_BIT(Stage2),
TO_CORE_BIT(Stage2_S), TO_CORE_BIT(Stage2_S),
@ -3130,10 +3135,6 @@ FIELD(TBFLAG_A32, NS, 10, 1)
* This requires an SME trap from AArch32 mode when using NEON. * This requires an SME trap from AArch32 mode when using NEON.
*/ */
FIELD(TBFLAG_A32, SME_TRAP_NONSTREAMING, 11, 1) FIELD(TBFLAG_A32, SME_TRAP_NONSTREAMING, 11, 1)
/*
* Indicates whether we are in the Secure PL1&0 translation regime
*/
FIELD(TBFLAG_A32, S_PL1_0, 12, 1)
/* /*
* Bit usage when in AArch32 state, for M-profile only. * Bit usage when in AArch32 state, for M-profile only.

View File

@ -444,6 +444,9 @@ static int alle1_tlbmask(CPUARMState *env)
* Note that the 'ALL' scope must invalidate both stage 1 and * Note that the 'ALL' scope must invalidate both stage 1 and
* stage 2 translations, whereas most other scopes only invalidate * stage 2 translations, whereas most other scopes only invalidate
* stage 1 translations. * stage 1 translations.
*
* For AArch32 this is only used for TLBIALLNSNH and VTTBR
* writes, so only needs to apply to NS PL1&0, not S PL1&0.
*/ */
return (ARMMMUIdxBit_E10_1 | return (ARMMMUIdxBit_E10_1 |
ARMMMUIdxBit_E10_1_PAN | ARMMMUIdxBit_E10_1_PAN |
@ -3701,7 +3704,7 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value,
*/ */
format64 = arm_s1_regime_using_lpae_format(env, mmu_idx); format64 = arm_s1_regime_using_lpae_format(env, mmu_idx);
if (arm_feature(env, ARM_FEATURE_EL2) && !arm_aa32_secure_pl1_0(env)) { if (arm_feature(env, ARM_FEATURE_EL2)) {
if (mmu_idx == ARMMMUIdx_E10_0 || if (mmu_idx == ARMMMUIdx_E10_0 ||
mmu_idx == ARMMMUIdx_E10_1 || mmu_idx == ARMMMUIdx_E10_1 ||
mmu_idx == ARMMMUIdx_E10_1_PAN) { mmu_idx == ARMMMUIdx_E10_1_PAN) {
@ -3775,11 +3778,17 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
case 0: case 0:
/* stage 1 current state PL1: ATS1CPR, ATS1CPW, ATS1CPRP, ATS1CPWP */ /* stage 1 current state PL1: ATS1CPR, ATS1CPW, ATS1CPRP, ATS1CPWP */
switch (el) { switch (el) {
case 3:
if (ri->crm == 9 && arm_pan_enabled(env)) {
mmu_idx = ARMMMUIdx_E30_3_PAN;
} else {
mmu_idx = ARMMMUIdx_E3;
}
break;
case 2: case 2:
g_assert(ss != ARMSS_Secure); /* ARMv8.4-SecEL2 is 64-bit only */ g_assert(ss != ARMSS_Secure); /* ARMv8.4-SecEL2 is 64-bit only */
/* fall through */ /* fall through */
case 1: case 1:
case 3:
if (ri->crm == 9 && arm_pan_enabled(env)) { if (ri->crm == 9 && arm_pan_enabled(env)) {
mmu_idx = ARMMMUIdx_Stage1_E1_PAN; mmu_idx = ARMMMUIdx_Stage1_E1_PAN;
} else { } else {
@ -3794,7 +3803,7 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
/* stage 1 current state PL0: ATS1CUR, ATS1CUW */ /* stage 1 current state PL0: ATS1CUR, ATS1CUW */
switch (el) { switch (el) {
case 3: case 3:
mmu_idx = ARMMMUIdx_E10_0; mmu_idx = ARMMMUIdx_E30_0;
break; break;
case 2: case 2:
g_assert(ss != ARMSS_Secure); /* ARMv8.4-SecEL2 is 64-bit only */ g_assert(ss != ARMSS_Secure); /* ARMv8.4-SecEL2 is 64-bit only */
@ -4904,11 +4913,14 @@ static int vae1_tlbmask(CPUARMState *env)
uint64_t hcr = arm_hcr_el2_eff(env); uint64_t hcr = arm_hcr_el2_eff(env);
uint16_t mask; uint16_t mask;
assert(arm_feature(env, ARM_FEATURE_AARCH64));
if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) { if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) {
mask = ARMMMUIdxBit_E20_2 | mask = ARMMMUIdxBit_E20_2 |
ARMMMUIdxBit_E20_2_PAN | ARMMMUIdxBit_E20_2_PAN |
ARMMMUIdxBit_E20_0; ARMMMUIdxBit_E20_0;
} else { } else {
/* This is AArch64 only, so we don't need to touch the EL30_x TLBs */
mask = ARMMMUIdxBit_E10_1 | mask = ARMMMUIdxBit_E10_1 |
ARMMMUIdxBit_E10_1_PAN | ARMMMUIdxBit_E10_1_PAN |
ARMMMUIdxBit_E10_0; ARMMMUIdxBit_E10_0;
@ -4947,6 +4959,8 @@ static int vae1_tlbbits(CPUARMState *env, uint64_t addr)
uint64_t hcr = arm_hcr_el2_eff(env); uint64_t hcr = arm_hcr_el2_eff(env);
ARMMMUIdx mmu_idx; ARMMMUIdx mmu_idx;
assert(arm_feature(env, ARM_FEATURE_AARCH64));
/* Only the regime of the mmu_idx below is significant. */ /* Only the regime of the mmu_idx below is significant. */
if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) { if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) {
mmu_idx = ARMMMUIdx_E20_0; mmu_idx = ARMMMUIdx_E20_0;
@ -6215,6 +6229,11 @@ static void hcrx_write(CPUARMState *env, const ARMCPRegInfo *ri,
if (cpu_isar_feature(aa64_nmi, cpu)) { if (cpu_isar_feature(aa64_nmi, cpu)) {
valid_mask |= HCRX_TALLINT | HCRX_VINMI | HCRX_VFNMI; valid_mask |= HCRX_TALLINT | HCRX_VINMI | HCRX_VFNMI;
} }
/* FEAT_CMOW adds CMOW */
if (cpu_isar_feature(aa64_cmow, cpu)) {
valid_mask |= HCRX_CMOW;
}
/* Clear RES0 bits. */ /* Clear RES0 bits. */
env->cp15.hcrx_el2 = value & valid_mask; env->cp15.hcrx_el2 = value & valid_mask;
@ -11860,13 +11879,20 @@ void arm_cpu_do_interrupt(CPUState *cs)
uint64_t arm_sctlr(CPUARMState *env, int el) uint64_t arm_sctlr(CPUARMState *env, int el)
{ {
if (arm_aa32_secure_pl1_0(env)) { /* Only EL0 needs to be adjusted for EL1&0 or EL2&0 or EL3&0 */
/* In Secure PL1&0 SCTLR_S is always controlling */ if (el == 0) {
el = 3;
} else if (el == 0) {
/* Only EL0 needs to be adjusted for EL1&0 or EL2&0. */
ARMMMUIdx mmu_idx = arm_mmu_idx_el(env, 0); ARMMMUIdx mmu_idx = arm_mmu_idx_el(env, 0);
el = mmu_idx == ARMMMUIdx_E20_0 ? 2 : 1; switch (mmu_idx) {
case ARMMMUIdx_E20_0:
el = 2;
break;
case ARMMMUIdx_E30_0:
el = 3;
break;
default:
el = 1;
break;
}
} }
return env->cp15.sctlr_el[el]; return env->cp15.sctlr_el[el];
} }
@ -12524,12 +12550,8 @@ int fp_exception_el(CPUARMState *env, int cur_el)
return 0; return 0;
} }
/* /* Return the exception level we're running at if this is our mmu_idx */
* Return the exception level we're running at if this is our mmu_idx. int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx)
* s_pl1_0 should be true if this is the AArch32 Secure PL1&0 translation
* regime.
*/
int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx, bool s_pl1_0)
{ {
if (mmu_idx & ARM_MMU_IDX_M) { if (mmu_idx & ARM_MMU_IDX_M) {
return mmu_idx & ARM_MMU_IDX_M_PRIV; return mmu_idx & ARM_MMU_IDX_M_PRIV;
@ -12538,15 +12560,17 @@ int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx, bool s_pl1_0)
switch (mmu_idx) { switch (mmu_idx) {
case ARMMMUIdx_E10_0: case ARMMMUIdx_E10_0:
case ARMMMUIdx_E20_0: case ARMMMUIdx_E20_0:
case ARMMMUIdx_E30_0:
return 0; return 0;
case ARMMMUIdx_E10_1: case ARMMMUIdx_E10_1:
case ARMMMUIdx_E10_1_PAN: case ARMMMUIdx_E10_1_PAN:
return s_pl1_0 ? 3 : 1; return 1;
case ARMMMUIdx_E2: case ARMMMUIdx_E2:
case ARMMMUIdx_E20_2: case ARMMMUIdx_E20_2:
case ARMMMUIdx_E20_2_PAN: case ARMMMUIdx_E20_2_PAN:
return 2; return 2;
case ARMMMUIdx_E3: case ARMMMUIdx_E3:
case ARMMMUIdx_E30_3_PAN:
return 3; return 3;
default: default:
g_assert_not_reached(); g_assert_not_reached();
@ -12575,19 +12599,13 @@ ARMMMUIdx arm_mmu_idx_el(CPUARMState *env, int el)
hcr = arm_hcr_el2_eff(env); hcr = arm_hcr_el2_eff(env);
if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) { if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) {
idx = ARMMMUIdx_E20_0; idx = ARMMMUIdx_E20_0;
} else if (arm_is_secure_below_el3(env) &&
!arm_el_is_aa64(env, 3)) {
idx = ARMMMUIdx_E30_0;
} else { } else {
idx = ARMMMUIdx_E10_0; idx = ARMMMUIdx_E10_0;
} }
break; break;
case 3:
/*
* AArch64 EL3 has its own translation regime; AArch32 EL3
* uses the Secure PL1&0 translation regime.
*/
if (arm_el_is_aa64(env, 3)) {
return ARMMMUIdx_E3;
}
/* fall through */
case 1: case 1:
if (arm_pan_enabled(env)) { if (arm_pan_enabled(env)) {
idx = ARMMMUIdx_E10_1_PAN; idx = ARMMMUIdx_E10_1_PAN;
@ -12607,6 +12625,11 @@ ARMMMUIdx arm_mmu_idx_el(CPUARMState *env, int el)
idx = ARMMMUIdx_E2; idx = ARMMMUIdx_E2;
} }
break; break;
case 3:
if (!arm_el_is_aa64(env, 3) && arm_pan_enabled(env)) {
return ARMMMUIdx_E30_3_PAN;
}
return ARMMMUIdx_E3;
default: default:
g_assert_not_reached(); g_assert_not_reached();
} }

View File

@ -275,20 +275,6 @@ FIELD(CNTHCTL, CNTPMASK, 19, 1)
#define M_FAKE_FSR_NSC_EXEC 0xf /* NS executing in S&NSC memory */ #define M_FAKE_FSR_NSC_EXEC 0xf /* NS executing in S&NSC memory */
#define M_FAKE_FSR_SFAULT 0xe /* SecureFault INVTRAN, INVEP or AUVIOL */ #define M_FAKE_FSR_SFAULT 0xe /* SecureFault INVTRAN, INVEP or AUVIOL */
/**
* arm_aa32_secure_pl1_0(): Return true if in Secure PL1&0 regime
*
* Return true if the CPU is in the Secure PL1&0 translation regime.
* This requires that EL3 exists and is AArch32 and we are currently
* Secure. If this is the case then the ARMMMUIdx_E10* apply and
* mean we are in EL3, not EL1.
*/
static inline bool arm_aa32_secure_pl1_0(CPUARMState *env)
{
return arm_feature(env, ARM_FEATURE_EL3) &&
!arm_el_is_aa64(env, 3) && arm_is_secure(env);
}
/** /**
* raise_exception: Raise the specified exception. * raise_exception: Raise the specified exception.
* Raise a guest exception with the specified value, syndrome register * Raise a guest exception with the specified value, syndrome register
@ -841,12 +827,7 @@ static inline ARMMMUIdx core_to_aa64_mmu_idx(int mmu_idx)
return mmu_idx | ARM_MMU_IDX_A; return mmu_idx | ARM_MMU_IDX_A;
} }
/** int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx);
* Return the exception level we're running at if our current MMU index
* is @mmu_idx. @s_pl1_0 should be true if this is the AArch32
* Secure PL1&0 translation regime.
*/
int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx, bool s_pl1_0);
/* Return the MMU index for a v7M CPU in the specified security state */ /* Return the MMU index for a v7M CPU in the specified security state */
ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate); ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate);
@ -890,7 +871,16 @@ static inline void arm_call_el_change_hook(ARMCPU *cpu)
} }
} }
/* Return true if this address translation regime has two ranges. */ /*
* Return true if this address translation regime has two ranges.
* Note that this will not return the correct answer for AArch32
* Secure PL1&0 (i.e. mmu indexes E3, E30_0, E30_3_PAN), but it is
* never called from a context where EL3 can be AArch32. (The
* correct return value for ARMMMUIdx_E3 would be different for
* that case, so we can't just make the function return the
* correct value anyway; we would need an extra "bool e3_is_aarch32"
* argument which all the current callsites would pass as 'false'.)
*/
static inline bool regime_has_2_ranges(ARMMMUIdx mmu_idx) static inline bool regime_has_2_ranges(ARMMMUIdx mmu_idx)
{ {
switch (mmu_idx) { switch (mmu_idx) {
@ -915,6 +905,7 @@ static inline bool regime_is_pan(CPUARMState *env, ARMMMUIdx mmu_idx)
case ARMMMUIdx_Stage1_E1_PAN: case ARMMMUIdx_Stage1_E1_PAN:
case ARMMMUIdx_E10_1_PAN: case ARMMMUIdx_E10_1_PAN:
case ARMMMUIdx_E20_2_PAN: case ARMMMUIdx_E20_2_PAN:
case ARMMMUIdx_E30_3_PAN:
return true; return true;
default: default:
return false; return false;
@ -938,14 +929,15 @@ static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx)
case ARMMMUIdx_E2: case ARMMMUIdx_E2:
return 2; return 2;
case ARMMMUIdx_E3: case ARMMMUIdx_E3:
case ARMMMUIdx_E30_0:
case ARMMMUIdx_E30_3_PAN:
return 3; return 3;
case ARMMMUIdx_E10_0: case ARMMMUIdx_E10_0:
case ARMMMUIdx_Stage1_E0: case ARMMMUIdx_Stage1_E0:
case ARMMMUIdx_E10_1:
case ARMMMUIdx_E10_1_PAN:
case ARMMMUIdx_Stage1_E1: case ARMMMUIdx_Stage1_E1:
case ARMMMUIdx_Stage1_E1_PAN: case ARMMMUIdx_Stage1_E1_PAN:
return arm_el_is_aa64(env, 3) || !arm_is_secure_below_el3(env) ? 1 : 3; case ARMMMUIdx_E10_1:
case ARMMMUIdx_E10_1_PAN:
case ARMMMUIdx_MPrivNegPri: case ARMMMUIdx_MPrivNegPri:
case ARMMMUIdx_MUserNegPri: case ARMMMUIdx_MUserNegPri:
case ARMMMUIdx_MPriv: case ARMMMUIdx_MPriv:
@ -965,6 +957,7 @@ static inline bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx)
switch (mmu_idx) { switch (mmu_idx) {
case ARMMMUIdx_E10_0: case ARMMMUIdx_E10_0:
case ARMMMUIdx_E20_0: case ARMMMUIdx_E20_0:
case ARMMMUIdx_E30_0:
case ARMMMUIdx_Stage1_E0: case ARMMMUIdx_Stage1_E0:
case ARMMMUIdx_MUser: case ARMMMUIdx_MUser:
case ARMMMUIdx_MSUser: case ARMMMUIdx_MSUser:

View File

@ -280,6 +280,8 @@ static bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx,
case ARMMMUIdx_E20_2_PAN: case ARMMMUIdx_E20_2_PAN:
case ARMMMUIdx_E2: case ARMMMUIdx_E2:
case ARMMMUIdx_E3: case ARMMMUIdx_E3:
case ARMMMUIdx_E30_0:
case ARMMMUIdx_E30_3_PAN:
break; break;
case ARMMMUIdx_Phys_S: case ARMMMUIdx_Phys_S:
@ -3607,11 +3609,7 @@ bool get_phys_addr(CPUARMState *env, vaddr address,
case ARMMMUIdx_Stage1_E1: case ARMMMUIdx_Stage1_E1:
case ARMMMUIdx_Stage1_E1_PAN: case ARMMMUIdx_Stage1_E1_PAN:
case ARMMMUIdx_E2: case ARMMMUIdx_E2:
if (arm_aa32_secure_pl1_0(env)) { ss = arm_security_space_below_el3(env);
ss = ARMSS_Secure;
} else {
ss = arm_security_space_below_el3(env);
}
break; break;
case ARMMMUIdx_Stage2: case ARMMMUIdx_Stage2:
/* /*
@ -3639,6 +3637,8 @@ bool get_phys_addr(CPUARMState *env, vaddr address,
ss = ARMSS_Secure; ss = ARMSS_Secure;
break; break;
case ARMMMUIdx_E3: case ARMMMUIdx_E3:
case ARMMMUIdx_E30_0:
case ARMMMUIdx_E30_3_PAN:
if (arm_feature(env, ARM_FEATURE_AARCH64) && if (arm_feature(env, ARM_FEATURE_AARCH64) &&
cpu_isar_feature(aa64_rme, env_archcpu(env))) { cpu_isar_feature(aa64_rme, env_archcpu(env))) {
ss = ARMSS_Root; ss = ARMSS_Root;

View File

@ -1218,6 +1218,7 @@ void aarch64_max_tcg_initfn(Object *obj)
t = FIELD_DP64(t, ID_AA64MMFR1, ETS, 2); /* FEAT_ETS2 */ t = FIELD_DP64(t, ID_AA64MMFR1, ETS, 2); /* FEAT_ETS2 */
t = FIELD_DP64(t, ID_AA64MMFR1, HCX, 1); /* FEAT_HCX */ t = FIELD_DP64(t, ID_AA64MMFR1, HCX, 1); /* FEAT_HCX */
t = FIELD_DP64(t, ID_AA64MMFR1, TIDCP1, 1); /* FEAT_TIDCP1 */ t = FIELD_DP64(t, ID_AA64MMFR1, TIDCP1, 1); /* FEAT_TIDCP1 */
t = FIELD_DP64(t, ID_AA64MMFR1, CMOW, 1); /* FEAT_CMOW */
cpu->isar.id_aa64mmfr1 = t; cpu->isar.id_aa64mmfr1 = t;
t = cpu->isar.id_aa64mmfr2; t = cpu->isar.id_aa64mmfr2;

View File

@ -198,10 +198,6 @@ static CPUARMTBFlags rebuild_hflags_a32(CPUARMState *env, int fp_el,
DP_TBFLAG_A32(flags, SME_TRAP_NONSTREAMING, 1); DP_TBFLAG_A32(flags, SME_TRAP_NONSTREAMING, 1);
} }
if (arm_aa32_secure_pl1_0(env)) {
DP_TBFLAG_A32(flags, S_PL1_0, 1);
}
return rebuild_hflags_common_32(env, fp_el, mmu_idx, flags); return rebuild_hflags_common_32(env, fp_el, mmu_idx, flags);
} }

View File

@ -912,7 +912,19 @@ void HELPER(tidcp_el0)(CPUARMState *env, uint32_t syndrome)
{ {
/* See arm_sctlr(), but we also need the sctlr el. */ /* See arm_sctlr(), but we also need the sctlr el. */
ARMMMUIdx mmu_idx = arm_mmu_idx_el(env, 0); ARMMMUIdx mmu_idx = arm_mmu_idx_el(env, 0);
int target_el = mmu_idx == ARMMMUIdx_E20_0 ? 2 : 1; int target_el;
switch (mmu_idx) {
case ARMMMUIdx_E20_0:
target_el = 2;
break;
case ARMMMUIdx_E30_0:
target_el = 3;
break;
default:
target_el = 1;
break;
}
/* /*
* The bit is not valid unless the target el is aa64, but since the * The bit is not valid unless the target el is aa64, but since the

View File

@ -11690,7 +11690,7 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
dc->tbii = EX_TBFLAG_A64(tb_flags, TBII); dc->tbii = EX_TBFLAG_A64(tb_flags, TBII);
dc->tbid = EX_TBFLAG_A64(tb_flags, TBID); dc->tbid = EX_TBFLAG_A64(tb_flags, TBID);
dc->tcma = EX_TBFLAG_A64(tb_flags, TCMA); dc->tcma = EX_TBFLAG_A64(tb_flags, TCMA);
dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx, false); dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
dc->user = (dc->current_el == 0); dc->user = (dc->current_el == 0);
#endif #endif

View File

@ -228,6 +228,9 @@ static inline int get_a32_user_mem_index(DisasContext *s)
*/ */
switch (s->mmu_idx) { switch (s->mmu_idx) {
case ARMMMUIdx_E3: case ARMMMUIdx_E3:
case ARMMMUIdx_E30_0:
case ARMMMUIdx_E30_3_PAN:
return arm_to_core_mmu_idx(ARMMMUIdx_E30_0);
case ARMMMUIdx_E2: /* this one is UNPREDICTABLE */ case ARMMMUIdx_E2: /* this one is UNPREDICTABLE */
case ARMMMUIdx_E10_0: case ARMMMUIdx_E10_0:
case ARMMMUIdx_E10_1: case ARMMMUIdx_E10_1:
@ -7546,6 +7549,10 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
core_mmu_idx = EX_TBFLAG_ANY(tb_flags, MMUIDX); core_mmu_idx = EX_TBFLAG_ANY(tb_flags, MMUIDX);
dc->mmu_idx = core_to_arm_mmu_idx(env, core_mmu_idx); dc->mmu_idx = core_to_arm_mmu_idx(env, core_mmu_idx);
dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
#if !defined(CONFIG_USER_ONLY)
dc->user = (dc->current_el == 0);
#endif
dc->fp_excp_el = EX_TBFLAG_ANY(tb_flags, FPEXC_EL); dc->fp_excp_el = EX_TBFLAG_ANY(tb_flags, FPEXC_EL);
dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM); dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM);
dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL); dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL);
@ -7576,12 +7583,7 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
} }
dc->sme_trap_nonstreaming = dc->sme_trap_nonstreaming =
EX_TBFLAG_A32(tb_flags, SME_TRAP_NONSTREAMING); EX_TBFLAG_A32(tb_flags, SME_TRAP_NONSTREAMING);
dc->s_pl1_0 = EX_TBFLAG_A32(tb_flags, S_PL1_0);
} }
dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx, dc->s_pl1_0);
#if !defined(CONFIG_USER_ONLY)
dc->user = (dc->current_el == 0);
#endif
dc->lse2 = false; /* applies only to aarch64 */ dc->lse2 = false; /* applies only to aarch64 */
dc->cp_regs = cpu->cp_regs; dc->cp_regs = cpu->cp_regs;
dc->features = env->features; dc->features = env->features;

View File

@ -165,8 +165,6 @@ typedef struct DisasContext {
uint8_t gm_blocksize; uint8_t gm_blocksize;
/* True if the current insn_start has been updated. */ /* True if the current insn_start has been updated. */
bool insn_start_updated; bool insn_start_updated;
/* True if this is the AArch32 Secure PL1&0 translation regime */
bool s_pl1_0;
/* Bottom two bits of XScale c15_cpar coprocessor access control reg */ /* Bottom two bits of XScale c15_cpar coprocessor access control reg */
int c15_cpar; int c15_cpar;
/* Offset from VNCR_EL2 when FEAT_NV2 redirects this reg to memory */ /* Offset from VNCR_EL2 when FEAT_NV2 redirects this reg to memory */

View File

@ -836,6 +836,13 @@ void HELPER(NAME)(void *vd, void *vn, void *vm, void *va, uint32_t desc) \
{ \ { \
intptr_t i = 0, opr_sz = simd_oprsz(desc); \ intptr_t i = 0, opr_sz = simd_oprsz(desc); \
intptr_t opr_sz_n = opr_sz / sizeof(TYPED); \ intptr_t opr_sz_n = opr_sz / sizeof(TYPED); \
/* \
* Special case: opr_sz == 8 from AA64/AA32 advsimd means the \
* first iteration might not be a full 16 byte segment. But \
* for vector lengths beyond that this must be SVE and we know \
* opr_sz is a multiple of 16, so we need not clamp segend \
* to opr_sz_n when we advance it at the end of the loop. \
*/ \
intptr_t segend = MIN(16 / sizeof(TYPED), opr_sz_n); \ intptr_t segend = MIN(16 / sizeof(TYPED), opr_sz_n); \
intptr_t index = simd_data(desc); \ intptr_t index = simd_data(desc); \
TYPED *d = vd, *a = va; \ TYPED *d = vd, *a = va; \
@ -853,7 +860,7 @@ void HELPER(NAME)(void *vd, void *vn, void *vm, void *va, uint32_t desc) \
n[i * 4 + 2] * m2 + \ n[i * 4 + 2] * m2 + \
n[i * 4 + 3] * m3); \ n[i * 4 + 3] * m3); \
} while (++i < segend); \ } while (++i < segend); \
segend = i + 4; \ segend = i + (16 / sizeof(TYPED)); \
} while (i < opr_sz_n); \ } while (i < opr_sz_n); \
clear_tail(d, opr_sz, simd_maxsz(desc)); \ clear_tail(d, opr_sz, simd_maxsz(desc)); \
} }

View File

@ -49,6 +49,12 @@ void HELPER(loaded_fr0)(CPUHPPAState *env)
d = FIELD_EX32(shadow, FPSR, D); d = FIELD_EX32(shadow, FPSR, D);
set_flush_to_zero(d, &env->fp_status); set_flush_to_zero(d, &env->fp_status);
set_flush_inputs_to_zero(d, &env->fp_status); set_flush_inputs_to_zero(d, &env->fp_status);
/*
* TODO: we only need to do this at CPU reset, but currently
* HPPA does note implement a CPU reset method at all...
*/
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fp_status);
} }
void cpu_hppa_loaded_fr0(CPUHPPAState *env) void cpu_hppa_loaded_fr0(CPUHPPAState *env)

View File

@ -7200,6 +7200,10 @@ static void x86_cpu_reset_hold(Object *obj, ResetType type)
memset(env, 0, offsetof(CPUX86State, end_reset_fields)); memset(env, 0, offsetof(CPUX86State, end_reset_fields));
if (tcg_enabled()) {
cpu_init_fp_statuses(env);
}
env->old_exception = -1; env->old_exception = -1;
/* init to reset state */ /* init to reset state */

View File

@ -2614,6 +2614,9 @@ static inline bool cpu_vmx_maybe_enabled(CPUX86State *env)
int get_pg_mode(CPUX86State *env); int get_pg_mode(CPUX86State *env);
/* fpu_helper.c */ /* fpu_helper.c */
/* Set all non-runtime-variable float_status fields to x86 handling */
void cpu_init_fp_statuses(CPUX86State *env);
void update_fp_status(CPUX86State *env); void update_fp_status(CPUX86State *env);
void update_mxcsr_status(CPUX86State *env); void update_mxcsr_status(CPUX86State *env);
void update_mxcsr_from_sse_status(CPUX86State *env); void update_mxcsr_from_sse_status(CPUX86State *env);

View File

@ -135,6 +135,46 @@ static void fpu_set_exception(CPUX86State *env, int mask)
} }
} }
void cpu_init_fp_statuses(CPUX86State *env)
{
/*
* Initialise the non-runtime-varying fields of the various
* float_status words to x86 behaviour. This must be called at
* CPU reset because the float_status words are in the
* "zeroed on reset" portion of the CPU state struct.
* Fields in float_status that vary under guest control are set
* via the codepath for setting that register, eg cpu_set_fpuc().
*/
/*
* Use 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).
*/
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status);
/*
* TODO: These are incorrect: the x86 Software Developer's Manual vol 1
* section 4.8.3.5 "Operating on SNaNs and QNaNs" says that the
* "larger significand" behaviour is only used for x87 FPU operations.
* For SSE the required behaviour is to always return the first NaN,
* which is float_2nan_prop_ab.
*
* mmx_status is used only for the AMD 3DNow! instructions, which
* are documented in the "3DNow! Technology Manual" as not supporting
* NaNs or infinities as inputs. The result of passing two NaNs is
* documented as "undefined", so we can do what we choose.
* (Strictly there is some behaviour we don't implement correctly
* for these "unsupported" NaN and Inf values, like "NaN * 0 == 0".)
*/
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->mmx_status);
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->sse_status);
}
static inline uint8_t save_exception_flags(CPUX86State *env) static inline uint8_t save_exception_flags(CPUX86State *env)
{ {
uint8_t old_flags = get_float_exception_flags(&env->fp_status); uint8_t old_flags = get_float_exception_flags(&env->fp_status);

View File

@ -31,6 +31,7 @@ void restore_fp_status(CPULoongArchState *env)
set_float_rounding_mode(ieee_rm[(env->fcsr0 >> FCSR0_RM) & 0x3], set_float_rounding_mode(ieee_rm[(env->fcsr0 >> FCSR0_RM) & 0x3],
&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);
} }
int ieee_ex_to_loongarch(int xcpt) int ieee_ex_to_loongarch(int xcpt)

View File

@ -93,6 +93,22 @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type)
env->fregs[i].d = nan; env->fregs[i].d = nan;
} }
cpu_m68k_set_fpcr(env, 0); cpu_m68k_set_fpcr(env, 0);
/*
* M68000 FAMILY PROGRAMMER'S REFERENCE MANUAL
* 3.4 FLOATING-POINT INSTRUCTION DETAILS
* If either operand, but not both operands, of an operation is a
* nonsignaling NaN, then that NaN is returned as the result. If both
* operands are nonsignaling NaNs, then the destination operand
* nonsignaling NaN is returned as the result.
* If either operand to an operation is a signaling NaN (SNaN), then the
* SNaN bit is set in the FPSR EXC byte. If the SNaN exception enable bit
* is set in the FPCR ENABLE byte, then the exception is taken and the
* destination is not modified. If the SNaN exception enable bit is not
* set, setting the SNaN bit in the operand to a one converts the SNaN to
* a nonsignaling NaN. The operation then continues as described in the
* preceding paragraph for nonsignaling NaNs.
*/
set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status);
env->fpsr = 0; env->fpsr = 0;
/* TODO: We should set PC from the interrupt vector. */ /* TODO: We should set PC from the interrupt vector. */

View File

@ -620,6 +620,7 @@ void HELPER(frem)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1)
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( set_floatx80_rounding_precision(
get_floatx80_rounding_precision(&env->fp_status), &fp_status); get_floatx80_rounding_precision(&env->fp_status), &fp_status);

View File

@ -36,7 +36,7 @@ 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; float_status s = {};
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 +56,7 @@ 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; float_status s = {};
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;
} }

View File

@ -201,6 +201,13 @@ static void mb_cpu_reset_hold(Object *obj, ResetType type)
env->pc = cpu->cfg.base_vectors; env->pc = cpu->cfg.base_vectors;
set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
/*
* TODO: this is probably not the correct NaN propagation rule for
* this architecture.
*/
set_float_2nan_prop_rule(float_2nan_prop_x87, &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. */
mb_cpu_write_msr(env, MSR_EE | MSR_IE | MSR_VM | MSR_UM); mb_cpu_write_msr(env, MSR_EE | MSR_IE | MSR_VM | MSR_UM);
@ -311,15 +318,12 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp)
static void mb_cpu_initfn(Object *obj) static void mb_cpu_initfn(Object *obj)
{ {
MicroBlazeCPU *cpu = MICROBLAZE_CPU(obj); MicroBlazeCPU *cpu = MICROBLAZE_CPU(obj);
CPUMBState *env = &cpu->env;
gdb_register_coprocessor(CPU(cpu), mb_cpu_gdb_read_stack_protect, gdb_register_coprocessor(CPU(cpu), mb_cpu_gdb_read_stack_protect,
mb_cpu_gdb_write_stack_protect, mb_cpu_gdb_write_stack_protect,
gdb_find_static_feature("microblaze-stack-protect.xml"), gdb_find_static_feature("microblaze-stack-protect.xml"),
0); 0);
set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
/* Inbound IRQ and FIR lines */ /* Inbound IRQ and FIR lines */
qdev_init_gpio_in(DEVICE(cpu), microblaze_cpu_set_irq, 2); qdev_init_gpio_in(DEVICE(cpu), microblaze_cpu_set_irq, 2);

View File

@ -407,9 +407,9 @@ static void mips_cpu_reset_hold(Object *obj, ResetType type)
} }
msa_reset(env); msa_reset(env);
fp_reset(env);
compute_hflags(env); compute_hflags(env);
restore_fp_status(env);
restore_pamask(env); restore_pamask(env);
cs->exception_index = EXCP_NONE; cs->exception_index = EXCP_NONE;

View File

@ -44,6 +44,28 @@ static inline void restore_fp_status(CPUMIPSState *env)
restore_snan_bit_mode(env); restore_snan_bit_mode(env);
} }
static inline void fp_reset(CPUMIPSState *env)
{
restore_fp_status(env);
/*
* According to MIPS specifications, if one of the two operands is
* a sNaN, a new qNaN has to be generated. This is done in
* floatXX_silence_nan(). For qNaN inputs the specifications
* says: "When possible, this QNaN result is one of the operand QNaN
* values." In practice it seems that most implementations choose
* the first operand if both operands are qNaN. In short this gives
* the following rules:
* 1. A if it is signaling
* 2. B if it is signaling
* 3. A (quiet)
* 4. B (quiet)
* A signaling NaN is always silenced before returning it.
*/
set_float_2nan_prop_rule(float_2nan_prop_s_ab,
&env->active_fpu.fp_status);
}
/* MSA */ /* MSA */
enum CPUMIPSMSADataFormat { enum CPUMIPSMSADataFormat {

View File

@ -49,6 +49,23 @@ void msa_reset(CPUMIPSState *env)
set_float_detect_tininess(float_tininess_after_rounding, set_float_detect_tininess(float_tininess_after_rounding,
&env->active_tc.msa_fp_status); &env->active_tc.msa_fp_status);
/*
* According to MIPS specifications, if one of the two operands is
* a sNaN, a new qNaN has to be generated. This is done in
* floatXX_silence_nan(). For qNaN inputs the specifications
* says: "When possible, this QNaN result is one of the operand QNaN
* values." In practice it seems that most implementations choose
* the first operand if both operands are qNaN. In short this gives
* the following rules:
* 1. A if it is signaling
* 2. B if it is signaling
* 3. A (quiet)
* 4. B (quiet)
* A signaling NaN is always silenced before returning it.
*/
set_float_2nan_prop_rule(float_2nan_prop_s_ab,
&env->active_tc.msa_fp_status);
/* 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);

View File

@ -105,6 +105,12 @@ static void openrisc_cpu_reset_hold(Object *obj, ResetType type)
set_float_detect_tininess(float_tininess_before_rounding, set_float_detect_tininess(float_tininess_before_rounding,
&cpu->env.fp_status); &cpu->env.fp_status);
/*
* TODO: this is probably not the correct NaN propagation rule for
* this architecture.
*/
set_float_2nan_prop_rule(float_2nan_prop_x87, &cpu->env.fp_status);
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
cpu->env.picmr = 0x00000000; cpu->env.picmr = 0x00000000;

View File

@ -7262,6 +7262,14 @@ static void ppc_cpu_reset_hold(Object *obj, ResetType type)
/* tininess for underflow is detected before rounding */ /* tininess for underflow is detected before rounding */
set_float_detect_tininess(float_tininess_before_rounding, set_float_detect_tininess(float_tininess_before_rounding,
&env->fp_status); &env->fp_status);
/*
* PowerPC propagation rules:
* 1. A if it sNaN or qNaN
* 2. B if it sNaN or qNaN
* A signaling NaN is always silenced before returning it.
*/
set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status);
set_float_2nan_prop_rule(float_2nan_prop_ab, &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];

View File

@ -93,6 +93,13 @@ static void rx_cpu_reset_hold(Object *obj, ResetType type)
env->fpsw = 0; env->fpsw = 0;
set_flush_to_zero(1, &env->fp_status); set_flush_to_zero(1, &env->fp_status);
set_flush_inputs_to_zero(1, &env->fp_status); set_flush_inputs_to_zero(1, &env->fp_status);
/*
* TODO: this is not the correct NaN propagation rule for this
* architecture. The "RX Family User's Manual: Software" table 1.6
* defines the propagation rules as "prefer SNaN over QNaN;
* then prefer dest over source", which is float_2nan_prop_s_ab.
*/
set_float_2nan_prop_rule(float_2nan_prop_x87, &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)

View File

@ -205,6 +205,7 @@ static void s390_cpu_reset_hold(Object *obj, ResetType type)
/* tininess for underflow is detected before rounding */ /* tininess for underflow is detected before rounding */
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);
/* 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;

View File

@ -26,6 +26,7 @@
#include "hw/qdev-properties.h" #include "hw/qdev-properties.h"
#include "qapi/visitor.h" #include "qapi/visitor.h"
#include "tcg/tcg.h" #include "tcg/tcg.h"
#include "fpu/softfloat.h"
//#define DEBUG_FEATURES //#define DEBUG_FEATURES
@ -76,6 +77,7 @@ static void sparc_cpu_reset_hold(Object *obj, ResetType type)
env->npc = env->pc + 4; env->npc = env->pc + 4;
#endif #endif
env->cache_control = 0; env->cache_control = 0;
cpu_put_fsr(env, 0);
} }
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
@ -805,7 +807,13 @@ static void sparc_cpu_realizefn(DeviceState *dev, Error **errp)
env->version |= env->def.maxtl << 8; env->version |= env->def.maxtl << 8;
env->version |= env->def.nwindows - 1; env->version |= env->def.nwindows - 1;
#endif #endif
cpu_put_fsr(env, 0);
/*
* Prefer SNaN over QNaN, order B then A. It's OK to do this in realize
* rather than reset, because fp_status is after 'end_reset_fields' in
* 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);
cpu_exec_realizefn(cs, &local_err); cpu_exec_realizefn(cs, &local_err);
if (local_err != NULL) { if (local_err != NULL) {

View File

@ -497,7 +497,10 @@ uint32_t helper_flcmps(float32 src1, float32 src2)
* Perform the comparison with a dummy fp environment. * Perform the comparison with a dummy fp environment.
*/ */
float_status discard = { }; float_status discard = { };
FloatRelation r = float32_compare_quiet(src1, src2, &discard); FloatRelation r;
set_float_2nan_prop_rule(float_2nan_prop_s_ba, &discard);
r = float32_compare_quiet(src1, src2, &discard);
switch (r) { switch (r) {
case float_relation_equal: case float_relation_equal:
@ -518,7 +521,10 @@ uint32_t helper_flcmps(float32 src1, float32 src2)
uint32_t helper_flcmpd(float64 src1, float64 src2) uint32_t helper_flcmpd(float64 src1, float64 src2)
{ {
float_status discard = { }; float_status discard = { };
FloatRelation r = float64_compare_quiet(src1, src2, &discard); FloatRelation r;
set_float_2nan_prop_rule(float_2nan_prop_s_ba, &discard);
r = float64_compare_quiet(src1, src2, &discard);
switch (r) { switch (r) {
case float_relation_equal: case float_relation_equal:

View File

@ -134,7 +134,7 @@ static void xtensa_cpu_reset_hold(Object *obj, ResetType type)
cs->halted = env->runstall; cs->halted = env->runstall;
#endif #endif
set_no_signaling_nans(!dfpu, &env->fp_status); set_no_signaling_nans(!dfpu, &env->fp_status);
set_use_first_nan(!dfpu, &env->fp_status); xtensa_use_first_nan(env, !dfpu);
} }
static ObjectClass *xtensa_cpu_class_by_name(const char *cpu_model) static ObjectClass *xtensa_cpu_class_by_name(const char *cpu_model)

View File

@ -802,4 +802,10 @@ static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, vaddr *pc,
XtensaCPU *xtensa_cpu_create_with_clock(const char *cpu_type, XtensaCPU *xtensa_cpu_create_with_clock(const char *cpu_type,
Clock *cpu_refclk); Clock *cpu_refclk);
/*
* Set the NaN propagation rule for future FPU operations:
* use_first is true to pick the first NaN as the result if both
* inputs are NaNs, false to pick the second.
*/
void xtensa_use_first_nan(CPUXtensaState *env, bool use_first);
#endif #endif

View File

@ -57,6 +57,13 @@ static const struct {
{ XTENSA_FP_V, float_flag_invalid, }, { XTENSA_FP_V, float_flag_invalid, },
}; };
void xtensa_use_first_nan(CPUXtensaState *env, bool use_first)
{
set_use_first_nan(use_first, &env->fp_status);
set_float_2nan_prop_rule(use_first ? float_2nan_prop_ab : float_2nan_prop_ba,
&env->fp_status);
}
void HELPER(wur_fpu2k_fcr)(CPUXtensaState *env, uint32_t v) void HELPER(wur_fpu2k_fcr)(CPUXtensaState *env, uint32_t v)
{ {
static const int rounding_mode[] = { static const int rounding_mode[] = {
@ -171,87 +178,87 @@ float32 HELPER(fpu2k_msub_s)(CPUXtensaState *env,
float64 HELPER(add_d)(CPUXtensaState *env, float64 a, float64 b) float64 HELPER(add_d)(CPUXtensaState *env, float64 a, float64 b)
{ {
set_use_first_nan(true, &env->fp_status); xtensa_use_first_nan(env, true);
return float64_add(a, b, &env->fp_status); return float64_add(a, b, &env->fp_status);
} }
float32 HELPER(add_s)(CPUXtensaState *env, float32 a, float32 b) float32 HELPER(add_s)(CPUXtensaState *env, float32 a, float32 b)
{ {
set_use_first_nan(env->config->use_first_nan, &env->fp_status); xtensa_use_first_nan(env, env->config->use_first_nan);
return float32_add(a, b, &env->fp_status); return float32_add(a, b, &env->fp_status);
} }
float64 HELPER(sub_d)(CPUXtensaState *env, float64 a, float64 b) float64 HELPER(sub_d)(CPUXtensaState *env, float64 a, float64 b)
{ {
set_use_first_nan(true, &env->fp_status); xtensa_use_first_nan(env, true);
return float64_sub(a, b, &env->fp_status); return float64_sub(a, b, &env->fp_status);
} }
float32 HELPER(sub_s)(CPUXtensaState *env, float32 a, float32 b) float32 HELPER(sub_s)(CPUXtensaState *env, float32 a, float32 b)
{ {
set_use_first_nan(env->config->use_first_nan, &env->fp_status); xtensa_use_first_nan(env, env->config->use_first_nan);
return float32_sub(a, b, &env->fp_status); return float32_sub(a, b, &env->fp_status);
} }
float64 HELPER(mul_d)(CPUXtensaState *env, float64 a, float64 b) float64 HELPER(mul_d)(CPUXtensaState *env, float64 a, float64 b)
{ {
set_use_first_nan(true, &env->fp_status); xtensa_use_first_nan(env, true);
return float64_mul(a, b, &env->fp_status); return float64_mul(a, b, &env->fp_status);
} }
float32 HELPER(mul_s)(CPUXtensaState *env, float32 a, float32 b) float32 HELPER(mul_s)(CPUXtensaState *env, float32 a, float32 b)
{ {
set_use_first_nan(env->config->use_first_nan, &env->fp_status); xtensa_use_first_nan(env, env->config->use_first_nan);
return float32_mul(a, b, &env->fp_status); return float32_mul(a, b, &env->fp_status);
} }
float64 HELPER(madd_d)(CPUXtensaState *env, float64 a, float64 b, float64 c) float64 HELPER(madd_d)(CPUXtensaState *env, float64 a, float64 b, float64 c)
{ {
set_use_first_nan(env->config->use_first_nan, &env->fp_status); xtensa_use_first_nan(env, env->config->use_first_nan);
return float64_muladd(b, c, a, 0, &env->fp_status); return float64_muladd(b, c, a, 0, &env->fp_status);
} }
float32 HELPER(madd_s)(CPUXtensaState *env, float32 a, float32 b, float32 c) float32 HELPER(madd_s)(CPUXtensaState *env, float32 a, float32 b, float32 c)
{ {
set_use_first_nan(env->config->use_first_nan, &env->fp_status); xtensa_use_first_nan(env, env->config->use_first_nan);
return float32_muladd(b, c, a, 0, &env->fp_status); return float32_muladd(b, c, a, 0, &env->fp_status);
} }
float64 HELPER(msub_d)(CPUXtensaState *env, float64 a, float64 b, float64 c) float64 HELPER(msub_d)(CPUXtensaState *env, float64 a, float64 b, float64 c)
{ {
set_use_first_nan(env->config->use_first_nan, &env->fp_status); xtensa_use_first_nan(env, env->config->use_first_nan);
return float64_muladd(b, c, a, float_muladd_negate_product, return float64_muladd(b, c, a, float_muladd_negate_product,
&env->fp_status); &env->fp_status);
} }
float32 HELPER(msub_s)(CPUXtensaState *env, float32 a, float32 b, float32 c) float32 HELPER(msub_s)(CPUXtensaState *env, float32 a, float32 b, float32 c)
{ {
set_use_first_nan(env->config->use_first_nan, &env->fp_status); xtensa_use_first_nan(env, env->config->use_first_nan);
return float32_muladd(b, c, a, float_muladd_negate_product, return float32_muladd(b, c, a, float_muladd_negate_product,
&env->fp_status); &env->fp_status);
} }
float64 HELPER(mkdadj_d)(CPUXtensaState *env, float64 a, float64 b) float64 HELPER(mkdadj_d)(CPUXtensaState *env, float64 a, float64 b)
{ {
set_use_first_nan(true, &env->fp_status); xtensa_use_first_nan(env, true);
return float64_div(b, a, &env->fp_status); return float64_div(b, a, &env->fp_status);
} }
float32 HELPER(mkdadj_s)(CPUXtensaState *env, float32 a, float32 b) float32 HELPER(mkdadj_s)(CPUXtensaState *env, float32 a, float32 b)
{ {
set_use_first_nan(env->config->use_first_nan, &env->fp_status); xtensa_use_first_nan(env, env->config->use_first_nan);
return float32_div(b, a, &env->fp_status); return float32_div(b, a, &env->fp_status);
} }
float64 HELPER(mksadj_d)(CPUXtensaState *env, float64 v) float64 HELPER(mksadj_d)(CPUXtensaState *env, float64 v)
{ {
set_use_first_nan(true, &env->fp_status); xtensa_use_first_nan(env, true);
return float64_sqrt(v, &env->fp_status); return float64_sqrt(v, &env->fp_status);
} }
float32 HELPER(mksadj_s)(CPUXtensaState *env, float32 v) float32 HELPER(mksadj_s)(CPUXtensaState *env, float32 v)
{ {
set_use_first_nan(env->config->use_first_nan, &env->fp_status); xtensa_use_first_nan(env, env->config->use_first_nan);
return float32_sqrt(v, &env->fp_status); return float32_sqrt(v, &env->fp_status);
} }

View File

@ -488,6 +488,8 @@ static void run_bench(void)
{ {
bench_func_t f; bench_func_t f;
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &soft_status);
f = bench_funcs[operation][precision]; f = bench_funcs[operation][precision];
g_assert(f); g_assert(f);
f(); f();

View File

@ -70,6 +70,7 @@ int main(int ac, char **av)
float_status qsf = {0}; float_status qsf = {0};
int i; int i;
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &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;

View File

@ -935,6 +935,8 @@ void run_test(void)
{ {
unsigned int i; unsigned int i;
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf);
genCases_setLevel(test_level); genCases_setLevel(test_level);
verCases_maxErrorCount = n_max_errors; verCases_maxErrorCount = n_max_errors;