1 | Mostly my FEAT_NV/NV2 stuff, but some other smaller series too. | 1 | First arm pullreq of the cycle; this is mostly my softfloat NaN |
---|---|---|---|
2 | handling series. (Lots more in my to-review queue, but I don't | ||
3 | like pullreqs growing too close to a hundred patches at a time :-)) | ||
2 | 4 | ||
5 | thanks | ||
3 | -- PMM | 6 | -- PMM |
4 | 7 | ||
5 | The following changes since commit 9468484fe904ab4691de6d9c34616667f377ceac: | 8 | The following changes since commit 97f2796a3736ed37a1b85dc1c76a6c45b829dd17: |
6 | 9 | ||
7 | Merge tag 'block-pull-request' of https://gitlab.com/stefanha/qemu into staging (2024-01-09 10:32:23 +0000) | 10 | Open 10.0 development tree (2024-12-10 17:41:17 +0000) |
8 | 11 | ||
9 | are available in the Git repository at: | 12 | are available in the Git repository at: |
10 | 13 | ||
11 | https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20240111 | 14 | https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20241211 |
12 | 15 | ||
13 | for you to fetch changes up to e2862554c257e908a3833265e38365e794abd362: | 16 | for you to fetch changes up to 1abe28d519239eea5cf9620bb13149423e5665f8: |
14 | 17 | ||
15 | target/arm: Add FEAT_NV2 to max, neoverse-n2, neoverse-v1 CPUs (2024-01-09 14:44:45 +0000) | 18 | MAINTAINERS: Add correct email address for Vikram Garhwal (2024-12-11 15:31:09 +0000) |
16 | 19 | ||
17 | ---------------------------------------------------------------- | 20 | ---------------------------------------------------------------- |
18 | target-arm queue: | 21 | target-arm queue: |
19 | * Emulate FEAT_NV, FEAT_NV2 | 22 | * hw/net/lan9118: Extract PHY model, reuse with imx_fec, fix bugs |
20 | * add cache controller for Freescale i.MX6 | 23 | * fpu: Make muladd NaN handling runtime-selected, not compile-time |
21 | * Add minimal support for the B-L475E-IOT01A board | 24 | * fpu: Make default NaN pattern runtime-selected, not compile-time |
22 | * Allow SoC models to configure M-profile CPUs with correct number | 25 | * fpu: Minor NaN-related cleanups |
23 | of NVIC priority bits | 26 | * MAINTAINERS: email address updates |
24 | * Add missing QOM parent for v7-M SoCs | ||
25 | * Set CTR_EL0.{IDC,DIC} for the 'max' CPU | ||
26 | * hw/intc/arm_gicv3_cpuif: handle LPIs in in the list registers | ||
27 | 27 | ||
28 | ---------------------------------------------------------------- | 28 | ---------------------------------------------------------------- |
29 | Inès Varhol (2): | 29 | Bernhard Beschow (5): |
30 | hw/arm: Add minimal support for the STM32L4x5 SoC | 30 | hw/net/lan9118: Extract lan9118_phy |
31 | hw/arm: Add minimal support for the B-L475E-IOT01A board | 31 | hw/net/lan9118_phy: Reuse in imx_fec and consolidate implementations |
32 | hw/net/lan9118_phy: Fix off-by-one error in MII_ANLPAR register | ||
33 | hw/net/lan9118_phy: Reuse MII constants | ||
34 | hw/net/lan9118_phy: Add missing 100 mbps full duplex advertisement | ||
32 | 35 | ||
33 | Nikita Ostrenkov (1): | 36 | Leif Lindholm (1): |
34 | hw/arm: add cache controller for Freescale i.MX6 | 37 | MAINTAINERS: update email address for Leif Lindholm |
35 | 38 | ||
36 | Peter Maydell (34): | 39 | Peter Maydell (54): |
37 | target/arm: Set CTR_EL0.{IDC,DIC} for the 'max' CPU | 40 | fpu: handle raising Invalid for infzero in pick_nan_muladd |
38 | hw/intc/arm_gicv3_cpuif: handle LPIs in in the list registers | 41 | fpu: Check for default_nan_mode before calling pickNaNMulAdd |
39 | target/arm: Handle HCR_EL2 accesses for bits introduced with FEAT_NV | 42 | softfloat: Allow runtime choice of inf * 0 + NaN result |
40 | target/arm: Implement HCR_EL2.AT handling | 43 | tests/fp: Explicitly set inf-zero-nan rule |
41 | target/arm: Enable trapping of ERET for FEAT_NV | 44 | target/arm: Set FloatInfZeroNaNRule explicitly |
42 | target/arm: Always honour HCR_EL2.TSC when HCR_EL2.NV is set | 45 | target/s390: Set FloatInfZeroNaNRule explicitly |
43 | target/arm: Allow use of upper 32 bits of TBFLAG_A64 | 46 | target/ppc: Set FloatInfZeroNaNRule explicitly |
44 | target/arm: Record correct opcode fields in cpreg for E2H aliases | 47 | target/mips: Set FloatInfZeroNaNRule explicitly |
45 | target/arm: *_EL12 registers should UNDEF when HCR_EL2.E2H is 0 | 48 | target/sparc: Set FloatInfZeroNaNRule explicitly |
46 | target/arm: Make EL2 cpreg accessfns safe for FEAT_NV EL1 accesses | 49 | target/xtensa: Set FloatInfZeroNaNRule explicitly |
47 | target/arm: Move FPU/SVE/SME access checks up above ARM_CP_SPECIAL_MASK check | 50 | target/x86: Set FloatInfZeroNaNRule explicitly |
48 | target/arm: Trap sysreg accesses for FEAT_NV | 51 | target/loongarch: Set FloatInfZeroNaNRule explicitly |
49 | target/arm: Make NV reads of CurrentEL return EL2 | 52 | target/hppa: Set FloatInfZeroNaNRule explicitly |
50 | target/arm: Set SPSR_EL1.M correctly when nested virt is enabled | 53 | softfloat: Pass have_snan to pickNaNMulAdd |
51 | target/arm: Trap registers when HCR_EL2.{NV, NV1} == {1, 1} | 54 | softfloat: Allow runtime choice of NaN propagation for muladd |
52 | target/arm: Always use arm_pan_enabled() when checking if PAN is enabled | 55 | tests/fp: Explicitly set 3-NaN propagation rule |
53 | target/arm: Don't honour PSTATE.PAN when HCR_EL2.{NV, NV1} == {1, 1} | 56 | target/arm: Set Float3NaNPropRule explicitly |
54 | target/arm: Treat LDTR* and STTR* as LDR/STR when NV, NV1 is 1, 1 | 57 | target/loongarch: Set Float3NaNPropRule explicitly |
55 | target/arm: Handle FEAT_NV page table attribute changes | 58 | target/ppc: Set Float3NaNPropRule explicitly |
56 | target/arm: Add FEAT_NV to max, neoverse-n2, neoverse-v1 CPUs | 59 | target/s390x: Set Float3NaNPropRule explicitly |
57 | target/arm: Handle HCR_EL2 accesses for FEAT_NV2 bits | 60 | target/sparc: Set Float3NaNPropRule explicitly |
58 | target/arm: Implement VNCR_EL2 register | 61 | target/mips: Set Float3NaNPropRule explicitly |
59 | target/arm: Handle FEAT_NV2 changes to when SPSR_EL1.M reports EL2 | 62 | target/xtensa: Set Float3NaNPropRule explicitly |
60 | target/arm: Handle FEAT_NV2 redirection of SPSR_EL2, ELR_EL2, ESR_EL2, FAR_EL2 | 63 | target/i386: Set Float3NaNPropRule explicitly |
61 | target/arm: Implement FEAT_NV2 redirection of sysregs to RAM | 64 | target/hppa: Set Float3NaNPropRule explicitly |
62 | target/arm: Report VNCR_EL2 based faults correctly | 65 | fpu: Remove use_first_nan field from float_status |
63 | target/arm: Mark up VNCR offsets (offsets 0x0..0xff) | 66 | target/m68k: Don't pass NULL float_status to floatx80_default_nan() |
64 | target/arm: Mark up VNCR offsets (offsets 0x100..0x160) | 67 | softfloat: Create floatx80 default NaN from parts64_default_nan |
65 | target/arm: Mark up VNCR offsets (offsets 0x168..0x1f8) | 68 | target/loongarch: Use normal float_status in fclass_s and fclass_d helpers |
66 | target/arm: Mark up VNCR offsets (offsets >= 0x200, except GIC) | 69 | target/m68k: In frem helper, initialize local float_status from env->fp_status |
67 | hw/intc/arm_gicv3_cpuif: Mark up VNCR offsets for GIC CPU registers | 70 | target/m68k: Init local float_status from env fp_status in gdb get/set reg |
68 | target/arm: Report HCR_EL2.{NV,NV1,NV2} in cpu dumps | 71 | target/sparc: Initialize local scratch float_status from env->fp_status |
69 | target/arm: Enhance CPU_LOG_INT to show SPSR on AArch64 exception-entry | 72 | target/ppc: Use env->fp_status in helper_compute_fprf functions |
70 | target/arm: Add FEAT_NV2 to max, neoverse-n2, neoverse-v1 CPUs | 73 | fpu: Allow runtime choice of default NaN value |
74 | tests/fp: Set default NaN pattern explicitly | ||
75 | target/microblaze: Set default NaN pattern explicitly | ||
76 | target/i386: Set default NaN pattern explicitly | ||
77 | target/hppa: Set default NaN pattern explicitly | ||
78 | target/alpha: Set default NaN pattern explicitly | ||
79 | target/arm: Set default NaN pattern explicitly | ||
80 | target/loongarch: Set default NaN pattern explicitly | ||
81 | target/m68k: Set default NaN pattern explicitly | ||
82 | target/mips: Set default NaN pattern explicitly | ||
83 | target/openrisc: Set default NaN pattern explicitly | ||
84 | target/ppc: Set default NaN pattern explicitly | ||
85 | target/sh4: Set default NaN pattern explicitly | ||
86 | target/rx: Set default NaN pattern explicitly | ||
87 | target/s390x: Set default NaN pattern explicitly | ||
88 | target/sparc: Set default NaN pattern explicitly | ||
89 | target/xtensa: Set default NaN pattern explicitly | ||
90 | target/hexagon: Set default NaN pattern explicitly | ||
91 | target/riscv: Set default NaN pattern explicitly | ||
92 | target/tricore: Set default NaN pattern explicitly | ||
93 | fpu: Remove default handling for dnan_pattern | ||
71 | 94 | ||
72 | Philippe Mathieu-Daudé (1): | 95 | Richard Henderson (11): |
73 | hw/arm: Add missing QOM parent for v7-M SoCs | 96 | target/arm: Copy entire float_status in is_ebf |
97 | softfloat: Inline pickNaNMulAdd | ||
98 | softfloat: Use goto for default nan case in pick_nan_muladd | ||
99 | softfloat: Remove which from parts_pick_nan_muladd | ||
100 | softfloat: Pad array size in pick_nan_muladd | ||
101 | softfloat: Move propagateFloatx80NaN to softfloat.c | ||
102 | softfloat: Use parts_pick_nan in propagateFloatx80NaN | ||
103 | softfloat: Inline pickNaN | ||
104 | softfloat: Share code between parts_pick_nan cases | ||
105 | softfloat: Sink frac_cmp in parts_pick_nan until needed | ||
106 | softfloat: Replace WHICH with RET in parts_pick_nan | ||
74 | 107 | ||
75 | Samuel Tardieu (3): | 108 | Vikram Garhwal (1): |
76 | hw/intc/armv7m_nvic: add "num-prio-bits" property | 109 | MAINTAINERS: Add correct email address for Vikram Garhwal |
77 | hw/arm/armv7m: alias the NVIC "num-prio-bits" property | ||
78 | hw/arm/socs: configure priority bits for existing SOCs | ||
79 | 110 | ||
80 | MAINTAINERS | 15 ++ | 111 | MAINTAINERS | 4 +- |
81 | docs/system/arm/b-l475e-iot01a.rst | 46 +++++ | 112 | include/fpu/softfloat-helpers.h | 38 +++- |
82 | docs/system/arm/emulation.rst | 2 + | 113 | include/fpu/softfloat-types.h | 89 +++++++- |
83 | docs/system/arm/stm32.rst | 6 +- | 114 | include/hw/net/imx_fec.h | 9 +- |
84 | docs/system/target-arm.rst | 1 + | 115 | include/hw/net/lan9118_phy.h | 37 ++++ |
85 | configs/devices/arm-softmmu/default.mak | 1 + | 116 | include/hw/net/mii.h | 6 + |
86 | include/hw/arm/armv7m.h | 1 + | 117 | target/mips/fpu_helper.h | 20 ++ |
87 | include/hw/arm/stm32l4x5_soc.h | 57 ++++++ | 118 | target/sparc/helper.h | 4 +- |
88 | target/arm/cpregs.h | 54 +++++- | 119 | fpu/softfloat.c | 19 ++ |
89 | target/arm/cpu-features.h | 10 + | 120 | hw/net/imx_fec.c | 146 ++------------ |
90 | target/arm/cpu.h | 24 ++- | 121 | hw/net/lan9118.c | 137 ++----------- |
91 | target/arm/syndrome.h | 20 +- | 122 | hw/net/lan9118_phy.c | 222 ++++++++++++++++++++ |
92 | target/arm/tcg/translate.h | 16 +- | 123 | linux-user/arm/nwfpe/fpa11.c | 5 + |
93 | hw/arm/armv7m.c | 2 + | 124 | target/alpha/cpu.c | 2 + |
94 | hw/arm/b-l475e-iot01a.c | 72 +++++++ | 125 | target/arm/cpu.c | 10 + |
95 | hw/arm/fsl-imx6.c | 3 + | 126 | target/arm/tcg/vec_helper.c | 20 +- |
96 | hw/arm/msf2-som.c | 1 + | 127 | target/hexagon/cpu.c | 2 + |
97 | hw/arm/netduino2.c | 1 + | 128 | target/hppa/fpu_helper.c | 12 ++ |
98 | hw/arm/netduinoplus2.c | 1 + | 129 | target/i386/tcg/fpu_helper.c | 12 ++ |
99 | hw/arm/olimex-stm32-h405.c | 1 + | 130 | target/loongarch/tcg/fpu_helper.c | 14 +- |
100 | hw/arm/stellaris.c | 2 + | 131 | target/m68k/cpu.c | 14 +- |
101 | hw/arm/stm32f100_soc.c | 1 + | 132 | target/m68k/fpu_helper.c | 6 +- |
102 | hw/arm/stm32f205_soc.c | 1 + | 133 | target/m68k/helper.c | 6 +- |
103 | hw/arm/stm32f405_soc.c | 1 + | 134 | target/microblaze/cpu.c | 2 + |
104 | hw/arm/stm32l4x5_soc.c | 266 ++++++++++++++++++++++++++ | 135 | target/mips/msa.c | 10 + |
105 | hw/arm/stm32vldiscovery.c | 1 + | 136 | target/openrisc/cpu.c | 2 + |
106 | hw/intc/arm_gicv3_cpuif.c | 28 ++- | 137 | target/ppc/cpu_init.c | 19 ++ |
107 | hw/intc/armv7m_nvic.c | 23 ++- | 138 | target/ppc/fpu_helper.c | 3 +- |
108 | target/arm/cpu.c | 8 +- | 139 | target/riscv/cpu.c | 2 + |
109 | target/arm/debug_helper.c | 13 +- | 140 | target/rx/cpu.c | 2 + |
110 | target/arm/helper.c | 326 +++++++++++++++++++++++++++++--- | 141 | target/s390x/cpu.c | 5 + |
111 | target/arm/ptw.c | 21 ++ | 142 | target/sh4/cpu.c | 2 + |
112 | target/arm/tcg/cpu64.c | 11 ++ | 143 | target/sparc/cpu.c | 6 + |
113 | target/arm/tcg/hflags.c | 30 ++- | 144 | target/sparc/fop_helper.c | 8 +- |
114 | target/arm/tcg/op_helper.c | 16 +- | 145 | target/sparc/translate.c | 4 +- |
115 | target/arm/tcg/tlb_helper.c | 27 ++- | 146 | target/tricore/helper.c | 2 + |
116 | target/arm/tcg/translate-a64.c | 160 ++++++++++++++-- | 147 | target/xtensa/cpu.c | 4 + |
117 | hw/arm/Kconfig | 12 ++ | 148 | target/xtensa/fpu_helper.c | 3 +- |
118 | hw/arm/meson.build | 2 + | 149 | tests/fp/fp-bench.c | 7 + |
119 | 39 files changed, 1203 insertions(+), 80 deletions(-) | 150 | tests/fp/fp-test-log2.c | 1 + |
120 | create mode 100644 docs/system/arm/b-l475e-iot01a.rst | 151 | tests/fp/fp-test.c | 7 + |
121 | create mode 100644 include/hw/arm/stm32l4x5_soc.h | 152 | fpu/softfloat-parts.c.inc | 152 +++++++++++--- |
122 | create mode 100644 hw/arm/b-l475e-iot01a.c | 153 | fpu/softfloat-specialize.c.inc | 412 ++------------------------------------ |
123 | create mode 100644 hw/arm/stm32l4x5_soc.c | 154 | .mailmap | 5 +- |
124 | 155 | hw/net/Kconfig | 5 + | |
156 | hw/net/meson.build | 1 + | ||
157 | hw/net/trace-events | 10 +- | ||
158 | 47 files changed, 778 insertions(+), 730 deletions(-) | ||
159 | create mode 100644 include/hw/net/lan9118_phy.h | ||
160 | create mode 100644 hw/net/lan9118_phy.c | diff view generated by jsdifflib |
1 | From: Inès Varhol <ines.varhol@telecom-paris.fr> | 1 | From: Bernhard Beschow <shentey@gmail.com> |
---|---|---|---|
2 | 2 | ||
3 | This patch adds a new STM32L4x5 SoC, it is necessary to add support for | 3 | A very similar implementation of the same device exists in imx_fec. Prepare for |
4 | the B-L475E-IOT01A board. | 4 | a common implementation by extracting a device model into its own files. |
5 | The implementation is derived from the STM32F405 SoC. | ||
6 | The implementation contains no peripherals, only memory regions are | ||
7 | implemented. | ||
8 | 5 | ||
9 | Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org> | 6 | Some migration state has been moved into the new device model which breaks |
10 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | 7 | migration compatibility for the following machines: |
11 | Acked-by: Alistair Francis <alistair.francis@wdc.com> | 8 | * smdkc210 |
12 | Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr> | 9 | * realview-* |
13 | Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr> | 10 | * vexpress-* |
14 | Message-id: 20240108135849.351719-2-ines.varhol@telecom-paris.fr | 11 | * kzm |
12 | * mps2-* | ||
13 | |||
14 | While breaking migration ABI, fix the size of the MII registers to be 16 bit, | ||
15 | as defined by IEEE 802.3u. | ||
16 | |||
17 | Signed-off-by: Bernhard Beschow <shentey@gmail.com> | ||
18 | Tested-by: Guenter Roeck <linux@roeck-us.net> | ||
19 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | ||
20 | Message-id: 20241102125724.532843-2-shentey@gmail.com | ||
15 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 21 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
16 | --- | 22 | --- |
17 | MAINTAINERS | 8 + | 23 | include/hw/net/lan9118_phy.h | 37 ++++++++ |
18 | include/hw/arm/stm32l4x5_soc.h | 57 +++++++ | 24 | hw/net/lan9118.c | 137 +++++----------------------- |
19 | hw/arm/stm32l4x5_soc.c | 265 +++++++++++++++++++++++++++++++++ | 25 | hw/net/lan9118_phy.c | 169 +++++++++++++++++++++++++++++++++++ |
20 | hw/arm/Kconfig | 5 + | 26 | hw/net/Kconfig | 4 + |
21 | hw/arm/meson.build | 1 + | 27 | hw/net/meson.build | 1 + |
22 | 5 files changed, 336 insertions(+) | 28 | 5 files changed, 233 insertions(+), 115 deletions(-) |
23 | create mode 100644 include/hw/arm/stm32l4x5_soc.h | 29 | create mode 100644 include/hw/net/lan9118_phy.h |
24 | create mode 100644 hw/arm/stm32l4x5_soc.c | 30 | create mode 100644 hw/net/lan9118_phy.c |
25 | 31 | ||
26 | diff --git a/MAINTAINERS b/MAINTAINERS | 32 | diff --git a/include/hw/net/lan9118_phy.h b/include/hw/net/lan9118_phy.h |
27 | index XXXXXXX..XXXXXXX 100644 | ||
28 | --- a/MAINTAINERS | ||
29 | +++ b/MAINTAINERS | ||
30 | @@ -XXX,XX +XXX,XX @@ L: qemu-arm@nongnu.org | ||
31 | S: Maintained | ||
32 | F: hw/arm/olimex-stm32-h405.c | ||
33 | |||
34 | +STM32L4x5 SoC Family | ||
35 | +M: Arnaud Minier <arnaud.minier@telecom-paris.fr> | ||
36 | +M: Inès Varhol <ines.varhol@telecom-paris.fr> | ||
37 | +L: qemu-arm@nongnu.org | ||
38 | +S: Maintained | ||
39 | +F: hw/arm/stm32l4x5_soc.c | ||
40 | +F: include/hw/arm/stm32l4x5_soc.h | ||
41 | + | ||
42 | SmartFusion2 | ||
43 | M: Subbaraya Sundeep <sundeep.lkml@gmail.com> | ||
44 | M: Peter Maydell <peter.maydell@linaro.org> | ||
45 | diff --git a/include/hw/arm/stm32l4x5_soc.h b/include/hw/arm/stm32l4x5_soc.h | ||
46 | new file mode 100644 | 33 | new file mode 100644 |
47 | index XXXXXXX..XXXXXXX | 34 | index XXXXXXX..XXXXXXX |
48 | --- /dev/null | 35 | --- /dev/null |
49 | +++ b/include/hw/arm/stm32l4x5_soc.h | 36 | +++ b/include/hw/net/lan9118_phy.h |
50 | @@ -XXX,XX +XXX,XX @@ | 37 | @@ -XXX,XX +XXX,XX @@ |
51 | +/* | 38 | +/* |
52 | + * STM32L4x5 SoC family | 39 | + * SMSC LAN9118 PHY emulation |
53 | + * | 40 | + * |
54 | + * Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr> | 41 | + * Copyright (c) 2009 CodeSourcery, LLC. |
55 | + * Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr> | 42 | + * Written by Paul Brook |
56 | + * | ||
57 | + * SPDX-License-Identifier: GPL-2.0-or-later | ||
58 | + * | 43 | + * |
59 | + * This work is licensed under the terms of the GNU GPL, version 2 or later. | 44 | + * This work is licensed under the terms of the GNU GPL, version 2 or later. |
60 | + * See the COPYING file in the top-level directory. | 45 | + * See the COPYING file in the top-level directory. |
61 | + * | ||
62 | + * This work is heavily inspired by the stm32f405_soc by Alistair Francis. | ||
63 | + * Original code is licensed under the MIT License: | ||
64 | + * | ||
65 | + * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me> | ||
66 | + */ | 46 | + */ |
67 | + | 47 | + |
68 | +/* | 48 | +#ifndef HW_NET_LAN9118_PHY_H |
69 | + * The reference used is the STMicroElectronics RM0351 Reference manual | 49 | +#define HW_NET_LAN9118_PHY_H |
70 | + * for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs. | 50 | + |
71 | + * https://www.st.com/en/microcontrollers-microprocessors/stm32l4x5/documentation.html | ||
72 | + */ | ||
73 | + | ||
74 | +#ifndef HW_ARM_STM32L4x5_SOC_H | ||
75 | +#define HW_ARM_STM32L4x5_SOC_H | ||
76 | + | ||
77 | +#include "exec/memory.h" | ||
78 | +#include "hw/arm/armv7m.h" | ||
79 | +#include "qom/object.h" | 51 | +#include "qom/object.h" |
80 | + | 52 | +#include "hw/sysbus.h" |
81 | +#define TYPE_STM32L4X5_SOC "stm32l4x5-soc" | 53 | + |
82 | +#define TYPE_STM32L4X5XC_SOC "stm32l4x5xc-soc" | 54 | +#define TYPE_LAN9118_PHY "lan9118-phy" |
83 | +#define TYPE_STM32L4X5XE_SOC "stm32l4x5xe-soc" | 55 | +OBJECT_DECLARE_SIMPLE_TYPE(Lan9118PhyState, LAN9118_PHY) |
84 | +#define TYPE_STM32L4X5XG_SOC "stm32l4x5xg-soc" | 56 | + |
85 | +OBJECT_DECLARE_TYPE(Stm32l4x5SocState, Stm32l4x5SocClass, STM32L4X5_SOC) | 57 | +typedef struct Lan9118PhyState { |
86 | + | ||
87 | +struct Stm32l4x5SocState { | ||
88 | + SysBusDevice parent_obj; | 58 | + SysBusDevice parent_obj; |
89 | + | 59 | + |
90 | + ARMv7MState armv7m; | 60 | + uint16_t status; |
91 | + | 61 | + uint16_t control; |
92 | + MemoryRegion sram1; | 62 | + uint16_t advertise; |
93 | + MemoryRegion sram2; | 63 | + uint16_t ints; |
94 | + MemoryRegion flash; | 64 | + uint16_t int_mask; |
95 | + MemoryRegion flash_alias; | 65 | + qemu_irq irq; |
96 | + | 66 | + bool link_down; |
97 | + Clock *sysclk; | 67 | +} Lan9118PhyState; |
98 | + Clock *refclk; | 68 | + |
99 | +}; | 69 | +void lan9118_phy_update_link(Lan9118PhyState *s, bool link_down); |
100 | + | 70 | +void lan9118_phy_reset(Lan9118PhyState *s); |
101 | +struct Stm32l4x5SocClass { | 71 | +uint16_t lan9118_phy_read(Lan9118PhyState *s, int reg); |
102 | + SysBusDeviceClass parent_class; | 72 | +void lan9118_phy_write(Lan9118PhyState *s, int reg, uint16_t val); |
103 | + | ||
104 | + size_t flash_size; | ||
105 | +}; | ||
106 | + | 73 | + |
107 | +#endif | 74 | +#endif |
108 | diff --git a/hw/arm/stm32l4x5_soc.c b/hw/arm/stm32l4x5_soc.c | 75 | diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c |
76 | index XXXXXXX..XXXXXXX 100644 | ||
77 | --- a/hw/net/lan9118.c | ||
78 | +++ b/hw/net/lan9118.c | ||
79 | @@ -XXX,XX +XXX,XX @@ | ||
80 | #include "net/net.h" | ||
81 | #include "net/eth.h" | ||
82 | #include "hw/irq.h" | ||
83 | +#include "hw/net/lan9118_phy.h" | ||
84 | #include "hw/net/lan9118.h" | ||
85 | #include "hw/ptimer.h" | ||
86 | #include "hw/qdev-properties.h" | ||
87 | @@ -XXX,XX +XXX,XX @@ do { printf("lan9118: " fmt , ## __VA_ARGS__); } while (0) | ||
88 | #define MAC_CR_RXEN 0x00000004 | ||
89 | #define MAC_CR_RESERVED 0x7f404213 | ||
90 | |||
91 | -#define PHY_INT_ENERGYON 0x80 | ||
92 | -#define PHY_INT_AUTONEG_COMPLETE 0x40 | ||
93 | -#define PHY_INT_FAULT 0x20 | ||
94 | -#define PHY_INT_DOWN 0x10 | ||
95 | -#define PHY_INT_AUTONEG_LP 0x08 | ||
96 | -#define PHY_INT_PARFAULT 0x04 | ||
97 | -#define PHY_INT_AUTONEG_PAGE 0x02 | ||
98 | - | ||
99 | #define GPT_TIMER_EN 0x20000000 | ||
100 | |||
101 | /* | ||
102 | @@ -XXX,XX +XXX,XX @@ struct lan9118_state { | ||
103 | uint32_t mac_mii_data; | ||
104 | uint32_t mac_flow; | ||
105 | |||
106 | - uint32_t phy_status; | ||
107 | - uint32_t phy_control; | ||
108 | - uint32_t phy_advertise; | ||
109 | - uint32_t phy_int; | ||
110 | - uint32_t phy_int_mask; | ||
111 | + Lan9118PhyState mii; | ||
112 | + IRQState mii_irq; | ||
113 | |||
114 | int32_t eeprom_writable; | ||
115 | uint8_t eeprom[128]; | ||
116 | @@ -XXX,XX +XXX,XX @@ struct lan9118_state { | ||
117 | |||
118 | static const VMStateDescription vmstate_lan9118 = { | ||
119 | .name = "lan9118", | ||
120 | - .version_id = 2, | ||
121 | - .minimum_version_id = 1, | ||
122 | + .version_id = 3, | ||
123 | + .minimum_version_id = 3, | ||
124 | .fields = (const VMStateField[]) { | ||
125 | VMSTATE_PTIMER(timer, lan9118_state), | ||
126 | VMSTATE_UINT32(irq_cfg, lan9118_state), | ||
127 | @@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_lan9118 = { | ||
128 | VMSTATE_UINT32(mac_mii_acc, lan9118_state), | ||
129 | VMSTATE_UINT32(mac_mii_data, lan9118_state), | ||
130 | VMSTATE_UINT32(mac_flow, lan9118_state), | ||
131 | - VMSTATE_UINT32(phy_status, lan9118_state), | ||
132 | - VMSTATE_UINT32(phy_control, lan9118_state), | ||
133 | - VMSTATE_UINT32(phy_advertise, lan9118_state), | ||
134 | - VMSTATE_UINT32(phy_int, lan9118_state), | ||
135 | - VMSTATE_UINT32(phy_int_mask, lan9118_state), | ||
136 | VMSTATE_INT32(eeprom_writable, lan9118_state), | ||
137 | VMSTATE_UINT8_ARRAY(eeprom, lan9118_state, 128), | ||
138 | VMSTATE_INT32(tx_fifo_size, lan9118_state), | ||
139 | @@ -XXX,XX +XXX,XX @@ static void lan9118_reload_eeprom(lan9118_state *s) | ||
140 | lan9118_mac_changed(s); | ||
141 | } | ||
142 | |||
143 | -static void phy_update_irq(lan9118_state *s) | ||
144 | +static void lan9118_update_irq(void *opaque, int n, int level) | ||
145 | { | ||
146 | - if (s->phy_int & s->phy_int_mask) { | ||
147 | + lan9118_state *s = opaque; | ||
148 | + | ||
149 | + if (level) { | ||
150 | s->int_sts |= PHY_INT; | ||
151 | } else { | ||
152 | s->int_sts &= ~PHY_INT; | ||
153 | @@ -XXX,XX +XXX,XX @@ static void phy_update_irq(lan9118_state *s) | ||
154 | lan9118_update(s); | ||
155 | } | ||
156 | |||
157 | -static void phy_update_link(lan9118_state *s) | ||
158 | -{ | ||
159 | - /* Autonegotiation status mirrors link status. */ | ||
160 | - if (qemu_get_queue(s->nic)->link_down) { | ||
161 | - s->phy_status &= ~0x0024; | ||
162 | - s->phy_int |= PHY_INT_DOWN; | ||
163 | - } else { | ||
164 | - s->phy_status |= 0x0024; | ||
165 | - s->phy_int |= PHY_INT_ENERGYON; | ||
166 | - s->phy_int |= PHY_INT_AUTONEG_COMPLETE; | ||
167 | - } | ||
168 | - phy_update_irq(s); | ||
169 | -} | ||
170 | - | ||
171 | static void lan9118_set_link(NetClientState *nc) | ||
172 | { | ||
173 | - phy_update_link(qemu_get_nic_opaque(nc)); | ||
174 | -} | ||
175 | - | ||
176 | -static void phy_reset(lan9118_state *s) | ||
177 | -{ | ||
178 | - s->phy_status = 0x7809; | ||
179 | - s->phy_control = 0x3000; | ||
180 | - s->phy_advertise = 0x01e1; | ||
181 | - s->phy_int_mask = 0; | ||
182 | - s->phy_int = 0; | ||
183 | - phy_update_link(s); | ||
184 | + lan9118_phy_update_link(&LAN9118(qemu_get_nic_opaque(nc))->mii, | ||
185 | + nc->link_down); | ||
186 | } | ||
187 | |||
188 | static void lan9118_reset(DeviceState *d) | ||
189 | @@ -XXX,XX +XXX,XX @@ static void lan9118_reset(DeviceState *d) | ||
190 | s->read_word_n = 0; | ||
191 | s->write_word_n = 0; | ||
192 | |||
193 | - phy_reset(s); | ||
194 | - | ||
195 | s->eeprom_writable = 0; | ||
196 | lan9118_reload_eeprom(s); | ||
197 | } | ||
198 | @@ -XXX,XX +XXX,XX @@ static void do_tx_packet(lan9118_state *s) | ||
199 | uint32_t status; | ||
200 | |||
201 | /* FIXME: Honor TX disable, and allow queueing of packets. */ | ||
202 | - if (s->phy_control & 0x4000) { | ||
203 | + if (s->mii.control & 0x4000) { | ||
204 | /* This assumes the receive routine doesn't touch the VLANClient. */ | ||
205 | qemu_receive_packet(qemu_get_queue(s->nic), s->txp->data, s->txp->len); | ||
206 | } else { | ||
207 | @@ -XXX,XX +XXX,XX @@ static void tx_fifo_push(lan9118_state *s, uint32_t val) | ||
208 | } | ||
209 | } | ||
210 | |||
211 | -static uint32_t do_phy_read(lan9118_state *s, int reg) | ||
212 | -{ | ||
213 | - uint32_t val; | ||
214 | - | ||
215 | - switch (reg) { | ||
216 | - case 0: /* Basic Control */ | ||
217 | - return s->phy_control; | ||
218 | - case 1: /* Basic Status */ | ||
219 | - return s->phy_status; | ||
220 | - case 2: /* ID1 */ | ||
221 | - return 0x0007; | ||
222 | - case 3: /* ID2 */ | ||
223 | - return 0xc0d1; | ||
224 | - case 4: /* Auto-neg advertisement */ | ||
225 | - return s->phy_advertise; | ||
226 | - case 5: /* Auto-neg Link Partner Ability */ | ||
227 | - return 0x0f71; | ||
228 | - case 6: /* Auto-neg Expansion */ | ||
229 | - return 1; | ||
230 | - /* TODO 17, 18, 27, 29, 30, 31 */ | ||
231 | - case 29: /* Interrupt source. */ | ||
232 | - val = s->phy_int; | ||
233 | - s->phy_int = 0; | ||
234 | - phy_update_irq(s); | ||
235 | - return val; | ||
236 | - case 30: /* Interrupt mask */ | ||
237 | - return s->phy_int_mask; | ||
238 | - default: | ||
239 | - qemu_log_mask(LOG_GUEST_ERROR, | ||
240 | - "do_phy_read: PHY read reg %d\n", reg); | ||
241 | - return 0; | ||
242 | - } | ||
243 | -} | ||
244 | - | ||
245 | -static void do_phy_write(lan9118_state *s, int reg, uint32_t val) | ||
246 | -{ | ||
247 | - switch (reg) { | ||
248 | - case 0: /* Basic Control */ | ||
249 | - if (val & 0x8000) { | ||
250 | - phy_reset(s); | ||
251 | - break; | ||
252 | - } | ||
253 | - s->phy_control = val & 0x7980; | ||
254 | - /* Complete autonegotiation immediately. */ | ||
255 | - if (val & 0x1000) { | ||
256 | - s->phy_status |= 0x0020; | ||
257 | - } | ||
258 | - break; | ||
259 | - case 4: /* Auto-neg advertisement */ | ||
260 | - s->phy_advertise = (val & 0x2d7f) | 0x80; | ||
261 | - break; | ||
262 | - /* TODO 17, 18, 27, 31 */ | ||
263 | - case 30: /* Interrupt mask */ | ||
264 | - s->phy_int_mask = val & 0xff; | ||
265 | - phy_update_irq(s); | ||
266 | - break; | ||
267 | - default: | ||
268 | - qemu_log_mask(LOG_GUEST_ERROR, | ||
269 | - "do_phy_write: PHY write reg %d = 0x%04x\n", reg, val); | ||
270 | - } | ||
271 | -} | ||
272 | - | ||
273 | static void do_mac_write(lan9118_state *s, int reg, uint32_t val) | ||
274 | { | ||
275 | switch (reg) { | ||
276 | @@ -XXX,XX +XXX,XX @@ static void do_mac_write(lan9118_state *s, int reg, uint32_t val) | ||
277 | if (val & 2) { | ||
278 | DPRINTF("PHY write %d = 0x%04x\n", | ||
279 | (val >> 6) & 0x1f, s->mac_mii_data); | ||
280 | - do_phy_write(s, (val >> 6) & 0x1f, s->mac_mii_data); | ||
281 | + lan9118_phy_write(&s->mii, (val >> 6) & 0x1f, s->mac_mii_data); | ||
282 | } else { | ||
283 | - s->mac_mii_data = do_phy_read(s, (val >> 6) & 0x1f); | ||
284 | + s->mac_mii_data = lan9118_phy_read(&s->mii, (val >> 6) & 0x1f); | ||
285 | DPRINTF("PHY read %d = 0x%04x\n", | ||
286 | (val >> 6) & 0x1f, s->mac_mii_data); | ||
287 | } | ||
288 | @@ -XXX,XX +XXX,XX @@ static void lan9118_writel(void *opaque, hwaddr offset, | ||
289 | break; | ||
290 | case CSR_PMT_CTRL: | ||
291 | if (val & 0x400) { | ||
292 | - phy_reset(s); | ||
293 | + lan9118_phy_reset(&s->mii); | ||
294 | } | ||
295 | s->pmt_ctrl &= ~0x34e; | ||
296 | s->pmt_ctrl |= (val & 0x34e); | ||
297 | @@ -XXX,XX +XXX,XX @@ static void lan9118_realize(DeviceState *dev, Error **errp) | ||
298 | const MemoryRegionOps *mem_ops = | ||
299 | s->mode_16bit ? &lan9118_16bit_mem_ops : &lan9118_mem_ops; | ||
300 | |||
301 | + qemu_init_irq(&s->mii_irq, lan9118_update_irq, s, 0); | ||
302 | + object_initialize_child(OBJECT(s), "mii", &s->mii, TYPE_LAN9118_PHY); | ||
303 | + if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(&s->mii), errp)) { | ||
304 | + return; | ||
305 | + } | ||
306 | + qdev_connect_gpio_out(DEVICE(&s->mii), 0, &s->mii_irq); | ||
307 | + | ||
308 | memory_region_init_io(&s->mmio, OBJECT(dev), mem_ops, s, | ||
309 | "lan9118-mmio", 0x100); | ||
310 | sysbus_init_mmio(sbd, &s->mmio); | ||
311 | diff --git a/hw/net/lan9118_phy.c b/hw/net/lan9118_phy.c | ||
109 | new file mode 100644 | 312 | new file mode 100644 |
110 | index XXXXXXX..XXXXXXX | 313 | index XXXXXXX..XXXXXXX |
111 | --- /dev/null | 314 | --- /dev/null |
112 | +++ b/hw/arm/stm32l4x5_soc.c | 315 | +++ b/hw/net/lan9118_phy.c |
113 | @@ -XXX,XX +XXX,XX @@ | 316 | @@ -XXX,XX +XXX,XX @@ |
114 | +/* | 317 | +/* |
115 | + * STM32L4x5 SoC family | 318 | + * SMSC LAN9118 PHY emulation |
116 | + * | 319 | + * |
117 | + * Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr> | 320 | + * Copyright (c) 2009 CodeSourcery, LLC. |
118 | + * Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr> | 321 | + * Written by Paul Brook |
119 | + * | 322 | + * |
120 | + * SPDX-License-Identifier: GPL-2.0-or-later | 323 | + * This code is licensed under the GNU GPL v2 |
121 | + * | 324 | + * |
122 | + * This work is licensed under the terms of the GNU GPL, version 2 or later. | 325 | + * Contributions after 2012-01-13 are licensed under the terms of the |
123 | + * See the COPYING file in the top-level directory. | 326 | + * GNU GPL, version 2 or (at your option) any later version. |
124 | + * | ||
125 | + * This work is heavily inspired by the stm32f405_soc by Alistair Francis. | ||
126 | + * Original code is licensed under the MIT License: | ||
127 | + * | ||
128 | + * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me> | ||
129 | + */ | 327 | + */ |
130 | + | 328 | + |
131 | +/* | ||
132 | + * The reference used is the STMicroElectronics RM0351 Reference manual | ||
133 | + * for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs. | ||
134 | + * https://www.st.com/en/microcontrollers-microprocessors/stm32l4x5/documentation.html | ||
135 | + */ | ||
136 | + | ||
137 | +#include "qemu/osdep.h" | 329 | +#include "qemu/osdep.h" |
138 | +#include "qemu/units.h" | 330 | +#include "hw/net/lan9118_phy.h" |
139 | +#include "qapi/error.h" | 331 | +#include "hw/irq.h" |
140 | +#include "exec/address-spaces.h" | 332 | +#include "hw/resettable.h" |
141 | +#include "sysemu/sysemu.h" | 333 | +#include "migration/vmstate.h" |
142 | +#include "hw/arm/stm32l4x5_soc.h" | 334 | +#include "qemu/log.h" |
143 | +#include "hw/qdev-clock.h" | 335 | + |
144 | +#include "hw/misc/unimp.h" | 336 | +#define PHY_INT_ENERGYON (1 << 7) |
145 | + | 337 | +#define PHY_INT_AUTONEG_COMPLETE (1 << 6) |
146 | +#define FLASH_BASE_ADDRESS 0x08000000 | 338 | +#define PHY_INT_FAULT (1 << 5) |
147 | +#define SRAM1_BASE_ADDRESS 0x20000000 | 339 | +#define PHY_INT_DOWN (1 << 4) |
148 | +#define SRAM1_SIZE (96 * KiB) | 340 | +#define PHY_INT_AUTONEG_LP (1 << 3) |
149 | +#define SRAM2_BASE_ADDRESS 0x10000000 | 341 | +#define PHY_INT_PARFAULT (1 << 2) |
150 | +#define SRAM2_SIZE (32 * KiB) | 342 | +#define PHY_INT_AUTONEG_PAGE (1 << 1) |
151 | + | 343 | + |
152 | +static void stm32l4x5_soc_initfn(Object *obj) | 344 | +static void lan9118_phy_update_irq(Lan9118PhyState *s) |
153 | +{ | 345 | +{ |
154 | + Stm32l4x5SocState *s = STM32L4X5_SOC(obj); | 346 | + qemu_set_irq(s->irq, !!(s->ints & s->int_mask)); |
155 | + | 347 | +} |
156 | + s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0); | 348 | + |
157 | + s->refclk = qdev_init_clock_in(DEVICE(s), "refclk", NULL, NULL, 0); | 349 | +uint16_t lan9118_phy_read(Lan9118PhyState *s, int reg) |
158 | +} | 350 | +{ |
159 | + | 351 | + uint16_t val; |
160 | +static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp) | 352 | + |
161 | +{ | 353 | + switch (reg) { |
162 | + ERRP_GUARD(); | 354 | + case 0: /* Basic Control */ |
163 | + Stm32l4x5SocState *s = STM32L4X5_SOC(dev_soc); | 355 | + return s->control; |
164 | + const Stm32l4x5SocClass *sc = STM32L4X5_SOC_GET_CLASS(dev_soc); | 356 | + case 1: /* Basic Status */ |
165 | + MemoryRegion *system_memory = get_system_memory(); | 357 | + return s->status; |
166 | + DeviceState *armv7m; | 358 | + case 2: /* ID1 */ |
167 | + | 359 | + return 0x0007; |
168 | + /* | 360 | + case 3: /* ID2 */ |
169 | + * We use s->refclk internally and only define it with qdev_init_clock_in() | 361 | + return 0xc0d1; |
170 | + * so it is correctly parented and not leaked on an init/deinit; it is not | 362 | + case 4: /* Auto-neg advertisement */ |
171 | + * intended as an externally exposed clock. | 363 | + return s->advertise; |
172 | + */ | 364 | + case 5: /* Auto-neg Link Partner Ability */ |
173 | + if (clock_has_source(s->refclk)) { | 365 | + return 0x0f71; |
174 | + error_setg(errp, "refclk clock must not be wired up by the board code"); | 366 | + case 6: /* Auto-neg Expansion */ |
175 | + return; | 367 | + return 1; |
368 | + /* TODO 17, 18, 27, 29, 30, 31 */ | ||
369 | + case 29: /* Interrupt source. */ | ||
370 | + val = s->ints; | ||
371 | + s->ints = 0; | ||
372 | + lan9118_phy_update_irq(s); | ||
373 | + return val; | ||
374 | + case 30: /* Interrupt mask */ | ||
375 | + return s->int_mask; | ||
376 | + default: | ||
377 | + qemu_log_mask(LOG_GUEST_ERROR, | ||
378 | + "lan9118_phy_read: PHY read reg %d\n", reg); | ||
379 | + return 0; | ||
176 | + } | 380 | + } |
177 | + | 381 | +} |
178 | + if (!clock_has_source(s->sysclk)) { | 382 | + |
179 | + error_setg(errp, "sysclk clock must be wired up by the board code"); | 383 | +void lan9118_phy_write(Lan9118PhyState *s, int reg, uint16_t val) |
180 | + return; | 384 | +{ |
385 | + switch (reg) { | ||
386 | + case 0: /* Basic Control */ | ||
387 | + if (val & 0x8000) { | ||
388 | + lan9118_phy_reset(s); | ||
389 | + break; | ||
390 | + } | ||
391 | + s->control = val & 0x7980; | ||
392 | + /* Complete autonegotiation immediately. */ | ||
393 | + if (val & 0x1000) { | ||
394 | + s->status |= 0x0020; | ||
395 | + } | ||
396 | + break; | ||
397 | + case 4: /* Auto-neg advertisement */ | ||
398 | + s->advertise = (val & 0x2d7f) | 0x80; | ||
399 | + break; | ||
400 | + /* TODO 17, 18, 27, 31 */ | ||
401 | + case 30: /* Interrupt mask */ | ||
402 | + s->int_mask = val & 0xff; | ||
403 | + lan9118_phy_update_irq(s); | ||
404 | + break; | ||
405 | + default: | ||
406 | + qemu_log_mask(LOG_GUEST_ERROR, | ||
407 | + "lan9118_phy_write: PHY write reg %d = 0x%04x\n", reg, val); | ||
181 | + } | 408 | + } |
182 | + | 409 | +} |
183 | + /* | 410 | + |
184 | + * TODO: ideally we should model the SoC RCC and its ability to | 411 | +void lan9118_phy_update_link(Lan9118PhyState *s, bool link_down) |
185 | + * change the sysclk frequency and define different sysclk sources. | 412 | +{ |
186 | + */ | 413 | + s->link_down = link_down; |
187 | + | 414 | + |
188 | + /* The refclk always runs at frequency HCLK / 8 */ | 415 | + /* Autonegotiation status mirrors link status. */ |
189 | + clock_set_mul_div(s->refclk, 8, 1); | 416 | + if (link_down) { |
190 | + clock_set_source(s->refclk, s->sysclk); | 417 | + s->status &= ~0x0024; |
191 | + | 418 | + s->ints |= PHY_INT_DOWN; |
192 | + if (!memory_region_init_rom(&s->flash, OBJECT(dev_soc), "flash", | 419 | + } else { |
193 | + sc->flash_size, errp)) { | 420 | + s->status |= 0x0024; |
194 | + return; | 421 | + s->ints |= PHY_INT_ENERGYON; |
422 | + s->ints |= PHY_INT_AUTONEG_COMPLETE; | ||
195 | + } | 423 | + } |
196 | + memory_region_init_alias(&s->flash_alias, OBJECT(dev_soc), | 424 | + lan9118_phy_update_irq(s); |
197 | + "flash_boot_alias", &s->flash, 0, | 425 | +} |
198 | + sc->flash_size); | 426 | + |
199 | + | 427 | +void lan9118_phy_reset(Lan9118PhyState *s) |
200 | + memory_region_add_subregion(system_memory, FLASH_BASE_ADDRESS, &s->flash); | 428 | +{ |
201 | + memory_region_add_subregion(system_memory, 0, &s->flash_alias); | 429 | + s->control = 0x3000; |
202 | + | 430 | + s->status = 0x7809; |
203 | + if (!memory_region_init_ram(&s->sram1, OBJECT(dev_soc), "SRAM1", SRAM1_SIZE, | 431 | + s->advertise = 0x01e1; |
204 | + errp)) { | 432 | + s->int_mask = 0; |
205 | + return; | 433 | + s->ints = 0; |
206 | + } | 434 | + lan9118_phy_update_link(s, s->link_down); |
207 | + memory_region_add_subregion(system_memory, SRAM1_BASE_ADDRESS, &s->sram1); | 435 | +} |
208 | + | 436 | + |
209 | + if (!memory_region_init_ram(&s->sram2, OBJECT(dev_soc), "SRAM2", SRAM2_SIZE, | 437 | +static void lan9118_phy_reset_hold(Object *obj, ResetType type) |
210 | + errp)) { | 438 | +{ |
211 | + return; | 439 | + Lan9118PhyState *s = LAN9118_PHY(obj); |
212 | + } | 440 | + |
213 | + memory_region_add_subregion(system_memory, SRAM2_BASE_ADDRESS, &s->sram2); | 441 | + lan9118_phy_reset(s); |
214 | + | 442 | +} |
215 | + object_initialize_child(OBJECT(dev_soc), "armv7m", &s->armv7m, TYPE_ARMV7M); | 443 | + |
216 | + armv7m = DEVICE(&s->armv7m); | 444 | +static void lan9118_phy_init(Object *obj) |
217 | + qdev_prop_set_uint32(armv7m, "num-irq", 96); | 445 | +{ |
218 | + qdev_prop_set_string(armv7m, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m4")); | 446 | + Lan9118PhyState *s = LAN9118_PHY(obj); |
219 | + qdev_prop_set_bit(armv7m, "enable-bitband", true); | 447 | + |
220 | + qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk); | 448 | + qdev_init_gpio_out(DEVICE(s), &s->irq, 1); |
221 | + qdev_connect_clock_in(armv7m, "refclk", s->refclk); | 449 | +} |
222 | + object_property_set_link(OBJECT(&s->armv7m), "memory", | 450 | + |
223 | + OBJECT(system_memory), &error_abort); | 451 | +static const VMStateDescription vmstate_lan9118_phy = { |
224 | + if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), errp)) { | 452 | + .name = "lan9118-phy", |
225 | + return; | 453 | + .version_id = 1, |
226 | + } | 454 | + .minimum_version_id = 1, |
227 | + | 455 | + .fields = (const VMStateField[]) { |
228 | + /* APB1 BUS */ | 456 | + VMSTATE_UINT16(control, Lan9118PhyState), |
229 | + create_unimplemented_device("TIM2", 0x40000000, 0x400); | 457 | + VMSTATE_UINT16(status, Lan9118PhyState), |
230 | + create_unimplemented_device("TIM3", 0x40000400, 0x400); | 458 | + VMSTATE_UINT16(advertise, Lan9118PhyState), |
231 | + create_unimplemented_device("TIM4", 0x40000800, 0x400); | 459 | + VMSTATE_UINT16(ints, Lan9118PhyState), |
232 | + create_unimplemented_device("TIM5", 0x40000C00, 0x400); | 460 | + VMSTATE_UINT16(int_mask, Lan9118PhyState), |
233 | + create_unimplemented_device("TIM6", 0x40001000, 0x400); | 461 | + VMSTATE_BOOL(link_down, Lan9118PhyState), |
234 | + create_unimplemented_device("TIM7", 0x40001400, 0x400); | 462 | + VMSTATE_END_OF_LIST() |
235 | + /* RESERVED: 0x40001800, 0x1000 */ | ||
236 | + create_unimplemented_device("RTC", 0x40002800, 0x400); | ||
237 | + create_unimplemented_device("WWDG", 0x40002C00, 0x400); | ||
238 | + create_unimplemented_device("IWDG", 0x40003000, 0x400); | ||
239 | + /* RESERVED: 0x40001800, 0x400 */ | ||
240 | + create_unimplemented_device("SPI2", 0x40003800, 0x400); | ||
241 | + create_unimplemented_device("SPI3", 0x40003C00, 0x400); | ||
242 | + /* RESERVED: 0x40004000, 0x400 */ | ||
243 | + create_unimplemented_device("USART2", 0x40004400, 0x400); | ||
244 | + create_unimplemented_device("USART3", 0x40004800, 0x400); | ||
245 | + create_unimplemented_device("UART4", 0x40004C00, 0x400); | ||
246 | + create_unimplemented_device("UART5", 0x40005000, 0x400); | ||
247 | + create_unimplemented_device("I2C1", 0x40005400, 0x400); | ||
248 | + create_unimplemented_device("I2C2", 0x40005800, 0x400); | ||
249 | + create_unimplemented_device("I2C3", 0x40005C00, 0x400); | ||
250 | + /* RESERVED: 0x40006000, 0x400 */ | ||
251 | + create_unimplemented_device("CAN1", 0x40006400, 0x400); | ||
252 | + /* RESERVED: 0x40006800, 0x400 */ | ||
253 | + create_unimplemented_device("PWR", 0x40007000, 0x400); | ||
254 | + create_unimplemented_device("DAC1", 0x40007400, 0x400); | ||
255 | + create_unimplemented_device("OPAMP", 0x40007800, 0x400); | ||
256 | + create_unimplemented_device("LPTIM1", 0x40007C00, 0x400); | ||
257 | + create_unimplemented_device("LPUART1", 0x40008000, 0x400); | ||
258 | + /* RESERVED: 0x40008400, 0x400 */ | ||
259 | + create_unimplemented_device("SWPMI1", 0x40008800, 0x400); | ||
260 | + /* RESERVED: 0x40008C00, 0x800 */ | ||
261 | + create_unimplemented_device("LPTIM2", 0x40009400, 0x400); | ||
262 | + /* RESERVED: 0x40009800, 0x6800 */ | ||
263 | + | ||
264 | + /* APB2 BUS */ | ||
265 | + create_unimplemented_device("SYSCFG", 0x40010000, 0x30); | ||
266 | + create_unimplemented_device("VREFBUF", 0x40010030, 0x1D0); | ||
267 | + create_unimplemented_device("COMP", 0x40010200, 0x200); | ||
268 | + create_unimplemented_device("EXTI", 0x40010400, 0x400); | ||
269 | + /* RESERVED: 0x40010800, 0x1400 */ | ||
270 | + create_unimplemented_device("FIREWALL", 0x40011C00, 0x400); | ||
271 | + /* RESERVED: 0x40012000, 0x800 */ | ||
272 | + create_unimplemented_device("SDMMC1", 0x40012800, 0x400); | ||
273 | + create_unimplemented_device("TIM1", 0x40012C00, 0x400); | ||
274 | + create_unimplemented_device("SPI1", 0x40013000, 0x400); | ||
275 | + create_unimplemented_device("TIM8", 0x40013400, 0x400); | ||
276 | + create_unimplemented_device("USART1", 0x40013800, 0x400); | ||
277 | + /* RESERVED: 0x40013C00, 0x400 */ | ||
278 | + create_unimplemented_device("TIM15", 0x40014000, 0x400); | ||
279 | + create_unimplemented_device("TIM16", 0x40014400, 0x400); | ||
280 | + create_unimplemented_device("TIM17", 0x40014800, 0x400); | ||
281 | + /* RESERVED: 0x40014C00, 0x800 */ | ||
282 | + create_unimplemented_device("SAI1", 0x40015400, 0x400); | ||
283 | + create_unimplemented_device("SAI2", 0x40015800, 0x400); | ||
284 | + /* RESERVED: 0x40015C00, 0x400 */ | ||
285 | + create_unimplemented_device("DFSDM1", 0x40016000, 0x400); | ||
286 | + /* RESERVED: 0x40016400, 0x9C00 */ | ||
287 | + | ||
288 | + /* AHB1 BUS */ | ||
289 | + create_unimplemented_device("DMA1", 0x40020000, 0x400); | ||
290 | + create_unimplemented_device("DMA2", 0x40020400, 0x400); | ||
291 | + /* RESERVED: 0x40020800, 0x800 */ | ||
292 | + create_unimplemented_device("RCC", 0x40021000, 0x400); | ||
293 | + /* RESERVED: 0x40021400, 0xC00 */ | ||
294 | + create_unimplemented_device("FLASH", 0x40022000, 0x400); | ||
295 | + /* RESERVED: 0x40022400, 0xC00 */ | ||
296 | + create_unimplemented_device("CRC", 0x40023000, 0x400); | ||
297 | + /* RESERVED: 0x40023400, 0x400 */ | ||
298 | + create_unimplemented_device("TSC", 0x40024000, 0x400); | ||
299 | + | ||
300 | + /* RESERVED: 0x40024400, 0x7FDBC00 */ | ||
301 | + | ||
302 | + /* AHB2 BUS */ | ||
303 | + create_unimplemented_device("GPIOA", 0x48000000, 0x400); | ||
304 | + create_unimplemented_device("GPIOB", 0x48000400, 0x400); | ||
305 | + create_unimplemented_device("GPIOC", 0x48000800, 0x400); | ||
306 | + create_unimplemented_device("GPIOD", 0x48000C00, 0x400); | ||
307 | + create_unimplemented_device("GPIOE", 0x48001000, 0x400); | ||
308 | + create_unimplemented_device("GPIOF", 0x48001400, 0x400); | ||
309 | + create_unimplemented_device("GPIOG", 0x48001800, 0x400); | ||
310 | + create_unimplemented_device("GPIOH", 0x48001C00, 0x400); | ||
311 | + /* RESERVED: 0x48002000, 0x7FDBC00 */ | ||
312 | + create_unimplemented_device("OTG_FS", 0x50000000, 0x40000); | ||
313 | + create_unimplemented_device("ADC", 0x50040000, 0x400); | ||
314 | + /* RESERVED: 0x50040400, 0x20400 */ | ||
315 | + create_unimplemented_device("RNG", 0x50060800, 0x400); | ||
316 | + | ||
317 | + /* AHB3 BUS */ | ||
318 | + create_unimplemented_device("FMC", 0xA0000000, 0x1000); | ||
319 | + create_unimplemented_device("QUADSPI", 0xA0001000, 0x400); | ||
320 | +} | ||
321 | + | ||
322 | +static void stm32l4x5_soc_class_init(ObjectClass *klass, void *data) | ||
323 | +{ | ||
324 | + | ||
325 | + DeviceClass *dc = DEVICE_CLASS(klass); | ||
326 | + | ||
327 | + dc->realize = stm32l4x5_soc_realize; | ||
328 | + /* Reason: Mapped at fixed location on the system bus */ | ||
329 | + dc->user_creatable = false; | ||
330 | + /* No vmstate or reset required: device has no internal state */ | ||
331 | +} | ||
332 | + | ||
333 | +static void stm32l4x5xc_soc_class_init(ObjectClass *oc, void *data) | ||
334 | +{ | ||
335 | + Stm32l4x5SocClass *ssc = STM32L4X5_SOC_CLASS(oc); | ||
336 | + | ||
337 | + ssc->flash_size = 256 * KiB; | ||
338 | +} | ||
339 | + | ||
340 | +static void stm32l4x5xe_soc_class_init(ObjectClass *oc, void *data) | ||
341 | +{ | ||
342 | + Stm32l4x5SocClass *ssc = STM32L4X5_SOC_CLASS(oc); | ||
343 | + | ||
344 | + ssc->flash_size = 512 * KiB; | ||
345 | +} | ||
346 | + | ||
347 | +static void stm32l4x5xg_soc_class_init(ObjectClass *oc, void *data) | ||
348 | +{ | ||
349 | + Stm32l4x5SocClass *ssc = STM32L4X5_SOC_CLASS(oc); | ||
350 | + | ||
351 | + ssc->flash_size = 1 * MiB; | ||
352 | +} | ||
353 | + | ||
354 | +static const TypeInfo stm32l4x5_soc_types[] = { | ||
355 | + { | ||
356 | + .name = TYPE_STM32L4X5XC_SOC, | ||
357 | + .parent = TYPE_STM32L4X5_SOC, | ||
358 | + .class_init = stm32l4x5xc_soc_class_init, | ||
359 | + }, { | ||
360 | + .name = TYPE_STM32L4X5XE_SOC, | ||
361 | + .parent = TYPE_STM32L4X5_SOC, | ||
362 | + .class_init = stm32l4x5xe_soc_class_init, | ||
363 | + }, { | ||
364 | + .name = TYPE_STM32L4X5XG_SOC, | ||
365 | + .parent = TYPE_STM32L4X5_SOC, | ||
366 | + .class_init = stm32l4x5xg_soc_class_init, | ||
367 | + }, { | ||
368 | + .name = TYPE_STM32L4X5_SOC, | ||
369 | + .parent = TYPE_SYS_BUS_DEVICE, | ||
370 | + .instance_size = sizeof(Stm32l4x5SocState), | ||
371 | + .instance_init = stm32l4x5_soc_initfn, | ||
372 | + .class_size = sizeof(Stm32l4x5SocClass), | ||
373 | + .class_init = stm32l4x5_soc_class_init, | ||
374 | + .abstract = true, | ||
375 | + } | 463 | + } |
376 | +}; | 464 | +}; |
377 | + | 465 | + |
378 | +DEFINE_TYPES(stm32l4x5_soc_types) | 466 | +static void lan9118_phy_class_init(ObjectClass *klass, void *data) |
379 | diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig | 467 | +{ |
468 | + ResettableClass *rc = RESETTABLE_CLASS(klass); | ||
469 | + DeviceClass *dc = DEVICE_CLASS(klass); | ||
470 | + | ||
471 | + rc->phases.hold = lan9118_phy_reset_hold; | ||
472 | + dc->vmsd = &vmstate_lan9118_phy; | ||
473 | +} | ||
474 | + | ||
475 | +static const TypeInfo types[] = { | ||
476 | + { | ||
477 | + .name = TYPE_LAN9118_PHY, | ||
478 | + .parent = TYPE_SYS_BUS_DEVICE, | ||
479 | + .instance_size = sizeof(Lan9118PhyState), | ||
480 | + .instance_init = lan9118_phy_init, | ||
481 | + .class_init = lan9118_phy_class_init, | ||
482 | + } | ||
483 | +}; | ||
484 | + | ||
485 | +DEFINE_TYPES(types) | ||
486 | diff --git a/hw/net/Kconfig b/hw/net/Kconfig | ||
380 | index XXXXXXX..XXXXXXX 100644 | 487 | index XXXXXXX..XXXXXXX 100644 |
381 | --- a/hw/arm/Kconfig | 488 | --- a/hw/net/Kconfig |
382 | +++ b/hw/arm/Kconfig | 489 | +++ b/hw/net/Kconfig |
383 | @@ -XXX,XX +XXX,XX @@ config STM32F405_SOC | 490 | @@ -XXX,XX +XXX,XX @@ config VMXNET3_PCI |
384 | select STM32F4XX_SYSCFG | 491 | config SMC91C111 |
385 | select STM32F4XX_EXTI | 492 | bool |
386 | 493 | ||
387 | +config STM32L4X5_SOC | 494 | +config LAN9118_PHY |
388 | + bool | 495 | + bool |
389 | + select ARM_V7M | 496 | + |
390 | + select OR_IRQ | 497 | config LAN9118 |
391 | + | ||
392 | config XLNX_ZYNQMP_ARM | ||
393 | bool | 498 | bool |
394 | default y if PIXMAN | 499 | + select LAN9118_PHY |
395 | diff --git a/hw/arm/meson.build b/hw/arm/meson.build | 500 | select PTIMER |
501 | |||
502 | config NE2000_ISA | ||
503 | diff --git a/hw/net/meson.build b/hw/net/meson.build | ||
396 | index XXXXXXX..XXXXXXX 100644 | 504 | index XXXXXXX..XXXXXXX 100644 |
397 | --- a/hw/arm/meson.build | 505 | --- a/hw/net/meson.build |
398 | +++ b/hw/arm/meson.build | 506 | +++ b/hw/net/meson.build |
399 | @@ -XXX,XX +XXX,XX @@ arm_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2836.c', 'raspi.c')) | 507 | @@ -XXX,XX +XXX,XX @@ system_ss.add(when: 'CONFIG_VMXNET3_PCI', if_true: files('vmxnet3.c')) |
400 | arm_ss.add(when: 'CONFIG_STM32F100_SOC', if_true: files('stm32f100_soc.c')) | 508 | |
401 | arm_ss.add(when: 'CONFIG_STM32F205_SOC', if_true: files('stm32f205_soc.c')) | 509 | system_ss.add(when: 'CONFIG_SMC91C111', if_true: files('smc91c111.c')) |
402 | arm_ss.add(when: 'CONFIG_STM32F405_SOC', if_true: files('stm32f405_soc.c')) | 510 | system_ss.add(when: 'CONFIG_LAN9118', if_true: files('lan9118.c')) |
403 | +arm_ss.add(when: 'CONFIG_STM32L4X5_SOC', if_true: files('stm32l4x5_soc.c')) | 511 | +system_ss.add(when: 'CONFIG_LAN9118_PHY', if_true: files('lan9118_phy.c')) |
404 | arm_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp.c', 'xlnx-zcu102.c')) | 512 | system_ss.add(when: 'CONFIG_NE2000_ISA', if_true: files('ne2000-isa.c')) |
405 | arm_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal.c', 'xlnx-versal-virt.c')) | 513 | system_ss.add(when: 'CONFIG_OPENCORES_ETH', if_true: files('opencores_eth.c')) |
406 | arm_ss.add(when: 'CONFIG_FSL_IMX25', if_true: files('fsl-imx25.c', 'imx25_pdk.c')) | 514 | system_ss.add(when: 'CONFIG_XGMAC', if_true: files('xgmac.c')) |
407 | -- | 515 | -- |
408 | 2.34.1 | 516 | 2.34.1 |
409 | |||
410 | diff view generated by jsdifflib |
1 | From: Samuel Tardieu <sam@rfc1149.net> | 1 | From: Bernhard Beschow <shentey@gmail.com> |
---|---|---|---|
2 | 2 | ||
3 | Cortex-M NVIC can have a different number of priority bits. | 3 | imx_fec models the same PHY as lan9118_phy. The code is almost the same with |
4 | Cortex-M0/M0+/M1 devices must use 2 or more bits, while devices based | 4 | imx_fec having more logging and tracing. Merge these improvements into |
5 | on ARMv7m and up must use 3 or more bits. | 5 | lan9118_phy and reuse in imx_fec to fix the code duplication. |
6 | 6 | ||
7 | This adds a "num-prio-bits" property which will get sensible default | 7 | Some migration state how resides in the new device model which breaks migration |
8 | values if unset (2 or 8 depending on the device). Unless a SOC | 8 | compatibility for the following machines: |
9 | specifies the number of bits to use, the previous behavior is | 9 | * imx25-pdk |
10 | maintained for backward compatibility. | 10 | * sabrelite |
11 | * mcimx7d-sabre | ||
12 | * mcimx6ul-evk | ||
11 | 13 | ||
12 | Signed-off-by: Samuel Tardieu <sam@rfc1149.net> | 14 | Signed-off-by: Bernhard Beschow <shentey@gmail.com> |
15 | Tested-by: Guenter Roeck <linux@roeck-us.net> | ||
13 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | 16 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> |
14 | Message-id: 20240106181503.1746200-2-sam@rfc1149.net | 17 | Message-id: 20241102125724.532843-3-shentey@gmail.com |
15 | Suggested-by: Anton Kochkov <anton.kochkov@proton.me> | ||
16 | Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1122 | ||
17 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | ||
18 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 18 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
19 | --- | 19 | --- |
20 | hw/intc/armv7m_nvic.c | 23 ++++++++++++++++++++++- | 20 | include/hw/net/imx_fec.h | 9 ++- |
21 | 1 file changed, 22 insertions(+), 1 deletion(-) | 21 | hw/net/imx_fec.c | 146 ++++----------------------------------- |
22 | hw/net/lan9118_phy.c | 82 ++++++++++++++++------ | ||
23 | hw/net/Kconfig | 1 + | ||
24 | hw/net/trace-events | 10 +-- | ||
25 | 5 files changed, 85 insertions(+), 163 deletions(-) | ||
22 | 26 | ||
23 | diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c | 27 | diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h |
24 | index XXXXXXX..XXXXXXX 100644 | 28 | index XXXXXXX..XXXXXXX 100644 |
25 | --- a/hw/intc/armv7m_nvic.c | 29 | --- a/include/hw/net/imx_fec.h |
26 | +++ b/hw/intc/armv7m_nvic.c | 30 | +++ b/include/hw/net/imx_fec.h |
27 | @@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_nvic = { | 31 | @@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_SIMPLE_TYPE(IMXFECState, IMX_FEC) |
28 | static Property props_nvic[] = { | 32 | #define TYPE_IMX_ENET "imx.enet" |
29 | /* Number of external IRQ lines (so excluding the 16 internal exceptions) */ | 33 | |
30 | DEFINE_PROP_UINT32("num-irq", NVICState, num_irq, 64), | 34 | #include "hw/sysbus.h" |
31 | + /* | 35 | +#include "hw/net/lan9118_phy.h" |
32 | + * Number of the maximum priority bits that can be used. 0 means | 36 | +#include "hw/irq.h" |
33 | + * to use a reasonable default. | 37 | #include "net/net.h" |
34 | + */ | 38 | |
35 | + DEFINE_PROP_UINT8("num-prio-bits", NVICState, num_prio_bits, 0), | 39 | #define ENET_EIR 1 |
36 | DEFINE_PROP_END_OF_LIST() | 40 | @@ -XXX,XX +XXX,XX @@ struct IMXFECState { |
41 | uint32_t tx_descriptor[ENET_TX_RING_NUM]; | ||
42 | uint32_t tx_ring_num; | ||
43 | |||
44 | - uint32_t phy_status; | ||
45 | - uint32_t phy_control; | ||
46 | - uint32_t phy_advertise; | ||
47 | - uint32_t phy_int; | ||
48 | - uint32_t phy_int_mask; | ||
49 | + Lan9118PhyState mii; | ||
50 | + IRQState mii_irq; | ||
51 | uint32_t phy_num; | ||
52 | bool phy_connected; | ||
53 | struct IMXFECState *phy_consumer; | ||
54 | diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c | ||
55 | index XXXXXXX..XXXXXXX 100644 | ||
56 | --- a/hw/net/imx_fec.c | ||
57 | +++ b/hw/net/imx_fec.c | ||
58 | @@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_imx_eth_txdescs = { | ||
59 | |||
60 | static const VMStateDescription vmstate_imx_eth = { | ||
61 | .name = TYPE_IMX_FEC, | ||
62 | - .version_id = 2, | ||
63 | - .minimum_version_id = 2, | ||
64 | + .version_id = 3, | ||
65 | + .minimum_version_id = 3, | ||
66 | .fields = (const VMStateField[]) { | ||
67 | VMSTATE_UINT32_ARRAY(regs, IMXFECState, ENET_MAX), | ||
68 | VMSTATE_UINT32(rx_descriptor, IMXFECState), | ||
69 | VMSTATE_UINT32(tx_descriptor[0], IMXFECState), | ||
70 | - VMSTATE_UINT32(phy_status, IMXFECState), | ||
71 | - VMSTATE_UINT32(phy_control, IMXFECState), | ||
72 | - VMSTATE_UINT32(phy_advertise, IMXFECState), | ||
73 | - VMSTATE_UINT32(phy_int, IMXFECState), | ||
74 | - VMSTATE_UINT32(phy_int_mask, IMXFECState), | ||
75 | VMSTATE_END_OF_LIST() | ||
76 | }, | ||
77 | .subsections = (const VMStateDescription * const []) { | ||
78 | @@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_imx_eth = { | ||
79 | }, | ||
37 | }; | 80 | }; |
38 | 81 | ||
39 | @@ -XXX,XX +XXX,XX @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp) | 82 | -#define PHY_INT_ENERGYON (1 << 7) |
40 | /* include space for internal exception vectors */ | 83 | -#define PHY_INT_AUTONEG_COMPLETE (1 << 6) |
41 | s->num_irq += NVIC_FIRST_IRQ; | 84 | -#define PHY_INT_FAULT (1 << 5) |
42 | 85 | -#define PHY_INT_DOWN (1 << 4) | |
43 | - s->num_prio_bits = arm_feature(&s->cpu->env, ARM_FEATURE_V7) ? 8 : 2; | 86 | -#define PHY_INT_AUTONEG_LP (1 << 3) |
44 | + if (s->num_prio_bits == 0) { | 87 | -#define PHY_INT_PARFAULT (1 << 2) |
45 | + /* | 88 | -#define PHY_INT_AUTONEG_PAGE (1 << 1) |
46 | + * If left unspecified, use 2 bits by default on Cortex-M0/M0+/M1 | 89 | - |
47 | + * and 8 bits otherwise. | 90 | static void imx_eth_update(IMXFECState *s); |
48 | + */ | 91 | |
49 | + s->num_prio_bits = arm_feature(&s->cpu->env, ARM_FEATURE_V7) ? 8 : 2; | 92 | /* |
50 | + } else { | 93 | @@ -XXX,XX +XXX,XX @@ static void imx_eth_update(IMXFECState *s); |
51 | + uint8_t min_prio_bits = | 94 | * For now we don't handle any GPIO/interrupt line, so the OS will |
52 | + arm_feature(&s->cpu->env, ARM_FEATURE_V7) ? 3 : 2; | 95 | * have to poll for the PHY status. |
53 | + if (s->num_prio_bits < min_prio_bits || s->num_prio_bits > 8) { | 96 | */ |
54 | + error_setg(errp, | 97 | -static void imx_phy_update_irq(IMXFECState *s) |
55 | + "num-prio-bits %d is outside " | 98 | +static void imx_phy_update_irq(void *opaque, int n, int level) |
56 | + "NVIC acceptable range [%d-8]", | 99 | { |
57 | + s->num_prio_bits, min_prio_bits); | 100 | - imx_eth_update(s); |
58 | + return; | 101 | -} |
59 | + } | 102 | - |
103 | -static void imx_phy_update_link(IMXFECState *s) | ||
104 | -{ | ||
105 | - /* Autonegotiation status mirrors link status. */ | ||
106 | - if (qemu_get_queue(s->nic)->link_down) { | ||
107 | - trace_imx_phy_update_link("down"); | ||
108 | - s->phy_status &= ~0x0024; | ||
109 | - s->phy_int |= PHY_INT_DOWN; | ||
110 | - } else { | ||
111 | - trace_imx_phy_update_link("up"); | ||
112 | - s->phy_status |= 0x0024; | ||
113 | - s->phy_int |= PHY_INT_ENERGYON; | ||
114 | - s->phy_int |= PHY_INT_AUTONEG_COMPLETE; | ||
115 | - } | ||
116 | - imx_phy_update_irq(s); | ||
117 | + imx_eth_update(opaque); | ||
118 | } | ||
119 | |||
120 | static void imx_eth_set_link(NetClientState *nc) | ||
121 | { | ||
122 | - imx_phy_update_link(IMX_FEC(qemu_get_nic_opaque(nc))); | ||
123 | -} | ||
124 | - | ||
125 | -static void imx_phy_reset(IMXFECState *s) | ||
126 | -{ | ||
127 | - trace_imx_phy_reset(); | ||
128 | - | ||
129 | - s->phy_status = 0x7809; | ||
130 | - s->phy_control = 0x3000; | ||
131 | - s->phy_advertise = 0x01e1; | ||
132 | - s->phy_int_mask = 0; | ||
133 | - s->phy_int = 0; | ||
134 | - imx_phy_update_link(s); | ||
135 | + lan9118_phy_update_link(&IMX_FEC(qemu_get_nic_opaque(nc))->mii, | ||
136 | + nc->link_down); | ||
137 | } | ||
138 | |||
139 | static uint32_t imx_phy_read(IMXFECState *s, int reg) | ||
140 | { | ||
141 | - uint32_t val; | ||
142 | uint32_t phy = reg / 32; | ||
143 | |||
144 | if (!s->phy_connected) { | ||
145 | @@ -XXX,XX +XXX,XX @@ static uint32_t imx_phy_read(IMXFECState *s, int reg) | ||
146 | |||
147 | reg %= 32; | ||
148 | |||
149 | - switch (reg) { | ||
150 | - case 0: /* Basic Control */ | ||
151 | - val = s->phy_control; | ||
152 | - break; | ||
153 | - case 1: /* Basic Status */ | ||
154 | - val = s->phy_status; | ||
155 | - break; | ||
156 | - case 2: /* ID1 */ | ||
157 | - val = 0x0007; | ||
158 | - break; | ||
159 | - case 3: /* ID2 */ | ||
160 | - val = 0xc0d1; | ||
161 | - break; | ||
162 | - case 4: /* Auto-neg advertisement */ | ||
163 | - val = s->phy_advertise; | ||
164 | - break; | ||
165 | - case 5: /* Auto-neg Link Partner Ability */ | ||
166 | - val = 0x0f71; | ||
167 | - break; | ||
168 | - case 6: /* Auto-neg Expansion */ | ||
169 | - val = 1; | ||
170 | - break; | ||
171 | - case 29: /* Interrupt source. */ | ||
172 | - val = s->phy_int; | ||
173 | - s->phy_int = 0; | ||
174 | - imx_phy_update_irq(s); | ||
175 | - break; | ||
176 | - case 30: /* Interrupt mask */ | ||
177 | - val = s->phy_int_mask; | ||
178 | - break; | ||
179 | - case 17: | ||
180 | - case 18: | ||
181 | - case 27: | ||
182 | - case 31: | ||
183 | - qemu_log_mask(LOG_UNIMP, "[%s.phy]%s: reg %d not implemented\n", | ||
184 | - TYPE_IMX_FEC, __func__, reg); | ||
185 | - val = 0; | ||
186 | - break; | ||
187 | - default: | ||
188 | - qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad address at offset %d\n", | ||
189 | - TYPE_IMX_FEC, __func__, reg); | ||
190 | - val = 0; | ||
191 | - break; | ||
192 | - } | ||
193 | - | ||
194 | - trace_imx_phy_read(val, phy, reg); | ||
195 | - | ||
196 | - return val; | ||
197 | + return lan9118_phy_read(&s->mii, reg); | ||
198 | } | ||
199 | |||
200 | static void imx_phy_write(IMXFECState *s, int reg, uint32_t val) | ||
201 | @@ -XXX,XX +XXX,XX @@ static void imx_phy_write(IMXFECState *s, int reg, uint32_t val) | ||
202 | |||
203 | reg %= 32; | ||
204 | |||
205 | - trace_imx_phy_write(val, phy, reg); | ||
206 | - | ||
207 | - switch (reg) { | ||
208 | - case 0: /* Basic Control */ | ||
209 | - if (val & 0x8000) { | ||
210 | - imx_phy_reset(s); | ||
211 | - } else { | ||
212 | - s->phy_control = val & 0x7980; | ||
213 | - /* Complete autonegotiation immediately. */ | ||
214 | - if (val & 0x1000) { | ||
215 | - s->phy_status |= 0x0020; | ||
216 | - } | ||
217 | - } | ||
218 | - break; | ||
219 | - case 4: /* Auto-neg advertisement */ | ||
220 | - s->phy_advertise = (val & 0x2d7f) | 0x80; | ||
221 | - break; | ||
222 | - case 30: /* Interrupt mask */ | ||
223 | - s->phy_int_mask = val & 0xff; | ||
224 | - imx_phy_update_irq(s); | ||
225 | - break; | ||
226 | - case 17: | ||
227 | - case 18: | ||
228 | - case 27: | ||
229 | - case 31: | ||
230 | - qemu_log_mask(LOG_UNIMP, "[%s.phy)%s: reg %d not implemented\n", | ||
231 | - TYPE_IMX_FEC, __func__, reg); | ||
232 | - break; | ||
233 | - default: | ||
234 | - qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad address at offset %d\n", | ||
235 | - TYPE_IMX_FEC, __func__, reg); | ||
236 | - break; | ||
237 | - } | ||
238 | + lan9118_phy_write(&s->mii, reg, val); | ||
239 | } | ||
240 | |||
241 | static void imx_fec_read_bd(IMXFECBufDesc *bd, dma_addr_t addr) | ||
242 | @@ -XXX,XX +XXX,XX @@ static void imx_eth_reset(DeviceState *d) | ||
243 | |||
244 | s->rx_descriptor = 0; | ||
245 | memset(s->tx_descriptor, 0, sizeof(s->tx_descriptor)); | ||
246 | - | ||
247 | - /* We also reset the PHY */ | ||
248 | - imx_phy_reset(s); | ||
249 | } | ||
250 | |||
251 | static uint32_t imx_default_read(IMXFECState *s, uint32_t index) | ||
252 | @@ -XXX,XX +XXX,XX @@ static void imx_eth_realize(DeviceState *dev, Error **errp) | ||
253 | sysbus_init_irq(sbd, &s->irq[0]); | ||
254 | sysbus_init_irq(sbd, &s->irq[1]); | ||
255 | |||
256 | + qemu_init_irq(&s->mii_irq, imx_phy_update_irq, s, 0); | ||
257 | + object_initialize_child(OBJECT(s), "mii", &s->mii, TYPE_LAN9118_PHY); | ||
258 | + if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(&s->mii), errp)) { | ||
259 | + return; | ||
60 | + } | 260 | + } |
61 | 261 | + qdev_connect_gpio_out(DEVICE(&s->mii), 0, &s->mii_irq); | |
62 | /* | 262 | + |
63 | * This device provides a single memory region which covers the | 263 | qemu_macaddr_default_if_unset(&s->conf.macaddr); |
264 | |||
265 | s->nic = qemu_new_nic(&imx_eth_net_info, &s->conf, | ||
266 | diff --git a/hw/net/lan9118_phy.c b/hw/net/lan9118_phy.c | ||
267 | index XXXXXXX..XXXXXXX 100644 | ||
268 | --- a/hw/net/lan9118_phy.c | ||
269 | +++ b/hw/net/lan9118_phy.c | ||
270 | @@ -XXX,XX +XXX,XX @@ | ||
271 | * Copyright (c) 2009 CodeSourcery, LLC. | ||
272 | * Written by Paul Brook | ||
273 | * | ||
274 | + * Copyright (c) 2013 Jean-Christophe Dubois. <jcd@tribudubois.net> | ||
275 | + * | ||
276 | * This code is licensed under the GNU GPL v2 | ||
277 | * | ||
278 | * Contributions after 2012-01-13 are licensed under the terms of the | ||
279 | @@ -XXX,XX +XXX,XX @@ | ||
280 | #include "hw/resettable.h" | ||
281 | #include "migration/vmstate.h" | ||
282 | #include "qemu/log.h" | ||
283 | +#include "trace.h" | ||
284 | |||
285 | #define PHY_INT_ENERGYON (1 << 7) | ||
286 | #define PHY_INT_AUTONEG_COMPLETE (1 << 6) | ||
287 | @@ -XXX,XX +XXX,XX @@ uint16_t lan9118_phy_read(Lan9118PhyState *s, int reg) | ||
288 | |||
289 | switch (reg) { | ||
290 | case 0: /* Basic Control */ | ||
291 | - return s->control; | ||
292 | + val = s->control; | ||
293 | + break; | ||
294 | case 1: /* Basic Status */ | ||
295 | - return s->status; | ||
296 | + val = s->status; | ||
297 | + break; | ||
298 | case 2: /* ID1 */ | ||
299 | - return 0x0007; | ||
300 | + val = 0x0007; | ||
301 | + break; | ||
302 | case 3: /* ID2 */ | ||
303 | - return 0xc0d1; | ||
304 | + val = 0xc0d1; | ||
305 | + break; | ||
306 | case 4: /* Auto-neg advertisement */ | ||
307 | - return s->advertise; | ||
308 | + val = s->advertise; | ||
309 | + break; | ||
310 | case 5: /* Auto-neg Link Partner Ability */ | ||
311 | - return 0x0f71; | ||
312 | + val = 0x0f71; | ||
313 | + break; | ||
314 | case 6: /* Auto-neg Expansion */ | ||
315 | - return 1; | ||
316 | - /* TODO 17, 18, 27, 29, 30, 31 */ | ||
317 | + val = 1; | ||
318 | + break; | ||
319 | case 29: /* Interrupt source. */ | ||
320 | val = s->ints; | ||
321 | s->ints = 0; | ||
322 | lan9118_phy_update_irq(s); | ||
323 | - return val; | ||
324 | + break; | ||
325 | case 30: /* Interrupt mask */ | ||
326 | - return s->int_mask; | ||
327 | + val = s->int_mask; | ||
328 | + break; | ||
329 | + case 17: | ||
330 | + case 18: | ||
331 | + case 27: | ||
332 | + case 31: | ||
333 | + qemu_log_mask(LOG_UNIMP, "%s: reg %d not implemented\n", | ||
334 | + __func__, reg); | ||
335 | + val = 0; | ||
336 | + break; | ||
337 | default: | ||
338 | - qemu_log_mask(LOG_GUEST_ERROR, | ||
339 | - "lan9118_phy_read: PHY read reg %d\n", reg); | ||
340 | - return 0; | ||
341 | + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address at offset %d\n", | ||
342 | + __func__, reg); | ||
343 | + val = 0; | ||
344 | + break; | ||
345 | } | ||
346 | + | ||
347 | + trace_lan9118_phy_read(val, reg); | ||
348 | + | ||
349 | + return val; | ||
350 | } | ||
351 | |||
352 | void lan9118_phy_write(Lan9118PhyState *s, int reg, uint16_t val) | ||
353 | { | ||
354 | + trace_lan9118_phy_write(val, reg); | ||
355 | + | ||
356 | switch (reg) { | ||
357 | case 0: /* Basic Control */ | ||
358 | if (val & 0x8000) { | ||
359 | lan9118_phy_reset(s); | ||
360 | - break; | ||
361 | - } | ||
362 | - s->control = val & 0x7980; | ||
363 | - /* Complete autonegotiation immediately. */ | ||
364 | - if (val & 0x1000) { | ||
365 | - s->status |= 0x0020; | ||
366 | + } else { | ||
367 | + s->control = val & 0x7980; | ||
368 | + /* Complete autonegotiation immediately. */ | ||
369 | + if (val & 0x1000) { | ||
370 | + s->status |= 0x0020; | ||
371 | + } | ||
372 | } | ||
373 | break; | ||
374 | case 4: /* Auto-neg advertisement */ | ||
375 | s->advertise = (val & 0x2d7f) | 0x80; | ||
376 | break; | ||
377 | - /* TODO 17, 18, 27, 31 */ | ||
378 | case 30: /* Interrupt mask */ | ||
379 | s->int_mask = val & 0xff; | ||
380 | lan9118_phy_update_irq(s); | ||
381 | break; | ||
382 | + case 17: | ||
383 | + case 18: | ||
384 | + case 27: | ||
385 | + case 31: | ||
386 | + qemu_log_mask(LOG_UNIMP, "%s: reg %d not implemented\n", | ||
387 | + __func__, reg); | ||
388 | + break; | ||
389 | default: | ||
390 | - qemu_log_mask(LOG_GUEST_ERROR, | ||
391 | - "lan9118_phy_write: PHY write reg %d = 0x%04x\n", reg, val); | ||
392 | + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address at offset %d\n", | ||
393 | + __func__, reg); | ||
394 | + break; | ||
395 | } | ||
396 | } | ||
397 | |||
398 | @@ -XXX,XX +XXX,XX @@ void lan9118_phy_update_link(Lan9118PhyState *s, bool link_down) | ||
399 | |||
400 | /* Autonegotiation status mirrors link status. */ | ||
401 | if (link_down) { | ||
402 | + trace_lan9118_phy_update_link("down"); | ||
403 | s->status &= ~0x0024; | ||
404 | s->ints |= PHY_INT_DOWN; | ||
405 | } else { | ||
406 | + trace_lan9118_phy_update_link("up"); | ||
407 | s->status |= 0x0024; | ||
408 | s->ints |= PHY_INT_ENERGYON; | ||
409 | s->ints |= PHY_INT_AUTONEG_COMPLETE; | ||
410 | @@ -XXX,XX +XXX,XX @@ void lan9118_phy_update_link(Lan9118PhyState *s, bool link_down) | ||
411 | |||
412 | void lan9118_phy_reset(Lan9118PhyState *s) | ||
413 | { | ||
414 | + trace_lan9118_phy_reset(); | ||
415 | + | ||
416 | s->control = 0x3000; | ||
417 | s->status = 0x7809; | ||
418 | s->advertise = 0x01e1; | ||
419 | @@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_lan9118_phy = { | ||
420 | .version_id = 1, | ||
421 | .minimum_version_id = 1, | ||
422 | .fields = (const VMStateField[]) { | ||
423 | - VMSTATE_UINT16(control, Lan9118PhyState), | ||
424 | VMSTATE_UINT16(status, Lan9118PhyState), | ||
425 | + VMSTATE_UINT16(control, Lan9118PhyState), | ||
426 | VMSTATE_UINT16(advertise, Lan9118PhyState), | ||
427 | VMSTATE_UINT16(ints, Lan9118PhyState), | ||
428 | VMSTATE_UINT16(int_mask, Lan9118PhyState), | ||
429 | diff --git a/hw/net/Kconfig b/hw/net/Kconfig | ||
430 | index XXXXXXX..XXXXXXX 100644 | ||
431 | --- a/hw/net/Kconfig | ||
432 | +++ b/hw/net/Kconfig | ||
433 | @@ -XXX,XX +XXX,XX @@ config ALLWINNER_SUN8I_EMAC | ||
434 | |||
435 | config IMX_FEC | ||
436 | bool | ||
437 | + select LAN9118_PHY | ||
438 | |||
439 | config CADENCE | ||
440 | bool | ||
441 | diff --git a/hw/net/trace-events b/hw/net/trace-events | ||
442 | index XXXXXXX..XXXXXXX 100644 | ||
443 | --- a/hw/net/trace-events | ||
444 | +++ b/hw/net/trace-events | ||
445 | @@ -XXX,XX +XXX,XX @@ allwinner_sun8i_emac_set_link(bool active) "Set link: active=%u" | ||
446 | allwinner_sun8i_emac_read(uint64_t offset, uint64_t val) "MMIO read: offset=0x%" PRIx64 " value=0x%" PRIx64 | ||
447 | allwinner_sun8i_emac_write(uint64_t offset, uint64_t val) "MMIO write: offset=0x%" PRIx64 " value=0x%" PRIx64 | ||
448 | |||
449 | +# lan9118_phy.c | ||
450 | +lan9118_phy_read(uint16_t val, int reg) "[0x%02x] -> 0x%04" PRIx16 | ||
451 | +lan9118_phy_write(uint16_t val, int reg) "[0x%02x] <- 0x%04" PRIx16 | ||
452 | +lan9118_phy_update_link(const char *s) "%s" | ||
453 | +lan9118_phy_reset(void) "" | ||
454 | + | ||
455 | # lance.c | ||
456 | lance_mem_readw(uint64_t addr, uint32_t ret) "addr=0x%"PRIx64"val=0x%04x" | ||
457 | lance_mem_writew(uint64_t addr, uint32_t val) "addr=0x%"PRIx64"val=0x%04x" | ||
458 | @@ -XXX,XX +XXX,XX @@ i82596_set_multicast(uint16_t count) "Added %d multicast entries" | ||
459 | i82596_channel_attention(void *s) "%p: Received CHANNEL ATTENTION" | ||
460 | |||
461 | # imx_fec.c | ||
462 | -imx_phy_read(uint32_t val, int phy, int reg) "0x%04"PRIx32" <= phy[%d].reg[%d]" | ||
463 | imx_phy_read_num(int phy, int configured) "read request from unconfigured phy %d (configured %d)" | ||
464 | -imx_phy_write(uint32_t val, int phy, int reg) "0x%04"PRIx32" => phy[%d].reg[%d]" | ||
465 | imx_phy_write_num(int phy, int configured) "write request to unconfigured phy %d (configured %d)" | ||
466 | -imx_phy_update_link(const char *s) "%s" | ||
467 | -imx_phy_reset(void) "" | ||
468 | 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" | ||
469 | 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" | ||
470 | imx_eth_tx_bd_busy(void) "tx_bd ran out of descriptors to transmit" | ||
64 | -- | 471 | -- |
65 | 2.34.1 | 472 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Bernhard Beschow <shentey@gmail.com> | ||
1 | 2 | ||
3 | Turns 0x70 into 0xe0 (== 0x70 << 1) which adds the missing MII_ANLPAR_TX and | ||
4 | fixes the MSB of selector field to be zero, as specified in the datasheet. | ||
5 | |||
6 | Fixes: 2a424990170b "LAN9118 emulation" | ||
7 | Signed-off-by: Bernhard Beschow <shentey@gmail.com> | ||
8 | Tested-by: Guenter Roeck <linux@roeck-us.net> | ||
9 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | ||
10 | Message-id: 20241102125724.532843-4-shentey@gmail.com | ||
11 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
12 | --- | ||
13 | hw/net/lan9118_phy.c | 2 +- | ||
14 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
15 | |||
16 | diff --git a/hw/net/lan9118_phy.c b/hw/net/lan9118_phy.c | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/hw/net/lan9118_phy.c | ||
19 | +++ b/hw/net/lan9118_phy.c | ||
20 | @@ -XXX,XX +XXX,XX @@ uint16_t lan9118_phy_read(Lan9118PhyState *s, int reg) | ||
21 | val = s->advertise; | ||
22 | break; | ||
23 | case 5: /* Auto-neg Link Partner Ability */ | ||
24 | - val = 0x0f71; | ||
25 | + val = 0x0fe1; | ||
26 | break; | ||
27 | case 6: /* Auto-neg Expansion */ | ||
28 | val = 1; | ||
29 | -- | ||
30 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Bernhard Beschow <shentey@gmail.com> | ||
1 | 2 | ||
3 | Prefer named constants over magic values for better readability. | ||
4 | |||
5 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | ||
6 | Signed-off-by: Bernhard Beschow <shentey@gmail.com> | ||
7 | Tested-by: Guenter Roeck <linux@roeck-us.net> | ||
8 | Message-id: 20241102125724.532843-5-shentey@gmail.com | ||
9 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
10 | --- | ||
11 | include/hw/net/mii.h | 6 +++++ | ||
12 | hw/net/lan9118_phy.c | 63 ++++++++++++++++++++++++++++---------------- | ||
13 | 2 files changed, 46 insertions(+), 23 deletions(-) | ||
14 | |||
15 | diff --git a/include/hw/net/mii.h b/include/hw/net/mii.h | ||
16 | index XXXXXXX..XXXXXXX 100644 | ||
17 | --- a/include/hw/net/mii.h | ||
18 | +++ b/include/hw/net/mii.h | ||
19 | @@ -XXX,XX +XXX,XX @@ | ||
20 | #define MII_BMSR_JABBER (1 << 1) /* Jabber detected */ | ||
21 | #define MII_BMSR_EXTCAP (1 << 0) /* Ext-reg capability */ | ||
22 | |||
23 | +#define MII_ANAR_RFAULT (1 << 13) /* Say we can detect faults */ | ||
24 | #define MII_ANAR_PAUSE_ASYM (1 << 11) /* Try for asymmetric pause */ | ||
25 | #define MII_ANAR_PAUSE (1 << 10) /* Try for pause */ | ||
26 | #define MII_ANAR_TXFD (1 << 8) | ||
27 | @@ -XXX,XX +XXX,XX @@ | ||
28 | #define MII_ANAR_10FD (1 << 6) | ||
29 | #define MII_ANAR_10 (1 << 5) | ||
30 | #define MII_ANAR_CSMACD (1 << 0) | ||
31 | +#define MII_ANAR_SELECT (0x001f) /* Selector bits */ | ||
32 | |||
33 | #define MII_ANLPAR_ACK (1 << 14) | ||
34 | #define MII_ANLPAR_PAUSEASY (1 << 11) /* can pause asymmetrically */ | ||
35 | @@ -XXX,XX +XXX,XX @@ | ||
36 | #define RTL8201CP_PHYID1 0x0000 | ||
37 | #define RTL8201CP_PHYID2 0x8201 | ||
38 | |||
39 | +/* SMSC LAN9118 */ | ||
40 | +#define SMSCLAN9118_PHYID1 0x0007 | ||
41 | +#define SMSCLAN9118_PHYID2 0xc0d1 | ||
42 | + | ||
43 | /* RealTek 8211E */ | ||
44 | #define RTL8211E_PHYID1 0x001c | ||
45 | #define RTL8211E_PHYID2 0xc915 | ||
46 | diff --git a/hw/net/lan9118_phy.c b/hw/net/lan9118_phy.c | ||
47 | index XXXXXXX..XXXXXXX 100644 | ||
48 | --- a/hw/net/lan9118_phy.c | ||
49 | +++ b/hw/net/lan9118_phy.c | ||
50 | @@ -XXX,XX +XXX,XX @@ | ||
51 | |||
52 | #include "qemu/osdep.h" | ||
53 | #include "hw/net/lan9118_phy.h" | ||
54 | +#include "hw/net/mii.h" | ||
55 | #include "hw/irq.h" | ||
56 | #include "hw/resettable.h" | ||
57 | #include "migration/vmstate.h" | ||
58 | @@ -XXX,XX +XXX,XX @@ uint16_t lan9118_phy_read(Lan9118PhyState *s, int reg) | ||
59 | uint16_t val; | ||
60 | |||
61 | switch (reg) { | ||
62 | - case 0: /* Basic Control */ | ||
63 | + case MII_BMCR: | ||
64 | val = s->control; | ||
65 | break; | ||
66 | - case 1: /* Basic Status */ | ||
67 | + case MII_BMSR: | ||
68 | val = s->status; | ||
69 | break; | ||
70 | - case 2: /* ID1 */ | ||
71 | - val = 0x0007; | ||
72 | + case MII_PHYID1: | ||
73 | + val = SMSCLAN9118_PHYID1; | ||
74 | break; | ||
75 | - case 3: /* ID2 */ | ||
76 | - val = 0xc0d1; | ||
77 | + case MII_PHYID2: | ||
78 | + val = SMSCLAN9118_PHYID2; | ||
79 | break; | ||
80 | - case 4: /* Auto-neg advertisement */ | ||
81 | + case MII_ANAR: | ||
82 | val = s->advertise; | ||
83 | break; | ||
84 | - case 5: /* Auto-neg Link Partner Ability */ | ||
85 | - val = 0x0fe1; | ||
86 | + case MII_ANLPAR: | ||
87 | + val = MII_ANLPAR_PAUSEASY | MII_ANLPAR_PAUSE | MII_ANLPAR_T4 | | ||
88 | + MII_ANLPAR_TXFD | MII_ANLPAR_TX | MII_ANLPAR_10FD | | ||
89 | + MII_ANLPAR_10 | MII_ANLPAR_CSMACD; | ||
90 | break; | ||
91 | - case 6: /* Auto-neg Expansion */ | ||
92 | - val = 1; | ||
93 | + case MII_ANER: | ||
94 | + val = MII_ANER_NWAY; | ||
95 | break; | ||
96 | case 29: /* Interrupt source. */ | ||
97 | val = s->ints; | ||
98 | @@ -XXX,XX +XXX,XX @@ void lan9118_phy_write(Lan9118PhyState *s, int reg, uint16_t val) | ||
99 | trace_lan9118_phy_write(val, reg); | ||
100 | |||
101 | switch (reg) { | ||
102 | - case 0: /* Basic Control */ | ||
103 | - if (val & 0x8000) { | ||
104 | + case MII_BMCR: | ||
105 | + if (val & MII_BMCR_RESET) { | ||
106 | lan9118_phy_reset(s); | ||
107 | } else { | ||
108 | - s->control = val & 0x7980; | ||
109 | + s->control = val & (MII_BMCR_LOOPBACK | MII_BMCR_SPEED100 | | ||
110 | + MII_BMCR_AUTOEN | MII_BMCR_PDOWN | MII_BMCR_FD | | ||
111 | + MII_BMCR_CTST); | ||
112 | /* Complete autonegotiation immediately. */ | ||
113 | - if (val & 0x1000) { | ||
114 | - s->status |= 0x0020; | ||
115 | + if (val & MII_BMCR_AUTOEN) { | ||
116 | + s->status |= MII_BMSR_AN_COMP; | ||
117 | } | ||
118 | } | ||
119 | break; | ||
120 | - case 4: /* Auto-neg advertisement */ | ||
121 | - s->advertise = (val & 0x2d7f) | 0x80; | ||
122 | + case MII_ANAR: | ||
123 | + s->advertise = (val & (MII_ANAR_RFAULT | MII_ANAR_PAUSE_ASYM | | ||
124 | + MII_ANAR_PAUSE | MII_ANAR_10FD | MII_ANAR_10 | | ||
125 | + MII_ANAR_SELECT)) | ||
126 | + | MII_ANAR_TX; | ||
127 | break; | ||
128 | case 30: /* Interrupt mask */ | ||
129 | s->int_mask = val & 0xff; | ||
130 | @@ -XXX,XX +XXX,XX @@ void lan9118_phy_update_link(Lan9118PhyState *s, bool link_down) | ||
131 | /* Autonegotiation status mirrors link status. */ | ||
132 | if (link_down) { | ||
133 | trace_lan9118_phy_update_link("down"); | ||
134 | - s->status &= ~0x0024; | ||
135 | + s->status &= ~(MII_BMSR_AN_COMP | MII_BMSR_LINK_ST); | ||
136 | s->ints |= PHY_INT_DOWN; | ||
137 | } else { | ||
138 | trace_lan9118_phy_update_link("up"); | ||
139 | - s->status |= 0x0024; | ||
140 | + s->status |= MII_BMSR_AN_COMP | MII_BMSR_LINK_ST; | ||
141 | s->ints |= PHY_INT_ENERGYON; | ||
142 | s->ints |= PHY_INT_AUTONEG_COMPLETE; | ||
143 | } | ||
144 | @@ -XXX,XX +XXX,XX @@ void lan9118_phy_reset(Lan9118PhyState *s) | ||
145 | { | ||
146 | trace_lan9118_phy_reset(); | ||
147 | |||
148 | - s->control = 0x3000; | ||
149 | - s->status = 0x7809; | ||
150 | - s->advertise = 0x01e1; | ||
151 | + s->control = MII_BMCR_AUTOEN | MII_BMCR_SPEED100; | ||
152 | + s->status = MII_BMSR_100TX_FD | ||
153 | + | MII_BMSR_100TX_HD | ||
154 | + | MII_BMSR_10T_FD | ||
155 | + | MII_BMSR_10T_HD | ||
156 | + | MII_BMSR_AUTONEG | ||
157 | + | MII_BMSR_EXTCAP; | ||
158 | + s->advertise = MII_ANAR_TXFD | ||
159 | + | MII_ANAR_TX | ||
160 | + | MII_ANAR_10FD | ||
161 | + | MII_ANAR_10 | ||
162 | + | MII_ANAR_CSMACD; | ||
163 | s->int_mask = 0; | ||
164 | s->ints = 0; | ||
165 | lan9118_phy_update_link(s, s->link_down); | ||
166 | -- | ||
167 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Bernhard Beschow <shentey@gmail.com> | ||
1 | 2 | ||
3 | The real device advertises this mode and the device model already advertises | ||
4 | 100 mbps half duplex and 10 mbps full+half duplex. So advertise this mode to | ||
5 | make the model more realistic. | ||
6 | |||
7 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | ||
8 | Signed-off-by: Bernhard Beschow <shentey@gmail.com> | ||
9 | Tested-by: Guenter Roeck <linux@roeck-us.net> | ||
10 | Message-id: 20241102125724.532843-6-shentey@gmail.com | ||
11 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
12 | --- | ||
13 | hw/net/lan9118_phy.c | 4 ++-- | ||
14 | 1 file changed, 2 insertions(+), 2 deletions(-) | ||
15 | |||
16 | diff --git a/hw/net/lan9118_phy.c b/hw/net/lan9118_phy.c | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/hw/net/lan9118_phy.c | ||
19 | +++ b/hw/net/lan9118_phy.c | ||
20 | @@ -XXX,XX +XXX,XX @@ void lan9118_phy_write(Lan9118PhyState *s, int reg, uint16_t val) | ||
21 | break; | ||
22 | case MII_ANAR: | ||
23 | s->advertise = (val & (MII_ANAR_RFAULT | MII_ANAR_PAUSE_ASYM | | ||
24 | - MII_ANAR_PAUSE | MII_ANAR_10FD | MII_ANAR_10 | | ||
25 | - MII_ANAR_SELECT)) | ||
26 | + MII_ANAR_PAUSE | MII_ANAR_TXFD | MII_ANAR_10FD | | ||
27 | + MII_ANAR_10 | MII_ANAR_SELECT)) | ||
28 | | MII_ANAR_TX; | ||
29 | break; | ||
30 | case 30: /* Interrupt mask */ | ||
31 | -- | ||
32 | 2.34.1 | diff view generated by jsdifflib |
1 | In handle_sys() we don't do the check for whether the register is | 1 | For IEEE fused multiply-add, the (0 * inf) + NaN case should raise |
---|---|---|---|
2 | marked as needing an FPU/SVE/SME access check until after we've | 2 | Invalid for the multiplication of 0 by infinity. Currently we handle |
3 | handled the special cases covered by ARM_CP_SPECIAL_MASK. This is | 3 | this in the per-architecture ifdef ladder in pickNaNMulAdd(). |
4 | conceptually the wrong way around, because if for example we happen | 4 | However, since this isn't really architecture specific we can hoist |
5 | to implement an FPU-access-checked register as ARM_CP_NOP, we should | 5 | it up to the generic code. |
6 | do the access check first. | ||
7 | 6 | ||
8 | Move the access checks up so they are with all the other access | 7 | For the cases where the infzero test in pickNaNMulAdd was |
9 | checks, not sandwiched between the special-case read/write handling | 8 | returning 2, we can delete the check entirely and allow the |
10 | and the normal-case read/write handling. This doesn't change | 9 | code to fall into the normal pick-a-NaN handling, because this |
11 | behaviour at the moment, because we happen not to define any | 10 | will return 2 anyway (input 'c' being the only NaN in this case). |
12 | cpregs with both ARM_CPU_{FPU,SVE,SME} and one of the cases | 11 | For the cases where infzero was returning 3 to indicate "return |
13 | dealt with by ARM_CP_SPECIAL_MASK. | 12 | the default NaN", we must retain that "return 3". |
14 | 13 | ||
15 | Moving this code also means we have the correct place to put the | 14 | For Arm, this looks like it might be a behaviour change because we |
16 | FEAT_NV/FEAT_NV2 access handling, which should come after the access | 15 | used to set float_flag_invalid | float_flag_invalid_imz only if C is |
17 | checks and before we try to do any read/write action. | 16 | a quiet NaN. However, it is not, because Arm target code never looks |
17 | at float_flag_invalid_imz, and for the (0 * inf) + SNaN case we | ||
18 | already raised float_flag_invalid via the "abc_mask & | ||
19 | float_cmask_snan" check in pick_nan_muladd. | ||
20 | |||
21 | For any target architecture using the "default implementation" at the | ||
22 | bottom of the ifdef, this is a behaviour change but will be fixing a | ||
23 | bug (where we failed to raise the Invalid exception for (0 * inf + | ||
24 | QNaN). The architectures using the default case are: | ||
25 | * hppa | ||
26 | * i386 | ||
27 | * sh4 | ||
28 | * tricore | ||
29 | |||
30 | The x86, Tricore and SH4 CPU architecture manuals are clear that this | ||
31 | should have raised Invalid; HPPA is a bit vaguer but still seems | ||
32 | clear enough. | ||
18 | 33 | ||
19 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 34 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
20 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 35 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
21 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 36 | Message-id: 20241202131347.498124-2-peter.maydell@linaro.org |
22 | --- | 37 | --- |
23 | target/arm/tcg/translate-a64.c | 15 ++++++++------- | 38 | fpu/softfloat-parts.c.inc | 13 +++++++------ |
24 | 1 file changed, 8 insertions(+), 7 deletions(-) | 39 | fpu/softfloat-specialize.c.inc | 29 +---------------------------- |
40 | 2 files changed, 8 insertions(+), 34 deletions(-) | ||
25 | 41 | ||
26 | diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c | 42 | diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc |
27 | index XXXXXXX..XXXXXXX 100644 | 43 | index XXXXXXX..XXXXXXX 100644 |
28 | --- a/target/arm/tcg/translate-a64.c | 44 | --- a/fpu/softfloat-parts.c.inc |
29 | +++ b/target/arm/tcg/translate-a64.c | 45 | +++ b/fpu/softfloat-parts.c.inc |
30 | @@ -XXX,XX +XXX,XX @@ static void handle_sys(DisasContext *s, bool isread, | 46 | @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b, |
31 | gen_a64_update_pc(s, 0); | 47 | int ab_mask, int abc_mask) |
48 | { | ||
49 | int which; | ||
50 | + bool infzero = (ab_mask == float_cmask_infzero); | ||
51 | |||
52 | if (unlikely(abc_mask & float_cmask_snan)) { | ||
53 | float_raise(float_flag_invalid | float_flag_invalid_snan, s); | ||
32 | } | 54 | } |
33 | 55 | ||
34 | + if ((ri->type & ARM_CP_FPU) && !fp_access_check_only(s)) { | 56 | - which = pickNaNMulAdd(a->cls, b->cls, c->cls, |
35 | + return; | 57 | - ab_mask == float_cmask_infzero, s); |
36 | + } else if ((ri->type & ARM_CP_SVE) && !sve_access_check(s)) { | 58 | + if (infzero) { |
37 | + return; | 59 | + /* This is (0 * inf) + NaN or (inf * 0) + NaN */ |
38 | + } else if ((ri->type & ARM_CP_SME) && !sme_access_check(s)) { | 60 | + float_raise(float_flag_invalid | float_flag_invalid_imz, s); |
39 | + return; | ||
40 | + } | 61 | + } |
41 | + | 62 | + |
42 | /* Handle special cases first */ | 63 | + which = pickNaNMulAdd(a->cls, b->cls, c->cls, infzero, s); |
43 | switch (ri->type & ARM_CP_SPECIAL_MASK) { | 64 | |
44 | case 0: | 65 | if (s->default_nan_mode || which == 3) { |
45 | @@ -XXX,XX +XXX,XX @@ static void handle_sys(DisasContext *s, bool isread, | 66 | - /* |
46 | default: | 67 | - * Note that this check is after pickNaNMulAdd so that function |
47 | g_assert_not_reached(); | 68 | - * has an opportunity to set the Invalid flag for infzero. |
69 | - */ | ||
70 | parts_default_nan(a, s); | ||
71 | return a; | ||
48 | } | 72 | } |
49 | - if ((ri->type & ARM_CP_FPU) && !fp_access_check_only(s)) { | 73 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc |
50 | - return; | 74 | index XXXXXXX..XXXXXXX 100644 |
51 | - } else if ((ri->type & ARM_CP_SVE) && !sve_access_check(s)) { | 75 | --- a/fpu/softfloat-specialize.c.inc |
52 | - return; | 76 | +++ b/fpu/softfloat-specialize.c.inc |
53 | - } else if ((ri->type & ARM_CP_SME) && !sme_access_check(s)) { | 77 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, |
54 | - return; | 78 | * the default NaN |
79 | */ | ||
80 | if (infzero && is_qnan(c_cls)) { | ||
81 | - float_raise(float_flag_invalid | float_flag_invalid_imz, status); | ||
82 | return 3; | ||
83 | } | ||
84 | |||
85 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
86 | * case sets InvalidOp and returns the default NaN | ||
87 | */ | ||
88 | if (infzero) { | ||
89 | - float_raise(float_flag_invalid | float_flag_invalid_imz, status); | ||
90 | return 3; | ||
91 | } | ||
92 | /* Prefer sNaN over qNaN, in the a, b, c order. */ | ||
93 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
94 | * For MIPS systems that conform to IEEE754-2008, the (inf,zero,nan) | ||
95 | * case sets InvalidOp and returns the input value 'c' | ||
96 | */ | ||
97 | - if (infzero) { | ||
98 | - float_raise(float_flag_invalid | float_flag_invalid_imz, status); | ||
99 | - return 2; | ||
100 | - } | ||
101 | /* Prefer sNaN over qNaN, in the c, a, b order. */ | ||
102 | if (is_snan(c_cls)) { | ||
103 | return 2; | ||
104 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
105 | * For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan) | ||
106 | * case sets InvalidOp and returns the input value 'c' | ||
107 | */ | ||
108 | - if (infzero) { | ||
109 | - float_raise(float_flag_invalid | float_flag_invalid_imz, status); | ||
110 | - return 2; | ||
55 | - } | 111 | - } |
56 | 112 | + | |
57 | if (ri->type & ARM_CP_IO) { | 113 | /* Prefer sNaN over qNaN, in the c, a, b order. */ |
58 | /* I/O operations must end the TB here (whether read or write) */ | 114 | if (is_snan(c_cls)) { |
115 | return 2; | ||
116 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
117 | * to return an input NaN if we have one (ie c) rather than generating | ||
118 | * a default NaN | ||
119 | */ | ||
120 | - if (infzero) { | ||
121 | - float_raise(float_flag_invalid | float_flag_invalid_imz, status); | ||
122 | - return 2; | ||
123 | - } | ||
124 | |||
125 | /* If fRA is a NaN return it; otherwise if fRB is a NaN return it; | ||
126 | * otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB | ||
127 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
128 | return 1; | ||
129 | } | ||
130 | #elif defined(TARGET_RISCV) | ||
131 | - /* For RISC-V, InvalidOp is set when multiplicands are Inf and zero */ | ||
132 | - if (infzero) { | ||
133 | - float_raise(float_flag_invalid | float_flag_invalid_imz, status); | ||
134 | - } | ||
135 | return 3; /* default NaN */ | ||
136 | #elif defined(TARGET_S390X) | ||
137 | if (infzero) { | ||
138 | - float_raise(float_flag_invalid | float_flag_invalid_imz, status); | ||
139 | return 3; | ||
140 | } | ||
141 | |||
142 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
143 | return 2; | ||
144 | } | ||
145 | #elif defined(TARGET_SPARC) | ||
146 | - /* For (inf,0,nan) return c. */ | ||
147 | - if (infzero) { | ||
148 | - float_raise(float_flag_invalid | float_flag_invalid_imz, status); | ||
149 | - return 2; | ||
150 | - } | ||
151 | /* Prefer SNaN over QNaN, order C, B, A. */ | ||
152 | if (is_snan(c_cls)) { | ||
153 | return 2; | ||
154 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
155 | * For Xtensa, the (inf,zero,nan) case sets InvalidOp and returns | ||
156 | * an input NaN if we have one (ie c). | ||
157 | */ | ||
158 | - if (infzero) { | ||
159 | - float_raise(float_flag_invalid | float_flag_invalid_imz, status); | ||
160 | - return 2; | ||
161 | - } | ||
162 | if (status->use_first_nan) { | ||
163 | if (is_nan(a_cls)) { | ||
164 | return 0; | ||
59 | -- | 165 | -- |
60 | 2.34.1 | 166 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | If the target sets default_nan_mode then we're always going to return | ||
2 | the default NaN, and pickNaNMulAdd() no longer has any side effects. | ||
3 | For consistency with pickNaN(), check for default_nan_mode before | ||
4 | calling pickNaNMulAdd(). | ||
1 | 5 | ||
6 | When we convert pickNaNMulAdd() to allow runtime selection of the NaN | ||
7 | propagation rule, this means we won't have to make the targets which | ||
8 | use default_nan_mode also set a propagation rule. | ||
9 | |||
10 | Since RiscV always uses default_nan_mode, this allows us to remove | ||
11 | its ifdef case from pickNaNMulAdd(). | ||
12 | |||
13 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
14 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
15 | Message-id: 20241202131347.498124-3-peter.maydell@linaro.org | ||
16 | --- | ||
17 | fpu/softfloat-parts.c.inc | 8 ++++++-- | ||
18 | fpu/softfloat-specialize.c.inc | 9 +++++++-- | ||
19 | 2 files changed, 13 insertions(+), 4 deletions(-) | ||
20 | |||
21 | diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc | ||
22 | index XXXXXXX..XXXXXXX 100644 | ||
23 | --- a/fpu/softfloat-parts.c.inc | ||
24 | +++ b/fpu/softfloat-parts.c.inc | ||
25 | @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b, | ||
26 | float_raise(float_flag_invalid | float_flag_invalid_imz, s); | ||
27 | } | ||
28 | |||
29 | - which = pickNaNMulAdd(a->cls, b->cls, c->cls, infzero, s); | ||
30 | + if (s->default_nan_mode) { | ||
31 | + which = 3; | ||
32 | + } else { | ||
33 | + which = pickNaNMulAdd(a->cls, b->cls, c->cls, infzero, s); | ||
34 | + } | ||
35 | |||
36 | - if (s->default_nan_mode || which == 3) { | ||
37 | + if (which == 3) { | ||
38 | parts_default_nan(a, s); | ||
39 | return a; | ||
40 | } | ||
41 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc | ||
42 | index XXXXXXX..XXXXXXX 100644 | ||
43 | --- a/fpu/softfloat-specialize.c.inc | ||
44 | +++ b/fpu/softfloat-specialize.c.inc | ||
45 | @@ -XXX,XX +XXX,XX @@ static int pickNaN(FloatClass a_cls, FloatClass b_cls, | ||
46 | static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
47 | bool infzero, float_status *status) | ||
48 | { | ||
49 | + /* | ||
50 | + * We guarantee not to require the target to tell us how to | ||
51 | + * pick a NaN if we're always returning the default NaN. | ||
52 | + * But if we're not in default-NaN mode then the target must | ||
53 | + * specify. | ||
54 | + */ | ||
55 | + assert(!status->default_nan_mode); | ||
56 | #if defined(TARGET_ARM) | ||
57 | /* For ARM, the (inf,zero,qnan) case sets InvalidOp and returns | ||
58 | * the default NaN | ||
59 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
60 | } else { | ||
61 | return 1; | ||
62 | } | ||
63 | -#elif defined(TARGET_RISCV) | ||
64 | - return 3; /* default NaN */ | ||
65 | #elif defined(TARGET_S390X) | ||
66 | if (infzero) { | ||
67 | return 3; | ||
68 | -- | ||
69 | 2.34.1 | diff view generated by jsdifflib |
1 | For FEAT_VHE, we define a set of register aliases, so that for instance: | 1 | IEEE 758 does not define a fixed rule for what NaN to return in |
---|---|---|---|
2 | * the SCTLR_EL1 either accesses the real SCTLR_EL1, or (if E2H is 1) | 2 | the case of a fused multiply-add of inf * 0 + NaN. Different |
3 | SCTLR_EL2 | 3 | architectures thus do different things: |
4 | * a new SCTLR_EL12 register accesses SCTLR_EL1 if E2H is 1 | 4 | * some return the default NaN |
5 | 5 | * some return the input NaN | |
6 | However when we create the 'new_reg' cpreg struct for the SCTLR_EL12 | 6 | * Arm returns the default NaN if the input NaN is quiet, |
7 | register, we duplicate the information in the SCTLR_EL1 cpreg, which | 7 | and the input NaN if it is signalling |
8 | means the opcode fields are those of SCTLR_EL1, not SCTLR_EL12. This | 8 | |
9 | is a problem for code which looks at the cpreg opcode fields to | 9 | We want to make this logic be runtime selected rather than |
10 | determine behaviour (e.g. in access_check_cp_reg()). In practice | 10 | hardcoded into the binary, because: |
11 | the current checks we do there don't intersect with the *_EL12 | 11 | * this will let us have multiple targets in one QEMU binary |
12 | registers, but for FEAT_NV this will become a problem. | 12 | * the Arm FEAT_AFP architectural feature includes letting |
13 | 13 | the guest select a NaN propagation rule at runtime | |
14 | Write the correct values from the encoding into the new_reg struct. | 14 | |
15 | This restores the invariant that the cpreg that you get back | 15 | In this commit we add an enum for the propagation rule, the field in |
16 | from the hashtable has opcode fields that match the key you used | 16 | float_status, and the corresponding getters and setters. We change |
17 | to retrieve it. | 17 | pickNaNMulAdd to honour this, but because all targets still leave |
18 | 18 | this field at its default 0 value, the fallback logic will pick the | |
19 | When we call the readfn or writefn for the target register, we | 19 | rule type with the old ifdef ladder. |
20 | pass it the cpreg struct for that target register, not the one | 20 | |
21 | for the alias, in case the readfn/writefn want to look at the | 21 | Note that four architectures both use the muladd softfloat functions |
22 | opcode fields to determine behaviour. This means we need to | 22 | and did not have a branch of the ifdef ladder to specify their |
23 | interpose custom read/writefns for the e12 aliases. | 23 | behaviour (and so were ending up with the "default" case, probably |
24 | wrongly): i386, HPPA, SH4 and Tricore. SH4 and Tricore both set | ||
25 | default_nan_mode, and so will never get into pickNaNMulAdd(). For | ||
26 | HPPA and i386 we retain the same behaviour as the old default-case, | ||
27 | which is to not ever return the default NaN. This might not be | ||
28 | correct but it is not a behaviour change. | ||
24 | 29 | ||
25 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 30 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
26 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 31 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
27 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 32 | Message-id: 20241202131347.498124-4-peter.maydell@linaro.org |
28 | --- | 33 | --- |
29 | target/arm/helper.c | 35 +++++++++++++++++++++++++++++++++++ | 34 | include/fpu/softfloat-helpers.h | 11 ++++ |
30 | 1 file changed, 35 insertions(+) | 35 | include/fpu/softfloat-types.h | 23 +++++++++ |
31 | 36 | fpu/softfloat-specialize.c.inc | 91 ++++++++++++++++++++++----------- | |
32 | diff --git a/target/arm/helper.c b/target/arm/helper.c | 37 | 3 files changed, 95 insertions(+), 30 deletions(-) |
38 | |||
39 | diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h | ||
33 | index XXXXXXX..XXXXXXX 100644 | 40 | index XXXXXXX..XXXXXXX 100644 |
34 | --- a/target/arm/helper.c | 41 | --- a/include/fpu/softfloat-helpers.h |
35 | +++ b/target/arm/helper.c | 42 | +++ b/include/fpu/softfloat-helpers.h |
36 | @@ -XXX,XX +XXX,XX @@ static void el2_e2h_write(CPUARMState *env, const ARMCPRegInfo *ri, | 43 | @@ -XXX,XX +XXX,XX @@ static inline void set_float_2nan_prop_rule(Float2NaNPropRule rule, |
37 | writefn(env, ri, value); | 44 | status->float_2nan_prop_rule = rule; |
38 | } | 45 | } |
39 | 46 | ||
40 | +static uint64_t el2_e2h_e12_read(CPUARMState *env, const ARMCPRegInfo *ri) | 47 | +static inline void set_float_infzeronan_rule(FloatInfZeroNaNRule rule, |
48 | + float_status *status) | ||
41 | +{ | 49 | +{ |
42 | + /* Pass the EL1 register accessor its ri, not the EL12 alias ri */ | 50 | + status->float_infzeronan_rule = rule; |
43 | + return ri->orig_readfn(env, ri->opaque); | ||
44 | +} | 51 | +} |
45 | + | 52 | + |
46 | +static void el2_e2h_e12_write(CPUARMState *env, const ARMCPRegInfo *ri, | 53 | static inline void set_flush_to_zero(bool val, float_status *status) |
47 | + uint64_t value) | 54 | { |
55 | status->flush_to_zero = val; | ||
56 | @@ -XXX,XX +XXX,XX @@ static inline Float2NaNPropRule get_float_2nan_prop_rule(float_status *status) | ||
57 | return status->float_2nan_prop_rule; | ||
58 | } | ||
59 | |||
60 | +static inline FloatInfZeroNaNRule get_float_infzeronan_rule(float_status *status) | ||
48 | +{ | 61 | +{ |
49 | + /* Pass the EL1 register accessor its ri, not the EL12 alias ri */ | 62 | + return status->float_infzeronan_rule; |
50 | + return ri->orig_writefn(env, ri->opaque, value); | ||
51 | +} | 63 | +} |
52 | + | 64 | + |
53 | static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu) | 65 | static inline bool get_flush_to_zero(float_status *status) |
54 | { | 66 | { |
55 | struct E2HAlias { | 67 | return status->flush_to_zero; |
56 | @@ -XXX,XX +XXX,XX @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu) | 68 | diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h |
57 | new_reg->type |= ARM_CP_ALIAS; | 69 | index XXXXXXX..XXXXXXX 100644 |
58 | /* Remove PL1/PL0 access, leaving PL2/PL3 R/W in place. */ | 70 | --- a/include/fpu/softfloat-types.h |
59 | new_reg->access &= PL2_RW | PL3_RW; | 71 | +++ b/include/fpu/softfloat-types.h |
60 | + /* The new_reg op fields are as per new_key, not the target reg */ | 72 | @@ -XXX,XX +XXX,XX @@ typedef enum __attribute__((__packed__)) { |
61 | + new_reg->crn = (a->new_key & CP_REG_ARM64_SYSREG_CRN_MASK) | 73 | float_2nan_prop_x87, |
62 | + >> CP_REG_ARM64_SYSREG_CRN_SHIFT; | 74 | } Float2NaNPropRule; |
63 | + new_reg->crm = (a->new_key & CP_REG_ARM64_SYSREG_CRM_MASK) | 75 | |
64 | + >> CP_REG_ARM64_SYSREG_CRM_SHIFT; | 76 | +/* |
65 | + new_reg->opc0 = (a->new_key & CP_REG_ARM64_SYSREG_OP0_MASK) | 77 | + * Rule for result of fused multiply-add 0 * Inf + NaN. |
66 | + >> CP_REG_ARM64_SYSREG_OP0_SHIFT; | 78 | + * This must be a NaN, but implementations differ on whether this |
67 | + new_reg->opc1 = (a->new_key & CP_REG_ARM64_SYSREG_OP1_MASK) | 79 | + * is the input NaN or the default NaN. |
68 | + >> CP_REG_ARM64_SYSREG_OP1_SHIFT; | 80 | + * |
69 | + new_reg->opc2 = (a->new_key & CP_REG_ARM64_SYSREG_OP2_MASK) | 81 | + * You don't need to set this if default_nan_mode is enabled. |
70 | + >> CP_REG_ARM64_SYSREG_OP2_SHIFT; | 82 | + * When not in default-NaN mode, it is an error for the target |
71 | + new_reg->opaque = src_reg; | 83 | + * not to set the rule in float_status if it uses muladd, and we |
72 | + new_reg->orig_readfn = src_reg->readfn ?: raw_read; | 84 | + * will assert if we need to handle an input NaN and no rule was |
73 | + new_reg->orig_writefn = src_reg->writefn ?: raw_write; | 85 | + * selected. |
74 | + if (!new_reg->raw_readfn) { | 86 | + */ |
75 | + new_reg->raw_readfn = raw_read; | 87 | +typedef enum __attribute__((__packed__)) { |
88 | + /* No propagation rule specified */ | ||
89 | + float_infzeronan_none = 0, | ||
90 | + /* Result is never the default NaN (so always the input NaN) */ | ||
91 | + float_infzeronan_dnan_never, | ||
92 | + /* Result is always the default NaN */ | ||
93 | + float_infzeronan_dnan_always, | ||
94 | + /* Result is the default NaN if the input NaN is quiet */ | ||
95 | + float_infzeronan_dnan_if_qnan, | ||
96 | +} FloatInfZeroNaNRule; | ||
97 | + | ||
98 | /* | ||
99 | * Floating Point Status. Individual architectures may maintain | ||
100 | * several versions of float_status for different functions. The | ||
101 | @@ -XXX,XX +XXX,XX @@ typedef struct float_status { | ||
102 | FloatRoundMode float_rounding_mode; | ||
103 | FloatX80RoundPrec floatx80_rounding_precision; | ||
104 | Float2NaNPropRule float_2nan_prop_rule; | ||
105 | + FloatInfZeroNaNRule float_infzeronan_rule; | ||
106 | bool tininess_before_rounding; | ||
107 | /* should denormalised results go to zero and set the inexact flag? */ | ||
108 | bool flush_to_zero; | ||
109 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc | ||
110 | index XXXXXXX..XXXXXXX 100644 | ||
111 | --- a/fpu/softfloat-specialize.c.inc | ||
112 | +++ b/fpu/softfloat-specialize.c.inc | ||
113 | @@ -XXX,XX +XXX,XX @@ static int pickNaN(FloatClass a_cls, FloatClass b_cls, | ||
114 | static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
115 | bool infzero, float_status *status) | ||
116 | { | ||
117 | + FloatInfZeroNaNRule rule = status->float_infzeronan_rule; | ||
118 | + | ||
119 | /* | ||
120 | * We guarantee not to require the target to tell us how to | ||
121 | * pick a NaN if we're always returning the default NaN. | ||
122 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
123 | * specify. | ||
124 | */ | ||
125 | assert(!status->default_nan_mode); | ||
126 | + | ||
127 | + if (rule == float_infzeronan_none) { | ||
128 | + /* | ||
129 | + * Temporarily fall back to ifdef ladder | ||
130 | + */ | ||
131 | #if defined(TARGET_ARM) | ||
132 | - /* For ARM, the (inf,zero,qnan) case sets InvalidOp and returns | ||
133 | - * the default NaN | ||
134 | - */ | ||
135 | - if (infzero && is_qnan(c_cls)) { | ||
136 | - return 3; | ||
137 | + /* | ||
138 | + * For ARM, the (inf,zero,qnan) case returns the default NaN, | ||
139 | + * but (inf,zero,snan) returns the input NaN. | ||
140 | + */ | ||
141 | + rule = float_infzeronan_dnan_if_qnan; | ||
142 | +#elif defined(TARGET_MIPS) | ||
143 | + if (snan_bit_is_one(status)) { | ||
144 | + /* | ||
145 | + * For MIPS systems that conform to IEEE754-1985, the (inf,zero,nan) | ||
146 | + * case sets InvalidOp and returns the default NaN | ||
147 | + */ | ||
148 | + rule = float_infzeronan_dnan_always; | ||
149 | + } else { | ||
150 | + /* | ||
151 | + * For MIPS systems that conform to IEEE754-2008, the (inf,zero,nan) | ||
152 | + * case sets InvalidOp and returns the input value 'c' | ||
153 | + */ | ||
154 | + rule = float_infzeronan_dnan_never; | ||
76 | + } | 155 | + } |
77 | + if (!new_reg->raw_writefn) { | 156 | +#elif defined(TARGET_PPC) || defined(TARGET_SPARC) || \ |
78 | + new_reg->raw_writefn = raw_write; | 157 | + defined(TARGET_XTENSA) || defined(TARGET_HPPA) || \ |
158 | + defined(TARGET_I386) || defined(TARGET_LOONGARCH) | ||
159 | + /* | ||
160 | + * For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan) | ||
161 | + * case sets InvalidOp and returns the input value 'c' | ||
162 | + */ | ||
163 | + /* | ||
164 | + * For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer | ||
165 | + * to return an input NaN if we have one (ie c) rather than generating | ||
166 | + * a default NaN | ||
167 | + */ | ||
168 | + rule = float_infzeronan_dnan_never; | ||
169 | +#elif defined(TARGET_S390X) | ||
170 | + rule = float_infzeronan_dnan_always; | ||
171 | +#endif | ||
172 | } | ||
173 | |||
174 | + if (infzero) { | ||
175 | + /* | ||
176 | + * Inf * 0 + NaN -- some implementations return the default NaN here, | ||
177 | + * and some return the input NaN. | ||
178 | + */ | ||
179 | + switch (rule) { | ||
180 | + case float_infzeronan_dnan_never: | ||
181 | + return 2; | ||
182 | + case float_infzeronan_dnan_always: | ||
183 | + return 3; | ||
184 | + case float_infzeronan_dnan_if_qnan: | ||
185 | + return is_qnan(c_cls) ? 3 : 2; | ||
186 | + default: | ||
187 | + g_assert_not_reached(); | ||
79 | + } | 188 | + } |
80 | + new_reg->readfn = el2_e2h_e12_read; | 189 | + } |
81 | + new_reg->writefn = el2_e2h_e12_write; | 190 | + |
82 | 191 | +#if defined(TARGET_ARM) | |
83 | ok = g_hash_table_insert(cpu->cp_regs, | 192 | + |
84 | (gpointer)(uintptr_t)a->new_key, new_reg); | 193 | /* This looks different from the ARM ARM pseudocode, because the ARM ARM |
194 | * puts the operands to a fused mac operation (a*b)+c in the order c,a,b. | ||
195 | */ | ||
196 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
197 | } | ||
198 | #elif defined(TARGET_MIPS) | ||
199 | if (snan_bit_is_one(status)) { | ||
200 | - /* | ||
201 | - * For MIPS systems that conform to IEEE754-1985, the (inf,zero,nan) | ||
202 | - * case sets InvalidOp and returns the default NaN | ||
203 | - */ | ||
204 | - if (infzero) { | ||
205 | - return 3; | ||
206 | - } | ||
207 | /* Prefer sNaN over qNaN, in the a, b, c order. */ | ||
208 | if (is_snan(a_cls)) { | ||
209 | return 0; | ||
210 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
211 | return 2; | ||
212 | } | ||
213 | } else { | ||
214 | - /* | ||
215 | - * For MIPS systems that conform to IEEE754-2008, the (inf,zero,nan) | ||
216 | - * case sets InvalidOp and returns the input value 'c' | ||
217 | - */ | ||
218 | /* Prefer sNaN over qNaN, in the c, a, b order. */ | ||
219 | if (is_snan(c_cls)) { | ||
220 | return 2; | ||
221 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
222 | } | ||
223 | } | ||
224 | #elif defined(TARGET_LOONGARCH64) | ||
225 | - /* | ||
226 | - * For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan) | ||
227 | - * case sets InvalidOp and returns the input value 'c' | ||
228 | - */ | ||
229 | - | ||
230 | /* Prefer sNaN over qNaN, in the c, a, b order. */ | ||
231 | if (is_snan(c_cls)) { | ||
232 | return 2; | ||
233 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
234 | return 1; | ||
235 | } | ||
236 | #elif defined(TARGET_PPC) | ||
237 | - /* For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer | ||
238 | - * to return an input NaN if we have one (ie c) rather than generating | ||
239 | - * a default NaN | ||
240 | - */ | ||
241 | - | ||
242 | /* If fRA is a NaN return it; otherwise if fRB is a NaN return it; | ||
243 | * otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB | ||
244 | */ | ||
245 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
246 | return 1; | ||
247 | } | ||
248 | #elif defined(TARGET_S390X) | ||
249 | - if (infzero) { | ||
250 | - return 3; | ||
251 | - } | ||
252 | - | ||
253 | if (is_snan(a_cls)) { | ||
254 | return 0; | ||
255 | } else if (is_snan(b_cls)) { | ||
85 | -- | 256 | -- |
86 | 2.34.1 | 257 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Explicitly set a rule in the softfloat tests for the inf-zero-nan | ||
2 | muladd special case. In meson.build we put -DTARGET_ARM in fpcflags, | ||
3 | and so we should select here the Arm rule of | ||
4 | float_infzeronan_dnan_if_qnan. | ||
1 | 5 | ||
6 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
7 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
8 | Message-id: 20241202131347.498124-5-peter.maydell@linaro.org | ||
9 | --- | ||
10 | tests/fp/fp-bench.c | 5 +++++ | ||
11 | tests/fp/fp-test.c | 5 +++++ | ||
12 | 2 files changed, 10 insertions(+) | ||
13 | |||
14 | diff --git a/tests/fp/fp-bench.c b/tests/fp/fp-bench.c | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/tests/fp/fp-bench.c | ||
17 | +++ b/tests/fp/fp-bench.c | ||
18 | @@ -XXX,XX +XXX,XX @@ static void run_bench(void) | ||
19 | { | ||
20 | bench_func_t f; | ||
21 | |||
22 | + /* | ||
23 | + * These implementation-defined choices for various things IEEE | ||
24 | + * doesn't specify match those used by the Arm architecture. | ||
25 | + */ | ||
26 | set_float_2nan_prop_rule(float_2nan_prop_s_ab, &soft_status); | ||
27 | + set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, &soft_status); | ||
28 | |||
29 | f = bench_funcs[operation][precision]; | ||
30 | g_assert(f); | ||
31 | diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c | ||
32 | index XXXXXXX..XXXXXXX 100644 | ||
33 | --- a/tests/fp/fp-test.c | ||
34 | +++ b/tests/fp/fp-test.c | ||
35 | @@ -XXX,XX +XXX,XX @@ void run_test(void) | ||
36 | { | ||
37 | unsigned int i; | ||
38 | |||
39 | + /* | ||
40 | + * These implementation-defined choices for various things IEEE | ||
41 | + * doesn't specify match those used by the Arm architecture. | ||
42 | + */ | ||
43 | set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf); | ||
44 | + set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, &qsf); | ||
45 | |||
46 | genCases_setLevel(test_level); | ||
47 | verCases_maxErrorCount = n_max_errors; | ||
48 | -- | ||
49 | 2.34.1 | diff view generated by jsdifflib |
1 | When interpreting CPU dumps where FEAT_NV and FEAT_NV2 are in use, | 1 | Set the FloatInfZeroNaNRule explicitly for the Arm target, |
---|---|---|---|
2 | it's helpful to include the values of HCR_EL2.{NV,NV1,NV2} in the CPU | 2 | so we can remove the ifdef from pickNaNMulAdd(). |
3 | dump format, as a way of distinguishing when we are in EL1 as part of | ||
4 | executing guest-EL2 and when we are just in normal EL1. | ||
5 | |||
6 | Add the bits to the end of the log line that shows PSTATE and similar | ||
7 | information: | ||
8 | |||
9 | PSTATE=000003c9 ---- EL2h BTYPE=0 NV NV2 | ||
10 | 3 | ||
11 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 4 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
12 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 5 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
13 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 6 | Message-id: 20241202131347.498124-6-peter.maydell@linaro.org |
14 | --- | 7 | --- |
15 | target/arm/cpu.c | 5 +++++ | 8 | target/arm/cpu.c | 3 +++ |
16 | 1 file changed, 5 insertions(+) | 9 | fpu/softfloat-specialize.c.inc | 8 +------- |
10 | 2 files changed, 4 insertions(+), 7 deletions(-) | ||
17 | 11 | ||
18 | diff --git a/target/arm/cpu.c b/target/arm/cpu.c | 12 | diff --git a/target/arm/cpu.c b/target/arm/cpu.c |
19 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
20 | --- a/target/arm/cpu.c | 14 | --- a/target/arm/cpu.c |
21 | +++ b/target/arm/cpu.c | 15 | +++ b/target/arm/cpu.c |
22 | @@ -XXX,XX +XXX,XX @@ static void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags) | 16 | @@ -XXX,XX +XXX,XX @@ void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook, |
23 | uint32_t psr = pstate_read(env); | 17 | * * tininess-before-rounding |
24 | int i, j; | 18 | * * 2-input NaN propagation prefers SNaN over QNaN, and then |
25 | int el = arm_current_el(env); | 19 | * operand A over operand B (see FPProcessNaNs() pseudocode) |
26 | + uint64_t hcr = arm_hcr_el2_eff(env); | 20 | + * * 0 * Inf + NaN returns the default NaN if the input NaN is quiet, |
27 | const char *ns_status; | 21 | + * and the input NaN if it is signalling |
28 | bool sve; | 22 | */ |
29 | 23 | static void arm_set_default_fp_behaviours(float_status *s) | |
30 | @@ -XXX,XX +XXX,XX @@ static void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags) | 24 | { |
31 | if (cpu_isar_feature(aa64_bti, cpu)) { | 25 | set_float_detect_tininess(float_tininess_before_rounding, s); |
32 | qemu_fprintf(f, " BTYPE=%d", (psr & PSTATE_BTYPE) >> 10); | 26 | set_float_2nan_prop_rule(float_2nan_prop_s_ab, s); |
33 | } | 27 | + set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, s); |
34 | + qemu_fprintf(f, "%s%s%s", | 28 | } |
35 | + (hcr & HCR_NV) ? " NV" : "", | 29 | |
36 | + (hcr & HCR_NV1) ? " NV1" : "", | 30 | static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque) |
37 | + (hcr & HCR_NV2) ? " NV2" : ""); | 31 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc |
38 | if (!(flags & CPU_DUMP_FPU)) { | 32 | index XXXXXXX..XXXXXXX 100644 |
39 | qemu_fprintf(f, "\n"); | 33 | --- a/fpu/softfloat-specialize.c.inc |
40 | return; | 34 | +++ b/fpu/softfloat-specialize.c.inc |
35 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
36 | /* | ||
37 | * Temporarily fall back to ifdef ladder | ||
38 | */ | ||
39 | -#if defined(TARGET_ARM) | ||
40 | - /* | ||
41 | - * For ARM, the (inf,zero,qnan) case returns the default NaN, | ||
42 | - * but (inf,zero,snan) returns the input NaN. | ||
43 | - */ | ||
44 | - rule = float_infzeronan_dnan_if_qnan; | ||
45 | -#elif defined(TARGET_MIPS) | ||
46 | +#if defined(TARGET_MIPS) | ||
47 | if (snan_bit_is_one(status)) { | ||
48 | /* | ||
49 | * For MIPS systems that conform to IEEE754-1985, the (inf,zero,nan) | ||
41 | -- | 50 | -- |
42 | 2.34.1 | 51 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Set the FloatInfZeroNaNRule explicitly for s390, so we | ||
2 | can remove the ifdef from pickNaNMulAdd(). | ||
1 | 3 | ||
4 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
5 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
6 | Message-id: 20241202131347.498124-7-peter.maydell@linaro.org | ||
7 | --- | ||
8 | target/s390x/cpu.c | 2 ++ | ||
9 | fpu/softfloat-specialize.c.inc | 2 -- | ||
10 | 2 files changed, 2 insertions(+), 2 deletions(-) | ||
11 | |||
12 | diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/target/s390x/cpu.c | ||
15 | +++ b/target/s390x/cpu.c | ||
16 | @@ -XXX,XX +XXX,XX @@ static void s390_cpu_reset_hold(Object *obj, ResetType type) | ||
17 | set_float_detect_tininess(float_tininess_before_rounding, | ||
18 | &env->fpu_status); | ||
19 | set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fpu_status); | ||
20 | + set_float_infzeronan_rule(float_infzeronan_dnan_always, | ||
21 | + &env->fpu_status); | ||
22 | /* fall through */ | ||
23 | case RESET_TYPE_S390_CPU_NORMAL: | ||
24 | env->psw.mask &= ~PSW_MASK_RI; | ||
25 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc | ||
26 | index XXXXXXX..XXXXXXX 100644 | ||
27 | --- a/fpu/softfloat-specialize.c.inc | ||
28 | +++ b/fpu/softfloat-specialize.c.inc | ||
29 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
30 | * a default NaN | ||
31 | */ | ||
32 | rule = float_infzeronan_dnan_never; | ||
33 | -#elif defined(TARGET_S390X) | ||
34 | - rule = float_infzeronan_dnan_always; | ||
35 | #endif | ||
36 | } | ||
37 | |||
38 | -- | ||
39 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Set the FloatInfZeroNaNRule explicitly for the PPC target, | ||
2 | so we can remove the ifdef from pickNaNMulAdd(). | ||
1 | 3 | ||
4 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
5 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
6 | Message-id: 20241202131347.498124-8-peter.maydell@linaro.org | ||
7 | --- | ||
8 | target/ppc/cpu_init.c | 7 +++++++ | ||
9 | fpu/softfloat-specialize.c.inc | 7 +------ | ||
10 | 2 files changed, 8 insertions(+), 6 deletions(-) | ||
11 | |||
12 | diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/target/ppc/cpu_init.c | ||
15 | +++ b/target/ppc/cpu_init.c | ||
16 | @@ -XXX,XX +XXX,XX @@ static void ppc_cpu_reset_hold(Object *obj, ResetType type) | ||
17 | */ | ||
18 | set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status); | ||
19 | set_float_2nan_prop_rule(float_2nan_prop_ab, &env->vec_status); | ||
20 | + /* | ||
21 | + * For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer | ||
22 | + * to return an input NaN if we have one (ie c) rather than generating | ||
23 | + * a default NaN | ||
24 | + */ | ||
25 | + set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status); | ||
26 | + set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->vec_status); | ||
27 | |||
28 | for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) { | ||
29 | ppc_spr_t *spr = &env->spr_cb[i]; | ||
30 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc | ||
31 | index XXXXXXX..XXXXXXX 100644 | ||
32 | --- a/fpu/softfloat-specialize.c.inc | ||
33 | +++ b/fpu/softfloat-specialize.c.inc | ||
34 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
35 | */ | ||
36 | rule = float_infzeronan_dnan_never; | ||
37 | } | ||
38 | -#elif defined(TARGET_PPC) || defined(TARGET_SPARC) || \ | ||
39 | +#elif defined(TARGET_SPARC) || \ | ||
40 | defined(TARGET_XTENSA) || defined(TARGET_HPPA) || \ | ||
41 | defined(TARGET_I386) || defined(TARGET_LOONGARCH) | ||
42 | /* | ||
43 | * For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan) | ||
44 | * case sets InvalidOp and returns the input value 'c' | ||
45 | */ | ||
46 | - /* | ||
47 | - * For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer | ||
48 | - * to return an input NaN if we have one (ie c) rather than generating | ||
49 | - * a default NaN | ||
50 | - */ | ||
51 | rule = float_infzeronan_dnan_never; | ||
52 | #endif | ||
53 | } | ||
54 | -- | ||
55 | 2.34.1 | diff view generated by jsdifflib |
1 | Mark up the cpreginfo structs to indicate offsets for system | 1 | Set the FloatInfZeroNaNRule explicitly for the MIPS target, |
---|---|---|---|
2 | registers from VNCR_EL2, as defined in table D8-66 in rule R_CSRPQ in | 2 | so we can remove the ifdef from pickNaNMulAdd(). |
3 | the Arm ARM. This commit covers offsets below 0x100; all of these | ||
4 | registers are redirected to memory regardless of the value of | ||
5 | HCR_EL2.NV1. | ||
6 | 3 | ||
7 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 4 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
8 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 5 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
9 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 6 | Message-id: 20241202131347.498124-9-peter.maydell@linaro.org |
10 | --- | 7 | --- |
11 | target/arm/helper.c | 12 ++++++++++++ | 8 | target/mips/fpu_helper.h | 9 +++++++++ |
12 | 1 file changed, 12 insertions(+) | 9 | target/mips/msa.c | 4 ++++ |
10 | fpu/softfloat-specialize.c.inc | 16 +--------------- | ||
11 | 3 files changed, 14 insertions(+), 15 deletions(-) | ||
13 | 12 | ||
14 | diff --git a/target/arm/helper.c b/target/arm/helper.c | 13 | diff --git a/target/mips/fpu_helper.h b/target/mips/fpu_helper.h |
15 | index XXXXXXX..XXXXXXX 100644 | 14 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/target/arm/helper.c | 15 | --- a/target/mips/fpu_helper.h |
17 | +++ b/target/arm/helper.c | 16 | +++ b/target/mips/fpu_helper.h |
18 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo hcrx_el2_reginfo = { | 17 | @@ -XXX,XX +XXX,XX @@ static inline void restore_flush_mode(CPUMIPSState *env) |
19 | .name = "HCRX_EL2", .state = ARM_CP_STATE_AA64, | 18 | static inline void restore_snan_bit_mode(CPUMIPSState *env) |
20 | .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 2, .opc2 = 2, | 19 | { |
21 | .access = PL2_RW, .writefn = hcrx_write, .accessfn = access_hxen, | 20 | bool nan2008 = env->active_fpu.fcr31 & (1 << FCR31_NAN2008); |
22 | + .nv2_redirect_offset = 0xa0, | 21 | + FloatInfZeroNaNRule izn_rule; |
23 | .fieldoffset = offsetof(CPUARMState, cp15.hcrx_el2), | 22 | |
24 | }; | 23 | /* |
25 | 24 | * With nan2008, SNaNs are silenced in the usual way. | |
26 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo el2_cp_reginfo[] = { | 25 | @@ -XXX,XX +XXX,XX @@ static inline void restore_snan_bit_mode(CPUMIPSState *env) |
27 | .type = ARM_CP_IO, | 26 | */ |
28 | .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 0, | 27 | set_snan_bit_is_one(!nan2008, &env->active_fpu.fp_status); |
29 | .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.hcr_el2), | 28 | set_default_nan_mode(!nan2008, &env->active_fpu.fp_status); |
30 | + .nv2_redirect_offset = 0x78, | 29 | + /* |
31 | .writefn = hcr_write, .raw_writefn = raw_write }, | 30 | + * For MIPS systems that conform to IEEE754-1985, the (inf,zero,nan) |
32 | { .name = "HCR", .state = ARM_CP_STATE_AA32, | 31 | + * case sets InvalidOp and returns the default NaN. |
33 | .type = ARM_CP_ALIAS | ARM_CP_IO, | 32 | + * For MIPS systems that conform to IEEE754-2008, the (inf,zero,nan) |
34 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo el2_cp_reginfo[] = { | 33 | + * case sets InvalidOp and returns the input value 'c'. |
35 | { .name = "VTCR_EL2", .state = ARM_CP_STATE_AA64, | 34 | + */ |
36 | .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 1, .opc2 = 2, | 35 | + izn_rule = nan2008 ? float_infzeronan_dnan_never : float_infzeronan_dnan_always; |
37 | .access = PL2_RW, | 36 | + set_float_infzeronan_rule(izn_rule, &env->active_fpu.fp_status); |
38 | + .nv2_redirect_offset = 0x40, | 37 | } |
39 | /* no .writefn needed as this can't cause an ASID change */ | 38 | |
40 | .fieldoffset = offsetof(CPUARMState, cp15.vtcr_el2) }, | 39 | static inline void restore_fp_status(CPUMIPSState *env) |
41 | { .name = "VTTBR", .state = ARM_CP_STATE_AA32, | 40 | diff --git a/target/mips/msa.c b/target/mips/msa.c |
42 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo el2_cp_reginfo[] = { | 41 | index XXXXXXX..XXXXXXX 100644 |
43 | { .name = "VTTBR_EL2", .state = ARM_CP_STATE_AA64, | 42 | --- a/target/mips/msa.c |
44 | .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 1, .opc2 = 0, | 43 | +++ b/target/mips/msa.c |
45 | .access = PL2_RW, .writefn = vttbr_write, .raw_writefn = raw_write, | 44 | @@ -XXX,XX +XXX,XX @@ void msa_reset(CPUMIPSState *env) |
46 | + .nv2_redirect_offset = 0x20, | 45 | |
47 | .fieldoffset = offsetof(CPUARMState, cp15.vttbr_el2) }, | 46 | /* set proper signanling bit meaning ("1" means "quiet") */ |
48 | { .name = "SCTLR_EL2", .state = ARM_CP_STATE_BOTH, | 47 | set_snan_bit_is_one(0, &env->active_tc.msa_fp_status); |
49 | .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 0, .opc2 = 0, | 48 | + |
50 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo el2_cp_reginfo[] = { | 49 | + /* Inf * 0 + NaN returns the input NaN */ |
51 | { .name = "TPIDR_EL2", .state = ARM_CP_STATE_BOTH, | 50 | + set_float_infzeronan_rule(float_infzeronan_dnan_never, |
52 | .opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 2, | 51 | + &env->active_tc.msa_fp_status); |
53 | .access = PL2_RW, .resetvalue = 0, | 52 | } |
54 | + .nv2_redirect_offset = 0x90, | 53 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc |
55 | .fieldoffset = offsetof(CPUARMState, cp15.tpidr_el[2]) }, | 54 | index XXXXXXX..XXXXXXX 100644 |
56 | { .name = "TTBR0_EL2", .state = ARM_CP_STATE_AA64, | 55 | --- a/fpu/softfloat-specialize.c.inc |
57 | .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 0, | 56 | +++ b/fpu/softfloat-specialize.c.inc |
58 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo el2_cp_reginfo[] = { | 57 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, |
59 | .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 0, .opc2 = 3, | 58 | /* |
60 | .access = PL2_RW, .type = ARM_CP_IO, .resetvalue = 0, | 59 | * Temporarily fall back to ifdef ladder |
61 | .writefn = gt_cntvoff_write, | 60 | */ |
62 | + .nv2_redirect_offset = 0x60, | 61 | -#if defined(TARGET_MIPS) |
63 | .fieldoffset = offsetof(CPUARMState, cp15.cntvoff_el2) }, | 62 | - if (snan_bit_is_one(status)) { |
64 | { .name = "CNTVOFF", .cp = 15, .opc1 = 4, .crm = 14, | 63 | - /* |
65 | .access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_ALIAS | ARM_CP_IO, | 64 | - * For MIPS systems that conform to IEEE754-1985, the (inf,zero,nan) |
66 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo el2_cp_reginfo[] = { | 65 | - * case sets InvalidOp and returns the default NaN |
67 | { .name = "HSTR_EL2", .state = ARM_CP_STATE_BOTH, | 66 | - */ |
68 | .cp = 15, .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 3, | 67 | - rule = float_infzeronan_dnan_always; |
69 | .access = PL2_RW, | 68 | - } else { |
70 | + .nv2_redirect_offset = 0x80, | 69 | - /* |
71 | .fieldoffset = offsetof(CPUARMState, cp15.hstr_el2) }, | 70 | - * For MIPS systems that conform to IEEE754-2008, the (inf,zero,nan) |
72 | }; | 71 | - * case sets InvalidOp and returns the input value 'c' |
73 | 72 | - */ | |
74 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo el2_sec_cp_reginfo[] = { | 73 | - rule = float_infzeronan_dnan_never; |
75 | { .name = "VSTTBR_EL2", .state = ARM_CP_STATE_AA64, | 74 | - } |
76 | .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 6, .opc2 = 0, | 75 | -#elif defined(TARGET_SPARC) || \ |
77 | .access = PL2_RW, .accessfn = sel2_access, | 76 | +#if defined(TARGET_SPARC) || \ |
78 | + .nv2_redirect_offset = 0x30, | 77 | defined(TARGET_XTENSA) || defined(TARGET_HPPA) || \ |
79 | .fieldoffset = offsetof(CPUARMState, cp15.vsttbr_el2) }, | 78 | defined(TARGET_I386) || defined(TARGET_LOONGARCH) |
80 | { .name = "VSTCR_EL2", .state = ARM_CP_STATE_AA64, | ||
81 | .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 6, .opc2 = 2, | ||
82 | .access = PL2_RW, .accessfn = sel2_access, | ||
83 | + .nv2_redirect_offset = 0x48, | ||
84 | .fieldoffset = offsetof(CPUARMState, cp15.vstcr_el2) }, | ||
85 | }; | ||
86 | |||
87 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo nv2_reginfo[] = { | ||
88 | .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 2, .opc2 = 0, | ||
89 | .access = PL2_RW, | ||
90 | .writefn = vncr_write, | ||
91 | + .nv2_redirect_offset = 0xb0, | ||
92 | .fieldoffset = offsetof(CPUARMState, cp15.vncr_el2) }, | ||
93 | }; | ||
94 | |||
95 | @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) | ||
96 | .opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 0, | ||
97 | .access = PL2_RW, .resetvalue = cpu->midr, | ||
98 | .type = ARM_CP_EL3_NO_EL2_C_NZ, | ||
99 | + .nv2_redirect_offset = 0x88, | ||
100 | .fieldoffset = offsetof(CPUARMState, cp15.vpidr_el2) }, | ||
101 | { .name = "VMPIDR", .state = ARM_CP_STATE_AA32, | ||
102 | .cp = 15, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 5, | ||
103 | @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) | ||
104 | .opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 5, | ||
105 | .access = PL2_RW, .resetvalue = vmpidr_def, | ||
106 | .type = ARM_CP_EL3_NO_EL2_C_NZ, | ||
107 | + .nv2_redirect_offset = 0x50, | ||
108 | .fieldoffset = offsetof(CPUARMState, cp15.vmpidr_el2) }, | ||
109 | }; | ||
110 | /* | 79 | /* |
111 | -- | 80 | -- |
112 | 2.34.1 | 81 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Set the FloatInfZeroNaNRule explicitly for the SPARC target, | ||
2 | so we can remove the ifdef from pickNaNMulAdd(). | ||
1 | 3 | ||
4 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
5 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
6 | Message-id: 20241202131347.498124-10-peter.maydell@linaro.org | ||
7 | --- | ||
8 | target/sparc/cpu.c | 2 ++ | ||
9 | fpu/softfloat-specialize.c.inc | 3 +-- | ||
10 | 2 files changed, 3 insertions(+), 2 deletions(-) | ||
11 | |||
12 | diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/target/sparc/cpu.c | ||
15 | +++ b/target/sparc/cpu.c | ||
16 | @@ -XXX,XX +XXX,XX @@ static void sparc_cpu_realizefn(DeviceState *dev, Error **errp) | ||
17 | * the CPU state struct so it won't get zeroed on reset. | ||
18 | */ | ||
19 | set_float_2nan_prop_rule(float_2nan_prop_s_ba, &env->fp_status); | ||
20 | + /* For inf * 0 + NaN, return the input NaN */ | ||
21 | + set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status); | ||
22 | |||
23 | cpu_exec_realizefn(cs, &local_err); | ||
24 | if (local_err != NULL) { | ||
25 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc | ||
26 | index XXXXXXX..XXXXXXX 100644 | ||
27 | --- a/fpu/softfloat-specialize.c.inc | ||
28 | +++ b/fpu/softfloat-specialize.c.inc | ||
29 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
30 | /* | ||
31 | * Temporarily fall back to ifdef ladder | ||
32 | */ | ||
33 | -#if defined(TARGET_SPARC) || \ | ||
34 | - defined(TARGET_XTENSA) || defined(TARGET_HPPA) || \ | ||
35 | +#if defined(TARGET_XTENSA) || defined(TARGET_HPPA) || \ | ||
36 | defined(TARGET_I386) || defined(TARGET_LOONGARCH) | ||
37 | /* | ||
38 | * For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan) | ||
39 | -- | ||
40 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Set the FloatInfZeroNaNRule explicitly for the xtensa target, | ||
2 | so we can remove the ifdef from pickNaNMulAdd(). | ||
1 | 3 | ||
4 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
5 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
6 | Message-id: 20241202131347.498124-11-peter.maydell@linaro.org | ||
7 | --- | ||
8 | target/xtensa/cpu.c | 2 ++ | ||
9 | fpu/softfloat-specialize.c.inc | 2 +- | ||
10 | 2 files changed, 3 insertions(+), 1 deletion(-) | ||
11 | |||
12 | diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/target/xtensa/cpu.c | ||
15 | +++ b/target/xtensa/cpu.c | ||
16 | @@ -XXX,XX +XXX,XX @@ static void xtensa_cpu_reset_hold(Object *obj, ResetType type) | ||
17 | reset_mmu(env); | ||
18 | cs->halted = env->runstall; | ||
19 | #endif | ||
20 | + /* For inf * 0 + NaN, return the input NaN */ | ||
21 | + set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status); | ||
22 | set_no_signaling_nans(!dfpu, &env->fp_status); | ||
23 | xtensa_use_first_nan(env, !dfpu); | ||
24 | } | ||
25 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc | ||
26 | index XXXXXXX..XXXXXXX 100644 | ||
27 | --- a/fpu/softfloat-specialize.c.inc | ||
28 | +++ b/fpu/softfloat-specialize.c.inc | ||
29 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
30 | /* | ||
31 | * Temporarily fall back to ifdef ladder | ||
32 | */ | ||
33 | -#if defined(TARGET_XTENSA) || defined(TARGET_HPPA) || \ | ||
34 | +#if defined(TARGET_HPPA) || \ | ||
35 | defined(TARGET_I386) || defined(TARGET_LOONGARCH) | ||
36 | /* | ||
37 | * For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan) | ||
38 | -- | ||
39 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Set the FloatInfZeroNaNRule explicitly for the x86 target. | ||
1 | 2 | ||
3 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
4 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
5 | Message-id: 20241202131347.498124-12-peter.maydell@linaro.org | ||
6 | --- | ||
7 | target/i386/tcg/fpu_helper.c | 7 +++++++ | ||
8 | fpu/softfloat-specialize.c.inc | 2 +- | ||
9 | 2 files changed, 8 insertions(+), 1 deletion(-) | ||
10 | |||
11 | diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c | ||
12 | index XXXXXXX..XXXXXXX 100644 | ||
13 | --- a/target/i386/tcg/fpu_helper.c | ||
14 | +++ b/target/i386/tcg/fpu_helper.c | ||
15 | @@ -XXX,XX +XXX,XX @@ void cpu_init_fp_statuses(CPUX86State *env) | ||
16 | */ | ||
17 | set_float_2nan_prop_rule(float_2nan_prop_x87, &env->mmx_status); | ||
18 | set_float_2nan_prop_rule(float_2nan_prop_x87, &env->sse_status); | ||
19 | + /* | ||
20 | + * Only SSE has multiply-add instructions. In the SDM Section 14.5.2 | ||
21 | + * "Fused-Multiply-ADD (FMA) Numeric Behavior" the NaN handling is | ||
22 | + * specified -- for 0 * inf + NaN the input NaN is selected, and if | ||
23 | + * there are multiple input NaNs they are selected in the order a, b, c. | ||
24 | + */ | ||
25 | + set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->sse_status); | ||
26 | } | ||
27 | |||
28 | static inline uint8_t save_exception_flags(CPUX86State *env) | ||
29 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc | ||
30 | index XXXXXXX..XXXXXXX 100644 | ||
31 | --- a/fpu/softfloat-specialize.c.inc | ||
32 | +++ b/fpu/softfloat-specialize.c.inc | ||
33 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
34 | * Temporarily fall back to ifdef ladder | ||
35 | */ | ||
36 | #if defined(TARGET_HPPA) || \ | ||
37 | - defined(TARGET_I386) || defined(TARGET_LOONGARCH) | ||
38 | + defined(TARGET_LOONGARCH) | ||
39 | /* | ||
40 | * For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan) | ||
41 | * case sets InvalidOp and returns the input value 'c' | ||
42 | -- | ||
43 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Set the FloatInfZeroNaNRule explicitly for the loongarch target. | ||
1 | 2 | ||
3 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
4 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
5 | Message-id: 20241202131347.498124-13-peter.maydell@linaro.org | ||
6 | --- | ||
7 | target/loongarch/tcg/fpu_helper.c | 5 +++++ | ||
8 | fpu/softfloat-specialize.c.inc | 7 +------ | ||
9 | 2 files changed, 6 insertions(+), 6 deletions(-) | ||
10 | |||
11 | diff --git a/target/loongarch/tcg/fpu_helper.c b/target/loongarch/tcg/fpu_helper.c | ||
12 | index XXXXXXX..XXXXXXX 100644 | ||
13 | --- a/target/loongarch/tcg/fpu_helper.c | ||
14 | +++ b/target/loongarch/tcg/fpu_helper.c | ||
15 | @@ -XXX,XX +XXX,XX @@ void restore_fp_status(CPULoongArchState *env) | ||
16 | &env->fp_status); | ||
17 | set_flush_to_zero(0, &env->fp_status); | ||
18 | set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fp_status); | ||
19 | + /* | ||
20 | + * For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan) | ||
21 | + * case sets InvalidOp and returns the input value 'c' | ||
22 | + */ | ||
23 | + set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status); | ||
24 | } | ||
25 | |||
26 | int ieee_ex_to_loongarch(int xcpt) | ||
27 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc | ||
28 | index XXXXXXX..XXXXXXX 100644 | ||
29 | --- a/fpu/softfloat-specialize.c.inc | ||
30 | +++ b/fpu/softfloat-specialize.c.inc | ||
31 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
32 | /* | ||
33 | * Temporarily fall back to ifdef ladder | ||
34 | */ | ||
35 | -#if defined(TARGET_HPPA) || \ | ||
36 | - defined(TARGET_LOONGARCH) | ||
37 | - /* | ||
38 | - * For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan) | ||
39 | - * case sets InvalidOp and returns the input value 'c' | ||
40 | - */ | ||
41 | +#if defined(TARGET_HPPA) | ||
42 | rule = float_infzeronan_dnan_never; | ||
43 | #endif | ||
44 | } | ||
45 | -- | ||
46 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Set the FloatInfZeroNaNRule explicitly for the HPPA target, | ||
2 | so we can remove the ifdef from pickNaNMulAdd(). | ||
1 | 3 | ||
4 | As this is the last target to be converted to explicitly setting | ||
5 | the rule, we can remove the fallback code in pickNaNMulAdd() | ||
6 | entirely. | ||
7 | |||
8 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
9 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
10 | Message-id: 20241202131347.498124-14-peter.maydell@linaro.org | ||
11 | --- | ||
12 | target/hppa/fpu_helper.c | 2 ++ | ||
13 | fpu/softfloat-specialize.c.inc | 13 +------------ | ||
14 | 2 files changed, 3 insertions(+), 12 deletions(-) | ||
15 | |||
16 | diff --git a/target/hppa/fpu_helper.c b/target/hppa/fpu_helper.c | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/target/hppa/fpu_helper.c | ||
19 | +++ b/target/hppa/fpu_helper.c | ||
20 | @@ -XXX,XX +XXX,XX @@ void HELPER(loaded_fr0)(CPUHPPAState *env) | ||
21 | * HPPA does note implement a CPU reset method at all... | ||
22 | */ | ||
23 | set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fp_status); | ||
24 | + /* For inf * 0 + NaN, return the input NaN */ | ||
25 | + set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status); | ||
26 | } | ||
27 | |||
28 | void cpu_hppa_loaded_fr0(CPUHPPAState *env) | ||
29 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc | ||
30 | index XXXXXXX..XXXXXXX 100644 | ||
31 | --- a/fpu/softfloat-specialize.c.inc | ||
32 | +++ b/fpu/softfloat-specialize.c.inc | ||
33 | @@ -XXX,XX +XXX,XX @@ static int pickNaN(FloatClass a_cls, FloatClass b_cls, | ||
34 | static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
35 | bool infzero, float_status *status) | ||
36 | { | ||
37 | - FloatInfZeroNaNRule rule = status->float_infzeronan_rule; | ||
38 | - | ||
39 | /* | ||
40 | * We guarantee not to require the target to tell us how to | ||
41 | * pick a NaN if we're always returning the default NaN. | ||
42 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
43 | */ | ||
44 | assert(!status->default_nan_mode); | ||
45 | |||
46 | - if (rule == float_infzeronan_none) { | ||
47 | - /* | ||
48 | - * Temporarily fall back to ifdef ladder | ||
49 | - */ | ||
50 | -#if defined(TARGET_HPPA) | ||
51 | - rule = float_infzeronan_dnan_never; | ||
52 | -#endif | ||
53 | - } | ||
54 | - | ||
55 | if (infzero) { | ||
56 | /* | ||
57 | * Inf * 0 + NaN -- some implementations return the default NaN here, | ||
58 | * and some return the input NaN. | ||
59 | */ | ||
60 | - switch (rule) { | ||
61 | + switch (status->float_infzeronan_rule) { | ||
62 | case float_infzeronan_dnan_never: | ||
63 | return 2; | ||
64 | case float_infzeronan_dnan_always: | ||
65 | -- | ||
66 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | The new implementation of pickNaNMulAdd() will find it convenient | ||
2 | to know whether at least one of the three arguments to the muladd | ||
3 | was a signaling NaN. We already calculate that in the caller, | ||
4 | so pass it in as a new bool have_snan. | ||
1 | 5 | ||
6 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
7 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
8 | Message-id: 20241202131347.498124-15-peter.maydell@linaro.org | ||
9 | --- | ||
10 | fpu/softfloat-parts.c.inc | 5 +++-- | ||
11 | fpu/softfloat-specialize.c.inc | 2 +- | ||
12 | 2 files changed, 4 insertions(+), 3 deletions(-) | ||
13 | |||
14 | diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/fpu/softfloat-parts.c.inc | ||
17 | +++ b/fpu/softfloat-parts.c.inc | ||
18 | @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b, | ||
19 | { | ||
20 | int which; | ||
21 | bool infzero = (ab_mask == float_cmask_infzero); | ||
22 | + bool have_snan = (abc_mask & float_cmask_snan); | ||
23 | |||
24 | - if (unlikely(abc_mask & float_cmask_snan)) { | ||
25 | + if (unlikely(have_snan)) { | ||
26 | float_raise(float_flag_invalid | float_flag_invalid_snan, s); | ||
27 | } | ||
28 | |||
29 | @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b, | ||
30 | if (s->default_nan_mode) { | ||
31 | which = 3; | ||
32 | } else { | ||
33 | - which = pickNaNMulAdd(a->cls, b->cls, c->cls, infzero, s); | ||
34 | + which = pickNaNMulAdd(a->cls, b->cls, c->cls, infzero, have_snan, s); | ||
35 | } | ||
36 | |||
37 | if (which == 3) { | ||
38 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc | ||
39 | index XXXXXXX..XXXXXXX 100644 | ||
40 | --- a/fpu/softfloat-specialize.c.inc | ||
41 | +++ b/fpu/softfloat-specialize.c.inc | ||
42 | @@ -XXX,XX +XXX,XX @@ static int pickNaN(FloatClass a_cls, FloatClass b_cls, | ||
43 | | Return values : 0 : a; 1 : b; 2 : c; 3 : default-NaN | ||
44 | *----------------------------------------------------------------------------*/ | ||
45 | static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
46 | - bool infzero, float_status *status) | ||
47 | + bool infzero, bool have_snan, float_status *status) | ||
48 | { | ||
49 | /* | ||
50 | * We guarantee not to require the target to tell us how to | ||
51 | -- | ||
52 | 2.34.1 | diff view generated by jsdifflib |
1 | FEAT_NV2 requires that when HCR_EL2.{NV,NV2} == 0b11 then accesses by | 1 | IEEE 758 does not define a fixed rule for which NaN to pick as the |
---|---|---|---|
2 | EL1 to certain system registers are redirected to RAM. The full list | 2 | result if both operands of a 3-operand fused multiply-add operation |
3 | of affected registers is in the table in rule R_CSRPQ in the Arm ARM. | 3 | are NaNs. As a result different architectures have ended up with |
4 | The registers may be normally accessible at EL1 (like ACTLR_EL1), or | 4 | different rules for propagating NaNs. |
5 | normally UNDEF at EL1 (like HCR_EL2). Some registers redirect to RAM | 5 | |
6 | only when HCR_EL2.NV1 is 0, and some only when HCR_EL2.NV1 is 1; | 6 | QEMU currently hardcodes the NaN propagation logic into the binary |
7 | others trap in both cases. | 7 | because pickNaNMulAdd() has an ifdef ladder for different targets. |
8 | 8 | We want to make the propagation rule instead be selectable at | |
9 | Add the infrastructure for identifying which registers should be | 9 | runtime, because: |
10 | redirected and turning them into memory accesses. | 10 | * this will let us have multiple targets in one QEMU binary |
11 | 11 | * the Arm FEAT_AFP architectural feature includes letting | |
12 | This code does not set the correct syndrome or arrange for the | 12 | the guest select a NaN propagation rule at runtime |
13 | exception to be taken to the correct target EL if the access via | 13 | |
14 | VNCR_EL2 faults; we will do that in the next commit. | 14 | In this commit we add an enum for the propagation rule, the field in |
15 | 15 | float_status, and the corresponding getters and setters. We change | |
16 | Subsequent commits will mark up the relevant regdefs to set their | 16 | pickNaNMulAdd to honour this, but because all targets still leave |
17 | nv2_redirect_offset, and if relevant one of the two flags which | 17 | this field at its default 0 value, the fallback logic will pick the |
18 | indicates that the redirect happens only for a particular value of | 18 | rule type with the old ifdef ladder. |
19 | HCR_EL2.NV1. | 19 | |
20 | It's valid not to set a propagation rule if default_nan_mode is | ||
21 | enabled, because in that case there's no need to pick a NaN; all the | ||
22 | callers of pickNaNMulAdd() catch this case and skip calling it. | ||
20 | 23 | ||
21 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 24 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
22 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | ||
23 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 25 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
26 | Message-id: 20241202131347.498124-16-peter.maydell@linaro.org | ||
24 | --- | 27 | --- |
25 | target/arm/cpregs.h | 12 ++++++++ | 28 | include/fpu/softfloat-helpers.h | 11 +++ |
26 | target/arm/cpu.h | 4 +++ | 29 | include/fpu/softfloat-types.h | 55 +++++++++++ |
27 | target/arm/tcg/translate.h | 6 ++++ | 30 | fpu/softfloat-specialize.c.inc | 167 ++++++++------------------------ |
28 | target/arm/tcg/hflags.c | 6 ++++ | 31 | 3 files changed, 107 insertions(+), 126 deletions(-) |
29 | target/arm/tcg/translate-a64.c | 56 ++++++++++++++++++++++++++++++++++ | 32 | |
30 | 5 files changed, 84 insertions(+) | 33 | diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h |
31 | |||
32 | diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h | ||
33 | index XXXXXXX..XXXXXXX 100644 | 34 | index XXXXXXX..XXXXXXX 100644 |
34 | --- a/target/arm/cpregs.h | 35 | --- a/include/fpu/softfloat-helpers.h |
35 | +++ b/target/arm/cpregs.h | 36 | +++ b/include/fpu/softfloat-helpers.h |
36 | @@ -XXX,XX +XXX,XX @@ typedef void CPResetFn(CPUARMState *env, const ARMCPRegInfo *opaque); | 37 | @@ -XXX,XX +XXX,XX @@ static inline void set_float_2nan_prop_rule(Float2NaNPropRule rule, |
37 | 38 | status->float_2nan_prop_rule = rule; | |
38 | #define CP_ANY 0xff | 39 | } |
39 | 40 | ||
40 | +/* Flags in the high bits of nv2_redirect_offset */ | 41 | +static inline void set_float_3nan_prop_rule(Float3NaNPropRule rule, |
41 | +#define NV2_REDIR_NV1 0x4000 /* Only redirect when HCR_EL2.NV1 == 1 */ | 42 | + float_status *status) |
42 | +#define NV2_REDIR_NO_NV1 0x8000 /* Only redirect when HCR_EL2.NV1 == 0 */ | 43 | +{ |
43 | +#define NV2_REDIR_FLAG_MASK 0xc000 | 44 | + status->float_3nan_prop_rule = rule; |
44 | + | 45 | +} |
45 | /* Definition of an ARM coprocessor register */ | 46 | + |
46 | struct ARMCPRegInfo { | 47 | static inline void set_float_infzeronan_rule(FloatInfZeroNaNRule rule, |
47 | /* Name of register (useful mainly for debugging, need not be unique) */ | 48 | float_status *status) |
48 | @@ -XXX,XX +XXX,XX @@ struct ARMCPRegInfo { | 49 | { |
49 | * value encodes both the trap register and bit within it. | 50 | @@ -XXX,XX +XXX,XX @@ static inline Float2NaNPropRule get_float_2nan_prop_rule(float_status *status) |
50 | */ | 51 | return status->float_2nan_prop_rule; |
51 | FGTBit fgt; | 52 | } |
52 | + | 53 | |
53 | + /* | 54 | +static inline Float3NaNPropRule get_float_3nan_prop_rule(float_status *status) |
54 | + * Offset from VNCR_EL2 when FEAT_NV2 redirects access to memory; | 55 | +{ |
55 | + * may include an NV2_REDIR_* flag. | 56 | + return status->float_3nan_prop_rule; |
56 | + */ | 57 | +} |
57 | + uint32_t nv2_redirect_offset; | 58 | + |
59 | static inline FloatInfZeroNaNRule get_float_infzeronan_rule(float_status *status) | ||
60 | { | ||
61 | return status->float_infzeronan_rule; | ||
62 | diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h | ||
63 | index XXXXXXX..XXXXXXX 100644 | ||
64 | --- a/include/fpu/softfloat-types.h | ||
65 | +++ b/include/fpu/softfloat-types.h | ||
66 | @@ -XXX,XX +XXX,XX @@ this code that are retained. | ||
67 | #ifndef SOFTFLOAT_TYPES_H | ||
68 | #define SOFTFLOAT_TYPES_H | ||
69 | |||
70 | +#include "hw/registerfields.h" | ||
71 | + | ||
72 | /* | ||
73 | * Software IEC/IEEE floating-point types. | ||
74 | */ | ||
75 | @@ -XXX,XX +XXX,XX @@ typedef enum __attribute__((__packed__)) { | ||
76 | float_2nan_prop_x87, | ||
77 | } Float2NaNPropRule; | ||
78 | |||
79 | +/* | ||
80 | + * 3-input NaN propagation rule, for fused multiply-add. Individual | ||
81 | + * architectures have different rules for which input NaN is | ||
82 | + * propagated to the output when there is more than one NaN on the | ||
83 | + * input. | ||
84 | + * | ||
85 | + * If default_nan_mode is enabled then it is valid not to set a NaN | ||
86 | + * propagation rule, because the softfloat code guarantees not to try | ||
87 | + * to pick a NaN to propagate in default NaN mode. When not in | ||
88 | + * default-NaN mode, it is an error for the target not to set the rule | ||
89 | + * in float_status if it uses a muladd, and we will assert if we need | ||
90 | + * to handle an input NaN and no rule was selected. | ||
91 | + * | ||
92 | + * The naming scheme for Float3NaNPropRule values is: | ||
93 | + * float_3nan_prop_s_abc: | ||
94 | + * = "Prefer SNaN over QNaN, then operand A over B over C" | ||
95 | + * float_3nan_prop_abc: | ||
96 | + * = "Prefer A over B over C regardless of SNaN vs QNAN" | ||
97 | + * | ||
98 | + * For QEMU, the multiply-add operation is A * B + C. | ||
99 | + */ | ||
100 | + | ||
101 | +/* | ||
102 | + * We set the Float3NaNPropRule enum values up so we can select the | ||
103 | + * right value in pickNaNMulAdd in a data driven way. | ||
104 | + */ | ||
105 | +FIELD(3NAN, 1ST, 0, 2) /* which operand is most preferred ? */ | ||
106 | +FIELD(3NAN, 2ND, 2, 2) /* which operand is next most preferred ? */ | ||
107 | +FIELD(3NAN, 3RD, 4, 2) /* which operand is least preferred ? */ | ||
108 | +FIELD(3NAN, SNAN, 6, 1) /* do we prefer SNaN over QNaN ? */ | ||
109 | + | ||
110 | +#define PROPRULE(X, Y, Z) \ | ||
111 | + ((X << R_3NAN_1ST_SHIFT) | (Y << R_3NAN_2ND_SHIFT) | (Z << R_3NAN_3RD_SHIFT)) | ||
112 | + | ||
113 | +typedef enum __attribute__((__packed__)) { | ||
114 | + float_3nan_prop_none = 0, /* No propagation rule specified */ | ||
115 | + float_3nan_prop_abc = PROPRULE(0, 1, 2), | ||
116 | + float_3nan_prop_acb = PROPRULE(0, 2, 1), | ||
117 | + float_3nan_prop_bac = PROPRULE(1, 0, 2), | ||
118 | + float_3nan_prop_bca = PROPRULE(1, 2, 0), | ||
119 | + float_3nan_prop_cab = PROPRULE(2, 0, 1), | ||
120 | + float_3nan_prop_cba = PROPRULE(2, 1, 0), | ||
121 | + float_3nan_prop_s_abc = float_3nan_prop_abc | R_3NAN_SNAN_MASK, | ||
122 | + float_3nan_prop_s_acb = float_3nan_prop_acb | R_3NAN_SNAN_MASK, | ||
123 | + float_3nan_prop_s_bac = float_3nan_prop_bac | R_3NAN_SNAN_MASK, | ||
124 | + float_3nan_prop_s_bca = float_3nan_prop_bca | R_3NAN_SNAN_MASK, | ||
125 | + float_3nan_prop_s_cab = float_3nan_prop_cab | R_3NAN_SNAN_MASK, | ||
126 | + float_3nan_prop_s_cba = float_3nan_prop_cba | R_3NAN_SNAN_MASK, | ||
127 | +} Float3NaNPropRule; | ||
128 | + | ||
129 | +#undef PROPRULE | ||
130 | + | ||
131 | /* | ||
132 | * Rule for result of fused multiply-add 0 * Inf + NaN. | ||
133 | * This must be a NaN, but implementations differ on whether this | ||
134 | @@ -XXX,XX +XXX,XX @@ typedef struct float_status { | ||
135 | FloatRoundMode float_rounding_mode; | ||
136 | FloatX80RoundPrec floatx80_rounding_precision; | ||
137 | Float2NaNPropRule float_2nan_prop_rule; | ||
138 | + Float3NaNPropRule float_3nan_prop_rule; | ||
139 | FloatInfZeroNaNRule float_infzeronan_rule; | ||
140 | bool tininess_before_rounding; | ||
141 | /* should denormalised results go to zero and set the inexact flag? */ | ||
142 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc | ||
143 | index XXXXXXX..XXXXXXX 100644 | ||
144 | --- a/fpu/softfloat-specialize.c.inc | ||
145 | +++ b/fpu/softfloat-specialize.c.inc | ||
146 | @@ -XXX,XX +XXX,XX @@ static int pickNaN(FloatClass a_cls, FloatClass b_cls, | ||
147 | static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
148 | bool infzero, bool have_snan, float_status *status) | ||
149 | { | ||
150 | + FloatClass cls[3] = { a_cls, b_cls, c_cls }; | ||
151 | + Float3NaNPropRule rule = status->float_3nan_prop_rule; | ||
152 | + int which; | ||
58 | + | 153 | + |
59 | /* | 154 | /* |
60 | * The opaque pointer passed to define_arm_cp_regs_with_opaque() when | 155 | * We guarantee not to require the target to tell us how to |
61 | * this register was defined: can be used to hand data through to the | 156 | * pick a NaN if we're always returning the default NaN. |
62 | diff --git a/target/arm/cpu.h b/target/arm/cpu.h | 157 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, |
63 | index XXXXXXX..XXXXXXX 100644 | ||
64 | --- a/target/arm/cpu.h | ||
65 | +++ b/target/arm/cpu.h | ||
66 | @@ -XXX,XX +XXX,XX @@ FIELD(TBFLAG_A64, ATA0, 31, 1) | ||
67 | FIELD(TBFLAG_A64, NV, 32, 1) | ||
68 | FIELD(TBFLAG_A64, NV1, 33, 1) | ||
69 | FIELD(TBFLAG_A64, NV2, 34, 1) | ||
70 | +/* Set if FEAT_NV2 RAM accesses use the EL2&0 translation regime */ | ||
71 | +FIELD(TBFLAG_A64, NV2_MEM_E20, 35, 1) | ||
72 | +/* Set if FEAT_NV2 RAM accesses are big-endian */ | ||
73 | +FIELD(TBFLAG_A64, NV2_MEM_BE, 36, 1) | ||
74 | |||
75 | /* | ||
76 | * Helpers for using the above. Note that only the A64 accessors use | ||
77 | diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h | ||
78 | index XXXXXXX..XXXXXXX 100644 | ||
79 | --- a/target/arm/tcg/translate.h | ||
80 | +++ b/target/arm/tcg/translate.h | ||
81 | @@ -XXX,XX +XXX,XX @@ typedef struct DisasContext { | ||
82 | bool nv1; | ||
83 | /* True if NV enabled and HCR_EL2.NV2 is set */ | ||
84 | bool nv2; | ||
85 | + /* True if NV2 enabled and NV2 RAM accesses use EL2&0 translation regime */ | ||
86 | + bool nv2_mem_e20; | ||
87 | + /* True if NV2 enabled and NV2 RAM accesses are big-endian */ | ||
88 | + bool nv2_mem_be; | ||
89 | /* | ||
90 | * >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI. | ||
91 | * < 0, set by the current instruction. | ||
92 | @@ -XXX,XX +XXX,XX @@ typedef struct DisasContext { | ||
93 | int c15_cpar; | ||
94 | /* TCG op of the current insn_start. */ | ||
95 | TCGOp *insn_start; | ||
96 | + /* Offset from VNCR_EL2 when FEAT_NV2 redirects this reg to memory */ | ||
97 | + uint32_t nv2_redirect_offset; | ||
98 | } DisasContext; | ||
99 | |||
100 | typedef struct DisasCompare { | ||
101 | diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c | ||
102 | index XXXXXXX..XXXXXXX 100644 | ||
103 | --- a/target/arm/tcg/hflags.c | ||
104 | +++ b/target/arm/tcg/hflags.c | ||
105 | @@ -XXX,XX +XXX,XX @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, | ||
106 | } | ||
107 | if (hcr & HCR_NV2) { | ||
108 | DP_TBFLAG_A64(flags, NV2, 1); | ||
109 | + if (hcr & HCR_E2H) { | ||
110 | + DP_TBFLAG_A64(flags, NV2_MEM_E20, 1); | ||
111 | + } | ||
112 | + if (env->cp15.sctlr_el[2] & SCTLR_EE) { | ||
113 | + DP_TBFLAG_A64(flags, NV2_MEM_BE, 1); | ||
114 | + } | ||
115 | } | 158 | } |
116 | } | 159 | } |
117 | 160 | ||
118 | diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c | 161 | + if (rule == float_3nan_prop_none) { |
119 | index XXXXXXX..XXXXXXX 100644 | 162 | #if defined(TARGET_ARM) |
120 | --- a/target/arm/tcg/translate-a64.c | 163 | - |
121 | +++ b/target/arm/tcg/translate-a64.c | 164 | - /* This looks different from the ARM ARM pseudocode, because the ARM ARM |
122 | @@ -XXX,XX +XXX,XX @@ static void handle_sys(DisasContext *s, bool isread, | 165 | - * puts the operands to a fused mac operation (a*b)+c in the order c,a,b. |
123 | bool nv_trap_to_el2 = false; | 166 | - */ |
124 | bool nv_redirect_reg = false; | 167 | - if (is_snan(c_cls)) { |
125 | bool skip_fp_access_checks = false; | 168 | - return 2; |
126 | + bool nv2_mem_redirect = false; | 169 | - } else if (is_snan(a_cls)) { |
127 | TCGv_ptr tcg_ri = NULL; | 170 | - return 0; |
128 | TCGv_i64 tcg_rt; | 171 | - } else if (is_snan(b_cls)) { |
129 | uint32_t syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread); | 172 | - return 1; |
130 | @@ -XXX,XX +XXX,XX @@ static void handle_sys(DisasContext *s, bool isread, | 173 | - } else if (is_qnan(c_cls)) { |
131 | return; | 174 | - return 2; |
132 | } | 175 | - } else if (is_qnan(a_cls)) { |
133 | 176 | - return 0; | |
134 | + if (s->nv2 && ri->nv2_redirect_offset) { | 177 | - } else { |
178 | - return 1; | ||
179 | - } | ||
135 | + /* | 180 | + /* |
136 | + * Some registers always redirect to memory; some only do so if | 181 | + * This looks different from the ARM ARM pseudocode, because the ARM ARM |
137 | + * HCR_EL2.NV1 is 0, and some only if NV1 is 1 (these come in | 182 | + * puts the operands to a fused mac operation (a*b)+c in the order c,a,b |
138 | + * pairs which share an offset; see the table in R_CSRPQ). | ||
139 | + */ | 183 | + */ |
140 | + if (ri->nv2_redirect_offset & NV2_REDIR_NV1) { | 184 | + rule = float_3nan_prop_s_cab; |
141 | + nv2_mem_redirect = s->nv1; | 185 | #elif defined(TARGET_MIPS) |
142 | + } else if (ri->nv2_redirect_offset & NV2_REDIR_NO_NV1) { | 186 | - if (snan_bit_is_one(status)) { |
143 | + nv2_mem_redirect = !s->nv1; | 187 | - /* Prefer sNaN over qNaN, in the a, b, c order. */ |
144 | + } else { | 188 | - if (is_snan(a_cls)) { |
145 | + nv2_mem_redirect = true; | 189 | - return 0; |
146 | + } | 190 | - } else if (is_snan(b_cls)) { |
191 | - return 1; | ||
192 | - } else if (is_snan(c_cls)) { | ||
193 | - return 2; | ||
194 | - } else if (is_qnan(a_cls)) { | ||
195 | - return 0; | ||
196 | - } else if (is_qnan(b_cls)) { | ||
197 | - return 1; | ||
198 | + if (snan_bit_is_one(status)) { | ||
199 | + rule = float_3nan_prop_s_abc; | ||
200 | } else { | ||
201 | - return 2; | ||
202 | + rule = float_3nan_prop_s_cab; | ||
203 | } | ||
204 | - } else { | ||
205 | - /* Prefer sNaN over qNaN, in the c, a, b order. */ | ||
206 | - if (is_snan(c_cls)) { | ||
207 | - return 2; | ||
208 | - } else if (is_snan(a_cls)) { | ||
209 | - return 0; | ||
210 | - } else if (is_snan(b_cls)) { | ||
211 | - return 1; | ||
212 | - } else if (is_qnan(c_cls)) { | ||
213 | - return 2; | ||
214 | - } else if (is_qnan(a_cls)) { | ||
215 | - return 0; | ||
216 | - } else { | ||
217 | - return 1; | ||
218 | - } | ||
219 | - } | ||
220 | #elif defined(TARGET_LOONGARCH64) | ||
221 | - /* Prefer sNaN over qNaN, in the c, a, b order. */ | ||
222 | - if (is_snan(c_cls)) { | ||
223 | - return 2; | ||
224 | - } else if (is_snan(a_cls)) { | ||
225 | - return 0; | ||
226 | - } else if (is_snan(b_cls)) { | ||
227 | - return 1; | ||
228 | - } else if (is_qnan(c_cls)) { | ||
229 | - return 2; | ||
230 | - } else if (is_qnan(a_cls)) { | ||
231 | - return 0; | ||
232 | - } else { | ||
233 | - return 1; | ||
234 | - } | ||
235 | + rule = float_3nan_prop_s_cab; | ||
236 | #elif defined(TARGET_PPC) | ||
237 | - /* If fRA is a NaN return it; otherwise if fRB is a NaN return it; | ||
238 | - * otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB | ||
239 | - */ | ||
240 | - if (is_nan(a_cls)) { | ||
241 | - return 0; | ||
242 | - } else if (is_nan(c_cls)) { | ||
243 | - return 2; | ||
244 | - } else { | ||
245 | - return 1; | ||
246 | - } | ||
247 | + /* | ||
248 | + * If fRA is a NaN return it; otherwise if fRB is a NaN return it; | ||
249 | + * otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB | ||
250 | + */ | ||
251 | + rule = float_3nan_prop_acb; | ||
252 | #elif defined(TARGET_S390X) | ||
253 | - if (is_snan(a_cls)) { | ||
254 | - return 0; | ||
255 | - } else if (is_snan(b_cls)) { | ||
256 | - return 1; | ||
257 | - } else if (is_snan(c_cls)) { | ||
258 | - return 2; | ||
259 | - } else if (is_qnan(a_cls)) { | ||
260 | - return 0; | ||
261 | - } else if (is_qnan(b_cls)) { | ||
262 | - return 1; | ||
263 | - } else { | ||
264 | - return 2; | ||
265 | - } | ||
266 | + rule = float_3nan_prop_s_abc; | ||
267 | #elif defined(TARGET_SPARC) | ||
268 | - /* Prefer SNaN over QNaN, order C, B, A. */ | ||
269 | - if (is_snan(c_cls)) { | ||
270 | - return 2; | ||
271 | - } else if (is_snan(b_cls)) { | ||
272 | - return 1; | ||
273 | - } else if (is_snan(a_cls)) { | ||
274 | - return 0; | ||
275 | - } else if (is_qnan(c_cls)) { | ||
276 | - return 2; | ||
277 | - } else if (is_qnan(b_cls)) { | ||
278 | - return 1; | ||
279 | - } else { | ||
280 | - return 0; | ||
281 | - } | ||
282 | + rule = float_3nan_prop_s_cba; | ||
283 | #elif defined(TARGET_XTENSA) | ||
284 | - /* | ||
285 | - * For Xtensa, the (inf,zero,nan) case sets InvalidOp and returns | ||
286 | - * an input NaN if we have one (ie c). | ||
287 | - */ | ||
288 | - if (status->use_first_nan) { | ||
289 | - if (is_nan(a_cls)) { | ||
290 | - return 0; | ||
291 | - } else if (is_nan(b_cls)) { | ||
292 | - return 1; | ||
293 | + if (status->use_first_nan) { | ||
294 | + rule = float_3nan_prop_abc; | ||
295 | } else { | ||
296 | - return 2; | ||
297 | + rule = float_3nan_prop_cba; | ||
298 | } | ||
299 | - } else { | ||
300 | - if (is_nan(c_cls)) { | ||
301 | - return 2; | ||
302 | - } else if (is_nan(b_cls)) { | ||
303 | - return 1; | ||
304 | - } else { | ||
305 | - return 0; | ||
306 | - } | ||
307 | - } | ||
308 | #else | ||
309 | - /* A default implementation: prefer a to b to c. | ||
310 | - * This is unlikely to actually match any real implementation. | ||
311 | - */ | ||
312 | - if (is_nan(a_cls)) { | ||
313 | - return 0; | ||
314 | - } else if (is_nan(b_cls)) { | ||
315 | - return 1; | ||
316 | - } else { | ||
317 | - return 2; | ||
318 | - } | ||
319 | + rule = float_3nan_prop_abc; | ||
320 | #endif | ||
147 | + } | 321 | + } |
148 | + | 322 | + |
149 | /* Check access permissions */ | 323 | + assert(rule != float_3nan_prop_none); |
150 | if (!cp_access_ok(s->current_el, ri, isread)) { | 324 | + if (have_snan && (rule & R_3NAN_SNAN_MASK)) { |
151 | /* | 325 | + /* We have at least one SNaN input and should prefer it */ |
152 | @@ -XXX,XX +XXX,XX @@ static void handle_sys(DisasContext *s, bool isread, | 326 | + do { |
153 | * the EL2 register's accessfn. | 327 | + which = rule & R_3NAN_1ST_MASK; |
154 | */ | 328 | + rule >>= R_3NAN_1ST_LENGTH; |
155 | nv_redirect_reg = true; | 329 | + } while (!is_snan(cls[which])); |
156 | + assert(!nv2_mem_redirect); | 330 | + } else { |
157 | + } else if (nv2_mem_redirect) { | 331 | + do { |
158 | + /* | 332 | + which = rule & R_3NAN_1ST_MASK; |
159 | + * NV2 redirect-to-memory takes precedence over trap to EL2 or | 333 | + rule >>= R_3NAN_1ST_LENGTH; |
160 | + * UNDEF to EL1. | 334 | + } while (!is_nan(cls[which])); |
161 | + */ | ||
162 | } else if (s->nv && arm_cpreg_traps_in_nv(ri)) { | ||
163 | /* | ||
164 | * This register / instruction exists and is an EL2 register, so | ||
165 | @@ -XXX,XX +XXX,XX @@ static void handle_sys(DisasContext *s, bool isread, | ||
166 | assert(!(ri->type & ARM_CP_RAISES_EXC)); | ||
167 | } | ||
168 | |||
169 | + if (nv2_mem_redirect) { | ||
170 | + /* | ||
171 | + * This system register is being redirected into an EL2 memory access. | ||
172 | + * This means it is not an IO operation, doesn't change hflags, | ||
173 | + * and need not end the TB, because it has no side effects. | ||
174 | + * | ||
175 | + * The access is 64-bit single copy atomic, guaranteed aligned because | ||
176 | + * of the definition of VCNR_EL2. Its endianness depends on | ||
177 | + * SCTLR_EL2.EE, not on the data endianness of EL1. | ||
178 | + * It is done under either the EL2 translation regime or the EL2&0 | ||
179 | + * translation regime, depending on HCR_EL2.E2H. It behaves as if | ||
180 | + * PSTATE.PAN is 0. | ||
181 | + */ | ||
182 | + TCGv_i64 ptr = tcg_temp_new_i64(); | ||
183 | + MemOp mop = MO_64 | MO_ALIGN | MO_ATOM_IFALIGN; | ||
184 | + ARMMMUIdx armmemidx = s->nv2_mem_e20 ? ARMMMUIdx_E20_2 : ARMMMUIdx_E2; | ||
185 | + int memidx = arm_to_core_mmu_idx(armmemidx); | ||
186 | + | ||
187 | + mop |= (s->nv2_mem_be ? MO_BE : MO_LE); | ||
188 | + | ||
189 | + tcg_gen_ld_i64(ptr, tcg_env, offsetof(CPUARMState, cp15.vncr_el2)); | ||
190 | + tcg_gen_addi_i64(ptr, ptr, | ||
191 | + (ri->nv2_redirect_offset & ~NV2_REDIR_FLAG_MASK)); | ||
192 | + tcg_rt = cpu_reg(s, rt); | ||
193 | + if (isread) { | ||
194 | + tcg_gen_qemu_ld_i64(tcg_rt, ptr, memidx, mop); | ||
195 | + } else { | ||
196 | + tcg_gen_qemu_st_i64(tcg_rt, ptr, memidx, mop); | ||
197 | + } | ||
198 | + return; | ||
199 | + } | 335 | + } |
200 | + | 336 | + return which; |
201 | /* Handle special cases first */ | 337 | } |
202 | switch (ri->type & ARM_CP_SPECIAL_MASK) { | 338 | |
203 | case 0: | 339 | /*---------------------------------------------------------------------------- |
204 | @@ -XXX,XX +XXX,XX @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, | ||
205 | dc->nv = EX_TBFLAG_A64(tb_flags, NV); | ||
206 | dc->nv1 = EX_TBFLAG_A64(tb_flags, NV1); | ||
207 | dc->nv2 = EX_TBFLAG_A64(tb_flags, NV2); | ||
208 | + dc->nv2_mem_e20 = EX_TBFLAG_A64(tb_flags, NV2_MEM_E20); | ||
209 | + dc->nv2_mem_be = EX_TBFLAG_A64(tb_flags, NV2_MEM_BE); | ||
210 | dc->vec_len = 0; | ||
211 | dc->vec_stride = 0; | ||
212 | dc->cp_regs = arm_cpu->cp_regs; | ||
213 | -- | 340 | -- |
214 | 2.34.1 | 341 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Explicitly set a rule in the softfloat tests for propagating NaNs in | ||
2 | the muladd case. In meson.build we put -DTARGET_ARM in fpcflags, and | ||
3 | so we should select here the Arm rule of float_3nan_prop_s_cab. | ||
1 | 4 | ||
5 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
6 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
7 | Message-id: 20241202131347.498124-17-peter.maydell@linaro.org | ||
8 | --- | ||
9 | tests/fp/fp-bench.c | 1 + | ||
10 | tests/fp/fp-test.c | 1 + | ||
11 | 2 files changed, 2 insertions(+) | ||
12 | |||
13 | diff --git a/tests/fp/fp-bench.c b/tests/fp/fp-bench.c | ||
14 | index XXXXXXX..XXXXXXX 100644 | ||
15 | --- a/tests/fp/fp-bench.c | ||
16 | +++ b/tests/fp/fp-bench.c | ||
17 | @@ -XXX,XX +XXX,XX @@ static void run_bench(void) | ||
18 | * doesn't specify match those used by the Arm architecture. | ||
19 | */ | ||
20 | set_float_2nan_prop_rule(float_2nan_prop_s_ab, &soft_status); | ||
21 | + set_float_3nan_prop_rule(float_3nan_prop_s_cab, &soft_status); | ||
22 | set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, &soft_status); | ||
23 | |||
24 | f = bench_funcs[operation][precision]; | ||
25 | diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c | ||
26 | index XXXXXXX..XXXXXXX 100644 | ||
27 | --- a/tests/fp/fp-test.c | ||
28 | +++ b/tests/fp/fp-test.c | ||
29 | @@ -XXX,XX +XXX,XX @@ void run_test(void) | ||
30 | * doesn't specify match those used by the Arm architecture. | ||
31 | */ | ||
32 | set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf); | ||
33 | + set_float_3nan_prop_rule(float_3nan_prop_s_cab, &qsf); | ||
34 | set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, &qsf); | ||
35 | |||
36 | genCases_setLevel(test_level); | ||
37 | -- | ||
38 | 2.34.1 | diff view generated by jsdifflib |
1 | Enable FEAT_NV2 on the 'max' CPU, and stop filtering it out for | 1 | Set the Float3NaNPropRule explicitly for Arm, and remove the |
---|---|---|---|
2 | the Neoverse N2 and Neoverse V1 CPUs. | 2 | ifdef from pickNaNMulAdd(). |
3 | 3 | ||
4 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 4 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
5 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 5 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
6 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 6 | Message-id: 20241202131347.498124-18-peter.maydell@linaro.org |
7 | --- | 7 | --- |
8 | docs/system/arm/emulation.rst | 1 + | 8 | target/arm/cpu.c | 5 +++++ |
9 | target/arm/cpu.c | 5 ----- | 9 | fpu/softfloat-specialize.c.inc | 8 +------- |
10 | target/arm/tcg/cpu64.c | 2 +- | 10 | 2 files changed, 6 insertions(+), 7 deletions(-) |
11 | 3 files changed, 2 insertions(+), 6 deletions(-) | ||
12 | 11 | ||
13 | diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst | ||
14 | index XXXXXXX..XXXXXXX 100644 | ||
15 | --- a/docs/system/arm/emulation.rst | ||
16 | +++ b/docs/system/arm/emulation.rst | ||
17 | @@ -XXX,XX +XXX,XX @@ the following architecture extensions: | ||
18 | - FEAT_MTE2 (Memory Tagging Extension) | ||
19 | - FEAT_MTE3 (MTE Asymmetric Fault Handling) | ||
20 | - FEAT_NV (Nested Virtualization) | ||
21 | +- FEAT_NV2 (Enhanced nested virtualization support) | ||
22 | - FEAT_PACIMP (Pointer authentication - IMPLEMENTATION DEFINED algorithm) | ||
23 | - FEAT_PACQARMA3 (Pointer authentication - QARMA3 algorithm) | ||
24 | - FEAT_PACQARMA5 (Pointer authentication - QARMA5 algorithm) | ||
25 | diff --git a/target/arm/cpu.c b/target/arm/cpu.c | 12 | diff --git a/target/arm/cpu.c b/target/arm/cpu.c |
26 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
27 | --- a/target/arm/cpu.c | 14 | --- a/target/arm/cpu.c |
28 | +++ b/target/arm/cpu.c | 15 | +++ b/target/arm/cpu.c |
29 | @@ -XXX,XX +XXX,XX @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) | 16 | @@ -XXX,XX +XXX,XX @@ void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook, |
30 | /* FEAT_MPAM (Memory Partitioning and Monitoring Extension) */ | 17 | * * tininess-before-rounding |
31 | cpu->isar.id_aa64pfr0 = | 18 | * * 2-input NaN propagation prefers SNaN over QNaN, and then |
32 | FIELD_DP64(cpu->isar.id_aa64pfr0, ID_AA64PFR0, MPAM, 0); | 19 | * operand A over operand B (see FPProcessNaNs() pseudocode) |
33 | - /* FEAT_NV2 (Enhanced Nested Virtualization support) */ | 20 | + * * 3-input NaN propagation prefers SNaN over QNaN, and then |
34 | - if (FIELD_EX64(cpu->isar.id_aa64mmfr2, ID_AA64MMFR2, NV) > 1) { | 21 | + * operand C over A over B (see FPProcessNaNs3() pseudocode, |
35 | - cpu->isar.id_aa64mmfr2 = | 22 | + * but note that for QEMU muladd is a * b + c, whereas for |
36 | - FIELD_DP64(cpu->isar.id_aa64mmfr2, ID_AA64MMFR2, NV, 1); | 23 | + * the pseudocode function the arguments are in the order c, a, b. |
37 | - } | 24 | * * 0 * Inf + NaN returns the default NaN if the input NaN is quiet, |
25 | * and the input NaN if it is signalling | ||
26 | */ | ||
27 | @@ -XXX,XX +XXX,XX @@ static void arm_set_default_fp_behaviours(float_status *s) | ||
28 | { | ||
29 | set_float_detect_tininess(float_tininess_before_rounding, s); | ||
30 | set_float_2nan_prop_rule(float_2nan_prop_s_ab, s); | ||
31 | + set_float_3nan_prop_rule(float_3nan_prop_s_cab, s); | ||
32 | set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, s); | ||
33 | } | ||
34 | |||
35 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc | ||
36 | index XXXXXXX..XXXXXXX 100644 | ||
37 | --- a/fpu/softfloat-specialize.c.inc | ||
38 | +++ b/fpu/softfloat-specialize.c.inc | ||
39 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
38 | } | 40 | } |
39 | 41 | ||
40 | /* MPU can be configured out of a PMSA CPU either by setting has-mpu | 42 | if (rule == float_3nan_prop_none) { |
41 | diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c | 43 | -#if defined(TARGET_ARM) |
42 | index XXXXXXX..XXXXXXX 100644 | 44 | - /* |
43 | --- a/target/arm/tcg/cpu64.c | 45 | - * This looks different from the ARM ARM pseudocode, because the ARM ARM |
44 | +++ b/target/arm/tcg/cpu64.c | 46 | - * puts the operands to a fused mac operation (a*b)+c in the order c,a,b |
45 | @@ -XXX,XX +XXX,XX @@ void aarch64_max_tcg_initfn(Object *obj) | 47 | - */ |
46 | t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1); /* FEAT_UAO */ | 48 | - rule = float_3nan_prop_s_cab; |
47 | t = FIELD_DP64(t, ID_AA64MMFR2, IESB, 1); /* FEAT_IESB */ | 49 | -#elif defined(TARGET_MIPS) |
48 | t = FIELD_DP64(t, ID_AA64MMFR2, VARANGE, 1); /* FEAT_LVA */ | 50 | +#if defined(TARGET_MIPS) |
49 | - t = FIELD_DP64(t, ID_AA64MMFR2, NV, 1); /* FEAT_NV */ | 51 | if (snan_bit_is_one(status)) { |
50 | + t = FIELD_DP64(t, ID_AA64MMFR2, NV, 2); /* FEAT_NV2 */ | 52 | rule = float_3nan_prop_s_abc; |
51 | t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* FEAT_TTST */ | 53 | } else { |
52 | t = FIELD_DP64(t, ID_AA64MMFR2, AT, 1); /* FEAT_LSE2 */ | ||
53 | t = FIELD_DP64(t, ID_AA64MMFR2, IDS, 1); /* FEAT_IDST */ | ||
54 | -- | 54 | -- |
55 | 2.34.1 | 55 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Set the Float3NaNPropRule explicitly for loongarch, and remove the | ||
2 | ifdef from pickNaNMulAdd(). | ||
1 | 3 | ||
4 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
5 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
6 | Message-id: 20241202131347.498124-19-peter.maydell@linaro.org | ||
7 | --- | ||
8 | target/loongarch/tcg/fpu_helper.c | 1 + | ||
9 | fpu/softfloat-specialize.c.inc | 2 -- | ||
10 | 2 files changed, 1 insertion(+), 2 deletions(-) | ||
11 | |||
12 | diff --git a/target/loongarch/tcg/fpu_helper.c b/target/loongarch/tcg/fpu_helper.c | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/target/loongarch/tcg/fpu_helper.c | ||
15 | +++ b/target/loongarch/tcg/fpu_helper.c | ||
16 | @@ -XXX,XX +XXX,XX @@ void restore_fp_status(CPULoongArchState *env) | ||
17 | * case sets InvalidOp and returns the input value 'c' | ||
18 | */ | ||
19 | set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status); | ||
20 | + set_float_3nan_prop_rule(float_3nan_prop_s_cab, &env->fp_status); | ||
21 | } | ||
22 | |||
23 | int ieee_ex_to_loongarch(int xcpt) | ||
24 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc | ||
25 | index XXXXXXX..XXXXXXX 100644 | ||
26 | --- a/fpu/softfloat-specialize.c.inc | ||
27 | +++ b/fpu/softfloat-specialize.c.inc | ||
28 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
29 | } else { | ||
30 | rule = float_3nan_prop_s_cab; | ||
31 | } | ||
32 | -#elif defined(TARGET_LOONGARCH64) | ||
33 | - rule = float_3nan_prop_s_cab; | ||
34 | #elif defined(TARGET_PPC) | ||
35 | /* | ||
36 | * If fRA is a NaN return it; otherwise if fRB is a NaN return it; | ||
37 | -- | ||
38 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Set the Float3NaNPropRule explicitly for PPC, and remove the | ||
2 | ifdef from pickNaNMulAdd(). | ||
1 | 3 | ||
4 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
5 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
6 | Message-id: 20241202131347.498124-20-peter.maydell@linaro.org | ||
7 | --- | ||
8 | target/ppc/cpu_init.c | 8 ++++++++ | ||
9 | fpu/softfloat-specialize.c.inc | 6 ------ | ||
10 | 2 files changed, 8 insertions(+), 6 deletions(-) | ||
11 | |||
12 | diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/target/ppc/cpu_init.c | ||
15 | +++ b/target/ppc/cpu_init.c | ||
16 | @@ -XXX,XX +XXX,XX @@ static void ppc_cpu_reset_hold(Object *obj, ResetType type) | ||
17 | */ | ||
18 | set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status); | ||
19 | set_float_2nan_prop_rule(float_2nan_prop_ab, &env->vec_status); | ||
20 | + /* | ||
21 | + * NaN propagation for fused multiply-add: | ||
22 | + * if fRA is a NaN return it; otherwise if fRB is a NaN return it; | ||
23 | + * otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB | ||
24 | + * whereas QEMU labels the operands as (a * b) + c. | ||
25 | + */ | ||
26 | + set_float_3nan_prop_rule(float_3nan_prop_acb, &env->fp_status); | ||
27 | + set_float_3nan_prop_rule(float_3nan_prop_acb, &env->vec_status); | ||
28 | /* | ||
29 | * For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer | ||
30 | * to return an input NaN if we have one (ie c) rather than generating | ||
31 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc | ||
32 | index XXXXXXX..XXXXXXX 100644 | ||
33 | --- a/fpu/softfloat-specialize.c.inc | ||
34 | +++ b/fpu/softfloat-specialize.c.inc | ||
35 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
36 | } else { | ||
37 | rule = float_3nan_prop_s_cab; | ||
38 | } | ||
39 | -#elif defined(TARGET_PPC) | ||
40 | - /* | ||
41 | - * If fRA is a NaN return it; otherwise if fRB is a NaN return it; | ||
42 | - * otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB | ||
43 | - */ | ||
44 | - rule = float_3nan_prop_acb; | ||
45 | #elif defined(TARGET_S390X) | ||
46 | rule = float_3nan_prop_s_abc; | ||
47 | #elif defined(TARGET_SPARC) | ||
48 | -- | ||
49 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Set the Float3NaNPropRule explicitly for s390x, and remove the | ||
2 | ifdef from pickNaNMulAdd(). | ||
1 | 3 | ||
4 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
5 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
6 | Message-id: 20241202131347.498124-21-peter.maydell@linaro.org | ||
7 | --- | ||
8 | target/s390x/cpu.c | 1 + | ||
9 | fpu/softfloat-specialize.c.inc | 2 -- | ||
10 | 2 files changed, 1 insertion(+), 2 deletions(-) | ||
11 | |||
12 | diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/target/s390x/cpu.c | ||
15 | +++ b/target/s390x/cpu.c | ||
16 | @@ -XXX,XX +XXX,XX @@ static void s390_cpu_reset_hold(Object *obj, ResetType type) | ||
17 | set_float_detect_tininess(float_tininess_before_rounding, | ||
18 | &env->fpu_status); | ||
19 | set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fpu_status); | ||
20 | + set_float_3nan_prop_rule(float_3nan_prop_s_abc, &env->fpu_status); | ||
21 | set_float_infzeronan_rule(float_infzeronan_dnan_always, | ||
22 | &env->fpu_status); | ||
23 | /* fall through */ | ||
24 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc | ||
25 | index XXXXXXX..XXXXXXX 100644 | ||
26 | --- a/fpu/softfloat-specialize.c.inc | ||
27 | +++ b/fpu/softfloat-specialize.c.inc | ||
28 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
29 | } else { | ||
30 | rule = float_3nan_prop_s_cab; | ||
31 | } | ||
32 | -#elif defined(TARGET_S390X) | ||
33 | - rule = float_3nan_prop_s_abc; | ||
34 | #elif defined(TARGET_SPARC) | ||
35 | rule = float_3nan_prop_s_cba; | ||
36 | #elif defined(TARGET_XTENSA) | ||
37 | -- | ||
38 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Set the Float3NaNPropRule explicitly for SPARC, and remove the | ||
2 | ifdef from pickNaNMulAdd(). | ||
1 | 3 | ||
4 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
5 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
6 | Message-id: 20241202131347.498124-22-peter.maydell@linaro.org | ||
7 | --- | ||
8 | target/sparc/cpu.c | 2 ++ | ||
9 | fpu/softfloat-specialize.c.inc | 2 -- | ||
10 | 2 files changed, 2 insertions(+), 2 deletions(-) | ||
11 | |||
12 | diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/target/sparc/cpu.c | ||
15 | +++ b/target/sparc/cpu.c | ||
16 | @@ -XXX,XX +XXX,XX @@ static void sparc_cpu_realizefn(DeviceState *dev, Error **errp) | ||
17 | * the CPU state struct so it won't get zeroed on reset. | ||
18 | */ | ||
19 | set_float_2nan_prop_rule(float_2nan_prop_s_ba, &env->fp_status); | ||
20 | + /* For fused-multiply add, prefer SNaN over QNaN, then C->B->A */ | ||
21 | + set_float_3nan_prop_rule(float_3nan_prop_s_cba, &env->fp_status); | ||
22 | /* For inf * 0 + NaN, return the input NaN */ | ||
23 | set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status); | ||
24 | |||
25 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc | ||
26 | index XXXXXXX..XXXXXXX 100644 | ||
27 | --- a/fpu/softfloat-specialize.c.inc | ||
28 | +++ b/fpu/softfloat-specialize.c.inc | ||
29 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
30 | } else { | ||
31 | rule = float_3nan_prop_s_cab; | ||
32 | } | ||
33 | -#elif defined(TARGET_SPARC) | ||
34 | - rule = float_3nan_prop_s_cba; | ||
35 | #elif defined(TARGET_XTENSA) | ||
36 | if (status->use_first_nan) { | ||
37 | rule = float_3nan_prop_abc; | ||
38 | -- | ||
39 | 2.34.1 | diff view generated by jsdifflib |
1 | FEAT_NV2 defines another new bit in HCR_EL2: NV2. When the | 1 | Set the Float3NaNPropRule explicitly for Arm, and remove the |
---|---|---|---|
2 | feature is enabled, allow this bit to be written in HCR_EL2. | 2 | ifdef from pickNaNMulAdd(). |
3 | 3 | ||
4 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 4 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
5 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 5 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
6 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 6 | Message-id: 20241202131347.498124-23-peter.maydell@linaro.org |
7 | --- | 7 | --- |
8 | target/arm/cpu-features.h | 5 +++++ | 8 | target/mips/fpu_helper.h | 4 ++++ |
9 | target/arm/helper.c | 3 +++ | 9 | target/mips/msa.c | 3 +++ |
10 | 2 files changed, 8 insertions(+) | 10 | fpu/softfloat-specialize.c.inc | 8 +------- |
11 | 3 files changed, 8 insertions(+), 7 deletions(-) | ||
11 | 12 | ||
12 | diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h | 13 | diff --git a/target/mips/fpu_helper.h b/target/mips/fpu_helper.h |
13 | index XXXXXXX..XXXXXXX 100644 | 14 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/target/arm/cpu-features.h | 15 | --- a/target/mips/fpu_helper.h |
15 | +++ b/target/arm/cpu-features.h | 16 | +++ b/target/mips/fpu_helper.h |
16 | @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_nv(const ARMISARegisters *id) | 17 | @@ -XXX,XX +XXX,XX @@ static inline void restore_snan_bit_mode(CPUMIPSState *env) |
17 | return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, NV) != 0; | 18 | { |
19 | bool nan2008 = env->active_fpu.fcr31 & (1 << FCR31_NAN2008); | ||
20 | FloatInfZeroNaNRule izn_rule; | ||
21 | + Float3NaNPropRule nan3_rule; | ||
22 | |||
23 | /* | ||
24 | * With nan2008, SNaNs are silenced in the usual way. | ||
25 | @@ -XXX,XX +XXX,XX @@ static inline void restore_snan_bit_mode(CPUMIPSState *env) | ||
26 | */ | ||
27 | izn_rule = nan2008 ? float_infzeronan_dnan_never : float_infzeronan_dnan_always; | ||
28 | set_float_infzeronan_rule(izn_rule, &env->active_fpu.fp_status); | ||
29 | + nan3_rule = nan2008 ? float_3nan_prop_s_cab : float_3nan_prop_s_abc; | ||
30 | + set_float_3nan_prop_rule(nan3_rule, &env->active_fpu.fp_status); | ||
31 | + | ||
18 | } | 32 | } |
19 | 33 | ||
20 | +static inline bool isar_feature_aa64_nv2(const ARMISARegisters *id) | 34 | static inline void restore_fp_status(CPUMIPSState *env) |
21 | +{ | 35 | diff --git a/target/mips/msa.c b/target/mips/msa.c |
22 | + return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, NV) >= 2; | 36 | index XXXXXXX..XXXXXXX 100644 |
23 | +} | 37 | --- a/target/mips/msa.c |
38 | +++ b/target/mips/msa.c | ||
39 | @@ -XXX,XX +XXX,XX @@ void msa_reset(CPUMIPSState *env) | ||
40 | set_float_2nan_prop_rule(float_2nan_prop_s_ab, | ||
41 | &env->active_tc.msa_fp_status); | ||
42 | |||
43 | + set_float_3nan_prop_rule(float_3nan_prop_s_cab, | ||
44 | + &env->active_tc.msa_fp_status); | ||
24 | + | 45 | + |
25 | static inline bool isar_feature_aa64_pmuv3p1(const ARMISARegisters *id) | 46 | /* clear float_status exception flags */ |
26 | { | 47 | set_float_exception_flags(0, &env->active_tc.msa_fp_status); |
27 | return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 4 && | 48 | |
28 | diff --git a/target/arm/helper.c b/target/arm/helper.c | 49 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc |
29 | index XXXXXXX..XXXXXXX 100644 | 50 | index XXXXXXX..XXXXXXX 100644 |
30 | --- a/target/arm/helper.c | 51 | --- a/fpu/softfloat-specialize.c.inc |
31 | +++ b/target/arm/helper.c | 52 | +++ b/fpu/softfloat-specialize.c.inc |
32 | @@ -XXX,XX +XXX,XX @@ static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask) | 53 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, |
33 | if (cpu_isar_feature(aa64_nv, cpu)) { | ||
34 | valid_mask |= HCR_NV | HCR_NV1 | HCR_AT; | ||
35 | } | ||
36 | + if (cpu_isar_feature(aa64_nv2, cpu)) { | ||
37 | + valid_mask |= HCR_NV2; | ||
38 | + } | ||
39 | } | 54 | } |
40 | 55 | ||
41 | if (cpu_isar_feature(any_evt, cpu)) { | 56 | if (rule == float_3nan_prop_none) { |
57 | -#if defined(TARGET_MIPS) | ||
58 | - if (snan_bit_is_one(status)) { | ||
59 | - rule = float_3nan_prop_s_abc; | ||
60 | - } else { | ||
61 | - rule = float_3nan_prop_s_cab; | ||
62 | - } | ||
63 | -#elif defined(TARGET_XTENSA) | ||
64 | +#if defined(TARGET_XTENSA) | ||
65 | if (status->use_first_nan) { | ||
66 | rule = float_3nan_prop_abc; | ||
67 | } else { | ||
42 | -- | 68 | -- |
43 | 2.34.1 | 69 | 2.34.1 | diff view generated by jsdifflib |
1 | For FEAT_NV, accesses to system registers and instructions from EL1 | 1 | Set the Float3NaNPropRule explicitly for xtensa, and remove the |
---|---|---|---|
2 | which would normally UNDEF there but which work in EL2 need to | 2 | ifdef from pickNaNMulAdd(). |
3 | instead be trapped to EL2. Detect this both for "we know this will | ||
4 | UNDEF at translate time" and "we found this UNDEFs at runtime", and | ||
5 | make the affected registers trap to EL2 instead. | ||
6 | |||
7 | The Arm ARM defines the set of registers that should trap in terms | ||
8 | of their names; for our implementation this would be both awkward | ||
9 | and inefficent as a test, so we instead trap based on the opc1 | ||
10 | field of the sysreg. The regularity of the architectural choice | ||
11 | of encodings for sysregs means that in practice this captures | ||
12 | exactly the correct set of registers. | ||
13 | |||
14 | Regardless of how we try to define the registers this trapping | ||
15 | applies to, there's going to be a certain possibility of breakage | ||
16 | if new architectural features introduce new registers that don't | ||
17 | follow the current rules (FEAT_MEC is one example already visible | ||
18 | in the released sysreg XML, though not yet in the Arm ARM). This | ||
19 | approach seems to me to be straightforward and likely to require | ||
20 | a minimum of manual overrides. | ||
21 | 3 | ||
22 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 4 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
23 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 5 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
24 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 6 | Message-id: 20241202131347.498124-24-peter.maydell@linaro.org |
25 | --- | 7 | --- |
26 | target/arm/cpregs.h | 34 +++++++++++++++++++++++ | 8 | target/xtensa/fpu_helper.c | 2 ++ |
27 | target/arm/cpu.h | 1 + | 9 | fpu/softfloat-specialize.c.inc | 8 -------- |
28 | target/arm/tcg/translate.h | 2 ++ | 10 | 2 files changed, 2 insertions(+), 8 deletions(-) |
29 | target/arm/tcg/hflags.c | 1 + | ||
30 | target/arm/tcg/translate-a64.c | 49 +++++++++++++++++++++++++++------- | ||
31 | 5 files changed, 77 insertions(+), 10 deletions(-) | ||
32 | 11 | ||
33 | diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h | 12 | diff --git a/target/xtensa/fpu_helper.c b/target/xtensa/fpu_helper.c |
34 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
35 | --- a/target/arm/cpregs.h | 14 | --- a/target/xtensa/fpu_helper.c |
36 | +++ b/target/arm/cpregs.h | 15 | +++ b/target/xtensa/fpu_helper.c |
37 | @@ -XXX,XX +XXX,XX @@ void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu); | 16 | @@ -XXX,XX +XXX,XX @@ void xtensa_use_first_nan(CPUXtensaState *env, bool use_first) |
38 | 17 | set_use_first_nan(use_first, &env->fp_status); | |
39 | CPAccessResult access_tvm_trvm(CPUARMState *, const ARMCPRegInfo *, bool); | 18 | set_float_2nan_prop_rule(use_first ? float_2nan_prop_ab : float_2nan_prop_ba, |
40 | 19 | &env->fp_status); | |
41 | +/** | 20 | + set_float_3nan_prop_rule(use_first ? float_3nan_prop_abc : float_3nan_prop_cba, |
42 | + * arm_cpreg_trap_in_nv: Return true if cpreg traps in nested virtualization | 21 | + &env->fp_status); |
43 | + * | 22 | } |
44 | + * Return true if this cpreg is one which should be trapped to EL2 if | 23 | |
45 | + * it is executed at EL1 when nested virtualization is enabled via HCR_EL2.NV. | 24 | void HELPER(wur_fpu2k_fcr)(CPUXtensaState *env, uint32_t v) |
46 | + */ | 25 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc |
47 | +static inline bool arm_cpreg_traps_in_nv(const ARMCPRegInfo *ri) | ||
48 | +{ | ||
49 | + /* | ||
50 | + * The Arm ARM defines the registers to be trapped in terms of | ||
51 | + * their names (I_TZTZL). However the underlying principle is "if | ||
52 | + * it would UNDEF at EL1 but work at EL2 then it should trap", and | ||
53 | + * the way the encoding of sysregs and system instructions is done | ||
54 | + * means that the right set of registers is exactly those where | ||
55 | + * the opc1 field is 4 or 5. (You can see this also in the assert | ||
56 | + * we do that the opc1 field and the permissions mask line up in | ||
57 | + * define_one_arm_cp_reg_with_opaque().) | ||
58 | + * Checking the opc1 field is easier for us and avoids the problem | ||
59 | + * that we do not consistently use the right architectural names | ||
60 | + * for all sysregs, since we treat the name field as largely for debug. | ||
61 | + * | ||
62 | + * However we do this check, it is going to be at least potentially | ||
63 | + * fragile to future new sysregs, but this seems the least likely | ||
64 | + * to break. | ||
65 | + * | ||
66 | + * In particular, note that the released sysreg XML defines that | ||
67 | + * the FEAT_MEC sysregs and instructions do not follow this FEAT_NV | ||
68 | + * trapping rule, so we will need to add an ARM_CP_* flag to indicate | ||
69 | + * "register does not trap on NV" to handle those if/when we implement | ||
70 | + * FEAT_MEC. | ||
71 | + */ | ||
72 | + return ri->opc1 == 4 || ri->opc1 == 5; | ||
73 | +} | ||
74 | + | ||
75 | #endif /* TARGET_ARM_CPREGS_H */ | ||
76 | diff --git a/target/arm/cpu.h b/target/arm/cpu.h | ||
77 | index XXXXXXX..XXXXXXX 100644 | 26 | index XXXXXXX..XXXXXXX 100644 |
78 | --- a/target/arm/cpu.h | 27 | --- a/fpu/softfloat-specialize.c.inc |
79 | +++ b/target/arm/cpu.h | 28 | +++ b/fpu/softfloat-specialize.c.inc |
80 | @@ -XXX,XX +XXX,XX @@ FIELD(TBFLAG_A64, SME_TRAP_NONSTREAMING, 28, 1) | 29 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, |
81 | FIELD(TBFLAG_A64, TRAP_ERET, 29, 1) | ||
82 | FIELD(TBFLAG_A64, NAA, 30, 1) | ||
83 | FIELD(TBFLAG_A64, ATA0, 31, 1) | ||
84 | +FIELD(TBFLAG_A64, NV, 32, 1) | ||
85 | |||
86 | /* | ||
87 | * Helpers for using the above. Note that only the A64 accessors use | ||
88 | diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h | ||
89 | index XXXXXXX..XXXXXXX 100644 | ||
90 | --- a/target/arm/tcg/translate.h | ||
91 | +++ b/target/arm/tcg/translate.h | ||
92 | @@ -XXX,XX +XXX,XX @@ typedef struct DisasContext { | ||
93 | bool trap_eret; | ||
94 | /* True if FEAT_LSE2 SCTLR_ELx.nAA is set */ | ||
95 | bool naa; | ||
96 | + /* True if FEAT_NV HCR_EL2.NV is enabled */ | ||
97 | + bool nv; | ||
98 | /* | ||
99 | * >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI. | ||
100 | * < 0, set by the current instruction. | ||
101 | diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c | ||
102 | index XXXXXXX..XXXXXXX 100644 | ||
103 | --- a/target/arm/tcg/hflags.c | ||
104 | +++ b/target/arm/tcg/hflags.c | ||
105 | @@ -XXX,XX +XXX,XX @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, | ||
106 | */ | ||
107 | if (el == 1 && (hcr & HCR_NV)) { | ||
108 | DP_TBFLAG_A64(flags, TRAP_ERET, 1); | ||
109 | + DP_TBFLAG_A64(flags, NV, 1); | ||
110 | } | 30 | } |
111 | 31 | ||
112 | if (cpu_isar_feature(aa64_mte, env_archcpu(env))) { | 32 | if (rule == float_3nan_prop_none) { |
113 | diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c | 33 | -#if defined(TARGET_XTENSA) |
114 | index XXXXXXX..XXXXXXX 100644 | 34 | - if (status->use_first_nan) { |
115 | --- a/target/arm/tcg/translate-a64.c | 35 | - rule = float_3nan_prop_abc; |
116 | +++ b/target/arm/tcg/translate-a64.c | 36 | - } else { |
117 | @@ -XXX,XX +XXX,XX @@ static void handle_sys(DisasContext *s, bool isread, | 37 | - rule = float_3nan_prop_cba; |
118 | crn, crm, op0, op1, op2); | 38 | - } |
119 | const ARMCPRegInfo *ri = get_arm_cp_reginfo(s->cp_regs, key); | 39 | -#else |
120 | bool need_exit_tb = false; | 40 | rule = float_3nan_prop_abc; |
121 | + bool nv_trap_to_el2 = false; | 41 | -#endif |
122 | + bool skip_fp_access_checks = false; | ||
123 | TCGv_ptr tcg_ri = NULL; | ||
124 | TCGv_i64 tcg_rt; | ||
125 | - uint32_t syndrome; | ||
126 | + uint32_t syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread); | ||
127 | |||
128 | if (crn == 11 || crn == 15) { | ||
129 | /* | ||
130 | * Check for TIDCP trap, which must take precedence over | ||
131 | * the UNDEF for "no such register" etc. | ||
132 | */ | ||
133 | - syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread); | ||
134 | switch (s->current_el) { | ||
135 | case 0: | ||
136 | if (dc_isar_feature(aa64_tidcp1, s)) { | ||
137 | @@ -XXX,XX +XXX,XX @@ static void handle_sys(DisasContext *s, bool isread, | ||
138 | |||
139 | /* Check access permissions */ | ||
140 | if (!cp_access_ok(s->current_el, ri, isread)) { | ||
141 | - gen_sysreg_undef(s, isread, op0, op1, op2, crn, crm, rt); | ||
142 | - return; | ||
143 | + /* | ||
144 | + * FEAT_NV/NV2 handling does not do the usual FP access checks | ||
145 | + * for registers only accessible at EL2 (though it *does* do them | ||
146 | + * for registers accessible at EL1). | ||
147 | + */ | ||
148 | + skip_fp_access_checks = true; | ||
149 | + if (s->nv && arm_cpreg_traps_in_nv(ri)) { | ||
150 | + /* | ||
151 | + * This register / instruction exists and is an EL2 register, so | ||
152 | + * we must trap to EL2 if accessed in nested virtualization EL1 | ||
153 | + * instead of UNDEFing. We'll do that after the usual access checks. | ||
154 | + * (This makes a difference only for a couple of registers like | ||
155 | + * VSTTBR_EL2 where the "UNDEF if NonSecure" should take priority | ||
156 | + * over the trap-to-EL2. Most trapped-by-FEAT_NV registers have | ||
157 | + * an accessfn which does nothing when called from EL1, because | ||
158 | + * the trap-to-EL3 controls which would apply to that register | ||
159 | + * at EL2 don't take priority over the FEAT_NV trap-to-EL2.) | ||
160 | + */ | ||
161 | + nv_trap_to_el2 = true; | ||
162 | + } else { | ||
163 | + gen_sysreg_undef(s, isread, op0, op1, op2, crn, crm, rt); | ||
164 | + return; | ||
165 | + } | ||
166 | } | 42 | } |
167 | 43 | ||
168 | if (ri->accessfn || (ri->fgt && s->fgt_active)) { | 44 | assert(rule != float_3nan_prop_none); |
169 | /* Emit code to perform further access permissions checks at | ||
170 | * runtime; this may result in an exception. | ||
171 | */ | ||
172 | - syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread); | ||
173 | gen_a64_update_pc(s, 0); | ||
174 | tcg_ri = tcg_temp_new_ptr(); | ||
175 | gen_helper_access_check_cp_reg(tcg_ri, tcg_env, | ||
176 | @@ -XXX,XX +XXX,XX @@ static void handle_sys(DisasContext *s, bool isread, | ||
177 | gen_a64_update_pc(s, 0); | ||
178 | } | ||
179 | |||
180 | - if ((ri->type & ARM_CP_FPU) && !fp_access_check_only(s)) { | ||
181 | - return; | ||
182 | - } else if ((ri->type & ARM_CP_SVE) && !sve_access_check(s)) { | ||
183 | - return; | ||
184 | - } else if ((ri->type & ARM_CP_SME) && !sme_access_check(s)) { | ||
185 | + if (!skip_fp_access_checks) { | ||
186 | + if ((ri->type & ARM_CP_FPU) && !fp_access_check_only(s)) { | ||
187 | + return; | ||
188 | + } else if ((ri->type & ARM_CP_SVE) && !sve_access_check(s)) { | ||
189 | + return; | ||
190 | + } else if ((ri->type & ARM_CP_SME) && !sme_access_check(s)) { | ||
191 | + return; | ||
192 | + } | ||
193 | + } | ||
194 | + | ||
195 | + if (nv_trap_to_el2) { | ||
196 | + gen_exception_insn_el(s, 0, EXCP_UDEF, syndrome, 2); | ||
197 | return; | ||
198 | } | ||
199 | |||
200 | @@ -XXX,XX +XXX,XX @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, | ||
201 | dc->pstate_za = EX_TBFLAG_A64(tb_flags, PSTATE_ZA); | ||
202 | dc->sme_trap_nonstreaming = EX_TBFLAG_A64(tb_flags, SME_TRAP_NONSTREAMING); | ||
203 | dc->naa = EX_TBFLAG_A64(tb_flags, NAA); | ||
204 | + dc->nv = EX_TBFLAG_A64(tb_flags, NV); | ||
205 | dc->vec_len = 0; | ||
206 | dc->vec_stride = 0; | ||
207 | dc->cp_regs = arm_cpu->cp_regs; | ||
208 | -- | 45 | -- |
209 | 2.34.1 | 46 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Set the Float3NaNPropRule explicitly for i386. We had no | ||
2 | i386-specific behaviour in the old ifdef ladder, so we were using the | ||
3 | default "prefer a then b then c" fallback; this is actually the | ||
4 | correct per-the-spec handling for i386. | ||
1 | 5 | ||
6 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
7 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
8 | Message-id: 20241202131347.498124-25-peter.maydell@linaro.org | ||
9 | --- | ||
10 | target/i386/tcg/fpu_helper.c | 1 + | ||
11 | 1 file changed, 1 insertion(+) | ||
12 | |||
13 | diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c | ||
14 | index XXXXXXX..XXXXXXX 100644 | ||
15 | --- a/target/i386/tcg/fpu_helper.c | ||
16 | +++ b/target/i386/tcg/fpu_helper.c | ||
17 | @@ -XXX,XX +XXX,XX @@ void cpu_init_fp_statuses(CPUX86State *env) | ||
18 | * there are multiple input NaNs they are selected in the order a, b, c. | ||
19 | */ | ||
20 | set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->sse_status); | ||
21 | + set_float_3nan_prop_rule(float_3nan_prop_abc, &env->sse_status); | ||
22 | } | ||
23 | |||
24 | static inline uint8_t save_exception_flags(CPUX86State *env) | ||
25 | -- | ||
26 | 2.34.1 | diff view generated by jsdifflib |
1 | When FEAT_NV is turned on via the HCR_EL2.NV bit, ERET instructions | 1 | Set the Float3NaNPropRule explicitly for HPPA, and remove the |
---|---|---|---|
2 | are trapped, with the same syndrome information as for the existing | 2 | ifdef from pickNaNMulAdd(). |
3 | FEAT_FGT fine-grained trap (in the pseudocode this is handled in | ||
4 | AArch64.CheckForEretTrap()). | ||
5 | 3 | ||
6 | Rename the DisasContext and tbflag bits to reflect that they are | 4 | HPPA is the only target that was using the default branch of the |
7 | no longer exclusively for FGT traps, and set the tbflag bit when | 5 | ifdef ladder (other targets either do not use muladd or set |
8 | FEAT_NV is enabled as well as when the FGT is enabled. | 6 | default_nan_mode), so we can remove the ifdef fallback entirely now |
7 | (allowing the "rule not set" case to fall into the default of the | ||
8 | switch statement and assert). | ||
9 | |||
10 | We add a TODO note that the HPPA rule is probably wrong; this is | ||
11 | not a behavioural change for this refactoring. | ||
9 | 12 | ||
10 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 13 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
11 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 14 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
12 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 15 | Message-id: 20241202131347.498124-26-peter.maydell@linaro.org |
13 | --- | 16 | --- |
14 | target/arm/cpu.h | 2 +- | 17 | target/hppa/fpu_helper.c | 8 ++++++++ |
15 | target/arm/tcg/translate.h | 4 ++-- | 18 | fpu/softfloat-specialize.c.inc | 4 ---- |
16 | target/arm/tcg/hflags.c | 11 ++++++++++- | 19 | 2 files changed, 8 insertions(+), 4 deletions(-) |
17 | target/arm/tcg/translate-a64.c | 6 +++--- | ||
18 | 4 files changed, 16 insertions(+), 7 deletions(-) | ||
19 | 20 | ||
20 | diff --git a/target/arm/cpu.h b/target/arm/cpu.h | 21 | diff --git a/target/hppa/fpu_helper.c b/target/hppa/fpu_helper.c |
21 | index XXXXXXX..XXXXXXX 100644 | 22 | index XXXXXXX..XXXXXXX 100644 |
22 | --- a/target/arm/cpu.h | 23 | --- a/target/hppa/fpu_helper.c |
23 | +++ b/target/arm/cpu.h | 24 | +++ b/target/hppa/fpu_helper.c |
24 | @@ -XXX,XX +XXX,XX @@ FIELD(TBFLAG_A64, PSTATE_ZA, 23, 1) | 25 | @@ -XXX,XX +XXX,XX @@ void HELPER(loaded_fr0)(CPUHPPAState *env) |
25 | FIELD(TBFLAG_A64, SVL, 24, 4) | 26 | * HPPA does note implement a CPU reset method at all... |
26 | /* Indicates that SME Streaming mode is active, and SMCR_ELx.FA64 is not. */ | 27 | */ |
27 | FIELD(TBFLAG_A64, SME_TRAP_NONSTREAMING, 28, 1) | 28 | set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fp_status); |
28 | -FIELD(TBFLAG_A64, FGT_ERET, 29, 1) | 29 | + /* |
29 | +FIELD(TBFLAG_A64, TRAP_ERET, 29, 1) | 30 | + * TODO: The HPPA architecture reference only documents its NaN |
30 | FIELD(TBFLAG_A64, NAA, 30, 1) | 31 | + * propagation rule for 2-operand operations. Testing on real hardware |
31 | FIELD(TBFLAG_A64, ATA0, 31, 1) | 32 | + * might be necessary to confirm whether this order for muladd is correct. |
32 | 33 | + * Not preferring the SNaN is almost certainly incorrect as it diverges | |
33 | diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h | 34 | + * from the documented rules for 2-operand operations. |
35 | + */ | ||
36 | + set_float_3nan_prop_rule(float_3nan_prop_abc, &env->fp_status); | ||
37 | /* For inf * 0 + NaN, return the input NaN */ | ||
38 | set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status); | ||
39 | } | ||
40 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc | ||
34 | index XXXXXXX..XXXXXXX 100644 | 41 | index XXXXXXX..XXXXXXX 100644 |
35 | --- a/target/arm/tcg/translate.h | 42 | --- a/fpu/softfloat-specialize.c.inc |
36 | +++ b/target/arm/tcg/translate.h | 43 | +++ b/fpu/softfloat-specialize.c.inc |
37 | @@ -XXX,XX +XXX,XX @@ typedef struct DisasContext { | 44 | @@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, |
38 | bool mve_no_pred; | ||
39 | /* True if fine-grained traps are active */ | ||
40 | bool fgt_active; | ||
41 | - /* True if fine-grained trap on ERET is enabled */ | ||
42 | - bool fgt_eret; | ||
43 | /* True if fine-grained trap on SVC is enabled */ | ||
44 | bool fgt_svc; | ||
45 | + /* True if a trap on ERET is enabled (FGT or NV) */ | ||
46 | + bool trap_eret; | ||
47 | /* True if FEAT_LSE2 SCTLR_ELx.nAA is set */ | ||
48 | bool naa; | ||
49 | /* | ||
50 | diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c | ||
51 | index XXXXXXX..XXXXXXX 100644 | ||
52 | --- a/target/arm/tcg/hflags.c | ||
53 | +++ b/target/arm/tcg/hflags.c | ||
54 | @@ -XXX,XX +XXX,XX @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, | ||
55 | CPUARMTBFlags flags = {}; | ||
56 | ARMMMUIdx stage1 = stage_1_mmu_idx(mmu_idx); | ||
57 | uint64_t tcr = regime_tcr(env, mmu_idx); | ||
58 | + uint64_t hcr = arm_hcr_el2_eff(env); | ||
59 | uint64_t sctlr; | ||
60 | int tbii, tbid; | ||
61 | |||
62 | @@ -XXX,XX +XXX,XX @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, | ||
63 | if (arm_fgt_active(env, el)) { | ||
64 | DP_TBFLAG_ANY(flags, FGT_ACTIVE, 1); | ||
65 | if (FIELD_EX64(env->cp15.fgt_exec[FGTREG_HFGITR], HFGITR_EL2, ERET)) { | ||
66 | - DP_TBFLAG_A64(flags, FGT_ERET, 1); | ||
67 | + DP_TBFLAG_A64(flags, TRAP_ERET, 1); | ||
68 | } | ||
69 | if (fgt_svc(env, el)) { | ||
70 | DP_TBFLAG_ANY(flags, FGT_SVC, 1); | ||
71 | } | 45 | } |
72 | } | 46 | } |
73 | 47 | ||
74 | + /* | 48 | - if (rule == float_3nan_prop_none) { |
75 | + * ERET can also be trapped for FEAT_NV. arm_hcr_el2_eff() takes care | 49 | - rule = float_3nan_prop_abc; |
76 | + * of "is EL2 enabled" and the NV bit can only be set if FEAT_NV is present. | 50 | - } |
77 | + */ | 51 | - |
78 | + if (el == 1 && (hcr & HCR_NV)) { | 52 | assert(rule != float_3nan_prop_none); |
79 | + DP_TBFLAG_A64(flags, TRAP_ERET, 1); | 53 | if (have_snan && (rule & R_3NAN_SNAN_MASK)) { |
80 | + } | 54 | /* We have at least one SNaN input and should prefer it */ |
81 | + | ||
82 | if (cpu_isar_feature(aa64_mte, env_archcpu(env))) { | ||
83 | /* | ||
84 | * Set MTE_ACTIVE if any access may be Checked, and leave clear | ||
85 | diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c | ||
86 | index XXXXXXX..XXXXXXX 100644 | ||
87 | --- a/target/arm/tcg/translate-a64.c | ||
88 | +++ b/target/arm/tcg/translate-a64.c | ||
89 | @@ -XXX,XX +XXX,XX @@ static bool trans_ERET(DisasContext *s, arg_ERET *a) | ||
90 | if (s->current_el == 0) { | ||
91 | return false; | ||
92 | } | ||
93 | - if (s->fgt_eret) { | ||
94 | + if (s->trap_eret) { | ||
95 | gen_exception_insn_el(s, 0, EXCP_UDEF, syn_erettrap(0), 2); | ||
96 | return true; | ||
97 | } | ||
98 | @@ -XXX,XX +XXX,XX @@ static bool trans_ERETA(DisasContext *s, arg_reta *a) | ||
99 | return false; | ||
100 | } | ||
101 | /* The FGT trap takes precedence over an auth trap. */ | ||
102 | - if (s->fgt_eret) { | ||
103 | + if (s->trap_eret) { | ||
104 | gen_exception_insn_el(s, 0, EXCP_UDEF, syn_erettrap(a->m ? 3 : 2), 2); | ||
105 | return true; | ||
106 | } | ||
107 | @@ -XXX,XX +XXX,XX @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, | ||
108 | dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL); | ||
109 | dc->fgt_active = EX_TBFLAG_ANY(tb_flags, FGT_ACTIVE); | ||
110 | dc->fgt_svc = EX_TBFLAG_ANY(tb_flags, FGT_SVC); | ||
111 | - dc->fgt_eret = EX_TBFLAG_A64(tb_flags, FGT_ERET); | ||
112 | + dc->trap_eret = EX_TBFLAG_A64(tb_flags, TRAP_ERET); | ||
113 | dc->sve_excp_el = EX_TBFLAG_A64(tb_flags, SVEEXC_EL); | ||
114 | dc->sme_excp_el = EX_TBFLAG_A64(tb_flags, SMEEXC_EL); | ||
115 | dc->vl = (EX_TBFLAG_A64(tb_flags, VL) + 1) * 16; | ||
116 | -- | 55 | -- |
117 | 2.34.1 | 56 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | The use_first_nan field in float_status was an xtensa-specific way to | ||
2 | select at runtime from two different NaN propagation rules. Now that | ||
3 | xtensa is using the target-agnostic NaN propagation rule selection | ||
4 | that we've just added, we can remove use_first_nan, because there is | ||
5 | no longer any code that reads it. | ||
1 | 6 | ||
7 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
8 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
9 | Message-id: 20241202131347.498124-27-peter.maydell@linaro.org | ||
10 | --- | ||
11 | include/fpu/softfloat-helpers.h | 5 ----- | ||
12 | include/fpu/softfloat-types.h | 1 - | ||
13 | target/xtensa/fpu_helper.c | 1 - | ||
14 | 3 files changed, 7 deletions(-) | ||
15 | |||
16 | diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/include/fpu/softfloat-helpers.h | ||
19 | +++ b/include/fpu/softfloat-helpers.h | ||
20 | @@ -XXX,XX +XXX,XX @@ static inline void set_snan_bit_is_one(bool val, float_status *status) | ||
21 | status->snan_bit_is_one = val; | ||
22 | } | ||
23 | |||
24 | -static inline void set_use_first_nan(bool val, float_status *status) | ||
25 | -{ | ||
26 | - status->use_first_nan = val; | ||
27 | -} | ||
28 | - | ||
29 | static inline void set_no_signaling_nans(bool val, float_status *status) | ||
30 | { | ||
31 | status->no_signaling_nans = val; | ||
32 | diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h | ||
33 | index XXXXXXX..XXXXXXX 100644 | ||
34 | --- a/include/fpu/softfloat-types.h | ||
35 | +++ b/include/fpu/softfloat-types.h | ||
36 | @@ -XXX,XX +XXX,XX @@ typedef struct float_status { | ||
37 | * softfloat-specialize.inc.c) | ||
38 | */ | ||
39 | bool snan_bit_is_one; | ||
40 | - bool use_first_nan; | ||
41 | bool no_signaling_nans; | ||
42 | /* should overflowed results subtract re_bias to its exponent? */ | ||
43 | bool rebias_overflow; | ||
44 | diff --git a/target/xtensa/fpu_helper.c b/target/xtensa/fpu_helper.c | ||
45 | index XXXXXXX..XXXXXXX 100644 | ||
46 | --- a/target/xtensa/fpu_helper.c | ||
47 | +++ b/target/xtensa/fpu_helper.c | ||
48 | @@ -XXX,XX +XXX,XX @@ static const struct { | ||
49 | |||
50 | void xtensa_use_first_nan(CPUXtensaState *env, bool use_first) | ||
51 | { | ||
52 | - set_use_first_nan(use_first, &env->fp_status); | ||
53 | set_float_2nan_prop_rule(use_first ? float_2nan_prop_ab : float_2nan_prop_ba, | ||
54 | &env->fp_status); | ||
55 | set_float_3nan_prop_rule(use_first ? float_3nan_prop_abc : float_3nan_prop_cba, | ||
56 | -- | ||
57 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Currently m68k_cpu_reset_hold() calls floatx80_default_nan(NULL) | ||
2 | to get the NaN bit pattern to reset the FPU registers. This | ||
3 | works because it happens that our implementation of | ||
4 | floatx80_default_nan() doesn't actually look at the float_status | ||
5 | pointer except for TARGET_MIPS. However, this isn't guaranteed, | ||
6 | and to be able to remove the ifdef in floatx80_default_nan() | ||
7 | we're going to need a real float_status here. | ||
1 | 8 | ||
9 | Rearrange m68k_cpu_reset_hold() so that we initialize env->fp_status | ||
10 | earlier, and thus can pass it to floatx80_default_nan(). | ||
11 | |||
12 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
13 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
14 | Message-id: 20241202131347.498124-28-peter.maydell@linaro.org | ||
15 | --- | ||
16 | target/m68k/cpu.c | 12 +++++++----- | ||
17 | 1 file changed, 7 insertions(+), 5 deletions(-) | ||
18 | |||
19 | diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c | ||
20 | index XXXXXXX..XXXXXXX 100644 | ||
21 | --- a/target/m68k/cpu.c | ||
22 | +++ b/target/m68k/cpu.c | ||
23 | @@ -XXX,XX +XXX,XX @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type) | ||
24 | CPUState *cs = CPU(obj); | ||
25 | M68kCPUClass *mcc = M68K_CPU_GET_CLASS(obj); | ||
26 | CPUM68KState *env = cpu_env(cs); | ||
27 | - floatx80 nan = floatx80_default_nan(NULL); | ||
28 | + floatx80 nan; | ||
29 | int i; | ||
30 | |||
31 | if (mcc->parent_phases.hold) { | ||
32 | @@ -XXX,XX +XXX,XX @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type) | ||
33 | #else | ||
34 | cpu_m68k_set_sr(env, SR_S | SR_I); | ||
35 | #endif | ||
36 | - for (i = 0; i < 8; i++) { | ||
37 | - env->fregs[i].d = nan; | ||
38 | - } | ||
39 | - cpu_m68k_set_fpcr(env, 0); | ||
40 | /* | ||
41 | * M68000 FAMILY PROGRAMMER'S REFERENCE MANUAL | ||
42 | * 3.4 FLOATING-POINT INSTRUCTION DETAILS | ||
43 | @@ -XXX,XX +XXX,XX @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type) | ||
44 | * preceding paragraph for nonsignaling NaNs. | ||
45 | */ | ||
46 | set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status); | ||
47 | + | ||
48 | + nan = floatx80_default_nan(&env->fp_status); | ||
49 | + for (i = 0; i < 8; i++) { | ||
50 | + env->fregs[i].d = nan; | ||
51 | + } | ||
52 | + cpu_m68k_set_fpcr(env, 0); | ||
53 | env->fpsr = 0; | ||
54 | |||
55 | /* TODO: We should set PC from the interrupt vector. */ | ||
56 | -- | ||
57 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | We create our 128-bit default NaN by calling parts64_default_nan() | ||
2 | and then adjusting the result. We can do the same trick for creating | ||
3 | the floatx80 default NaN, which lets us drop a target ifdef. | ||
1 | 4 | ||
5 | floatx80 is used only by: | ||
6 | i386 | ||
7 | m68k | ||
8 | arm nwfpe old floating-point emulation emulation support | ||
9 | (which is essentially dead, especially the parts involving floatx80) | ||
10 | PPC (only in the xsrqpxp instruction, which just rounds an input | ||
11 | value by converting to floatx80 and back, so will never generate | ||
12 | the default NaN) | ||
13 | |||
14 | The floatx80 default NaN as currently implemented is: | ||
15 | m68k: sign = 0, exp = 1...1, int = 1, frac = 1....1 | ||
16 | i386: sign = 1, exp = 1...1, int = 1, frac = 10...0 | ||
17 | |||
18 | These are the same as the parts64_default_nan for these architectures. | ||
19 | |||
20 | This is technically a possible behaviour change for arm linux-user | ||
21 | nwfpe emulation emulation, because the default NaN will now have the | ||
22 | sign bit clear. But we were already generating a different floatx80 | ||
23 | default NaN from the real kernel emulation we are supposedly | ||
24 | following, which appears to use an all-bits-1 value: | ||
25 | https://elixir.bootlin.com/linux/v6.12/source/arch/arm/nwfpe/softfloat-specialize#L267 | ||
26 | |||
27 | This won't affect the only "real" use of the nwfpe emulation, which | ||
28 | is ancient binaries that used it as part of the old floating point | ||
29 | calling convention; that only uses loads and stores of 32 and 64 bit | ||
30 | floats, not any of the floatx80 behaviour the original hardware had. | ||
31 | We also get the nwfpe float64 default NaN value wrong: | ||
32 | https://elixir.bootlin.com/linux/v6.12/source/arch/arm/nwfpe/softfloat-specialize#L166 | ||
33 | so if we ever cared about this obscure corner the right fix would be | ||
34 | to correct that so nwfpe used its own default-NaN setting rather | ||
35 | than the Arm VFP one. | ||
36 | |||
37 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
38 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
39 | Message-id: 20241202131347.498124-29-peter.maydell@linaro.org | ||
40 | --- | ||
41 | fpu/softfloat-specialize.c.inc | 20 ++++++++++---------- | ||
42 | 1 file changed, 10 insertions(+), 10 deletions(-) | ||
43 | |||
44 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc | ||
45 | index XXXXXXX..XXXXXXX 100644 | ||
46 | --- a/fpu/softfloat-specialize.c.inc | ||
47 | +++ b/fpu/softfloat-specialize.c.inc | ||
48 | @@ -XXX,XX +XXX,XX @@ static void parts128_silence_nan(FloatParts128 *p, float_status *status) | ||
49 | floatx80 floatx80_default_nan(float_status *status) | ||
50 | { | ||
51 | floatx80 r; | ||
52 | + /* | ||
53 | + * Extrapolate from the choices made by parts64_default_nan to fill | ||
54 | + * in the floatx80 format. We assume that floatx80's explicit | ||
55 | + * integer bit is always set (this is true for i386 and m68k, | ||
56 | + * which are the only real users of this format). | ||
57 | + */ | ||
58 | + FloatParts64 p64; | ||
59 | + parts64_default_nan(&p64, status); | ||
60 | |||
61 | - /* None of the targets that have snan_bit_is_one use floatx80. */ | ||
62 | - assert(!snan_bit_is_one(status)); | ||
63 | -#if defined(TARGET_M68K) | ||
64 | - r.low = UINT64_C(0xFFFFFFFFFFFFFFFF); | ||
65 | - r.high = 0x7FFF; | ||
66 | -#else | ||
67 | - /* X86 */ | ||
68 | - r.low = UINT64_C(0xC000000000000000); | ||
69 | - r.high = 0xFFFF; | ||
70 | -#endif | ||
71 | + r.high = 0x7FFF | (p64.sign << 15); | ||
72 | + r.low = (1ULL << DECOMPOSED_BINARY_POINT) | p64.frac; | ||
73 | return r; | ||
74 | } | ||
75 | |||
76 | -- | ||
77 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | In target/loongarch's helper_fclass_s() and helper_fclass_d() we pass | ||
2 | a zero-initialized float_status struct to float32_is_quiet_nan() and | ||
3 | float64_is_quiet_nan(), with the cryptic comment "for | ||
4 | snan_bit_is_one". | ||
1 | 5 | ||
6 | This pattern appears to have been copied from target/riscv, where it | ||
7 | is used because the functions there do not have ready access to the | ||
8 | CPU state struct. The comment presumably refers to the fact that the | ||
9 | main reason the is_quiet_nan() functions want the float_state is | ||
10 | because they want to know about the snan_bit_is_one config. | ||
11 | |||
12 | In the loongarch helpers, though, we have the CPU state struct | ||
13 | to hand. Use the usual env->fp_status here. This avoids our needing | ||
14 | to track that we need to update the initializer of the local | ||
15 | float_status structs when the core softfloat code adds new | ||
16 | options for targets to configure their behaviour. | ||
17 | |||
18 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
19 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
20 | Message-id: 20241202131347.498124-30-peter.maydell@linaro.org | ||
21 | --- | ||
22 | target/loongarch/tcg/fpu_helper.c | 6 ++---- | ||
23 | 1 file changed, 2 insertions(+), 4 deletions(-) | ||
24 | |||
25 | diff --git a/target/loongarch/tcg/fpu_helper.c b/target/loongarch/tcg/fpu_helper.c | ||
26 | index XXXXXXX..XXXXXXX 100644 | ||
27 | --- a/target/loongarch/tcg/fpu_helper.c | ||
28 | +++ b/target/loongarch/tcg/fpu_helper.c | ||
29 | @@ -XXX,XX +XXX,XX @@ uint64_t helper_fclass_s(CPULoongArchState *env, uint64_t fj) | ||
30 | } else if (float32_is_zero_or_denormal(f)) { | ||
31 | return sign ? 1 << 4 : 1 << 8; | ||
32 | } else if (float32_is_any_nan(f)) { | ||
33 | - float_status s = { }; /* for snan_bit_is_one */ | ||
34 | - return float32_is_quiet_nan(f, &s) ? 1 << 1 : 1 << 0; | ||
35 | + return float32_is_quiet_nan(f, &env->fp_status) ? 1 << 1 : 1 << 0; | ||
36 | } else { | ||
37 | return sign ? 1 << 3 : 1 << 7; | ||
38 | } | ||
39 | @@ -XXX,XX +XXX,XX @@ uint64_t helper_fclass_d(CPULoongArchState *env, uint64_t fj) | ||
40 | } else if (float64_is_zero_or_denormal(f)) { | ||
41 | return sign ? 1 << 4 : 1 << 8; | ||
42 | } else if (float64_is_any_nan(f)) { | ||
43 | - float_status s = { }; /* for snan_bit_is_one */ | ||
44 | - return float64_is_quiet_nan(f, &s) ? 1 << 1 : 1 << 0; | ||
45 | + return float64_is_quiet_nan(f, &env->fp_status) ? 1 << 1 : 1 << 0; | ||
46 | } else { | ||
47 | return sign ? 1 << 3 : 1 << 7; | ||
48 | } | ||
49 | -- | ||
50 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | In the frem helper, we have a local float_status because we want to | ||
2 | execute the floatx80_div() with a custom rounding mode. Instead of | ||
3 | zero-initializing the local float_status and then having to set it up | ||
4 | with the m68k standard behaviour (including the NaN propagation rule | ||
5 | and copying the rounding precision from env->fp_status), initialize | ||
6 | it as a complete copy of env->fp_status. This will avoid our having | ||
7 | to add new code in this function for every new config knob we add | ||
8 | to fp_status. | ||
1 | 9 | ||
10 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
11 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
12 | Message-id: 20241202131347.498124-31-peter.maydell@linaro.org | ||
13 | --- | ||
14 | target/m68k/fpu_helper.c | 6 ++---- | ||
15 | 1 file changed, 2 insertions(+), 4 deletions(-) | ||
16 | |||
17 | diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/target/m68k/fpu_helper.c | ||
20 | +++ b/target/m68k/fpu_helper.c | ||
21 | @@ -XXX,XX +XXX,XX @@ void HELPER(frem)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) | ||
22 | |||
23 | fp_rem = floatx80_rem(val1->d, val0->d, &env->fp_status); | ||
24 | if (!floatx80_is_any_nan(fp_rem)) { | ||
25 | - float_status fp_status = { }; | ||
26 | + /* Use local temporary fp_status to set different rounding mode */ | ||
27 | + float_status fp_status = env->fp_status; | ||
28 | uint32_t quotient; | ||
29 | int sign; | ||
30 | |||
31 | /* Calculate quotient directly using round to nearest mode */ | ||
32 | - set_float_2nan_prop_rule(float_2nan_prop_ab, &fp_status); | ||
33 | set_float_rounding_mode(float_round_nearest_even, &fp_status); | ||
34 | - set_floatx80_rounding_precision( | ||
35 | - get_floatx80_rounding_precision(&env->fp_status), &fp_status); | ||
36 | fp_quot.d = floatx80_div(val1->d, val0->d, &fp_status); | ||
37 | |||
38 | sign = extractFloatx80Sign(fp_quot.d); | ||
39 | -- | ||
40 | 2.34.1 | diff view generated by jsdifflib |
1 | FEAT_NV requires (per I_JKLJK) that when HCR_EL2.{NV,NV1} is {1,1} the | 1 | In cf_fpu_gdb_get_reg() and cf_fpu_gdb_set_reg() we do the conversion |
---|---|---|---|
2 | unprivileged-access instructions LDTR, STTR etc behave as normal | 2 | from float64 to floatx80 using a scratch float_status, because we |
3 | loads and stores. Implement the check that handles this. | 3 | don't want the conversion to affect the CPU's floating point exception |
4 | status. Currently we use a zero-initialized float_status. This will | ||
5 | get steadily more awkward as we add config knobs to float_status | ||
6 | that the target must initialize. Avoid having to add any of that | ||
7 | configuration here by instead initializing our local float_status | ||
8 | from the env->fp_status. | ||
4 | 9 | ||
5 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 10 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
6 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 11 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
7 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 12 | Message-id: 20241202131347.498124-32-peter.maydell@linaro.org |
8 | --- | 13 | --- |
9 | target/arm/tcg/hflags.c | 6 ++++-- | 14 | target/m68k/helper.c | 6 ++++-- |
10 | 1 file changed, 4 insertions(+), 2 deletions(-) | 15 | 1 file changed, 4 insertions(+), 2 deletions(-) |
11 | 16 | ||
12 | diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c | 17 | diff --git a/target/m68k/helper.c b/target/m68k/helper.c |
13 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/target/arm/tcg/hflags.c | 19 | --- a/target/m68k/helper.c |
15 | +++ b/target/arm/tcg/hflags.c | 20 | +++ b/target/m68k/helper.c |
16 | @@ -XXX,XX +XXX,XX @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, | 21 | @@ -XXX,XX +XXX,XX @@ static int cf_fpu_gdb_get_reg(CPUState *cs, GByteArray *mem_buf, int n) |
17 | switch (mmu_idx) { | 22 | CPUM68KState *env = &cpu->env; |
18 | case ARMMMUIdx_E10_1: | 23 | |
19 | case ARMMMUIdx_E10_1_PAN: | 24 | if (n < 8) { |
20 | - /* TODO: ARMv8.3-NV */ | 25 | - float_status s = {}; |
21 | - DP_TBFLAG_A64(flags, UNPRIV, 1); | 26 | + /* Use scratch float_status so any exceptions don't change CPU state */ |
22 | + /* FEAT_NV: NV,NV1 == 1,1 means we don't do UNPRIV accesses */ | 27 | + float_status s = env->fp_status; |
23 | + if ((hcr & (HCR_NV | HCR_NV1)) != (HCR_NV | HCR_NV1)) { | 28 | return gdb_get_reg64(mem_buf, floatx80_to_float64(env->fregs[n].d, &s)); |
24 | + DP_TBFLAG_A64(flags, UNPRIV, 1); | 29 | } |
25 | + } | 30 | switch (n) { |
26 | break; | 31 | @@ -XXX,XX +XXX,XX @@ static int cf_fpu_gdb_set_reg(CPUState *cs, uint8_t *mem_buf, int n) |
27 | case ARMMMUIdx_E20_2: | 32 | CPUM68KState *env = &cpu->env; |
28 | case ARMMMUIdx_E20_2_PAN: | 33 | |
34 | if (n < 8) { | ||
35 | - float_status s = {}; | ||
36 | + /* Use scratch float_status so any exceptions don't change CPU state */ | ||
37 | + float_status s = env->fp_status; | ||
38 | env->fregs[n].d = float64_to_floatx80(ldq_be_p(mem_buf), &s); | ||
39 | return 8; | ||
40 | } | ||
29 | -- | 41 | -- |
30 | 2.34.1 | 42 | 2.34.1 | diff view generated by jsdifflib |
1 | When HCR_EL2.{NV,NV1} is {1,1} we must trap five extra registers to | 1 | In the helper functions flcmps and flcmpd we use a scratch float_status |
---|---|---|---|
2 | EL2: VBAR_EL1, ELR_EL1, SPSR_EL1, SCXTNUM_EL1 and TFSR_EL1. | 2 | so that we don't change the CPU state if the comparison raises any |
3 | Implement these traps. | 3 | floating point exception flags. Instead of zero-initializing this |
4 | scratch float_status, initialize it as a copy of env->fp_status. This | ||
5 | avoids the need to explicitly initialize settings like the NaN | ||
6 | propagation rule or others we might add to softfloat in future. | ||
4 | 7 | ||
5 | This trap does not apply when FEAT_NV2 is implemented and enabled; | 8 | To do this we need to pass the CPU env pointer in to the helper. |
6 | include the check that HCR_EL2.NV2 is 0 here, to save us having | ||
7 | to come back and add it later. | ||
8 | 9 | ||
9 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 10 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
10 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 11 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
11 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 12 | Message-id: 20241202131347.498124-33-peter.maydell@linaro.org |
12 | --- | 13 | --- |
13 | target/arm/helper.c | 45 +++++++++++++++++++++++++++++++++++++++++---- | 14 | target/sparc/helper.h | 4 ++-- |
14 | 1 file changed, 41 insertions(+), 4 deletions(-) | 15 | target/sparc/fop_helper.c | 8 ++++---- |
16 | target/sparc/translate.c | 4 ++-- | ||
17 | 3 files changed, 8 insertions(+), 8 deletions(-) | ||
15 | 18 | ||
16 | diff --git a/target/arm/helper.c b/target/arm/helper.c | 19 | diff --git a/target/sparc/helper.h b/target/sparc/helper.h |
17 | index XXXXXXX..XXXXXXX 100644 | 20 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/target/arm/helper.c | 21 | --- a/target/sparc/helper.h |
19 | +++ b/target/arm/helper.c | 22 | +++ b/target/sparc/helper.h |
20 | @@ -XXX,XX +XXX,XX @@ static void mdcr_el2_write(CPUARMState *env, const ARMCPRegInfo *ri, | 23 | @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_3(fcmpd, TCG_CALL_NO_WG, i32, env, f64, f64) |
21 | } | 24 | DEF_HELPER_FLAGS_3(fcmped, TCG_CALL_NO_WG, i32, env, f64, f64) |
25 | DEF_HELPER_FLAGS_3(fcmpq, TCG_CALL_NO_WG, i32, env, i128, i128) | ||
26 | DEF_HELPER_FLAGS_3(fcmpeq, TCG_CALL_NO_WG, i32, env, i128, i128) | ||
27 | -DEF_HELPER_FLAGS_2(flcmps, TCG_CALL_NO_RWG_SE, i32, f32, f32) | ||
28 | -DEF_HELPER_FLAGS_2(flcmpd, TCG_CALL_NO_RWG_SE, i32, f64, f64) | ||
29 | +DEF_HELPER_FLAGS_3(flcmps, TCG_CALL_NO_RWG_SE, i32, env, f32, f32) | ||
30 | +DEF_HELPER_FLAGS_3(flcmpd, TCG_CALL_NO_RWG_SE, i32, env, f64, f64) | ||
31 | DEF_HELPER_2(raise_exception, noreturn, env, int) | ||
32 | |||
33 | DEF_HELPER_FLAGS_3(faddd, TCG_CALL_NO_WG, f64, env, f64, f64) | ||
34 | diff --git a/target/sparc/fop_helper.c b/target/sparc/fop_helper.c | ||
35 | index XXXXXXX..XXXXXXX 100644 | ||
36 | --- a/target/sparc/fop_helper.c | ||
37 | +++ b/target/sparc/fop_helper.c | ||
38 | @@ -XXX,XX +XXX,XX @@ uint32_t helper_fcmpeq(CPUSPARCState *env, Int128 src1, Int128 src2) | ||
39 | return finish_fcmp(env, r, GETPC()); | ||
22 | } | 40 | } |
23 | 41 | ||
24 | +static CPAccessResult access_nv1(CPUARMState *env, const ARMCPRegInfo *ri, | 42 | -uint32_t helper_flcmps(float32 src1, float32 src2) |
25 | + bool isread) | 43 | +uint32_t helper_flcmps(CPUSPARCState *env, float32 src1, float32 src2) |
26 | +{ | 44 | { |
27 | + if (arm_current_el(env) == 1) { | ||
28 | + uint64_t hcr_nv = arm_hcr_el2_eff(env) & (HCR_NV | HCR_NV1 | HCR_NV2); | ||
29 | + | ||
30 | + if (hcr_nv == (HCR_NV | HCR_NV1)) { | ||
31 | + return CP_ACCESS_TRAP_EL2; | ||
32 | + } | ||
33 | + } | ||
34 | + return CP_ACCESS_OK; | ||
35 | +} | ||
36 | + | ||
37 | #ifdef CONFIG_USER_ONLY | ||
38 | /* | ||
39 | * `IC IVAU` is handled to improve compatibility with JITs that dual-map their | ||
40 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo v8_cp_reginfo[] = { | ||
41 | { .name = "ELR_EL1", .state = ARM_CP_STATE_AA64, | ||
42 | .type = ARM_CP_ALIAS, | ||
43 | .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 1, | ||
44 | - .access = PL1_RW, | ||
45 | + .access = PL1_RW, .accessfn = access_nv1, | ||
46 | .fieldoffset = offsetof(CPUARMState, elr_el[1]) }, | ||
47 | { .name = "SPSR_EL1", .state = ARM_CP_STATE_AA64, | ||
48 | .type = ARM_CP_ALIAS, | ||
49 | .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 0, | ||
50 | - .access = PL1_RW, | ||
51 | + .access = PL1_RW, .accessfn = access_nv1, | ||
52 | .fieldoffset = offsetof(CPUARMState, banked_spsr[BANK_SVC]) }, | ||
53 | /* | 45 | /* |
54 | * We rely on the access checks not allowing the guest to write to the | 46 | * FLCMP never raises an exception nor modifies any FSR fields. |
55 | @@ -XXX,XX +XXX,XX @@ static CPAccessResult access_mte(CPUARMState *env, const ARMCPRegInfo *ri, | 47 | * Perform the comparison with a dummy fp environment. |
56 | return CP_ACCESS_OK; | 48 | */ |
49 | - float_status discard = { }; | ||
50 | + float_status discard = env->fp_status; | ||
51 | FloatRelation r; | ||
52 | |||
53 | set_float_2nan_prop_rule(float_2nan_prop_s_ba, &discard); | ||
54 | @@ -XXX,XX +XXX,XX @@ uint32_t helper_flcmps(float32 src1, float32 src2) | ||
55 | g_assert_not_reached(); | ||
57 | } | 56 | } |
58 | 57 | ||
59 | +static CPAccessResult access_tfsr_el1(CPUARMState *env, const ARMCPRegInfo *ri, | 58 | -uint32_t helper_flcmpd(float64 src1, float64 src2) |
60 | + bool isread) | 59 | +uint32_t helper_flcmpd(CPUSPARCState *env, float64 src1, float64 src2) |
61 | +{ | ||
62 | + CPAccessResult nv1 = access_nv1(env, ri, isread); | ||
63 | + | ||
64 | + if (nv1 != CP_ACCESS_OK) { | ||
65 | + return nv1; | ||
66 | + } | ||
67 | + return access_mte(env, ri, isread); | ||
68 | +} | ||
69 | + | ||
70 | static CPAccessResult access_tfsr_el2(CPUARMState *env, const ARMCPRegInfo *ri, | ||
71 | bool isread) | ||
72 | { | 60 | { |
73 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo mte_reginfo[] = { | 61 | - float_status discard = { }; |
74 | .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[0]) }, | 62 | + float_status discard = env->fp_status; |
75 | { .name = "TFSR_EL1", .state = ARM_CP_STATE_AA64, | 63 | FloatRelation r; |
76 | .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 6, .opc2 = 0, | 64 | |
77 | - .access = PL1_RW, .accessfn = access_mte, | 65 | set_float_2nan_prop_rule(float_2nan_prop_s_ba, &discard); |
78 | + .access = PL1_RW, .accessfn = access_tfsr_el1, | 66 | diff --git a/target/sparc/translate.c b/target/sparc/translate.c |
79 | .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[1]) }, | 67 | index XXXXXXX..XXXXXXX 100644 |
80 | { .name = "TFSR_EL2", .state = ARM_CP_STATE_AA64, | 68 | --- a/target/sparc/translate.c |
81 | .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 6, .opc2 = 0, | 69 | +++ b/target/sparc/translate.c |
82 | @@ -XXX,XX +XXX,XX @@ static CPAccessResult access_scxtnum(CPUARMState *env, const ARMCPRegInfo *ri, | 70 | @@ -XXX,XX +XXX,XX @@ static bool trans_FLCMPs(DisasContext *dc, arg_FLCMPs *a) |
83 | return CP_ACCESS_OK; | 71 | |
72 | src1 = gen_load_fpr_F(dc, a->rs1); | ||
73 | src2 = gen_load_fpr_F(dc, a->rs2); | ||
74 | - gen_helper_flcmps(cpu_fcc[a->cc], src1, src2); | ||
75 | + gen_helper_flcmps(cpu_fcc[a->cc], tcg_env, src1, src2); | ||
76 | return advance_pc(dc); | ||
84 | } | 77 | } |
85 | 78 | ||
86 | +static CPAccessResult access_scxtnum_el1(CPUARMState *env, | 79 | @@ -XXX,XX +XXX,XX @@ static bool trans_FLCMPd(DisasContext *dc, arg_FLCMPd *a) |
87 | + const ARMCPRegInfo *ri, | 80 | |
88 | + bool isread) | 81 | src1 = gen_load_fpr_D(dc, a->rs1); |
89 | +{ | 82 | src2 = gen_load_fpr_D(dc, a->rs2); |
90 | + CPAccessResult nv1 = access_nv1(env, ri, isread); | 83 | - gen_helper_flcmpd(cpu_fcc[a->cc], src1, src2); |
91 | + | 84 | + gen_helper_flcmpd(cpu_fcc[a->cc], tcg_env, src1, src2); |
92 | + if (nv1 != CP_ACCESS_OK) { | 85 | return advance_pc(dc); |
93 | + return nv1; | 86 | } |
94 | + } | 87 | |
95 | + return access_scxtnum(env, ri, isread); | ||
96 | +} | ||
97 | + | ||
98 | static const ARMCPRegInfo scxtnum_reginfo[] = { | ||
99 | { .name = "SCXTNUM_EL0", .state = ARM_CP_STATE_AA64, | ||
100 | .opc0 = 3, .opc1 = 3, .crn = 13, .crm = 0, .opc2 = 7, | ||
101 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo scxtnum_reginfo[] = { | ||
102 | .fieldoffset = offsetof(CPUARMState, scxtnum_el[0]) }, | ||
103 | { .name = "SCXTNUM_EL1", .state = ARM_CP_STATE_AA64, | ||
104 | .opc0 = 3, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 7, | ||
105 | - .access = PL1_RW, .accessfn = access_scxtnum, | ||
106 | + .access = PL1_RW, .accessfn = access_scxtnum_el1, | ||
107 | .fgt = FGT_SCXTNUM_EL1, | ||
108 | .fieldoffset = offsetof(CPUARMState, scxtnum_el[1]) }, | ||
109 | { .name = "SCXTNUM_EL2", .state = ARM_CP_STATE_AA64, | ||
110 | @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) | ||
111 | { .name = "VBAR", .state = ARM_CP_STATE_BOTH, | ||
112 | .opc0 = 3, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0, | ||
113 | .access = PL1_RW, .writefn = vbar_write, | ||
114 | + .accessfn = access_nv1, | ||
115 | .fgt = FGT_VBAR_EL1, | ||
116 | .bank_fieldoffsets = { offsetof(CPUARMState, cp15.vbar_s), | ||
117 | offsetof(CPUARMState, cp15.vbar_ns) }, | ||
118 | -- | 88 | -- |
119 | 2.34.1 | 89 | 2.34.1 | diff view generated by jsdifflib |
1 | Mark up the cpreginfo structs for the GIC CPU registers to indicate | 1 | In the helper_compute_fprf functions, we pass a dummy float_status |
---|---|---|---|
2 | the offsets from VNCR_EL2, as defined in table D8-66 in rule R_CSRPQ | 2 | in to the is_signaling_nan() function. This is unnecessary, because |
3 | in the Arm ARM. | 3 | we have convenient access to the CPU env pointer here and that |
4 | is already set up with the correct values for the snan_bit_is_one | ||
5 | and no_signaling_nans config settings. is_signaling_nan() doesn't | ||
6 | ever update the fp_status with any exception flags, so there is | ||
7 | no reason not to use env->fp_status here. | ||
8 | |||
9 | Use env->fp_status instead of the dummy fp_status. | ||
4 | 10 | ||
5 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 11 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
6 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 12 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
7 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 13 | Message-id: 20241202131347.498124-34-peter.maydell@linaro.org |
8 | --- | 14 | --- |
9 | hw/intc/arm_gicv3_cpuif.c | 11 +++++++++++ | 15 | target/ppc/fpu_helper.c | 3 +-- |
10 | 1 file changed, 11 insertions(+) | 16 | 1 file changed, 1 insertion(+), 2 deletions(-) |
11 | 17 | ||
12 | diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c | 18 | diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c |
13 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/hw/intc/arm_gicv3_cpuif.c | 20 | --- a/target/ppc/fpu_helper.c |
15 | +++ b/hw/intc/arm_gicv3_cpuif.c | 21 | +++ b/target/ppc/fpu_helper.c |
16 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo gicv3_cpuif_hcr_reginfo[] = { | 22 | @@ -XXX,XX +XXX,XX @@ void helper_compute_fprf_##tp(CPUPPCState *env, tp arg) \ |
17 | { .name = "ICH_AP0R0_EL2", .state = ARM_CP_STATE_BOTH, | 23 | } else if (tp##_is_infinity(arg)) { \ |
18 | .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 8, .opc2 = 0, | 24 | fprf = neg ? 0x09 << FPSCR_FPRF : 0x05 << FPSCR_FPRF; \ |
19 | .type = ARM_CP_IO | ARM_CP_NO_RAW, | 25 | } else { \ |
20 | + .nv2_redirect_offset = 0x480, | 26 | - float_status dummy = { }; /* snan_bit_is_one = 0 */ \ |
21 | .access = PL2_RW, | 27 | - if (tp##_is_signaling_nan(arg, &dummy)) { \ |
22 | .readfn = ich_ap_read, | 28 | + if (tp##_is_signaling_nan(arg, &env->fp_status)) { \ |
23 | .writefn = ich_ap_write, | 29 | fprf = 0x00 << FPSCR_FPRF; \ |
24 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo gicv3_cpuif_hcr_reginfo[] = { | 30 | } else { \ |
25 | { .name = "ICH_AP1R0_EL2", .state = ARM_CP_STATE_BOTH, | 31 | fprf = 0x11 << FPSCR_FPRF; \ |
26 | .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 0, | ||
27 | .type = ARM_CP_IO | ARM_CP_NO_RAW, | ||
28 | + .nv2_redirect_offset = 0x4a0, | ||
29 | .access = PL2_RW, | ||
30 | .readfn = ich_ap_read, | ||
31 | .writefn = ich_ap_write, | ||
32 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo gicv3_cpuif_hcr_reginfo[] = { | ||
33 | { .name = "ICH_HCR_EL2", .state = ARM_CP_STATE_BOTH, | ||
34 | .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 11, .opc2 = 0, | ||
35 | .type = ARM_CP_IO | ARM_CP_NO_RAW, | ||
36 | + .nv2_redirect_offset = 0x4c0, | ||
37 | .access = PL2_RW, | ||
38 | .readfn = ich_hcr_read, | ||
39 | .writefn = ich_hcr_write, | ||
40 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo gicv3_cpuif_hcr_reginfo[] = { | ||
41 | { .name = "ICH_VMCR_EL2", .state = ARM_CP_STATE_BOTH, | ||
42 | .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 11, .opc2 = 7, | ||
43 | .type = ARM_CP_IO | ARM_CP_NO_RAW, | ||
44 | + .nv2_redirect_offset = 0x4c8, | ||
45 | .access = PL2_RW, | ||
46 | .readfn = ich_vmcr_read, | ||
47 | .writefn = ich_vmcr_write, | ||
48 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr1_reginfo[] = { | ||
49 | { .name = "ICH_AP0R1_EL2", .state = ARM_CP_STATE_BOTH, | ||
50 | .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 8, .opc2 = 1, | ||
51 | .type = ARM_CP_IO | ARM_CP_NO_RAW, | ||
52 | + .nv2_redirect_offset = 0x488, | ||
53 | .access = PL2_RW, | ||
54 | .readfn = ich_ap_read, | ||
55 | .writefn = ich_ap_write, | ||
56 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr1_reginfo[] = { | ||
57 | { .name = "ICH_AP1R1_EL2", .state = ARM_CP_STATE_BOTH, | ||
58 | .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 1, | ||
59 | .type = ARM_CP_IO | ARM_CP_NO_RAW, | ||
60 | + .nv2_redirect_offset = 0x4a8, | ||
61 | .access = PL2_RW, | ||
62 | .readfn = ich_ap_read, | ||
63 | .writefn = ich_ap_write, | ||
64 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr23_reginfo[] = { | ||
65 | { .name = "ICH_AP0R2_EL2", .state = ARM_CP_STATE_BOTH, | ||
66 | .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 8, .opc2 = 2, | ||
67 | .type = ARM_CP_IO | ARM_CP_NO_RAW, | ||
68 | + .nv2_redirect_offset = 0x490, | ||
69 | .access = PL2_RW, | ||
70 | .readfn = ich_ap_read, | ||
71 | .writefn = ich_ap_write, | ||
72 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr23_reginfo[] = { | ||
73 | { .name = "ICH_AP0R3_EL2", .state = ARM_CP_STATE_BOTH, | ||
74 | .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 8, .opc2 = 3, | ||
75 | .type = ARM_CP_IO | ARM_CP_NO_RAW, | ||
76 | + .nv2_redirect_offset = 0x498, | ||
77 | .access = PL2_RW, | ||
78 | .readfn = ich_ap_read, | ||
79 | .writefn = ich_ap_write, | ||
80 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr23_reginfo[] = { | ||
81 | { .name = "ICH_AP1R2_EL2", .state = ARM_CP_STATE_BOTH, | ||
82 | .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 2, | ||
83 | .type = ARM_CP_IO | ARM_CP_NO_RAW, | ||
84 | + .nv2_redirect_offset = 0x4b0, | ||
85 | .access = PL2_RW, | ||
86 | .readfn = ich_ap_read, | ||
87 | .writefn = ich_ap_write, | ||
88 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr23_reginfo[] = { | ||
89 | { .name = "ICH_AP1R3_EL2", .state = ARM_CP_STATE_BOTH, | ||
90 | .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 3, | ||
91 | .type = ARM_CP_IO | ARM_CP_NO_RAW, | ||
92 | + .nv2_redirect_offset = 0x4b8, | ||
93 | .access = PL2_RW, | ||
94 | .readfn = ich_ap_read, | ||
95 | .writefn = ich_ap_write, | ||
96 | @@ -XXX,XX +XXX,XX @@ void gicv3_init_cpuif(GICv3State *s) | ||
97 | .opc0 = 3, .opc1 = 4, .crn = 12, | ||
98 | .crm = 12 + (j >> 3), .opc2 = j & 7, | ||
99 | .type = ARM_CP_IO | ARM_CP_NO_RAW, | ||
100 | + .nv2_redirect_offset = 0x400 + 8 * j, | ||
101 | .access = PL2_RW, | ||
102 | .readfn = ich_lr_read, | ||
103 | .writefn = ich_lr_write, | ||
104 | -- | 32 | -- |
105 | 2.34.1 | 33 | 2.34.1 | diff view generated by jsdifflib |
1 | From: Philippe Mathieu-Daudé <philmd@linaro.org> | 1 | From: Richard Henderson <richard.henderson@linaro.org> |
---|---|---|---|
2 | 2 | ||
3 | QDev objects created with qdev_new() need to manually add | 3 | Now that float_status has a bunch of fp parameters, |
4 | their parent relationship with object_property_add_child(). | 4 | it is easier to copy an existing structure than create |
5 | one from scratch. Begin by copying the structure that | ||
6 | corresponds to the FPSR and make only the adjustments | ||
7 | required for BFloat16 semantics. | ||
5 | 8 | ||
6 | Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> | 9 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
7 | Reviewed-by: Alistair Francis <alistair.francis@wdc.com> | 10 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> |
8 | Message-id: 20240104141159.53883-1-philmd@linaro.org | 11 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> |
12 | Message-id: 20241203203949.483774-2-richard.henderson@linaro.org | ||
9 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 13 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
10 | --- | 14 | --- |
11 | hw/arm/msf2-som.c | 1 + | 15 | target/arm/tcg/vec_helper.c | 20 +++++++------------- |
12 | hw/arm/netduino2.c | 1 + | 16 | 1 file changed, 7 insertions(+), 13 deletions(-) |
13 | hw/arm/netduinoplus2.c | 1 + | ||
14 | hw/arm/olimex-stm32-h405.c | 1 + | ||
15 | hw/arm/stm32vldiscovery.c | 1 + | ||
16 | 5 files changed, 5 insertions(+) | ||
17 | 17 | ||
18 | diff --git a/hw/arm/msf2-som.c b/hw/arm/msf2-som.c | 18 | diff --git a/target/arm/tcg/vec_helper.c b/target/arm/tcg/vec_helper.c |
19 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
20 | --- a/hw/arm/msf2-som.c | 20 | --- a/target/arm/tcg/vec_helper.c |
21 | +++ b/hw/arm/msf2-som.c | 21 | +++ b/target/arm/tcg/vec_helper.c |
22 | @@ -XXX,XX +XXX,XX @@ static void emcraft_sf2_s2s010_init(MachineState *machine) | 22 | @@ -XXX,XX +XXX,XX @@ bool is_ebf(CPUARMState *env, float_status *statusp, float_status *oddstatusp) |
23 | memory_region_add_subregion(sysmem, DDR_BASE_ADDRESS, ddr); | 23 | * no effect on AArch32 instructions. |
24 | 24 | */ | |
25 | dev = qdev_new(TYPE_MSF2_SOC); | 25 | bool ebf = is_a64(env) && env->vfp.fpcr & FPCR_EBF; |
26 | + object_property_add_child(OBJECT(machine), "soc", OBJECT(dev)); | 26 | - *statusp = (float_status){ |
27 | qdev_prop_set_string(dev, "part-name", "M2S010"); | 27 | - .tininess_before_rounding = float_tininess_before_rounding, |
28 | qdev_prop_set_string(dev, "cpu-type", mc->default_cpu_type); | 28 | - .float_rounding_mode = float_round_to_odd_inf, |
29 | 29 | - .flush_to_zero = true, | |
30 | diff --git a/hw/arm/netduino2.c b/hw/arm/netduino2.c | 30 | - .flush_inputs_to_zero = true, |
31 | index XXXXXXX..XXXXXXX 100644 | 31 | - .default_nan_mode = true, |
32 | --- a/hw/arm/netduino2.c | 32 | - }; |
33 | +++ b/hw/arm/netduino2.c | 33 | + |
34 | @@ -XXX,XX +XXX,XX @@ static void netduino2_init(MachineState *machine) | 34 | + *statusp = env->vfp.fp_status; |
35 | clock_set_hz(sysclk, SYSCLK_FRQ); | 35 | + set_default_nan_mode(true, statusp); |
36 | 36 | ||
37 | dev = qdev_new(TYPE_STM32F205_SOC); | 37 | if (ebf) { |
38 | + object_property_add_child(OBJECT(machine), "soc", OBJECT(dev)); | 38 | - float_status *fpst = &env->vfp.fp_status; |
39 | qdev_connect_clock_in(dev, "sysclk", sysclk); | 39 | - set_flush_to_zero(get_flush_to_zero(fpst), statusp); |
40 | sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); | 40 | - set_flush_inputs_to_zero(get_flush_inputs_to_zero(fpst), statusp); |
41 | 41 | - set_float_rounding_mode(get_float_rounding_mode(fpst), statusp); | |
42 | diff --git a/hw/arm/netduinoplus2.c b/hw/arm/netduinoplus2.c | 42 | - |
43 | index XXXXXXX..XXXXXXX 100644 | 43 | /* EBF=1 needs to do a step with round-to-odd semantics */ |
44 | --- a/hw/arm/netduinoplus2.c | 44 | *oddstatusp = *statusp; |
45 | +++ b/hw/arm/netduinoplus2.c | 45 | set_float_rounding_mode(float_round_to_odd, oddstatusp); |
46 | @@ -XXX,XX +XXX,XX @@ static void netduinoplus2_init(MachineState *machine) | 46 | + } else { |
47 | clock_set_hz(sysclk, SYSCLK_FRQ); | 47 | + set_flush_to_zero(true, statusp); |
48 | 48 | + set_flush_inputs_to_zero(true, statusp); | |
49 | dev = qdev_new(TYPE_STM32F405_SOC); | 49 | + set_float_rounding_mode(float_round_to_odd_inf, statusp); |
50 | + object_property_add_child(OBJECT(machine), "soc", OBJECT(dev)); | 50 | } |
51 | qdev_connect_clock_in(dev, "sysclk", sysclk); | 51 | - |
52 | sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); | 52 | return ebf; |
53 | 53 | } | |
54 | diff --git a/hw/arm/olimex-stm32-h405.c b/hw/arm/olimex-stm32-h405.c | ||
55 | index XXXXXXX..XXXXXXX 100644 | ||
56 | --- a/hw/arm/olimex-stm32-h405.c | ||
57 | +++ b/hw/arm/olimex-stm32-h405.c | ||
58 | @@ -XXX,XX +XXX,XX @@ static void olimex_stm32_h405_init(MachineState *machine) | ||
59 | clock_set_hz(sysclk, SYSCLK_FRQ); | ||
60 | |||
61 | dev = qdev_new(TYPE_STM32F405_SOC); | ||
62 | + object_property_add_child(OBJECT(machine), "soc", OBJECT(dev)); | ||
63 | qdev_connect_clock_in(dev, "sysclk", sysclk); | ||
64 | sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); | ||
65 | |||
66 | diff --git a/hw/arm/stm32vldiscovery.c b/hw/arm/stm32vldiscovery.c | ||
67 | index XXXXXXX..XXXXXXX 100644 | ||
68 | --- a/hw/arm/stm32vldiscovery.c | ||
69 | +++ b/hw/arm/stm32vldiscovery.c | ||
70 | @@ -XXX,XX +XXX,XX @@ static void stm32vldiscovery_init(MachineState *machine) | ||
71 | clock_set_hz(sysclk, SYSCLK_FRQ); | ||
72 | |||
73 | dev = qdev_new(TYPE_STM32F100_SOC); | ||
74 | + object_property_add_child(OBJECT(machine), "soc", OBJECT(dev)); | ||
75 | qdev_connect_clock_in(dev, "sysclk", sysclk); | ||
76 | sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); | ||
77 | 54 | ||
78 | -- | 55 | -- |
79 | 2.34.1 | 56 | 2.34.1 |
80 | 57 | ||
81 | 58 | diff view generated by jsdifflib |
1 | FEAT_NV and FEAT_NV2 will allow EL1 to attempt to access cpregs that | 1 | Currently we hardcode the default NaN value in parts64_default_nan() |
---|---|---|---|
2 | only exist at EL2. This means we're going to want to run their | 2 | using a compile-time ifdef ladder. This is awkward for two cases: |
3 | accessfns when the CPU is at EL1. In almost all cases, the behaviour | 3 | * for single-QEMU-binary we can't hard-code target-specifics like this |
4 | we want is "the accessfn returns OK if at EL1". | 4 | * for Arm FEAT_AFP the default NaN value depends on FPCR.AH |
5 | (specifically the sign bit is different) | ||
5 | 6 | ||
6 | Mostly the accessfn already does the right thing; in a few cases we | 7 | Add a field to float_status to specify the default NaN value; fall |
7 | need to explicitly check that the EL is not 1 before applying various | 8 | back to the old ifdef behaviour if these are not set. |
8 | trap controls, or split out an accessfn used both for an _EL1 and an | ||
9 | _EL2 register into two so we can handle the FEAT_NV case correctly | ||
10 | for the _EL2 register. | ||
11 | 9 | ||
12 | There are two registers where we want the accessfn to trap for | 10 | The default NaN value is specified by setting a uint8_t to a |
13 | a FEAT_NV EL1 access: VSTTBR_EL2 and VSTCR_EL2 should UNDEF | 11 | pattern corresponding to the sign and upper fraction parts of |
14 | an access from NonSecure EL1, not trap to EL2 under FEAT_NV. | 12 | the NaN; the lower bits of the fraction are set from bit 0 of |
15 | The way we have written sel2_access() already results in this | 13 | the pattern. |
16 | behaviour. | ||
17 | |||
18 | We can identify the registers we care about here because they | ||
19 | all have opc1 == 4 or 5. | ||
20 | 14 | ||
21 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 15 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
22 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 16 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
23 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 17 | Message-id: 20241202131347.498124-35-peter.maydell@linaro.org |
24 | --- | 18 | --- |
25 | target/arm/debug_helper.c | 12 +++++++- | 19 | include/fpu/softfloat-helpers.h | 11 +++++++ |
26 | target/arm/helper.c | 65 ++++++++++++++++++++++++++++++++++----- | 20 | include/fpu/softfloat-types.h | 10 ++++++ |
27 | 2 files changed, 69 insertions(+), 8 deletions(-) | 21 | fpu/softfloat-specialize.c.inc | 55 ++++++++++++++++++++------------- |
22 | 3 files changed, 54 insertions(+), 22 deletions(-) | ||
28 | 23 | ||
29 | diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c | 24 | diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h |
30 | index XXXXXXX..XXXXXXX 100644 | 25 | index XXXXXXX..XXXXXXX 100644 |
31 | --- a/target/arm/debug_helper.c | 26 | --- a/include/fpu/softfloat-helpers.h |
32 | +++ b/target/arm/debug_helper.c | 27 | +++ b/include/fpu/softfloat-helpers.h |
33 | @@ -XXX,XX +XXX,XX @@ static CPAccessResult access_tda(CPUARMState *env, const ARMCPRegInfo *ri, | 28 | @@ -XXX,XX +XXX,XX @@ static inline void set_float_infzeronan_rule(FloatInfZeroNaNRule rule, |
34 | return CP_ACCESS_OK; | 29 | status->float_infzeronan_rule = rule; |
35 | } | 30 | } |
36 | 31 | ||
37 | +static CPAccessResult access_dbgvcr32(CPUARMState *env, const ARMCPRegInfo *ri, | 32 | +static inline void set_float_default_nan_pattern(uint8_t dnan_pattern, |
38 | + bool isread) | 33 | + float_status *status) |
39 | +{ | 34 | +{ |
40 | + /* MCDR_EL3.TDMA doesn't apply for FEAT_NV traps */ | 35 | + status->default_nan_pattern = dnan_pattern; |
41 | + if (arm_current_el(env) == 2 && (env->cp15.mdcr_el3 & MDCR_TDA)) { | ||
42 | + return CP_ACCESS_TRAP_EL3; | ||
43 | + } | ||
44 | + return CP_ACCESS_OK; | ||
45 | +} | 36 | +} |
46 | + | 37 | + |
47 | /* | 38 | static inline void set_flush_to_zero(bool val, float_status *status) |
48 | * Check for traps to Debug Comms Channel registers. If FEAT_FGT | ||
49 | * is implemented then these are controlled by MDCR_EL2.TDCC for | ||
50 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo debug_aa32_el1_reginfo[] = { | ||
51 | */ | ||
52 | { .name = "DBGVCR32_EL2", .state = ARM_CP_STATE_AA64, | ||
53 | .opc0 = 2, .opc1 = 4, .crn = 0, .crm = 7, .opc2 = 0, | ||
54 | - .access = PL2_RW, .accessfn = access_tda, | ||
55 | + .access = PL2_RW, .accessfn = access_dbgvcr32, | ||
56 | .type = ARM_CP_NOP | ARM_CP_EL3_NO_EL2_KEEP }, | ||
57 | }; | ||
58 | |||
59 | diff --git a/target/arm/helper.c b/target/arm/helper.c | ||
60 | index XXXXXXX..XXXXXXX 100644 | ||
61 | --- a/target/arm/helper.c | ||
62 | +++ b/target/arm/helper.c | ||
63 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { | ||
64 | static CPAccessResult e2h_access(CPUARMState *env, const ARMCPRegInfo *ri, | ||
65 | bool isread) | ||
66 | { | 39 | { |
67 | + if (arm_current_el(env) == 1) { | 40 | status->flush_to_zero = val; |
68 | + /* This must be a FEAT_NV access */ | 41 | @@ -XXX,XX +XXX,XX @@ static inline FloatInfZeroNaNRule get_float_infzeronan_rule(float_status *status |
69 | + /* TODO: FEAT_ECV will need to check CNTHCTL_EL2 here */ | 42 | return status->float_infzeronan_rule; |
70 | + return CP_ACCESS_OK; | ||
71 | + } | ||
72 | if (!(arm_hcr_el2_eff(env) & HCR_E2H)) { | ||
73 | return CP_ACCESS_TRAP; | ||
74 | } | ||
75 | @@ -XXX,XX +XXX,XX @@ static void hcrx_write(CPUARMState *env, const ARMCPRegInfo *ri, | ||
76 | static CPAccessResult access_hxen(CPUARMState *env, const ARMCPRegInfo *ri, | ||
77 | bool isread) | ||
78 | { | ||
79 | - if (arm_current_el(env) < 3 | ||
80 | + if (arm_current_el(env) == 2 | ||
81 | && arm_feature(env, ARM_FEATURE_EL3) | ||
82 | && !(env->cp15.scr_el3 & SCR_HXEN)) { | ||
83 | return CP_ACCESS_TRAP_EL3; | ||
84 | @@ -XXX,XX +XXX,XX @@ static CPAccessResult el2_e2h_e12_access(CPUARMState *env, | ||
85 | const ARMCPRegInfo *ri, | ||
86 | bool isread) | ||
87 | { | ||
88 | + if (arm_current_el(env) == 1) { | ||
89 | + /* | ||
90 | + * This must be a FEAT_NV access (will either trap or redirect | ||
91 | + * to memory). None of the registers with _EL12 aliases want to | ||
92 | + * apply their trap controls for this kind of access, so don't | ||
93 | + * call the orig_accessfn or do the "UNDEF when E2H is 0" check. | ||
94 | + */ | ||
95 | + return CP_ACCESS_OK; | ||
96 | + } | ||
97 | /* FOO_EL12 aliases only exist when E2H is 1; otherwise they UNDEF */ | ||
98 | if (!(arm_hcr_el2_eff(env) & HCR_E2H)) { | ||
99 | return CP_ACCESS_TRAP_UNCATEGORIZED; | ||
100 | @@ -XXX,XX +XXX,XX @@ static CPAccessResult access_tpidr2(CPUARMState *env, const ARMCPRegInfo *ri, | ||
101 | return CP_ACCESS_OK; | ||
102 | } | 43 | } |
103 | 44 | ||
104 | -static CPAccessResult access_esm(CPUARMState *env, const ARMCPRegInfo *ri, | 45 | +static inline uint8_t get_float_default_nan_pattern(float_status *status) |
105 | - bool isread) | ||
106 | +static CPAccessResult access_smprimap(CPUARMState *env, const ARMCPRegInfo *ri, | ||
107 | + bool isread) | ||
108 | +{ | 46 | +{ |
109 | + /* If EL1 this is a FEAT_NV access and CPTR_EL3.ESM doesn't apply */ | 47 | + return status->default_nan_pattern; |
110 | + if (arm_current_el(env) == 2 | ||
111 | + && arm_feature(env, ARM_FEATURE_EL3) | ||
112 | + && !FIELD_EX64(env->cp15.cptr_el[3], CPTR_EL3, ESM)) { | ||
113 | + return CP_ACCESS_TRAP_EL3; | ||
114 | + } | ||
115 | + return CP_ACCESS_OK; | ||
116 | +} | 48 | +} |
117 | + | 49 | + |
118 | +static CPAccessResult access_smpri(CPUARMState *env, const ARMCPRegInfo *ri, | 50 | static inline bool get_flush_to_zero(float_status *status) |
119 | + bool isread) | ||
120 | { | 51 | { |
121 | - /* TODO: FEAT_FGT for SMPRI_EL1 but not SMPRIMAP_EL2 */ | 52 | return status->flush_to_zero; |
122 | if (arm_current_el(env) < 3 | 53 | diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h |
123 | && arm_feature(env, ARM_FEATURE_EL3) | 54 | index XXXXXXX..XXXXXXX 100644 |
124 | && !FIELD_EX64(env->cp15.cptr_el[3], CPTR_EL3, ESM)) { | 55 | --- a/include/fpu/softfloat-types.h |
125 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo sme_reginfo[] = { | 56 | +++ b/include/fpu/softfloat-types.h |
126 | */ | 57 | @@ -XXX,XX +XXX,XX @@ typedef struct float_status { |
127 | { .name = "SMPRI_EL1", .state = ARM_CP_STATE_AA64, | 58 | /* should denormalised inputs go to zero and set the input_denormal flag? */ |
128 | .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 2, .opc2 = 4, | 59 | bool flush_inputs_to_zero; |
129 | - .access = PL1_RW, .accessfn = access_esm, | 60 | bool default_nan_mode; |
130 | + .access = PL1_RW, .accessfn = access_smpri, | 61 | + /* |
131 | .fgt = FGT_NSMPRI_EL1, | 62 | + * The pattern to use for the default NaN. Here the high bit specifies |
132 | .type = ARM_CP_CONST, .resetvalue = 0 }, | 63 | + * the default NaN's sign bit, and bits 6..0 specify the high bits of the |
133 | { .name = "SMPRIMAP_EL2", .state = ARM_CP_STATE_AA64, | 64 | + * fractional part. The low bits of the fractional part are copies of bit 0. |
134 | .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 2, .opc2 = 5, | 65 | + * The exponent of the default NaN is (as for any NaN) always all 1s. |
135 | - .access = PL2_RW, .accessfn = access_esm, | 66 | + * Note that a value of 0 here is not a valid NaN. The target must set |
136 | + .access = PL2_RW, .accessfn = access_smprimap, | 67 | + * this to the correct non-zero value, or we will assert when trying to |
137 | .type = ARM_CP_CONST, .resetvalue = 0 }, | 68 | + * create a default NaN. |
138 | }; | 69 | + */ |
139 | 70 | + uint8_t default_nan_pattern; | |
140 | @@ -XXX,XX +XXX,XX @@ static CPAccessResult access_mte(CPUARMState *env, const ARMCPRegInfo *ri, | 71 | /* |
141 | bool isread) | 72 | * The flags below are not used on all specializations and may |
73 | * constant fold away (see snan_bit_is_one()/no_signalling_nans() in | ||
74 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc | ||
75 | index XXXXXXX..XXXXXXX 100644 | ||
76 | --- a/fpu/softfloat-specialize.c.inc | ||
77 | +++ b/fpu/softfloat-specialize.c.inc | ||
78 | @@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status) | ||
142 | { | 79 | { |
143 | int el = arm_current_el(env); | 80 | bool sign = 0; |
144 | + if (el < 2 && arm_is_el2_enabled(env)) { | 81 | uint64_t frac; |
145 | + uint64_t hcr = arm_hcr_el2_eff(env); | 82 | + uint8_t dnan_pattern = status->default_nan_pattern; |
146 | + if (!(hcr & HCR_ATA) && (!(hcr & HCR_E2H) || !(hcr & HCR_TGE))) { | 83 | |
147 | + return CP_ACCESS_TRAP_EL2; | 84 | + if (dnan_pattern == 0) { |
85 | #if defined(TARGET_SPARC) || defined(TARGET_M68K) | ||
86 | - /* !snan_bit_is_one, set all bits */ | ||
87 | - frac = (1ULL << DECOMPOSED_BINARY_POINT) - 1; | ||
88 | -#elif defined(TARGET_I386) || defined(TARGET_X86_64) \ | ||
89 | + /* Sign bit clear, all frac bits set */ | ||
90 | + dnan_pattern = 0b01111111; | ||
91 | +#elif defined(TARGET_I386) || defined(TARGET_X86_64) \ | ||
92 | || defined(TARGET_MICROBLAZE) | ||
93 | - /* !snan_bit_is_one, set sign and msb */ | ||
94 | - frac = 1ULL << (DECOMPOSED_BINARY_POINT - 1); | ||
95 | - sign = 1; | ||
96 | + /* Sign bit set, most significant frac bit set */ | ||
97 | + dnan_pattern = 0b11000000; | ||
98 | #elif defined(TARGET_HPPA) | ||
99 | - /* snan_bit_is_one, set msb-1. */ | ||
100 | - frac = 1ULL << (DECOMPOSED_BINARY_POINT - 2); | ||
101 | + /* Sign bit clear, msb-1 frac bit set */ | ||
102 | + dnan_pattern = 0b00100000; | ||
103 | #elif defined(TARGET_HEXAGON) | ||
104 | - sign = 1; | ||
105 | - frac = ~0ULL; | ||
106 | + /* Sign bit set, all frac bits set. */ | ||
107 | + dnan_pattern = 0b11111111; | ||
108 | #else | ||
109 | - /* | ||
110 | - * This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V, | ||
111 | - * S390, SH4, TriCore, and Xtensa. Our other supported targets | ||
112 | - * do not have floating-point. | ||
113 | - */ | ||
114 | - if (snan_bit_is_one(status)) { | ||
115 | - /* set all bits other than msb */ | ||
116 | - frac = (1ULL << (DECOMPOSED_BINARY_POINT - 1)) - 1; | ||
117 | - } else { | ||
118 | - /* set msb */ | ||
119 | - frac = 1ULL << (DECOMPOSED_BINARY_POINT - 1); | ||
120 | - } | ||
121 | + /* | ||
122 | + * This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V, | ||
123 | + * S390, SH4, TriCore, and Xtensa. Our other supported targets | ||
124 | + * do not have floating-point. | ||
125 | + */ | ||
126 | + if (snan_bit_is_one(status)) { | ||
127 | + /* sign bit clear, set all frac bits other than msb */ | ||
128 | + dnan_pattern = 0b00111111; | ||
129 | + } else { | ||
130 | + /* sign bit clear, set frac msb */ | ||
131 | + dnan_pattern = 0b01000000; | ||
148 | + } | 132 | + } |
133 | #endif | ||
149 | + } | 134 | + } |
150 | + if (el < 3 && | 135 | + assert(dnan_pattern != 0); |
151 | + arm_feature(env, ARM_FEATURE_EL3) && | 136 | + |
152 | + !(env->cp15.scr_el3 & SCR_ATA)) { | 137 | + sign = dnan_pattern >> 7; |
153 | + return CP_ACCESS_TRAP_EL3; | ||
154 | + } | ||
155 | + return CP_ACCESS_OK; | ||
156 | +} | ||
157 | |||
158 | +static CPAccessResult access_tfsr_el2(CPUARMState *env, const ARMCPRegInfo *ri, | ||
159 | + bool isread) | ||
160 | +{ | ||
161 | + /* | 138 | + /* |
162 | + * TFSR_EL2: similar to generic access_mte(), but we need to | 139 | + * Place default_nan_pattern [6:0] into bits [62:56], |
163 | + * account for FEAT_NV. At EL1 this must be a FEAT_NV access; | 140 | + * and replecate bit [0] down into [55:0] |
164 | + * we will trap to EL2 and the HCR/SCR traps do not apply. | ||
165 | + */ | 141 | + */ |
166 | + int el = arm_current_el(env); | 142 | + frac = deposit64(0, DECOMPOSED_BINARY_POINT - 7, 7, dnan_pattern); |
167 | + | 143 | + frac = deposit64(frac, 0, DECOMPOSED_BINARY_POINT - 7, -(dnan_pattern & 1)); |
168 | + if (el == 1) { | 144 | |
169 | + return CP_ACCESS_OK; | 145 | *p = (FloatParts64) { |
170 | + } | 146 | .cls = float_class_qnan, |
171 | if (el < 2 && arm_is_el2_enabled(env)) { | ||
172 | uint64_t hcr = arm_hcr_el2_eff(env); | ||
173 | if (!(hcr & HCR_ATA) && (!(hcr & HCR_E2H) || !(hcr & HCR_TGE))) { | ||
174 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo mte_reginfo[] = { | ||
175 | .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[1]) }, | ||
176 | { .name = "TFSR_EL2", .state = ARM_CP_STATE_AA64, | ||
177 | .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 6, .opc2 = 0, | ||
178 | - .access = PL2_RW, .accessfn = access_mte, | ||
179 | + .access = PL2_RW, .accessfn = access_tfsr_el2, | ||
180 | .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[2]) }, | ||
181 | { .name = "TFSR_EL3", .state = ARM_CP_STATE_AA64, | ||
182 | .opc0 = 3, .opc1 = 6, .crn = 5, .crm = 6, .opc2 = 0, | ||
183 | -- | 147 | -- |
184 | 2.34.1 | 148 | 2.34.1 | diff view generated by jsdifflib |
1 | Mark up the cpreginfo structs to indicate offsets for system | 1 | Set the default NaN pattern explicitly for the tests/fp code. |
---|---|---|---|
2 | registers from VNCR_EL2, as defined in table D8-66 in rule R_CSRPQ in | ||
3 | the Arm ARM. This covers all the remaining offsets at 0x200 and | ||
4 | above, except for the GIC ICH_* registers. | ||
5 | |||
6 | (Note that because we don't implement FEAT_SPE, FEAT_TRF, | ||
7 | FEAT_MPAM, FEAT_BRBE or FEAT_AMUv1p1 we don't implement any | ||
8 | of the registers that use offsets at 0x800 and above.) | ||
9 | 2 | ||
10 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 3 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
11 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 4 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
12 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 5 | Message-id: 20241202131347.498124-36-peter.maydell@linaro.org |
13 | --- | 6 | --- |
14 | target/arm/helper.c | 8 ++++++++ | 7 | tests/fp/fp-bench.c | 1 + |
15 | 1 file changed, 8 insertions(+) | 8 | tests/fp/fp-test-log2.c | 1 + |
9 | tests/fp/fp-test.c | 1 + | ||
10 | 3 files changed, 3 insertions(+) | ||
16 | 11 | ||
17 | diff --git a/target/arm/helper.c b/target/arm/helper.c | 12 | diff --git a/tests/fp/fp-bench.c b/tests/fp/fp-bench.c |
18 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/target/arm/helper.c | 14 | --- a/tests/fp/fp-bench.c |
20 | +++ b/target/arm/helper.c | 15 | +++ b/tests/fp/fp-bench.c |
21 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo vmsa_pmsa_cp_reginfo[] = { | 16 | @@ -XXX,XX +XXX,XX @@ static void run_bench(void) |
22 | .opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0, | 17 | set_float_2nan_prop_rule(float_2nan_prop_s_ab, &soft_status); |
23 | .access = PL1_RW, .accessfn = access_tvm_trvm, | 18 | set_float_3nan_prop_rule(float_3nan_prop_s_cab, &soft_status); |
24 | .fgt = FGT_FAR_EL1, | 19 | set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, &soft_status); |
25 | + .nv2_redirect_offset = 0x220 | NV2_REDIR_NV1, | 20 | + set_float_default_nan_pattern(0b01000000, &soft_status); |
26 | .fieldoffset = offsetof(CPUARMState, cp15.far_el[1]), | 21 | |
27 | .resetvalue = 0, }, | 22 | f = bench_funcs[operation][precision]; |
28 | }; | 23 | g_assert(f); |
29 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { | 24 | diff --git a/tests/fp/fp-test-log2.c b/tests/fp/fp-test-log2.c |
30 | .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 0, | 25 | index XXXXXXX..XXXXXXX 100644 |
31 | .access = PL1_RW, .accessfn = access_tvm_trvm, | 26 | --- a/tests/fp/fp-test-log2.c |
32 | .fgt = FGT_TTBR0_EL1, | 27 | +++ b/tests/fp/fp-test-log2.c |
33 | + .nv2_redirect_offset = 0x200 | NV2_REDIR_NV1, | 28 | @@ -XXX,XX +XXX,XX @@ int main(int ac, char **av) |
34 | .writefn = vmsa_ttbr_write, .resetvalue = 0, .raw_writefn = raw_write, | 29 | int i; |
35 | .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr0_s), | 30 | |
36 | offsetof(CPUARMState, cp15.ttbr0_ns) } }, | 31 | set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf); |
37 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { | 32 | + set_float_default_nan_pattern(0b01000000, &qsf); |
38 | .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 1, | 33 | set_float_rounding_mode(float_round_nearest_even, &qsf); |
39 | .access = PL1_RW, .accessfn = access_tvm_trvm, | 34 | |
40 | .fgt = FGT_TTBR1_EL1, | 35 | test.d = 0.0; |
41 | + .nv2_redirect_offset = 0x210 | NV2_REDIR_NV1, | 36 | diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c |
42 | .writefn = vmsa_ttbr_write, .resetvalue = 0, .raw_writefn = raw_write, | 37 | index XXXXXXX..XXXXXXX 100644 |
43 | .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr1_s), | 38 | --- a/tests/fp/fp-test.c |
44 | offsetof(CPUARMState, cp15.ttbr1_ns) } }, | 39 | +++ b/tests/fp/fp-test.c |
45 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo v8_cp_reginfo[] = { | 40 | @@ -XXX,XX +XXX,XX @@ void run_test(void) |
46 | .type = ARM_CP_ALIAS, | 41 | */ |
47 | .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 1, | 42 | set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf); |
48 | .access = PL1_RW, .accessfn = access_nv1, | 43 | set_float_3nan_prop_rule(float_3nan_prop_s_cab, &qsf); |
49 | + .nv2_redirect_offset = 0x230 | NV2_REDIR_NV1, | 44 | + set_float_default_nan_pattern(0b01000000, &qsf); |
50 | .fieldoffset = offsetof(CPUARMState, elr_el[1]) }, | 45 | set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, &qsf); |
51 | { .name = "SPSR_EL1", .state = ARM_CP_STATE_AA64, | 46 | |
52 | .type = ARM_CP_ALIAS, | 47 | genCases_setLevel(test_level); |
53 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo v8_cp_reginfo[] = { | ||
54 | .fieldoffset = offsetof(CPUARMState, sp_el[0]) }, | ||
55 | { .name = "SP_EL1", .state = ARM_CP_STATE_AA64, | ||
56 | .opc0 = 3, .opc1 = 4, .crn = 4, .crm = 1, .opc2 = 0, | ||
57 | + .nv2_redirect_offset = 0x240, | ||
58 | .access = PL2_RW, .type = ARM_CP_ALIAS | ARM_CP_EL3_NO_EL2_KEEP, | ||
59 | .fieldoffset = offsetof(CPUARMState, sp_el[1]) }, | ||
60 | { .name = "SPSel", .state = ARM_CP_STATE_AA64, | ||
61 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo minimal_ras_reginfo[] = { | ||
62 | .type = ARM_CP_CONST, .resetvalue = 0 }, | ||
63 | { .name = "VDISR_EL2", .state = ARM_CP_STATE_BOTH, | ||
64 | .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 1, .opc2 = 1, | ||
65 | + .nv2_redirect_offset = 0x500, | ||
66 | .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.vdisr_el2) }, | ||
67 | { .name = "VSESR_EL2", .state = ARM_CP_STATE_BOTH, | ||
68 | .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 2, .opc2 = 3, | ||
69 | + .nv2_redirect_offset = 0x508, | ||
70 | .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.vsesr_el2) }, | ||
71 | }; | ||
72 | |||
73 | @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) | ||
74 | .access = PL1_RW, .writefn = vbar_write, | ||
75 | .accessfn = access_nv1, | ||
76 | .fgt = FGT_VBAR_EL1, | ||
77 | + .nv2_redirect_offset = 0x250 | NV2_REDIR_NV1, | ||
78 | .bank_fieldoffsets = { offsetof(CPUARMState, cp15.vbar_s), | ||
79 | offsetof(CPUARMState, cp15.vbar_ns) }, | ||
80 | .resetvalue = 0 }, | ||
81 | -- | 48 | -- |
82 | 2.34.1 | 49 | 2.34.1 | diff view generated by jsdifflib |
1 | Mark up the cpreginfo structs to indicate offsets for system | 1 | Set the default NaN pattern explicitly, and remove the ifdef from |
---|---|---|---|
2 | registers from VNCR_EL2, as defined in table D8-66 in rule R_CSRPQ in | 2 | parts64_default_nan(). |
3 | the Arm ARM. This commit covers offsets 0x168 to 0x1f8. | ||
4 | 3 | ||
5 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 4 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
6 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 5 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
7 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 6 | Message-id: 20241202131347.498124-37-peter.maydell@linaro.org |
8 | --- | 7 | --- |
9 | target/arm/helper.c | 18 ++++++++++++++++++ | 8 | target/microblaze/cpu.c | 2 ++ |
10 | 1 file changed, 18 insertions(+) | 9 | fpu/softfloat-specialize.c.inc | 3 +-- |
10 | 2 files changed, 3 insertions(+), 2 deletions(-) | ||
11 | 11 | ||
12 | diff --git a/target/arm/helper.c b/target/arm/helper.c | 12 | diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c |
13 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/target/arm/helper.c | 14 | --- a/target/microblaze/cpu.c |
15 | +++ b/target/arm/helper.c | 15 | +++ b/target/microblaze/cpu.c |
16 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { | 16 | @@ -XXX,XX +XXX,XX @@ static void mb_cpu_reset_hold(Object *obj, ResetType type) |
17 | .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 1, | 17 | * this architecture. |
18 | .type = ARM_CP_IO, .access = PL0_RW, | 18 | */ |
19 | .accessfn = gt_ptimer_access, | 19 | set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status); |
20 | + .nv2_redirect_offset = 0x180 | NV2_REDIR_NV1, | 20 | + /* Default NaN: sign bit set, most significant frac bit set */ |
21 | .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].ctl), | 21 | + set_float_default_nan_pattern(0b11000000, &env->fp_status); |
22 | .resetvalue = 0, | 22 | |
23 | .readfn = gt_phys_redir_ctl_read, .raw_readfn = raw_read, | 23 | #if defined(CONFIG_USER_ONLY) |
24 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { | 24 | /* start in user mode with interrupts enabled. */ |
25 | .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 1, | 25 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc |
26 | .type = ARM_CP_IO, .access = PL0_RW, | 26 | index XXXXXXX..XXXXXXX 100644 |
27 | .accessfn = gt_vtimer_access, | 27 | --- a/fpu/softfloat-specialize.c.inc |
28 | + .nv2_redirect_offset = 0x170 | NV2_REDIR_NV1, | 28 | +++ b/fpu/softfloat-specialize.c.inc |
29 | .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].ctl), | 29 | @@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status) |
30 | .resetvalue = 0, | 30 | #if defined(TARGET_SPARC) || defined(TARGET_M68K) |
31 | .readfn = gt_virt_redir_ctl_read, .raw_readfn = raw_read, | 31 | /* Sign bit clear, all frac bits set */ |
32 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { | 32 | dnan_pattern = 0b01111111; |
33 | .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 2, | 33 | -#elif defined(TARGET_I386) || defined(TARGET_X86_64) \ |
34 | .access = PL0_RW, | 34 | - || defined(TARGET_MICROBLAZE) |
35 | .type = ARM_CP_IO, | 35 | +#elif defined(TARGET_I386) || defined(TARGET_X86_64) |
36 | + .nv2_redirect_offset = 0x178 | NV2_REDIR_NV1, | 36 | /* Sign bit set, most significant frac bit set */ |
37 | .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval), | 37 | dnan_pattern = 0b11000000; |
38 | .resetvalue = 0, .accessfn = gt_ptimer_access, | 38 | #elif defined(TARGET_HPPA) |
39 | .readfn = gt_phys_redir_cval_read, .raw_readfn = raw_read, | ||
40 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { | ||
41 | .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 2, | ||
42 | .access = PL0_RW, | ||
43 | .type = ARM_CP_IO, | ||
44 | + .nv2_redirect_offset = 0x168 | NV2_REDIR_NV1, | ||
45 | .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval), | ||
46 | .resetvalue = 0, .accessfn = gt_vtimer_access, | ||
47 | .readfn = gt_virt_redir_cval_read, .raw_readfn = raw_read, | ||
48 | @@ -XXX,XX +XXX,XX @@ static void zcr_write(CPUARMState *env, const ARMCPRegInfo *ri, | ||
49 | static const ARMCPRegInfo zcr_reginfo[] = { | ||
50 | { .name = "ZCR_EL1", .state = ARM_CP_STATE_AA64, | ||
51 | .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 2, .opc2 = 0, | ||
52 | + .nv2_redirect_offset = 0x1e0 | NV2_REDIR_NV1, | ||
53 | .access = PL1_RW, .type = ARM_CP_SVE, | ||
54 | .fieldoffset = offsetof(CPUARMState, vfp.zcr_el[1]), | ||
55 | .writefn = zcr_write, .raw_writefn = raw_write }, | ||
56 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo sme_reginfo[] = { | ||
57 | .writefn = svcr_write, .raw_writefn = raw_write }, | ||
58 | { .name = "SMCR_EL1", .state = ARM_CP_STATE_AA64, | ||
59 | .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 2, .opc2 = 6, | ||
60 | + .nv2_redirect_offset = 0x1f0 | NV2_REDIR_NV1, | ||
61 | .access = PL1_RW, .type = ARM_CP_SME, | ||
62 | .fieldoffset = offsetof(CPUARMState, vfp.smcr_el[1]), | ||
63 | .writefn = smcr_write, .raw_writefn = raw_write }, | ||
64 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo sme_reginfo[] = { | ||
65 | .type = ARM_CP_CONST, .resetvalue = 0 }, | ||
66 | { .name = "SMPRIMAP_EL2", .state = ARM_CP_STATE_AA64, | ||
67 | .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 2, .opc2 = 5, | ||
68 | + .nv2_redirect_offset = 0x1f8, | ||
69 | .access = PL2_RW, .accessfn = access_smprimap, | ||
70 | .type = ARM_CP_CONST, .resetvalue = 0 }, | ||
71 | }; | ||
72 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo mte_reginfo[] = { | ||
73 | { .name = "TFSR_EL1", .state = ARM_CP_STATE_AA64, | ||
74 | .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 6, .opc2 = 0, | ||
75 | .access = PL1_RW, .accessfn = access_tfsr_el1, | ||
76 | + .nv2_redirect_offset = 0x190 | NV2_REDIR_NV1, | ||
77 | .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[1]) }, | ||
78 | { .name = "TFSR_EL2", .state = ARM_CP_STATE_AA64, | ||
79 | .type = ARM_CP_NV2_REDIRECT, | ||
80 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo scxtnum_reginfo[] = { | ||
81 | .opc0 = 3, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 7, | ||
82 | .access = PL1_RW, .accessfn = access_scxtnum_el1, | ||
83 | .fgt = FGT_SCXTNUM_EL1, | ||
84 | + .nv2_redirect_offset = 0x188 | NV2_REDIR_NV1, | ||
85 | .fieldoffset = offsetof(CPUARMState, scxtnum_el[1]) }, | ||
86 | { .name = "SCXTNUM_EL2", .state = ARM_CP_STATE_AA64, | ||
87 | .opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 7, | ||
88 | @@ -XXX,XX +XXX,XX @@ static CPAccessResult access_fgt(CPUARMState *env, const ARMCPRegInfo *ri, | ||
89 | static const ARMCPRegInfo fgt_reginfo[] = { | ||
90 | { .name = "HFGRTR_EL2", .state = ARM_CP_STATE_AA64, | ||
91 | .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 4, | ||
92 | + .nv2_redirect_offset = 0x1b8, | ||
93 | .access = PL2_RW, .accessfn = access_fgt, | ||
94 | .fieldoffset = offsetof(CPUARMState, cp15.fgt_read[FGTREG_HFGRTR]) }, | ||
95 | { .name = "HFGWTR_EL2", .state = ARM_CP_STATE_AA64, | ||
96 | .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 5, | ||
97 | + .nv2_redirect_offset = 0x1c0, | ||
98 | .access = PL2_RW, .accessfn = access_fgt, | ||
99 | .fieldoffset = offsetof(CPUARMState, cp15.fgt_write[FGTREG_HFGWTR]) }, | ||
100 | { .name = "HDFGRTR_EL2", .state = ARM_CP_STATE_AA64, | ||
101 | .opc0 = 3, .opc1 = 4, .crn = 3, .crm = 1, .opc2 = 4, | ||
102 | + .nv2_redirect_offset = 0x1d0, | ||
103 | .access = PL2_RW, .accessfn = access_fgt, | ||
104 | .fieldoffset = offsetof(CPUARMState, cp15.fgt_read[FGTREG_HDFGRTR]) }, | ||
105 | { .name = "HDFGWTR_EL2", .state = ARM_CP_STATE_AA64, | ||
106 | .opc0 = 3, .opc1 = 4, .crn = 3, .crm = 1, .opc2 = 5, | ||
107 | + .nv2_redirect_offset = 0x1d8, | ||
108 | .access = PL2_RW, .accessfn = access_fgt, | ||
109 | .fieldoffset = offsetof(CPUARMState, cp15.fgt_write[FGTREG_HDFGWTR]) }, | ||
110 | { .name = "HFGITR_EL2", .state = ARM_CP_STATE_AA64, | ||
111 | .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 6, | ||
112 | + .nv2_redirect_offset = 0x1c8, | ||
113 | .access = PL2_RW, .accessfn = access_fgt, | ||
114 | .fieldoffset = offsetof(CPUARMState, cp15.fgt_exec[FGTREG_HFGITR]) }, | ||
115 | }; | ||
116 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo vhe_reginfo[] = { | ||
117 | .opc0 = 3, .opc1 = 5, .crn = 14, .crm = 2, .opc2 = 1, | ||
118 | .type = ARM_CP_IO | ARM_CP_ALIAS, | ||
119 | .access = PL2_RW, .accessfn = e2h_access, | ||
120 | + .nv2_redirect_offset = 0x180 | NV2_REDIR_NO_NV1, | ||
121 | .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].ctl), | ||
122 | .writefn = gt_phys_ctl_write, .raw_writefn = raw_write }, | ||
123 | { .name = "CNTV_CTL_EL02", .state = ARM_CP_STATE_AA64, | ||
124 | .opc0 = 3, .opc1 = 5, .crn = 14, .crm = 3, .opc2 = 1, | ||
125 | .type = ARM_CP_IO | ARM_CP_ALIAS, | ||
126 | .access = PL2_RW, .accessfn = e2h_access, | ||
127 | + .nv2_redirect_offset = 0x170 | NV2_REDIR_NO_NV1, | ||
128 | .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].ctl), | ||
129 | .writefn = gt_virt_ctl_write, .raw_writefn = raw_write }, | ||
130 | { .name = "CNTP_TVAL_EL02", .state = ARM_CP_STATE_AA64, | ||
131 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo vhe_reginfo[] = { | ||
132 | .opc0 = 3, .opc1 = 5, .crn = 14, .crm = 2, .opc2 = 2, | ||
133 | .type = ARM_CP_IO | ARM_CP_ALIAS, | ||
134 | .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval), | ||
135 | + .nv2_redirect_offset = 0x178 | NV2_REDIR_NO_NV1, | ||
136 | .access = PL2_RW, .accessfn = e2h_access, | ||
137 | .writefn = gt_phys_cval_write, .raw_writefn = raw_write }, | ||
138 | { .name = "CNTV_CVAL_EL02", .state = ARM_CP_STATE_AA64, | ||
139 | .opc0 = 3, .opc1 = 5, .crn = 14, .crm = 3, .opc2 = 2, | ||
140 | .type = ARM_CP_IO | ARM_CP_ALIAS, | ||
141 | + .nv2_redirect_offset = 0x168 | NV2_REDIR_NO_NV1, | ||
142 | .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval), | ||
143 | .access = PL2_RW, .accessfn = e2h_access, | ||
144 | .writefn = gt_virt_cval_write, .raw_writefn = raw_write }, | ||
145 | -- | 39 | -- |
146 | 2.34.1 | 40 | 2.34.1 | diff view generated by jsdifflib |
1 | Mark up the cpreginfo structs to indicate offsets for system | 1 | Set the default NaN pattern explicitly, and remove the ifdef from |
---|---|---|---|
2 | registers from VNCR_EL2, as defined in table D8-66 in rule R_CSRPQ in | 2 | parts64_default_nan(). |
3 | the Arm ARM. This commit covers offsets 0x100 to 0x160. | ||
4 | |||
5 | Many (but not all) of the registers in this range have _EL12 aliases, | ||
6 | and the slot in memory is shared between the _EL12 version of the | ||
7 | register and the _EL1 version. Where we programmatically generate | ||
8 | the regdef for the _EL12 register, arrange that its | ||
9 | nv2_redirect_offset is set up correctly to do this. | ||
10 | 3 | ||
11 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 4 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
12 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 5 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
13 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 6 | Message-id: 20241202131347.498124-38-peter.maydell@linaro.org |
14 | --- | 7 | --- |
15 | target/arm/debug_helper.c | 1 + | 8 | target/i386/tcg/fpu_helper.c | 4 ++++ |
16 | target/arm/helper.c | 22 ++++++++++++++++++++++ | 9 | fpu/softfloat-specialize.c.inc | 3 --- |
17 | 2 files changed, 23 insertions(+) | 10 | 2 files changed, 4 insertions(+), 3 deletions(-) |
18 | 11 | ||
19 | diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c | 12 | diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c |
20 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
21 | --- a/target/arm/debug_helper.c | 14 | --- a/target/i386/tcg/fpu_helper.c |
22 | +++ b/target/arm/debug_helper.c | 15 | +++ b/target/i386/tcg/fpu_helper.c |
23 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo debug_cp_reginfo[] = { | 16 | @@ -XXX,XX +XXX,XX @@ void cpu_init_fp_statuses(CPUX86State *env) |
24 | .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 2, | 17 | */ |
25 | .access = PL1_RW, .accessfn = access_tda, | 18 | set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->sse_status); |
26 | .fgt = FGT_MDSCR_EL1, | 19 | set_float_3nan_prop_rule(float_3nan_prop_abc, &env->sse_status); |
27 | + .nv2_redirect_offset = 0x158, | 20 | + /* Default NaN: sign bit set, most significant frac bit set */ |
28 | .fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1), | 21 | + set_float_default_nan_pattern(0b11000000, &env->fp_status); |
29 | .resetvalue = 0 }, | 22 | + set_float_default_nan_pattern(0b11000000, &env->mmx_status); |
30 | /* | 23 | + set_float_default_nan_pattern(0b11000000, &env->sse_status); |
31 | diff --git a/target/arm/helper.c b/target/arm/helper.c | 24 | } |
25 | |||
26 | static inline uint8_t save_exception_flags(CPUX86State *env) | ||
27 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc | ||
32 | index XXXXXXX..XXXXXXX 100644 | 28 | index XXXXXXX..XXXXXXX 100644 |
33 | --- a/target/arm/helper.c | 29 | --- a/fpu/softfloat-specialize.c.inc |
34 | +++ b/target/arm/helper.c | 30 | +++ b/fpu/softfloat-specialize.c.inc |
35 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo cp_reginfo[] = { | 31 | @@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status) |
36 | .opc0 = 3, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 1, | 32 | #if defined(TARGET_SPARC) || defined(TARGET_M68K) |
37 | .access = PL1_RW, .accessfn = access_tvm_trvm, | 33 | /* Sign bit clear, all frac bits set */ |
38 | .fgt = FGT_CONTEXTIDR_EL1, | 34 | dnan_pattern = 0b01111111; |
39 | + .nv2_redirect_offset = 0x108 | NV2_REDIR_NV1, | 35 | -#elif defined(TARGET_I386) || defined(TARGET_X86_64) |
40 | .secure = ARM_CP_SECSTATE_NS, | 36 | - /* Sign bit set, most significant frac bit set */ |
41 | .fieldoffset = offsetof(CPUARMState, cp15.contextidr_el[1]), | 37 | - dnan_pattern = 0b11000000; |
42 | .resetvalue = 0, .writefn = contextidr_write, .raw_writefn = raw_write, }, | 38 | #elif defined(TARGET_HPPA) |
43 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo v6_cp_reginfo[] = { | 39 | /* Sign bit clear, msb-1 frac bit set */ |
44 | { .name = "CPACR", .state = ARM_CP_STATE_BOTH, .opc0 = 3, | 40 | dnan_pattern = 0b00100000; |
45 | .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 2, .accessfn = cpacr_access, | ||
46 | .fgt = FGT_CPACR_EL1, | ||
47 | + .nv2_redirect_offset = 0x100 | NV2_REDIR_NV1, | ||
48 | .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.cpacr_el1), | ||
49 | .resetfn = cpacr_reset, .writefn = cpacr_write, .readfn = cpacr_read }, | ||
50 | }; | ||
51 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo v7_cp_reginfo[] = { | ||
52 | .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 1, .opc2 = 0, | ||
53 | .access = PL1_RW, .accessfn = access_tvm_trvm, | ||
54 | .fgt = FGT_AFSR0_EL1, | ||
55 | + .nv2_redirect_offset = 0x128 | NV2_REDIR_NV1, | ||
56 | .type = ARM_CP_CONST, .resetvalue = 0 }, | ||
57 | { .name = "AFSR1_EL1", .state = ARM_CP_STATE_BOTH, | ||
58 | .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 1, .opc2 = 1, | ||
59 | .access = PL1_RW, .accessfn = access_tvm_trvm, | ||
60 | .fgt = FGT_AFSR1_EL1, | ||
61 | + .nv2_redirect_offset = 0x130 | NV2_REDIR_NV1, | ||
62 | .type = ARM_CP_CONST, .resetvalue = 0 }, | ||
63 | /* | ||
64 | * MAIR can just read-as-written because we don't implement caches | ||
65 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo v7_cp_reginfo[] = { | ||
66 | .opc0 = 3, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 0, | ||
67 | .access = PL1_RW, .accessfn = access_tvm_trvm, | ||
68 | .fgt = FGT_MAIR_EL1, | ||
69 | + .nv2_redirect_offset = 0x140 | NV2_REDIR_NV1, | ||
70 | .fieldoffset = offsetof(CPUARMState, cp15.mair_el[1]), | ||
71 | .resetvalue = 0 }, | ||
72 | { .name = "MAIR_EL3", .state = ARM_CP_STATE_AA64, | ||
73 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { | ||
74 | .opc0 = 3, .crn = 5, .crm = 2, .opc1 = 0, .opc2 = 0, | ||
75 | .access = PL1_RW, .accessfn = access_tvm_trvm, | ||
76 | .fgt = FGT_ESR_EL1, | ||
77 | + .nv2_redirect_offset = 0x138 | NV2_REDIR_NV1, | ||
78 | .fieldoffset = offsetof(CPUARMState, cp15.esr_el[1]), .resetvalue = 0, }, | ||
79 | { .name = "TTBR0_EL1", .state = ARM_CP_STATE_BOTH, | ||
80 | .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 0, | ||
81 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { | ||
82 | .opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2, | ||
83 | .access = PL1_RW, .accessfn = access_tvm_trvm, | ||
84 | .fgt = FGT_TCR_EL1, | ||
85 | + .nv2_redirect_offset = 0x120 | NV2_REDIR_NV1, | ||
86 | .writefn = vmsa_tcr_el12_write, | ||
87 | .raw_writefn = raw_write, | ||
88 | .resetvalue = 0, | ||
89 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo lpae_cp_reginfo[] = { | ||
90 | .opc0 = 3, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 0, | ||
91 | .access = PL1_RW, .accessfn = access_tvm_trvm, | ||
92 | .fgt = FGT_AMAIR_EL1, | ||
93 | + .nv2_redirect_offset = 0x148 | NV2_REDIR_NV1, | ||
94 | .type = ARM_CP_CONST, .resetvalue = 0 }, | ||
95 | /* AMAIR1 is mapped to AMAIR_EL1[63:32] */ | ||
96 | { .name = "AMAIR1", .cp = 15, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 1, | ||
97 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo v8_cp_reginfo[] = { | ||
98 | .type = ARM_CP_ALIAS, | ||
99 | .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 0, | ||
100 | .access = PL1_RW, .accessfn = access_nv1, | ||
101 | + .nv2_redirect_offset = 0x160 | NV2_REDIR_NV1, | ||
102 | .fieldoffset = offsetof(CPUARMState, banked_spsr[BANK_SVC]) }, | ||
103 | /* | ||
104 | * We rely on the access checks not allowing the guest to write to the | ||
105 | @@ -XXX,XX +XXX,XX @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu) | ||
106 | new_reg->writefn = el2_e2h_e12_write; | ||
107 | new_reg->accessfn = el2_e2h_e12_access; | ||
108 | |||
109 | + /* | ||
110 | + * If the _EL1 register is redirected to memory by FEAT_NV2, | ||
111 | + * then it shares the offset with the _EL12 register, | ||
112 | + * and which one is redirected depends on HCR_EL2.NV1. | ||
113 | + */ | ||
114 | + if (new_reg->nv2_redirect_offset) { | ||
115 | + assert(new_reg->nv2_redirect_offset & NV2_REDIR_NV1); | ||
116 | + new_reg->nv2_redirect_offset &= ~NV2_REDIR_NV1; | ||
117 | + new_reg->nv2_redirect_offset |= NV2_REDIR_NO_NV1; | ||
118 | + } | ||
119 | + | ||
120 | ok = g_hash_table_insert(cpu->cp_regs, | ||
121 | (gpointer)(uintptr_t)a->new_key, new_reg); | ||
122 | g_assert(ok); | ||
123 | @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) | ||
124 | { .name = "ACTLR_EL1", .state = ARM_CP_STATE_BOTH, | ||
125 | .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 1, | ||
126 | .access = PL1_RW, .accessfn = access_tacr, | ||
127 | + .nv2_redirect_offset = 0x118, | ||
128 | .type = ARM_CP_CONST, .resetvalue = cpu->reset_auxcr }, | ||
129 | { .name = "ACTLR_EL2", .state = ARM_CP_STATE_BOTH, | ||
130 | .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 0, .opc2 = 1, | ||
131 | @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) | ||
132 | .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 0, | ||
133 | .access = PL1_RW, .accessfn = access_tvm_trvm, | ||
134 | .fgt = FGT_SCTLR_EL1, | ||
135 | + .nv2_redirect_offset = 0x110 | NV2_REDIR_NV1, | ||
136 | .bank_fieldoffsets = { offsetof(CPUARMState, cp15.sctlr_s), | ||
137 | offsetof(CPUARMState, cp15.sctlr_ns) }, | ||
138 | .writefn = sctlr_write, .resetvalue = cpu->reset_sctlr, | ||
139 | -- | 41 | -- |
140 | 2.34.1 | 42 | 2.34.1 | diff view generated by jsdifflib |
1 | Under FEAT_NV2, when HCR_EL2.{NV,NV2} == 0b11 at EL1, accesses to the | 1 | Set the default NaN pattern explicitly, and remove the ifdef from |
---|---|---|---|
2 | registers SPSR_EL2, ELR_EL2, ESR_EL2, FAR_EL2 and TFSR_EL2 (which | 2 | parts64_default_nan(). |
3 | would UNDEF without FEAT_NV or FEAT_NV2) should instead access the | ||
4 | equivalent EL1 registers SPSR_EL1, ELR_EL1, ESR_EL1, FAR_EL1 and | ||
5 | TFSR_EL1. | ||
6 | |||
7 | Because there are only five registers involved and the encoding for | ||
8 | the EL1 register is identical to that of the EL2 register except | ||
9 | that opc1 is 0, we handle this by finding the EL1 register in the | ||
10 | hash table and using it instead. | ||
11 | |||
12 | Note that traps that apply to direct accesses to the EL1 register, | ||
13 | such as active fine-grained traps or other trap bits, do not trigger | ||
14 | when it is accessed via the EL2 encoding in this way. However, some | ||
15 | traps that are defined by the EL2 register may apply. We therefore | ||
16 | call the EL2 register's accessfn first. The only one of the five | ||
17 | which has such traps is TFSR_EL2: make sure its accessfn correctly | ||
18 | handles both FEAT_NV (where we trap to EL2 without checking ATA bits) | ||
19 | and FEAT_NV2 (where we check ATA bits and then redirect to TFSR_EL1). | ||
20 | |||
21 | (We don't need the NV1 tbflag bit until the next patch, but we | ||
22 | introduce it here to avoid putting the NV, NV1, NV2 bits in an | ||
23 | odd order.) | ||
24 | 3 | ||
25 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 4 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
26 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 5 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
27 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 6 | Message-id: 20241202131347.498124-39-peter.maydell@linaro.org |
28 | --- | 7 | --- |
29 | target/arm/cpregs.h | 5 +++++ | 8 | target/hppa/fpu_helper.c | 2 ++ |
30 | target/arm/cpu.h | 2 ++ | 9 | fpu/softfloat-specialize.c.inc | 3 --- |
31 | target/arm/tcg/translate.h | 4 ++++ | 10 | 2 files changed, 2 insertions(+), 3 deletions(-) |
32 | target/arm/helper.c | 13 +++++++++---- | ||
33 | target/arm/tcg/hflags.c | 6 ++++++ | ||
34 | target/arm/tcg/translate-a64.c | 33 ++++++++++++++++++++++++++++++++- | ||
35 | 6 files changed, 58 insertions(+), 5 deletions(-) | ||
36 | 11 | ||
37 | diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h | 12 | diff --git a/target/hppa/fpu_helper.c b/target/hppa/fpu_helper.c |
38 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
39 | --- a/target/arm/cpregs.h | 14 | --- a/target/hppa/fpu_helper.c |
40 | +++ b/target/arm/cpregs.h | 15 | +++ b/target/hppa/fpu_helper.c |
41 | @@ -XXX,XX +XXX,XX @@ enum { | 16 | @@ -XXX,XX +XXX,XX @@ void HELPER(loaded_fr0)(CPUHPPAState *env) |
42 | * ARM pseudocode function CheckSMEAccess(). | 17 | set_float_3nan_prop_rule(float_3nan_prop_abc, &env->fp_status); |
43 | */ | 18 | /* For inf * 0 + NaN, return the input NaN */ |
44 | ARM_CP_SME = 1 << 19, | 19 | set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status); |
45 | + /* | 20 | + /* Default NaN: sign bit clear, msb-1 frac bit set */ |
46 | + * Flag: one of the four EL2 registers which redirect to the | 21 | + set_float_default_nan_pattern(0b00100000, &env->fp_status); |
47 | + * equivalent EL1 register when FEAT_NV2 is enabled. | 22 | } |
48 | + */ | 23 | |
49 | + ARM_CP_NV2_REDIRECT = 1 << 20, | 24 | void cpu_hppa_loaded_fr0(CPUHPPAState *env) |
50 | }; | 25 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc |
51 | |||
52 | /* | ||
53 | diff --git a/target/arm/cpu.h b/target/arm/cpu.h | ||
54 | index XXXXXXX..XXXXXXX 100644 | 26 | index XXXXXXX..XXXXXXX 100644 |
55 | --- a/target/arm/cpu.h | 27 | --- a/fpu/softfloat-specialize.c.inc |
56 | +++ b/target/arm/cpu.h | 28 | +++ b/fpu/softfloat-specialize.c.inc |
57 | @@ -XXX,XX +XXX,XX @@ FIELD(TBFLAG_A64, TRAP_ERET, 29, 1) | 29 | @@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status) |
58 | FIELD(TBFLAG_A64, NAA, 30, 1) | 30 | #if defined(TARGET_SPARC) || defined(TARGET_M68K) |
59 | FIELD(TBFLAG_A64, ATA0, 31, 1) | 31 | /* Sign bit clear, all frac bits set */ |
60 | FIELD(TBFLAG_A64, NV, 32, 1) | 32 | dnan_pattern = 0b01111111; |
61 | +FIELD(TBFLAG_A64, NV1, 33, 1) | 33 | -#elif defined(TARGET_HPPA) |
62 | +FIELD(TBFLAG_A64, NV2, 34, 1) | 34 | - /* Sign bit clear, msb-1 frac bit set */ |
63 | 35 | - dnan_pattern = 0b00100000; | |
64 | /* | 36 | #elif defined(TARGET_HEXAGON) |
65 | * Helpers for using the above. Note that only the A64 accessors use | 37 | /* Sign bit set, all frac bits set. */ |
66 | diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h | 38 | dnan_pattern = 0b11111111; |
67 | index XXXXXXX..XXXXXXX 100644 | ||
68 | --- a/target/arm/tcg/translate.h | ||
69 | +++ b/target/arm/tcg/translate.h | ||
70 | @@ -XXX,XX +XXX,XX @@ typedef struct DisasContext { | ||
71 | bool naa; | ||
72 | /* True if FEAT_NV HCR_EL2.NV is enabled */ | ||
73 | bool nv; | ||
74 | + /* True if NV enabled and HCR_EL2.NV1 is set */ | ||
75 | + bool nv1; | ||
76 | + /* True if NV enabled and HCR_EL2.NV2 is set */ | ||
77 | + bool nv2; | ||
78 | /* | ||
79 | * >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI. | ||
80 | * < 0, set by the current instruction. | ||
81 | diff --git a/target/arm/helper.c b/target/arm/helper.c | ||
82 | index XXXXXXX..XXXXXXX 100644 | ||
83 | --- a/target/arm/helper.c | ||
84 | +++ b/target/arm/helper.c | ||
85 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo el2_cp_reginfo[] = { | ||
86 | .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 7, | ||
87 | .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, | ||
88 | { .name = "ELR_EL2", .state = ARM_CP_STATE_AA64, | ||
89 | - .type = ARM_CP_ALIAS, | ||
90 | + .type = ARM_CP_ALIAS | ARM_CP_NV2_REDIRECT, | ||
91 | .opc0 = 3, .opc1 = 4, .crn = 4, .crm = 0, .opc2 = 1, | ||
92 | .access = PL2_RW, | ||
93 | .fieldoffset = offsetof(CPUARMState, elr_el[2]) }, | ||
94 | { .name = "ESR_EL2", .state = ARM_CP_STATE_BOTH, | ||
95 | + .type = ARM_CP_NV2_REDIRECT, | ||
96 | .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 2, .opc2 = 0, | ||
97 | .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.esr_el[2]) }, | ||
98 | { .name = "FAR_EL2", .state = ARM_CP_STATE_BOTH, | ||
99 | + .type = ARM_CP_NV2_REDIRECT, | ||
100 | .opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 0, | ||
101 | .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el[2]) }, | ||
102 | { .name = "HIFAR", .state = ARM_CP_STATE_AA32, | ||
103 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo el2_cp_reginfo[] = { | ||
104 | .access = PL2_RW, | ||
105 | .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el[2]) }, | ||
106 | { .name = "SPSR_EL2", .state = ARM_CP_STATE_AA64, | ||
107 | - .type = ARM_CP_ALIAS, | ||
108 | + .type = ARM_CP_ALIAS | ARM_CP_NV2_REDIRECT, | ||
109 | .opc0 = 3, .opc1 = 4, .crn = 4, .crm = 0, .opc2 = 0, | ||
110 | .access = PL2_RW, | ||
111 | .fieldoffset = offsetof(CPUARMState, banked_spsr[BANK_HYP]) }, | ||
112 | @@ -XXX,XX +XXX,XX @@ static CPAccessResult access_tfsr_el2(CPUARMState *env, const ARMCPRegInfo *ri, | ||
113 | /* | ||
114 | * TFSR_EL2: similar to generic access_mte(), but we need to | ||
115 | * account for FEAT_NV. At EL1 this must be a FEAT_NV access; | ||
116 | - * we will trap to EL2 and the HCR/SCR traps do not apply. | ||
117 | + * if NV2 is enabled then we will redirect this to TFSR_EL1 | ||
118 | + * after doing the HCR and SCR ATA traps; otherwise this will | ||
119 | + * be a trap to EL2 and the HCR/SCR traps do not apply. | ||
120 | */ | ||
121 | int el = arm_current_el(env); | ||
122 | |||
123 | - if (el == 1) { | ||
124 | + if (el == 1 && (arm_hcr_el2_eff(env) & HCR_NV2)) { | ||
125 | return CP_ACCESS_OK; | ||
126 | } | ||
127 | if (el < 2 && arm_is_el2_enabled(env)) { | ||
128 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo mte_reginfo[] = { | ||
129 | .access = PL1_RW, .accessfn = access_tfsr_el1, | ||
130 | .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[1]) }, | ||
131 | { .name = "TFSR_EL2", .state = ARM_CP_STATE_AA64, | ||
132 | + .type = ARM_CP_NV2_REDIRECT, | ||
133 | .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 6, .opc2 = 0, | ||
134 | .access = PL2_RW, .accessfn = access_tfsr_el2, | ||
135 | .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[2]) }, | ||
136 | diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c | ||
137 | index XXXXXXX..XXXXXXX 100644 | ||
138 | --- a/target/arm/tcg/hflags.c | ||
139 | +++ b/target/arm/tcg/hflags.c | ||
140 | @@ -XXX,XX +XXX,XX @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, | ||
141 | if (el == 1 && (hcr & HCR_NV)) { | ||
142 | DP_TBFLAG_A64(flags, TRAP_ERET, 1); | ||
143 | DP_TBFLAG_A64(flags, NV, 1); | ||
144 | + if (hcr & HCR_NV1) { | ||
145 | + DP_TBFLAG_A64(flags, NV1, 1); | ||
146 | + } | ||
147 | + if (hcr & HCR_NV2) { | ||
148 | + DP_TBFLAG_A64(flags, NV2, 1); | ||
149 | + } | ||
150 | } | ||
151 | |||
152 | if (cpu_isar_feature(aa64_mte, env_archcpu(env))) { | ||
153 | diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c | ||
154 | index XXXXXXX..XXXXXXX 100644 | ||
155 | --- a/target/arm/tcg/translate-a64.c | ||
156 | +++ b/target/arm/tcg/translate-a64.c | ||
157 | @@ -XXX,XX +XXX,XX @@ static void handle_sys(DisasContext *s, bool isread, | ||
158 | const ARMCPRegInfo *ri = get_arm_cp_reginfo(s->cp_regs, key); | ||
159 | bool need_exit_tb = false; | ||
160 | bool nv_trap_to_el2 = false; | ||
161 | + bool nv_redirect_reg = false; | ||
162 | bool skip_fp_access_checks = false; | ||
163 | TCGv_ptr tcg_ri = NULL; | ||
164 | TCGv_i64 tcg_rt; | ||
165 | @@ -XXX,XX +XXX,XX @@ static void handle_sys(DisasContext *s, bool isread, | ||
166 | * for registers accessible at EL1). | ||
167 | */ | ||
168 | skip_fp_access_checks = true; | ||
169 | - if (s->nv && arm_cpreg_traps_in_nv(ri)) { | ||
170 | + if (s->nv2 && (ri->type & ARM_CP_NV2_REDIRECT)) { | ||
171 | + /* | ||
172 | + * This is one of the few EL2 registers which should redirect | ||
173 | + * to the equivalent EL1 register. We do that after running | ||
174 | + * the EL2 register's accessfn. | ||
175 | + */ | ||
176 | + nv_redirect_reg = true; | ||
177 | + } else if (s->nv && arm_cpreg_traps_in_nv(ri)) { | ||
178 | /* | ||
179 | * This register / instruction exists and is an EL2 register, so | ||
180 | * we must trap to EL2 if accessed in nested virtualization EL1 | ||
181 | @@ -XXX,XX +XXX,XX @@ static void handle_sys(DisasContext *s, bool isread, | ||
182 | return; | ||
183 | } | ||
184 | |||
185 | + if (nv_redirect_reg) { | ||
186 | + /* | ||
187 | + * FEAT_NV2 redirection of an EL2 register to an EL1 register. | ||
188 | + * Conveniently in all cases the encoding of the EL1 register is | ||
189 | + * identical to the EL2 register except that opc1 is 0. | ||
190 | + * Get the reginfo for the EL1 register to use for the actual access. | ||
191 | + * We don't use the EL1 register's access function, and | ||
192 | + * fine-grained-traps on EL1 also do not apply here. | ||
193 | + */ | ||
194 | + key = ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, | ||
195 | + crn, crm, op0, 0, op2); | ||
196 | + ri = get_arm_cp_reginfo(s->cp_regs, key); | ||
197 | + assert(ri); | ||
198 | + assert(cp_access_ok(s->current_el, ri, isread)); | ||
199 | + /* | ||
200 | + * We might not have done an update_pc earlier, so check we don't | ||
201 | + * need it. We could support this in future if necessary. | ||
202 | + */ | ||
203 | + assert(!(ri->type & ARM_CP_RAISES_EXC)); | ||
204 | + } | ||
205 | + | ||
206 | /* Handle special cases first */ | ||
207 | switch (ri->type & ARM_CP_SPECIAL_MASK) { | ||
208 | case 0: | ||
209 | @@ -XXX,XX +XXX,XX @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, | ||
210 | dc->sme_trap_nonstreaming = EX_TBFLAG_A64(tb_flags, SME_TRAP_NONSTREAMING); | ||
211 | dc->naa = EX_TBFLAG_A64(tb_flags, NAA); | ||
212 | dc->nv = EX_TBFLAG_A64(tb_flags, NV); | ||
213 | + dc->nv1 = EX_TBFLAG_A64(tb_flags, NV1); | ||
214 | + dc->nv2 = EX_TBFLAG_A64(tb_flags, NV2); | ||
215 | dc->vec_len = 0; | ||
216 | dc->vec_stride = 0; | ||
217 | dc->cp_regs = arm_cpu->cp_regs; | ||
218 | -- | 39 | -- |
219 | 2.34.1 | 40 | 2.34.1 | diff view generated by jsdifflib |
1 | With FEAT_NV2, the condition for when SPSR_EL1.M should report that | 1 | Set the default NaN pattern explicitly for the alpha target. |
---|---|---|---|
2 | an exception was taken from EL2 changes. | ||
3 | 2 | ||
4 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 3 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
5 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 4 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
6 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 5 | Message-id: 20241202131347.498124-40-peter.maydell@linaro.org |
7 | --- | 6 | --- |
8 | target/arm/helper.c | 16 ++++++++++++---- | 7 | target/alpha/cpu.c | 2 ++ |
9 | 1 file changed, 12 insertions(+), 4 deletions(-) | 8 | 1 file changed, 2 insertions(+) |
10 | 9 | ||
11 | diff --git a/target/arm/helper.c b/target/arm/helper.c | 10 | diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c |
12 | index XXXXXXX..XXXXXXX 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
13 | --- a/target/arm/helper.c | 12 | --- a/target/alpha/cpu.c |
14 | +++ b/target/arm/helper.c | 13 | +++ b/target/alpha/cpu.c |
15 | @@ -XXX,XX +XXX,XX @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) | 14 | @@ -XXX,XX +XXX,XX @@ static void alpha_cpu_initfn(Object *obj) |
16 | aarch64_save_sp(env, arm_current_el(env)); | 15 | * operand in Fa. That is float_2nan_prop_ba. |
17 | env->elr_el[new_el] = env->pc; | 16 | */ |
18 | 17 | set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status); | |
19 | - if (cur_el == 1 && new_el == 1 && | 18 | + /* Default NaN: sign bit clear, msb frac bit set */ |
20 | - ((arm_hcr_el2_eff(env) & (HCR_NV | HCR_NV1)) == HCR_NV)) { | 19 | + set_float_default_nan_pattern(0b01000000, &env->fp_status); |
21 | - /* I_ZJRNN: report EL2 in the SPSR by setting M[3:2] to 0b10 */ | 20 | #if defined(CONFIG_USER_ONLY) |
22 | - old_mode = deposit32(old_mode, 2, 2, 2); | 21 | env->flags = ENV_FLAG_PS_USER | ENV_FLAG_FEN; |
23 | + if (cur_el == 1 && new_el == 1) { | 22 | cpu_alpha_store_fpcr(env, (uint64_t)(FPCR_INVD | FPCR_DZED | FPCR_OVFD |
24 | + uint64_t hcr = arm_hcr_el2_eff(env); | ||
25 | + if ((hcr & (HCR_NV | HCR_NV1 | HCR_NV2)) == HCR_NV || | ||
26 | + (hcr & (HCR_NV | HCR_NV2)) == (HCR_NV | HCR_NV2)) { | ||
27 | + /* | ||
28 | + * FEAT_NV, FEAT_NV2 may need to report EL2 in the SPSR | ||
29 | + * by setting M[3:2] to 0b10. | ||
30 | + * If NV2 is disabled, change SPSR when NV,NV1 == 1,0 (I_ZJRNN) | ||
31 | + * If NV2 is enabled, change SPSR when NV is 1 (I_DBTLM) | ||
32 | + */ | ||
33 | + old_mode = deposit32(old_mode, 2, 2, 2); | ||
34 | + } | ||
35 | } | ||
36 | } else { | ||
37 | old_mode = cpsr_read_for_spsr_elx(env); | ||
38 | -- | 23 | -- |
39 | 2.34.1 | 24 | 2.34.1 | diff view generated by jsdifflib |
1 | Enable FEAT_NV on the 'max' CPU, and stop filtering it out for the | 1 | Set the default NaN pattern explicitly for the arm target. |
---|---|---|---|
2 | Neoverse N2 and Neoverse V1 CPUs. We continue to downgrade FEAT_NV2 | 2 | This includes setting it for the old linux-user nwfpe emulation. |
3 | support to FEAT_NV for the latter two CPU types. | 3 | For nwfpe, our default doesn't match the real kernel, but we |
4 | avoid making a behaviour change in this commit. | ||
4 | 5 | ||
5 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 6 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
6 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 7 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
7 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 8 | Message-id: 20241202131347.498124-41-peter.maydell@linaro.org |
8 | --- | 9 | --- |
9 | docs/system/arm/emulation.rst | 1 + | 10 | linux-user/arm/nwfpe/fpa11.c | 5 +++++ |
10 | target/arm/cpu.c | 8 +++++--- | 11 | target/arm/cpu.c | 2 ++ |
11 | target/arm/tcg/cpu64.c | 1 + | 12 | 2 files changed, 7 insertions(+) |
12 | 3 files changed, 7 insertions(+), 3 deletions(-) | ||
13 | 13 | ||
14 | diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst | 14 | diff --git a/linux-user/arm/nwfpe/fpa11.c b/linux-user/arm/nwfpe/fpa11.c |
15 | index XXXXXXX..XXXXXXX 100644 | 15 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/docs/system/arm/emulation.rst | 16 | --- a/linux-user/arm/nwfpe/fpa11.c |
17 | +++ b/docs/system/arm/emulation.rst | 17 | +++ b/linux-user/arm/nwfpe/fpa11.c |
18 | @@ -XXX,XX +XXX,XX @@ the following architecture extensions: | 18 | @@ -XXX,XX +XXX,XX @@ void resetFPA11(void) |
19 | - FEAT_MTE (Memory Tagging Extension) | 19 | * this late date. |
20 | - FEAT_MTE2 (Memory Tagging Extension) | 20 | */ |
21 | - FEAT_MTE3 (MTE Asymmetric Fault Handling) | 21 | set_float_2nan_prop_rule(float_2nan_prop_s_ab, &fpa11->fp_status); |
22 | +- FEAT_NV (Nested Virtualization) | 22 | + /* |
23 | - FEAT_PACIMP (Pointer authentication - IMPLEMENTATION DEFINED algorithm) | 23 | + * Use the same default NaN value as Arm VFP. This doesn't match |
24 | - FEAT_PACQARMA3 (Pointer authentication - QARMA3 algorithm) | 24 | + * the Linux kernel's nwfpe emulation, which uses an all-1s value. |
25 | - FEAT_PACQARMA5 (Pointer authentication - QARMA5 algorithm) | 25 | + */ |
26 | + set_float_default_nan_pattern(0b01000000, &fpa11->fp_status); | ||
27 | } | ||
28 | |||
29 | void SetRoundingMode(const unsigned int opcode) | ||
26 | diff --git a/target/arm/cpu.c b/target/arm/cpu.c | 30 | diff --git a/target/arm/cpu.c b/target/arm/cpu.c |
27 | index XXXXXXX..XXXXXXX 100644 | 31 | index XXXXXXX..XXXXXXX 100644 |
28 | --- a/target/arm/cpu.c | 32 | --- a/target/arm/cpu.c |
29 | +++ b/target/arm/cpu.c | 33 | +++ b/target/arm/cpu.c |
30 | @@ -XXX,XX +XXX,XX @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) | 34 | @@ -XXX,XX +XXX,XX @@ void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook, |
31 | /* FEAT_MPAM (Memory Partitioning and Monitoring Extension) */ | 35 | * the pseudocode function the arguments are in the order c, a, b. |
32 | cpu->isar.id_aa64pfr0 = | 36 | * * 0 * Inf + NaN returns the default NaN if the input NaN is quiet, |
33 | FIELD_DP64(cpu->isar.id_aa64pfr0, ID_AA64PFR0, MPAM, 0); | 37 | * and the input NaN if it is signalling |
34 | - /* FEAT_NV (Nested Virtualization) */ | 38 | + * * Default NaN has sign bit clear, msb frac bit set |
35 | - cpu->isar.id_aa64mmfr2 = | 39 | */ |
36 | - FIELD_DP64(cpu->isar.id_aa64mmfr2, ID_AA64MMFR2, NV, 0); | 40 | static void arm_set_default_fp_behaviours(float_status *s) |
37 | + /* FEAT_NV2 (Enhanced Nested Virtualization support) */ | 41 | { |
38 | + if (FIELD_EX64(cpu->isar.id_aa64mmfr2, ID_AA64MMFR2, NV) > 1) { | 42 | @@ -XXX,XX +XXX,XX @@ static void arm_set_default_fp_behaviours(float_status *s) |
39 | + cpu->isar.id_aa64mmfr2 = | 43 | set_float_2nan_prop_rule(float_2nan_prop_s_ab, s); |
40 | + FIELD_DP64(cpu->isar.id_aa64mmfr2, ID_AA64MMFR2, NV, 1); | 44 | set_float_3nan_prop_rule(float_3nan_prop_s_cab, s); |
41 | + } | 45 | set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, s); |
42 | } | 46 | + set_float_default_nan_pattern(0b01000000, s); |
43 | 47 | } | |
44 | /* MPU can be configured out of a PMSA CPU either by setting has-mpu | 48 | |
45 | diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c | 49 | static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque) |
46 | index XXXXXXX..XXXXXXX 100644 | ||
47 | --- a/target/arm/tcg/cpu64.c | ||
48 | +++ b/target/arm/tcg/cpu64.c | ||
49 | @@ -XXX,XX +XXX,XX @@ void aarch64_max_tcg_initfn(Object *obj) | ||
50 | t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1); /* FEAT_UAO */ | ||
51 | t = FIELD_DP64(t, ID_AA64MMFR2, IESB, 1); /* FEAT_IESB */ | ||
52 | t = FIELD_DP64(t, ID_AA64MMFR2, VARANGE, 1); /* FEAT_LVA */ | ||
53 | + t = FIELD_DP64(t, ID_AA64MMFR2, NV, 1); /* FEAT_NV */ | ||
54 | t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* FEAT_TTST */ | ||
55 | t = FIELD_DP64(t, ID_AA64MMFR2, AT, 1); /* FEAT_LSE2 */ | ||
56 | t = FIELD_DP64(t, ID_AA64MMFR2, IDS, 1); /* FEAT_IDST */ | ||
57 | -- | 50 | -- |
58 | 2.34.1 | 51 | 2.34.1 | diff view generated by jsdifflib |
1 | If FEAT_NV2 redirects a system register access to a memory offset | 1 | Set the default NaN pattern explicitly for loongarch. |
---|---|---|---|
2 | from VNCR_EL2, that access might fault. In this case we need to | ||
3 | report the correct syndrome information: | ||
4 | * Data Abort, from same-EL | ||
5 | * no ISS information | ||
6 | * the VNCR bit (bit 13) is set | ||
7 | |||
8 | and the exception must be taken to EL2. | ||
9 | |||
10 | Save an appropriate syndrome template when generating code; we can | ||
11 | then use that to: | ||
12 | * select the right target EL | ||
13 | * reconstitute a correct final syndrome for the data abort | ||
14 | * report the right syndrome if we take a FEAT_RME granule protection | ||
15 | fault on the VNCR-based write | ||
16 | |||
17 | Note that because VNCR is bit 13, we must start keeping bit 13 in | ||
18 | template syndromes, by adjusting ARM_INSN_START_WORD2_SHIFT. | ||
19 | 2 | ||
20 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 3 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
21 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 4 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
22 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 5 | Message-id: 20241202131347.498124-42-peter.maydell@linaro.org |
23 | --- | 6 | --- |
24 | target/arm/cpu.h | 4 ++-- | 7 | target/loongarch/tcg/fpu_helper.c | 2 ++ |
25 | target/arm/syndrome.h | 20 ++++++++++++++++---- | 8 | 1 file changed, 2 insertions(+) |
26 | target/arm/tcg/tlb_helper.c | 27 +++++++++++++++++++++++++-- | ||
27 | target/arm/tcg/translate-a64.c | 4 ++++ | ||
28 | 4 files changed, 47 insertions(+), 8 deletions(-) | ||
29 | 9 | ||
30 | diff --git a/target/arm/cpu.h b/target/arm/cpu.h | 10 | diff --git a/target/loongarch/tcg/fpu_helper.c b/target/loongarch/tcg/fpu_helper.c |
31 | index XXXXXXX..XXXXXXX 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
32 | --- a/target/arm/cpu.h | 12 | --- a/target/loongarch/tcg/fpu_helper.c |
33 | +++ b/target/arm/cpu.h | 13 | +++ b/target/loongarch/tcg/fpu_helper.c |
34 | @@ -XXX,XX +XXX,XX @@ enum { | 14 | @@ -XXX,XX +XXX,XX @@ void restore_fp_status(CPULoongArchState *env) |
35 | #define TARGET_INSN_START_EXTRA_WORDS 2 | 15 | */ |
36 | 16 | set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status); | |
37 | /* The 2nd extra word holding syndrome info for data aborts does not use | 17 | set_float_3nan_prop_rule(float_3nan_prop_s_cab, &env->fp_status); |
38 | - * the upper 6 bits nor the lower 14 bits. We mask and shift it down to | 18 | + /* Default NaN: sign bit clear, msb frac bit set */ |
39 | + * the upper 6 bits nor the lower 13 bits. We mask and shift it down to | 19 | + set_float_default_nan_pattern(0b01000000, &env->fp_status); |
40 | * help the sleb128 encoder do a better job. | ||
41 | * When restoring the CPU state, we shift it back up. | ||
42 | */ | ||
43 | #define ARM_INSN_START_WORD2_MASK ((1 << 26) - 1) | ||
44 | -#define ARM_INSN_START_WORD2_SHIFT 14 | ||
45 | +#define ARM_INSN_START_WORD2_SHIFT 13 | ||
46 | |||
47 | /* We currently assume float and double are IEEE single and double | ||
48 | precision respectively. | ||
49 | diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h | ||
50 | index XXXXXXX..XXXXXXX 100644 | ||
51 | --- a/target/arm/syndrome.h | ||
52 | +++ b/target/arm/syndrome.h | ||
53 | @@ -XXX,XX +XXX,XX @@ typedef enum { | ||
54 | #define ARM_EL_IL (1 << ARM_EL_IL_SHIFT) | ||
55 | #define ARM_EL_ISV (1 << ARM_EL_ISV_SHIFT) | ||
56 | |||
57 | +/* In the Data Abort syndrome */ | ||
58 | +#define ARM_EL_VNCR (1 << 13) | ||
59 | + | ||
60 | static inline uint32_t syn_get_ec(uint32_t syn) | ||
61 | { | ||
62 | return syn >> ARM_EL_EC_SHIFT; | ||
63 | @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_bxjtrap(int cv, int cond, int rm) | ||
64 | (cv << 24) | (cond << 20) | rm; | ||
65 | } | 20 | } |
66 | 21 | ||
67 | -static inline uint32_t syn_gpc(int s2ptw, int ind, int gpcsc, | 22 | int ieee_ex_to_loongarch(int xcpt) |
68 | +static inline uint32_t syn_gpc(int s2ptw, int ind, int gpcsc, int vncr, | ||
69 | int cm, int s1ptw, int wnr, int fsc) | ||
70 | { | ||
71 | - /* TODO: FEAT_NV2 adds VNCR */ | ||
72 | return (EC_GPC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (s2ptw << 21) | ||
73 | - | (ind << 20) | (gpcsc << 14) | (cm << 8) | (s1ptw << 7) | ||
74 | - | (wnr << 6) | fsc; | ||
75 | + | (ind << 20) | (gpcsc << 14) | (vncr << 13) | (cm << 8) | ||
76 | + | (s1ptw << 7) | (wnr << 6) | fsc; | ||
77 | } | ||
78 | |||
79 | static inline uint32_t syn_insn_abort(int same_el, int ea, int s1ptw, int fsc) | ||
80 | @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_data_abort_with_iss(int same_el, | ||
81 | | (ea << 9) | (cm << 8) | (s1ptw << 7) | (wnr << 6) | fsc; | ||
82 | } | ||
83 | |||
84 | +/* | ||
85 | + * Faults due to FEAT_NV2 VNCR_EL2-based accesses report as same-EL | ||
86 | + * Data Aborts with the VNCR bit set. | ||
87 | + */ | ||
88 | +static inline uint32_t syn_data_abort_vncr(int ea, int wnr, int fsc) | ||
89 | +{ | ||
90 | + return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (1 << ARM_EL_EC_SHIFT) | ||
91 | + | ARM_EL_IL | ARM_EL_VNCR | (wnr << 6) | fsc; | ||
92 | +} | ||
93 | + | ||
94 | static inline uint32_t syn_swstep(int same_el, int isv, int ex) | ||
95 | { | ||
96 | return (EC_SOFTWARESTEP << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT) | ||
97 | diff --git a/target/arm/tcg/tlb_helper.c b/target/arm/tcg/tlb_helper.c | ||
98 | index XXXXXXX..XXXXXXX 100644 | ||
99 | --- a/target/arm/tcg/tlb_helper.c | ||
100 | +++ b/target/arm/tcg/tlb_helper.c | ||
101 | @@ -XXX,XX +XXX,XX @@ static inline uint32_t merge_syn_data_abort(uint32_t template_syn, | ||
102 | * ST64BV, or ST64BV0 insns report syndrome info even for stage-1 | ||
103 | * faults and regardless of the target EL. | ||
104 | */ | ||
105 | - if (!(template_syn & ARM_EL_ISV) || target_el != 2 | ||
106 | + if (template_syn & ARM_EL_VNCR) { | ||
107 | + /* | ||
108 | + * FEAT_NV2 faults on accesses via VNCR_EL2 are a special case: | ||
109 | + * they are always reported as "same EL", even though we are going | ||
110 | + * from EL1 to EL2. | ||
111 | + */ | ||
112 | + assert(!fi->stage2); | ||
113 | + syn = syn_data_abort_vncr(fi->ea, is_write, fsc); | ||
114 | + } else if (!(template_syn & ARM_EL_ISV) || target_el != 2 | ||
115 | || fi->s1ptw || !fi->stage2) { | ||
116 | syn = syn_data_abort_no_iss(same_el, 0, | ||
117 | fi->ea, 0, fi->s1ptw, is_write, fsc); | ||
118 | @@ -XXX,XX +XXX,XX @@ void arm_deliver_fault(ARMCPU *cpu, vaddr addr, | ||
119 | int current_el = arm_current_el(env); | ||
120 | bool same_el; | ||
121 | uint32_t syn, exc, fsr, fsc; | ||
122 | + /* | ||
123 | + * We know this must be a data or insn abort, and that | ||
124 | + * env->exception.syndrome contains the template syndrome set | ||
125 | + * up at translate time. So we can check only the VNCR bit | ||
126 | + * (and indeed syndrome does not have the EC field in it, | ||
127 | + * because we masked that out in disas_set_insn_syndrome()) | ||
128 | + */ | ||
129 | + bool is_vncr = (mmu_idx != MMU_INST_FETCH) && | ||
130 | + (env->exception.syndrome & ARM_EL_VNCR); | ||
131 | + | ||
132 | + if (is_vncr) { | ||
133 | + /* FEAT_NV2 faults on accesses via VNCR_EL2 go to EL2 */ | ||
134 | + target_el = 2; | ||
135 | + } | ||
136 | |||
137 | if (report_as_gpc_exception(cpu, current_el, fi)) { | ||
138 | target_el = 3; | ||
139 | @@ -XXX,XX +XXX,XX @@ void arm_deliver_fault(ARMCPU *cpu, vaddr addr, | ||
140 | |||
141 | syn = syn_gpc(fi->stage2 && fi->type == ARMFault_GPCFOnWalk, | ||
142 | access_type == MMU_INST_FETCH, | ||
143 | - encode_gpcsc(fi), 0, fi->s1ptw, | ||
144 | + encode_gpcsc(fi), is_vncr, | ||
145 | + 0, fi->s1ptw, | ||
146 | access_type == MMU_DATA_STORE, fsc); | ||
147 | |||
148 | env->cp15.mfar_el3 = fi->paddr; | ||
149 | diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c | ||
150 | index XXXXXXX..XXXXXXX 100644 | ||
151 | --- a/target/arm/tcg/translate-a64.c | ||
152 | +++ b/target/arm/tcg/translate-a64.c | ||
153 | @@ -XXX,XX +XXX,XX @@ static void handle_sys(DisasContext *s, bool isread, | ||
154 | MemOp mop = MO_64 | MO_ALIGN | MO_ATOM_IFALIGN; | ||
155 | ARMMMUIdx armmemidx = s->nv2_mem_e20 ? ARMMMUIdx_E20_2 : ARMMMUIdx_E2; | ||
156 | int memidx = arm_to_core_mmu_idx(armmemidx); | ||
157 | + uint32_t syn; | ||
158 | |||
159 | mop |= (s->nv2_mem_be ? MO_BE : MO_LE); | ||
160 | |||
161 | @@ -XXX,XX +XXX,XX @@ static void handle_sys(DisasContext *s, bool isread, | ||
162 | tcg_gen_addi_i64(ptr, ptr, | ||
163 | (ri->nv2_redirect_offset & ~NV2_REDIR_FLAG_MASK)); | ||
164 | tcg_rt = cpu_reg(s, rt); | ||
165 | + | ||
166 | + syn = syn_data_abort_vncr(0, !isread, 0); | ||
167 | + disas_set_insn_syndrome(s, syn); | ||
168 | if (isread) { | ||
169 | tcg_gen_qemu_ld_i64(tcg_rt, ptr, memidx, mop); | ||
170 | } else { | ||
171 | -- | 23 | -- |
172 | 2.34.1 | 24 | 2.34.1 | diff view generated by jsdifflib |
1 | For FEAT_NV2, a new system register VNCR_EL2 holds the base | 1 | Set the default NaN pattern explicitly for m68k. |
---|---|---|---|
2 | address of the memory which nested-guest system register | ||
3 | accesses are redirected to. Implement this register. | ||
4 | 2 | ||
5 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 3 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
6 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 4 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
7 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 5 | Message-id: 20241202131347.498124-43-peter.maydell@linaro.org |
8 | --- | 6 | --- |
9 | target/arm/cpu.h | 3 +++ | 7 | target/m68k/cpu.c | 2 ++ |
10 | target/arm/helper.c | 26 ++++++++++++++++++++++++++ | 8 | fpu/softfloat-specialize.c.inc | 2 +- |
11 | 2 files changed, 29 insertions(+) | 9 | 2 files changed, 3 insertions(+), 1 deletion(-) |
12 | 10 | ||
13 | diff --git a/target/arm/cpu.h b/target/arm/cpu.h | 11 | diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c |
14 | index XXXXXXX..XXXXXXX 100644 | 12 | index XXXXXXX..XXXXXXX 100644 |
15 | --- a/target/arm/cpu.h | 13 | --- a/target/m68k/cpu.c |
16 | +++ b/target/arm/cpu.h | 14 | +++ b/target/m68k/cpu.c |
17 | @@ -XXX,XX +XXX,XX @@ typedef struct CPUArchState { | 15 | @@ -XXX,XX +XXX,XX @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type) |
18 | uint64_t gpccr_el3; | 16 | * preceding paragraph for nonsignaling NaNs. |
19 | uint64_t gptbr_el3; | 17 | */ |
20 | uint64_t mfar_el3; | 18 | set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status); |
21 | + | 19 | + /* Default NaN: sign bit clear, all frac bits set */ |
22 | + /* NV2 register */ | 20 | + set_float_default_nan_pattern(0b01111111, &env->fp_status); |
23 | + uint64_t vncr_el2; | 21 | |
24 | } cp15; | 22 | nan = floatx80_default_nan(&env->fp_status); |
25 | 23 | for (i = 0; i < 8; i++) { | |
26 | struct { | 24 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc |
27 | diff --git a/target/arm/helper.c b/target/arm/helper.c | ||
28 | index XXXXXXX..XXXXXXX 100644 | 25 | index XXXXXXX..XXXXXXX 100644 |
29 | --- a/target/arm/helper.c | 26 | --- a/fpu/softfloat-specialize.c.inc |
30 | +++ b/target/arm/helper.c | 27 | +++ b/fpu/softfloat-specialize.c.inc |
31 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo fgt_reginfo[] = { | 28 | @@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status) |
32 | .access = PL2_RW, .accessfn = access_fgt, | 29 | uint8_t dnan_pattern = status->default_nan_pattern; |
33 | .fieldoffset = offsetof(CPUARMState, cp15.fgt_exec[FGTREG_HFGITR]) }, | 30 | |
34 | }; | 31 | if (dnan_pattern == 0) { |
35 | + | 32 | -#if defined(TARGET_SPARC) || defined(TARGET_M68K) |
36 | +static void vncr_write(CPUARMState *env, const ARMCPRegInfo *ri, | 33 | +#if defined(TARGET_SPARC) |
37 | + uint64_t value) | 34 | /* Sign bit clear, all frac bits set */ |
38 | +{ | 35 | dnan_pattern = 0b01111111; |
39 | + /* | 36 | #elif defined(TARGET_HEXAGON) |
40 | + * Clear the RES0 bottom 12 bits; this means at runtime we can guarantee | ||
41 | + * that VNCR_EL2 + offset is 64-bit aligned. We don't need to do anything | ||
42 | + * about the RESS bits at the top -- we choose the "generate an EL2 | ||
43 | + * translation abort on use" CONSTRAINED UNPREDICTABLE option (i.e. let | ||
44 | + * the ptw.c code detect the resulting invalid address). | ||
45 | + */ | ||
46 | + env->cp15.vncr_el2 = value & ~0xfffULL; | ||
47 | +} | ||
48 | + | ||
49 | +static const ARMCPRegInfo nv2_reginfo[] = { | ||
50 | + { .name = "VNCR_EL2", .state = ARM_CP_STATE_AA64, | ||
51 | + .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 2, .opc2 = 0, | ||
52 | + .access = PL2_RW, | ||
53 | + .writefn = vncr_write, | ||
54 | + .fieldoffset = offsetof(CPUARMState, cp15.vncr_el2) }, | ||
55 | +}; | ||
56 | + | ||
57 | #endif /* TARGET_AARCH64 */ | ||
58 | |||
59 | static CPAccessResult access_predinv(CPUARMState *env, const ARMCPRegInfo *ri, | ||
60 | @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) | ||
61 | define_arm_cp_regs(cpu, rme_mte_reginfo); | ||
62 | } | ||
63 | } | ||
64 | + | ||
65 | + if (cpu_isar_feature(aa64_nv2, cpu)) { | ||
66 | + define_arm_cp_regs(cpu, nv2_reginfo); | ||
67 | + } | ||
68 | #endif | ||
69 | |||
70 | if (cpu_isar_feature(any_predinv, cpu)) { | ||
71 | -- | 37 | -- |
72 | 2.34.1 | 38 | 2.34.1 | diff view generated by jsdifflib |
1 | FEAT_NV requires that when HCR_EL2.{NV,NV1} == {1,1} the handling | 1 | Set the default NaN pattern explicitly for MIPS. Note that this |
---|---|---|---|
2 | of some of the page table attribute bits changes for the EL1&0 | 2 | is our only target which currently changes the default NaN |
3 | translation regime: | 3 | at runtime (which it was previously doing indirectly when it |
4 | 4 | changed the snan_bit_is_one setting). | |
5 | * for block and page descriptors: | ||
6 | - bit [54] holds PXN, not UXN | ||
7 | - bit [53] is RES0, and the effective value of UXN is 0 | ||
8 | - bit [6], AP[1], is treated as 0 | ||
9 | * for table descriptors, when hierarchical permissions are enabled: | ||
10 | - bit [60] holds PXNTable, not UXNTable | ||
11 | - bit [59] is RES0 | ||
12 | - bit [61], APTable[0] is treated as 0 | ||
13 | |||
14 | Implement these changes to the page table attribute handling. | ||
15 | 5 | ||
16 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 6 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
17 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 7 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
18 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 8 | Message-id: 20241202131347.498124-44-peter.maydell@linaro.org |
19 | --- | 9 | --- |
20 | target/arm/ptw.c | 21 +++++++++++++++++++++ | 10 | target/mips/fpu_helper.h | 7 +++++++ |
21 | 1 file changed, 21 insertions(+) | 11 | target/mips/msa.c | 3 +++ |
12 | 2 files changed, 10 insertions(+) | ||
22 | 13 | ||
23 | diff --git a/target/arm/ptw.c b/target/arm/ptw.c | 14 | diff --git a/target/mips/fpu_helper.h b/target/mips/fpu_helper.h |
24 | index XXXXXXX..XXXXXXX 100644 | 15 | index XXXXXXX..XXXXXXX 100644 |
25 | --- a/target/arm/ptw.c | 16 | --- a/target/mips/fpu_helper.h |
26 | +++ b/target/arm/ptw.c | 17 | +++ b/target/mips/fpu_helper.h |
27 | @@ -XXX,XX +XXX,XX @@ static bool lpae_block_desc_valid(ARMCPU *cpu, bool ds, | 18 | @@ -XXX,XX +XXX,XX @@ static inline void restore_snan_bit_mode(CPUMIPSState *env) |
28 | } | 19 | set_float_infzeronan_rule(izn_rule, &env->active_fpu.fp_status); |
20 | nan3_rule = nan2008 ? float_3nan_prop_s_cab : float_3nan_prop_s_abc; | ||
21 | set_float_3nan_prop_rule(nan3_rule, &env->active_fpu.fp_status); | ||
22 | + /* | ||
23 | + * With nan2008, the default NaN value has the sign bit clear and the | ||
24 | + * frac msb set; with the older mode, the sign bit is clear, and all | ||
25 | + * frac bits except the msb are set. | ||
26 | + */ | ||
27 | + set_float_default_nan_pattern(nan2008 ? 0b01000000 : 0b00111111, | ||
28 | + &env->active_fpu.fp_status); | ||
29 | |||
29 | } | 30 | } |
30 | 31 | ||
31 | +static bool nv_nv1_enabled(CPUARMState *env, S1Translate *ptw) | 32 | diff --git a/target/mips/msa.c b/target/mips/msa.c |
32 | +{ | 33 | index XXXXXXX..XXXXXXX 100644 |
33 | + uint64_t hcr = arm_hcr_el2_eff_secstate(env, ptw->in_space); | 34 | --- a/target/mips/msa.c |
34 | + return (hcr & (HCR_NV | HCR_NV1)) == (HCR_NV | HCR_NV1); | 35 | +++ b/target/mips/msa.c |
35 | +} | 36 | @@ -XXX,XX +XXX,XX @@ void msa_reset(CPUMIPSState *env) |
36 | + | 37 | /* Inf * 0 + NaN returns the input NaN */ |
37 | /** | 38 | set_float_infzeronan_rule(float_infzeronan_dnan_never, |
38 | * get_phys_addr_lpae: perform one stage of page table walk, LPAE format | 39 | &env->active_tc.msa_fp_status); |
39 | * | 40 | + /* Default NaN: sign bit clear, frac msb set */ |
40 | @@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, | 41 | + set_float_default_nan_pattern(0b01000000, |
41 | xn = extract64(attrs, 54, 1); | 42 | + &env->active_tc.msa_fp_status); |
42 | pxn = extract64(attrs, 53, 1); | 43 | } |
43 | |||
44 | + if (el == 1 && nv_nv1_enabled(env, ptw)) { | ||
45 | + /* | ||
46 | + * With FEAT_NV, when HCR_EL2.{NV,NV1} == {1,1}, the block/page | ||
47 | + * descriptor bit 54 holds PXN, 53 is RES0, and the effective value | ||
48 | + * of UXN is 0. Similarly for bits 59 and 60 in table descriptors | ||
49 | + * (which we have already folded into bits 53 and 54 of attrs). | ||
50 | + * AP[1] (descriptor bit 6, our ap bit 0) is treated as 0. | ||
51 | + * Similarly, APTable[0] from the table descriptor is treated as 0; | ||
52 | + * we already folded this into AP[1] and squashing that to 0 does | ||
53 | + * the right thing. | ||
54 | + */ | ||
55 | + pxn = xn; | ||
56 | + xn = 0; | ||
57 | + ap &= ~1; | ||
58 | + } | ||
59 | /* | ||
60 | * Note that we modified ptw->in_space earlier for NSTable, but | ||
61 | * result->f.attrs retains a copy of the original security space. | ||
62 | -- | 44 | -- |
63 | 2.34.1 | 45 | 2.34.1 | diff view generated by jsdifflib |
1 | For FEAT_NV, when HCR_EL2.{NV,NV1} is {1,1} PAN is always disabled | 1 | Set the default NaN pattern explicitly for openrisc. |
---|---|---|---|
2 | even when the PSTATE.PAN bit is set. Implement this by having | ||
3 | arm_pan_enabled() return false in this situation. | ||
4 | 2 | ||
5 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 3 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
6 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 4 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
7 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 5 | Message-id: 20241202131347.498124-45-peter.maydell@linaro.org |
8 | --- | 6 | --- |
9 | target/arm/helper.c | 3 +++ | 7 | target/openrisc/cpu.c | 2 ++ |
10 | 1 file changed, 3 insertions(+) | 8 | 1 file changed, 2 insertions(+) |
11 | 9 | ||
12 | diff --git a/target/arm/helper.c b/target/arm/helper.c | 10 | diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c |
13 | index XXXXXXX..XXXXXXX 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/target/arm/helper.c | 12 | --- a/target/openrisc/cpu.c |
15 | +++ b/target/arm/helper.c | 13 | +++ b/target/openrisc/cpu.c |
16 | @@ -XXX,XX +XXX,XX @@ void init_cpreg_list(ARMCPU *cpu) | 14 | @@ -XXX,XX +XXX,XX @@ static void openrisc_cpu_reset_hold(Object *obj, ResetType type) |
17 | static bool arm_pan_enabled(CPUARMState *env) | 15 | */ |
18 | { | 16 | set_float_2nan_prop_rule(float_2nan_prop_x87, &cpu->env.fp_status); |
19 | if (is_a64(env)) { | 17 | |
20 | + if ((arm_hcr_el2_eff(env) & (HCR_NV | HCR_NV1)) == (HCR_NV | HCR_NV1)) { | 18 | + /* Default NaN: sign bit clear, frac msb set */ |
21 | + return false; | 19 | + set_float_default_nan_pattern(0b01000000, &cpu->env.fp_status); |
22 | + } | 20 | |
23 | return env->pstate & PSTATE_PAN; | 21 | #ifndef CONFIG_USER_ONLY |
24 | } else { | 22 | cpu->env.picmr = 0x00000000; |
25 | return env->uncached_cpsr & CPSR_PAN; | ||
26 | -- | 23 | -- |
27 | 2.34.1 | 24 | 2.34.1 | diff view generated by jsdifflib |
1 | We already print various lines of information when we take an | 1 | Set the default NaN pattern explicitly for ppc. |
---|---|---|---|
2 | exception, including the ELR and (if relevant) the FAR. Now | ||
3 | that FEAT_NV means that we might report something other than | ||
4 | the old PSTATE to the guest as the SPSR, it's worth logging | ||
5 | this as well. | ||
6 | 2 | ||
7 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 3 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
8 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 4 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
9 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 5 | Message-id: 20241202131347.498124-46-peter.maydell@linaro.org |
10 | --- | 6 | --- |
11 | target/arm/helper.c | 1 + | 7 | target/ppc/cpu_init.c | 4 ++++ |
12 | 1 file changed, 1 insertion(+) | 8 | 1 file changed, 4 insertions(+) |
13 | 9 | ||
14 | diff --git a/target/arm/helper.c b/target/arm/helper.c | 10 | diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c |
15 | index XXXXXXX..XXXXXXX 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/target/arm/helper.c | 12 | --- a/target/ppc/cpu_init.c |
17 | +++ b/target/arm/helper.c | 13 | +++ b/target/ppc/cpu_init.c |
18 | @@ -XXX,XX +XXX,XX @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) | 14 | @@ -XXX,XX +XXX,XX @@ static void ppc_cpu_reset_hold(Object *obj, ResetType type) |
19 | } | 15 | set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status); |
20 | env->banked_spsr[aarch64_banked_spsr_index(new_el)] = old_mode; | 16 | set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->vec_status); |
21 | 17 | ||
22 | + qemu_log_mask(CPU_LOG_INT, "...with SPSR 0x%x\n", old_mode); | 18 | + /* Default NaN: sign bit clear, set frac msb */ |
23 | qemu_log_mask(CPU_LOG_INT, "...with ELR 0x%" PRIx64 "\n", | 19 | + set_float_default_nan_pattern(0b01000000, &env->fp_status); |
24 | env->elr_el[new_el]); | 20 | + set_float_default_nan_pattern(0b01000000, &env->vec_status); |
21 | + | ||
22 | for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) { | ||
23 | ppc_spr_t *spr = &env->spr_cb[i]; | ||
25 | 24 | ||
26 | -- | 25 | -- |
27 | 2.34.1 | 26 | 2.34.1 | diff view generated by jsdifflib |
1 | FEAT_NV requires that when HCR_EL2.{NV,NV1} == {1,0} and an exception | 1 | Set the default NaN pattern explicitly for sh4. Note that sh4 |
---|---|---|---|
2 | is taken from EL1 to EL1 then the reported EL in SPSR_EL1.M should be | 2 | is one of the only three targets (the others being HPPA and |
3 | EL2, not EL1. Implement this behaviour. | 3 | sometimes MIPS) that has snan_bit_is_one set. |
4 | 4 | ||
5 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 5 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
6 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 6 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
7 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 7 | Message-id: 20241202131347.498124-47-peter.maydell@linaro.org |
8 | --- | 8 | --- |
9 | target/arm/helper.c | 6 ++++++ | 9 | target/sh4/cpu.c | 2 ++ |
10 | 1 file changed, 6 insertions(+) | 10 | 1 file changed, 2 insertions(+) |
11 | 11 | ||
12 | diff --git a/target/arm/helper.c b/target/arm/helper.c | 12 | diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c |
13 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/target/arm/helper.c | 14 | --- a/target/sh4/cpu.c |
15 | +++ b/target/arm/helper.c | 15 | +++ b/target/sh4/cpu.c |
16 | @@ -XXX,XX +XXX,XX @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) | 16 | @@ -XXX,XX +XXX,XX @@ static void superh_cpu_reset_hold(Object *obj, ResetType type) |
17 | old_mode = pstate_read(env); | 17 | set_flush_to_zero(1, &env->fp_status); |
18 | aarch64_save_sp(env, arm_current_el(env)); | 18 | #endif |
19 | env->elr_el[new_el] = env->pc; | 19 | set_default_nan_mode(1, &env->fp_status); |
20 | + | 20 | + /* sign bit clear, set all frac bits other than msb */ |
21 | + if (cur_el == 1 && new_el == 1 && | 21 | + set_float_default_nan_pattern(0b00111111, &env->fp_status); |
22 | + ((arm_hcr_el2_eff(env) & (HCR_NV | HCR_NV1)) == HCR_NV)) { | 22 | } |
23 | + /* I_ZJRNN: report EL2 in the SPSR by setting M[3:2] to 0b10 */ | 23 | |
24 | + old_mode = deposit32(old_mode, 2, 2, 2); | 24 | static void superh_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) |
25 | + } | ||
26 | } else { | ||
27 | old_mode = cpsr_read_for_spsr_elx(env); | ||
28 | env->elr_el[new_el] = env->regs[15]; | ||
29 | -- | 25 | -- |
30 | 2.34.1 | 26 | 2.34.1 | diff view generated by jsdifflib |
1 | FEAT_NV requires that when HCR_EL2.NV is set reads of the CurrentEL | 1 | Set the default NaN pattern explicitly for rx. |
---|---|---|---|
2 | register from EL1 always report EL2 rather than the real EL. | ||
3 | Implement this. | ||
4 | 2 | ||
5 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 3 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
6 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 4 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
7 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 5 | Message-id: 20241202131347.498124-48-peter.maydell@linaro.org |
8 | --- | 6 | --- |
9 | target/arm/tcg/translate-a64.c | 9 +++++++-- | 7 | target/rx/cpu.c | 2 ++ |
10 | 1 file changed, 7 insertions(+), 2 deletions(-) | 8 | 1 file changed, 2 insertions(+) |
11 | 9 | ||
12 | diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c | 10 | diff --git a/target/rx/cpu.c b/target/rx/cpu.c |
13 | index XXXXXXX..XXXXXXX 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/target/arm/tcg/translate-a64.c | 12 | --- a/target/rx/cpu.c |
15 | +++ b/target/arm/tcg/translate-a64.c | 13 | +++ b/target/rx/cpu.c |
16 | @@ -XXX,XX +XXX,XX @@ static void handle_sys(DisasContext *s, bool isread, | 14 | @@ -XXX,XX +XXX,XX @@ static void rx_cpu_reset_hold(Object *obj, ResetType type) |
17 | } | 15 | * then prefer dest over source", which is float_2nan_prop_s_ab. |
18 | return; | 16 | */ |
19 | case ARM_CP_CURRENTEL: | 17 | set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status); |
20 | - /* Reads as current EL value from pstate, which is | 18 | + /* Default NaN value: sign bit clear, set frac msb */ |
21 | + { | 19 | + set_float_default_nan_pattern(0b01000000, &env->fp_status); |
22 | + /* | 20 | } |
23 | + * Reads as current EL value from pstate, which is | 21 | |
24 | * guaranteed to be constant by the tb flags. | 22 | static ObjectClass *rx_cpu_class_by_name(const char *cpu_model) |
25 | + * For nested virt we should report EL2. | ||
26 | */ | ||
27 | + int el = s->nv ? 2 : s->current_el; | ||
28 | tcg_rt = cpu_reg(s, rt); | ||
29 | - tcg_gen_movi_i64(tcg_rt, s->current_el << 2); | ||
30 | + tcg_gen_movi_i64(tcg_rt, el << 2); | ||
31 | return; | ||
32 | + } | ||
33 | case ARM_CP_DC_ZVA: | ||
34 | /* Writes clear the aligned block of memory which rt points into. */ | ||
35 | if (s->mte_active[0]) { | ||
36 | -- | 23 | -- |
37 | 2.34.1 | 24 | 2.34.1 | diff view generated by jsdifflib |
1 | The TBFLAG_A64 TB flag bits go in flags2, which for AArch64 guests | 1 | Set the default NaN pattern explicitly for s390x. |
---|---|---|---|
2 | we know is 64 bits. However at the moment we use FIELD_EX32() and | ||
3 | FIELD_DP32() to read and write these bits, which only works for | ||
4 | bits 0 to 31. Since we're about to add a flag that uses bit 32, | ||
5 | switch to FIELD_EX64() and FIELD_DP64() so that this will work. | ||
6 | 2 | ||
7 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 3 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
8 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 4 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
9 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 5 | Message-id: 20241202131347.498124-49-peter.maydell@linaro.org |
10 | --- | 6 | --- |
11 | target/arm/cpu.h | 8 +++++--- | 7 | target/s390x/cpu.c | 2 ++ |
12 | 1 file changed, 5 insertions(+), 3 deletions(-) | 8 | 1 file changed, 2 insertions(+) |
13 | 9 | ||
14 | diff --git a/target/arm/cpu.h b/target/arm/cpu.h | 10 | diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c |
15 | index XXXXXXX..XXXXXXX 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/target/arm/cpu.h | 12 | --- a/target/s390x/cpu.c |
17 | +++ b/target/arm/cpu.h | 13 | +++ b/target/s390x/cpu.c |
18 | @@ -XXX,XX +XXX,XX @@ FIELD(TBFLAG_A64, NAA, 30, 1) | 14 | @@ -XXX,XX +XXX,XX @@ static void s390_cpu_reset_hold(Object *obj, ResetType type) |
19 | FIELD(TBFLAG_A64, ATA0, 31, 1) | 15 | set_float_3nan_prop_rule(float_3nan_prop_s_abc, &env->fpu_status); |
20 | 16 | set_float_infzeronan_rule(float_infzeronan_dnan_always, | |
21 | /* | 17 | &env->fpu_status); |
22 | - * Helpers for using the above. | 18 | + /* Default NaN value: sign bit clear, frac msb set */ |
23 | + * Helpers for using the above. Note that only the A64 accessors use | 19 | + set_float_default_nan_pattern(0b01000000, &env->fpu_status); |
24 | + * FIELD_DP64() and FIELD_EX64(), because in the other cases the flags | 20 | /* fall through */ |
25 | + * word either is or might be 32 bits only. | 21 | case RESET_TYPE_S390_CPU_NORMAL: |
26 | */ | 22 | env->psw.mask &= ~PSW_MASK_RI; |
27 | #define DP_TBFLAG_ANY(DST, WHICH, VAL) \ | ||
28 | (DST.flags = FIELD_DP32(DST.flags, TBFLAG_ANY, WHICH, VAL)) | ||
29 | #define DP_TBFLAG_A64(DST, WHICH, VAL) \ | ||
30 | - (DST.flags2 = FIELD_DP32(DST.flags2, TBFLAG_A64, WHICH, VAL)) | ||
31 | + (DST.flags2 = FIELD_DP64(DST.flags2, TBFLAG_A64, WHICH, VAL)) | ||
32 | #define DP_TBFLAG_A32(DST, WHICH, VAL) \ | ||
33 | (DST.flags2 = FIELD_DP32(DST.flags2, TBFLAG_A32, WHICH, VAL)) | ||
34 | #define DP_TBFLAG_M32(DST, WHICH, VAL) \ | ||
35 | @@ -XXX,XX +XXX,XX @@ FIELD(TBFLAG_A64, ATA0, 31, 1) | ||
36 | (DST.flags2 = FIELD_DP32(DST.flags2, TBFLAG_AM32, WHICH, VAL)) | ||
37 | |||
38 | #define EX_TBFLAG_ANY(IN, WHICH) FIELD_EX32(IN.flags, TBFLAG_ANY, WHICH) | ||
39 | -#define EX_TBFLAG_A64(IN, WHICH) FIELD_EX32(IN.flags2, TBFLAG_A64, WHICH) | ||
40 | +#define EX_TBFLAG_A64(IN, WHICH) FIELD_EX64(IN.flags2, TBFLAG_A64, WHICH) | ||
41 | #define EX_TBFLAG_A32(IN, WHICH) FIELD_EX32(IN.flags2, TBFLAG_A32, WHICH) | ||
42 | #define EX_TBFLAG_M32(IN, WHICH) FIELD_EX32(IN.flags2, TBFLAG_M32, WHICH) | ||
43 | #define EX_TBFLAG_AM32(IN, WHICH) FIELD_EX32(IN.flags2, TBFLAG_AM32, WHICH) | ||
44 | -- | 23 | -- |
45 | 2.34.1 | 24 | 2.34.1 | diff view generated by jsdifflib |
1 | The HCR_EL2.TSC trap for trapping EL1 execution of SMC instructions | 1 | Set the default NaN pattern explicitly for SPARC, and remove |
---|---|---|---|
2 | has a behaviour change for FEAT_NV when EL3 is not implemented: | 2 | the ifdef from parts64_default_nan. |
3 | |||
4 | * in older architecture versions TSC was required to have no | ||
5 | effect (i.e. the SMC insn UNDEFs) | ||
6 | * with FEAT_NV, when HCR_EL2.NV == 1 the trap must apply | ||
7 | (i.e. SMC traps to EL2, as it already does in all cases when | ||
8 | EL3 is implemented) | ||
9 | * in newer architecture versions, the behaviour either without | ||
10 | FEAT_NV or with FEAT_NV and HCR_EL2.NV == 0 is relaxed to | ||
11 | an IMPDEF choice between UNDEF and trap-to-EL2 (i.e. it is | ||
12 | permitted to always honour HCR_EL2.TSC) for AArch64 only | ||
13 | |||
14 | Add the condition to honour the trap bit when HCR_EL2.NV == 1. We | ||
15 | leave the HCR_EL2.NV == 0 case with the existing (UNDEF) behaviour, | ||
16 | as our IMPDEF choice (both because it avoids a behaviour change | ||
17 | for older CPU models and because we'd have to distinguish AArch32 | ||
18 | from AArch64 if we opted to trap to EL2). | ||
19 | 3 | ||
20 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 4 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
21 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 5 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
22 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 6 | Message-id: 20241202131347.498124-50-peter.maydell@linaro.org |
23 | --- | 7 | --- |
24 | target/arm/tcg/op_helper.c | 16 +++++++++++++--- | 8 | target/sparc/cpu.c | 2 ++ |
25 | 1 file changed, 13 insertions(+), 3 deletions(-) | 9 | fpu/softfloat-specialize.c.inc | 5 +---- |
10 | 2 files changed, 3 insertions(+), 4 deletions(-) | ||
26 | 11 | ||
27 | diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c | 12 | diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c |
28 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
29 | --- a/target/arm/tcg/op_helper.c | 14 | --- a/target/sparc/cpu.c |
30 | +++ b/target/arm/tcg/op_helper.c | 15 | +++ b/target/sparc/cpu.c |
31 | @@ -XXX,XX +XXX,XX @@ void HELPER(pre_smc)(CPUARMState *env, uint32_t syndrome) | 16 | @@ -XXX,XX +XXX,XX @@ static void sparc_cpu_realizefn(DeviceState *dev, Error **errp) |
32 | * | 17 | set_float_3nan_prop_rule(float_3nan_prop_s_cba, &env->fp_status); |
33 | * Conduit SMC, valid call Trap to EL2 PSCI Call | 18 | /* For inf * 0 + NaN, return the input NaN */ |
34 | * Conduit SMC, inval call Trap to EL2 Undef insn | 19 | set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status); |
35 | - * Conduit not SMC Undef insn Undef insn | 20 | + /* Default NaN value: sign bit clear, all frac bits set */ |
36 | + * Conduit not SMC Undef or trap[1] Undef insn | 21 | + set_float_default_nan_pattern(0b01111111, &env->fp_status); |
37 | + * | 22 | |
38 | + * [1] In this case: | 23 | cpu_exec_realizefn(cs, &local_err); |
39 | + * - if HCR_EL2.NV == 1 we must trap to EL2 | 24 | if (local_err != NULL) { |
40 | + * - if HCR_EL2.NV == 0 then newer architecture revisions permit | 25 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc |
41 | + * AArch64 (but not AArch32) to trap to EL2 as an IMPDEF choice | 26 | index XXXXXXX..XXXXXXX 100644 |
42 | + * - otherwise we must UNDEF | 27 | --- a/fpu/softfloat-specialize.c.inc |
43 | + * We take the IMPDEF choice to always UNDEF if HCR_EL2.NV == 0. | 28 | +++ b/fpu/softfloat-specialize.c.inc |
44 | */ | 29 | @@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status) |
45 | 30 | uint8_t dnan_pattern = status->default_nan_pattern; | |
46 | /* On ARMv8 with EL3 AArch64, SMD applies to both S and NS state. | 31 | |
47 | @@ -XXX,XX +XXX,XX @@ void HELPER(pre_smc)(CPUARMState *env, uint32_t syndrome) | 32 | if (dnan_pattern == 0) { |
48 | : smd_flag && !secure; | 33 | -#if defined(TARGET_SPARC) |
49 | 34 | - /* Sign bit clear, all frac bits set */ | |
50 | if (!arm_feature(env, ARM_FEATURE_EL3) && | 35 | - dnan_pattern = 0b01111111; |
51 | + !(arm_hcr_el2_eff(env) & HCR_NV) && | 36 | -#elif defined(TARGET_HEXAGON) |
52 | cpu->psci_conduit != QEMU_PSCI_CONDUIT_SMC) { | 37 | +#if defined(TARGET_HEXAGON) |
53 | - /* If we have no EL3 then SMC always UNDEFs and can't be | 38 | /* Sign bit set, all frac bits set. */ |
54 | - * trapped to EL2. PSCI-via-SMC is a sort of ersatz EL3 | 39 | dnan_pattern = 0b11111111; |
55 | + /* | 40 | #else |
56 | + * If we have no EL3 then traditionally SMC always UNDEFs and can't be | ||
57 | + * trapped to EL2. For nested virtualization, SMC can be trapped to | ||
58 | + * the outer hypervisor. PSCI-via-SMC is a sort of ersatz EL3 | ||
59 | * firmware within QEMU, and we want an EL2 guest to be able | ||
60 | * to forbid its EL1 from making PSCI calls into QEMU's | ||
61 | * "firmware" via HCR.TSC, so for these purposes treat | ||
62 | -- | 41 | -- |
63 | 2.34.1 | 42 | 2.34.1 | diff view generated by jsdifflib |
1 | The alias registers like SCTLR_EL12 only exist when HCR_EL2.E2H | 1 | Set the default NaN pattern explicitly for xtensa. |
---|---|---|---|
2 | is 1; they should UNDEF otherwise. We weren't implementing this. | ||
3 | Add an intercept of the accessfn for these aliases, and implement | ||
4 | the UNDEF check. | ||
5 | 2 | ||
6 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 3 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
7 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 4 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
8 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 5 | Message-id: 20241202131347.498124-51-peter.maydell@linaro.org |
9 | --- | 6 | --- |
10 | target/arm/cpregs.h | 3 ++- | 7 | target/xtensa/cpu.c | 2 ++ |
11 | target/arm/helper.c | 16 ++++++++++++++++ | 8 | 1 file changed, 2 insertions(+) |
12 | 2 files changed, 18 insertions(+), 1 deletion(-) | ||
13 | 9 | ||
14 | diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h | 10 | diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c |
15 | index XXXXXXX..XXXXXXX 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/target/arm/cpregs.h | 12 | --- a/target/xtensa/cpu.c |
17 | +++ b/target/arm/cpregs.h | 13 | +++ b/target/xtensa/cpu.c |
18 | @@ -XXX,XX +XXX,XX @@ struct ARMCPRegInfo { | 14 | @@ -XXX,XX +XXX,XX @@ static void xtensa_cpu_reset_hold(Object *obj, ResetType type) |
19 | CPResetFn *resetfn; | 15 | /* For inf * 0 + NaN, return the input NaN */ |
20 | 16 | set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status); | |
21 | /* | 17 | set_no_signaling_nans(!dfpu, &env->fp_status); |
22 | - * "Original" writefn and readfn. | 18 | + /* Default NaN value: sign bit clear, set frac msb */ |
23 | + * "Original" readfn, writefn, accessfn. | 19 | + set_float_default_nan_pattern(0b01000000, &env->fp_status); |
24 | * For ARMv8.1-VHE register aliases, we overwrite the read/write | 20 | xtensa_use_first_nan(env, !dfpu); |
25 | * accessor functions of various EL1/EL0 to perform the runtime | ||
26 | * check for which sysreg should actually be modified, and then | ||
27 | @@ -XXX,XX +XXX,XX @@ struct ARMCPRegInfo { | ||
28 | */ | ||
29 | CPReadFn *orig_readfn; | ||
30 | CPWriteFn *orig_writefn; | ||
31 | + CPAccessFn *orig_accessfn; | ||
32 | }; | ||
33 | |||
34 | /* | ||
35 | diff --git a/target/arm/helper.c b/target/arm/helper.c | ||
36 | index XXXXXXX..XXXXXXX 100644 | ||
37 | --- a/target/arm/helper.c | ||
38 | +++ b/target/arm/helper.c | ||
39 | @@ -XXX,XX +XXX,XX @@ static void el2_e2h_e12_write(CPUARMState *env, const ARMCPRegInfo *ri, | ||
40 | return ri->orig_writefn(env, ri->opaque, value); | ||
41 | } | 21 | } |
42 | 22 | ||
43 | +static CPAccessResult el2_e2h_e12_access(CPUARMState *env, | ||
44 | + const ARMCPRegInfo *ri, | ||
45 | + bool isread) | ||
46 | +{ | ||
47 | + /* FOO_EL12 aliases only exist when E2H is 1; otherwise they UNDEF */ | ||
48 | + if (!(arm_hcr_el2_eff(env) & HCR_E2H)) { | ||
49 | + return CP_ACCESS_TRAP_UNCATEGORIZED; | ||
50 | + } | ||
51 | + if (ri->orig_accessfn) { | ||
52 | + return ri->orig_accessfn(env, ri->opaque, isread); | ||
53 | + } | ||
54 | + return CP_ACCESS_OK; | ||
55 | +} | ||
56 | + | ||
57 | static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu) | ||
58 | { | ||
59 | struct E2HAlias { | ||
60 | @@ -XXX,XX +XXX,XX @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu) | ||
61 | new_reg->opaque = src_reg; | ||
62 | new_reg->orig_readfn = src_reg->readfn ?: raw_read; | ||
63 | new_reg->orig_writefn = src_reg->writefn ?: raw_write; | ||
64 | + new_reg->orig_accessfn = src_reg->accessfn; | ||
65 | if (!new_reg->raw_readfn) { | ||
66 | new_reg->raw_readfn = raw_read; | ||
67 | } | ||
68 | @@ -XXX,XX +XXX,XX @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu) | ||
69 | } | ||
70 | new_reg->readfn = el2_e2h_e12_read; | ||
71 | new_reg->writefn = el2_e2h_e12_write; | ||
72 | + new_reg->accessfn = el2_e2h_e12_access; | ||
73 | |||
74 | ok = g_hash_table_insert(cpu->cp_regs, | ||
75 | (gpointer)(uintptr_t)a->new_key, new_reg); | ||
76 | -- | 23 | -- |
77 | 2.34.1 | 24 | 2.34.1 | diff view generated by jsdifflib |
1 | The FEAT_NV HCR_EL2.AT bit enables trapping of some address | 1 | Set the default NaN pattern explicitly for hexagon. |
---|---|---|---|
2 | translation instructions from EL1 to EL2. Implement this behaviour. | 2 | Remove the ifdef from parts64_default_nan(); the only |
3 | remaining unconverted targets all use the default case. | ||
3 | 4 | ||
4 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 5 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
5 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 6 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
6 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 7 | Message-id: 20241202131347.498124-52-peter.maydell@linaro.org |
7 | --- | 8 | --- |
8 | target/arm/helper.c | 21 +++++++++++++++------ | 9 | target/hexagon/cpu.c | 2 ++ |
9 | 1 file changed, 15 insertions(+), 6 deletions(-) | 10 | fpu/softfloat-specialize.c.inc | 5 ----- |
11 | 2 files changed, 2 insertions(+), 5 deletions(-) | ||
10 | 12 | ||
11 | diff --git a/target/arm/helper.c b/target/arm/helper.c | 13 | diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c |
12 | index XXXXXXX..XXXXXXX 100644 | 14 | index XXXXXXX..XXXXXXX 100644 |
13 | --- a/target/arm/helper.c | 15 | --- a/target/hexagon/cpu.c |
14 | +++ b/target/arm/helper.c | 16 | +++ b/target/hexagon/cpu.c |
15 | @@ -XXX,XX +XXX,XX @@ static CPAccessResult at_s1e2_access(CPUARMState *env, const ARMCPRegInfo *ri, | 17 | @@ -XXX,XX +XXX,XX @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type) |
16 | return at_e012_access(env, ri, isread); | 18 | |
19 | set_default_nan_mode(1, &env->fp_status); | ||
20 | set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status); | ||
21 | + /* Default NaN value: sign bit set, all frac bits set */ | ||
22 | + set_float_default_nan_pattern(0b11111111, &env->fp_status); | ||
17 | } | 23 | } |
18 | 24 | ||
19 | +static CPAccessResult at_s1e01_access(CPUARMState *env, const ARMCPRegInfo *ri, | 25 | static void hexagon_cpu_disas_set_info(CPUState *s, disassemble_info *info) |
20 | + bool isread) | 26 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc |
21 | +{ | 27 | index XXXXXXX..XXXXXXX 100644 |
22 | + if (arm_current_el(env) == 1 && (arm_hcr_el2_eff(env) & HCR_AT)) { | 28 | --- a/fpu/softfloat-specialize.c.inc |
23 | + return CP_ACCESS_TRAP_EL2; | 29 | +++ b/fpu/softfloat-specialize.c.inc |
24 | + } | 30 | @@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status) |
25 | + return at_e012_access(env, ri, isread); | 31 | uint8_t dnan_pattern = status->default_nan_pattern; |
26 | +} | 32 | |
27 | + | 33 | if (dnan_pattern == 0) { |
28 | static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri, | 34 | -#if defined(TARGET_HEXAGON) |
29 | uint64_t value) | 35 | - /* Sign bit set, all frac bits set. */ |
30 | { | 36 | - dnan_pattern = 0b11111111; |
31 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo v8_cp_reginfo[] = { | 37 | -#else |
32 | .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 0, | 38 | /* |
33 | .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, | 39 | * This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V, |
34 | .fgt = FGT_ATS1E1R, | 40 | * S390, SH4, TriCore, and Xtensa. Our other supported targets |
35 | - .accessfn = at_e012_access, .writefn = ats_write64 }, | 41 | @@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status) |
36 | + .accessfn = at_s1e01_access, .writefn = ats_write64 }, | 42 | /* sign bit clear, set frac msb */ |
37 | { .name = "AT_S1E1W", .state = ARM_CP_STATE_AA64, | 43 | dnan_pattern = 0b01000000; |
38 | .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 1, | 44 | } |
39 | .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, | 45 | -#endif |
40 | .fgt = FGT_ATS1E1W, | 46 | } |
41 | - .accessfn = at_e012_access, .writefn = ats_write64 }, | 47 | assert(dnan_pattern != 0); |
42 | + .accessfn = at_s1e01_access, .writefn = ats_write64 }, | 48 | |
43 | { .name = "AT_S1E0R", .state = ARM_CP_STATE_AA64, | ||
44 | .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 2, | ||
45 | .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, | ||
46 | .fgt = FGT_ATS1E0R, | ||
47 | - .accessfn = at_e012_access, .writefn = ats_write64 }, | ||
48 | + .accessfn = at_s1e01_access, .writefn = ats_write64 }, | ||
49 | { .name = "AT_S1E0W", .state = ARM_CP_STATE_AA64, | ||
50 | .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 3, | ||
51 | .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, | ||
52 | .fgt = FGT_ATS1E0W, | ||
53 | - .accessfn = at_e012_access, .writefn = ats_write64 }, | ||
54 | + .accessfn = at_s1e01_access, .writefn = ats_write64 }, | ||
55 | { .name = "AT_S12E1R", .state = ARM_CP_STATE_AA64, | ||
56 | .opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 4, | ||
57 | .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, | ||
58 | @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo ats1e1_reginfo[] = { | ||
59 | .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 0, | ||
60 | .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, | ||
61 | .fgt = FGT_ATS1E1RP, | ||
62 | - .accessfn = at_e012_access, .writefn = ats_write64 }, | ||
63 | + .accessfn = at_s1e01_access, .writefn = ats_write64 }, | ||
64 | { .name = "AT_S1E1WP", .state = ARM_CP_STATE_AA64, | ||
65 | .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 1, | ||
66 | .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, | ||
67 | .fgt = FGT_ATS1E1WP, | ||
68 | - .accessfn = at_e012_access, .writefn = ats_write64 }, | ||
69 | + .accessfn = at_s1e01_access, .writefn = ats_write64 }, | ||
70 | }; | ||
71 | |||
72 | static const ARMCPRegInfo ats1cp_reginfo[] = { | ||
73 | -- | 49 | -- |
74 | 2.34.1 | 50 | 2.34.1 | diff view generated by jsdifflib |
1 | The hypervisor can deliver (virtual) LPIs to a guest by setting up a | 1 | Set the default NaN pattern explicitly for riscv. |
---|---|---|---|
2 | list register to have an intid which is an LPI. The GIC has to treat | ||
3 | these a little differently to standard interrupt IDs, because LPIs | ||
4 | have no Active state, and so the guest will only EOI them, it will | ||
5 | not also deactivate them. So icv_eoir_write() must do two things: | ||
6 | 2 | ||
7 | * if the LPI ID is not in any list register, we drop the | ||
8 | priority but do not increment the EOI count | ||
9 | * if the LPI ID is in a list register, we immediately deactivate | ||
10 | it, regardless of the split-drop-and-deactivate control | ||
11 | |||
12 | This can be seen in the VirtualWriteEOIR0() and VirtualWriteEOIR1() | ||
13 | pseudocode in the GICv3 architecture specification. | ||
14 | |||
15 | Without this fix, potentially a hypervisor guest might stall because | ||
16 | LPIs get stuck in a bogus Active+Pending state. | ||
17 | |||
18 | Cc: qemu-stable@nongnu.org | ||
19 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 3 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
20 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 4 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
21 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 5 | Message-id: 20241202131347.498124-53-peter.maydell@linaro.org |
22 | --- | 6 | --- |
23 | hw/intc/arm_gicv3_cpuif.c | 17 +++++++++++++---- | 7 | target/riscv/cpu.c | 2 ++ |
24 | 1 file changed, 13 insertions(+), 4 deletions(-) | 8 | 1 file changed, 2 insertions(+) |
25 | 9 | ||
26 | diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c | 10 | diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c |
27 | index XXXXXXX..XXXXXXX 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
28 | --- a/hw/intc/arm_gicv3_cpuif.c | 12 | --- a/target/riscv/cpu.c |
29 | +++ b/hw/intc/arm_gicv3_cpuif.c | 13 | +++ b/target/riscv/cpu.c |
30 | @@ -XXX,XX +XXX,XX @@ static void icv_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri, | 14 | @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type) |
31 | idx = icv_find_active(cs, irq); | 15 | cs->exception_index = RISCV_EXCP_NONE; |
32 | 16 | env->load_res = -1; | |
33 | if (idx < 0) { | 17 | set_default_nan_mode(1, &env->fp_status); |
34 | - /* No valid list register corresponding to EOI ID */ | 18 | + /* Default NaN value: sign bit clear, frac msb set */ |
35 | - icv_increment_eoicount(cs); | 19 | + set_float_default_nan_pattern(0b01000000, &env->fp_status); |
36 | + /* | 20 | env->vill = true; |
37 | + * No valid list register corresponding to EOI ID; if this is a vLPI | 21 | |
38 | + * not in the list regs then do nothing; otherwise increment EOI count | 22 | #ifndef CONFIG_USER_ONLY |
39 | + */ | ||
40 | + if (irq < GICV3_LPI_INTID_START) { | ||
41 | + icv_increment_eoicount(cs); | ||
42 | + } | ||
43 | } else { | ||
44 | uint64_t lr = cs->ich_lr_el2[idx]; | ||
45 | int thisgrp = (lr & ICH_LR_EL2_GROUP) ? GICV3_G1NS : GICV3_G0; | ||
46 | int lr_gprio = ich_lr_prio(lr) & icv_gprio_mask(cs, grp); | ||
47 | |||
48 | if (thisgrp == grp && lr_gprio == dropprio) { | ||
49 | - if (!icv_eoi_split(env, cs)) { | ||
50 | - /* Priority drop and deactivate not split: deactivate irq now */ | ||
51 | + if (!icv_eoi_split(env, cs) || irq >= GICV3_LPI_INTID_START) { | ||
52 | + /* | ||
53 | + * Priority drop and deactivate not split: deactivate irq now. | ||
54 | + * LPIs always get their active state cleared immediately | ||
55 | + * because no separate deactivate is expected. | ||
56 | + */ | ||
57 | icv_deactivate_irq(cs, idx); | ||
58 | } | ||
59 | } | ||
60 | -- | 23 | -- |
61 | 2.34.1 | 24 | 2.34.1 | diff view generated by jsdifflib |
1 | FEAT_NV defines three new bits in HCR_EL2: NV, NV1 and AT. When the | 1 | Set the default NaN pattern explicitly for tricore. |
---|---|---|---|
2 | feature is enabled, allow these bits to be written, and flush the | ||
3 | TLBs for the bits which affect page table interpretation. | ||
4 | 2 | ||
5 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 3 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
6 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 4 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
7 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 5 | Message-id: 20241202131347.498124-54-peter.maydell@linaro.org |
8 | --- | 6 | --- |
9 | target/arm/cpu-features.h | 5 +++++ | 7 | target/tricore/helper.c | 2 ++ |
10 | target/arm/helper.c | 6 +++++- | 8 | 1 file changed, 2 insertions(+) |
11 | 2 files changed, 10 insertions(+), 1 deletion(-) | ||
12 | 9 | ||
13 | diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h | 10 | diff --git a/target/tricore/helper.c b/target/tricore/helper.c |
14 | index XXXXXXX..XXXXXXX 100644 | 11 | index XXXXXXX..XXXXXXX 100644 |
15 | --- a/target/arm/cpu-features.h | 12 | --- a/target/tricore/helper.c |
16 | +++ b/target/arm/cpu-features.h | 13 | +++ b/target/tricore/helper.c |
17 | @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_e0pd(const ARMISARegisters *id) | 14 | @@ -XXX,XX +XXX,XX @@ void fpu_set_state(CPUTriCoreState *env) |
18 | return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, E0PD) != 0; | 15 | set_flush_to_zero(1, &env->fp_status); |
16 | set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status); | ||
17 | set_default_nan_mode(1, &env->fp_status); | ||
18 | + /* Default NaN pattern: sign bit clear, frac msb set */ | ||
19 | + set_float_default_nan_pattern(0b01000000, &env->fp_status); | ||
19 | } | 20 | } |
20 | 21 | ||
21 | +static inline bool isar_feature_aa64_nv(const ARMISARegisters *id) | 22 | uint32_t psw_read(CPUTriCoreState *env) |
22 | +{ | ||
23 | + return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, NV) != 0; | ||
24 | +} | ||
25 | + | ||
26 | static inline bool isar_feature_aa64_pmuv3p1(const ARMISARegisters *id) | ||
27 | { | ||
28 | return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 4 && | ||
29 | diff --git a/target/arm/helper.c b/target/arm/helper.c | ||
30 | index XXXXXXX..XXXXXXX 100644 | ||
31 | --- a/target/arm/helper.c | ||
32 | +++ b/target/arm/helper.c | ||
33 | @@ -XXX,XX +XXX,XX @@ static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask) | ||
34 | if (cpu_isar_feature(aa64_rme, cpu)) { | ||
35 | valid_mask |= HCR_GPF; | ||
36 | } | ||
37 | + if (cpu_isar_feature(aa64_nv, cpu)) { | ||
38 | + valid_mask |= HCR_NV | HCR_NV1 | HCR_AT; | ||
39 | + } | ||
40 | } | ||
41 | |||
42 | if (cpu_isar_feature(any_evt, cpu)) { | ||
43 | @@ -XXX,XX +XXX,XX @@ static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask) | ||
44 | * HCR_DC disables stage1 and enables stage2 translation | ||
45 | * HCR_DCT enables tagging on (disabled) stage1 translation | ||
46 | * HCR_FWB changes the interpretation of stage2 descriptor bits | ||
47 | + * HCR_NV and HCR_NV1 affect interpretation of descriptor bits | ||
48 | */ | ||
49 | if ((env->cp15.hcr_el2 ^ value) & | ||
50 | - (HCR_VM | HCR_PTW | HCR_DC | HCR_DCT | HCR_FWB)) { | ||
51 | + (HCR_VM | HCR_PTW | HCR_DC | HCR_DCT | HCR_FWB | HCR_NV | HCR_NV1)) { | ||
52 | tlb_flush(CPU(cpu)); | ||
53 | } | ||
54 | env->cp15.hcr_el2 = value; | ||
55 | -- | 23 | -- |
56 | 2.34.1 | 24 | 2.34.1 | diff view generated by jsdifflib |
1 | The CTR_EL0 register has some bits which allow the implementation to | 1 | Now that all our targets have bene converted to explicitly specify |
---|---|---|---|
2 | tell the guest that it does not need to do cache maintenance for | 2 | their pattern for the default NaN value we can remove the remaining |
3 | data-to-instruction coherence and instruction-to-data coherence. | 3 | fallback code in parts64_default_nan(). |
4 | QEMU doesn't emulate caches and so our cache maintenance insns are | ||
5 | all NOPs. | ||
6 | |||
7 | We already have some models of specific CPUs where we set these bits | ||
8 | (e.g. the Neoverse V1), but the 'max' CPU still uses the settings it | ||
9 | inherits from Cortex-A57. Set the bits for 'max' as well, so the | ||
10 | guest doesn't need to do unnecessary work. | ||
11 | 4 | ||
12 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 5 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
13 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | 6 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> |
14 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | 7 | Message-id: 20241202131347.498124-55-peter.maydell@linaro.org |
15 | --- | 8 | --- |
16 | target/arm/tcg/cpu64.c | 10 ++++++++++ | 9 | fpu/softfloat-specialize.c.inc | 14 -------------- |
17 | 1 file changed, 10 insertions(+) | 10 | 1 file changed, 14 deletions(-) |
18 | 11 | ||
19 | diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c | 12 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc |
20 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
21 | --- a/target/arm/tcg/cpu64.c | 14 | --- a/fpu/softfloat-specialize.c.inc |
22 | +++ b/target/arm/tcg/cpu64.c | 15 | +++ b/fpu/softfloat-specialize.c.inc |
23 | @@ -XXX,XX +XXX,XX @@ void aarch64_max_tcg_initfn(Object *obj) | 16 | @@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status) |
24 | u = FIELD_DP32(u, CLIDR_EL1, LOUU, 0); | 17 | uint64_t frac; |
25 | cpu->clidr = u; | 18 | uint8_t dnan_pattern = status->default_nan_pattern; |
26 | 19 | ||
27 | + /* | 20 | - if (dnan_pattern == 0) { |
28 | + * Set CTR_EL0.DIC and IDC to tell the guest it doesnt' need to | 21 | - /* |
29 | + * do any cache maintenance for data-to-instruction or | 22 | - * This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V, |
30 | + * instruction-to-guest coherence. (Our cache ops are nops.) | 23 | - * S390, SH4, TriCore, and Xtensa. Our other supported targets |
31 | + */ | 24 | - * do not have floating-point. |
32 | + t = cpu->ctr; | 25 | - */ |
33 | + t = FIELD_DP64(t, CTR_EL0, IDC, 1); | 26 | - if (snan_bit_is_one(status)) { |
34 | + t = FIELD_DP64(t, CTR_EL0, DIC, 1); | 27 | - /* sign bit clear, set all frac bits other than msb */ |
35 | + cpu->ctr = t; | 28 | - dnan_pattern = 0b00111111; |
36 | + | 29 | - } else { |
37 | t = cpu->isar.id_aa64isar0; | 30 | - /* sign bit clear, set frac msb */ |
38 | t = FIELD_DP64(t, ID_AA64ISAR0, AES, 2); /* FEAT_PMULL */ | 31 | - dnan_pattern = 0b01000000; |
39 | t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 1); /* FEAT_SHA1 */ | 32 | - } |
33 | - } | ||
34 | assert(dnan_pattern != 0); | ||
35 | |||
36 | sign = dnan_pattern >> 7; | ||
40 | -- | 37 | -- |
41 | 2.34.1 | 38 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Richard Henderson <richard.henderson@linaro.org> | ||
1 | 2 | ||
3 | Inline pickNaNMulAdd into its only caller. This makes | ||
4 | one assert redundant with the immediately preceding IF. | ||
5 | |||
6 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
7 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
8 | Message-id: 20241203203949.483774-3-richard.henderson@linaro.org | ||
9 | [PMM: keep comment from old code in new location] | ||
10 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
11 | --- | ||
12 | fpu/softfloat-parts.c.inc | 41 +++++++++++++++++++++++++- | ||
13 | fpu/softfloat-specialize.c.inc | 54 ---------------------------------- | ||
14 | 2 files changed, 40 insertions(+), 55 deletions(-) | ||
15 | |||
16 | diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/fpu/softfloat-parts.c.inc | ||
19 | +++ b/fpu/softfloat-parts.c.inc | ||
20 | @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b, | ||
21 | } | ||
22 | |||
23 | if (s->default_nan_mode) { | ||
24 | + /* | ||
25 | + * We guarantee not to require the target to tell us how to | ||
26 | + * pick a NaN if we're always returning the default NaN. | ||
27 | + * But if we're not in default-NaN mode then the target must | ||
28 | + * specify. | ||
29 | + */ | ||
30 | which = 3; | ||
31 | + } else if (infzero) { | ||
32 | + /* | ||
33 | + * Inf * 0 + NaN -- some implementations return the | ||
34 | + * default NaN here, and some return the input NaN. | ||
35 | + */ | ||
36 | + switch (s->float_infzeronan_rule) { | ||
37 | + case float_infzeronan_dnan_never: | ||
38 | + which = 2; | ||
39 | + break; | ||
40 | + case float_infzeronan_dnan_always: | ||
41 | + which = 3; | ||
42 | + break; | ||
43 | + case float_infzeronan_dnan_if_qnan: | ||
44 | + which = is_qnan(c->cls) ? 3 : 2; | ||
45 | + break; | ||
46 | + default: | ||
47 | + g_assert_not_reached(); | ||
48 | + } | ||
49 | } else { | ||
50 | - which = pickNaNMulAdd(a->cls, b->cls, c->cls, infzero, have_snan, s); | ||
51 | + FloatClass cls[3] = { a->cls, b->cls, c->cls }; | ||
52 | + Float3NaNPropRule rule = s->float_3nan_prop_rule; | ||
53 | + | ||
54 | + assert(rule != float_3nan_prop_none); | ||
55 | + if (have_snan && (rule & R_3NAN_SNAN_MASK)) { | ||
56 | + /* We have at least one SNaN input and should prefer it */ | ||
57 | + do { | ||
58 | + which = rule & R_3NAN_1ST_MASK; | ||
59 | + rule >>= R_3NAN_1ST_LENGTH; | ||
60 | + } while (!is_snan(cls[which])); | ||
61 | + } else { | ||
62 | + do { | ||
63 | + which = rule & R_3NAN_1ST_MASK; | ||
64 | + rule >>= R_3NAN_1ST_LENGTH; | ||
65 | + } while (!is_nan(cls[which])); | ||
66 | + } | ||
67 | } | ||
68 | |||
69 | if (which == 3) { | ||
70 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc | ||
71 | index XXXXXXX..XXXXXXX 100644 | ||
72 | --- a/fpu/softfloat-specialize.c.inc | ||
73 | +++ b/fpu/softfloat-specialize.c.inc | ||
74 | @@ -XXX,XX +XXX,XX @@ static int pickNaN(FloatClass a_cls, FloatClass b_cls, | ||
75 | } | ||
76 | } | ||
77 | |||
78 | -/*---------------------------------------------------------------------------- | ||
79 | -| Select which NaN to propagate for a three-input operation. | ||
80 | -| For the moment we assume that no CPU needs the 'larger significand' | ||
81 | -| information. | ||
82 | -| Return values : 0 : a; 1 : b; 2 : c; 3 : default-NaN | ||
83 | -*----------------------------------------------------------------------------*/ | ||
84 | -static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, | ||
85 | - bool infzero, bool have_snan, float_status *status) | ||
86 | -{ | ||
87 | - FloatClass cls[3] = { a_cls, b_cls, c_cls }; | ||
88 | - Float3NaNPropRule rule = status->float_3nan_prop_rule; | ||
89 | - int which; | ||
90 | - | ||
91 | - /* | ||
92 | - * We guarantee not to require the target to tell us how to | ||
93 | - * pick a NaN if we're always returning the default NaN. | ||
94 | - * But if we're not in default-NaN mode then the target must | ||
95 | - * specify. | ||
96 | - */ | ||
97 | - assert(!status->default_nan_mode); | ||
98 | - | ||
99 | - if (infzero) { | ||
100 | - /* | ||
101 | - * Inf * 0 + NaN -- some implementations return the default NaN here, | ||
102 | - * and some return the input NaN. | ||
103 | - */ | ||
104 | - switch (status->float_infzeronan_rule) { | ||
105 | - case float_infzeronan_dnan_never: | ||
106 | - return 2; | ||
107 | - case float_infzeronan_dnan_always: | ||
108 | - return 3; | ||
109 | - case float_infzeronan_dnan_if_qnan: | ||
110 | - return is_qnan(c_cls) ? 3 : 2; | ||
111 | - default: | ||
112 | - g_assert_not_reached(); | ||
113 | - } | ||
114 | - } | ||
115 | - | ||
116 | - assert(rule != float_3nan_prop_none); | ||
117 | - if (have_snan && (rule & R_3NAN_SNAN_MASK)) { | ||
118 | - /* We have at least one SNaN input and should prefer it */ | ||
119 | - do { | ||
120 | - which = rule & R_3NAN_1ST_MASK; | ||
121 | - rule >>= R_3NAN_1ST_LENGTH; | ||
122 | - } while (!is_snan(cls[which])); | ||
123 | - } else { | ||
124 | - do { | ||
125 | - which = rule & R_3NAN_1ST_MASK; | ||
126 | - rule >>= R_3NAN_1ST_LENGTH; | ||
127 | - } while (!is_nan(cls[which])); | ||
128 | - } | ||
129 | - return which; | ||
130 | -} | ||
131 | - | ||
132 | /*---------------------------------------------------------------------------- | ||
133 | | Returns 1 if the double-precision floating-point value `a' is a quiet | ||
134 | | NaN; otherwise returns 0. | ||
135 | -- | ||
136 | 2.34.1 | ||
137 | |||
138 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Richard Henderson <richard.henderson@linaro.org> | ||
1 | 2 | ||
3 | Remove "3" as a special case for which and simply | ||
4 | branch to return the desired value. | ||
5 | |||
6 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
7 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
8 | Message-id: 20241203203949.483774-4-richard.henderson@linaro.org | ||
9 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
10 | --- | ||
11 | fpu/softfloat-parts.c.inc | 20 ++++++++++---------- | ||
12 | 1 file changed, 10 insertions(+), 10 deletions(-) | ||
13 | |||
14 | diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/fpu/softfloat-parts.c.inc | ||
17 | +++ b/fpu/softfloat-parts.c.inc | ||
18 | @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b, | ||
19 | * But if we're not in default-NaN mode then the target must | ||
20 | * specify. | ||
21 | */ | ||
22 | - which = 3; | ||
23 | + goto default_nan; | ||
24 | } else if (infzero) { | ||
25 | /* | ||
26 | * Inf * 0 + NaN -- some implementations return the | ||
27 | @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b, | ||
28 | */ | ||
29 | switch (s->float_infzeronan_rule) { | ||
30 | case float_infzeronan_dnan_never: | ||
31 | - which = 2; | ||
32 | break; | ||
33 | case float_infzeronan_dnan_always: | ||
34 | - which = 3; | ||
35 | - break; | ||
36 | + goto default_nan; | ||
37 | case float_infzeronan_dnan_if_qnan: | ||
38 | - which = is_qnan(c->cls) ? 3 : 2; | ||
39 | + if (is_qnan(c->cls)) { | ||
40 | + goto default_nan; | ||
41 | + } | ||
42 | break; | ||
43 | default: | ||
44 | g_assert_not_reached(); | ||
45 | } | ||
46 | + which = 2; | ||
47 | } else { | ||
48 | FloatClass cls[3] = { a->cls, b->cls, c->cls }; | ||
49 | Float3NaNPropRule rule = s->float_3nan_prop_rule; | ||
50 | @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b, | ||
51 | } | ||
52 | } | ||
53 | |||
54 | - if (which == 3) { | ||
55 | - parts_default_nan(a, s); | ||
56 | - return a; | ||
57 | - } | ||
58 | - | ||
59 | switch (which) { | ||
60 | case 0: | ||
61 | break; | ||
62 | @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b, | ||
63 | parts_silence_nan(a, s); | ||
64 | } | ||
65 | return a; | ||
66 | + | ||
67 | + default_nan: | ||
68 | + parts_default_nan(a, s); | ||
69 | + return a; | ||
70 | } | ||
71 | |||
72 | /* | ||
73 | -- | ||
74 | 2.34.1 | ||
75 | |||
76 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Richard Henderson <richard.henderson@linaro.org> | ||
1 | 2 | ||
3 | Assign the pointer return value to 'a' directly, | ||
4 | rather than going through an intermediary index. | ||
5 | |||
6 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
7 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
8 | Message-id: 20241203203949.483774-5-richard.henderson@linaro.org | ||
9 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
10 | --- | ||
11 | fpu/softfloat-parts.c.inc | 32 ++++++++++---------------------- | ||
12 | 1 file changed, 10 insertions(+), 22 deletions(-) | ||
13 | |||
14 | diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/fpu/softfloat-parts.c.inc | ||
17 | +++ b/fpu/softfloat-parts.c.inc | ||
18 | @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b, | ||
19 | FloatPartsN *c, float_status *s, | ||
20 | int ab_mask, int abc_mask) | ||
21 | { | ||
22 | - int which; | ||
23 | bool infzero = (ab_mask == float_cmask_infzero); | ||
24 | bool have_snan = (abc_mask & float_cmask_snan); | ||
25 | + FloatPartsN *ret; | ||
26 | |||
27 | if (unlikely(have_snan)) { | ||
28 | float_raise(float_flag_invalid | float_flag_invalid_snan, s); | ||
29 | @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b, | ||
30 | default: | ||
31 | g_assert_not_reached(); | ||
32 | } | ||
33 | - which = 2; | ||
34 | + ret = c; | ||
35 | } else { | ||
36 | - FloatClass cls[3] = { a->cls, b->cls, c->cls }; | ||
37 | + FloatPartsN *val[3] = { a, b, c }; | ||
38 | Float3NaNPropRule rule = s->float_3nan_prop_rule; | ||
39 | |||
40 | assert(rule != float_3nan_prop_none); | ||
41 | if (have_snan && (rule & R_3NAN_SNAN_MASK)) { | ||
42 | /* We have at least one SNaN input and should prefer it */ | ||
43 | do { | ||
44 | - which = rule & R_3NAN_1ST_MASK; | ||
45 | + ret = val[rule & R_3NAN_1ST_MASK]; | ||
46 | rule >>= R_3NAN_1ST_LENGTH; | ||
47 | - } while (!is_snan(cls[which])); | ||
48 | + } while (!is_snan(ret->cls)); | ||
49 | } else { | ||
50 | do { | ||
51 | - which = rule & R_3NAN_1ST_MASK; | ||
52 | + ret = val[rule & R_3NAN_1ST_MASK]; | ||
53 | rule >>= R_3NAN_1ST_LENGTH; | ||
54 | - } while (!is_nan(cls[which])); | ||
55 | + } while (!is_nan(ret->cls)); | ||
56 | } | ||
57 | } | ||
58 | |||
59 | - switch (which) { | ||
60 | - case 0: | ||
61 | - break; | ||
62 | - case 1: | ||
63 | - a = b; | ||
64 | - break; | ||
65 | - case 2: | ||
66 | - a = c; | ||
67 | - break; | ||
68 | - default: | ||
69 | - g_assert_not_reached(); | ||
70 | + if (is_snan(ret->cls)) { | ||
71 | + parts_silence_nan(ret, s); | ||
72 | } | ||
73 | - if (is_snan(a->cls)) { | ||
74 | - parts_silence_nan(a, s); | ||
75 | - } | ||
76 | - return a; | ||
77 | + return ret; | ||
78 | |||
79 | default_nan: | ||
80 | parts_default_nan(a, s); | ||
81 | -- | ||
82 | 2.34.1 | ||
83 | |||
84 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Richard Henderson <richard.henderson@linaro.org> | ||
1 | 2 | ||
3 | While all indices into val[] should be in [0-2], the mask | ||
4 | applied is two bits. To help static analysis see there is | ||
5 | no possibility of read beyond the end of the array, pad the | ||
6 | array to 4 entries, with the final being (implicitly) NULL. | ||
7 | |||
8 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
9 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
10 | Message-id: 20241203203949.483774-6-richard.henderson@linaro.org | ||
11 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
12 | --- | ||
13 | fpu/softfloat-parts.c.inc | 2 +- | ||
14 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
15 | |||
16 | diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/fpu/softfloat-parts.c.inc | ||
19 | +++ b/fpu/softfloat-parts.c.inc | ||
20 | @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b, | ||
21 | } | ||
22 | ret = c; | ||
23 | } else { | ||
24 | - FloatPartsN *val[3] = { a, b, c }; | ||
25 | + FloatPartsN *val[R_3NAN_1ST_MASK + 1] = { a, b, c }; | ||
26 | Float3NaNPropRule rule = s->float_3nan_prop_rule; | ||
27 | |||
28 | assert(rule != float_3nan_prop_none); | ||
29 | -- | ||
30 | 2.34.1 | ||
31 | |||
32 | diff view generated by jsdifflib |
1 | Currently the code in target/arm/helper.c mostly checks the PAN bits | 1 | From: Richard Henderson <richard.henderson@linaro.org> |
---|---|---|---|
2 | in env->pstate or env->uncached_cpsr directly when it wants to know | ||
3 | if PAN is enabled, because in most callsites we know whether we are | ||
4 | in AArch64 or AArch32. We do have an arm_pan_enabled() function, but | ||
5 | we only use it in a few places where the code might run in either an | ||
6 | AArch32 or AArch64 context. | ||
7 | 2 | ||
8 | For FEAT_NV, when HCR_EL2.{NV,NV1} is {1,1} PAN is always disabled | 3 | This function is part of the public interface and |
9 | even when the PSTATE.PAN bit is set, the "is PAN enabled" test | 4 | is not "specialized" to any target in any way. |
10 | becomes more complicated. Make all places that check for PAN use | ||
11 | arm_pan_enabled(), so we have a place to put the FEAT_NV test. | ||
12 | 5 | ||
6 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
7 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | ||
8 | Message-id: 20241203203949.483774-7-richard.henderson@linaro.org | ||
13 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 9 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
14 | Reviewed-by: Richard Henderson <richard.henderson@linaro.org> | ||
15 | Tested-by: Miguel Luis <miguel.luis@oracle.com> | ||
16 | --- | 10 | --- |
17 | target/arm/helper.c | 22 +++++++++++----------- | 11 | fpu/softfloat.c | 52 ++++++++++++++++++++++++++++++++++ |
18 | 1 file changed, 11 insertions(+), 11 deletions(-) | 12 | fpu/softfloat-specialize.c.inc | 52 ---------------------------------- |
13 | 2 files changed, 52 insertions(+), 52 deletions(-) | ||
19 | 14 | ||
20 | diff --git a/target/arm/helper.c b/target/arm/helper.c | 15 | diff --git a/fpu/softfloat.c b/fpu/softfloat.c |
21 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100644 |
22 | --- a/target/arm/helper.c | 17 | --- a/fpu/softfloat.c |
23 | +++ b/target/arm/helper.c | 18 | +++ b/fpu/softfloat.c |
24 | @@ -XXX,XX +XXX,XX @@ void init_cpreg_list(ARMCPU *cpu) | 19 | @@ -XXX,XX +XXX,XX @@ void normalizeFloatx80Subnormal(uint64_t aSig, int32_t *zExpPtr, |
25 | g_list_free(keys); | 20 | *zExpPtr = 1 - shiftCount; |
26 | } | 21 | } |
27 | 22 | ||
28 | +static bool arm_pan_enabled(CPUARMState *env) | 23 | +/*---------------------------------------------------------------------------- |
24 | +| Takes two extended double-precision floating-point values `a' and `b', one | ||
25 | +| of which is a NaN, and returns the appropriate NaN result. If either `a' or | ||
26 | +| `b' is a signaling NaN, the invalid exception is raised. | ||
27 | +*----------------------------------------------------------------------------*/ | ||
28 | + | ||
29 | +floatx80 propagateFloatx80NaN(floatx80 a, floatx80 b, float_status *status) | ||
29 | +{ | 30 | +{ |
30 | + if (is_a64(env)) { | 31 | + bool aIsLargerSignificand; |
31 | + return env->pstate & PSTATE_PAN; | 32 | + FloatClass a_cls, b_cls; |
33 | + | ||
34 | + /* This is not complete, but is good enough for pickNaN. */ | ||
35 | + a_cls = (!floatx80_is_any_nan(a) | ||
36 | + ? float_class_normal | ||
37 | + : floatx80_is_signaling_nan(a, status) | ||
38 | + ? float_class_snan | ||
39 | + : float_class_qnan); | ||
40 | + b_cls = (!floatx80_is_any_nan(b) | ||
41 | + ? float_class_normal | ||
42 | + : floatx80_is_signaling_nan(b, status) | ||
43 | + ? float_class_snan | ||
44 | + : float_class_qnan); | ||
45 | + | ||
46 | + if (is_snan(a_cls) || is_snan(b_cls)) { | ||
47 | + float_raise(float_flag_invalid, status); | ||
48 | + } | ||
49 | + | ||
50 | + if (status->default_nan_mode) { | ||
51 | + return floatx80_default_nan(status); | ||
52 | + } | ||
53 | + | ||
54 | + if (a.low < b.low) { | ||
55 | + aIsLargerSignificand = 0; | ||
56 | + } else if (b.low < a.low) { | ||
57 | + aIsLargerSignificand = 1; | ||
32 | + } else { | 58 | + } else { |
33 | + return env->uncached_cpsr & CPSR_PAN; | 59 | + aIsLargerSignificand = (a.high < b.high) ? 1 : 0; |
60 | + } | ||
61 | + | ||
62 | + if (pickNaN(a_cls, b_cls, aIsLargerSignificand, status)) { | ||
63 | + if (is_snan(b_cls)) { | ||
64 | + return floatx80_silence_nan(b, status); | ||
65 | + } | ||
66 | + return b; | ||
67 | + } else { | ||
68 | + if (is_snan(a_cls)) { | ||
69 | + return floatx80_silence_nan(a, status); | ||
70 | + } | ||
71 | + return a; | ||
34 | + } | 72 | + } |
35 | +} | 73 | +} |
36 | + | 74 | + |
37 | /* | 75 | /*---------------------------------------------------------------------------- |
38 | * Some registers are not accessible from AArch32 EL3 if SCR.NS == 0. | 76 | | Takes an abstract floating-point value having sign `zSign', exponent `zExp', |
39 | */ | 77 | | and extended significand formed by the concatenation of `zSig0' and `zSig1', |
40 | @@ -XXX,XX +XXX,XX @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) | 78 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc |
41 | g_assert(ss != ARMSS_Secure); /* ARMv8.4-SecEL2 is 64-bit only */ | 79 | index XXXXXXX..XXXXXXX 100644 |
42 | /* fall through */ | 80 | --- a/fpu/softfloat-specialize.c.inc |
43 | case 1: | 81 | +++ b/fpu/softfloat-specialize.c.inc |
44 | - if (ri->crm == 9 && (env->uncached_cpsr & CPSR_PAN)) { | 82 | @@ -XXX,XX +XXX,XX @@ floatx80 floatx80_silence_nan(floatx80 a, float_status *status) |
45 | + if (ri->crm == 9 && arm_pan_enabled(env)) { | 83 | return a; |
46 | mmu_idx = ARMMMUIdx_Stage1_E1_PAN; | ||
47 | } else { | ||
48 | mmu_idx = ARMMMUIdx_Stage1_E1; | ||
49 | @@ -XXX,XX +XXX,XX @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri, | ||
50 | case 0: | ||
51 | switch (ri->opc1) { | ||
52 | case 0: /* AT S1E1R, AT S1E1W, AT S1E1RP, AT S1E1WP */ | ||
53 | - if (ri->crm == 9 && (env->pstate & PSTATE_PAN)) { | ||
54 | + if (ri->crm == 9 && arm_pan_enabled(env)) { | ||
55 | mmu_idx = regime_e20 ? | ||
56 | ARMMMUIdx_E20_2_PAN : ARMMMUIdx_Stage1_E1_PAN; | ||
57 | } else { | ||
58 | @@ -XXX,XX +XXX,XX @@ ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate) | ||
59 | } | 84 | } |
60 | #endif | 85 | |
61 | 86 | -/*---------------------------------------------------------------------------- | |
62 | -static bool arm_pan_enabled(CPUARMState *env) | 87 | -| Takes two extended double-precision floating-point values `a' and `b', one |
88 | -| of which is a NaN, and returns the appropriate NaN result. If either `a' or | ||
89 | -| `b' is a signaling NaN, the invalid exception is raised. | ||
90 | -*----------------------------------------------------------------------------*/ | ||
91 | - | ||
92 | -floatx80 propagateFloatx80NaN(floatx80 a, floatx80 b, float_status *status) | ||
63 | -{ | 93 | -{ |
64 | - if (is_a64(env)) { | 94 | - bool aIsLargerSignificand; |
65 | - return env->pstate & PSTATE_PAN; | 95 | - FloatClass a_cls, b_cls; |
96 | - | ||
97 | - /* This is not complete, but is good enough for pickNaN. */ | ||
98 | - a_cls = (!floatx80_is_any_nan(a) | ||
99 | - ? float_class_normal | ||
100 | - : floatx80_is_signaling_nan(a, status) | ||
101 | - ? float_class_snan | ||
102 | - : float_class_qnan); | ||
103 | - b_cls = (!floatx80_is_any_nan(b) | ||
104 | - ? float_class_normal | ||
105 | - : floatx80_is_signaling_nan(b, status) | ||
106 | - ? float_class_snan | ||
107 | - : float_class_qnan); | ||
108 | - | ||
109 | - if (is_snan(a_cls) || is_snan(b_cls)) { | ||
110 | - float_raise(float_flag_invalid, status); | ||
111 | - } | ||
112 | - | ||
113 | - if (status->default_nan_mode) { | ||
114 | - return floatx80_default_nan(status); | ||
115 | - } | ||
116 | - | ||
117 | - if (a.low < b.low) { | ||
118 | - aIsLargerSignificand = 0; | ||
119 | - } else if (b.low < a.low) { | ||
120 | - aIsLargerSignificand = 1; | ||
66 | - } else { | 121 | - } else { |
67 | - return env->uncached_cpsr & CPSR_PAN; | 122 | - aIsLargerSignificand = (a.high < b.high) ? 1 : 0; |
123 | - } | ||
124 | - | ||
125 | - if (pickNaN(a_cls, b_cls, aIsLargerSignificand, status)) { | ||
126 | - if (is_snan(b_cls)) { | ||
127 | - return floatx80_silence_nan(b, status); | ||
128 | - } | ||
129 | - return b; | ||
130 | - } else { | ||
131 | - if (is_snan(a_cls)) { | ||
132 | - return floatx80_silence_nan(a, status); | ||
133 | - } | ||
134 | - return a; | ||
68 | - } | 135 | - } |
69 | -} | 136 | -} |
70 | - | 137 | - |
71 | ARMMMUIdx arm_mmu_idx_el(CPUARMState *env, int el) | 138 | /*---------------------------------------------------------------------------- |
72 | { | 139 | | Returns 1 if the quadruple-precision floating-point value `a' is a quiet |
73 | ARMMMUIdx idx; | 140 | | NaN; otherwise returns 0. |
74 | -- | 141 | -- |
75 | 2.34.1 | 142 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Richard Henderson <richard.henderson@linaro.org> | ||
1 | 2 | ||
3 | Unpacking and repacking the parts may be slightly more work | ||
4 | than we did before, but we get to reuse more code. For a | ||
5 | code path handling exceptional values, this is an improvement. | ||
6 | |||
7 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
8 | Message-id: 20241203203949.483774-8-richard.henderson@linaro.org | ||
9 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
10 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | ||
11 | --- | ||
12 | fpu/softfloat.c | 43 +++++-------------------------------------- | ||
13 | 1 file changed, 5 insertions(+), 38 deletions(-) | ||
14 | |||
15 | diff --git a/fpu/softfloat.c b/fpu/softfloat.c | ||
16 | index XXXXXXX..XXXXXXX 100644 | ||
17 | --- a/fpu/softfloat.c | ||
18 | +++ b/fpu/softfloat.c | ||
19 | @@ -XXX,XX +XXX,XX @@ void normalizeFloatx80Subnormal(uint64_t aSig, int32_t *zExpPtr, | ||
20 | |||
21 | floatx80 propagateFloatx80NaN(floatx80 a, floatx80 b, float_status *status) | ||
22 | { | ||
23 | - bool aIsLargerSignificand; | ||
24 | - FloatClass a_cls, b_cls; | ||
25 | + FloatParts128 pa, pb, *pr; | ||
26 | |||
27 | - /* This is not complete, but is good enough for pickNaN. */ | ||
28 | - a_cls = (!floatx80_is_any_nan(a) | ||
29 | - ? float_class_normal | ||
30 | - : floatx80_is_signaling_nan(a, status) | ||
31 | - ? float_class_snan | ||
32 | - : float_class_qnan); | ||
33 | - b_cls = (!floatx80_is_any_nan(b) | ||
34 | - ? float_class_normal | ||
35 | - : floatx80_is_signaling_nan(b, status) | ||
36 | - ? float_class_snan | ||
37 | - : float_class_qnan); | ||
38 | - | ||
39 | - if (is_snan(a_cls) || is_snan(b_cls)) { | ||
40 | - float_raise(float_flag_invalid, status); | ||
41 | - } | ||
42 | - | ||
43 | - if (status->default_nan_mode) { | ||
44 | + if (!floatx80_unpack_canonical(&pa, a, status) || | ||
45 | + !floatx80_unpack_canonical(&pb, b, status)) { | ||
46 | return floatx80_default_nan(status); | ||
47 | } | ||
48 | |||
49 | - if (a.low < b.low) { | ||
50 | - aIsLargerSignificand = 0; | ||
51 | - } else if (b.low < a.low) { | ||
52 | - aIsLargerSignificand = 1; | ||
53 | - } else { | ||
54 | - aIsLargerSignificand = (a.high < b.high) ? 1 : 0; | ||
55 | - } | ||
56 | - | ||
57 | - if (pickNaN(a_cls, b_cls, aIsLargerSignificand, status)) { | ||
58 | - if (is_snan(b_cls)) { | ||
59 | - return floatx80_silence_nan(b, status); | ||
60 | - } | ||
61 | - return b; | ||
62 | - } else { | ||
63 | - if (is_snan(a_cls)) { | ||
64 | - return floatx80_silence_nan(a, status); | ||
65 | - } | ||
66 | - return a; | ||
67 | - } | ||
68 | + pr = parts_pick_nan(&pa, &pb, status); | ||
69 | + return floatx80_round_pack_canonical(pr, status); | ||
70 | } | ||
71 | |||
72 | /*---------------------------------------------------------------------------- | ||
73 | -- | ||
74 | 2.34.1 | diff view generated by jsdifflib |
1 | From: Samuel Tardieu <sam@rfc1149.net> | 1 | From: Richard Henderson <richard.henderson@linaro.org> |
---|---|---|---|
2 | 2 | ||
3 | A SoC will not have a direct access to the NVIC embedded in its ARM | 3 | Inline pickNaN into its only caller. This makes one assert |
4 | core. By aliasing the "num-prio-bits" property similarly to what is | 4 | redundant with the immediately preceding IF. |
5 | done for the "num-irq" one, a SoC can easily configure it on its | 5 | |
6 | armv7m instance. | 6 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> |
7 | |||
8 | Signed-off-by: Samuel Tardieu <sam@rfc1149.net> | ||
9 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | ||
10 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | 7 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> |
11 | Message-id: 20240106181503.1746200-3-sam@rfc1149.net | 8 | Message-id: 20241203203949.483774-9-richard.henderson@linaro.org |
12 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 9 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
13 | --- | 10 | --- |
14 | include/hw/arm/armv7m.h | 1 + | 11 | fpu/softfloat-parts.c.inc | 82 +++++++++++++++++++++++++---- |
15 | hw/arm/armv7m.c | 2 ++ | 12 | fpu/softfloat-specialize.c.inc | 96 ---------------------------------- |
16 | 2 files changed, 3 insertions(+) | 13 | 2 files changed, 73 insertions(+), 105 deletions(-) |
17 | 14 | ||
18 | diff --git a/include/hw/arm/armv7m.h b/include/hw/arm/armv7m.h | 15 | diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc |
19 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100644 |
20 | --- a/include/hw/arm/armv7m.h | 17 | --- a/fpu/softfloat-parts.c.inc |
21 | +++ b/include/hw/arm/armv7m.h | 18 | +++ b/fpu/softfloat-parts.c.inc |
22 | @@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_SIMPLE_TYPE(ARMv7MState, ARMV7M) | 19 | @@ -XXX,XX +XXX,XX @@ static void partsN(return_nan)(FloatPartsN *a, float_status *s) |
23 | * a qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET). | 20 | static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b, |
24 | * + Property "cpu-type": CPU type to instantiate | 21 | float_status *s) |
25 | * + Property "num-irq": number of external IRQ lines | 22 | { |
26 | + * + Property "num-prio-bits": number of priority bits in the NVIC | 23 | + int cmp, which; |
27 | * + Property "memory": MemoryRegion defining the physical address space | 24 | + |
28 | * that CPU accesses see. (The NVIC, bitbanding and other CPU-internal | 25 | if (is_snan(a->cls) || is_snan(b->cls)) { |
29 | * devices will be automatically layered on top of this view.) | 26 | float_raise(float_flag_invalid | float_flag_invalid_snan, s); |
30 | diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c | 27 | } |
28 | |||
29 | if (s->default_nan_mode) { | ||
30 | parts_default_nan(a, s); | ||
31 | - } else { | ||
32 | - int cmp = frac_cmp(a, b); | ||
33 | - if (cmp == 0) { | ||
34 | - cmp = a->sign < b->sign; | ||
35 | - } | ||
36 | + return a; | ||
37 | + } | ||
38 | |||
39 | - if (pickNaN(a->cls, b->cls, cmp > 0, s)) { | ||
40 | - a = b; | ||
41 | - } | ||
42 | + cmp = frac_cmp(a, b); | ||
43 | + if (cmp == 0) { | ||
44 | + cmp = a->sign < b->sign; | ||
45 | + } | ||
46 | + | ||
47 | + switch (s->float_2nan_prop_rule) { | ||
48 | + case float_2nan_prop_s_ab: | ||
49 | if (is_snan(a->cls)) { | ||
50 | - parts_silence_nan(a, s); | ||
51 | + which = 0; | ||
52 | + } else if (is_snan(b->cls)) { | ||
53 | + which = 1; | ||
54 | + } else if (is_qnan(a->cls)) { | ||
55 | + which = 0; | ||
56 | + } else { | ||
57 | + which = 1; | ||
58 | } | ||
59 | + break; | ||
60 | + case float_2nan_prop_s_ba: | ||
61 | + if (is_snan(b->cls)) { | ||
62 | + which = 1; | ||
63 | + } else if (is_snan(a->cls)) { | ||
64 | + which = 0; | ||
65 | + } else if (is_qnan(b->cls)) { | ||
66 | + which = 1; | ||
67 | + } else { | ||
68 | + which = 0; | ||
69 | + } | ||
70 | + break; | ||
71 | + case float_2nan_prop_ab: | ||
72 | + which = is_nan(a->cls) ? 0 : 1; | ||
73 | + break; | ||
74 | + case float_2nan_prop_ba: | ||
75 | + which = is_nan(b->cls) ? 1 : 0; | ||
76 | + break; | ||
77 | + case float_2nan_prop_x87: | ||
78 | + /* | ||
79 | + * This implements x87 NaN propagation rules: | ||
80 | + * SNaN + QNaN => return the QNaN | ||
81 | + * two SNaNs => return the one with the larger significand, silenced | ||
82 | + * two QNaNs => return the one with the larger significand | ||
83 | + * SNaN and a non-NaN => return the SNaN, silenced | ||
84 | + * QNaN and a non-NaN => return the QNaN | ||
85 | + * | ||
86 | + * If we get down to comparing significands and they are the same, | ||
87 | + * return the NaN with the positive sign bit (if any). | ||
88 | + */ | ||
89 | + if (is_snan(a->cls)) { | ||
90 | + if (is_snan(b->cls)) { | ||
91 | + which = cmp > 0 ? 0 : 1; | ||
92 | + } else { | ||
93 | + which = is_qnan(b->cls) ? 1 : 0; | ||
94 | + } | ||
95 | + } else if (is_qnan(a->cls)) { | ||
96 | + if (is_snan(b->cls) || !is_qnan(b->cls)) { | ||
97 | + which = 0; | ||
98 | + } else { | ||
99 | + which = cmp > 0 ? 0 : 1; | ||
100 | + } | ||
101 | + } else { | ||
102 | + which = 1; | ||
103 | + } | ||
104 | + break; | ||
105 | + default: | ||
106 | + g_assert_not_reached(); | ||
107 | + } | ||
108 | + | ||
109 | + if (which) { | ||
110 | + a = b; | ||
111 | + } | ||
112 | + if (is_snan(a->cls)) { | ||
113 | + parts_silence_nan(a, s); | ||
114 | } | ||
115 | return a; | ||
116 | } | ||
117 | diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc | ||
31 | index XXXXXXX..XXXXXXX 100644 | 118 | index XXXXXXX..XXXXXXX 100644 |
32 | --- a/hw/arm/armv7m.c | 119 | --- a/fpu/softfloat-specialize.c.inc |
33 | +++ b/hw/arm/armv7m.c | 120 | +++ b/fpu/softfloat-specialize.c.inc |
34 | @@ -XXX,XX +XXX,XX @@ static void armv7m_instance_init(Object *obj) | 121 | @@ -XXX,XX +XXX,XX @@ bool float32_is_signaling_nan(float32 a_, float_status *status) |
35 | object_initialize_child(obj, "nvic", &s->nvic, TYPE_NVIC); | 122 | } |
36 | object_property_add_alias(obj, "num-irq", | 123 | } |
37 | OBJECT(&s->nvic), "num-irq"); | 124 | |
38 | + object_property_add_alias(obj, "num-prio-bits", | 125 | -/*---------------------------------------------------------------------------- |
39 | + OBJECT(&s->nvic), "num-prio-bits"); | 126 | -| Select which NaN to propagate for a two-input operation. |
40 | 127 | -| IEEE754 doesn't specify all the details of this, so the | |
41 | object_initialize_child(obj, "systick-reg-ns", &s->systick[M_REG_NS], | 128 | -| algorithm is target-specific. |
42 | TYPE_SYSTICK); | 129 | -| The routine is passed various bits of information about the |
130 | -| two NaNs and should return 0 to select NaN a and 1 for NaN b. | ||
131 | -| Note that signalling NaNs are always squashed to quiet NaNs | ||
132 | -| by the caller, by calling floatXX_silence_nan() before | ||
133 | -| returning them. | ||
134 | -| | ||
135 | -| aIsLargerSignificand is only valid if both a and b are NaNs | ||
136 | -| of some kind, and is true if a has the larger significand, | ||
137 | -| or if both a and b have the same significand but a is | ||
138 | -| positive but b is negative. It is only needed for the x87 | ||
139 | -| tie-break rule. | ||
140 | -*----------------------------------------------------------------------------*/ | ||
141 | - | ||
142 | -static int pickNaN(FloatClass a_cls, FloatClass b_cls, | ||
143 | - bool aIsLargerSignificand, float_status *status) | ||
144 | -{ | ||
145 | - /* | ||
146 | - * We guarantee not to require the target to tell us how to | ||
147 | - * pick a NaN if we're always returning the default NaN. | ||
148 | - * But if we're not in default-NaN mode then the target must | ||
149 | - * specify via set_float_2nan_prop_rule(). | ||
150 | - */ | ||
151 | - assert(!status->default_nan_mode); | ||
152 | - | ||
153 | - switch (status->float_2nan_prop_rule) { | ||
154 | - case float_2nan_prop_s_ab: | ||
155 | - if (is_snan(a_cls)) { | ||
156 | - return 0; | ||
157 | - } else if (is_snan(b_cls)) { | ||
158 | - return 1; | ||
159 | - } else if (is_qnan(a_cls)) { | ||
160 | - return 0; | ||
161 | - } else { | ||
162 | - return 1; | ||
163 | - } | ||
164 | - break; | ||
165 | - case float_2nan_prop_s_ba: | ||
166 | - if (is_snan(b_cls)) { | ||
167 | - return 1; | ||
168 | - } else if (is_snan(a_cls)) { | ||
169 | - return 0; | ||
170 | - } else if (is_qnan(b_cls)) { | ||
171 | - return 1; | ||
172 | - } else { | ||
173 | - return 0; | ||
174 | - } | ||
175 | - break; | ||
176 | - case float_2nan_prop_ab: | ||
177 | - if (is_nan(a_cls)) { | ||
178 | - return 0; | ||
179 | - } else { | ||
180 | - return 1; | ||
181 | - } | ||
182 | - break; | ||
183 | - case float_2nan_prop_ba: | ||
184 | - if (is_nan(b_cls)) { | ||
185 | - return 1; | ||
186 | - } else { | ||
187 | - return 0; | ||
188 | - } | ||
189 | - break; | ||
190 | - case float_2nan_prop_x87: | ||
191 | - /* | ||
192 | - * This implements x87 NaN propagation rules: | ||
193 | - * SNaN + QNaN => return the QNaN | ||
194 | - * two SNaNs => return the one with the larger significand, silenced | ||
195 | - * two QNaNs => return the one with the larger significand | ||
196 | - * SNaN and a non-NaN => return the SNaN, silenced | ||
197 | - * QNaN and a non-NaN => return the QNaN | ||
198 | - * | ||
199 | - * If we get down to comparing significands and they are the same, | ||
200 | - * return the NaN with the positive sign bit (if any). | ||
201 | - */ | ||
202 | - if (is_snan(a_cls)) { | ||
203 | - if (is_snan(b_cls)) { | ||
204 | - return aIsLargerSignificand ? 0 : 1; | ||
205 | - } | ||
206 | - return is_qnan(b_cls) ? 1 : 0; | ||
207 | - } else if (is_qnan(a_cls)) { | ||
208 | - if (is_snan(b_cls) || !is_qnan(b_cls)) { | ||
209 | - return 0; | ||
210 | - } else { | ||
211 | - return aIsLargerSignificand ? 0 : 1; | ||
212 | - } | ||
213 | - } else { | ||
214 | - return 1; | ||
215 | - } | ||
216 | - default: | ||
217 | - g_assert_not_reached(); | ||
218 | - } | ||
219 | -} | ||
220 | - | ||
221 | /*---------------------------------------------------------------------------- | ||
222 | | Returns 1 if the double-precision floating-point value `a' is a quiet | ||
223 | | NaN; otherwise returns 0. | ||
43 | -- | 224 | -- |
44 | 2.34.1 | 225 | 2.34.1 |
45 | 226 | ||
46 | 227 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Richard Henderson <richard.henderson@linaro.org> | ||
1 | 2 | ||
3 | Remember if there was an SNaN, and use that to simplify | ||
4 | float_2nan_prop_s_{ab,ba} to only the snan component. | ||
5 | Then, fall through to the corresponding | ||
6 | float_2nan_prop_{ab,ba} case to handle any remaining | ||
7 | nans, which must be quiet. | ||
8 | |||
9 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
10 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | ||
11 | Message-id: 20241203203949.483774-10-richard.henderson@linaro.org | ||
12 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
13 | --- | ||
14 | fpu/softfloat-parts.c.inc | 32 ++++++++++++-------------------- | ||
15 | 1 file changed, 12 insertions(+), 20 deletions(-) | ||
16 | |||
17 | diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/fpu/softfloat-parts.c.inc | ||
20 | +++ b/fpu/softfloat-parts.c.inc | ||
21 | @@ -XXX,XX +XXX,XX @@ static void partsN(return_nan)(FloatPartsN *a, float_status *s) | ||
22 | static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b, | ||
23 | float_status *s) | ||
24 | { | ||
25 | + bool have_snan = false; | ||
26 | int cmp, which; | ||
27 | |||
28 | if (is_snan(a->cls) || is_snan(b->cls)) { | ||
29 | float_raise(float_flag_invalid | float_flag_invalid_snan, s); | ||
30 | + have_snan = true; | ||
31 | } | ||
32 | |||
33 | if (s->default_nan_mode) { | ||
34 | @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b, | ||
35 | |||
36 | switch (s->float_2nan_prop_rule) { | ||
37 | case float_2nan_prop_s_ab: | ||
38 | - if (is_snan(a->cls)) { | ||
39 | - which = 0; | ||
40 | - } else if (is_snan(b->cls)) { | ||
41 | - which = 1; | ||
42 | - } else if (is_qnan(a->cls)) { | ||
43 | - which = 0; | ||
44 | - } else { | ||
45 | - which = 1; | ||
46 | + if (have_snan) { | ||
47 | + which = is_snan(a->cls) ? 0 : 1; | ||
48 | + break; | ||
49 | } | ||
50 | - break; | ||
51 | - case float_2nan_prop_s_ba: | ||
52 | - if (is_snan(b->cls)) { | ||
53 | - which = 1; | ||
54 | - } else if (is_snan(a->cls)) { | ||
55 | - which = 0; | ||
56 | - } else if (is_qnan(b->cls)) { | ||
57 | - which = 1; | ||
58 | - } else { | ||
59 | - which = 0; | ||
60 | - } | ||
61 | - break; | ||
62 | + /* fall through */ | ||
63 | case float_2nan_prop_ab: | ||
64 | which = is_nan(a->cls) ? 0 : 1; | ||
65 | break; | ||
66 | + case float_2nan_prop_s_ba: | ||
67 | + if (have_snan) { | ||
68 | + which = is_snan(b->cls) ? 1 : 0; | ||
69 | + break; | ||
70 | + } | ||
71 | + /* fall through */ | ||
72 | case float_2nan_prop_ba: | ||
73 | which = is_nan(b->cls) ? 1 : 0; | ||
74 | break; | ||
75 | -- | ||
76 | 2.34.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Richard Henderson <richard.henderson@linaro.org> | ||
1 | 2 | ||
3 | Move the fractional comparison to the end of the | ||
4 | float_2nan_prop_x87 case. This is not required for | ||
5 | any other 2nan propagation rule. Reorganize the | ||
6 | x87 case itself to break out of the switch when the | ||
7 | fractional comparison is not required. | ||
8 | |||
9 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
10 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | ||
11 | Message-id: 20241203203949.483774-11-richard.henderson@linaro.org | ||
12 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
13 | --- | ||
14 | fpu/softfloat-parts.c.inc | 19 +++++++++---------- | ||
15 | 1 file changed, 9 insertions(+), 10 deletions(-) | ||
16 | |||
17 | diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/fpu/softfloat-parts.c.inc | ||
20 | +++ b/fpu/softfloat-parts.c.inc | ||
21 | @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b, | ||
22 | return a; | ||
23 | } | ||
24 | |||
25 | - cmp = frac_cmp(a, b); | ||
26 | - if (cmp == 0) { | ||
27 | - cmp = a->sign < b->sign; | ||
28 | - } | ||
29 | - | ||
30 | switch (s->float_2nan_prop_rule) { | ||
31 | case float_2nan_prop_s_ab: | ||
32 | if (have_snan) { | ||
33 | @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b, | ||
34 | * return the NaN with the positive sign bit (if any). | ||
35 | */ | ||
36 | if (is_snan(a->cls)) { | ||
37 | - if (is_snan(b->cls)) { | ||
38 | - which = cmp > 0 ? 0 : 1; | ||
39 | - } else { | ||
40 | + if (!is_snan(b->cls)) { | ||
41 | which = is_qnan(b->cls) ? 1 : 0; | ||
42 | + break; | ||
43 | } | ||
44 | } else if (is_qnan(a->cls)) { | ||
45 | if (is_snan(b->cls) || !is_qnan(b->cls)) { | ||
46 | which = 0; | ||
47 | - } else { | ||
48 | - which = cmp > 0 ? 0 : 1; | ||
49 | + break; | ||
50 | } | ||
51 | } else { | ||
52 | which = 1; | ||
53 | + break; | ||
54 | } | ||
55 | + cmp = frac_cmp(a, b); | ||
56 | + if (cmp == 0) { | ||
57 | + cmp = a->sign < b->sign; | ||
58 | + } | ||
59 | + which = cmp > 0 ? 0 : 1; | ||
60 | break; | ||
61 | default: | ||
62 | g_assert_not_reached(); | ||
63 | -- | ||
64 | 2.34.1 | diff view generated by jsdifflib |
1 | From: Nikita Ostrenkov <n.ostrenkov@gmail.com> | 1 | From: Richard Henderson <richard.henderson@linaro.org> |
---|---|---|---|
2 | 2 | ||
3 | Signed-off-by: Nikita Ostrenkov <n.ostrenkov@gmail.com> | 3 | Replace the "index" selecting between A and B with a result variable |
4 | of the proper type. This improves clarity within the function. | ||
5 | |||
6 | Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||
4 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | 7 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> |
5 | Message-id: 20231219105510.4907-1-n.ostrenkov@gmail.com | 8 | Message-id: 20241203203949.483774-12-richard.henderson@linaro.org |
6 | [PMM: fixed stray whitespace] | ||
7 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 9 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
8 | --- | 10 | --- |
9 | hw/arm/fsl-imx6.c | 3 +++ | 11 | fpu/softfloat-parts.c.inc | 28 +++++++++++++--------------- |
10 | hw/arm/Kconfig | 1 + | 12 | 1 file changed, 13 insertions(+), 15 deletions(-) |
11 | 2 files changed, 4 insertions(+) | ||
12 | 13 | ||
13 | diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c | 14 | diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc |
14 | index XXXXXXX..XXXXXXX 100644 | 15 | index XXXXXXX..XXXXXXX 100644 |
15 | --- a/hw/arm/fsl-imx6.c | 16 | --- a/fpu/softfloat-parts.c.inc |
16 | +++ b/hw/arm/fsl-imx6.c | 17 | +++ b/fpu/softfloat-parts.c.inc |
17 | @@ -XXX,XX +XXX,XX @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) | 18 | @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b, |
18 | qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_FIQ)); | 19 | float_status *s) |
20 | { | ||
21 | bool have_snan = false; | ||
22 | - int cmp, which; | ||
23 | + FloatPartsN *ret; | ||
24 | + int cmp; | ||
25 | |||
26 | if (is_snan(a->cls) || is_snan(b->cls)) { | ||
27 | float_raise(float_flag_invalid | float_flag_invalid_snan, s); | ||
28 | @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b, | ||
29 | switch (s->float_2nan_prop_rule) { | ||
30 | case float_2nan_prop_s_ab: | ||
31 | if (have_snan) { | ||
32 | - which = is_snan(a->cls) ? 0 : 1; | ||
33 | + ret = is_snan(a->cls) ? a : b; | ||
34 | break; | ||
35 | } | ||
36 | /* fall through */ | ||
37 | case float_2nan_prop_ab: | ||
38 | - which = is_nan(a->cls) ? 0 : 1; | ||
39 | + ret = is_nan(a->cls) ? a : b; | ||
40 | break; | ||
41 | case float_2nan_prop_s_ba: | ||
42 | if (have_snan) { | ||
43 | - which = is_snan(b->cls) ? 1 : 0; | ||
44 | + ret = is_snan(b->cls) ? b : a; | ||
45 | break; | ||
46 | } | ||
47 | /* fall through */ | ||
48 | case float_2nan_prop_ba: | ||
49 | - which = is_nan(b->cls) ? 1 : 0; | ||
50 | + ret = is_nan(b->cls) ? b : a; | ||
51 | break; | ||
52 | case float_2nan_prop_x87: | ||
53 | /* | ||
54 | @@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b, | ||
55 | */ | ||
56 | if (is_snan(a->cls)) { | ||
57 | if (!is_snan(b->cls)) { | ||
58 | - which = is_qnan(b->cls) ? 1 : 0; | ||
59 | + ret = is_qnan(b->cls) ? b : a; | ||
60 | break; | ||
61 | } | ||
62 | } else if (is_qnan(a->cls)) { | ||
63 | if (is_snan(b->cls) || !is_qnan(b->cls)) { | ||
64 | - which = 0; | ||
65 | + ret = a; | ||
66 | break; | ||
67 | } | ||
68 | } else { | ||
69 | - which = 1; | ||
70 | + ret = b; | ||
71 | break; | ||
72 | } | ||
73 | cmp = frac_cmp(a, b); | ||
74 | if (cmp == 0) { | ||
75 | cmp = a->sign < b->sign; | ||
76 | } | ||
77 | - which = cmp > 0 ? 0 : 1; | ||
78 | + ret = cmp > 0 ? a : b; | ||
79 | break; | ||
80 | default: | ||
81 | g_assert_not_reached(); | ||
19 | } | 82 | } |
20 | 83 | ||
21 | + /* L2 cache controller */ | 84 | - if (which) { |
22 | + sysbus_create_simple("l2x0", FSL_IMX6_PL310_ADDR, NULL); | 85 | - a = b; |
23 | + | 86 | + if (is_snan(ret->cls)) { |
24 | if (!sysbus_realize(SYS_BUS_DEVICE(&s->ccm), errp)) { | 87 | + parts_silence_nan(ret, s); |
25 | return; | ||
26 | } | 88 | } |
27 | diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig | 89 | - if (is_snan(a->cls)) { |
28 | index XXXXXXX..XXXXXXX 100644 | 90 | - parts_silence_nan(a, s); |
29 | --- a/hw/arm/Kconfig | 91 | - } |
30 | +++ b/hw/arm/Kconfig | 92 | - return a; |
31 | @@ -XXX,XX +XXX,XX @@ config FSL_IMX6 | 93 | + return ret; |
32 | select IMX_I2C | 94 | } |
33 | select IMX_USBPHY | 95 | |
34 | select WDT_IMX2 | 96 | static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b, |
35 | + select PL310 # cache controller | ||
36 | select SDHCI | ||
37 | |||
38 | config ASPEED_SOC | ||
39 | -- | 97 | -- |
40 | 2.34.1 | 98 | 2.34.1 |
41 | 99 | ||
42 | 100 | diff view generated by jsdifflib |
1 | From: Inès Varhol <ines.varhol@telecom-paris.fr> | 1 | From: Leif Lindholm <quic_llindhol@quicinc.com> |
---|---|---|---|
2 | 2 | ||
3 | This commit adds a new B-L475E-IOT01A board using the STM32L475VG SoC | 3 | I'm migrating to Qualcomm's new open source email infrastructure, so |
4 | as well as a dedicated documentation file. | 4 | update my email address, and update the mailmap to match. |
5 | The implementation is derived from the Netduino Plus 2 machine. | ||
6 | There are no peripherals implemented yet, only memory regions. | ||
7 | 5 | ||
6 | Signed-off-by: Leif Lindholm <leif.lindholm@oss.qualcomm.com> | ||
7 | Reviewed-by: Leif Lindholm <quic_llindhol@quicinc.com> | ||
8 | Reviewed-by: Brian Cain <brian.cain@oss.qualcomm.com> | ||
9 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
8 | Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org> | 10 | Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org> |
9 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | 11 | Message-id: 20241205114047.1125842-1-leif.lindholm@oss.qualcomm.com |
10 | Acked-by: Alistair Francis <alistair.francis@wdc.com> | ||
11 | Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr> | ||
12 | Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr> | ||
13 | Message-id: 20240108135849.351719-3-ines.varhol@telecom-paris.fr | ||
14 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 12 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
15 | --- | 13 | --- |
16 | MAINTAINERS | 7 +++ | 14 | MAINTAINERS | 2 +- |
17 | docs/system/arm/b-l475e-iot01a.rst | 46 ++++++++++++++++ | 15 | .mailmap | 5 +++-- |
18 | docs/system/arm/stm32.rst | 6 ++- | 16 | 2 files changed, 4 insertions(+), 3 deletions(-) |
19 | docs/system/target-arm.rst | 1 + | ||
20 | configs/devices/arm-softmmu/default.mak | 1 + | ||
21 | hw/arm/b-l475e-iot01a.c | 72 +++++++++++++++++++++++++ | ||
22 | hw/arm/Kconfig | 6 +++ | ||
23 | hw/arm/meson.build | 1 + | ||
24 | 8 files changed, 138 insertions(+), 2 deletions(-) | ||
25 | create mode 100644 docs/system/arm/b-l475e-iot01a.rst | ||
26 | create mode 100644 hw/arm/b-l475e-iot01a.c | ||
27 | 17 | ||
28 | diff --git a/MAINTAINERS b/MAINTAINERS | 18 | diff --git a/MAINTAINERS b/MAINTAINERS |
29 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
30 | --- a/MAINTAINERS | 20 | --- a/MAINTAINERS |
31 | +++ b/MAINTAINERS | 21 | +++ b/MAINTAINERS |
32 | @@ -XXX,XX +XXX,XX @@ S: Maintained | 22 | @@ -XXX,XX +XXX,XX @@ F: include/hw/ssi/imx_spi.h |
33 | F: hw/arm/stm32l4x5_soc.c | 23 | SBSA-REF |
34 | F: include/hw/arm/stm32l4x5_soc.h | 24 | M: Radoslaw Biernacki <rad@semihalf.com> |
35 | |||
36 | +B-L475E-IOT01A IoT Node | ||
37 | +M: Arnaud Minier <arnaud.minier@telecom-paris.fr> | ||
38 | +M: Inès Varhol <ines.varhol@telecom-paris.fr> | ||
39 | +L: qemu-arm@nongnu.org | ||
40 | +S: Maintained | ||
41 | +F: hw/arm/b-l475e-iot01a.c | ||
42 | + | ||
43 | SmartFusion2 | ||
44 | M: Subbaraya Sundeep <sundeep.lkml@gmail.com> | ||
45 | M: Peter Maydell <peter.maydell@linaro.org> | 25 | M: Peter Maydell <peter.maydell@linaro.org> |
46 | diff --git a/docs/system/arm/b-l475e-iot01a.rst b/docs/system/arm/b-l475e-iot01a.rst | 26 | -R: Leif Lindholm <quic_llindhol@quicinc.com> |
47 | new file mode 100644 | 27 | +R: Leif Lindholm <leif.lindholm@oss.qualcomm.com> |
48 | index XXXXXXX..XXXXXXX | 28 | R: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org> |
49 | --- /dev/null | 29 | L: qemu-arm@nongnu.org |
50 | +++ b/docs/system/arm/b-l475e-iot01a.rst | 30 | S: Maintained |
51 | @@ -XXX,XX +XXX,XX @@ | 31 | diff --git a/.mailmap b/.mailmap |
52 | +B-L475E-IOT01A IoT Node (``b-l475e-iot01a``) | ||
53 | +============================================ | ||
54 | + | ||
55 | +The B-L475E-IOT01A IoT Node uses the STM32L475VG SoC which is based on | ||
56 | +ARM Cortex-M4F core. It is part of STMicroelectronics | ||
57 | +:doc:`STM32 boards </system/arm/stm32>` and more specifically the STM32L4 | ||
58 | +ultra-low power series. The STM32L4x5 chip runs at up to 80 MHz and | ||
59 | +integrates 128 KiB of SRAM and up to 1MiB of Flash. The B-L475E-IOT01A board | ||
60 | +namely features 64 Mibit QSPI Flash, BT, WiFi and RF connectivity, | ||
61 | +USART, I2C, SPI, CAN and USB OTG, as well as a variety of sensors. | ||
62 | + | ||
63 | +Supported devices | ||
64 | +""""""""""""""""" | ||
65 | + | ||
66 | +Currently, B-L475E-IOT01A machine's implementation is minimal, | ||
67 | +it only supports the following device: | ||
68 | + | ||
69 | +- Cortex-M4F based STM32L4x5 SoC | ||
70 | + | ||
71 | +Missing devices | ||
72 | +""""""""""""""" | ||
73 | + | ||
74 | +The B-L475E-IOT01A does *not* support the following devices: | ||
75 | + | ||
76 | +- Extended interrupts and events controller (EXTI) | ||
77 | +- Reset and clock control (RCC) | ||
78 | +- Serial ports (UART) | ||
79 | +- System configuration controller (SYSCFG) | ||
80 | +- General-purpose I/Os (GPIO) | ||
81 | +- Analog to Digital Converter (ADC) | ||
82 | +- SPI controller | ||
83 | +- Timer controller (TIMER) | ||
84 | + | ||
85 | +See the complete list of unimplemented peripheral devices | ||
86 | +in the STM32L4x5 module : ``./hw/arm/stm32l4x5_soc.c`` | ||
87 | + | ||
88 | +Boot options | ||
89 | +"""""""""""" | ||
90 | + | ||
91 | +The B-L475E-IOT01A machine can be started using the ``-kernel`` | ||
92 | +option to load a firmware. Example: | ||
93 | + | ||
94 | +.. code-block:: bash | ||
95 | + | ||
96 | + $ qemu-system-arm -M b-l475e-iot01a -kernel firmware.bin | ||
97 | + | ||
98 | diff --git a/docs/system/arm/stm32.rst b/docs/system/arm/stm32.rst | ||
99 | index XXXXXXX..XXXXXXX 100644 | 32 | index XXXXXXX..XXXXXXX 100644 |
100 | --- a/docs/system/arm/stm32.rst | 33 | --- a/.mailmap |
101 | +++ b/docs/system/arm/stm32.rst | 34 | +++ b/.mailmap |
102 | @@ -XXX,XX +XXX,XX @@ based on this chip : | 35 | @@ -XXX,XX +XXX,XX @@ Huacai Chen <chenhuacai@kernel.org> <chenhc@lemote.com> |
103 | 36 | Huacai Chen <chenhuacai@kernel.org> <chenhuacai@loongson.cn> | |
104 | - ``netduino2`` Netduino 2 board with STM32F205RFT6 microcontroller | 37 | James Hogan <jhogan@kernel.org> <james.hogan@imgtec.com> |
105 | 38 | Juan Quintela <quintela@trasno.org> <quintela@redhat.com> | |
106 | -The STM32F4 series is based on ARM Cortex-M4F core. This series is pin-to-pin | 39 | -Leif Lindholm <quic_llindhol@quicinc.com> <leif.lindholm@linaro.org> |
107 | -compatible with STM32F2 series. The following machines are based on this chip : | 40 | -Leif Lindholm <quic_llindhol@quicinc.com> <leif@nuviainc.com> |
108 | +The STM32F4 series is based on ARM Cortex-M4F core, as well as the STM32L4 | 41 | +Leif Lindholm <leif.lindholm@oss.qualcomm.com> <quic_llindhol@quicinc.com> |
109 | +ultra-low-power series. The STM32F4 series is pin-to-pin compatible with STM32F2 series. | 42 | +Leif Lindholm <leif.lindholm@oss.qualcomm.com> <leif.lindholm@linaro.org> |
110 | +The following machines are based on this ARM Cortex-M4F chip : | 43 | +Leif Lindholm <leif.lindholm@oss.qualcomm.com> <leif@nuviainc.com> |
111 | 44 | Luc Michel <luc@lmichel.fr> <luc.michel@git.antfield.fr> | |
112 | - ``netduinoplus2`` Netduino Plus 2 board with STM32F405RGT6 microcontroller | 45 | Luc Michel <luc@lmichel.fr> <luc.michel@greensocs.com> |
113 | - ``olimex-stm32-h405`` Olimex STM32 H405 board with STM32F405RGT6 microcontroller | 46 | Luc Michel <luc@lmichel.fr> <lmichel@kalray.eu> |
114 | +- ``b-l475e-iot01a`` :doc:`B-L475E-IOT01A IoT Node </system/arm/b-l475e-iot01a>` board with STM32L475VG microcontroller | ||
115 | |||
116 | There are many other STM32 series that are currently not supported by QEMU. | ||
117 | |||
118 | diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst | ||
119 | index XXXXXXX..XXXXXXX 100644 | ||
120 | --- a/docs/system/target-arm.rst | ||
121 | +++ b/docs/system/target-arm.rst | ||
122 | @@ -XXX,XX +XXX,XX @@ undocumented; you can get a complete list by running | ||
123 | arm/vexpress | ||
124 | arm/aspeed | ||
125 | arm/bananapi_m2u.rst | ||
126 | + arm/b-l475e-iot01a.rst | ||
127 | arm/sabrelite | ||
128 | arm/digic | ||
129 | arm/cubieboard | ||
130 | diff --git a/configs/devices/arm-softmmu/default.mak b/configs/devices/arm-softmmu/default.mak | ||
131 | index XXXXXXX..XXXXXXX 100644 | ||
132 | --- a/configs/devices/arm-softmmu/default.mak | ||
133 | +++ b/configs/devices/arm-softmmu/default.mak | ||
134 | @@ -XXX,XX +XXX,XX @@ CONFIG_ARM_VIRT=y | ||
135 | # CONFIG_NSERIES=n | ||
136 | # CONFIG_STELLARIS=n | ||
137 | # CONFIG_STM32VLDISCOVERY=n | ||
138 | +# CONFIG_B_L475E_IOT01A=n | ||
139 | # CONFIG_REALVIEW=n | ||
140 | # CONFIG_VERSATILE=n | ||
141 | # CONFIG_VEXPRESS=n | ||
142 | diff --git a/hw/arm/b-l475e-iot01a.c b/hw/arm/b-l475e-iot01a.c | ||
143 | new file mode 100644 | ||
144 | index XXXXXXX..XXXXXXX | ||
145 | --- /dev/null | ||
146 | +++ b/hw/arm/b-l475e-iot01a.c | ||
147 | @@ -XXX,XX +XXX,XX @@ | ||
148 | +/* | ||
149 | + * B-L475E-IOT01A Discovery Kit machine | ||
150 | + * (B-L475E-IOT01A IoT Node) | ||
151 | + * | ||
152 | + * Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr> | ||
153 | + * Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr> | ||
154 | + * | ||
155 | + * SPDX-License-Identifier: GPL-2.0-or-later | ||
156 | + * | ||
157 | + * This work is licensed under the terms of the GNU GPL, version 2 or later. | ||
158 | + * See the COPYING file in the top-level directory. | ||
159 | + * | ||
160 | + * This work is heavily inspired by the netduinoplus2 by Alistair Francis. | ||
161 | + * Original code is licensed under the MIT License: | ||
162 | + * | ||
163 | + * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me> | ||
164 | + */ | ||
165 | + | ||
166 | +/* | ||
167 | + * The reference used is the STMicroElectronics UM2153 User manual | ||
168 | + * Discovery kit for IoT node, multi-channel communication with STM32L4. | ||
169 | + * https://www.st.com/en/evaluation-tools/b-l475e-iot01a.html#documentation | ||
170 | + */ | ||
171 | + | ||
172 | +#include "qemu/osdep.h" | ||
173 | +#include "qapi/error.h" | ||
174 | +#include "hw/boards.h" | ||
175 | +#include "hw/qdev-properties.h" | ||
176 | +#include "hw/qdev-clock.h" | ||
177 | +#include "qemu/error-report.h" | ||
178 | +#include "hw/arm/stm32l4x5_soc.h" | ||
179 | +#include "hw/arm/boot.h" | ||
180 | + | ||
181 | +/* Main SYSCLK frequency in Hz (80MHz) */ | ||
182 | +#define MAIN_SYSCLK_FREQ_HZ 80000000ULL | ||
183 | + | ||
184 | +static void b_l475e_iot01a_init(MachineState *machine) | ||
185 | +{ | ||
186 | + const Stm32l4x5SocClass *sc; | ||
187 | + DeviceState *dev; | ||
188 | + Clock *sysclk; | ||
189 | + | ||
190 | + /* This clock doesn't need migration because it is fixed-frequency */ | ||
191 | + sysclk = clock_new(OBJECT(machine), "SYSCLK"); | ||
192 | + clock_set_hz(sysclk, MAIN_SYSCLK_FREQ_HZ); | ||
193 | + | ||
194 | + dev = qdev_new(TYPE_STM32L4X5XG_SOC); | ||
195 | + object_property_add_child(OBJECT(machine), "soc", OBJECT(dev)); | ||
196 | + qdev_connect_clock_in(dev, "sysclk", sysclk); | ||
197 | + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); | ||
198 | + | ||
199 | + sc = STM32L4X5_SOC_GET_CLASS(dev); | ||
200 | + armv7m_load_kernel(ARM_CPU(first_cpu), | ||
201 | + machine->kernel_filename, | ||
202 | + 0, sc->flash_size); | ||
203 | +} | ||
204 | + | ||
205 | +static void b_l475e_iot01a_machine_init(MachineClass *mc) | ||
206 | +{ | ||
207 | + static const char *machine_valid_cpu_types[] = { | ||
208 | + ARM_CPU_TYPE_NAME("cortex-m4"), | ||
209 | + NULL | ||
210 | + }; | ||
211 | + mc->desc = "B-L475E-IOT01A Discovery Kit (Cortex-M4)"; | ||
212 | + mc->init = b_l475e_iot01a_init; | ||
213 | + mc->valid_cpu_types = machine_valid_cpu_types; | ||
214 | + | ||
215 | + /* SRAM pre-allocated as part of the SoC instantiation */ | ||
216 | + mc->default_ram_size = 0; | ||
217 | +} | ||
218 | + | ||
219 | +DEFINE_MACHINE("b-l475e-iot01a", b_l475e_iot01a_machine_init) | ||
220 | diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig | ||
221 | index XXXXXXX..XXXXXXX 100644 | ||
222 | --- a/hw/arm/Kconfig | ||
223 | +++ b/hw/arm/Kconfig | ||
224 | @@ -XXX,XX +XXX,XX @@ config STM32F405_SOC | ||
225 | select STM32F4XX_SYSCFG | ||
226 | select STM32F4XX_EXTI | ||
227 | |||
228 | +config B_L475E_IOT01A | ||
229 | + bool | ||
230 | + default y | ||
231 | + depends on TCG && ARM | ||
232 | + select STM32L4X5_SOC | ||
233 | + | ||
234 | config STM32L4X5_SOC | ||
235 | bool | ||
236 | select ARM_V7M | ||
237 | diff --git a/hw/arm/meson.build b/hw/arm/meson.build | ||
238 | index XXXXXXX..XXXXXXX 100644 | ||
239 | --- a/hw/arm/meson.build | ||
240 | +++ b/hw/arm/meson.build | ||
241 | @@ -XXX,XX +XXX,XX @@ arm_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2836.c', 'raspi.c')) | ||
242 | arm_ss.add(when: 'CONFIG_STM32F100_SOC', if_true: files('stm32f100_soc.c')) | ||
243 | arm_ss.add(when: 'CONFIG_STM32F205_SOC', if_true: files('stm32f205_soc.c')) | ||
244 | arm_ss.add(when: 'CONFIG_STM32F405_SOC', if_true: files('stm32f405_soc.c')) | ||
245 | +arm_ss.add(when: 'CONFIG_B_L475E_IOT01A', if_true: files('b-l475e-iot01a.c')) | ||
246 | arm_ss.add(when: 'CONFIG_STM32L4X5_SOC', if_true: files('stm32l4x5_soc.c')) | ||
247 | arm_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp.c', 'xlnx-zcu102.c')) | ||
248 | arm_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal.c', 'xlnx-versal-virt.c')) | ||
249 | -- | 47 | -- |
250 | 2.34.1 | 48 | 2.34.1 |
251 | 49 | ||
252 | 50 | diff view generated by jsdifflib |
1 | From: Samuel Tardieu <sam@rfc1149.net> | 1 | From: Vikram Garhwal <vikram.garhwal@bytedance.com> |
---|---|---|---|
2 | 2 | ||
3 | Update the number of priority bits for a number of existing | 3 | Previously, maintainer role was paused due to inactive email id. Commit id: |
4 | SoCs according to their technical documentation: | 4 | c009d715721861984c4987bcc78b7ee183e86d75. |
5 | 5 | ||
6 | - STM32F100/F205/F405/L4x5: 4 bits | 6 | Signed-off-by: Vikram Garhwal <vikram.garhwal@bytedance.com> |
7 | - Stellaris (Sandstorm/Fury): 3 bits | 7 | Reviewed-by: Francisco Iglesias <francisco.iglesias@amd.com> |
8 | 8 | Message-id: 20241204184205.12952-1-vikram.garhwal@bytedance.com | |
9 | Signed-off-by: Samuel Tardieu <sam@rfc1149.net> | ||
10 | Reviewed-by: Peter Maydell <peter.maydell@linaro.org> | ||
11 | Message-id: 20240106181503.1746200-4-sam@rfc1149.net | ||
12 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 9 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> |
13 | --- | 10 | --- |
14 | hw/arm/stellaris.c | 2 ++ | 11 | MAINTAINERS | 2 ++ |
15 | hw/arm/stm32f100_soc.c | 1 + | 12 | 1 file changed, 2 insertions(+) |
16 | hw/arm/stm32f205_soc.c | 1 + | ||
17 | hw/arm/stm32f405_soc.c | 1 + | ||
18 | hw/arm/stm32l4x5_soc.c | 1 + | ||
19 | 5 files changed, 6 insertions(+) | ||
20 | 13 | ||
21 | diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c | 14 | diff --git a/MAINTAINERS b/MAINTAINERS |
22 | index XXXXXXX..XXXXXXX 100644 | 15 | index XXXXXXX..XXXXXXX 100644 |
23 | --- a/hw/arm/stellaris.c | 16 | --- a/MAINTAINERS |
24 | +++ b/hw/arm/stellaris.c | 17 | +++ b/MAINTAINERS |
25 | @@ -XXX,XX +XXX,XX @@ | 18 | @@ -XXX,XX +XXX,XX @@ F: tests/qtest/fuzz-sb16-test.c |
26 | #define BP_GAMEPAD 0x04 | 19 | |
27 | 20 | Xilinx CAN | |
28 | #define NUM_IRQ_LINES 64 | 21 | M: Francisco Iglesias <francisco.iglesias@amd.com> |
29 | +#define NUM_PRIO_BITS 3 | 22 | +M: Vikram Garhwal <vikram.garhwal@bytedance.com> |
30 | 23 | S: Maintained | |
31 | typedef const struct { | 24 | F: hw/net/can/xlnx-* |
32 | const char *name; | 25 | F: include/hw/net/xlnx-* |
33 | @@ -XXX,XX +XXX,XX @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board) | 26 | @@ -XXX,XX +XXX,XX @@ F: include/hw/rx/ |
34 | 27 | CAN bus subsystem and hardware | |
35 | nvic = qdev_new(TYPE_ARMV7M); | 28 | M: Pavel Pisa <pisa@cmp.felk.cvut.cz> |
36 | qdev_prop_set_uint32(nvic, "num-irq", NUM_IRQ_LINES); | 29 | M: Francisco Iglesias <francisco.iglesias@amd.com> |
37 | + qdev_prop_set_uint8(nvic, "num-prio-bits", NUM_PRIO_BITS); | 30 | +M: Vikram Garhwal <vikram.garhwal@bytedance.com> |
38 | qdev_prop_set_string(nvic, "cpu-type", ms->cpu_type); | 31 | S: Maintained |
39 | qdev_prop_set_bit(nvic, "enable-bitband", true); | 32 | W: https://canbus.pages.fel.cvut.cz/ |
40 | qdev_connect_clock_in(nvic, "cpuclk", | 33 | F: net/can/* |
41 | diff --git a/hw/arm/stm32f100_soc.c b/hw/arm/stm32f100_soc.c | ||
42 | index XXXXXXX..XXXXXXX 100644 | ||
43 | --- a/hw/arm/stm32f100_soc.c | ||
44 | +++ b/hw/arm/stm32f100_soc.c | ||
45 | @@ -XXX,XX +XXX,XX @@ static void stm32f100_soc_realize(DeviceState *dev_soc, Error **errp) | ||
46 | /* Init ARMv7m */ | ||
47 | armv7m = DEVICE(&s->armv7m); | ||
48 | qdev_prop_set_uint32(armv7m, "num-irq", 61); | ||
49 | + qdev_prop_set_uint8(armv7m, "num-prio-bits", 4); | ||
50 | qdev_prop_set_string(armv7m, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m3")); | ||
51 | qdev_prop_set_bit(armv7m, "enable-bitband", true); | ||
52 | qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk); | ||
53 | diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c | ||
54 | index XXXXXXX..XXXXXXX 100644 | ||
55 | --- a/hw/arm/stm32f205_soc.c | ||
56 | +++ b/hw/arm/stm32f205_soc.c | ||
57 | @@ -XXX,XX +XXX,XX @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) | ||
58 | |||
59 | armv7m = DEVICE(&s->armv7m); | ||
60 | qdev_prop_set_uint32(armv7m, "num-irq", 96); | ||
61 | + qdev_prop_set_uint8(armv7m, "num-prio-bits", 4); | ||
62 | qdev_prop_set_string(armv7m, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m3")); | ||
63 | qdev_prop_set_bit(armv7m, "enable-bitband", true); | ||
64 | qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk); | ||
65 | diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c | ||
66 | index XXXXXXX..XXXXXXX 100644 | ||
67 | --- a/hw/arm/stm32f405_soc.c | ||
68 | +++ b/hw/arm/stm32f405_soc.c | ||
69 | @@ -XXX,XX +XXX,XX @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) | ||
70 | |||
71 | armv7m = DEVICE(&s->armv7m); | ||
72 | qdev_prop_set_uint32(armv7m, "num-irq", 96); | ||
73 | + qdev_prop_set_uint8(armv7m, "num-prio-bits", 4); | ||
74 | qdev_prop_set_string(armv7m, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m4")); | ||
75 | qdev_prop_set_bit(armv7m, "enable-bitband", true); | ||
76 | qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk); | ||
77 | diff --git a/hw/arm/stm32l4x5_soc.c b/hw/arm/stm32l4x5_soc.c | ||
78 | index XXXXXXX..XXXXXXX 100644 | ||
79 | --- a/hw/arm/stm32l4x5_soc.c | ||
80 | +++ b/hw/arm/stm32l4x5_soc.c | ||
81 | @@ -XXX,XX +XXX,XX @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp) | ||
82 | object_initialize_child(OBJECT(dev_soc), "armv7m", &s->armv7m, TYPE_ARMV7M); | ||
83 | armv7m = DEVICE(&s->armv7m); | ||
84 | qdev_prop_set_uint32(armv7m, "num-irq", 96); | ||
85 | + qdev_prop_set_uint32(armv7m, "num-prio-bits", 4); | ||
86 | qdev_prop_set_string(armv7m, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m4")); | ||
87 | qdev_prop_set_bit(armv7m, "enable-bitband", true); | ||
88 | qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk); | ||
89 | -- | 34 | -- |
90 | 2.34.1 | 35 | 2.34.1 | diff view generated by jsdifflib |