1
Arm queue -- mostly the first slice of my Musca patches.
1
The following changes since commit 3214bec13d8d4c40f707d21d8350d04e4123ae97:
2
2
3
thanks
3
Merge tag 'migration-20250110-pull-request' of https://gitlab.com/farosas/qemu into staging (2025-01-10 13:39:19 -0500)
4
-- PMM
5
6
The following changes since commit fc3dbb90f2eb069801bfb4cfe9cbc83cf9c5f4a9:
7
8
Merge remote-tracking branch 'remotes/jnsnow/tags/bitmaps-pull-request' into staging (2019-02-21 13:09:33 +0000)
9
4
10
are available in the Git repository at:
5
are available in the Git repository at:
11
6
12
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20190221
7
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20250113
13
8
14
for you to fetch changes up to 3733f80308d2a7f23f5e39b039e0547aba6c07f1:
9
for you to fetch changes up to 435d260e7ec5ff9c79e3e62f1d66ec82d2d691ae:
15
10
16
hw/arm/armsse: Make 0x5... alias region work for per-CPU devices (2019-02-21 18:17:48 +0000)
11
docs/system/arm/virt: mention specific migration information (2025-01-13 12:35:35 +0000)
17
12
18
----------------------------------------------------------------
13
----------------------------------------------------------------
19
target-arm queue:
14
target-arm queue:
20
* Model the Arm "Musca" development boards: "musca-a" and "musca-b1"
15
* hw/arm_sysctl: fix extracting 31th bit of val
21
* Implement the ARMv8.3-JSConv extension
16
* hw/misc: cast rpm to uint64_t
22
* v8M MPU should use background region as default, not always
17
* tests/qtest/boot-serial-test: Improve ASM
23
* Stop unintentional sign extension in pmu_init
18
* target/arm: Move minor arithmetic helpers out of helper.c
19
* target/arm: change default pauth algorithm to impdef
24
20
25
----------------------------------------------------------------
21
----------------------------------------------------------------
26
Aaron Lindsay OS (1):
22
Anastasia Belova (1):
27
target/arm: Stop unintentional sign extension in pmu_init
23
hw/arm_sysctl: fix extracting 31th bit of val
28
24
29
Peter Maydell (16):
25
Peter Maydell (2):
30
hw/arm/armsse: Fix memory leak in error-exit path
26
target/arm: Move minor arithmetic helpers out of helper.c
31
target/arm: v8M MPU should use background region as default, not always
27
tests/tcg/aarch64: force qarma5 for pauth-3 test
32
hw/misc/tz-ppc: Support having unused ports in the middle of the range
33
hw/timer/pl031: Allow use as an embedded-struct device
34
hw/timer/pl031: Convert to using trace events
35
hw/char/pl011: Allow use as an embedded-struct device
36
hw/char/pl011: Support all interrupt lines
37
hw/char/pl011: Use '0x' prefix when logging hex numbers
38
hw/arm/armsse: Document SRAM_ADDR_WIDTH property in header comment
39
hw/arm/armsse: Allow boards to specify init-svtor
40
hw/arm/musca.c: Implement models of the Musca-A and -B1 boards
41
hw/arm/musca: Add PPCs
42
hw/arm/musca: Add MPCs
43
hw/arm/musca: Wire up PL031 RTC
44
hw/arm/musca: Wire up PL011 UARTs
45
hw/arm/armsse: Make 0x5... alias region work for per-CPU devices
46
28
47
Richard Henderson (4):
29
Philippe Mathieu-Daudé (4):
48
target/arm: Restructure disas_fp_int_conv
30
tests/qtest/boot-serial-test: Improve ASM comments of PL011 tests
49
target/arm: Split out vfp_helper.c
31
tests/qtest/boot-serial-test: Reduce for() loop in PL011 tests
50
target/arm: Rearrange Floating-point data-processing (2 regs)
32
tests/qtest/boot-serial-test: Reorder pair of instructions in PL011 test
51
target/arm: Implement ARMv8.3-JSConv
33
tests/qtest/boot-serial-test: Initialize PL011 Control register
52
34
53
hw/arm/Makefile.objs | 1 +
35
Pierrick Bouvier (3):
54
target/arm/Makefile.objs | 2 +-
36
target/arm: add new property to select pauth-qarma5
55
include/hw/arm/armsse.h | 7 +-
37
target/arm: change default pauth algorithm to impdef
56
include/hw/char/pl011.h | 34 ++
38
docs/system/arm/virt: mention specific migration information
57
include/hw/misc/tz-ppc.h | 8 +-
58
include/hw/timer/pl031.h | 44 ++
59
target/arm/cpu.h | 10 +
60
target/arm/helper.h | 3 +
61
hw/arm/armsse.c | 44 +-
62
hw/arm/musca.c | 669 ++++++++++++++++++++++
63
hw/char/pl011.c | 81 +--
64
hw/misc/tz-ppc.c | 32 ++
65
hw/timer/pl031.c | 80 ++-
66
target/arm/cpu.c | 1 +
67
target/arm/cpu64.c | 2 +
68
target/arm/helper.c | 1072 +----------------------------------
69
target/arm/translate-a64.c | 120 ++--
70
target/arm/translate.c | 237 ++++----
71
target/arm/vfp_helper.c | 1176 +++++++++++++++++++++++++++++++++++++++
72
MAINTAINERS | 7 +
73
default-configs/arm-softmmu.mak | 1 +
74
hw/timer/trace-events | 6 +
75
22 files changed, 2307 insertions(+), 1330 deletions(-)
76
create mode 100644 include/hw/timer/pl031.h
77
create mode 100644 hw/arm/musca.c
78
create mode 100644 target/arm/vfp_helper.c
79
39
40
Tigran Sogomonian (1):
41
hw/misc: cast rpm to uint64_t
42
43
docs/system/arm/cpu-features.rst | 7 +-
44
docs/system/arm/virt.rst | 4 +
45
docs/system/introduction.rst | 2 +-
46
target/arm/cpu.h | 4 +
47
hw/core/machine.c | 4 +-
48
hw/misc/arm_sysctl.c | 2 +-
49
hw/misc/npcm7xx_mft.c | 5 +-
50
target/arm/arm-qmp-cmds.c | 2 +-
51
target/arm/cpu.c | 2 +
52
target/arm/cpu64.c | 38 ++-
53
target/arm/helper.c | 285 -----------------------
54
target/arm/tcg/arith_helper.c | 296 ++++++++++++++++++++++++
55
tests/qtest/arm-cpu-features.c | 15 +-
56
tests/qtest/boot-serial-test.c | 23 +-
57
target/arm/{op_addsub.h => tcg/op_addsub.c.inc} | 0
58
target/arm/tcg/meson.build | 1 +
59
tests/tcg/aarch64/Makefile.softmmu-target | 3 +
60
17 files changed, 377 insertions(+), 316 deletions(-)
61
create mode 100644 target/arm/tcg/arith_helper.c
62
rename target/arm/{op_addsub.h => tcg/op_addsub.c.inc} (100%)
63
diff view generated by jsdifflib
Deleted patch
1
Coverity points out (CID 1398632, CID 1398650) that we
2
leak a couple of allocated strings in the error-exit
3
code path for setting up the MHUs in the ARMSSE.
4
Fix this bug by moving the allocate-and-free of each
5
string to be closer to the use, so we do the free before
6
doing the error-exit check.
7
1
8
Fixes: f8574705f62b38a ("hw/arm/armsse: Add unimplemented-device stubs for MHUs")
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
11
Message-id: 20190215113707.24553-1-peter.maydell@linaro.org
12
---
13
hw/arm/armsse.c | 10 ++++++----
14
1 file changed, 6 insertions(+), 4 deletions(-)
15
16
diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/arm/armsse.c
19
+++ b/hw/arm/armsse.c
20
@@ -XXX,XX +XXX,XX @@ static void armsse_realize(DeviceState *dev, Error **errp)
21
22
if (info->has_mhus) {
23
for (i = 0; i < ARRAY_SIZE(s->mhu); i++) {
24
- char *name = g_strdup_printf("MHU%d", i);
25
- char *port = g_strdup_printf("port[%d]", i + 3);
26
+ char *name;
27
+ char *port;
28
29
+ name = g_strdup_printf("MHU%d", i);
30
qdev_prop_set_string(DEVICE(&s->mhu[i]), "name", name);
31
qdev_prop_set_uint64(DEVICE(&s->mhu[i]), "size", 0x1000);
32
object_property_set_bool(OBJECT(&s->mhu[i]), true,
33
"realized", &err);
34
+ g_free(name);
35
if (err) {
36
error_propagate(errp, err);
37
return;
38
}
39
+ port = g_strdup_printf("port[%d]", i + 3);
40
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mhu[i]), 0);
41
object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr),
42
port, &err);
43
+ g_free(port);
44
if (err) {
45
error_propagate(errp, err);
46
return;
47
}
48
- g_free(name);
49
- g_free(port);
50
}
51
}
52
53
--
54
2.20.1
55
56
diff view generated by jsdifflib
Deleted patch
1
The "background region" for a v8M MPU is a default which will be used
2
(if enabled, and if the access is privileged) if the access does
3
not match any specific MPU region. We were incorrectly using it
4
always (by putting the condition at the wrong nesting level). This
5
meant that we would always return the default background permissions
6
rather than the correct permissions for a specific region, and also
7
that we would not return the right information in response to a
8
TT instruction.
9
1
10
Move the check for the background region to the same place in the
11
logic as the equivalent v8M MPUCheck() pseudocode puts it.
12
This in turn means we must adjust the condition we use to detect
13
matches in multiple regions to avoid false-positives.
14
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
17
Message-id: 20190214113408.10214-1-peter.maydell@linaro.org
18
---
19
target/arm/helper.c | 8 +++++---
20
1 file changed, 5 insertions(+), 3 deletions(-)
21
22
diff --git a/target/arm/helper.c b/target/arm/helper.c
23
index XXXXXXX..XXXXXXX 100644
24
--- a/target/arm/helper.c
25
+++ b/target/arm/helper.c
26
@@ -XXX,XX +XXX,XX @@ static bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
27
hit = true;
28
} else if (m_is_ppb_region(env, address)) {
29
hit = true;
30
- } else if (pmsav7_use_background_region(cpu, mmu_idx, is_user)) {
31
- hit = true;
32
} else {
33
+ if (pmsav7_use_background_region(cpu, mmu_idx, is_user)) {
34
+ hit = true;
35
+ }
36
+
37
for (n = (int)cpu->pmsav7_dregion - 1; n >= 0; n--) {
38
/* region search */
39
/* Note that the base address is bits [31:5] from the register
40
@@ -XXX,XX +XXX,XX @@ static bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
41
*is_subpage = true;
42
}
43
44
- if (hit) {
45
+ if (matchregion != -1) {
46
/* Multiple regions match -- always a failure (unlike
47
* PMSAv7 where highest-numbered-region wins)
48
*/
49
--
50
2.20.1
51
52
diff view generated by jsdifflib
1
From: Aaron Lindsay OS <aaron@os.amperecomputing.com>
1
From: Anastasia Belova <abelova@astralinux.ru>
2
2
3
This was introduced by
3
1 << 31 is casted to uint64_t while bitwise and with val.
4
commit bf8d09694ccc07487cd73d7562081fdaec3370c8
4
So this value may become 0xffffffff80000000 but only
5
target/arm: Don't clear supported PMU events when initializing PMCEID1
5
31th "start" bit is required.
6
and identified by Coverity (CID 1398645).
7
6
8
Signed-off-by: Aaron Lindsay <aaron@os.amperecomputing.com>
7
This is not possible in practice because the MemoryRegionOps
9
Reported-by: Peter Maydell <peter.maydell@linaro.org>
8
uses the default max access size of 4 bytes and so none
10
Message-id: 20190219144621.450-1-aaron@os.amperecomputing.com
9
of the upper bytes of val will be set, but the bitfield
10
extract API is clearer anyway.
11
12
Use the bitfield extract() API instead.
13
14
Found by Linux Verification Center (linuxtesting.org) with SVACE.
15
16
Signed-off-by: Anastasia Belova <abelova@astralinux.ru>
17
Message-id: 20241220125429.7552-1-abelova@astralinux.ru
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
18
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
19
[PMM: add clarification to commit message]
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
20
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
21
---
14
target/arm/helper.c | 2 +-
22
hw/misc/arm_sysctl.c | 2 +-
15
1 file changed, 1 insertion(+), 1 deletion(-)
23
1 file changed, 1 insertion(+), 1 deletion(-)
16
24
17
diff --git a/target/arm/helper.c b/target/arm/helper.c
25
diff --git a/hw/misc/arm_sysctl.c b/hw/misc/arm_sysctl.c
18
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/helper.c
27
--- a/hw/misc/arm_sysctl.c
20
+++ b/target/arm/helper.c
28
+++ b/hw/misc/arm_sysctl.c
21
@@ -XXX,XX +XXX,XX @@ void pmu_init(ARMCPU *cpu)
29
@@ -XXX,XX +XXX,XX @@ static void arm_sysctl_write(void *opaque, hwaddr offset,
22
30
* as zero.
23
if (cnt->supported(&cpu->env)) {
31
*/
24
supported_event_map[cnt->number] = i;
32
s->sys_cfgctrl = val & ~((3 << 18) | (1 << 31));
25
- uint64_t event_mask = 1 << (cnt->number & 0x1f);
33
- if (val & (1 << 31)) {
26
+ uint64_t event_mask = 1ULL << (cnt->number & 0x1f);
34
+ if (extract64(val, 31, 1)) {
27
if (cnt->number & 0x20) {
35
/* Start bit set -- actually do something */
28
cpu->pmceid1 |= event_mask;
36
unsigned int dcc = extract32(s->sys_cfgctrl, 26, 4);
29
} else {
37
unsigned int function = extract32(s->sys_cfgctrl, 20, 6);
30
--
38
--
31
2.20.1
39
2.34.1
32
33
diff view generated by jsdifflib
1
The region 0x40010000 .. 0x4001ffff and its secure-only alias
1
From: Tigran Sogomonian <tsogomonian@astralinux.ru>
2
at 0x50010000... are for per-CPU devices. We implement this by
3
giving each CPU its own container memory region, where the
4
per-CPU devices live. Unfortunately, the alias region which
5
makes devices mapped at 0x4... addresses also appear at 0x5...
6
is only implemented in the overall "all CPUs" container. The
7
effect of this bug is that the CPU_IDENTITY register block appears
8
only at 0x4001f000, but not at the 0x5001f000 alias where it should
9
also appear. Guests (like very recent Arm Trusted Firmware-M)
10
which try to access it at 0x5001f000 will crash.
11
2
12
Fix this by moving the handling for this alias from the "all CPUs"
3
The value of an arithmetic expression
13
container to the per-CPU container. (We leave the aliases for
4
'rpm * NPCM7XX_MFT_PULSE_PER_REVOLUTION' is a subject
14
0x1... and 0x3... in the overall container, because there are
5
to overflow because its operands are not cast to
15
no per-CPU devices there.)
6
a larger data type before performing arithmetic. Thus, need
7
to cast rpm to uint64_t.
16
8
9
Found by Linux Verification Center (linuxtesting.org) with SVACE.
10
11
Signed-off-by: Tigran Sogomonian <tsogomonian@astralinux.ru>
12
Reviewed-by: Patrick Leis <venture@google.com>
13
Reviewed-by: Hao Wu <wuhaotsh@google.com>
14
Message-id: 20241226130311.1349-1-tsogomonian@astralinux.ru
17
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
18
Message-id: 20190215180500.6906-1-peter.maydell@linaro.org
19
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
20
---
16
---
21
include/hw/arm/armsse.h | 2 +-
17
hw/misc/npcm7xx_mft.c | 5 +++--
22
hw/arm/armsse.c | 26 ++++++++++++++++----------
18
1 file changed, 3 insertions(+), 2 deletions(-)
23
2 files changed, 17 insertions(+), 11 deletions(-)
24
19
25
diff --git a/include/hw/arm/armsse.h b/include/hw/arm/armsse.h
20
diff --git a/hw/misc/npcm7xx_mft.c b/hw/misc/npcm7xx_mft.c
26
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
27
--- a/include/hw/arm/armsse.h
22
--- a/hw/misc/npcm7xx_mft.c
28
+++ b/include/hw/arm/armsse.h
23
+++ b/hw/misc/npcm7xx_mft.c
29
@@ -XXX,XX +XXX,XX @@ typedef struct ARMSSE {
24
@@ -XXX,XX +XXX,XX @@ static NPCM7xxMFTCaptureState npcm7xx_mft_compute_cnt(
30
MemoryRegion cpu_container[SSE_MAX_CPUS];
25
* RPM = revolution/min. The time for one revlution (in ns) is
31
MemoryRegion alias1;
26
* MINUTE_TO_NANOSECOND / RPM.
32
MemoryRegion alias2;
27
*/
33
- MemoryRegion alias3;
28
- count = clock_ns_to_ticks(clock, (60 * NANOSECONDS_PER_SECOND) /
34
+ MemoryRegion alias3[SSE_MAX_CPUS];
29
- (rpm * NPCM7XX_MFT_PULSE_PER_REVOLUTION));
35
MemoryRegion sram[MAX_SRAM_BANKS];
30
+ count = clock_ns_to_ticks(clock,
36
31
+ (uint64_t)(60 * NANOSECONDS_PER_SECOND) /
37
qemu_irq *exp_irqs[SSE_MAX_CPUS];
32
+ ((uint64_t)rpm * NPCM7XX_MFT_PULSE_PER_REVOLUTION));
38
diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c
39
index XXXXXXX..XXXXXXX 100644
40
--- a/hw/arm/armsse.c
41
+++ b/hw/arm/armsse.c
42
@@ -XXX,XX +XXX,XX @@ static bool irq_is_common[32] = {
43
/* 30, 31: reserved */
44
};
45
46
-/* Create an alias region of @size bytes starting at @base
47
+/*
48
+ * Create an alias region in @container of @size bytes starting at @base
49
* which mirrors the memory starting at @orig.
50
*/
51
-static void make_alias(ARMSSE *s, MemoryRegion *mr, const char *name,
52
- hwaddr base, hwaddr size, hwaddr orig)
53
+static void make_alias(ARMSSE *s, MemoryRegion *mr, MemoryRegion *container,
54
+ const char *name, hwaddr base, hwaddr size, hwaddr orig)
55
{
56
- memory_region_init_alias(mr, NULL, name, &s->container, orig, size);
57
+ memory_region_init_alias(mr, NULL, name, container, orig, size);
58
/* The alias is even lower priority than unimplemented_device regions */
59
- memory_region_add_subregion_overlap(&s->container, base, mr, -1500);
60
+ memory_region_add_subregion_overlap(container, base, mr, -1500);
61
}
62
63
static void irq_status_forwarder(void *opaque, int n, int level)
64
@@ -XXX,XX +XXX,XX @@ static void armsse_realize(DeviceState *dev, Error **errp)
65
}
33
}
66
34
67
/* Set up the big aliases first */
35
if (count > NPCM7XX_MFT_MAX_CNT) {
68
- make_alias(s, &s->alias1, "alias 1", 0x10000000, 0x10000000, 0x00000000);
69
- make_alias(s, &s->alias2, "alias 2", 0x30000000, 0x10000000, 0x20000000);
70
+ make_alias(s, &s->alias1, &s->container, "alias 1",
71
+ 0x10000000, 0x10000000, 0x00000000);
72
+ make_alias(s, &s->alias2, &s->container,
73
+ "alias 2", 0x30000000, 0x10000000, 0x20000000);
74
/* The 0x50000000..0x5fffffff region is not a pure alias: it has
75
* a few extra devices that only appear there (generally the
76
* control interfaces for the protection controllers).
77
* We implement this by mapping those devices over the top of this
78
- * alias MR at a higher priority.
79
+ * alias MR at a higher priority. Some of the devices in this range
80
+ * are per-CPU, so we must put this alias in the per-cpu containers.
81
*/
82
- make_alias(s, &s->alias3, "alias 3", 0x50000000, 0x10000000, 0x40000000);
83
-
84
+ for (i = 0; i < info->num_cpus; i++) {
85
+ make_alias(s, &s->alias3[i], &s->cpu_container[i],
86
+ "alias 3", 0x50000000, 0x10000000, 0x40000000);
87
+ }
88
89
/* Security controller */
90
object_property_set_bool(OBJECT(&s->secctl), true, "realized", &err);
91
--
36
--
92
2.20.1
37
2.34.1
93
94
diff view generated by jsdifflib
1
The Musca boards have DAPLink firmware that sets the initial
1
From: Philippe Mathieu-Daudé <philmd@linaro.org>
2
secure VTOR value (the location of the vector table) differently
3
depending on the boot mode (from flash, from RAM, etc). Export
4
the init-svtor as a QOM property of the ARMSSE object so that
5
the board can change it.
6
2
3
Re-indent ASM comments adding the 'loop:' label.
4
5
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Reviewed-by: Fabiano Rosas <farosas@suse.de>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
---
9
---
11
include/hw/arm/armsse.h | 3 +++
10
tests/qtest/boot-serial-test.c | 18 +++++++++---------
12
hw/arm/armsse.c | 8 ++++----
11
1 file changed, 9 insertions(+), 9 deletions(-)
13
2 files changed, 7 insertions(+), 4 deletions(-)
14
12
15
diff --git a/include/hw/arm/armsse.h b/include/hw/arm/armsse.h
13
diff --git a/tests/qtest/boot-serial-test.c b/tests/qtest/boot-serial-test.c
16
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
17
--- a/include/hw/arm/armsse.h
15
--- a/tests/qtest/boot-serial-test.c
18
+++ b/include/hw/arm/armsse.h
16
+++ b/tests/qtest/boot-serial-test.c
19
@@ -XXX,XX +XXX,XX @@
17
@@ -XXX,XX +XXX,XX @@ static const uint8_t kernel_plml605[] = {
20
* if necessary.)
21
* + QOM property "SRAM_ADDR_WIDTH" sets the number of bits used for the
22
* address of each SRAM bank (and thus the total amount of internal SRAM)
23
+ * + QOM property "init-svtor" sets the initial value of the CPU SVTOR register
24
+ * (where it expects to load the PC and SP from the vector table on reset)
25
* + Named GPIO inputs "EXP_IRQ" 0..n are the expansion interrupts for CPU 0,
26
* which are wired to its NVIC lines 32 .. n+32
27
* + Named GPIO inputs "EXP_CPU1_IRQ" 0..n are the expansion interrupts for
28
@@ -XXX,XX +XXX,XX @@ typedef struct ARMSSE {
29
uint32_t exp_numirq;
30
uint32_t mainclk_frq;
31
uint32_t sram_addr_width;
32
+ uint32_t init_svtor;
33
} ARMSSE;
34
35
typedef struct ARMSSEInfo ARMSSEInfo;
36
diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c
37
index XXXXXXX..XXXXXXX 100644
38
--- a/hw/arm/armsse.c
39
+++ b/hw/arm/armsse.c
40
@@ -XXX,XX +XXX,XX @@ static void armsse_realize(DeviceState *dev, Error **errp)
41
* the INITSVTOR* registers before powering up the CPUs in any case,
42
* so the hardware's default value doesn't matter. QEMU doesn't emulate
43
* the control processor, so instead we behave in the way that the
44
- * firmware does. All boards currently known about have firmware that
45
- * sets the INITSVTOR0 and INITSVTOR1 registers to 0x10000000, like the
46
- * IoTKit default. We can make this more configurable if necessary.
47
+ * firmware does. The initial value is configurable by the board code
48
+ * to match whatever its firmware does.
49
*/
50
- qdev_prop_set_uint32(cpudev, "init-svtor", 0x10000000);
51
+ qdev_prop_set_uint32(cpudev, "init-svtor", s->init_svtor);
52
/*
53
* Start all CPUs except CPU0 powered down. In real hardware it is
54
* a configurable property of the SSE-200 which CPUs start powered up
55
@@ -XXX,XX +XXX,XX @@ static Property armsse_properties[] = {
56
DEFINE_PROP_UINT32("EXP_NUMIRQ", ARMSSE, exp_numirq, 64),
57
DEFINE_PROP_UINT32("MAINCLK", ARMSSE, mainclk_frq, 0),
58
DEFINE_PROP_UINT32("SRAM_ADDR_WIDTH", ARMSSE, sram_addr_width, 15),
59
+ DEFINE_PROP_UINT32("init-svtor", ARMSSE, init_svtor, 0x10000000),
60
DEFINE_PROP_END_OF_LIST()
61
};
18
};
62
19
20
static const uint8_t bios_raspi2[] = {
21
- 0x08, 0x30, 0x9f, 0xe5, /* ldr r3,[pc,#8] Get base */
22
- 0x54, 0x20, 0xa0, 0xe3, /* mov r2,#'T' */
23
- 0x00, 0x20, 0xc3, 0xe5, /* strb r2,[r3] */
24
- 0xfb, 0xff, 0xff, 0xea, /* b loop */
25
- 0x00, 0x10, 0x20, 0x3f, /* 0x3f201000 = UART0 base addr */
26
+ 0x08, 0x30, 0x9f, 0xe5, /* loop: ldr r3, [pc, #8] Get &UART0 */
27
+ 0x54, 0x20, 0xa0, 0xe3, /* mov r2, #'T' */
28
+ 0x00, 0x20, 0xc3, 0xe5, /* strb r2, [r3] *TXDAT = 'T' */
29
+ 0xfb, 0xff, 0xff, 0xea, /* b -12 (loop) */
30
+ 0x00, 0x10, 0x20, 0x3f, /* UART0: 0x3f201000 */
31
};
32
33
static const uint8_t kernel_aarch64[] = {
34
- 0x81, 0x0a, 0x80, 0x52, /* mov w1, #0x54 */
35
- 0x02, 0x20, 0xa1, 0xd2, /* mov x2, #0x9000000 */
36
- 0x41, 0x00, 0x00, 0x39, /* strb w1, [x2] */
37
- 0xfd, 0xff, 0xff, 0x17, /* b -12 (loop) */
38
+ 0x81, 0x0a, 0x80, 0x52, /* loop: mov w1, #'T' */
39
+ 0x02, 0x20, 0xa1, 0xd2, /* mov x2, #0x9000000 Load UART0 */
40
+ 0x41, 0x00, 0x00, 0x39, /* strb w1, [x2] *TXDAT = 'T' */
41
+ 0xfd, 0xff, 0xff, 0x17, /* b -12 (loop) */
42
};
43
44
static const uint8_t kernel_nrf51[] = {
63
--
45
--
64
2.20.1
46
2.34.1
65
47
66
48
diff view generated by jsdifflib
1
The Peripheral Protection Controller's handling of unused ports
1
From: Philippe Mathieu-Daudé <philmd@linaro.org>
2
is that if there is nothing connected to the port's downstream
3
then it does not create the sysbus MMIO region for the upstream
4
end of the port. This results in odd behaviour when there is
5
an unused port in the middle of the range: since sysbus MMIO
6
regions are implicitly consecutively allocated, any used ports
7
above the unused ones end up with sysbus MMIO region numbers
8
that don't match the port number.
9
2
10
Avoid this numbering mismatch by creating dummy MMIO regions
3
Since registers are not modified, we don't need
11
for the unused ports. This doesn't change anything for our
4
to refill their values. Directly jump to the previous
12
existing boards, which don't have any gaps in the middle of
5
store instruction to keep filling the TXDAT register.
13
the port ranges they use; but it will be needed for the Musca
14
board.
15
6
7
The equivalent C code remains:
8
9
while (true) {
10
*UART_DATA = 'T';
11
}
12
13
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
14
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
15
Reviewed-by: Fabiano Rosas <farosas@suse.de>
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
18
---
17
---
19
include/hw/misc/tz-ppc.h | 8 +++++++-
18
tests/qtest/boot-serial-test.c | 12 ++++++------
20
hw/misc/tz-ppc.c | 32 ++++++++++++++++++++++++++++++++
19
1 file changed, 6 insertions(+), 6 deletions(-)
21
2 files changed, 39 insertions(+), 1 deletion(-)
22
20
23
diff --git a/include/hw/misc/tz-ppc.h b/include/hw/misc/tz-ppc.h
21
diff --git a/tests/qtest/boot-serial-test.c b/tests/qtest/boot-serial-test.c
24
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
25
--- a/include/hw/misc/tz-ppc.h
23
--- a/tests/qtest/boot-serial-test.c
26
+++ b/include/hw/misc/tz-ppc.h
24
+++ b/tests/qtest/boot-serial-test.c
27
@@ -XXX,XX +XXX,XX @@
25
@@ -XXX,XX +XXX,XX @@ static const uint8_t kernel_plml605[] = {
28
*
29
* QEMU interface:
30
* + sysbus MMIO regions 0..15: MemoryRegions defining the upstream end
31
- * of each of the 16 ports of the PPC
32
+ * of each of the 16 ports of the PPC. When a port is unused (i.e. no
33
+ * downstream MemoryRegion is connected to it) at the end of the 0..15
34
+ * range then no sysbus MMIO region is created for its upstream. When an
35
+ * unused port lies in the middle of the range with other used ports at
36
+ * higher port numbers, a dummy MMIO region is created to ensure that
37
+ * port N's upstream is always sysbus MMIO region N. Dummy regions should
38
+ * not be mapped, and will assert if any access is made to them.
39
* + Property "port[0..15]": MemoryRegion defining the downstream device(s)
40
* for each of the 16 ports of the PPC
41
* + Named GPIO inputs "cfg_nonsec[0..15]": set to 1 if the port should be
42
diff --git a/hw/misc/tz-ppc.c b/hw/misc/tz-ppc.c
43
index XXXXXXX..XXXXXXX 100644
44
--- a/hw/misc/tz-ppc.c
45
+++ b/hw/misc/tz-ppc.c
46
@@ -XXX,XX +XXX,XX @@ static const MemoryRegionOps tz_ppc_ops = {
47
.endianness = DEVICE_LITTLE_ENDIAN,
48
};
26
};
49
27
50
+static bool tz_ppc_dummy_accepts(void *opaque, hwaddr addr,
28
static const uint8_t bios_raspi2[] = {
51
+ unsigned size, bool is_write,
29
- 0x08, 0x30, 0x9f, 0xe5, /* loop: ldr r3, [pc, #8] Get &UART0 */
52
+ MemTxAttrs attrs)
30
+ 0x08, 0x30, 0x9f, 0xe5, /* ldr r3, [pc, #8] Get &UART0 */
53
+{
31
0x54, 0x20, 0xa0, 0xe3, /* mov r2, #'T' */
54
+ /*
32
- 0x00, 0x20, 0xc3, 0xe5, /* strb r2, [r3] *TXDAT = 'T' */
55
+ * Board code should never map the upstream end of an unused port,
33
- 0xfb, 0xff, 0xff, 0xea, /* b -12 (loop) */
56
+ * so we should never try to make a memory access to it.
34
+ 0x00, 0x20, 0xc3, 0xe5, /* loop: strb r2, [r3] *TXDAT = 'T' */
57
+ */
35
+ 0xff, 0xff, 0xff, 0xea, /* b -4 (loop) */
58
+ g_assert_not_reached();
36
0x00, 0x10, 0x20, 0x3f, /* UART0: 0x3f201000 */
59
+}
37
};
60
+
38
61
+static const MemoryRegionOps tz_ppc_dummy_ops = {
39
static const uint8_t kernel_aarch64[] = {
62
+ .valid.accepts = tz_ppc_dummy_accepts,
40
- 0x81, 0x0a, 0x80, 0x52, /* loop: mov w1, #'T' */
63
+};
41
+ 0x81, 0x0a, 0x80, 0x52, /* mov w1, #'T' */
64
+
42
0x02, 0x20, 0xa1, 0xd2, /* mov x2, #0x9000000 Load UART0 */
65
static void tz_ppc_reset(DeviceState *dev)
43
- 0x41, 0x00, 0x00, 0x39, /* strb w1, [x2] *TXDAT = 'T' */
66
{
44
- 0xfd, 0xff, 0xff, 0x17, /* b -12 (loop) */
67
TZPPC *s = TZ_PPC(dev);
45
+ 0x41, 0x00, 0x00, 0x39, /* loop: strb w1, [x2] *TXDAT = 'T' */
68
@@ -XXX,XX +XXX,XX @@ static void tz_ppc_realize(DeviceState *dev, Error **errp)
46
+ 0xff, 0xff, 0xff, 0x17, /* b -4 (loop) */
69
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
47
};
70
TZPPC *s = TZ_PPC(dev);
48
71
int i;
49
static const uint8_t kernel_nrf51[] = {
72
+ int max_port = 0;
73
74
/* We can't create the upstream end of the port until realize,
75
* as we don't know the size of the MR used as the downstream until then.
76
*/
77
for (i = 0; i < TZ_NUM_PORTS; i++) {
78
+ if (s->port[i].downstream) {
79
+ max_port = i;
80
+ }
81
+ }
82
+
83
+ for (i = 0; i <= max_port; i++) {
84
TZPPCPort *port = &s->port[i];
85
char *name;
86
uint64_t size;
87
88
if (!port->downstream) {
89
+ /*
90
+ * Create dummy sysbus MMIO region so the sysbus region
91
+ * numbering doesn't get out of sync with the port numbers.
92
+ * The size is entirely arbitrary.
93
+ */
94
+ name = g_strdup_printf("tz-ppc-dummy-port[%d]", i);
95
+ memory_region_init_io(&port->upstream, obj, &tz_ppc_dummy_ops,
96
+ port, name, 0x10000);
97
+ sysbus_init_mmio(sbd, &port->upstream);
98
+ g_free(name);
99
continue;
100
}
101
102
--
50
--
103
2.20.1
51
2.34.1
104
52
105
53
diff view generated by jsdifflib
1
Create a new include file for the pl011's device struct,
1
From: Philippe Mathieu-Daudé <philmd@linaro.org>
2
type macros, etc, so that it can be instantiated using
3
the "embedded struct" coding style.
4
2
3
In the next commit we are going to use a different value
4
for the $w1 register, maintaining the same $x2 value. In
5
order to keep the next commit trivial to review, set $x2
6
before $w1.
7
8
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Reviewed-by: Fabiano Rosas <farosas@suse.de>
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
---
12
---
9
include/hw/char/pl011.h | 34 ++++++++++++++++++++++++++++++++++
13
tests/qtest/boot-serial-test.c | 2 +-
10
hw/char/pl011.c | 31 ++-----------------------------
14
1 file changed, 1 insertion(+), 1 deletion(-)
11
2 files changed, 36 insertions(+), 29 deletions(-)
12
15
13
diff --git a/include/hw/char/pl011.h b/include/hw/char/pl011.h
16
diff --git a/tests/qtest/boot-serial-test.c b/tests/qtest/boot-serial-test.c
14
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
15
--- a/include/hw/char/pl011.h
18
--- a/tests/qtest/boot-serial-test.c
16
+++ b/include/hw/char/pl011.h
19
+++ b/tests/qtest/boot-serial-test.c
17
@@ -XXX,XX +XXX,XX @@
20
@@ -XXX,XX +XXX,XX @@ static const uint8_t bios_raspi2[] = {
18
#ifndef HW_PL011_H
21
};
19
#define HW_PL011_H
22
20
23
static const uint8_t kernel_aarch64[] = {
21
+#include "hw/sysbus.h"
24
- 0x81, 0x0a, 0x80, 0x52, /* mov w1, #'T' */
22
+#include "chardev/char-fe.h"
25
0x02, 0x20, 0xa1, 0xd2, /* mov x2, #0x9000000 Load UART0 */
23
+
26
+ 0x81, 0x0a, 0x80, 0x52, /* mov w1, #'T' */
24
+#define TYPE_PL011 "pl011"
27
0x41, 0x00, 0x00, 0x39, /* loop: strb w1, [x2] *TXDAT = 'T' */
25
+#define PL011(obj) OBJECT_CHECK(PL011State, (obj), TYPE_PL011)
28
0xff, 0xff, 0xff, 0x17, /* b -4 (loop) */
26
+
27
+/* This shares the same struct (and cast macro) as the base pl011 device */
28
+#define TYPE_PL011_LUMINARY "pl011_luminary"
29
+
30
+typedef struct PL011State {
31
+ SysBusDevice parent_obj;
32
+
33
+ MemoryRegion iomem;
34
+ uint32_t readbuff;
35
+ uint32_t flags;
36
+ uint32_t lcr;
37
+ uint32_t rsr;
38
+ uint32_t cr;
39
+ uint32_t dmacr;
40
+ uint32_t int_enabled;
41
+ uint32_t int_level;
42
+ uint32_t read_fifo[16];
43
+ uint32_t ilpr;
44
+ uint32_t ibrd;
45
+ uint32_t fbrd;
46
+ uint32_t ifl;
47
+ int read_pos;
48
+ int read_count;
49
+ int read_trigger;
50
+ CharBackend chr;
51
+ qemu_irq irq;
52
+ const unsigned char *id;
53
+} PL011State;
54
+
55
static inline DeviceState *pl011_create(hwaddr addr,
56
qemu_irq irq,
57
Chardev *chr)
58
diff --git a/hw/char/pl011.c b/hw/char/pl011.c
59
index XXXXXXX..XXXXXXX 100644
60
--- a/hw/char/pl011.c
61
+++ b/hw/char/pl011.c
62
@@ -XXX,XX +XXX,XX @@
63
*/
64
65
#include "qemu/osdep.h"
66
+#include "hw/char/pl011.h"
67
#include "hw/sysbus.h"
68
#include "chardev/char-fe.h"
69
#include "qemu/log.h"
70
#include "trace.h"
71
72
-#define TYPE_PL011 "pl011"
73
-#define PL011(obj) OBJECT_CHECK(PL011State, (obj), TYPE_PL011)
74
-
75
-typedef struct PL011State {
76
- SysBusDevice parent_obj;
77
-
78
- MemoryRegion iomem;
79
- uint32_t readbuff;
80
- uint32_t flags;
81
- uint32_t lcr;
82
- uint32_t rsr;
83
- uint32_t cr;
84
- uint32_t dmacr;
85
- uint32_t int_enabled;
86
- uint32_t int_level;
87
- uint32_t read_fifo[16];
88
- uint32_t ilpr;
89
- uint32_t ibrd;
90
- uint32_t fbrd;
91
- uint32_t ifl;
92
- int read_pos;
93
- int read_count;
94
- int read_trigger;
95
- CharBackend chr;
96
- qemu_irq irq;
97
- const unsigned char *id;
98
-} PL011State;
99
-
100
#define PL011_INT_TX 0x20
101
#define PL011_INT_RX 0x10
102
103
@@ -XXX,XX +XXX,XX @@ static void pl011_luminary_init(Object *obj)
104
}
105
106
static const TypeInfo pl011_luminary_info = {
107
- .name = "pl011_luminary",
108
+ .name = TYPE_PL011_LUMINARY,
109
.parent = TYPE_PL011,
110
.instance_init = pl011_luminary_init,
111
};
29
};
112
--
30
--
113
2.20.1
31
2.34.1
114
32
115
33
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Philippe Mathieu-Daudé <philmd@linaro.org>
2
2
3
There are lots of special cases within these insns. Split the
3
The tests using the PL011 UART of the virt and raspi machines
4
major argument decode/loading/saving into no_output (compares),
4
weren't properly enabling the UART and its transmitter previous
5
rd_is_dp, and rm_is_dp.
5
to sending characters. Follow the PL011 manual initialization
6
recommendation by setting the proper bits of the control register.
6
7
7
We still need to special case argument load for compare (rd as
8
Update the ASM code prefixing:
8
input, rm as zero) and vcvt fixed (rd as input+output), but lots
9
of special cases do disappear.
10
9
11
Now that we have a full switch at the beginning, hoist the ISA
10
*UART_CTRL = UART_ENABLE | TX_ENABLE;
12
checks from the code generation.
13
11
14
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
12
to:
15
Message-id: 20190215192302.27855-4-richard.henderson@linaro.org
13
16
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
14
while (true) {
15
*UART_DATA = 'T';
16
}
17
18
Note, since commit 51b61dd4d56 ("hw/char/pl011: Warn when using
19
disabled transmitter") incomplete PL011 initialization can be
20
logged using the '-d guest_errors' command line option.
21
22
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
23
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
17
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
24
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
18
---
25
---
19
target/arm/translate.c | 227 ++++++++++++++++++++---------------------
26
tests/qtest/boot-serial-test.c | 7 ++++++-
20
1 file changed, 111 insertions(+), 116 deletions(-)
27
1 file changed, 6 insertions(+), 1 deletion(-)
21
28
22
diff --git a/target/arm/translate.c b/target/arm/translate.c
29
diff --git a/tests/qtest/boot-serial-test.c b/tests/qtest/boot-serial-test.c
23
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
24
--- a/target/arm/translate.c
31
--- a/tests/qtest/boot-serial-test.c
25
+++ b/target/arm/translate.c
32
+++ b/tests/qtest/boot-serial-test.c
26
@@ -XXX,XX +XXX,XX @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
33
@@ -XXX,XX +XXX,XX @@ static const uint8_t kernel_plml605[] = {
27
}
34
};
28
} else {
35
29
/* data processing */
36
static const uint8_t bios_raspi2[] = {
30
+ bool rd_is_dp = dp;
37
- 0x08, 0x30, 0x9f, 0xe5, /* ldr r3, [pc, #8] Get &UART0 */
31
+ bool rm_is_dp = dp;
38
+ 0x10, 0x30, 0x9f, 0xe5, /* ldr r3, [pc, #16] Get &UART0 */
32
+ bool no_output = false;
39
+ 0x10, 0x20, 0x9f, 0xe5, /* ldr r2, [pc, #16] Get &CR */
33
+
40
+ 0xb0, 0x23, 0xc3, 0xe1, /* strh r2, [r3, #48] Set CR */
34
/* The opcode is in bits 23, 21, 20 and 6. */
41
0x54, 0x20, 0xa0, 0xe3, /* mov r2, #'T' */
35
op = ((insn >> 20) & 8) | ((insn >> 19) & 6) | ((insn >> 6) & 1);
42
0x00, 0x20, 0xc3, 0xe5, /* loop: strb r2, [r3] *TXDAT = 'T' */
36
- if (dp) {
43
0xff, 0xff, 0xff, 0xea, /* b -4 (loop) */
37
- if (op == 15) {
44
0x00, 0x10, 0x20, 0x3f, /* UART0: 0x3f201000 */
38
- /* rn is opcode */
45
+ 0x01, 0x01, 0x00, 0x00, /* CR: 0x101 = UARTEN|TXE */
39
- rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
46
};
40
- } else {
47
41
- /* rn is register number */
48
static const uint8_t kernel_aarch64[] = {
42
- VFP_DREG_N(rn, insn);
49
0x02, 0x20, 0xa1, 0xd2, /* mov x2, #0x9000000 Load UART0 */
43
- }
50
+ 0x21, 0x20, 0x80, 0x52, /* mov w1, 0x101 CR = UARTEN|TXE */
44
+ rn = VFP_SREG_N(insn);
51
+ 0x41, 0x60, 0x00, 0x79, /* strh w1, [x2, #48] Set CR */
45
52
0x81, 0x0a, 0x80, 0x52, /* mov w1, #'T' */
46
- if (op == 15 && (rn == 15 || ((rn & 0x1c) == 0x18) ||
53
0x41, 0x00, 0x00, 0x39, /* loop: strb w1, [x2] *TXDAT = 'T' */
47
- ((rn & 0x1e) == 0x6))) {
54
0xff, 0xff, 0xff, 0x17, /* b -4 (loop) */
48
- /* Integer or single/half precision destination. */
49
- rd = VFP_SREG_D(insn);
50
- } else {
51
- VFP_DREG_D(rd, insn);
52
- }
53
- if (op == 15 &&
54
- (((rn & 0x1c) == 0x10) || ((rn & 0x14) == 0x14) ||
55
- ((rn & 0x1e) == 0x4))) {
56
- /* VCVT from int or half precision is always from S reg
57
- * regardless of dp bit. VCVT with immediate frac_bits
58
- * has same format as SREG_M.
59
+ if (op == 15) {
60
+ /* rn is opcode, encoded as per VFP_SREG_N. */
61
+ switch (rn) {
62
+ case 0x00: /* vmov */
63
+ case 0x01: /* vabs */
64
+ case 0x02: /* vneg */
65
+ case 0x03: /* vsqrt */
66
+ break;
67
+
68
+ case 0x04: /* vcvtb.f64.f16, vcvtb.f32.f16 */
69
+ case 0x05: /* vcvtt.f64.f16, vcvtt.f32.f16 */
70
+ /*
71
+ * VCVTB, VCVTT: only present with the halfprec extension
72
+ * UNPREDICTABLE if bit 8 is set prior to ARMv8
73
+ * (we choose to UNDEF)
74
*/
75
- rm = VFP_SREG_M(insn);
76
- } else {
77
- VFP_DREG_M(rm, insn);
78
+ if ((dp && !arm_dc_feature(s, ARM_FEATURE_V8)) ||
79
+ !arm_dc_feature(s, ARM_FEATURE_VFP_FP16)) {
80
+ return 1;
81
+ }
82
+ rm_is_dp = false;
83
+ break;
84
+ case 0x06: /* vcvtb.f16.f32, vcvtb.f16.f64 */
85
+ case 0x07: /* vcvtt.f16.f32, vcvtt.f16.f64 */
86
+ if ((dp && !arm_dc_feature(s, ARM_FEATURE_V8)) ||
87
+ !arm_dc_feature(s, ARM_FEATURE_VFP_FP16)) {
88
+ return 1;
89
+ }
90
+ rd_is_dp = false;
91
+ break;
92
+
93
+ case 0x08: case 0x0a: /* vcmp, vcmpz */
94
+ case 0x09: case 0x0b: /* vcmpe, vcmpez */
95
+ no_output = true;
96
+ break;
97
+
98
+ case 0x0c: /* vrintr */
99
+ case 0x0d: /* vrintz */
100
+ case 0x0e: /* vrintx */
101
+ break;
102
+
103
+ case 0x0f: /* vcvt double<->single */
104
+ rd_is_dp = !dp;
105
+ break;
106
+
107
+ case 0x10: /* vcvt.fxx.u32 */
108
+ case 0x11: /* vcvt.fxx.s32 */
109
+ rm_is_dp = false;
110
+ break;
111
+ case 0x18: /* vcvtr.u32.fxx */
112
+ case 0x19: /* vcvtz.u32.fxx */
113
+ case 0x1a: /* vcvtr.s32.fxx */
114
+ case 0x1b: /* vcvtz.s32.fxx */
115
+ rd_is_dp = false;
116
+ break;
117
+
118
+ case 0x14: /* vcvt fp <-> fixed */
119
+ case 0x15:
120
+ case 0x16:
121
+ case 0x17:
122
+ case 0x1c:
123
+ case 0x1d:
124
+ case 0x1e:
125
+ case 0x1f:
126
+ if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
127
+ return 1;
128
+ }
129
+ /* Immediate frac_bits has same format as SREG_M. */
130
+ rm_is_dp = false;
131
+ break;
132
+
133
+ default:
134
+ return 1;
135
}
136
+ } else if (dp) {
137
+ /* rn is register number */
138
+ VFP_DREG_N(rn, insn);
139
+ }
140
+
141
+ if (rd_is_dp) {
142
+ VFP_DREG_D(rd, insn);
143
+ } else {
144
+ rd = VFP_SREG_D(insn);
145
+ }
146
+ if (rm_is_dp) {
147
+ VFP_DREG_M(rm, insn);
148
} else {
149
- rn = VFP_SREG_N(insn);
150
- if (op == 15 && rn == 15) {
151
- /* Double precision destination. */
152
- VFP_DREG_D(rd, insn);
153
- } else {
154
- rd = VFP_SREG_D(insn);
155
- }
156
- /* NB that we implicitly rely on the encoding for the frac_bits
157
- * in VCVT of fixed to float being the same as that of an SREG_M
158
- */
159
rm = VFP_SREG_M(insn);
160
}
161
162
veclen = s->vec_len;
163
- if (op == 15 && rn > 3)
164
+ if (op == 15 && rn > 3) {
165
veclen = 0;
166
+ }
167
168
/* Shut up compiler warnings. */
169
delta_m = 0;
170
@@ -XXX,XX +XXX,XX @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
171
/* Load the initial operands. */
172
if (op == 15) {
173
switch (rn) {
174
- case 16:
175
- case 17:
176
- /* Integer source */
177
- gen_mov_F0_vreg(0, rm);
178
- break;
179
- case 8:
180
- case 9:
181
- /* Compare */
182
+ case 0x08: case 0x09: /* Compare */
183
gen_mov_F0_vreg(dp, rd);
184
gen_mov_F1_vreg(dp, rm);
185
break;
186
- case 10:
187
- case 11:
188
- /* Compare with zero */
189
+ case 0x0a: case 0x0b: /* Compare with zero */
190
gen_mov_F0_vreg(dp, rd);
191
gen_vfp_F1_ld0(dp);
192
break;
193
- case 20:
194
- case 21:
195
- case 22:
196
- case 23:
197
- case 28:
198
- case 29:
199
- case 30:
200
- case 31:
201
+ case 0x14: /* vcvt fp <-> fixed */
202
+ case 0x15:
203
+ case 0x16:
204
+ case 0x17:
205
+ case 0x1c:
206
+ case 0x1d:
207
+ case 0x1e:
208
+ case 0x1f:
209
/* Source and destination the same. */
210
gen_mov_F0_vreg(dp, rd);
211
break;
212
- case 4:
213
- case 5:
214
- case 6:
215
- case 7:
216
- /* VCVTB, VCVTT: only present with the halfprec extension
217
- * UNPREDICTABLE if bit 8 is set prior to ARMv8
218
- * (we choose to UNDEF)
219
- */
220
- if ((dp && !arm_dc_feature(s, ARM_FEATURE_V8)) ||
221
- !arm_dc_feature(s, ARM_FEATURE_VFP_FP16)) {
222
- return 1;
223
- }
224
- if (!extract32(rn, 1, 1)) {
225
- /* Half precision source. */
226
- gen_mov_F0_vreg(0, rm);
227
- break;
228
- }
229
- /* Otherwise fall through */
230
default:
231
/* One source operand. */
232
- gen_mov_F0_vreg(dp, rm);
233
+ gen_mov_F0_vreg(rm_is_dp, rm);
234
break;
235
}
236
} else {
237
@@ -XXX,XX +XXX,XX @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
238
break;
239
}
240
case 15: /* single<->double conversion */
241
- if (dp)
242
+ if (dp) {
243
gen_helper_vfp_fcvtsd(cpu_F0s, cpu_F0d, cpu_env);
244
- else
245
+ } else {
246
gen_helper_vfp_fcvtds(cpu_F0d, cpu_F0s, cpu_env);
247
+ }
248
break;
249
case 16: /* fuito */
250
gen_vfp_uito(dp, 0);
251
@@ -XXX,XX +XXX,XX @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
252
gen_vfp_sito(dp, 0);
253
break;
254
case 20: /* fshto */
255
- if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
256
- return 1;
257
- }
258
gen_vfp_shto(dp, 16 - rm, 0);
259
break;
260
case 21: /* fslto */
261
- if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
262
- return 1;
263
- }
264
gen_vfp_slto(dp, 32 - rm, 0);
265
break;
266
case 22: /* fuhto */
267
- if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
268
- return 1;
269
- }
270
gen_vfp_uhto(dp, 16 - rm, 0);
271
break;
272
case 23: /* fulto */
273
- if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
274
- return 1;
275
- }
276
gen_vfp_ulto(dp, 32 - rm, 0);
277
break;
278
case 24: /* ftoui */
279
@@ -XXX,XX +XXX,XX @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
280
gen_vfp_tosiz(dp, 0);
281
break;
282
case 28: /* ftosh */
283
- if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
284
- return 1;
285
- }
286
gen_vfp_tosh(dp, 16 - rm, 0);
287
break;
288
case 29: /* ftosl */
289
- if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
290
- return 1;
291
- }
292
gen_vfp_tosl(dp, 32 - rm, 0);
293
break;
294
case 30: /* ftouh */
295
- if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
296
- return 1;
297
- }
298
gen_vfp_touh(dp, 16 - rm, 0);
299
break;
300
case 31: /* ftoul */
301
- if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
302
- return 1;
303
- }
304
gen_vfp_toul(dp, 32 - rm, 0);
305
break;
306
default: /* undefined */
307
- return 1;
308
+ g_assert_not_reached();
309
}
310
break;
311
default: /* undefined */
312
return 1;
313
}
314
315
- /* Write back the result. */
316
- if (op == 15 && (rn >= 8 && rn <= 11)) {
317
- /* Comparison, do nothing. */
318
- } else if (op == 15 && dp && ((rn & 0x1c) == 0x18 ||
319
- (rn & 0x1e) == 0x6)) {
320
- /* VCVT double to int: always integer result.
321
- * VCVT double to half precision is always a single
322
- * precision result.
323
- */
324
- gen_mov_vreg_F0(0, rd);
325
- } else if (op == 15 && rn == 15) {
326
- /* conversion */
327
- gen_mov_vreg_F0(!dp, rd);
328
- } else {
329
- gen_mov_vreg_F0(dp, rd);
330
+ /* Write back the result, if any. */
331
+ if (!no_output) {
332
+ gen_mov_vreg_F0(rd_is_dp, rd);
333
}
334
335
/* break out of the loop if we have finished */
336
- if (veclen == 0)
337
+ if (veclen == 0) {
338
break;
339
+ }
340
341
if (op == 15 && delta_m == 0) {
342
/* single source one-many */
343
--
55
--
344
2.20.1
56
2.34.1
345
57
346
58
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
helper.c includes some small TCG helper functions used for mostly
2
arithmetic instructions. These are TCG only and there's no need for
3
them to be in the large and unwieldy helper.c. Move them out to
4
their own source file in the tcg/ subdirectory, together with the
5
op_addsub.h multiply-included template header that they use.
2
6
3
Move all of the fp helpers out of helper.c into a new file.
7
Since we are moving op_addsub.h, we take the opportunity to
4
This is code movement only. Since helper.c has no copyright
8
give it a name which matches our convention for files which
5
header, take the one from cpu.h for the new file.
9
are not true header files but which are #included from other
10
C files: op_addsub.c.inc.
6
11
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
12
(Ironically, this means that helper.c no longer contains
8
Message-id: 20190215192302.27855-3-richard.henderson@linaro.org
13
any TCG helper function definitions at all.)
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
14
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
17
Message-id: 20250110131211.2546314-1-peter.maydell@linaro.org
18
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
11
---
19
---
12
target/arm/Makefile.objs | 2 +-
20
target/arm/helper.c | 285 -----------------
13
target/arm/helper.c | 1062 -------------------------------------
21
target/arm/tcg/arith_helper.c | 296 ++++++++++++++++++
14
target/arm/vfp_helper.c | 1088 ++++++++++++++++++++++++++++++++++++++
22
.../arm/{op_addsub.h => tcg/op_addsub.c.inc} | 0
15
3 files changed, 1089 insertions(+), 1063 deletions(-)
23
target/arm/tcg/meson.build | 1 +
16
create mode 100644 target/arm/vfp_helper.c
24
4 files changed, 297 insertions(+), 285 deletions(-)
25
create mode 100644 target/arm/tcg/arith_helper.c
26
rename target/arm/{op_addsub.h => tcg/op_addsub.c.inc} (100%)
17
27
18
diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
19
index XXXXXXX..XXXXXXX 100644
20
--- a/target/arm/Makefile.objs
21
+++ b/target/arm/Makefile.objs
22
@@ -XXX,XX +XXX,XX @@ obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
23
obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
24
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
25
obj-y += translate.o op_helper.o helper.o cpu.o
26
-obj-y += neon_helper.o iwmmxt_helper.o vec_helper.o
27
+obj-y += neon_helper.o iwmmxt_helper.o vec_helper.o vfp_helper.o
28
obj-y += gdbstub.o
29
obj-$(TARGET_AARCH64) += cpu64.o translate-a64.o helper-a64.o gdbstub64.o
30
obj-$(TARGET_AARCH64) += pauth_helper.o
31
diff --git a/target/arm/helper.c b/target/arm/helper.c
28
diff --git a/target/arm/helper.c b/target/arm/helper.c
32
index XXXXXXX..XXXXXXX 100644
29
index XXXXXXX..XXXXXXX 100644
33
--- a/target/arm/helper.c
30
--- a/target/arm/helper.c
34
+++ b/target/arm/helper.c
31
+++ b/target/arm/helper.c
35
@@ -XXX,XX +XXX,XX @@ uint32_t HELPER(sel_flags)(uint32_t flags, uint32_t a, uint32_t b)
32
@@ -XXX,XX +XXX,XX @@
36
return (a & mask) | (b & ~mask);
33
#include "qemu/main-loop.h"
34
#include "qemu/timer.h"
35
#include "qemu/bitops.h"
36
-#include "qemu/crc32c.h"
37
#include "qemu/qemu-print.h"
38
#include "exec/exec-all.h"
39
#include "exec/translation-block.h"
40
-#include <zlib.h> /* for crc32 */
41
#include "hw/irq.h"
42
#include "system/cpu-timers.h"
43
#include "system/kvm.h"
44
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
45
};
37
}
46
}
38
47
39
-/* VFP support. We follow the convention used for VFP instructions:
48
-/*
40
- Single precision routines have a "s" suffix, double precision a
49
- * Note that signed overflow is undefined in C. The following routines are
41
- "d" suffix. */
50
- * careful to use unsigned types where modulo arithmetic is required.
42
-
51
- * Failure to do so _will_ break on newer gcc.
43
-/* Convert host exception flags to vfp form. */
52
- */
44
-static inline int vfp_exceptbits_from_host(int host_bits)
53
-
45
-{
54
-/* Signed saturating arithmetic. */
46
- int target_bits = 0;
55
-
47
-
56
-/* Perform 16-bit signed saturating addition. */
48
- if (host_bits & float_flag_invalid)
57
-static inline uint16_t add16_sat(uint16_t a, uint16_t b)
49
- target_bits |= 1;
58
-{
50
- if (host_bits & float_flag_divbyzero)
59
- uint16_t res;
51
- target_bits |= 2;
60
-
52
- if (host_bits & float_flag_overflow)
61
- res = a + b;
53
- target_bits |= 4;
62
- if (((res ^ a) & 0x8000) && !((a ^ b) & 0x8000)) {
54
- if (host_bits & (float_flag_underflow | float_flag_output_denormal))
63
- if (a & 0x8000) {
55
- target_bits |= 8;
64
- res = 0x8000;
56
- if (host_bits & float_flag_inexact)
65
- } else {
57
- target_bits |= 0x10;
66
- res = 0x7fff;
58
- if (host_bits & float_flag_input_denormal)
59
- target_bits |= 0x80;
60
- return target_bits;
61
-}
62
-
63
-uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env)
64
-{
65
- uint32_t i, fpscr;
66
-
67
- fpscr = env->vfp.xregs[ARM_VFP_FPSCR]
68
- | (env->vfp.vec_len << 16)
69
- | (env->vfp.vec_stride << 20);
70
-
71
- i = get_float_exception_flags(&env->vfp.fp_status);
72
- i |= get_float_exception_flags(&env->vfp.standard_fp_status);
73
- /* FZ16 does not generate an input denormal exception. */
74
- i |= (get_float_exception_flags(&env->vfp.fp_status_f16)
75
- & ~float_flag_input_denormal);
76
- fpscr |= vfp_exceptbits_from_host(i);
77
-
78
- i = env->vfp.qc[0] | env->vfp.qc[1] | env->vfp.qc[2] | env->vfp.qc[3];
79
- fpscr |= i ? FPCR_QC : 0;
80
-
81
- return fpscr;
82
-}
83
-
84
-uint32_t vfp_get_fpscr(CPUARMState *env)
85
-{
86
- return HELPER(vfp_get_fpscr)(env);
87
-}
88
-
89
-/* Convert vfp exception flags to target form. */
90
-static inline int vfp_exceptbits_to_host(int target_bits)
91
-{
92
- int host_bits = 0;
93
-
94
- if (target_bits & 1)
95
- host_bits |= float_flag_invalid;
96
- if (target_bits & 2)
97
- host_bits |= float_flag_divbyzero;
98
- if (target_bits & 4)
99
- host_bits |= float_flag_overflow;
100
- if (target_bits & 8)
101
- host_bits |= float_flag_underflow;
102
- if (target_bits & 0x10)
103
- host_bits |= float_flag_inexact;
104
- if (target_bits & 0x80)
105
- host_bits |= float_flag_input_denormal;
106
- return host_bits;
107
-}
108
-
109
-void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val)
110
-{
111
- int i;
112
- uint32_t changed = env->vfp.xregs[ARM_VFP_FPSCR];
113
-
114
- /* When ARMv8.2-FP16 is not supported, FZ16 is RES0. */
115
- if (!cpu_isar_feature(aa64_fp16, arm_env_get_cpu(env))) {
116
- val &= ~FPCR_FZ16;
117
- }
118
-
119
- /*
120
- * We don't implement trapped exception handling, so the
121
- * trap enable bits, IDE|IXE|UFE|OFE|DZE|IOE are all RAZ/WI (not RES0!)
122
- *
123
- * If we exclude the exception flags, IOC|DZC|OFC|UFC|IXC|IDC
124
- * (which are stored in fp_status), and the other RES0 bits
125
- * in between, then we clear all of the low 16 bits.
126
- */
127
- env->vfp.xregs[ARM_VFP_FPSCR] = val & 0xf7c80000;
128
- env->vfp.vec_len = (val >> 16) & 7;
129
- env->vfp.vec_stride = (val >> 20) & 3;
130
-
131
- /*
132
- * The bit we set within fpscr_q is arbitrary; the register as a
133
- * whole being zero/non-zero is what counts.
134
- */
135
- env->vfp.qc[0] = val & FPCR_QC;
136
- env->vfp.qc[1] = 0;
137
- env->vfp.qc[2] = 0;
138
- env->vfp.qc[3] = 0;
139
-
140
- changed ^= val;
141
- if (changed & (3 << 22)) {
142
- i = (val >> 22) & 3;
143
- switch (i) {
144
- case FPROUNDING_TIEEVEN:
145
- i = float_round_nearest_even;
146
- break;
147
- case FPROUNDING_POSINF:
148
- i = float_round_up;
149
- break;
150
- case FPROUNDING_NEGINF:
151
- i = float_round_down;
152
- break;
153
- case FPROUNDING_ZERO:
154
- i = float_round_to_zero;
155
- break;
156
- }
67
- }
157
- set_float_rounding_mode(i, &env->vfp.fp_status);
68
- }
158
- set_float_rounding_mode(i, &env->vfp.fp_status_f16);
69
- return res;
159
- }
70
-}
160
- if (changed & FPCR_FZ16) {
71
-
161
- bool ftz_enabled = val & FPCR_FZ16;
72
-/* Perform 8-bit signed saturating addition. */
162
- set_flush_to_zero(ftz_enabled, &env->vfp.fp_status_f16);
73
-static inline uint8_t add8_sat(uint8_t a, uint8_t b)
163
- set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status_f16);
74
-{
164
- }
75
- uint8_t res;
165
- if (changed & FPCR_FZ) {
76
-
166
- bool ftz_enabled = val & FPCR_FZ;
77
- res = a + b;
167
- set_flush_to_zero(ftz_enabled, &env->vfp.fp_status);
78
- if (((res ^ a) & 0x80) && !((a ^ b) & 0x80)) {
168
- set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status);
79
- if (a & 0x80) {
169
- }
80
- res = 0x80;
170
- if (changed & FPCR_DN) {
81
- } else {
171
- bool dnan_enabled = val & FPCR_DN;
82
- res = 0x7f;
172
- set_default_nan_mode(dnan_enabled, &env->vfp.fp_status);
83
- }
173
- set_default_nan_mode(dnan_enabled, &env->vfp.fp_status_f16);
84
- }
174
- }
85
- return res;
175
-
86
-}
176
- /* The exception flags are ORed together when we read fpscr so we
87
-
177
- * only need to preserve the current state in one of our
88
-/* Perform 16-bit signed saturating subtraction. */
178
- * float_status values.
89
-static inline uint16_t sub16_sat(uint16_t a, uint16_t b)
179
- */
90
-{
180
- i = vfp_exceptbits_to_host(val);
91
- uint16_t res;
181
- set_float_exception_flags(i, &env->vfp.fp_status);
92
-
182
- set_float_exception_flags(0, &env->vfp.fp_status_f16);
93
- res = a - b;
183
- set_float_exception_flags(0, &env->vfp.standard_fp_status);
94
- if (((res ^ a) & 0x8000) && ((a ^ b) & 0x8000)) {
184
-}
95
- if (a & 0x8000) {
185
-
96
- res = 0x8000;
186
-void vfp_set_fpscr(CPUARMState *env, uint32_t val)
97
- } else {
187
-{
98
- res = 0x7fff;
188
- HELPER(vfp_set_fpscr)(env, val);
99
- }
189
-}
100
- }
190
-
101
- return res;
191
-#define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p))
102
-}
192
-
103
-
193
-#define VFP_BINOP(name) \
104
-/* Perform 8-bit signed saturating subtraction. */
194
-float32 VFP_HELPER(name, s)(float32 a, float32 b, void *fpstp) \
105
-static inline uint8_t sub8_sat(uint8_t a, uint8_t b)
195
-{ \
106
-{
196
- float_status *fpst = fpstp; \
107
- uint8_t res;
197
- return float32_ ## name(a, b, fpst); \
108
-
198
-} \
109
- res = a - b;
199
-float64 VFP_HELPER(name, d)(float64 a, float64 b, void *fpstp) \
110
- if (((res ^ a) & 0x80) && ((a ^ b) & 0x80)) {
200
-{ \
111
- if (a & 0x80) {
201
- float_status *fpst = fpstp; \
112
- res = 0x80;
202
- return float64_ ## name(a, b, fpst); \
113
- } else {
203
-}
114
- res = 0x7f;
204
-VFP_BINOP(add)
115
- }
205
-VFP_BINOP(sub)
116
- }
206
-VFP_BINOP(mul)
117
- return res;
207
-VFP_BINOP(div)
118
-}
208
-VFP_BINOP(min)
119
-
209
-VFP_BINOP(max)
120
-#define ADD16(a, b, n) RESULT(add16_sat(a, b), n, 16);
210
-VFP_BINOP(minnum)
121
-#define SUB16(a, b, n) RESULT(sub16_sat(a, b), n, 16);
211
-VFP_BINOP(maxnum)
122
-#define ADD8(a, b, n) RESULT(add8_sat(a, b), n, 8);
212
-#undef VFP_BINOP
123
-#define SUB8(a, b, n) RESULT(sub8_sat(a, b), n, 8);
213
-
124
-#define PFX q
214
-float32 VFP_HELPER(neg, s)(float32 a)
125
-
215
-{
126
-#include "op_addsub.h"
216
- return float32_chs(a);
127
-
217
-}
128
-/* Unsigned saturating arithmetic. */
218
-
129
-static inline uint16_t add16_usat(uint16_t a, uint16_t b)
219
-float64 VFP_HELPER(neg, d)(float64 a)
130
-{
220
-{
131
- uint16_t res;
221
- return float64_chs(a);
132
- res = a + b;
222
-}
133
- if (res < a) {
223
-
134
- res = 0xffff;
224
-float32 VFP_HELPER(abs, s)(float32 a)
135
- }
225
-{
136
- return res;
226
- return float32_abs(a);
137
-}
227
-}
138
-
228
-
139
-static inline uint16_t sub16_usat(uint16_t a, uint16_t b)
229
-float64 VFP_HELPER(abs, d)(float64 a)
140
-{
230
-{
141
- if (a > b) {
231
- return float64_abs(a);
142
- return a - b;
232
-}
143
- } else {
233
-
234
-float32 VFP_HELPER(sqrt, s)(float32 a, CPUARMState *env)
235
-{
236
- return float32_sqrt(a, &env->vfp.fp_status);
237
-}
238
-
239
-float64 VFP_HELPER(sqrt, d)(float64 a, CPUARMState *env)
240
-{
241
- return float64_sqrt(a, &env->vfp.fp_status);
242
-}
243
-
244
-static void softfloat_to_vfp_compare(CPUARMState *env, int cmp)
245
-{
246
- uint32_t flags;
247
- switch (cmp) {
248
- case float_relation_equal:
249
- flags = 0x6;
250
- break;
251
- case float_relation_less:
252
- flags = 0x8;
253
- break;
254
- case float_relation_greater:
255
- flags = 0x2;
256
- break;
257
- case float_relation_unordered:
258
- flags = 0x3;
259
- break;
260
- default:
261
- g_assert_not_reached();
262
- }
263
- env->vfp.xregs[ARM_VFP_FPSCR] =
264
- deposit32(env->vfp.xregs[ARM_VFP_FPSCR], 28, 4, flags);
265
-}
266
-
267
-/* XXX: check quiet/signaling case */
268
-#define DO_VFP_cmp(p, type) \
269
-void VFP_HELPER(cmp, p)(type a, type b, CPUARMState *env) \
270
-{ \
271
- softfloat_to_vfp_compare(env, \
272
- type ## _compare_quiet(a, b, &env->vfp.fp_status)); \
273
-} \
274
-void VFP_HELPER(cmpe, p)(type a, type b, CPUARMState *env) \
275
-{ \
276
- softfloat_to_vfp_compare(env, \
277
- type ## _compare(a, b, &env->vfp.fp_status)); \
278
-}
279
-DO_VFP_cmp(s, float32)
280
-DO_VFP_cmp(d, float64)
281
-#undef DO_VFP_cmp
282
-
283
-/* Integer to float and float to integer conversions */
284
-
285
-#define CONV_ITOF(name, ftype, fsz, sign) \
286
-ftype HELPER(name)(uint32_t x, void *fpstp) \
287
-{ \
288
- float_status *fpst = fpstp; \
289
- return sign##int32_to_##float##fsz((sign##int32_t)x, fpst); \
290
-}
291
-
292
-#define CONV_FTOI(name, ftype, fsz, sign, round) \
293
-sign##int32_t HELPER(name)(ftype x, void *fpstp) \
294
-{ \
295
- float_status *fpst = fpstp; \
296
- if (float##fsz##_is_any_nan(x)) { \
297
- float_raise(float_flag_invalid, fpst); \
298
- return 0; \
299
- } \
300
- return float##fsz##_to_##sign##int32##round(x, fpst); \
301
-}
302
-
303
-#define FLOAT_CONVS(name, p, ftype, fsz, sign) \
304
- CONV_ITOF(vfp_##name##to##p, ftype, fsz, sign) \
305
- CONV_FTOI(vfp_to##name##p, ftype, fsz, sign, ) \
306
- CONV_FTOI(vfp_to##name##z##p, ftype, fsz, sign, _round_to_zero)
307
-
308
-FLOAT_CONVS(si, h, uint32_t, 16, )
309
-FLOAT_CONVS(si, s, float32, 32, )
310
-FLOAT_CONVS(si, d, float64, 64, )
311
-FLOAT_CONVS(ui, h, uint32_t, 16, u)
312
-FLOAT_CONVS(ui, s, float32, 32, u)
313
-FLOAT_CONVS(ui, d, float64, 64, u)
314
-
315
-#undef CONV_ITOF
316
-#undef CONV_FTOI
317
-#undef FLOAT_CONVS
318
-
319
-/* floating point conversion */
320
-float64 VFP_HELPER(fcvtd, s)(float32 x, CPUARMState *env)
321
-{
322
- return float32_to_float64(x, &env->vfp.fp_status);
323
-}
324
-
325
-float32 VFP_HELPER(fcvts, d)(float64 x, CPUARMState *env)
326
-{
327
- return float64_to_float32(x, &env->vfp.fp_status);
328
-}
329
-
330
-/* VFP3 fixed point conversion. */
331
-#define VFP_CONV_FIX_FLOAT(name, p, fsz, isz, itype) \
332
-float##fsz HELPER(vfp_##name##to##p)(uint##isz##_t x, uint32_t shift, \
333
- void *fpstp) \
334
-{ return itype##_to_##float##fsz##_scalbn(x, -shift, fpstp); }
335
-
336
-#define VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, ROUND, suff) \
337
-uint##isz##_t HELPER(vfp_to##name##p##suff)(float##fsz x, uint32_t shift, \
338
- void *fpst) \
339
-{ \
340
- if (unlikely(float##fsz##_is_any_nan(x))) { \
341
- float_raise(float_flag_invalid, fpst); \
342
- return 0; \
343
- } \
344
- return float##fsz##_to_##itype##_scalbn(x, ROUND, shift, fpst); \
345
-}
346
-
347
-#define VFP_CONV_FIX(name, p, fsz, isz, itype) \
348
-VFP_CONV_FIX_FLOAT(name, p, fsz, isz, itype) \
349
-VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, \
350
- float_round_to_zero, _round_to_zero) \
351
-VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, \
352
- get_float_rounding_mode(fpst), )
353
-
354
-#define VFP_CONV_FIX_A64(name, p, fsz, isz, itype) \
355
-VFP_CONV_FIX_FLOAT(name, p, fsz, isz, itype) \
356
-VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, \
357
- get_float_rounding_mode(fpst), )
358
-
359
-VFP_CONV_FIX(sh, d, 64, 64, int16)
360
-VFP_CONV_FIX(sl, d, 64, 64, int32)
361
-VFP_CONV_FIX_A64(sq, d, 64, 64, int64)
362
-VFP_CONV_FIX(uh, d, 64, 64, uint16)
363
-VFP_CONV_FIX(ul, d, 64, 64, uint32)
364
-VFP_CONV_FIX_A64(uq, d, 64, 64, uint64)
365
-VFP_CONV_FIX(sh, s, 32, 32, int16)
366
-VFP_CONV_FIX(sl, s, 32, 32, int32)
367
-VFP_CONV_FIX_A64(sq, s, 32, 64, int64)
368
-VFP_CONV_FIX(uh, s, 32, 32, uint16)
369
-VFP_CONV_FIX(ul, s, 32, 32, uint32)
370
-VFP_CONV_FIX_A64(uq, s, 32, 64, uint64)
371
-
372
-#undef VFP_CONV_FIX
373
-#undef VFP_CONV_FIX_FLOAT
374
-#undef VFP_CONV_FLOAT_FIX_ROUND
375
-#undef VFP_CONV_FIX_A64
376
-
377
-uint32_t HELPER(vfp_sltoh)(uint32_t x, uint32_t shift, void *fpst)
378
-{
379
- return int32_to_float16_scalbn(x, -shift, fpst);
380
-}
381
-
382
-uint32_t HELPER(vfp_ultoh)(uint32_t x, uint32_t shift, void *fpst)
383
-{
384
- return uint32_to_float16_scalbn(x, -shift, fpst);
385
-}
386
-
387
-uint32_t HELPER(vfp_sqtoh)(uint64_t x, uint32_t shift, void *fpst)
388
-{
389
- return int64_to_float16_scalbn(x, -shift, fpst);
390
-}
391
-
392
-uint32_t HELPER(vfp_uqtoh)(uint64_t x, uint32_t shift, void *fpst)
393
-{
394
- return uint64_to_float16_scalbn(x, -shift, fpst);
395
-}
396
-
397
-uint32_t HELPER(vfp_toshh)(uint32_t x, uint32_t shift, void *fpst)
398
-{
399
- if (unlikely(float16_is_any_nan(x))) {
400
- float_raise(float_flag_invalid, fpst);
401
- return 0;
144
- return 0;
402
- }
145
- }
403
- return float16_to_int16_scalbn(x, get_float_rounding_mode(fpst),
146
-}
404
- shift, fpst);
147
-
405
-}
148
-static inline uint8_t add8_usat(uint8_t a, uint8_t b)
406
-
149
-{
407
-uint32_t HELPER(vfp_touhh)(uint32_t x, uint32_t shift, void *fpst)
150
- uint8_t res;
408
-{
151
- res = a + b;
409
- if (unlikely(float16_is_any_nan(x))) {
152
- if (res < a) {
410
- float_raise(float_flag_invalid, fpst);
153
- res = 0xff;
154
- }
155
- return res;
156
-}
157
-
158
-static inline uint8_t sub8_usat(uint8_t a, uint8_t b)
159
-{
160
- if (a > b) {
161
- return a - b;
162
- } else {
411
- return 0;
163
- return 0;
412
- }
164
- }
413
- return float16_to_uint16_scalbn(x, get_float_rounding_mode(fpst),
165
-}
414
- shift, fpst);
166
-
415
-}
167
-#define ADD16(a, b, n) RESULT(add16_usat(a, b), n, 16);
416
-
168
-#define SUB16(a, b, n) RESULT(sub16_usat(a, b), n, 16);
417
-uint32_t HELPER(vfp_toslh)(uint32_t x, uint32_t shift, void *fpst)
169
-#define ADD8(a, b, n) RESULT(add8_usat(a, b), n, 8);
418
-{
170
-#define SUB8(a, b, n) RESULT(sub8_usat(a, b), n, 8);
419
- if (unlikely(float16_is_any_nan(x))) {
171
-#define PFX uq
420
- float_raise(float_flag_invalid, fpst);
172
-
421
- return 0;
173
-#include "op_addsub.h"
422
- }
174
-
423
- return float16_to_int32_scalbn(x, get_float_rounding_mode(fpst),
175
-/* Signed modulo arithmetic. */
424
- shift, fpst);
176
-#define SARITH16(a, b, n, op) do { \
425
-}
177
- int32_t sum; \
426
-
178
- sum = (int32_t)(int16_t)(a) op (int32_t)(int16_t)(b); \
427
-uint32_t HELPER(vfp_toulh)(uint32_t x, uint32_t shift, void *fpst)
179
- RESULT(sum, n, 16); \
428
-{
180
- if (sum >= 0) \
429
- if (unlikely(float16_is_any_nan(x))) {
181
- ge |= 3 << (n * 2); \
430
- float_raise(float_flag_invalid, fpst);
182
- } while (0)
431
- return 0;
183
-
432
- }
184
-#define SARITH8(a, b, n, op) do { \
433
- return float16_to_uint32_scalbn(x, get_float_rounding_mode(fpst),
185
- int32_t sum; \
434
- shift, fpst);
186
- sum = (int32_t)(int8_t)(a) op (int32_t)(int8_t)(b); \
435
-}
187
- RESULT(sum, n, 8); \
436
-
188
- if (sum >= 0) \
437
-uint64_t HELPER(vfp_tosqh)(uint32_t x, uint32_t shift, void *fpst)
189
- ge |= 1 << n; \
438
-{
190
- } while (0)
439
- if (unlikely(float16_is_any_nan(x))) {
191
-
440
- float_raise(float_flag_invalid, fpst);
192
-
441
- return 0;
193
-#define ADD16(a, b, n) SARITH16(a, b, n, +)
442
- }
194
-#define SUB16(a, b, n) SARITH16(a, b, n, -)
443
- return float16_to_int64_scalbn(x, get_float_rounding_mode(fpst),
195
-#define ADD8(a, b, n) SARITH8(a, b, n, +)
444
- shift, fpst);
196
-#define SUB8(a, b, n) SARITH8(a, b, n, -)
445
-}
197
-#define PFX s
446
-
198
-#define ARITH_GE
447
-uint64_t HELPER(vfp_touqh)(uint32_t x, uint32_t shift, void *fpst)
199
-
448
-{
200
-#include "op_addsub.h"
449
- if (unlikely(float16_is_any_nan(x))) {
201
-
450
- float_raise(float_flag_invalid, fpst);
202
-/* Unsigned modulo arithmetic. */
451
- return 0;
203
-#define ADD16(a, b, n) do { \
452
- }
204
- uint32_t sum; \
453
- return float16_to_uint64_scalbn(x, get_float_rounding_mode(fpst),
205
- sum = (uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b); \
454
- shift, fpst);
206
- RESULT(sum, n, 16); \
455
-}
207
- if ((sum >> 16) == 1) \
456
-
208
- ge |= 3 << (n * 2); \
457
-/* Set the current fp rounding mode and return the old one.
209
- } while (0)
458
- * The argument is a softfloat float_round_ value.
210
-
211
-#define ADD8(a, b, n) do { \
212
- uint32_t sum; \
213
- sum = (uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b); \
214
- RESULT(sum, n, 8); \
215
- if ((sum >> 8) == 1) \
216
- ge |= 1 << n; \
217
- } while (0)
218
-
219
-#define SUB16(a, b, n) do { \
220
- uint32_t sum; \
221
- sum = (uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b); \
222
- RESULT(sum, n, 16); \
223
- if ((sum >> 16) == 0) \
224
- ge |= 3 << (n * 2); \
225
- } while (0)
226
-
227
-#define SUB8(a, b, n) do { \
228
- uint32_t sum; \
229
- sum = (uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b); \
230
- RESULT(sum, n, 8); \
231
- if ((sum >> 8) == 0) \
232
- ge |= 1 << n; \
233
- } while (0)
234
-
235
-#define PFX u
236
-#define ARITH_GE
237
-
238
-#include "op_addsub.h"
239
-
240
-/* Halved signed arithmetic. */
241
-#define ADD16(a, b, n) \
242
- RESULT(((int32_t)(int16_t)(a) + (int32_t)(int16_t)(b)) >> 1, n, 16)
243
-#define SUB16(a, b, n) \
244
- RESULT(((int32_t)(int16_t)(a) - (int32_t)(int16_t)(b)) >> 1, n, 16)
245
-#define ADD8(a, b, n) \
246
- RESULT(((int32_t)(int8_t)(a) + (int32_t)(int8_t)(b)) >> 1, n, 8)
247
-#define SUB8(a, b, n) \
248
- RESULT(((int32_t)(int8_t)(a) - (int32_t)(int8_t)(b)) >> 1, n, 8)
249
-#define PFX sh
250
-
251
-#include "op_addsub.h"
252
-
253
-/* Halved unsigned arithmetic. */
254
-#define ADD16(a, b, n) \
255
- RESULT(((uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b)) >> 1, n, 16)
256
-#define SUB16(a, b, n) \
257
- RESULT(((uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b)) >> 1, n, 16)
258
-#define ADD8(a, b, n) \
259
- RESULT(((uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b)) >> 1, n, 8)
260
-#define SUB8(a, b, n) \
261
- RESULT(((uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b)) >> 1, n, 8)
262
-#define PFX uh
263
-
264
-#include "op_addsub.h"
265
-
266
-static inline uint8_t do_usad(uint8_t a, uint8_t b)
267
-{
268
- if (a > b) {
269
- return a - b;
270
- } else {
271
- return b - a;
272
- }
273
-}
274
-
275
-/* Unsigned sum of absolute byte differences. */
276
-uint32_t HELPER(usad8)(uint32_t a, uint32_t b)
277
-{
278
- uint32_t sum;
279
- sum = do_usad(a, b);
280
- sum += do_usad(a >> 8, b >> 8);
281
- sum += do_usad(a >> 16, b >> 16);
282
- sum += do_usad(a >> 24, b >> 24);
283
- return sum;
284
-}
285
-
286
-/* For ARMv6 SEL instruction. */
287
-uint32_t HELPER(sel_flags)(uint32_t flags, uint32_t a, uint32_t b)
288
-{
289
- uint32_t mask;
290
-
291
- mask = 0;
292
- if (flags & 1) {
293
- mask |= 0xff;
294
- }
295
- if (flags & 2) {
296
- mask |= 0xff00;
297
- }
298
- if (flags & 4) {
299
- mask |= 0xff0000;
300
- }
301
- if (flags & 8) {
302
- mask |= 0xff000000;
303
- }
304
- return (a & mask) | (b & ~mask);
305
-}
306
-
307
-/*
308
- * CRC helpers.
309
- * The upper bytes of val (above the number specified by 'bytes') must have
310
- * been zeroed out by the caller.
459
- */
311
- */
460
-uint32_t HELPER(set_rmode)(uint32_t rmode, void *fpstp)
312
-uint32_t HELPER(crc32)(uint32_t acc, uint32_t val, uint32_t bytes)
461
-{
313
-{
462
- float_status *fp_status = fpstp;
314
- uint8_t buf[4];
463
-
315
-
464
- uint32_t prev_rmode = get_float_rounding_mode(fp_status);
316
- stl_le_p(buf, val);
465
- set_float_rounding_mode(rmode, fp_status);
317
-
466
-
318
- /* zlib crc32 converts the accumulator and output to one's complement. */
467
- return prev_rmode;
319
- return crc32(acc ^ 0xffffffff, buf, bytes) ^ 0xffffffff;
468
-}
320
-}
469
-
321
-
470
-/* Set the current fp rounding mode in the standard fp status and return
322
-uint32_t HELPER(crc32c)(uint32_t acc, uint32_t val, uint32_t bytes)
471
- * the old one. This is for NEON instructions that need to change the
323
-{
472
- * rounding mode but wish to use the standard FPSCR values for everything
324
- uint8_t buf[4];
473
- * else. Always set the rounding mode back to the correct value after
325
-
474
- * modifying it.
326
- stl_le_p(buf, val);
475
- * The argument is a softfloat float_round_ value.
327
-
476
- */
328
- /* Linux crc32c converts the output to one's complement. */
477
-uint32_t HELPER(set_neon_rmode)(uint32_t rmode, CPUARMState *env)
329
- return crc32c(acc, buf, bytes) ^ 0xffffffff;
478
-{
330
-}
479
- float_status *fp_status = &env->vfp.standard_fp_status;
331
480
-
332
/*
481
- uint32_t prev_rmode = get_float_rounding_mode(fp_status);
333
* Return the exception level to which FP-disabled exceptions should
482
- set_float_rounding_mode(rmode, fp_status);
334
diff --git a/target/arm/tcg/arith_helper.c b/target/arm/tcg/arith_helper.c
483
-
484
- return prev_rmode;
485
-}
486
-
487
-/* Half precision conversions. */
488
-float32 HELPER(vfp_fcvt_f16_to_f32)(uint32_t a, void *fpstp, uint32_t ahp_mode)
489
-{
490
- /* Squash FZ16 to 0 for the duration of conversion. In this case,
491
- * it would affect flushing input denormals.
492
- */
493
- float_status *fpst = fpstp;
494
- flag save = get_flush_inputs_to_zero(fpst);
495
- set_flush_inputs_to_zero(false, fpst);
496
- float32 r = float16_to_float32(a, !ahp_mode, fpst);
497
- set_flush_inputs_to_zero(save, fpst);
498
- return r;
499
-}
500
-
501
-uint32_t HELPER(vfp_fcvt_f32_to_f16)(float32 a, void *fpstp, uint32_t ahp_mode)
502
-{
503
- /* Squash FZ16 to 0 for the duration of conversion. In this case,
504
- * it would affect flushing output denormals.
505
- */
506
- float_status *fpst = fpstp;
507
- flag save = get_flush_to_zero(fpst);
508
- set_flush_to_zero(false, fpst);
509
- float16 r = float32_to_float16(a, !ahp_mode, fpst);
510
- set_flush_to_zero(save, fpst);
511
- return r;
512
-}
513
-
514
-float64 HELPER(vfp_fcvt_f16_to_f64)(uint32_t a, void *fpstp, uint32_t ahp_mode)
515
-{
516
- /* Squash FZ16 to 0 for the duration of conversion. In this case,
517
- * it would affect flushing input denormals.
518
- */
519
- float_status *fpst = fpstp;
520
- flag save = get_flush_inputs_to_zero(fpst);
521
- set_flush_inputs_to_zero(false, fpst);
522
- float64 r = float16_to_float64(a, !ahp_mode, fpst);
523
- set_flush_inputs_to_zero(save, fpst);
524
- return r;
525
-}
526
-
527
-uint32_t HELPER(vfp_fcvt_f64_to_f16)(float64 a, void *fpstp, uint32_t ahp_mode)
528
-{
529
- /* Squash FZ16 to 0 for the duration of conversion. In this case,
530
- * it would affect flushing output denormals.
531
- */
532
- float_status *fpst = fpstp;
533
- flag save = get_flush_to_zero(fpst);
534
- set_flush_to_zero(false, fpst);
535
- float16 r = float64_to_float16(a, !ahp_mode, fpst);
536
- set_flush_to_zero(save, fpst);
537
- return r;
538
-}
539
-
540
-#define float32_two make_float32(0x40000000)
541
-#define float32_three make_float32(0x40400000)
542
-#define float32_one_point_five make_float32(0x3fc00000)
543
-
544
-float32 HELPER(recps_f32)(float32 a, float32 b, CPUARMState *env)
545
-{
546
- float_status *s = &env->vfp.standard_fp_status;
547
- if ((float32_is_infinity(a) && float32_is_zero_or_denormal(b)) ||
548
- (float32_is_infinity(b) && float32_is_zero_or_denormal(a))) {
549
- if (!(float32_is_zero(a) || float32_is_zero(b))) {
550
- float_raise(float_flag_input_denormal, s);
551
- }
552
- return float32_two;
553
- }
554
- return float32_sub(float32_two, float32_mul(a, b, s), s);
555
-}
556
-
557
-float32 HELPER(rsqrts_f32)(float32 a, float32 b, CPUARMState *env)
558
-{
559
- float_status *s = &env->vfp.standard_fp_status;
560
- float32 product;
561
- if ((float32_is_infinity(a) && float32_is_zero_or_denormal(b)) ||
562
- (float32_is_infinity(b) && float32_is_zero_or_denormal(a))) {
563
- if (!(float32_is_zero(a) || float32_is_zero(b))) {
564
- float_raise(float_flag_input_denormal, s);
565
- }
566
- return float32_one_point_five;
567
- }
568
- product = float32_mul(a, b, s);
569
- return float32_div(float32_sub(float32_three, product, s), float32_two, s);
570
-}
571
-
572
-/* NEON helpers. */
573
-
574
-/* Constants 256 and 512 are used in some helpers; we avoid relying on
575
- * int->float conversions at run-time. */
576
-#define float64_256 make_float64(0x4070000000000000LL)
577
-#define float64_512 make_float64(0x4080000000000000LL)
578
-#define float16_maxnorm make_float16(0x7bff)
579
-#define float32_maxnorm make_float32(0x7f7fffff)
580
-#define float64_maxnorm make_float64(0x7fefffffffffffffLL)
581
-
582
-/* Reciprocal functions
583
- *
584
- * The algorithm that must be used to calculate the estimate
585
- * is specified by the ARM ARM, see FPRecipEstimate()/RecipEstimate
586
- */
587
-
588
-/* See RecipEstimate()
589
- *
590
- * input is a 9 bit fixed point number
591
- * input range 256 .. 511 for a number from 0.5 <= x < 1.0.
592
- * result range 256 .. 511 for a number from 1.0 to 511/256.
593
- */
594
-
595
-static int recip_estimate(int input)
596
-{
597
- int a, b, r;
598
- assert(256 <= input && input < 512);
599
- a = (input * 2) + 1;
600
- b = (1 << 19) / a;
601
- r = (b + 1) >> 1;
602
- assert(256 <= r && r < 512);
603
- return r;
604
-}
605
-
606
-/*
607
- * Common wrapper to call recip_estimate
608
- *
609
- * The parameters are exponent and 64 bit fraction (without implicit
610
- * bit) where the binary point is nominally at bit 52. Returns a
611
- * float64 which can then be rounded to the appropriate size by the
612
- * callee.
613
- */
614
-
615
-static uint64_t call_recip_estimate(int *exp, int exp_off, uint64_t frac)
616
-{
617
- uint32_t scaled, estimate;
618
- uint64_t result_frac;
619
- int result_exp;
620
-
621
- /* Handle sub-normals */
622
- if (*exp == 0) {
623
- if (extract64(frac, 51, 1) == 0) {
624
- *exp = -1;
625
- frac <<= 2;
626
- } else {
627
- frac <<= 1;
628
- }
629
- }
630
-
631
- /* scaled = UInt('1':fraction<51:44>) */
632
- scaled = deposit32(1 << 8, 0, 8, extract64(frac, 44, 8));
633
- estimate = recip_estimate(scaled);
634
-
635
- result_exp = exp_off - *exp;
636
- result_frac = deposit64(0, 44, 8, estimate);
637
- if (result_exp == 0) {
638
- result_frac = deposit64(result_frac >> 1, 51, 1, 1);
639
- } else if (result_exp == -1) {
640
- result_frac = deposit64(result_frac >> 2, 50, 2, 1);
641
- result_exp = 0;
642
- }
643
-
644
- *exp = result_exp;
645
-
646
- return result_frac;
647
-}
648
-
649
-static bool round_to_inf(float_status *fpst, bool sign_bit)
650
-{
651
- switch (fpst->float_rounding_mode) {
652
- case float_round_nearest_even: /* Round to Nearest */
653
- return true;
654
- case float_round_up: /* Round to +Inf */
655
- return !sign_bit;
656
- case float_round_down: /* Round to -Inf */
657
- return sign_bit;
658
- case float_round_to_zero: /* Round to Zero */
659
- return false;
660
- }
661
-
662
- g_assert_not_reached();
663
-}
664
-
665
-uint32_t HELPER(recpe_f16)(uint32_t input, void *fpstp)
666
-{
667
- float_status *fpst = fpstp;
668
- float16 f16 = float16_squash_input_denormal(input, fpst);
669
- uint32_t f16_val = float16_val(f16);
670
- uint32_t f16_sign = float16_is_neg(f16);
671
- int f16_exp = extract32(f16_val, 10, 5);
672
- uint32_t f16_frac = extract32(f16_val, 0, 10);
673
- uint64_t f64_frac;
674
-
675
- if (float16_is_any_nan(f16)) {
676
- float16 nan = f16;
677
- if (float16_is_signaling_nan(f16, fpst)) {
678
- float_raise(float_flag_invalid, fpst);
679
- nan = float16_silence_nan(f16, fpst);
680
- }
681
- if (fpst->default_nan_mode) {
682
- nan = float16_default_nan(fpst);
683
- }
684
- return nan;
685
- } else if (float16_is_infinity(f16)) {
686
- return float16_set_sign(float16_zero, float16_is_neg(f16));
687
- } else if (float16_is_zero(f16)) {
688
- float_raise(float_flag_divbyzero, fpst);
689
- return float16_set_sign(float16_infinity, float16_is_neg(f16));
690
- } else if (float16_abs(f16) < (1 << 8)) {
691
- /* Abs(value) < 2.0^-16 */
692
- float_raise(float_flag_overflow | float_flag_inexact, fpst);
693
- if (round_to_inf(fpst, f16_sign)) {
694
- return float16_set_sign(float16_infinity, f16_sign);
695
- } else {
696
- return float16_set_sign(float16_maxnorm, f16_sign);
697
- }
698
- } else if (f16_exp >= 29 && fpst->flush_to_zero) {
699
- float_raise(float_flag_underflow, fpst);
700
- return float16_set_sign(float16_zero, float16_is_neg(f16));
701
- }
702
-
703
- f64_frac = call_recip_estimate(&f16_exp, 29,
704
- ((uint64_t) f16_frac) << (52 - 10));
705
-
706
- /* result = sign : result_exp<4:0> : fraction<51:42> */
707
- f16_val = deposit32(0, 15, 1, f16_sign);
708
- f16_val = deposit32(f16_val, 10, 5, f16_exp);
709
- f16_val = deposit32(f16_val, 0, 10, extract64(f64_frac, 52 - 10, 10));
710
- return make_float16(f16_val);
711
-}
712
-
713
-float32 HELPER(recpe_f32)(float32 input, void *fpstp)
714
-{
715
- float_status *fpst = fpstp;
716
- float32 f32 = float32_squash_input_denormal(input, fpst);
717
- uint32_t f32_val = float32_val(f32);
718
- bool f32_sign = float32_is_neg(f32);
719
- int f32_exp = extract32(f32_val, 23, 8);
720
- uint32_t f32_frac = extract32(f32_val, 0, 23);
721
- uint64_t f64_frac;
722
-
723
- if (float32_is_any_nan(f32)) {
724
- float32 nan = f32;
725
- if (float32_is_signaling_nan(f32, fpst)) {
726
- float_raise(float_flag_invalid, fpst);
727
- nan = float32_silence_nan(f32, fpst);
728
- }
729
- if (fpst->default_nan_mode) {
730
- nan = float32_default_nan(fpst);
731
- }
732
- return nan;
733
- } else if (float32_is_infinity(f32)) {
734
- return float32_set_sign(float32_zero, float32_is_neg(f32));
735
- } else if (float32_is_zero(f32)) {
736
- float_raise(float_flag_divbyzero, fpst);
737
- return float32_set_sign(float32_infinity, float32_is_neg(f32));
738
- } else if (float32_abs(f32) < (1ULL << 21)) {
739
- /* Abs(value) < 2.0^-128 */
740
- float_raise(float_flag_overflow | float_flag_inexact, fpst);
741
- if (round_to_inf(fpst, f32_sign)) {
742
- return float32_set_sign(float32_infinity, f32_sign);
743
- } else {
744
- return float32_set_sign(float32_maxnorm, f32_sign);
745
- }
746
- } else if (f32_exp >= 253 && fpst->flush_to_zero) {
747
- float_raise(float_flag_underflow, fpst);
748
- return float32_set_sign(float32_zero, float32_is_neg(f32));
749
- }
750
-
751
- f64_frac = call_recip_estimate(&f32_exp, 253,
752
- ((uint64_t) f32_frac) << (52 - 23));
753
-
754
- /* result = sign : result_exp<7:0> : fraction<51:29> */
755
- f32_val = deposit32(0, 31, 1, f32_sign);
756
- f32_val = deposit32(f32_val, 23, 8, f32_exp);
757
- f32_val = deposit32(f32_val, 0, 23, extract64(f64_frac, 52 - 23, 23));
758
- return make_float32(f32_val);
759
-}
760
-
761
-float64 HELPER(recpe_f64)(float64 input, void *fpstp)
762
-{
763
- float_status *fpst = fpstp;
764
- float64 f64 = float64_squash_input_denormal(input, fpst);
765
- uint64_t f64_val = float64_val(f64);
766
- bool f64_sign = float64_is_neg(f64);
767
- int f64_exp = extract64(f64_val, 52, 11);
768
- uint64_t f64_frac = extract64(f64_val, 0, 52);
769
-
770
- /* Deal with any special cases */
771
- if (float64_is_any_nan(f64)) {
772
- float64 nan = f64;
773
- if (float64_is_signaling_nan(f64, fpst)) {
774
- float_raise(float_flag_invalid, fpst);
775
- nan = float64_silence_nan(f64, fpst);
776
- }
777
- if (fpst->default_nan_mode) {
778
- nan = float64_default_nan(fpst);
779
- }
780
- return nan;
781
- } else if (float64_is_infinity(f64)) {
782
- return float64_set_sign(float64_zero, float64_is_neg(f64));
783
- } else if (float64_is_zero(f64)) {
784
- float_raise(float_flag_divbyzero, fpst);
785
- return float64_set_sign(float64_infinity, float64_is_neg(f64));
786
- } else if ((f64_val & ~(1ULL << 63)) < (1ULL << 50)) {
787
- /* Abs(value) < 2.0^-1024 */
788
- float_raise(float_flag_overflow | float_flag_inexact, fpst);
789
- if (round_to_inf(fpst, f64_sign)) {
790
- return float64_set_sign(float64_infinity, f64_sign);
791
- } else {
792
- return float64_set_sign(float64_maxnorm, f64_sign);
793
- }
794
- } else if (f64_exp >= 2045 && fpst->flush_to_zero) {
795
- float_raise(float_flag_underflow, fpst);
796
- return float64_set_sign(float64_zero, float64_is_neg(f64));
797
- }
798
-
799
- f64_frac = call_recip_estimate(&f64_exp, 2045, f64_frac);
800
-
801
- /* result = sign : result_exp<10:0> : fraction<51:0>; */
802
- f64_val = deposit64(0, 63, 1, f64_sign);
803
- f64_val = deposit64(f64_val, 52, 11, f64_exp);
804
- f64_val = deposit64(f64_val, 0, 52, f64_frac);
805
- return make_float64(f64_val);
806
-}
807
-
808
-/* The algorithm that must be used to calculate the estimate
809
- * is specified by the ARM ARM.
810
- */
811
-
812
-static int do_recip_sqrt_estimate(int a)
813
-{
814
- int b, estimate;
815
-
816
- assert(128 <= a && a < 512);
817
- if (a < 256) {
818
- a = a * 2 + 1;
819
- } else {
820
- a = (a >> 1) << 1;
821
- a = (a + 1) * 2;
822
- }
823
- b = 512;
824
- while (a * (b + 1) * (b + 1) < (1 << 28)) {
825
- b += 1;
826
- }
827
- estimate = (b + 1) / 2;
828
- assert(256 <= estimate && estimate < 512);
829
-
830
- return estimate;
831
-}
832
-
833
-
834
-static uint64_t recip_sqrt_estimate(int *exp , int exp_off, uint64_t frac)
835
-{
836
- int estimate;
837
- uint32_t scaled;
838
-
839
- if (*exp == 0) {
840
- while (extract64(frac, 51, 1) == 0) {
841
- frac = frac << 1;
842
- *exp -= 1;
843
- }
844
- frac = extract64(frac, 0, 51) << 1;
845
- }
846
-
847
- if (*exp & 1) {
848
- /* scaled = UInt('01':fraction<51:45>) */
849
- scaled = deposit32(1 << 7, 0, 7, extract64(frac, 45, 7));
850
- } else {
851
- /* scaled = UInt('1':fraction<51:44>) */
852
- scaled = deposit32(1 << 8, 0, 8, extract64(frac, 44, 8));
853
- }
854
- estimate = do_recip_sqrt_estimate(scaled);
855
-
856
- *exp = (exp_off - *exp) / 2;
857
- return extract64(estimate, 0, 8) << 44;
858
-}
859
-
860
-uint32_t HELPER(rsqrte_f16)(uint32_t input, void *fpstp)
861
-{
862
- float_status *s = fpstp;
863
- float16 f16 = float16_squash_input_denormal(input, s);
864
- uint16_t val = float16_val(f16);
865
- bool f16_sign = float16_is_neg(f16);
866
- int f16_exp = extract32(val, 10, 5);
867
- uint16_t f16_frac = extract32(val, 0, 10);
868
- uint64_t f64_frac;
869
-
870
- if (float16_is_any_nan(f16)) {
871
- float16 nan = f16;
872
- if (float16_is_signaling_nan(f16, s)) {
873
- float_raise(float_flag_invalid, s);
874
- nan = float16_silence_nan(f16, s);
875
- }
876
- if (s->default_nan_mode) {
877
- nan = float16_default_nan(s);
878
- }
879
- return nan;
880
- } else if (float16_is_zero(f16)) {
881
- float_raise(float_flag_divbyzero, s);
882
- return float16_set_sign(float16_infinity, f16_sign);
883
- } else if (f16_sign) {
884
- float_raise(float_flag_invalid, s);
885
- return float16_default_nan(s);
886
- } else if (float16_is_infinity(f16)) {
887
- return float16_zero;
888
- }
889
-
890
- /* Scale and normalize to a double-precision value between 0.25 and 1.0,
891
- * preserving the parity of the exponent. */
892
-
893
- f64_frac = ((uint64_t) f16_frac) << (52 - 10);
894
-
895
- f64_frac = recip_sqrt_estimate(&f16_exp, 44, f64_frac);
896
-
897
- /* result = sign : result_exp<4:0> : estimate<7:0> : Zeros(2) */
898
- val = deposit32(0, 15, 1, f16_sign);
899
- val = deposit32(val, 10, 5, f16_exp);
900
- val = deposit32(val, 2, 8, extract64(f64_frac, 52 - 8, 8));
901
- return make_float16(val);
902
-}
903
-
904
-float32 HELPER(rsqrte_f32)(float32 input, void *fpstp)
905
-{
906
- float_status *s = fpstp;
907
- float32 f32 = float32_squash_input_denormal(input, s);
908
- uint32_t val = float32_val(f32);
909
- uint32_t f32_sign = float32_is_neg(f32);
910
- int f32_exp = extract32(val, 23, 8);
911
- uint32_t f32_frac = extract32(val, 0, 23);
912
- uint64_t f64_frac;
913
-
914
- if (float32_is_any_nan(f32)) {
915
- float32 nan = f32;
916
- if (float32_is_signaling_nan(f32, s)) {
917
- float_raise(float_flag_invalid, s);
918
- nan = float32_silence_nan(f32, s);
919
- }
920
- if (s->default_nan_mode) {
921
- nan = float32_default_nan(s);
922
- }
923
- return nan;
924
- } else if (float32_is_zero(f32)) {
925
- float_raise(float_flag_divbyzero, s);
926
- return float32_set_sign(float32_infinity, float32_is_neg(f32));
927
- } else if (float32_is_neg(f32)) {
928
- float_raise(float_flag_invalid, s);
929
- return float32_default_nan(s);
930
- } else if (float32_is_infinity(f32)) {
931
- return float32_zero;
932
- }
933
-
934
- /* Scale and normalize to a double-precision value between 0.25 and 1.0,
935
- * preserving the parity of the exponent. */
936
-
937
- f64_frac = ((uint64_t) f32_frac) << 29;
938
-
939
- f64_frac = recip_sqrt_estimate(&f32_exp, 380, f64_frac);
940
-
941
- /* result = sign : result_exp<4:0> : estimate<7:0> : Zeros(15) */
942
- val = deposit32(0, 31, 1, f32_sign);
943
- val = deposit32(val, 23, 8, f32_exp);
944
- val = deposit32(val, 15, 8, extract64(f64_frac, 52 - 8, 8));
945
- return make_float32(val);
946
-}
947
-
948
-float64 HELPER(rsqrte_f64)(float64 input, void *fpstp)
949
-{
950
- float_status *s = fpstp;
951
- float64 f64 = float64_squash_input_denormal(input, s);
952
- uint64_t val = float64_val(f64);
953
- bool f64_sign = float64_is_neg(f64);
954
- int f64_exp = extract64(val, 52, 11);
955
- uint64_t f64_frac = extract64(val, 0, 52);
956
-
957
- if (float64_is_any_nan(f64)) {
958
- float64 nan = f64;
959
- if (float64_is_signaling_nan(f64, s)) {
960
- float_raise(float_flag_invalid, s);
961
- nan = float64_silence_nan(f64, s);
962
- }
963
- if (s->default_nan_mode) {
964
- nan = float64_default_nan(s);
965
- }
966
- return nan;
967
- } else if (float64_is_zero(f64)) {
968
- float_raise(float_flag_divbyzero, s);
969
- return float64_set_sign(float64_infinity, float64_is_neg(f64));
970
- } else if (float64_is_neg(f64)) {
971
- float_raise(float_flag_invalid, s);
972
- return float64_default_nan(s);
973
- } else if (float64_is_infinity(f64)) {
974
- return float64_zero;
975
- }
976
-
977
- f64_frac = recip_sqrt_estimate(&f64_exp, 3068, f64_frac);
978
-
979
- /* result = sign : result_exp<4:0> : estimate<7:0> : Zeros(44) */
980
- val = deposit64(0, 61, 1, f64_sign);
981
- val = deposit64(val, 52, 11, f64_exp);
982
- val = deposit64(val, 44, 8, extract64(f64_frac, 52 - 8, 8));
983
- return make_float64(val);
984
-}
985
-
986
-uint32_t HELPER(recpe_u32)(uint32_t a, void *fpstp)
987
-{
988
- /* float_status *s = fpstp; */
989
- int input, estimate;
990
-
991
- if ((a & 0x80000000) == 0) {
992
- return 0xffffffff;
993
- }
994
-
995
- input = extract32(a, 23, 9);
996
- estimate = recip_estimate(input);
997
-
998
- return deposit32(0, (32 - 9), 9, estimate);
999
-}
1000
-
1001
-uint32_t HELPER(rsqrte_u32)(uint32_t a, void *fpstp)
1002
-{
1003
- int estimate;
1004
-
1005
- if ((a & 0xc0000000) == 0) {
1006
- return 0xffffffff;
1007
- }
1008
-
1009
- estimate = do_recip_sqrt_estimate(extract32(a, 23, 9));
1010
-
1011
- return deposit32(0, 23, 9, estimate);
1012
-}
1013
-
1014
-/* VFPv4 fused multiply-accumulate */
1015
-float32 VFP_HELPER(muladd, s)(float32 a, float32 b, float32 c, void *fpstp)
1016
-{
1017
- float_status *fpst = fpstp;
1018
- return float32_muladd(a, b, c, 0, fpst);
1019
-}
1020
-
1021
-float64 VFP_HELPER(muladd, d)(float64 a, float64 b, float64 c, void *fpstp)
1022
-{
1023
- float_status *fpst = fpstp;
1024
- return float64_muladd(a, b, c, 0, fpst);
1025
-}
1026
-
1027
-/* ARMv8 round to integral */
1028
-float32 HELPER(rints_exact)(float32 x, void *fp_status)
1029
-{
1030
- return float32_round_to_int(x, fp_status);
1031
-}
1032
-
1033
-float64 HELPER(rintd_exact)(float64 x, void *fp_status)
1034
-{
1035
- return float64_round_to_int(x, fp_status);
1036
-}
1037
-
1038
-float32 HELPER(rints)(float32 x, void *fp_status)
1039
-{
1040
- int old_flags = get_float_exception_flags(fp_status), new_flags;
1041
- float32 ret;
1042
-
1043
- ret = float32_round_to_int(x, fp_status);
1044
-
1045
- /* Suppress any inexact exceptions the conversion produced */
1046
- if (!(old_flags & float_flag_inexact)) {
1047
- new_flags = get_float_exception_flags(fp_status);
1048
- set_float_exception_flags(new_flags & ~float_flag_inexact, fp_status);
1049
- }
1050
-
1051
- return ret;
1052
-}
1053
-
1054
-float64 HELPER(rintd)(float64 x, void *fp_status)
1055
-{
1056
- int old_flags = get_float_exception_flags(fp_status), new_flags;
1057
- float64 ret;
1058
-
1059
- ret = float64_round_to_int(x, fp_status);
1060
-
1061
- new_flags = get_float_exception_flags(fp_status);
1062
-
1063
- /* Suppress any inexact exceptions the conversion produced */
1064
- if (!(old_flags & float_flag_inexact)) {
1065
- new_flags = get_float_exception_flags(fp_status);
1066
- set_float_exception_flags(new_flags & ~float_flag_inexact, fp_status);
1067
- }
1068
-
1069
- return ret;
1070
-}
1071
-
1072
-/* Convert ARM rounding mode to softfloat */
1073
-int arm_rmode_to_sf(int rmode)
1074
-{
1075
- switch (rmode) {
1076
- case FPROUNDING_TIEAWAY:
1077
- rmode = float_round_ties_away;
1078
- break;
1079
- case FPROUNDING_ODD:
1080
- /* FIXME: add support for TIEAWAY and ODD */
1081
- qemu_log_mask(LOG_UNIMP, "arm: unimplemented rounding mode: %d\n",
1082
- rmode);
1083
- /* fall through for now */
1084
- case FPROUNDING_TIEEVEN:
1085
- default:
1086
- rmode = float_round_nearest_even;
1087
- break;
1088
- case FPROUNDING_POSINF:
1089
- rmode = float_round_up;
1090
- break;
1091
- case FPROUNDING_NEGINF:
1092
- rmode = float_round_down;
1093
- break;
1094
- case FPROUNDING_ZERO:
1095
- rmode = float_round_to_zero;
1096
- break;
1097
- }
1098
- return rmode;
1099
-}
1100
-
1101
/* CRC helpers.
1102
* The upper bytes of val (above the number specified by 'bytes') must have
1103
* been zeroed out by the caller.
1104
diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c
1105
new file mode 100644
335
new file mode 100644
1106
index XXXXXXX..XXXXXXX
336
index XXXXXXX..XXXXXXX
1107
--- /dev/null
337
--- /dev/null
1108
+++ b/target/arm/vfp_helper.c
338
+++ b/target/arm/tcg/arith_helper.c
1109
@@ -XXX,XX +XXX,XX @@
339
@@ -XXX,XX +XXX,XX @@
1110
+/*
340
+/*
1111
+ * ARM VFP floating-point operations
341
+ * ARM generic helpers for various arithmetical operations.
1112
+ *
342
+ *
1113
+ * Copyright (c) 2003 Fabrice Bellard
343
+ * This code is licensed under the GNU GPL v2 or later.
1114
+ *
344
+ *
1115
+ * This library is free software; you can redistribute it and/or
345
+ * SPDX-License-Identifier: GPL-2.0-or-later
1116
+ * modify it under the terms of the GNU Lesser General Public
1117
+ * License as published by the Free Software Foundation; either
1118
+ * version 2.1 of the License, or (at your option) any later version.
1119
+ *
1120
+ * This library is distributed in the hope that it will be useful,
1121
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1122
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1123
+ * Lesser General Public License for more details.
1124
+ *
1125
+ * You should have received a copy of the GNU Lesser General Public
1126
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1127
+ */
346
+ */
1128
+
1129
+#include "qemu/osdep.h"
347
+#include "qemu/osdep.h"
1130
+#include "qemu/log.h"
1131
+#include "cpu.h"
348
+#include "cpu.h"
1132
+#include "exec/helper-proto.h"
349
+#include "exec/helper-proto.h"
1133
+#include "fpu/softfloat.h"
350
+#include "qemu/crc32c.h"
1134
+#include "internals.h"
351
+#include <zlib.h> /* for crc32 */
1135
+
352
+
1136
+
353
+/*
1137
+/* VFP support. We follow the convention used for VFP instructions:
354
+ * Note that signed overflow is undefined in C. The following routines are
1138
+ Single precision routines have a "s" suffix, double precision a
355
+ * careful to use unsigned types where modulo arithmetic is required.
1139
+ "d" suffix. */
356
+ * Failure to do so _will_ break on newer gcc.
1140
+
357
+ */
1141
+/* Convert host exception flags to vfp form. */
358
+
1142
+static inline int vfp_exceptbits_from_host(int host_bits)
359
+/* Signed saturating arithmetic. */
1143
+{
360
+
1144
+ int target_bits = 0;
361
+/* Perform 16-bit signed saturating addition. */
1145
+
362
+static inline uint16_t add16_sat(uint16_t a, uint16_t b)
1146
+ if (host_bits & float_flag_invalid)
363
+{
1147
+ target_bits |= 1;
364
+ uint16_t res;
1148
+ if (host_bits & float_flag_divbyzero)
365
+
1149
+ target_bits |= 2;
366
+ res = a + b;
1150
+ if (host_bits & float_flag_overflow)
367
+ if (((res ^ a) & 0x8000) && !((a ^ b) & 0x8000)) {
1151
+ target_bits |= 4;
368
+ if (a & 0x8000) {
1152
+ if (host_bits & (float_flag_underflow | float_flag_output_denormal))
369
+ res = 0x8000;
1153
+ target_bits |= 8;
370
+ } else {
1154
+ if (host_bits & float_flag_inexact)
371
+ res = 0x7fff;
1155
+ target_bits |= 0x10;
1156
+ if (host_bits & float_flag_input_denormal)
1157
+ target_bits |= 0x80;
1158
+ return target_bits;
1159
+}
1160
+
1161
+uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env)
1162
+{
1163
+ uint32_t i, fpscr;
1164
+
1165
+ fpscr = env->vfp.xregs[ARM_VFP_FPSCR]
1166
+ | (env->vfp.vec_len << 16)
1167
+ | (env->vfp.vec_stride << 20);
1168
+
1169
+ i = get_float_exception_flags(&env->vfp.fp_status);
1170
+ i |= get_float_exception_flags(&env->vfp.standard_fp_status);
1171
+ /* FZ16 does not generate an input denormal exception. */
1172
+ i |= (get_float_exception_flags(&env->vfp.fp_status_f16)
1173
+ & ~float_flag_input_denormal);
1174
+ fpscr |= vfp_exceptbits_from_host(i);
1175
+
1176
+ i = env->vfp.qc[0] | env->vfp.qc[1] | env->vfp.qc[2] | env->vfp.qc[3];
1177
+ fpscr |= i ? FPCR_QC : 0;
1178
+
1179
+ return fpscr;
1180
+}
1181
+
1182
+uint32_t vfp_get_fpscr(CPUARMState *env)
1183
+{
1184
+ return HELPER(vfp_get_fpscr)(env);
1185
+}
1186
+
1187
+/* Convert vfp exception flags to target form. */
1188
+static inline int vfp_exceptbits_to_host(int target_bits)
1189
+{
1190
+ int host_bits = 0;
1191
+
1192
+ if (target_bits & 1)
1193
+ host_bits |= float_flag_invalid;
1194
+ if (target_bits & 2)
1195
+ host_bits |= float_flag_divbyzero;
1196
+ if (target_bits & 4)
1197
+ host_bits |= float_flag_overflow;
1198
+ if (target_bits & 8)
1199
+ host_bits |= float_flag_underflow;
1200
+ if (target_bits & 0x10)
1201
+ host_bits |= float_flag_inexact;
1202
+ if (target_bits & 0x80)
1203
+ host_bits |= float_flag_input_denormal;
1204
+ return host_bits;
1205
+}
1206
+
1207
+void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val)
1208
+{
1209
+ int i;
1210
+ uint32_t changed = env->vfp.xregs[ARM_VFP_FPSCR];
1211
+
1212
+ /* When ARMv8.2-FP16 is not supported, FZ16 is RES0. */
1213
+ if (!cpu_isar_feature(aa64_fp16, arm_env_get_cpu(env))) {
1214
+ val &= ~FPCR_FZ16;
1215
+ }
1216
+
1217
+ /*
1218
+ * We don't implement trapped exception handling, so the
1219
+ * trap enable bits, IDE|IXE|UFE|OFE|DZE|IOE are all RAZ/WI (not RES0!)
1220
+ *
1221
+ * If we exclude the exception flags, IOC|DZC|OFC|UFC|IXC|IDC
1222
+ * (which are stored in fp_status), and the other RES0 bits
1223
+ * in between, then we clear all of the low 16 bits.
1224
+ */
1225
+ env->vfp.xregs[ARM_VFP_FPSCR] = val & 0xf7c80000;
1226
+ env->vfp.vec_len = (val >> 16) & 7;
1227
+ env->vfp.vec_stride = (val >> 20) & 3;
1228
+
1229
+ /*
1230
+ * The bit we set within fpscr_q is arbitrary; the register as a
1231
+ * whole being zero/non-zero is what counts.
1232
+ */
1233
+ env->vfp.qc[0] = val & FPCR_QC;
1234
+ env->vfp.qc[1] = 0;
1235
+ env->vfp.qc[2] = 0;
1236
+ env->vfp.qc[3] = 0;
1237
+
1238
+ changed ^= val;
1239
+ if (changed & (3 << 22)) {
1240
+ i = (val >> 22) & 3;
1241
+ switch (i) {
1242
+ case FPROUNDING_TIEEVEN:
1243
+ i = float_round_nearest_even;
1244
+ break;
1245
+ case FPROUNDING_POSINF:
1246
+ i = float_round_up;
1247
+ break;
1248
+ case FPROUNDING_NEGINF:
1249
+ i = float_round_down;
1250
+ break;
1251
+ case FPROUNDING_ZERO:
1252
+ i = float_round_to_zero;
1253
+ break;
1254
+ }
372
+ }
1255
+ set_float_rounding_mode(i, &env->vfp.fp_status);
373
+ }
1256
+ set_float_rounding_mode(i, &env->vfp.fp_status_f16);
374
+ return res;
1257
+ }
375
+}
1258
+ if (changed & FPCR_FZ16) {
376
+
1259
+ bool ftz_enabled = val & FPCR_FZ16;
377
+/* Perform 8-bit signed saturating addition. */
1260
+ set_flush_to_zero(ftz_enabled, &env->vfp.fp_status_f16);
378
+static inline uint8_t add8_sat(uint8_t a, uint8_t b)
1261
+ set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status_f16);
379
+{
1262
+ }
380
+ uint8_t res;
1263
+ if (changed & FPCR_FZ) {
381
+
1264
+ bool ftz_enabled = val & FPCR_FZ;
382
+ res = a + b;
1265
+ set_flush_to_zero(ftz_enabled, &env->vfp.fp_status);
383
+ if (((res ^ a) & 0x80) && !((a ^ b) & 0x80)) {
1266
+ set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status);
384
+ if (a & 0x80) {
1267
+ }
385
+ res = 0x80;
1268
+ if (changed & FPCR_DN) {
386
+ } else {
1269
+ bool dnan_enabled = val & FPCR_DN;
387
+ res = 0x7f;
1270
+ set_default_nan_mode(dnan_enabled, &env->vfp.fp_status);
388
+ }
1271
+ set_default_nan_mode(dnan_enabled, &env->vfp.fp_status_f16);
389
+ }
1272
+ }
390
+ return res;
1273
+
391
+}
1274
+ /* The exception flags are ORed together when we read fpscr so we
392
+
1275
+ * only need to preserve the current state in one of our
393
+/* Perform 16-bit signed saturating subtraction. */
1276
+ * float_status values.
394
+static inline uint16_t sub16_sat(uint16_t a, uint16_t b)
1277
+ */
395
+{
1278
+ i = vfp_exceptbits_to_host(val);
396
+ uint16_t res;
1279
+ set_float_exception_flags(i, &env->vfp.fp_status);
397
+
1280
+ set_float_exception_flags(0, &env->vfp.fp_status_f16);
398
+ res = a - b;
1281
+ set_float_exception_flags(0, &env->vfp.standard_fp_status);
399
+ if (((res ^ a) & 0x8000) && ((a ^ b) & 0x8000)) {
1282
+}
400
+ if (a & 0x8000) {
1283
+
401
+ res = 0x8000;
1284
+void vfp_set_fpscr(CPUARMState *env, uint32_t val)
402
+ } else {
1285
+{
403
+ res = 0x7fff;
1286
+ HELPER(vfp_set_fpscr)(env, val);
404
+ }
1287
+}
405
+ }
1288
+
406
+ return res;
1289
+#define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p))
407
+}
1290
+
408
+
1291
+#define VFP_BINOP(name) \
409
+/* Perform 8-bit signed saturating subtraction. */
1292
+float32 VFP_HELPER(name, s)(float32 a, float32 b, void *fpstp) \
410
+static inline uint8_t sub8_sat(uint8_t a, uint8_t b)
1293
+{ \
411
+{
1294
+ float_status *fpst = fpstp; \
412
+ uint8_t res;
1295
+ return float32_ ## name(a, b, fpst); \
413
+
1296
+} \
414
+ res = a - b;
1297
+float64 VFP_HELPER(name, d)(float64 a, float64 b, void *fpstp) \
415
+ if (((res ^ a) & 0x80) && ((a ^ b) & 0x80)) {
1298
+{ \
416
+ if (a & 0x80) {
1299
+ float_status *fpst = fpstp; \
417
+ res = 0x80;
1300
+ return float64_ ## name(a, b, fpst); \
418
+ } else {
1301
+}
419
+ res = 0x7f;
1302
+VFP_BINOP(add)
420
+ }
1303
+VFP_BINOP(sub)
421
+ }
1304
+VFP_BINOP(mul)
422
+ return res;
1305
+VFP_BINOP(div)
423
+}
1306
+VFP_BINOP(min)
424
+
1307
+VFP_BINOP(max)
425
+#define ADD16(a, b, n) RESULT(add16_sat(a, b), n, 16);
1308
+VFP_BINOP(minnum)
426
+#define SUB16(a, b, n) RESULT(sub16_sat(a, b), n, 16);
1309
+VFP_BINOP(maxnum)
427
+#define ADD8(a, b, n) RESULT(add8_sat(a, b), n, 8);
1310
+#undef VFP_BINOP
428
+#define SUB8(a, b, n) RESULT(sub8_sat(a, b), n, 8);
1311
+
429
+#define PFX q
1312
+float32 VFP_HELPER(neg, s)(float32 a)
430
+
1313
+{
431
+#include "op_addsub.c.inc"
1314
+ return float32_chs(a);
432
+
1315
+}
433
+/* Unsigned saturating arithmetic. */
1316
+
434
+static inline uint16_t add16_usat(uint16_t a, uint16_t b)
1317
+float64 VFP_HELPER(neg, d)(float64 a)
435
+{
1318
+{
436
+ uint16_t res;
1319
+ return float64_chs(a);
437
+ res = a + b;
1320
+}
438
+ if (res < a) {
1321
+
439
+ res = 0xffff;
1322
+float32 VFP_HELPER(abs, s)(float32 a)
440
+ }
1323
+{
441
+ return res;
1324
+ return float32_abs(a);
442
+}
1325
+}
443
+
1326
+
444
+static inline uint16_t sub16_usat(uint16_t a, uint16_t b)
1327
+float64 VFP_HELPER(abs, d)(float64 a)
445
+{
1328
+{
446
+ if (a > b) {
1329
+ return float64_abs(a);
447
+ return a - b;
1330
+}
448
+ } else {
1331
+
1332
+float32 VFP_HELPER(sqrt, s)(float32 a, CPUARMState *env)
1333
+{
1334
+ return float32_sqrt(a, &env->vfp.fp_status);
1335
+}
1336
+
1337
+float64 VFP_HELPER(sqrt, d)(float64 a, CPUARMState *env)
1338
+{
1339
+ return float64_sqrt(a, &env->vfp.fp_status);
1340
+}
1341
+
1342
+static void softfloat_to_vfp_compare(CPUARMState *env, int cmp)
1343
+{
1344
+ uint32_t flags;
1345
+ switch (cmp) {
1346
+ case float_relation_equal:
1347
+ flags = 0x6;
1348
+ break;
1349
+ case float_relation_less:
1350
+ flags = 0x8;
1351
+ break;
1352
+ case float_relation_greater:
1353
+ flags = 0x2;
1354
+ break;
1355
+ case float_relation_unordered:
1356
+ flags = 0x3;
1357
+ break;
1358
+ default:
1359
+ g_assert_not_reached();
1360
+ }
1361
+ env->vfp.xregs[ARM_VFP_FPSCR] =
1362
+ deposit32(env->vfp.xregs[ARM_VFP_FPSCR], 28, 4, flags);
1363
+}
1364
+
1365
+/* XXX: check quiet/signaling case */
1366
+#define DO_VFP_cmp(p, type) \
1367
+void VFP_HELPER(cmp, p)(type a, type b, CPUARMState *env) \
1368
+{ \
1369
+ softfloat_to_vfp_compare(env, \
1370
+ type ## _compare_quiet(a, b, &env->vfp.fp_status)); \
1371
+} \
1372
+void VFP_HELPER(cmpe, p)(type a, type b, CPUARMState *env) \
1373
+{ \
1374
+ softfloat_to_vfp_compare(env, \
1375
+ type ## _compare(a, b, &env->vfp.fp_status)); \
1376
+}
1377
+DO_VFP_cmp(s, float32)
1378
+DO_VFP_cmp(d, float64)
1379
+#undef DO_VFP_cmp
1380
+
1381
+/* Integer to float and float to integer conversions */
1382
+
1383
+#define CONV_ITOF(name, ftype, fsz, sign) \
1384
+ftype HELPER(name)(uint32_t x, void *fpstp) \
1385
+{ \
1386
+ float_status *fpst = fpstp; \
1387
+ return sign##int32_to_##float##fsz((sign##int32_t)x, fpst); \
1388
+}
1389
+
1390
+#define CONV_FTOI(name, ftype, fsz, sign, round) \
1391
+sign##int32_t HELPER(name)(ftype x, void *fpstp) \
1392
+{ \
1393
+ float_status *fpst = fpstp; \
1394
+ if (float##fsz##_is_any_nan(x)) { \
1395
+ float_raise(float_flag_invalid, fpst); \
1396
+ return 0; \
1397
+ } \
1398
+ return float##fsz##_to_##sign##int32##round(x, fpst); \
1399
+}
1400
+
1401
+#define FLOAT_CONVS(name, p, ftype, fsz, sign) \
1402
+ CONV_ITOF(vfp_##name##to##p, ftype, fsz, sign) \
1403
+ CONV_FTOI(vfp_to##name##p, ftype, fsz, sign, ) \
1404
+ CONV_FTOI(vfp_to##name##z##p, ftype, fsz, sign, _round_to_zero)
1405
+
1406
+FLOAT_CONVS(si, h, uint32_t, 16, )
1407
+FLOAT_CONVS(si, s, float32, 32, )
1408
+FLOAT_CONVS(si, d, float64, 64, )
1409
+FLOAT_CONVS(ui, h, uint32_t, 16, u)
1410
+FLOAT_CONVS(ui, s, float32, 32, u)
1411
+FLOAT_CONVS(ui, d, float64, 64, u)
1412
+
1413
+#undef CONV_ITOF
1414
+#undef CONV_FTOI
1415
+#undef FLOAT_CONVS
1416
+
1417
+/* floating point conversion */
1418
+float64 VFP_HELPER(fcvtd, s)(float32 x, CPUARMState *env)
1419
+{
1420
+ return float32_to_float64(x, &env->vfp.fp_status);
1421
+}
1422
+
1423
+float32 VFP_HELPER(fcvts, d)(float64 x, CPUARMState *env)
1424
+{
1425
+ return float64_to_float32(x, &env->vfp.fp_status);
1426
+}
1427
+
1428
+/* VFP3 fixed point conversion. */
1429
+#define VFP_CONV_FIX_FLOAT(name, p, fsz, isz, itype) \
1430
+float##fsz HELPER(vfp_##name##to##p)(uint##isz##_t x, uint32_t shift, \
1431
+ void *fpstp) \
1432
+{ return itype##_to_##float##fsz##_scalbn(x, -shift, fpstp); }
1433
+
1434
+#define VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, ROUND, suff) \
1435
+uint##isz##_t HELPER(vfp_to##name##p##suff)(float##fsz x, uint32_t shift, \
1436
+ void *fpst) \
1437
+{ \
1438
+ if (unlikely(float##fsz##_is_any_nan(x))) { \
1439
+ float_raise(float_flag_invalid, fpst); \
1440
+ return 0; \
1441
+ } \
1442
+ return float##fsz##_to_##itype##_scalbn(x, ROUND, shift, fpst); \
1443
+}
1444
+
1445
+#define VFP_CONV_FIX(name, p, fsz, isz, itype) \
1446
+VFP_CONV_FIX_FLOAT(name, p, fsz, isz, itype) \
1447
+VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, \
1448
+ float_round_to_zero, _round_to_zero) \
1449
+VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, \
1450
+ get_float_rounding_mode(fpst), )
1451
+
1452
+#define VFP_CONV_FIX_A64(name, p, fsz, isz, itype) \
1453
+VFP_CONV_FIX_FLOAT(name, p, fsz, isz, itype) \
1454
+VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, \
1455
+ get_float_rounding_mode(fpst), )
1456
+
1457
+VFP_CONV_FIX(sh, d, 64, 64, int16)
1458
+VFP_CONV_FIX(sl, d, 64, 64, int32)
1459
+VFP_CONV_FIX_A64(sq, d, 64, 64, int64)
1460
+VFP_CONV_FIX(uh, d, 64, 64, uint16)
1461
+VFP_CONV_FIX(ul, d, 64, 64, uint32)
1462
+VFP_CONV_FIX_A64(uq, d, 64, 64, uint64)
1463
+VFP_CONV_FIX(sh, s, 32, 32, int16)
1464
+VFP_CONV_FIX(sl, s, 32, 32, int32)
1465
+VFP_CONV_FIX_A64(sq, s, 32, 64, int64)
1466
+VFP_CONV_FIX(uh, s, 32, 32, uint16)
1467
+VFP_CONV_FIX(ul, s, 32, 32, uint32)
1468
+VFP_CONV_FIX_A64(uq, s, 32, 64, uint64)
1469
+
1470
+#undef VFP_CONV_FIX
1471
+#undef VFP_CONV_FIX_FLOAT
1472
+#undef VFP_CONV_FLOAT_FIX_ROUND
1473
+#undef VFP_CONV_FIX_A64
1474
+
1475
+uint32_t HELPER(vfp_sltoh)(uint32_t x, uint32_t shift, void *fpst)
1476
+{
1477
+ return int32_to_float16_scalbn(x, -shift, fpst);
1478
+}
1479
+
1480
+uint32_t HELPER(vfp_ultoh)(uint32_t x, uint32_t shift, void *fpst)
1481
+{
1482
+ return uint32_to_float16_scalbn(x, -shift, fpst);
1483
+}
1484
+
1485
+uint32_t HELPER(vfp_sqtoh)(uint64_t x, uint32_t shift, void *fpst)
1486
+{
1487
+ return int64_to_float16_scalbn(x, -shift, fpst);
1488
+}
1489
+
1490
+uint32_t HELPER(vfp_uqtoh)(uint64_t x, uint32_t shift, void *fpst)
1491
+{
1492
+ return uint64_to_float16_scalbn(x, -shift, fpst);
1493
+}
1494
+
1495
+uint32_t HELPER(vfp_toshh)(uint32_t x, uint32_t shift, void *fpst)
1496
+{
1497
+ if (unlikely(float16_is_any_nan(x))) {
1498
+ float_raise(float_flag_invalid, fpst);
1499
+ return 0;
449
+ return 0;
1500
+ }
450
+ }
1501
+ return float16_to_int16_scalbn(x, get_float_rounding_mode(fpst),
451
+}
1502
+ shift, fpst);
452
+
1503
+}
453
+static inline uint8_t add8_usat(uint8_t a, uint8_t b)
1504
+
454
+{
1505
+uint32_t HELPER(vfp_touhh)(uint32_t x, uint32_t shift, void *fpst)
455
+ uint8_t res;
1506
+{
456
+ res = a + b;
1507
+ if (unlikely(float16_is_any_nan(x))) {
457
+ if (res < a) {
1508
+ float_raise(float_flag_invalid, fpst);
458
+ res = 0xff;
459
+ }
460
+ return res;
461
+}
462
+
463
+static inline uint8_t sub8_usat(uint8_t a, uint8_t b)
464
+{
465
+ if (a > b) {
466
+ return a - b;
467
+ } else {
1509
+ return 0;
468
+ return 0;
1510
+ }
469
+ }
1511
+ return float16_to_uint16_scalbn(x, get_float_rounding_mode(fpst),
470
+}
1512
+ shift, fpst);
471
+
1513
+}
472
+#define ADD16(a, b, n) RESULT(add16_usat(a, b), n, 16);
1514
+
473
+#define SUB16(a, b, n) RESULT(sub16_usat(a, b), n, 16);
1515
+uint32_t HELPER(vfp_toslh)(uint32_t x, uint32_t shift, void *fpst)
474
+#define ADD8(a, b, n) RESULT(add8_usat(a, b), n, 8);
1516
+{
475
+#define SUB8(a, b, n) RESULT(sub8_usat(a, b), n, 8);
1517
+ if (unlikely(float16_is_any_nan(x))) {
476
+#define PFX uq
1518
+ float_raise(float_flag_invalid, fpst);
477
+
1519
+ return 0;
478
+#include "op_addsub.c.inc"
1520
+ }
479
+
1521
+ return float16_to_int32_scalbn(x, get_float_rounding_mode(fpst),
480
+/* Signed modulo arithmetic. */
1522
+ shift, fpst);
481
+#define SARITH16(a, b, n, op) do { \
1523
+}
482
+ int32_t sum; \
1524
+
483
+ sum = (int32_t)(int16_t)(a) op (int32_t)(int16_t)(b); \
1525
+uint32_t HELPER(vfp_toulh)(uint32_t x, uint32_t shift, void *fpst)
484
+ RESULT(sum, n, 16); \
1526
+{
485
+ if (sum >= 0) \
1527
+ if (unlikely(float16_is_any_nan(x))) {
486
+ ge |= 3 << (n * 2); \
1528
+ float_raise(float_flag_invalid, fpst);
487
+ } while (0)
1529
+ return 0;
488
+
1530
+ }
489
+#define SARITH8(a, b, n, op) do { \
1531
+ return float16_to_uint32_scalbn(x, get_float_rounding_mode(fpst),
490
+ int32_t sum; \
1532
+ shift, fpst);
491
+ sum = (int32_t)(int8_t)(a) op (int32_t)(int8_t)(b); \
1533
+}
492
+ RESULT(sum, n, 8); \
1534
+
493
+ if (sum >= 0) \
1535
+uint64_t HELPER(vfp_tosqh)(uint32_t x, uint32_t shift, void *fpst)
494
+ ge |= 1 << n; \
1536
+{
495
+ } while (0)
1537
+ if (unlikely(float16_is_any_nan(x))) {
496
+
1538
+ float_raise(float_flag_invalid, fpst);
497
+
1539
+ return 0;
498
+#define ADD16(a, b, n) SARITH16(a, b, n, +)
1540
+ }
499
+#define SUB16(a, b, n) SARITH16(a, b, n, -)
1541
+ return float16_to_int64_scalbn(x, get_float_rounding_mode(fpst),
500
+#define ADD8(a, b, n) SARITH8(a, b, n, +)
1542
+ shift, fpst);
501
+#define SUB8(a, b, n) SARITH8(a, b, n, -)
1543
+}
502
+#define PFX s
1544
+
503
+#define ARITH_GE
1545
+uint64_t HELPER(vfp_touqh)(uint32_t x, uint32_t shift, void *fpst)
504
+
1546
+{
505
+#include "op_addsub.c.inc"
1547
+ if (unlikely(float16_is_any_nan(x))) {
506
+
1548
+ float_raise(float_flag_invalid, fpst);
507
+/* Unsigned modulo arithmetic. */
1549
+ return 0;
508
+#define ADD16(a, b, n) do { \
1550
+ }
509
+ uint32_t sum; \
1551
+ return float16_to_uint64_scalbn(x, get_float_rounding_mode(fpst),
510
+ sum = (uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b); \
1552
+ shift, fpst);
511
+ RESULT(sum, n, 16); \
1553
+}
512
+ if ((sum >> 16) == 1) \
1554
+
513
+ ge |= 3 << (n * 2); \
1555
+/* Set the current fp rounding mode and return the old one.
514
+ } while (0)
1556
+ * The argument is a softfloat float_round_ value.
515
+
516
+#define ADD8(a, b, n) do { \
517
+ uint32_t sum; \
518
+ sum = (uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b); \
519
+ RESULT(sum, n, 8); \
520
+ if ((sum >> 8) == 1) \
521
+ ge |= 1 << n; \
522
+ } while (0)
523
+
524
+#define SUB16(a, b, n) do { \
525
+ uint32_t sum; \
526
+ sum = (uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b); \
527
+ RESULT(sum, n, 16); \
528
+ if ((sum >> 16) == 0) \
529
+ ge |= 3 << (n * 2); \
530
+ } while (0)
531
+
532
+#define SUB8(a, b, n) do { \
533
+ uint32_t sum; \
534
+ sum = (uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b); \
535
+ RESULT(sum, n, 8); \
536
+ if ((sum >> 8) == 0) \
537
+ ge |= 1 << n; \
538
+ } while (0)
539
+
540
+#define PFX u
541
+#define ARITH_GE
542
+
543
+#include "op_addsub.c.inc"
544
+
545
+/* Halved signed arithmetic. */
546
+#define ADD16(a, b, n) \
547
+ RESULT(((int32_t)(int16_t)(a) + (int32_t)(int16_t)(b)) >> 1, n, 16)
548
+#define SUB16(a, b, n) \
549
+ RESULT(((int32_t)(int16_t)(a) - (int32_t)(int16_t)(b)) >> 1, n, 16)
550
+#define ADD8(a, b, n) \
551
+ RESULT(((int32_t)(int8_t)(a) + (int32_t)(int8_t)(b)) >> 1, n, 8)
552
+#define SUB8(a, b, n) \
553
+ RESULT(((int32_t)(int8_t)(a) - (int32_t)(int8_t)(b)) >> 1, n, 8)
554
+#define PFX sh
555
+
556
+#include "op_addsub.c.inc"
557
+
558
+/* Halved unsigned arithmetic. */
559
+#define ADD16(a, b, n) \
560
+ RESULT(((uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b)) >> 1, n, 16)
561
+#define SUB16(a, b, n) \
562
+ RESULT(((uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b)) >> 1, n, 16)
563
+#define ADD8(a, b, n) \
564
+ RESULT(((uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b)) >> 1, n, 8)
565
+#define SUB8(a, b, n) \
566
+ RESULT(((uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b)) >> 1, n, 8)
567
+#define PFX uh
568
+
569
+#include "op_addsub.c.inc"
570
+
571
+static inline uint8_t do_usad(uint8_t a, uint8_t b)
572
+{
573
+ if (a > b) {
574
+ return a - b;
575
+ } else {
576
+ return b - a;
577
+ }
578
+}
579
+
580
+/* Unsigned sum of absolute byte differences. */
581
+uint32_t HELPER(usad8)(uint32_t a, uint32_t b)
582
+{
583
+ uint32_t sum;
584
+ sum = do_usad(a, b);
585
+ sum += do_usad(a >> 8, b >> 8);
586
+ sum += do_usad(a >> 16, b >> 16);
587
+ sum += do_usad(a >> 24, b >> 24);
588
+ return sum;
589
+}
590
+
591
+/* For ARMv6 SEL instruction. */
592
+uint32_t HELPER(sel_flags)(uint32_t flags, uint32_t a, uint32_t b)
593
+{
594
+ uint32_t mask;
595
+
596
+ mask = 0;
597
+ if (flags & 1) {
598
+ mask |= 0xff;
599
+ }
600
+ if (flags & 2) {
601
+ mask |= 0xff00;
602
+ }
603
+ if (flags & 4) {
604
+ mask |= 0xff0000;
605
+ }
606
+ if (flags & 8) {
607
+ mask |= 0xff000000;
608
+ }
609
+ return (a & mask) | (b & ~mask);
610
+}
611
+
612
+/*
613
+ * CRC helpers.
614
+ * The upper bytes of val (above the number specified by 'bytes') must have
615
+ * been zeroed out by the caller.
1557
+ */
616
+ */
1558
+uint32_t HELPER(set_rmode)(uint32_t rmode, void *fpstp)
617
+uint32_t HELPER(crc32)(uint32_t acc, uint32_t val, uint32_t bytes)
1559
+{
618
+{
1560
+ float_status *fp_status = fpstp;
619
+ uint8_t buf[4];
1561
+
620
+
1562
+ uint32_t prev_rmode = get_float_rounding_mode(fp_status);
621
+ stl_le_p(buf, val);
1563
+ set_float_rounding_mode(rmode, fp_status);
622
+
1564
+
623
+ /* zlib crc32 converts the accumulator and output to one's complement. */
1565
+ return prev_rmode;
624
+ return crc32(acc ^ 0xffffffff, buf, bytes) ^ 0xffffffff;
1566
+}
625
+}
1567
+
626
+
1568
+/* Set the current fp rounding mode in the standard fp status and return
627
+uint32_t HELPER(crc32c)(uint32_t acc, uint32_t val, uint32_t bytes)
1569
+ * the old one. This is for NEON instructions that need to change the
628
+{
1570
+ * rounding mode but wish to use the standard FPSCR values for everything
629
+ uint8_t buf[4];
1571
+ * else. Always set the rounding mode back to the correct value after
630
+
1572
+ * modifying it.
631
+ stl_le_p(buf, val);
1573
+ * The argument is a softfloat float_round_ value.
632
+
1574
+ */
633
+ /* Linux crc32c converts the output to one's complement. */
1575
+uint32_t HELPER(set_neon_rmode)(uint32_t rmode, CPUARMState *env)
634
+ return crc32c(acc, buf, bytes) ^ 0xffffffff;
1576
+{
635
+}
1577
+ float_status *fp_status = &env->vfp.standard_fp_status;
636
diff --git a/target/arm/op_addsub.h b/target/arm/tcg/op_addsub.c.inc
1578
+
637
similarity index 100%
1579
+ uint32_t prev_rmode = get_float_rounding_mode(fp_status);
638
rename from target/arm/op_addsub.h
1580
+ set_float_rounding_mode(rmode, fp_status);
639
rename to target/arm/tcg/op_addsub.c.inc
1581
+
640
diff --git a/target/arm/tcg/meson.build b/target/arm/tcg/meson.build
1582
+ return prev_rmode;
641
index XXXXXXX..XXXXXXX 100644
1583
+}
642
--- a/target/arm/tcg/meson.build
1584
+
643
+++ b/target/arm/tcg/meson.build
1585
+/* Half precision conversions. */
644
@@ -XXX,XX +XXX,XX @@ arm_ss.add(files(
1586
+float32 HELPER(vfp_fcvt_f16_to_f32)(uint32_t a, void *fpstp, uint32_t ahp_mode)
645
'tlb_helper.c',
1587
+{
646
'vec_helper.c',
1588
+ /* Squash FZ16 to 0 for the duration of conversion. In this case,
647
'tlb-insns.c',
1589
+ * it would affect flushing input denormals.
648
+ 'arith_helper.c',
1590
+ */
649
))
1591
+ float_status *fpst = fpstp;
650
1592
+ flag save = get_flush_inputs_to_zero(fpst);
651
arm_ss.add(when: 'TARGET_AARCH64', if_true: files(
1593
+ set_flush_inputs_to_zero(false, fpst);
1594
+ float32 r = float16_to_float32(a, !ahp_mode, fpst);
1595
+ set_flush_inputs_to_zero(save, fpst);
1596
+ return r;
1597
+}
1598
+
1599
+uint32_t HELPER(vfp_fcvt_f32_to_f16)(float32 a, void *fpstp, uint32_t ahp_mode)
1600
+{
1601
+ /* Squash FZ16 to 0 for the duration of conversion. In this case,
1602
+ * it would affect flushing output denormals.
1603
+ */
1604
+ float_status *fpst = fpstp;
1605
+ flag save = get_flush_to_zero(fpst);
1606
+ set_flush_to_zero(false, fpst);
1607
+ float16 r = float32_to_float16(a, !ahp_mode, fpst);
1608
+ set_flush_to_zero(save, fpst);
1609
+ return r;
1610
+}
1611
+
1612
+float64 HELPER(vfp_fcvt_f16_to_f64)(uint32_t a, void *fpstp, uint32_t ahp_mode)
1613
+{
1614
+ /* Squash FZ16 to 0 for the duration of conversion. In this case,
1615
+ * it would affect flushing input denormals.
1616
+ */
1617
+ float_status *fpst = fpstp;
1618
+ flag save = get_flush_inputs_to_zero(fpst);
1619
+ set_flush_inputs_to_zero(false, fpst);
1620
+ float64 r = float16_to_float64(a, !ahp_mode, fpst);
1621
+ set_flush_inputs_to_zero(save, fpst);
1622
+ return r;
1623
+}
1624
+
1625
+uint32_t HELPER(vfp_fcvt_f64_to_f16)(float64 a, void *fpstp, uint32_t ahp_mode)
1626
+{
1627
+ /* Squash FZ16 to 0 for the duration of conversion. In this case,
1628
+ * it would affect flushing output denormals.
1629
+ */
1630
+ float_status *fpst = fpstp;
1631
+ flag save = get_flush_to_zero(fpst);
1632
+ set_flush_to_zero(false, fpst);
1633
+ float16 r = float64_to_float16(a, !ahp_mode, fpst);
1634
+ set_flush_to_zero(save, fpst);
1635
+ return r;
1636
+}
1637
+
1638
+#define float32_two make_float32(0x40000000)
1639
+#define float32_three make_float32(0x40400000)
1640
+#define float32_one_point_five make_float32(0x3fc00000)
1641
+
1642
+float32 HELPER(recps_f32)(float32 a, float32 b, CPUARMState *env)
1643
+{
1644
+ float_status *s = &env->vfp.standard_fp_status;
1645
+ if ((float32_is_infinity(a) && float32_is_zero_or_denormal(b)) ||
1646
+ (float32_is_infinity(b) && float32_is_zero_or_denormal(a))) {
1647
+ if (!(float32_is_zero(a) || float32_is_zero(b))) {
1648
+ float_raise(float_flag_input_denormal, s);
1649
+ }
1650
+ return float32_two;
1651
+ }
1652
+ return float32_sub(float32_two, float32_mul(a, b, s), s);
1653
+}
1654
+
1655
+float32 HELPER(rsqrts_f32)(float32 a, float32 b, CPUARMState *env)
1656
+{
1657
+ float_status *s = &env->vfp.standard_fp_status;
1658
+ float32 product;
1659
+ if ((float32_is_infinity(a) && float32_is_zero_or_denormal(b)) ||
1660
+ (float32_is_infinity(b) && float32_is_zero_or_denormal(a))) {
1661
+ if (!(float32_is_zero(a) || float32_is_zero(b))) {
1662
+ float_raise(float_flag_input_denormal, s);
1663
+ }
1664
+ return float32_one_point_five;
1665
+ }
1666
+ product = float32_mul(a, b, s);
1667
+ return float32_div(float32_sub(float32_three, product, s), float32_two, s);
1668
+}
1669
+
1670
+/* NEON helpers. */
1671
+
1672
+/* Constants 256 and 512 are used in some helpers; we avoid relying on
1673
+ * int->float conversions at run-time. */
1674
+#define float64_256 make_float64(0x4070000000000000LL)
1675
+#define float64_512 make_float64(0x4080000000000000LL)
1676
+#define float16_maxnorm make_float16(0x7bff)
1677
+#define float32_maxnorm make_float32(0x7f7fffff)
1678
+#define float64_maxnorm make_float64(0x7fefffffffffffffLL)
1679
+
1680
+/* Reciprocal functions
1681
+ *
1682
+ * The algorithm that must be used to calculate the estimate
1683
+ * is specified by the ARM ARM, see FPRecipEstimate()/RecipEstimate
1684
+ */
1685
+
1686
+/* See RecipEstimate()
1687
+ *
1688
+ * input is a 9 bit fixed point number
1689
+ * input range 256 .. 511 for a number from 0.5 <= x < 1.0.
1690
+ * result range 256 .. 511 for a number from 1.0 to 511/256.
1691
+ */
1692
+
1693
+static int recip_estimate(int input)
1694
+{
1695
+ int a, b, r;
1696
+ assert(256 <= input && input < 512);
1697
+ a = (input * 2) + 1;
1698
+ b = (1 << 19) / a;
1699
+ r = (b + 1) >> 1;
1700
+ assert(256 <= r && r < 512);
1701
+ return r;
1702
+}
1703
+
1704
+/*
1705
+ * Common wrapper to call recip_estimate
1706
+ *
1707
+ * The parameters are exponent and 64 bit fraction (without implicit
1708
+ * bit) where the binary point is nominally at bit 52. Returns a
1709
+ * float64 which can then be rounded to the appropriate size by the
1710
+ * callee.
1711
+ */
1712
+
1713
+static uint64_t call_recip_estimate(int *exp, int exp_off, uint64_t frac)
1714
+{
1715
+ uint32_t scaled, estimate;
1716
+ uint64_t result_frac;
1717
+ int result_exp;
1718
+
1719
+ /* Handle sub-normals */
1720
+ if (*exp == 0) {
1721
+ if (extract64(frac, 51, 1) == 0) {
1722
+ *exp = -1;
1723
+ frac <<= 2;
1724
+ } else {
1725
+ frac <<= 1;
1726
+ }
1727
+ }
1728
+
1729
+ /* scaled = UInt('1':fraction<51:44>) */
1730
+ scaled = deposit32(1 << 8, 0, 8, extract64(frac, 44, 8));
1731
+ estimate = recip_estimate(scaled);
1732
+
1733
+ result_exp = exp_off - *exp;
1734
+ result_frac = deposit64(0, 44, 8, estimate);
1735
+ if (result_exp == 0) {
1736
+ result_frac = deposit64(result_frac >> 1, 51, 1, 1);
1737
+ } else if (result_exp == -1) {
1738
+ result_frac = deposit64(result_frac >> 2, 50, 2, 1);
1739
+ result_exp = 0;
1740
+ }
1741
+
1742
+ *exp = result_exp;
1743
+
1744
+ return result_frac;
1745
+}
1746
+
1747
+static bool round_to_inf(float_status *fpst, bool sign_bit)
1748
+{
1749
+ switch (fpst->float_rounding_mode) {
1750
+ case float_round_nearest_even: /* Round to Nearest */
1751
+ return true;
1752
+ case float_round_up: /* Round to +Inf */
1753
+ return !sign_bit;
1754
+ case float_round_down: /* Round to -Inf */
1755
+ return sign_bit;
1756
+ case float_round_to_zero: /* Round to Zero */
1757
+ return false;
1758
+ }
1759
+
1760
+ g_assert_not_reached();
1761
+}
1762
+
1763
+uint32_t HELPER(recpe_f16)(uint32_t input, void *fpstp)
1764
+{
1765
+ float_status *fpst = fpstp;
1766
+ float16 f16 = float16_squash_input_denormal(input, fpst);
1767
+ uint32_t f16_val = float16_val(f16);
1768
+ uint32_t f16_sign = float16_is_neg(f16);
1769
+ int f16_exp = extract32(f16_val, 10, 5);
1770
+ uint32_t f16_frac = extract32(f16_val, 0, 10);
1771
+ uint64_t f64_frac;
1772
+
1773
+ if (float16_is_any_nan(f16)) {
1774
+ float16 nan = f16;
1775
+ if (float16_is_signaling_nan(f16, fpst)) {
1776
+ float_raise(float_flag_invalid, fpst);
1777
+ nan = float16_silence_nan(f16, fpst);
1778
+ }
1779
+ if (fpst->default_nan_mode) {
1780
+ nan = float16_default_nan(fpst);
1781
+ }
1782
+ return nan;
1783
+ } else if (float16_is_infinity(f16)) {
1784
+ return float16_set_sign(float16_zero, float16_is_neg(f16));
1785
+ } else if (float16_is_zero(f16)) {
1786
+ float_raise(float_flag_divbyzero, fpst);
1787
+ return float16_set_sign(float16_infinity, float16_is_neg(f16));
1788
+ } else if (float16_abs(f16) < (1 << 8)) {
1789
+ /* Abs(value) < 2.0^-16 */
1790
+ float_raise(float_flag_overflow | float_flag_inexact, fpst);
1791
+ if (round_to_inf(fpst, f16_sign)) {
1792
+ return float16_set_sign(float16_infinity, f16_sign);
1793
+ } else {
1794
+ return float16_set_sign(float16_maxnorm, f16_sign);
1795
+ }
1796
+ } else if (f16_exp >= 29 && fpst->flush_to_zero) {
1797
+ float_raise(float_flag_underflow, fpst);
1798
+ return float16_set_sign(float16_zero, float16_is_neg(f16));
1799
+ }
1800
+
1801
+ f64_frac = call_recip_estimate(&f16_exp, 29,
1802
+ ((uint64_t) f16_frac) << (52 - 10));
1803
+
1804
+ /* result = sign : result_exp<4:0> : fraction<51:42> */
1805
+ f16_val = deposit32(0, 15, 1, f16_sign);
1806
+ f16_val = deposit32(f16_val, 10, 5, f16_exp);
1807
+ f16_val = deposit32(f16_val, 0, 10, extract64(f64_frac, 52 - 10, 10));
1808
+ return make_float16(f16_val);
1809
+}
1810
+
1811
+float32 HELPER(recpe_f32)(float32 input, void *fpstp)
1812
+{
1813
+ float_status *fpst = fpstp;
1814
+ float32 f32 = float32_squash_input_denormal(input, fpst);
1815
+ uint32_t f32_val = float32_val(f32);
1816
+ bool f32_sign = float32_is_neg(f32);
1817
+ int f32_exp = extract32(f32_val, 23, 8);
1818
+ uint32_t f32_frac = extract32(f32_val, 0, 23);
1819
+ uint64_t f64_frac;
1820
+
1821
+ if (float32_is_any_nan(f32)) {
1822
+ float32 nan = f32;
1823
+ if (float32_is_signaling_nan(f32, fpst)) {
1824
+ float_raise(float_flag_invalid, fpst);
1825
+ nan = float32_silence_nan(f32, fpst);
1826
+ }
1827
+ if (fpst->default_nan_mode) {
1828
+ nan = float32_default_nan(fpst);
1829
+ }
1830
+ return nan;
1831
+ } else if (float32_is_infinity(f32)) {
1832
+ return float32_set_sign(float32_zero, float32_is_neg(f32));
1833
+ } else if (float32_is_zero(f32)) {
1834
+ float_raise(float_flag_divbyzero, fpst);
1835
+ return float32_set_sign(float32_infinity, float32_is_neg(f32));
1836
+ } else if (float32_abs(f32) < (1ULL << 21)) {
1837
+ /* Abs(value) < 2.0^-128 */
1838
+ float_raise(float_flag_overflow | float_flag_inexact, fpst);
1839
+ if (round_to_inf(fpst, f32_sign)) {
1840
+ return float32_set_sign(float32_infinity, f32_sign);
1841
+ } else {
1842
+ return float32_set_sign(float32_maxnorm, f32_sign);
1843
+ }
1844
+ } else if (f32_exp >= 253 && fpst->flush_to_zero) {
1845
+ float_raise(float_flag_underflow, fpst);
1846
+ return float32_set_sign(float32_zero, float32_is_neg(f32));
1847
+ }
1848
+
1849
+ f64_frac = call_recip_estimate(&f32_exp, 253,
1850
+ ((uint64_t) f32_frac) << (52 - 23));
1851
+
1852
+ /* result = sign : result_exp<7:0> : fraction<51:29> */
1853
+ f32_val = deposit32(0, 31, 1, f32_sign);
1854
+ f32_val = deposit32(f32_val, 23, 8, f32_exp);
1855
+ f32_val = deposit32(f32_val, 0, 23, extract64(f64_frac, 52 - 23, 23));
1856
+ return make_float32(f32_val);
1857
+}
1858
+
1859
+float64 HELPER(recpe_f64)(float64 input, void *fpstp)
1860
+{
1861
+ float_status *fpst = fpstp;
1862
+ float64 f64 = float64_squash_input_denormal(input, fpst);
1863
+ uint64_t f64_val = float64_val(f64);
1864
+ bool f64_sign = float64_is_neg(f64);
1865
+ int f64_exp = extract64(f64_val, 52, 11);
1866
+ uint64_t f64_frac = extract64(f64_val, 0, 52);
1867
+
1868
+ /* Deal with any special cases */
1869
+ if (float64_is_any_nan(f64)) {
1870
+ float64 nan = f64;
1871
+ if (float64_is_signaling_nan(f64, fpst)) {
1872
+ float_raise(float_flag_invalid, fpst);
1873
+ nan = float64_silence_nan(f64, fpst);
1874
+ }
1875
+ if (fpst->default_nan_mode) {
1876
+ nan = float64_default_nan(fpst);
1877
+ }
1878
+ return nan;
1879
+ } else if (float64_is_infinity(f64)) {
1880
+ return float64_set_sign(float64_zero, float64_is_neg(f64));
1881
+ } else if (float64_is_zero(f64)) {
1882
+ float_raise(float_flag_divbyzero, fpst);
1883
+ return float64_set_sign(float64_infinity, float64_is_neg(f64));
1884
+ } else if ((f64_val & ~(1ULL << 63)) < (1ULL << 50)) {
1885
+ /* Abs(value) < 2.0^-1024 */
1886
+ float_raise(float_flag_overflow | float_flag_inexact, fpst);
1887
+ if (round_to_inf(fpst, f64_sign)) {
1888
+ return float64_set_sign(float64_infinity, f64_sign);
1889
+ } else {
1890
+ return float64_set_sign(float64_maxnorm, f64_sign);
1891
+ }
1892
+ } else if (f64_exp >= 2045 && fpst->flush_to_zero) {
1893
+ float_raise(float_flag_underflow, fpst);
1894
+ return float64_set_sign(float64_zero, float64_is_neg(f64));
1895
+ }
1896
+
1897
+ f64_frac = call_recip_estimate(&f64_exp, 2045, f64_frac);
1898
+
1899
+ /* result = sign : result_exp<10:0> : fraction<51:0>; */
1900
+ f64_val = deposit64(0, 63, 1, f64_sign);
1901
+ f64_val = deposit64(f64_val, 52, 11, f64_exp);
1902
+ f64_val = deposit64(f64_val, 0, 52, f64_frac);
1903
+ return make_float64(f64_val);
1904
+}
1905
+
1906
+/* The algorithm that must be used to calculate the estimate
1907
+ * is specified by the ARM ARM.
1908
+ */
1909
+
1910
+static int do_recip_sqrt_estimate(int a)
1911
+{
1912
+ int b, estimate;
1913
+
1914
+ assert(128 <= a && a < 512);
1915
+ if (a < 256) {
1916
+ a = a * 2 + 1;
1917
+ } else {
1918
+ a = (a >> 1) << 1;
1919
+ a = (a + 1) * 2;
1920
+ }
1921
+ b = 512;
1922
+ while (a * (b + 1) * (b + 1) < (1 << 28)) {
1923
+ b += 1;
1924
+ }
1925
+ estimate = (b + 1) / 2;
1926
+ assert(256 <= estimate && estimate < 512);
1927
+
1928
+ return estimate;
1929
+}
1930
+
1931
+
1932
+static uint64_t recip_sqrt_estimate(int *exp , int exp_off, uint64_t frac)
1933
+{
1934
+ int estimate;
1935
+ uint32_t scaled;
1936
+
1937
+ if (*exp == 0) {
1938
+ while (extract64(frac, 51, 1) == 0) {
1939
+ frac = frac << 1;
1940
+ *exp -= 1;
1941
+ }
1942
+ frac = extract64(frac, 0, 51) << 1;
1943
+ }
1944
+
1945
+ if (*exp & 1) {
1946
+ /* scaled = UInt('01':fraction<51:45>) */
1947
+ scaled = deposit32(1 << 7, 0, 7, extract64(frac, 45, 7));
1948
+ } else {
1949
+ /* scaled = UInt('1':fraction<51:44>) */
1950
+ scaled = deposit32(1 << 8, 0, 8, extract64(frac, 44, 8));
1951
+ }
1952
+ estimate = do_recip_sqrt_estimate(scaled);
1953
+
1954
+ *exp = (exp_off - *exp) / 2;
1955
+ return extract64(estimate, 0, 8) << 44;
1956
+}
1957
+
1958
+uint32_t HELPER(rsqrte_f16)(uint32_t input, void *fpstp)
1959
+{
1960
+ float_status *s = fpstp;
1961
+ float16 f16 = float16_squash_input_denormal(input, s);
1962
+ uint16_t val = float16_val(f16);
1963
+ bool f16_sign = float16_is_neg(f16);
1964
+ int f16_exp = extract32(val, 10, 5);
1965
+ uint16_t f16_frac = extract32(val, 0, 10);
1966
+ uint64_t f64_frac;
1967
+
1968
+ if (float16_is_any_nan(f16)) {
1969
+ float16 nan = f16;
1970
+ if (float16_is_signaling_nan(f16, s)) {
1971
+ float_raise(float_flag_invalid, s);
1972
+ nan = float16_silence_nan(f16, s);
1973
+ }
1974
+ if (s->default_nan_mode) {
1975
+ nan = float16_default_nan(s);
1976
+ }
1977
+ return nan;
1978
+ } else if (float16_is_zero(f16)) {
1979
+ float_raise(float_flag_divbyzero, s);
1980
+ return float16_set_sign(float16_infinity, f16_sign);
1981
+ } else if (f16_sign) {
1982
+ float_raise(float_flag_invalid, s);
1983
+ return float16_default_nan(s);
1984
+ } else if (float16_is_infinity(f16)) {
1985
+ return float16_zero;
1986
+ }
1987
+
1988
+ /* Scale and normalize to a double-precision value between 0.25 and 1.0,
1989
+ * preserving the parity of the exponent. */
1990
+
1991
+ f64_frac = ((uint64_t) f16_frac) << (52 - 10);
1992
+
1993
+ f64_frac = recip_sqrt_estimate(&f16_exp, 44, f64_frac);
1994
+
1995
+ /* result = sign : result_exp<4:0> : estimate<7:0> : Zeros(2) */
1996
+ val = deposit32(0, 15, 1, f16_sign);
1997
+ val = deposit32(val, 10, 5, f16_exp);
1998
+ val = deposit32(val, 2, 8, extract64(f64_frac, 52 - 8, 8));
1999
+ return make_float16(val);
2000
+}
2001
+
2002
+float32 HELPER(rsqrte_f32)(float32 input, void *fpstp)
2003
+{
2004
+ float_status *s = fpstp;
2005
+ float32 f32 = float32_squash_input_denormal(input, s);
2006
+ uint32_t val = float32_val(f32);
2007
+ uint32_t f32_sign = float32_is_neg(f32);
2008
+ int f32_exp = extract32(val, 23, 8);
2009
+ uint32_t f32_frac = extract32(val, 0, 23);
2010
+ uint64_t f64_frac;
2011
+
2012
+ if (float32_is_any_nan(f32)) {
2013
+ float32 nan = f32;
2014
+ if (float32_is_signaling_nan(f32, s)) {
2015
+ float_raise(float_flag_invalid, s);
2016
+ nan = float32_silence_nan(f32, s);
2017
+ }
2018
+ if (s->default_nan_mode) {
2019
+ nan = float32_default_nan(s);
2020
+ }
2021
+ return nan;
2022
+ } else if (float32_is_zero(f32)) {
2023
+ float_raise(float_flag_divbyzero, s);
2024
+ return float32_set_sign(float32_infinity, float32_is_neg(f32));
2025
+ } else if (float32_is_neg(f32)) {
2026
+ float_raise(float_flag_invalid, s);
2027
+ return float32_default_nan(s);
2028
+ } else if (float32_is_infinity(f32)) {
2029
+ return float32_zero;
2030
+ }
2031
+
2032
+ /* Scale and normalize to a double-precision value between 0.25 and 1.0,
2033
+ * preserving the parity of the exponent. */
2034
+
2035
+ f64_frac = ((uint64_t) f32_frac) << 29;
2036
+
2037
+ f64_frac = recip_sqrt_estimate(&f32_exp, 380, f64_frac);
2038
+
2039
+ /* result = sign : result_exp<4:0> : estimate<7:0> : Zeros(15) */
2040
+ val = deposit32(0, 31, 1, f32_sign);
2041
+ val = deposit32(val, 23, 8, f32_exp);
2042
+ val = deposit32(val, 15, 8, extract64(f64_frac, 52 - 8, 8));
2043
+ return make_float32(val);
2044
+}
2045
+
2046
+float64 HELPER(rsqrte_f64)(float64 input, void *fpstp)
2047
+{
2048
+ float_status *s = fpstp;
2049
+ float64 f64 = float64_squash_input_denormal(input, s);
2050
+ uint64_t val = float64_val(f64);
2051
+ bool f64_sign = float64_is_neg(f64);
2052
+ int f64_exp = extract64(val, 52, 11);
2053
+ uint64_t f64_frac = extract64(val, 0, 52);
2054
+
2055
+ if (float64_is_any_nan(f64)) {
2056
+ float64 nan = f64;
2057
+ if (float64_is_signaling_nan(f64, s)) {
2058
+ float_raise(float_flag_invalid, s);
2059
+ nan = float64_silence_nan(f64, s);
2060
+ }
2061
+ if (s->default_nan_mode) {
2062
+ nan = float64_default_nan(s);
2063
+ }
2064
+ return nan;
2065
+ } else if (float64_is_zero(f64)) {
2066
+ float_raise(float_flag_divbyzero, s);
2067
+ return float64_set_sign(float64_infinity, float64_is_neg(f64));
2068
+ } else if (float64_is_neg(f64)) {
2069
+ float_raise(float_flag_invalid, s);
2070
+ return float64_default_nan(s);
2071
+ } else if (float64_is_infinity(f64)) {
2072
+ return float64_zero;
2073
+ }
2074
+
2075
+ f64_frac = recip_sqrt_estimate(&f64_exp, 3068, f64_frac);
2076
+
2077
+ /* result = sign : result_exp<4:0> : estimate<7:0> : Zeros(44) */
2078
+ val = deposit64(0, 61, 1, f64_sign);
2079
+ val = deposit64(val, 52, 11, f64_exp);
2080
+ val = deposit64(val, 44, 8, extract64(f64_frac, 52 - 8, 8));
2081
+ return make_float64(val);
2082
+}
2083
+
2084
+uint32_t HELPER(recpe_u32)(uint32_t a, void *fpstp)
2085
+{
2086
+ /* float_status *s = fpstp; */
2087
+ int input, estimate;
2088
+
2089
+ if ((a & 0x80000000) == 0) {
2090
+ return 0xffffffff;
2091
+ }
2092
+
2093
+ input = extract32(a, 23, 9);
2094
+ estimate = recip_estimate(input);
2095
+
2096
+ return deposit32(0, (32 - 9), 9, estimate);
2097
+}
2098
+
2099
+uint32_t HELPER(rsqrte_u32)(uint32_t a, void *fpstp)
2100
+{
2101
+ int estimate;
2102
+
2103
+ if ((a & 0xc0000000) == 0) {
2104
+ return 0xffffffff;
2105
+ }
2106
+
2107
+ estimate = do_recip_sqrt_estimate(extract32(a, 23, 9));
2108
+
2109
+ return deposit32(0, 23, 9, estimate);
2110
+}
2111
+
2112
+/* VFPv4 fused multiply-accumulate */
2113
+float32 VFP_HELPER(muladd, s)(float32 a, float32 b, float32 c, void *fpstp)
2114
+{
2115
+ float_status *fpst = fpstp;
2116
+ return float32_muladd(a, b, c, 0, fpst);
2117
+}
2118
+
2119
+float64 VFP_HELPER(muladd, d)(float64 a, float64 b, float64 c, void *fpstp)
2120
+{
2121
+ float_status *fpst = fpstp;
2122
+ return float64_muladd(a, b, c, 0, fpst);
2123
+}
2124
+
2125
+/* ARMv8 round to integral */
2126
+float32 HELPER(rints_exact)(float32 x, void *fp_status)
2127
+{
2128
+ return float32_round_to_int(x, fp_status);
2129
+}
2130
+
2131
+float64 HELPER(rintd_exact)(float64 x, void *fp_status)
2132
+{
2133
+ return float64_round_to_int(x, fp_status);
2134
+}
2135
+
2136
+float32 HELPER(rints)(float32 x, void *fp_status)
2137
+{
2138
+ int old_flags = get_float_exception_flags(fp_status), new_flags;
2139
+ float32 ret;
2140
+
2141
+ ret = float32_round_to_int(x, fp_status);
2142
+
2143
+ /* Suppress any inexact exceptions the conversion produced */
2144
+ if (!(old_flags & float_flag_inexact)) {
2145
+ new_flags = get_float_exception_flags(fp_status);
2146
+ set_float_exception_flags(new_flags & ~float_flag_inexact, fp_status);
2147
+ }
2148
+
2149
+ return ret;
2150
+}
2151
+
2152
+float64 HELPER(rintd)(float64 x, void *fp_status)
2153
+{
2154
+ int old_flags = get_float_exception_flags(fp_status), new_flags;
2155
+ float64 ret;
2156
+
2157
+ ret = float64_round_to_int(x, fp_status);
2158
+
2159
+ new_flags = get_float_exception_flags(fp_status);
2160
+
2161
+ /* Suppress any inexact exceptions the conversion produced */
2162
+ if (!(old_flags & float_flag_inexact)) {
2163
+ new_flags = get_float_exception_flags(fp_status);
2164
+ set_float_exception_flags(new_flags & ~float_flag_inexact, fp_status);
2165
+ }
2166
+
2167
+ return ret;
2168
+}
2169
+
2170
+/* Convert ARM rounding mode to softfloat */
2171
+int arm_rmode_to_sf(int rmode)
2172
+{
2173
+ switch (rmode) {
2174
+ case FPROUNDING_TIEAWAY:
2175
+ rmode = float_round_ties_away;
2176
+ break;
2177
+ case FPROUNDING_ODD:
2178
+ /* FIXME: add support for TIEAWAY and ODD */
2179
+ qemu_log_mask(LOG_UNIMP, "arm: unimplemented rounding mode: %d\n",
2180
+ rmode);
2181
+ /* fall through for now */
2182
+ case FPROUNDING_TIEEVEN:
2183
+ default:
2184
+ rmode = float_round_nearest_even;
2185
+ break;
2186
+ case FPROUNDING_POSINF:
2187
+ rmode = float_round_up;
2188
+ break;
2189
+ case FPROUNDING_NEGINF:
2190
+ rmode = float_round_down;
2191
+ break;
2192
+ case FPROUNDING_ZERO:
2193
+ rmode = float_round_to_zero;
2194
+ break;
2195
+ }
2196
+ return rmode;
2197
+}
2198
--
652
--
2199
2.20.1
653
2.34.1
2200
654
2201
655
diff view generated by jsdifflib
1
The Musca board puts its SRAM and flash behind TrustZone
1
From: Pierrick Bouvier <pierrick.bouvier@linaro.org>
2
Memory Protection Controllers (MPCs). Each MPC sits between
3
the CPU and the RAM/flash, and also has a set of memory mapped
4
control registers. Wire up the MPCs, and the memory behind them.
5
For the moment we implement the flash as simple ROM, which
6
cannot be reprogrammed by the guest.
7
2
3
Before changing default pauth algorithm, we need to make sure current
4
default one (QARMA5) can still be selected.
5
6
$ qemu-system-aarch64 -cpu max,pauth-qarma5=on ...
7
8
Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 20241219183211.3493974-2-pierrick.bouvier@linaro.org
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
---
12
---
11
hw/arm/musca.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++---
13
docs/system/arm/cpu-features.rst | 5 ++++-
12
1 file changed, 147 insertions(+), 8 deletions(-)
14
target/arm/cpu.h | 1 +
15
target/arm/arm-qmp-cmds.c | 2 +-
16
target/arm/cpu64.c | 20 ++++++++++++++------
17
tests/qtest/arm-cpu-features.c | 15 +++++++++++----
18
5 files changed, 31 insertions(+), 12 deletions(-)
13
19
14
diff --git a/hw/arm/musca.c b/hw/arm/musca.c
20
diff --git a/docs/system/arm/cpu-features.rst b/docs/system/arm/cpu-features.rst
15
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/arm/musca.c
22
--- a/docs/system/arm/cpu-features.rst
17
+++ b/hw/arm/musca.c
23
+++ b/docs/system/arm/cpu-features.rst
18
@@ -XXX,XX +XXX,XX @@
24
@@ -XXX,XX +XXX,XX @@ Below is the list of TCG VCPU features and their descriptions.
19
#include "hw/arm/armsse.h"
25
``pauth-qarma3``
20
#include "hw/boards.h"
26
When ``pauth`` is enabled, select the architected QARMA3 algorithm.
21
#include "hw/core/split-irq.h"
27
22
+#include "hw/misc/tz-mpc.h"
28
-Without either ``pauth-impdef`` or ``pauth-qarma3`` enabled,
23
#include "hw/misc/tz-ppc.h"
29
+``pauth-qarma5``
24
#include "hw/misc/unimp.h"
30
+ When ``pauth`` is enabled, select the architected QARMA5 algorithm.
25
26
#define MUSCA_NUMIRQ_MAX 96
27
#define MUSCA_PPC_MAX 3
28
+#define MUSCA_MPC_MAX 5
29
+
31
+
30
+typedef struct MPCInfo MPCInfo;
32
+Without ``pauth-impdef``, ``pauth-qarma3`` or ``pauth-qarma5`` enabled,
31
33
the architected QARMA5 algorithm is used. The architected QARMA5
32
typedef enum MuscaType {
34
and QARMA3 algorithms have good cryptographic properties, but can
33
MUSCA_A,
35
be quite slow to emulate. The impdef algorithm used by QEMU is
34
@@ -XXX,XX +XXX,XX @@ typedef struct {
36
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
35
uint32_t init_svtor;
37
index XXXXXXX..XXXXXXX 100644
36
int sram_addr_width;
38
--- a/target/arm/cpu.h
37
int num_irqs;
39
+++ b/target/arm/cpu.h
38
+ const MPCInfo *mpc_info;
40
@@ -XXX,XX +XXX,XX @@ struct ArchCPU {
39
+ int num_mpcs;
41
bool prop_pauth;
40
} MuscaMachineClass;
42
bool prop_pauth_impdef;
41
43
bool prop_pauth_qarma3;
42
typedef struct {
44
+ bool prop_pauth_qarma5;
43
MachineState parent;
45
bool prop_lpa2;
44
46
45
ARMSSE sse;
47
/* DCZ blocksize, in log_2(words), ie low 4 bits of DCZID_EL0 */
46
+ /* RAM and flash */
48
diff --git a/target/arm/arm-qmp-cmds.c b/target/arm/arm-qmp-cmds.c
47
+ MemoryRegion ram[MUSCA_MPC_MAX];
49
index XXXXXXX..XXXXXXX 100644
48
SplitIRQ cpu_irq_splitter[MUSCA_NUMIRQ_MAX];
50
--- a/target/arm/arm-qmp-cmds.c
49
SplitIRQ sec_resp_splitter;
51
+++ b/target/arm/arm-qmp-cmds.c
50
TZPPC ppc[MUSCA_PPC_MAX];
52
@@ -XXX,XX +XXX,XX @@ static const char *cpu_model_advertised_features[] = {
51
MemoryRegion container;
53
"sve640", "sve768", "sve896", "sve1024", "sve1152", "sve1280",
52
UnimplementedDeviceState eflash[2];
54
"sve1408", "sve1536", "sve1664", "sve1792", "sve1920", "sve2048",
53
UnimplementedDeviceState qspi;
55
"kvm-no-adjvtime", "kvm-steal-time",
54
- UnimplementedDeviceState mpc[5];
56
- "pauth", "pauth-impdef", "pauth-qarma3",
55
+ TZMPC mpc[MUSCA_MPC_MAX];
57
+ "pauth", "pauth-impdef", "pauth-qarma3", "pauth-qarma5",
56
UnimplementedDeviceState mhu[2];
58
NULL
57
UnimplementedDeviceState pwm[3];
59
};
58
UnimplementedDeviceState i2s;
60
59
@@ -XXX,XX +XXX,XX @@ typedef struct {
61
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
60
UnimplementedDeviceState pvt;
62
index XXXXXXX..XXXXXXX 100644
61
UnimplementedDeviceState sdio;
63
--- a/target/arm/cpu64.c
62
UnimplementedDeviceState gpio;
64
+++ b/target/arm/cpu64.c
63
+ UnimplementedDeviceState cryptoisland;
65
@@ -XXX,XX +XXX,XX @@ void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp)
64
} MuscaMachineState;
66
}
65
67
66
#define TYPE_MUSCA_MACHINE "musca"
68
if (cpu->prop_pauth) {
67
@@ -XXX,XX +XXX,XX @@ static MemoryRegion *make_unimp_dev(MuscaMachineState *mms,
69
- if (cpu->prop_pauth_impdef && cpu->prop_pauth_qarma3) {
68
return sysbus_mmio_get_region(SYS_BUS_DEVICE(uds), 0);
70
+ if ((cpu->prop_pauth_impdef && cpu->prop_pauth_qarma3) ||
71
+ (cpu->prop_pauth_impdef && cpu->prop_pauth_qarma5) ||
72
+ (cpu->prop_pauth_qarma3 && cpu->prop_pauth_qarma5)) {
73
error_setg(errp,
74
- "cannot enable both pauth-impdef and pauth-qarma3");
75
+ "cannot enable pauth-impdef, pauth-qarma3 and "
76
+ "pauth-qarma5 at the same time");
77
return;
78
}
79
80
@@ -XXX,XX +XXX,XX @@ void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp)
81
} else if (cpu->prop_pauth_qarma3) {
82
isar2 = FIELD_DP64(isar2, ID_AA64ISAR2, APA3, features);
83
isar2 = FIELD_DP64(isar2, ID_AA64ISAR2, GPA3, 1);
84
- } else {
85
+ } else { /* default is pauth-qarma5 */
86
isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, APA, features);
87
isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, GPA, 1);
88
}
89
- } else if (cpu->prop_pauth_impdef || cpu->prop_pauth_qarma3) {
90
- error_setg(errp, "cannot enable pauth-impdef or "
91
- "pauth-qarma3 without pauth");
92
+ } else if (cpu->prop_pauth_impdef ||
93
+ cpu->prop_pauth_qarma3 ||
94
+ cpu->prop_pauth_qarma5) {
95
+ error_setg(errp, "cannot enable pauth-impdef, pauth-qarma3 or "
96
+ "pauth-qarma5 without pauth");
97
error_append_hint(errp, "Add pauth=on to the CPU property list.\n");
98
}
99
}
100
@@ -XXX,XX +XXX,XX @@ static const Property arm_cpu_pauth_impdef_property =
101
DEFINE_PROP_BOOL("pauth-impdef", ARMCPU, prop_pauth_impdef, false);
102
static const Property arm_cpu_pauth_qarma3_property =
103
DEFINE_PROP_BOOL("pauth-qarma3", ARMCPU, prop_pauth_qarma3, false);
104
+static Property arm_cpu_pauth_qarma5_property =
105
+ DEFINE_PROP_BOOL("pauth-qarma5", ARMCPU, prop_pauth_qarma5, false);
106
107
void aarch64_add_pauth_properties(Object *obj)
108
{
109
@@ -XXX,XX +XXX,XX @@ void aarch64_add_pauth_properties(Object *obj)
110
} else {
111
qdev_property_add_static(DEVICE(obj), &arm_cpu_pauth_impdef_property);
112
qdev_property_add_static(DEVICE(obj), &arm_cpu_pauth_qarma3_property);
113
+ qdev_property_add_static(DEVICE(obj), &arm_cpu_pauth_qarma5_property);
114
}
69
}
115
}
70
116
71
+typedef enum MPCInfoType {
117
diff --git a/tests/qtest/arm-cpu-features.c b/tests/qtest/arm-cpu-features.c
72
+ MPC_RAM,
118
index XXXXXXX..XXXXXXX 100644
73
+ MPC_ROM,
119
--- a/tests/qtest/arm-cpu-features.c
74
+ MPC_CRYPTOISLAND,
120
+++ b/tests/qtest/arm-cpu-features.c
75
+} MPCInfoType;
121
@@ -XXX,XX +XXX,XX @@ static void pauth_tests_default(QTestState *qts, const char *cpu_type)
76
+
122
assert_has_feature_enabled(qts, cpu_type, "pauth");
77
+struct MPCInfo {
123
assert_has_feature_disabled(qts, cpu_type, "pauth-impdef");
78
+ const char *name;
124
assert_has_feature_disabled(qts, cpu_type, "pauth-qarma3");
79
+ hwaddr addr;
125
+ assert_has_feature_disabled(qts, cpu_type, "pauth-qarma5");
80
+ hwaddr size;
126
assert_set_feature(qts, cpu_type, "pauth", false);
81
+ MPCInfoType type;
127
assert_set_feature(qts, cpu_type, "pauth", true);
82
+};
128
assert_set_feature(qts, cpu_type, "pauth-impdef", true);
83
+
129
assert_set_feature(qts, cpu_type, "pauth-impdef", false);
84
+/* Order of the MPCs here must match the order of the bits in SECMPCINTSTATUS */
130
assert_set_feature(qts, cpu_type, "pauth-qarma3", true);
85
+static const MPCInfo a_mpc_info[] = { {
131
assert_set_feature(qts, cpu_type, "pauth-qarma3", false);
86
+ .name = "qspi",
132
+ assert_set_feature(qts, cpu_type, "pauth-qarma5", true);
87
+ .type = MPC_ROM,
133
+ assert_set_feature(qts, cpu_type, "pauth-qarma5", false);
88
+ .addr = 0x00200000,
134
assert_error(qts, cpu_type,
89
+ .size = 0x00800000,
135
- "cannot enable pauth-impdef or pauth-qarma3 without pauth",
90
+ }, {
136
+ "cannot enable pauth-impdef, pauth-qarma3 or pauth-qarma5 without pauth",
91
+ .name = "sram",
137
"{ 'pauth': false, 'pauth-impdef': true }");
92
+ .type = MPC_RAM,
138
assert_error(qts, cpu_type,
93
+ .addr = 0x00000000,
139
- "cannot enable pauth-impdef or pauth-qarma3 without pauth",
94
+ .size = 0x00200000,
140
+ "cannot enable pauth-impdef, pauth-qarma3 or pauth-qarma5 without pauth",
95
+ }
141
"{ 'pauth': false, 'pauth-qarma3': true }");
96
+};
142
assert_error(qts, cpu_type,
97
+
143
- "cannot enable both pauth-impdef and pauth-qarma3",
98
+static const MPCInfo b1_mpc_info[] = { {
144
- "{ 'pauth': true, 'pauth-impdef': true, 'pauth-qarma3': true }");
99
+ .name = "qspi",
145
+ "cannot enable pauth-impdef, pauth-qarma3 or pauth-qarma5 without pauth",
100
+ .type = MPC_ROM,
146
+ "{ 'pauth': false, 'pauth-qarma5': true }");
101
+ .addr = 0x00000000,
147
+ assert_error(qts, cpu_type,
102
+ .size = 0x02000000,
148
+ "cannot enable pauth-impdef, pauth-qarma3 and pauth-qarma5 at the same time",
103
+ }, {
149
+ "{ 'pauth': true, 'pauth-impdef': true, 'pauth-qarma3': true,"
104
+ .name = "sram",
150
+ " 'pauth-qarma5': true }");
105
+ .type = MPC_RAM,
106
+ .addr = 0x0a400000,
107
+ .size = 0x00080000,
108
+ }, {
109
+ .name = "eflash0",
110
+ .type = MPC_ROM,
111
+ .addr = 0x0a000000,
112
+ .size = 0x00200000,
113
+ }, {
114
+ .name = "eflash1",
115
+ .type = MPC_ROM,
116
+ .addr = 0x0a200000,
117
+ .size = 0x00200000,
118
+ }, {
119
+ .name = "cryptoisland",
120
+ .type = MPC_CRYPTOISLAND,
121
+ .addr = 0x0a000000,
122
+ .size = 0x00200000,
123
+ }
124
+};
125
+
126
+static MemoryRegion *make_mpc(MuscaMachineState *mms, void *opaque,
127
+ const char *name, hwaddr size)
128
+{
129
+ /*
130
+ * Create an MPC and the RAM or flash behind it.
131
+ * MPC 0: eFlash 0
132
+ * MPC 1: eFlash 1
133
+ * MPC 2: SRAM
134
+ * MPC 3: QSPI flash
135
+ * MPC 4: CryptoIsland
136
+ * For now we implement the flash regions as ROM (ie not programmable)
137
+ * (with their control interface memory regions being unimplemented
138
+ * stubs behind the PPCs).
139
+ * The whole CryptoIsland region behind its MPC is an unimplemented stub.
140
+ */
141
+ MuscaMachineClass *mmc = MUSCA_MACHINE_GET_CLASS(mms);
142
+ TZMPC *mpc = opaque;
143
+ int i = mpc - &mms->mpc[0];
144
+ MemoryRegion *downstream;
145
+ MemoryRegion *upstream;
146
+ UnimplementedDeviceState *uds;
147
+ char *mpcname;
148
+ const MPCInfo *mpcinfo = mmc->mpc_info;
149
+
150
+ mpcname = g_strdup_printf("%s-mpc", mpcinfo[i].name);
151
+
152
+ switch (mpcinfo[i].type) {
153
+ case MPC_ROM:
154
+ downstream = &mms->ram[i];
155
+ memory_region_init_rom(downstream, NULL, mpcinfo[i].name,
156
+ mpcinfo[i].size, &error_fatal);
157
+ break;
158
+ case MPC_RAM:
159
+ downstream = &mms->ram[i];
160
+ memory_region_init_ram(downstream, NULL, mpcinfo[i].name,
161
+ mpcinfo[i].size, &error_fatal);
162
+ break;
163
+ case MPC_CRYPTOISLAND:
164
+ /* We don't implement the CryptoIsland yet */
165
+ uds = &mms->cryptoisland;
166
+ sysbus_init_child_obj(OBJECT(mms), name, uds,
167
+ sizeof(UnimplementedDeviceState),
168
+ TYPE_UNIMPLEMENTED_DEVICE);
169
+ qdev_prop_set_string(DEVICE(uds), "name", mpcinfo[i].name);
170
+ qdev_prop_set_uint64(DEVICE(uds), "size", mpcinfo[i].size);
171
+ object_property_set_bool(OBJECT(uds), true, "realized", &error_fatal);
172
+ downstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(uds), 0);
173
+ break;
174
+ default:
175
+ g_assert_not_reached();
176
+ }
177
+
178
+ sysbus_init_child_obj(OBJECT(mms), mpcname, mpc, sizeof(mms->mpc[0]),
179
+ TYPE_TZ_MPC);
180
+ object_property_set_link(OBJECT(mpc), OBJECT(downstream),
181
+ "downstream", &error_fatal);
182
+ object_property_set_bool(OBJECT(mpc), true, "realized", &error_fatal);
183
+ /* Map the upstream end of the MPC into system memory */
184
+ upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 1);
185
+ memory_region_add_subregion(get_system_memory(), mpcinfo[i].addr, upstream);
186
+ /* and connect its interrupt to the SSE-200 */
187
+ qdev_connect_gpio_out_named(DEVICE(mpc), "irq", 0,
188
+ qdev_get_gpio_in_named(DEVICE(&mms->sse),
189
+ "mpcexp_status", i));
190
+
191
+ g_free(mpcname);
192
+ /* Return the register interface MR for our caller to map behind the PPC */
193
+ return sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 0);
194
+}
195
+
196
static MemoryRegion *make_musca_a_devs(MuscaMachineState *mms, void *opaque,
197
const char *name, hwaddr size)
198
{
199
@@ -XXX,XX +XXX,XX @@ static MemoryRegion *make_musca_a_devs(MuscaMachineState *mms, void *opaque,
200
{ "pwm1", make_unimp_dev, &mms->pwm[1], 0xe000, 0x1000 },
201
{ "pwm2", make_unimp_dev, &mms->pwm[2], 0xf000, 0x1000 },
202
{ "gpio", make_unimp_dev, &mms->gpio, 0x10000, 0x1000 },
203
- { "mpc0", make_unimp_dev, &mms->mpc[0], 0x12000, 0x1000 },
204
- { "mpc1", make_unimp_dev, &mms->mpc[1], 0x13000, 0x1000 },
205
+ { "mpc0", make_mpc, &mms->mpc[0], 0x12000, 0x1000 },
206
+ { "mpc1", make_mpc, &mms->mpc[1], 0x13000, 0x1000 },
207
};
208
209
memory_region_init(container, OBJECT(mms), "musca-device-container", size);
210
@@ -XXX,XX +XXX,XX @@ static void musca_init(MachineState *machine)
211
int i;
212
213
assert(mmc->num_irqs <= MUSCA_NUMIRQ_MAX);
214
+ assert(mmc->num_mpcs <= MUSCA_MPC_MAX);
215
216
if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) {
217
error_report("This board can only be used with CPU %s",
218
@@ -XXX,XX +XXX,XX @@ static void musca_init(MachineState *machine)
219
{ "eflash1", make_unimp_dev, &mms->eflash[1],
220
0x52500000, 0x1000 },
221
{ "qspi", make_unimp_dev, &mms->qspi, 0x42800000, 0x100000 },
222
- { "mpc0", make_unimp_dev, &mms->mpc[0], 0x52000000, 0x1000 },
223
- { "mpc1", make_unimp_dev, &mms->mpc[1], 0x52100000, 0x1000 },
224
- { "mpc2", make_unimp_dev, &mms->mpc[2], 0x52200000, 0x1000 },
225
- { "mpc3", make_unimp_dev, &mms->mpc[3], 0x52300000, 0x1000 },
226
+ { "mpc0", make_mpc, &mms->mpc[0], 0x52000000, 0x1000 },
227
+ { "mpc1", make_mpc, &mms->mpc[1], 0x52100000, 0x1000 },
228
+ { "mpc2", make_mpc, &mms->mpc[2], 0x52200000, 0x1000 },
229
+ { "mpc3", make_mpc, &mms->mpc[3], 0x52300000, 0x1000 },
230
{ "mhu0", make_unimp_dev, &mms->mhu[0], 0x42600000, 0x100000 },
231
{ "mhu1", make_unimp_dev, &mms->mhu[1], 0x42700000, 0x100000 },
232
{ }, /* port 9: unused */
233
@@ -XXX,XX +XXX,XX @@ static void musca_init(MachineState *machine)
234
{ }, /* port 11: unused */
235
{ }, /* port 12: unused */
236
{ }, /* port 13: unused */
237
- { "mpc4", make_unimp_dev, &mms->mpc[4], 0x52e00000, 0x1000 },
238
+ { "mpc4", make_mpc, &mms->mpc[4], 0x52e00000, 0x1000 },
239
},
240
}, {
241
.name = "apb_ppcexp1",
242
@@ -XXX,XX +XXX,XX @@ static void musca_a_class_init(ObjectClass *oc, void *data)
243
mmc->init_svtor = 0x10200000;
244
mmc->sram_addr_width = 15;
245
mmc->num_irqs = 64;
246
+ mmc->mpc_info = a_mpc_info;
247
+ mmc->num_mpcs = ARRAY_SIZE(a_mpc_info);
248
}
151
}
249
152
250
static void musca_b1_class_init(ObjectClass *oc, void *data)
153
static void test_query_cpu_model_expansion(const void *data)
251
@@ -XXX,XX +XXX,XX @@ static void musca_b1_class_init(ObjectClass *oc, void *data)
252
mmc->init_svtor = 0x10000000;
253
mmc->sram_addr_width = 17;
254
mmc->num_irqs = 96;
255
+ mmc->mpc_info = b1_mpc_info;
256
+ mmc->num_mpcs = ARRAY_SIZE(b1_mpc_info);
257
}
258
259
static const TypeInfo musca_info = {
260
--
154
--
261
2.20.1
155
2.34.1
262
263
diff view generated by jsdifflib
1
Wire up the two PL011 UARTs in the Musca board.
1
The pauth-3 test explicitly tests that a computation of the
2
pointer-authentication produces the expected result. This means that
3
it must be run with the QARMA5 algorithm.
4
5
Explicitly set the pauth algorithm when running this test, so that it
6
doesn't break when we change the default algorithm the 'max' CPU
7
uses.
2
8
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
---
10
---
6
hw/arm/musca.c | 34 +++++++++++++++++++++++++++++-----
11
tests/tcg/aarch64/Makefile.softmmu-target | 3 +++
7
1 file changed, 29 insertions(+), 5 deletions(-)
12
1 file changed, 3 insertions(+)
8
13
9
diff --git a/hw/arm/musca.c b/hw/arm/musca.c
14
diff --git a/tests/tcg/aarch64/Makefile.softmmu-target b/tests/tcg/aarch64/Makefile.softmmu-target
10
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
11
--- a/hw/arm/musca.c
16
--- a/tests/tcg/aarch64/Makefile.softmmu-target
12
+++ b/hw/arm/musca.c
17
+++ b/tests/tcg/aarch64/Makefile.softmmu-target
13
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@ EXTRA_RUNS+=run-memory-replay
14
#include "qemu/error-report.h"
19
15
#include "qapi/error.h"
20
ifneq ($(CROSS_CC_HAS_ARMV8_3),)
16
#include "exec/address-spaces.h"
21
pauth-3: CFLAGS += $(CROSS_CC_HAS_ARMV8_3)
17
+#include "sysemu/sysemu.h"
22
+# This test explicitly checks the output of the pauth operation so we
18
#include "hw/arm/arm.h"
23
+# must force the use of the QARMA5 algorithm for it.
19
#include "hw/arm/armsse.h"
24
+run-pauth-3: QEMU_BASE_MACHINE=-M virt -cpu max,pauth-qarma5=on -display none
20
#include "hw/boards.h"
25
else
21
+#include "hw/char/pl011.h"
26
pauth-3:
22
#include "hw/core/split-irq.h"
27
    $(call skip-test, "BUILD of $@", "missing compiler support")
23
#include "hw/misc/tz-mpc.h"
24
#include "hw/misc/tz-ppc.h"
25
@@ -XXX,XX +XXX,XX @@ typedef struct {
26
UnimplementedDeviceState mhu[2];
27
UnimplementedDeviceState pwm[3];
28
UnimplementedDeviceState i2s;
29
- UnimplementedDeviceState uart[2];
30
+ PL011State uart[2];
31
UnimplementedDeviceState i2c[2];
32
UnimplementedDeviceState spi;
33
UnimplementedDeviceState scc;
34
@@ -XXX,XX +XXX,XX @@ static MemoryRegion *make_rtc(MuscaMachineState *mms, void *opaque,
35
return sysbus_mmio_get_region(SYS_BUS_DEVICE(rtc), 0);
36
}
37
38
+static MemoryRegion *make_uart(MuscaMachineState *mms, void *opaque,
39
+ const char *name, hwaddr size)
40
+{
41
+ PL011State *uart = opaque;
42
+ int i = uart - &mms->uart[0];
43
+ int irqbase = 7 + i * 6;
44
+ SysBusDevice *s;
45
+
46
+ sysbus_init_child_obj(OBJECT(mms), name, uart, sizeof(mms->uart[0]),
47
+ TYPE_PL011);
48
+ qdev_prop_set_chr(DEVICE(uart), "chardev", serial_hd(i));
49
+ object_property_set_bool(OBJECT(uart), true, "realized", &error_fatal);
50
+ s = SYS_BUS_DEVICE(uart);
51
+ sysbus_connect_irq(s, 0, get_sse_irq_in(mms, irqbase + 5)); /* combined */
52
+ sysbus_connect_irq(s, 1, get_sse_irq_in(mms, irqbase + 0)); /* RX */
53
+ sysbus_connect_irq(s, 2, get_sse_irq_in(mms, irqbase + 1)); /* TX */
54
+ sysbus_connect_irq(s, 3, get_sse_irq_in(mms, irqbase + 2)); /* RT */
55
+ sysbus_connect_irq(s, 4, get_sse_irq_in(mms, irqbase + 3)); /* MS */
56
+ sysbus_connect_irq(s, 5, get_sse_irq_in(mms, irqbase + 4)); /* E */
57
+ return sysbus_mmio_get_region(SYS_BUS_DEVICE(uart), 0);
58
+}
59
+
60
static MemoryRegion *make_musca_a_devs(MuscaMachineState *mms, void *opaque,
61
const char *name, hwaddr size)
62
{
63
@@ -XXX,XX +XXX,XX @@ static MemoryRegion *make_musca_a_devs(MuscaMachineState *mms, void *opaque,
64
MemoryRegion *container = &mms->container;
65
66
const PPCPortInfo devices[] = {
67
- { "uart0", make_unimp_dev, &mms->uart[0], 0x1000, 0x1000 },
68
- { "uart1", make_unimp_dev, &mms->uart[1], 0x2000, 0x1000 },
69
+ { "uart0", make_uart, &mms->uart[0], 0x1000, 0x1000 },
70
+ { "uart1", make_uart, &mms->uart[1], 0x2000, 0x1000 },
71
{ "spi", make_unimp_dev, &mms->spi, 0x3000, 0x1000 },
72
{ "i2c0", make_unimp_dev, &mms->i2c[0], 0x4000, 0x1000 },
73
{ "i2c1", make_unimp_dev, &mms->i2c[1], 0x5000, 0x1000 },
74
@@ -XXX,XX +XXX,XX @@ static void musca_init(MachineState *machine)
75
{ "pwm1", make_unimp_dev, &mms->pwm[1], 0x40102000, 0x1000 },
76
{ "pwm2", make_unimp_dev, &mms->pwm[2], 0x40103000, 0x1000 },
77
{ "i2s", make_unimp_dev, &mms->i2s, 0x40104000, 0x1000 },
78
- { "uart0", make_unimp_dev, &mms->uart[0], 0x40105000, 0x1000 },
79
- { "uart1", make_unimp_dev, &mms->uart[1], 0x40106000, 0x1000 },
80
+ { "uart0", make_uart, &mms->uart[0], 0x40105000, 0x1000 },
81
+ { "uart1", make_uart, &mms->uart[1], 0x40106000, 0x1000 },
82
{ "i2c0", make_unimp_dev, &mms->i2c[0], 0x40108000, 0x1000 },
83
{ "i2c1", make_unimp_dev, &mms->i2c[1], 0x40109000, 0x1000 },
84
{ "spi", make_unimp_dev, &mms->spi, 0x4010a000, 0x1000 },
85
--
28
--
86
2.20.1
29
2.34.1
87
88
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Pierrick Bouvier <pierrick.bouvier@linaro.org>
2
2
3
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
3
Pointer authentication on aarch64 is pretty expensive (up to 50% of
4
Message-id: 20190215192302.27855-5-richard.henderson@linaro.org
4
execution time) when running a virtual machine with tcg and -cpu max
5
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
5
(which enables pauth=on).
6
[PMM: fixed a couple of comment typos]
6
7
The advice is always: use pauth-impdef=on.
8
Our documentation even mentions it "by default" in
9
docs/system/introduction.rst.
10
11
Thus, we change the default to use impdef by default. This does not
12
affect kvm or hvf acceleration, since pauth algorithm used is the one
13
from host cpu.
14
15
This change is retro compatible, in terms of cli, with previous
16
versions, as the semantic of using -cpu max,pauth-impdef=on, and -cpu
17
max,pauth-qarma3=on is preserved.
18
The new option introduced in previous patch and matching old default is
19
-cpu max,pauth-qarma5=on.
20
It is retro compatible with migration as well, by defining a backcompat
21
property, that will use qarma5 by default for virt machine <= 9.2.
22
Tested by saving and restoring a vm from qemu 9.2.0 into qemu-master
23
(10.0) for cpus neoverse-n2 and max.
24
25
Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
26
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
27
Message-id: 20241219183211.3493974-3-pierrick.bouvier@linaro.org
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
28
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
---
29
---
9
target/arm/cpu.h | 10 +++++
30
docs/system/arm/cpu-features.rst | 2 +-
10
target/arm/helper.h | 3 ++
31
docs/system/introduction.rst | 2 +-
11
target/arm/cpu.c | 1 +
32
target/arm/cpu.h | 3 +++
12
target/arm/cpu64.c | 2 +
33
hw/core/machine.c | 4 +++-
13
target/arm/translate-a64.c | 26 +++++++++++
34
target/arm/cpu.c | 2 ++
14
target/arm/translate.c | 10 +++++
35
target/arm/cpu64.c | 22 ++++++++++++++++------
15
target/arm/vfp_helper.c | 88 ++++++++++++++++++++++++++++++++++++++
36
6 files changed, 26 insertions(+), 9 deletions(-)
16
7 files changed, 140 insertions(+)
17
37
38
diff --git a/docs/system/arm/cpu-features.rst b/docs/system/arm/cpu-features.rst
39
index XXXXXXX..XXXXXXX 100644
40
--- a/docs/system/arm/cpu-features.rst
41
+++ b/docs/system/arm/cpu-features.rst
42
@@ -XXX,XX +XXX,XX @@ Below is the list of TCG VCPU features and their descriptions.
43
When ``pauth`` is enabled, select the architected QARMA5 algorithm.
44
45
Without ``pauth-impdef``, ``pauth-qarma3`` or ``pauth-qarma5`` enabled,
46
-the architected QARMA5 algorithm is used. The architected QARMA5
47
+the QEMU impdef algorithm is used. The architected QARMA5
48
and QARMA3 algorithms have good cryptographic properties, but can
49
be quite slow to emulate. The impdef algorithm used by QEMU is
50
non-cryptographic but significantly faster.
51
diff --git a/docs/system/introduction.rst b/docs/system/introduction.rst
52
index XXXXXXX..XXXXXXX 100644
53
--- a/docs/system/introduction.rst
54
+++ b/docs/system/introduction.rst
55
@@ -XXX,XX +XXX,XX @@ would default to it anyway.
56
57
.. code::
58
59
- -cpu max,pauth-impdef=on \
60
+ -cpu max \
61
-smp 4 \
62
-accel tcg \
63
18
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
64
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
19
index XXXXXXX..XXXXXXX 100644
65
index XXXXXXX..XXXXXXX 100644
20
--- a/target/arm/cpu.h
66
--- a/target/arm/cpu.h
21
+++ b/target/arm/cpu.h
67
+++ b/target/arm/cpu.h
22
@@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa32_vcma(const ARMISARegisters *id)
68
@@ -XXX,XX +XXX,XX @@ struct ArchCPU {
23
return FIELD_EX32(id->id_isar5, ID_ISAR5, VCMA) != 0;
69
/* QOM property to indicate we should use the back-compat CNTFRQ default */
24
}
70
bool backcompat_cntfrq;
25
71
26
+static inline bool isar_feature_aa32_jscvt(const ARMISARegisters *id)
72
+ /* QOM property to indicate we should use the back-compat QARMA5 default */
27
+{
73
+ bool backcompat_pauth_default_use_qarma5;
28
+ return FIELD_EX32(id->id_isar6, ID_ISAR6, JSCVT) != 0;
29
+}
30
+
74
+
31
static inline bool isar_feature_aa32_dp(const ARMISARegisters *id)
75
/* Specify the number of cores in this CPU cluster. Used for the L2CTLR
32
{
76
* register.
33
return FIELD_EX32(id->id_isar6, ID_ISAR6, DP) != 0;
77
*/
34
@@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_dp(const ARMISARegisters *id)
78
diff --git a/hw/core/machine.c b/hw/core/machine.c
35
return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, DP) != 0;
36
}
37
38
+static inline bool isar_feature_aa64_jscvt(const ARMISARegisters *id)
39
+{
40
+ return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, JSCVT) != 0;
41
+}
42
+
43
static inline bool isar_feature_aa64_fcma(const ARMISARegisters *id)
44
{
45
return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, FCMA) != 0;
46
diff --git a/target/arm/helper.h b/target/arm/helper.h
47
index XXXXXXX..XXXXXXX 100644
79
index XXXXXXX..XXXXXXX 100644
48
--- a/target/arm/helper.h
80
--- a/hw/core/machine.c
49
+++ b/target/arm/helper.h
81
+++ b/hw/core/machine.c
50
@@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_2(rintd_exact, TCG_CALL_NO_RWG, f64, f64, ptr)
82
@@ -XXX,XX +XXX,XX @@
51
DEF_HELPER_FLAGS_2(rints, TCG_CALL_NO_RWG, f32, f32, ptr)
83
#include "hw/virtio/virtio-iommu.h"
52
DEF_HELPER_FLAGS_2(rintd, TCG_CALL_NO_RWG, f64, f64, ptr)
84
#include "audio/audio.h"
53
85
54
+DEF_HELPER_FLAGS_2(vjcvt, TCG_CALL_NO_RWG, i32, f64, env)
86
-GlobalProperty hw_compat_9_2[] = {};
55
+DEF_HELPER_FLAGS_2(fjcvtzs, TCG_CALL_NO_RWG, i64, f64, ptr)
87
+GlobalProperty hw_compat_9_2[] = {
56
+
88
+ {"arm-cpu", "backcompat-pauth-default-use-qarma5", "true"},
57
/* neon_helper.c */
89
+};
58
DEF_HELPER_FLAGS_3(neon_qadd_u8, TCG_CALL_NO_RWG, i32, env, i32, i32)
90
const size_t hw_compat_9_2_len = G_N_ELEMENTS(hw_compat_9_2);
59
DEF_HELPER_FLAGS_3(neon_qadd_s8, TCG_CALL_NO_RWG, i32, env, i32, i32)
91
92
GlobalProperty hw_compat_9_1[] = {
60
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
93
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
61
index XXXXXXX..XXXXXXX 100644
94
index XXXXXXX..XXXXXXX 100644
62
--- a/target/arm/cpu.c
95
--- a/target/arm/cpu.c
63
+++ b/target/arm/cpu.c
96
+++ b/target/arm/cpu.c
64
@@ -XXX,XX +XXX,XX @@ static void arm_max_initfn(Object *obj)
97
@@ -XXX,XX +XXX,XX @@ static const Property arm_cpu_properties[] = {
65
cpu->isar.id_isar5 = t;
98
DEFINE_PROP_INT32("core-count", ARMCPU, core_count, -1),
66
99
/* True to default to the backward-compat old CNTFRQ rather than 1Ghz */
67
t = cpu->isar.id_isar6;
100
DEFINE_PROP_BOOL("backcompat-cntfrq", ARMCPU, backcompat_cntfrq, false),
68
+ t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1);
101
+ DEFINE_PROP_BOOL("backcompat-pauth-default-use-qarma5", ARMCPU,
69
t = FIELD_DP32(t, ID_ISAR6, DP, 1);
102
+ backcompat_pauth_default_use_qarma5, false),
70
cpu->isar.id_isar6 = t;
103
};
71
104
105
static const gchar *arm_gdb_arch_name(CPUState *cs)
72
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
106
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
73
index XXXXXXX..XXXXXXX 100644
107
index XXXXXXX..XXXXXXX 100644
74
--- a/target/arm/cpu64.c
108
--- a/target/arm/cpu64.c
75
+++ b/target/arm/cpu64.c
109
+++ b/target/arm/cpu64.c
76
@@ -XXX,XX +XXX,XX @@ static void aarch64_max_initfn(Object *obj)
110
@@ -XXX,XX +XXX,XX @@ void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp)
77
cpu->isar.id_aa64isar0 = t;
111
return;
78
112
}
79
t = cpu->isar.id_aa64isar1;
113
80
+ t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 1);
114
- if (cpu->prop_pauth_impdef) {
81
t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 1);
115
- isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, API, features);
82
t = FIELD_DP64(t, ID_AA64ISAR1, APA, 1); /* PAuth, architected only */
116
- isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, GPI, 1);
83
t = FIELD_DP64(t, ID_AA64ISAR1, API, 0);
117
+ bool use_default = !cpu->prop_pauth_qarma5 &&
84
@@ -XXX,XX +XXX,XX @@ static void aarch64_max_initfn(Object *obj)
118
+ !cpu->prop_pauth_qarma3 &&
85
cpu->isar.id_isar5 = u;
119
+ !cpu->prop_pauth_impdef;
86
87
u = cpu->isar.id_isar6;
88
+ u = FIELD_DP32(u, ID_ISAR6, JSCVT, 1);
89
u = FIELD_DP32(u, ID_ISAR6, DP, 1);
90
cpu->isar.id_isar6 = u;
91
92
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
93
index XXXXXXX..XXXXXXX 100644
94
--- a/target/arm/translate-a64.c
95
+++ b/target/arm/translate-a64.c
96
@@ -XXX,XX +XXX,XX @@ static void handle_fmov(DisasContext *s, int rd, int rn, int type, bool itof)
97
}
98
}
99
100
+static void handle_fjcvtzs(DisasContext *s, int rd, int rn)
101
+{
102
+ TCGv_i64 t = read_fp_dreg(s, rn);
103
+ TCGv_ptr fpstatus = get_fpstatus_ptr(false);
104
+
120
+
105
+ gen_helper_fjcvtzs(t, t, fpstatus);
121
+ if (cpu->prop_pauth_qarma5 ||
106
+
122
+ (use_default &&
107
+ tcg_temp_free_ptr(fpstatus);
123
+ cpu->backcompat_pauth_default_use_qarma5)) {
108
+
124
+ isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, APA, features);
109
+ tcg_gen_ext32u_i64(cpu_reg(s, rd), t);
125
+ isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, GPA, 1);
110
+ tcg_gen_extrh_i64_i32(cpu_ZF, t);
126
} else if (cpu->prop_pauth_qarma3) {
111
+ tcg_gen_movi_i32(cpu_CF, 0);
127
isar2 = FIELD_DP64(isar2, ID_AA64ISAR2, APA3, features);
112
+ tcg_gen_movi_i32(cpu_NF, 0);
128
isar2 = FIELD_DP64(isar2, ID_AA64ISAR2, GPA3, 1);
113
+ tcg_gen_movi_i32(cpu_VF, 0);
129
- } else { /* default is pauth-qarma5 */
114
+
130
- isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, APA, features);
115
+ tcg_temp_free_i64(t);
131
- isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, GPA, 1);
116
+}
132
+ } else if (cpu->prop_pauth_impdef ||
117
+
133
+ (use_default &&
118
/* Floating point <-> integer conversions
134
+ !cpu->backcompat_pauth_default_use_qarma5)) {
119
* 31 30 29 28 24 23 22 21 20 19 18 16 15 10 9 5 4 0
135
+ isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, API, features);
120
* +----+---+---+-----------+------+---+-------+-----+-------------+----+----+
136
+ isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, GPI, 1);
121
@@ -XXX,XX +XXX,XX @@ static void disas_fp_int_conv(DisasContext *s, uint32_t insn)
122
handle_fmov(s, rd, rn, type, itof);
123
break;
124
125
+ case 0b00111110: /* FJCVTZS */
126
+ if (!dc_isar_feature(aa64_jscvt, s)) {
127
+ goto do_unallocated;
128
+ } else if (fp_access_check(s)) {
129
+ handle_fjcvtzs(s, rd, rn);
130
+ }
131
+ break;
132
+
133
default:
134
do_unallocated:
135
unallocated_encoding(s);
136
diff --git a/target/arm/translate.c b/target/arm/translate.c
137
index XXXXXXX..XXXXXXX 100644
138
--- a/target/arm/translate.c
139
+++ b/target/arm/translate.c
140
@@ -XXX,XX +XXX,XX @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
141
rm_is_dp = false;
142
break;
143
144
+ case 0x13: /* vjcvt */
145
+ if (!dp || !dc_isar_feature(aa32_jscvt, s)) {
146
+ return 1;
147
+ }
148
+ rd_is_dp = false;
149
+ break;
150
+
151
default:
152
return 1;
153
}
154
@@ -XXX,XX +XXX,XX @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
155
case 17: /* fsito */
156
gen_vfp_sito(dp, 0);
157
break;
158
+ case 19: /* vjcvt */
159
+ gen_helper_vjcvt(cpu_F0s, cpu_F0d, cpu_env);
160
+ break;
161
case 20: /* fshto */
162
gen_vfp_shto(dp, 16 - rm, 0);
163
break;
164
diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c
165
index XXXXXXX..XXXXXXX 100644
166
--- a/target/arm/vfp_helper.c
167
+++ b/target/arm/vfp_helper.c
168
@@ -XXX,XX +XXX,XX @@ int arm_rmode_to_sf(int rmode)
169
}
170
return rmode;
171
}
172
+
173
+/*
174
+ * Implement float64 to int32_t conversion without saturation;
175
+ * the result is supplied modulo 2^32.
176
+ */
177
+uint64_t HELPER(fjcvtzs)(float64 value, void *vstatus)
178
+{
179
+ float_status *status = vstatus;
180
+ uint32_t exp, sign;
181
+ uint64_t frac;
182
+ uint32_t inexact = 1; /* !Z */
183
+
184
+ sign = extract64(value, 63, 1);
185
+ exp = extract64(value, 52, 11);
186
+ frac = extract64(value, 0, 52);
187
+
188
+ if (exp == 0) {
189
+ /* While not inexact for IEEE FP, -0.0 is inexact for JavaScript. */
190
+ inexact = sign;
191
+ if (frac != 0) {
192
+ if (status->flush_inputs_to_zero) {
193
+ float_raise(float_flag_input_denormal, status);
194
+ } else {
137
+ } else {
195
+ float_raise(float_flag_inexact, status);
138
+ g_assert_not_reached();
196
+ inexact = 1;
139
}
197
+ }
140
} else if (cpu->prop_pauth_impdef ||
198
+ }
141
cpu->prop_pauth_qarma3 ||
199
+ frac = 0;
200
+ } else if (exp == 0x7ff) {
201
+ /* This operation raises Invalid for both NaN and overflow (Inf). */
202
+ float_raise(float_flag_invalid, status);
203
+ frac = 0;
204
+ } else {
205
+ int true_exp = exp - 1023;
206
+ int shift = true_exp - 52;
207
+
208
+ /* Restore implicit bit. */
209
+ frac |= 1ull << 52;
210
+
211
+ /* Shift the fraction into place. */
212
+ if (shift >= 0) {
213
+ /* The number is so large we must shift the fraction left. */
214
+ if (shift >= 64) {
215
+ /* The fraction is shifted out entirely. */
216
+ frac = 0;
217
+ } else {
218
+ frac <<= shift;
219
+ }
220
+ } else if (shift > -64) {
221
+ /* Normal case -- shift right and notice if bits shift out. */
222
+ inexact = (frac << (64 + shift)) != 0;
223
+ frac >>= -shift;
224
+ } else {
225
+ /* The fraction is shifted out entirely. */
226
+ frac = 0;
227
+ }
228
+
229
+ /* Notice overflow or inexact exceptions. */
230
+ if (true_exp > 31 || frac > (sign ? 0x80000000ull : 0x7fffffff)) {
231
+ /* Overflow, for which this operation raises invalid. */
232
+ float_raise(float_flag_invalid, status);
233
+ inexact = 1;
234
+ } else if (inexact) {
235
+ float_raise(float_flag_inexact, status);
236
+ }
237
+
238
+ /* Honor the sign. */
239
+ if (sign) {
240
+ frac = -frac;
241
+ }
242
+ }
243
+
244
+ /* Pack the result and the env->ZF representation of Z together. */
245
+ return deposit64(frac, 32, 32, inexact);
246
+}
247
+
248
+uint32_t HELPER(vjcvt)(float64 value, CPUARMState *env)
249
+{
250
+ uint64_t pair = HELPER(fjcvtzs)(value, &env->vfp.fp_status);
251
+ uint32_t result = pair;
252
+ uint32_t z = (pair >> 32) == 0;
253
+
254
+ /* Store Z, clear NCV, in FPSCR.NZCV. */
255
+ env->vfp.xregs[ARM_VFP_FPSCR]
256
+ = (env->vfp.xregs[ARM_VFP_FPSCR] & ~CPSR_NZCV) | (z * CPSR_Z);
257
+
258
+ return result;
259
+}
260
--
142
--
261
2.20.1
143
2.34.1
262
263
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Pierrick Bouvier <pierrick.bouvier@linaro.org>
2
2
3
For opcodes 0-5, move some if conditions into the structure
3
Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
4
of a switch statement. For opcodes 6 & 7, decode everything
4
Message-id: 20241219183211.3493974-4-pierrick.bouvier@linaro.org
5
at once with a second switch.
5
[PMM: Removed a paragraph about using non-versioned models.]
6
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20190215192302.27855-2-richard.henderson@linaro.org
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
7
---
12
target/arm/translate-a64.c | 94 ++++++++++++++++++++------------------
8
docs/system/arm/virt.rst | 4 ++++
13
1 file changed, 49 insertions(+), 45 deletions(-)
9
1 file changed, 4 insertions(+)
14
10
15
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
11
diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst
16
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/translate-a64.c
13
--- a/docs/system/arm/virt.rst
18
+++ b/target/arm/translate-a64.c
14
+++ b/docs/system/arm/virt.rst
19
@@ -XXX,XX +XXX,XX @@ static void disas_fp_int_conv(DisasContext *s, uint32_t insn)
15
@@ -XXX,XX +XXX,XX @@ of the 5.0 release and ``virt-5.0`` of the 5.1 release. Migration
20
int type = extract32(insn, 22, 2);
16
is not guaranteed to work between different QEMU releases for
21
bool sbit = extract32(insn, 29, 1);
17
the non-versioned ``virt`` machine type.
22
bool sf = extract32(insn, 31, 1);
18
23
+ bool itof = false;
19
+VM migration is not guaranteed when using ``-cpu max``, as features
24
20
+supported may change between QEMU versions. To ensure your VM can be
25
if (sbit) {
21
+migrated, it is recommended to use another cpu model instead.
26
- unallocated_encoding(s);
27
- return;
28
+ goto do_unallocated;
29
}
30
31
- if (opcode > 5) {
32
- /* FMOV */
33
- bool itof = opcode & 1;
34
-
35
- if (rmode >= 2) {
36
- unallocated_encoding(s);
37
- return;
38
- }
39
-
40
- switch (sf << 3 | type << 1 | rmode) {
41
- case 0x0: /* 32 bit */
42
- case 0xa: /* 64 bit */
43
- case 0xd: /* 64 bit to top half of quad */
44
- break;
45
- case 0x6: /* 16-bit float, 32-bit int */
46
- case 0xe: /* 16-bit float, 64-bit int */
47
- if (dc_isar_feature(aa64_fp16, s)) {
48
- break;
49
- }
50
- /* fallthru */
51
- default:
52
- /* all other sf/type/rmode combinations are invalid */
53
- unallocated_encoding(s);
54
- return;
55
- }
56
-
57
- if (!fp_access_check(s)) {
58
- return;
59
- }
60
- handle_fmov(s, rd, rn, type, itof);
61
- } else {
62
- /* actual FP conversions */
63
- bool itof = extract32(opcode, 1, 1);
64
-
65
- if (rmode != 0 && opcode > 1) {
66
- unallocated_encoding(s);
67
- return;
68
+ switch (opcode) {
69
+ case 2: /* SCVTF */
70
+ case 3: /* UCVTF */
71
+ itof = true;
72
+ /* fallthru */
73
+ case 4: /* FCVTAS */
74
+ case 5: /* FCVTAU */
75
+ if (rmode != 0) {
76
+ goto do_unallocated;
77
}
78
+ /* fallthru */
79
+ case 0: /* FCVT[NPMZ]S */
80
+ case 1: /* FCVT[NPMZ]U */
81
switch (type) {
82
case 0: /* float32 */
83
case 1: /* float64 */
84
break;
85
case 3: /* float16 */
86
- if (dc_isar_feature(aa64_fp16, s)) {
87
- break;
88
+ if (!dc_isar_feature(aa64_fp16, s)) {
89
+ goto do_unallocated;
90
}
91
- /* fallthru */
92
+ break;
93
default:
94
- unallocated_encoding(s);
95
- return;
96
+ goto do_unallocated;
97
}
98
-
99
if (!fp_access_check(s)) {
100
return;
101
}
102
handle_fpfpcvt(s, rd, rn, opcode, itof, rmode, 64, sf, type);
103
+ break;
104
+
22
+
105
+ default:
23
Supported devices
106
+ switch (sf << 7 | type << 5 | rmode << 3 | opcode) {
24
"""""""""""""""""
107
+ case 0b01100110: /* FMOV half <-> 32-bit int */
108
+ case 0b01100111:
109
+ case 0b11100110: /* FMOV half <-> 64-bit int */
110
+ case 0b11100111:
111
+ if (!dc_isar_feature(aa64_fp16, s)) {
112
+ goto do_unallocated;
113
+ }
114
+ /* fallthru */
115
+ case 0b00000110: /* FMOV 32-bit */
116
+ case 0b00000111:
117
+ case 0b10100110: /* FMOV 64-bit */
118
+ case 0b10100111:
119
+ case 0b11001110: /* FMOV top half of 128-bit */
120
+ case 0b11001111:
121
+ if (!fp_access_check(s)) {
122
+ return;
123
+ }
124
+ itof = opcode & 1;
125
+ handle_fmov(s, rd, rn, type, itof);
126
+ break;
127
+
128
+ default:
129
+ do_unallocated:
130
+ unallocated_encoding(s);
131
+ return;
132
+ }
133
+ break;
134
}
135
}
136
25
137
--
26
--
138
2.20.1
27
2.34.1
139
140
diff view generated by jsdifflib
Deleted patch
1
Create a new include file for the pl031's device struct,
2
type macros, etc, so that it can be instantiated using
3
the "embedded struct" coding style.
4
1
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
---
9
include/hw/timer/pl031.h | 44 ++++++++++++++++++++++++++++++++++++++++
10
hw/timer/pl031.c | 25 +----------------------
11
MAINTAINERS | 1 +
12
3 files changed, 46 insertions(+), 24 deletions(-)
13
create mode 100644 include/hw/timer/pl031.h
14
15
diff --git a/include/hw/timer/pl031.h b/include/hw/timer/pl031.h
16
new file mode 100644
17
index XXXXXXX..XXXXXXX
18
--- /dev/null
19
+++ b/include/hw/timer/pl031.h
20
@@ -XXX,XX +XXX,XX @@
21
+/*
22
+ * ARM AMBA PrimeCell PL031 RTC
23
+ *
24
+ * Copyright (c) 2007 CodeSourcery
25
+ *
26
+ * This file is free software; you can redistribute it and/or modify
27
+ * it under the terms of the GNU General Public License version 2 as
28
+ * published by the Free Software Foundation.
29
+ *
30
+ * Contributions after 2012-01-13 are licensed under the terms of the
31
+ * GNU GPL, version 2 or (at your option) any later version.
32
+ */
33
+
34
+#ifndef HW_TIMER_PL031
35
+#define HW_TIMER_PL031
36
+
37
+#include "hw/sysbus.h"
38
+
39
+#define TYPE_PL031 "pl031"
40
+#define PL031(obj) OBJECT_CHECK(PL031State, (obj), TYPE_PL031)
41
+
42
+typedef struct PL031State {
43
+ SysBusDevice parent_obj;
44
+
45
+ MemoryRegion iomem;
46
+ QEMUTimer *timer;
47
+ qemu_irq irq;
48
+
49
+ /*
50
+ * Needed to preserve the tick_count across migration, even if the
51
+ * absolute value of the rtc_clock is different on the source and
52
+ * destination.
53
+ */
54
+ uint32_t tick_offset_vmstate;
55
+ uint32_t tick_offset;
56
+
57
+ uint32_t mr;
58
+ uint32_t lr;
59
+ uint32_t cr;
60
+ uint32_t im;
61
+ uint32_t is;
62
+} PL031State;
63
+
64
+#endif
65
diff --git a/hw/timer/pl031.c b/hw/timer/pl031.c
66
index XXXXXXX..XXXXXXX 100644
67
--- a/hw/timer/pl031.c
68
+++ b/hw/timer/pl031.c
69
@@ -XXX,XX +XXX,XX @@
70
*/
71
72
#include "qemu/osdep.h"
73
+#include "hw/timer/pl031.h"
74
#include "hw/sysbus.h"
75
#include "qemu/timer.h"
76
#include "sysemu/sysemu.h"
77
@@ -XXX,XX +XXX,XX @@ do { printf("pl031: " fmt , ## __VA_ARGS__); } while (0)
78
#define RTC_MIS 0x18 /* Masked interrupt status register */
79
#define RTC_ICR 0x1c /* Interrupt clear register */
80
81
-#define TYPE_PL031 "pl031"
82
-#define PL031(obj) OBJECT_CHECK(PL031State, (obj), TYPE_PL031)
83
-
84
-typedef struct PL031State {
85
- SysBusDevice parent_obj;
86
-
87
- MemoryRegion iomem;
88
- QEMUTimer *timer;
89
- qemu_irq irq;
90
-
91
- /* Needed to preserve the tick_count across migration, even if the
92
- * absolute value of the rtc_clock is different on the source and
93
- * destination.
94
- */
95
- uint32_t tick_offset_vmstate;
96
- uint32_t tick_offset;
97
-
98
- uint32_t mr;
99
- uint32_t lr;
100
- uint32_t cr;
101
- uint32_t im;
102
- uint32_t is;
103
-} PL031State;
104
-
105
static const unsigned char pl031_id[] = {
106
0x31, 0x10, 0x14, 0x00, /* Device ID */
107
0x0d, 0xf0, 0x05, 0xb1 /* Cell ID */
108
diff --git a/MAINTAINERS b/MAINTAINERS
109
index XXXXXXX..XXXXXXX 100644
110
--- a/MAINTAINERS
111
+++ b/MAINTAINERS
112
@@ -XXX,XX +XXX,XX @@ F: hw/sd/pl181.c
113
F: hw/ssi/pl022.c
114
F: include/hw/ssi/pl022.h
115
F: hw/timer/pl031.c
116
+F: include/hw/timer/pl031.h
117
F: include/hw/arm/primecell.h
118
F: hw/timer/cmsdk-apb-timer.c
119
F: include/hw/timer/cmsdk-apb-timer.h
120
--
121
2.20.1
122
123
diff view generated by jsdifflib
Deleted patch
1
Convert the debug printing in the PL031 device to use trace events,
2
and augment it to cover the interesting parts of device operation.
3
1
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
---
8
hw/timer/pl031.c | 55 +++++++++++++++++++++++--------------------
9
hw/timer/trace-events | 6 +++++
10
2 files changed, 36 insertions(+), 25 deletions(-)
11
12
diff --git a/hw/timer/pl031.c b/hw/timer/pl031.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/timer/pl031.c
15
+++ b/hw/timer/pl031.c
16
@@ -XXX,XX +XXX,XX @@
17
#include "sysemu/sysemu.h"
18
#include "qemu/cutils.h"
19
#include "qemu/log.h"
20
-
21
-//#define DEBUG_PL031
22
-
23
-#ifdef DEBUG_PL031
24
-#define DPRINTF(fmt, ...) \
25
-do { printf("pl031: " fmt , ## __VA_ARGS__); } while (0)
26
-#else
27
-#define DPRINTF(fmt, ...) do {} while(0)
28
-#endif
29
+#include "trace.h"
30
31
#define RTC_DR 0x00 /* Data read register */
32
#define RTC_MR 0x04 /* Match register */
33
@@ -XXX,XX +XXX,XX @@ static const unsigned char pl031_id[] = {
34
35
static void pl031_update(PL031State *s)
36
{
37
- qemu_set_irq(s->irq, s->is & s->im);
38
+ uint32_t flags = s->is & s->im;
39
+
40
+ trace_pl031_irq_state(flags);
41
+ qemu_set_irq(s->irq, flags);
42
}
43
44
static void pl031_interrupt(void * opaque)
45
@@ -XXX,XX +XXX,XX @@ static void pl031_interrupt(void * opaque)
46
PL031State *s = (PL031State *)opaque;
47
48
s->is = 1;
49
- DPRINTF("Alarm raised\n");
50
+ trace_pl031_alarm_raised();
51
pl031_update(s);
52
}
53
54
@@ -XXX,XX +XXX,XX @@ static void pl031_set_alarm(PL031State *s)
55
/* The timer wraps around. This subtraction also wraps in the same way,
56
and gives correct results when alarm < now_ticks. */
57
ticks = s->mr - pl031_get_count(s);
58
- DPRINTF("Alarm set in %ud ticks\n", ticks);
59
+ trace_pl031_set_alarm(ticks);
60
if (ticks == 0) {
61
timer_del(s->timer);
62
pl031_interrupt(s);
63
@@ -XXX,XX +XXX,XX @@ static uint64_t pl031_read(void *opaque, hwaddr offset,
64
unsigned size)
65
{
66
PL031State *s = (PL031State *)opaque;
67
-
68
- if (offset >= 0xfe0 && offset < 0x1000)
69
- return pl031_id[(offset - 0xfe0) >> 2];
70
+ uint64_t r;
71
72
switch (offset) {
73
case RTC_DR:
74
- return pl031_get_count(s);
75
+ r = pl031_get_count(s);
76
+ break;
77
case RTC_MR:
78
- return s->mr;
79
+ r = s->mr;
80
+ break;
81
case RTC_IMSC:
82
- return s->im;
83
+ r = s->im;
84
+ break;
85
case RTC_RIS:
86
- return s->is;
87
+ r = s->is;
88
+ break;
89
case RTC_LR:
90
- return s->lr;
91
+ r = s->lr;
92
+ break;
93
case RTC_CR:
94
/* RTC is permanently enabled. */
95
- return 1;
96
+ r = 1;
97
+ break;
98
case RTC_MIS:
99
- return s->is & s->im;
100
+ r = s->is & s->im;
101
+ break;
102
+ case 0xfe0 ... 0xfff:
103
+ r = pl031_id[(offset - 0xfe0) >> 2];
104
+ break;
105
case RTC_ICR:
106
qemu_log_mask(LOG_GUEST_ERROR,
107
"pl031: read of write-only register at offset 0x%x\n",
108
(int)offset);
109
+ r = 0;
110
break;
111
default:
112
qemu_log_mask(LOG_GUEST_ERROR,
113
"pl031_read: Bad offset 0x%x\n", (int)offset);
114
+ r = 0;
115
break;
116
}
117
118
- return 0;
119
+ trace_pl031_read(offset, r);
120
+ return r;
121
}
122
123
static void pl031_write(void * opaque, hwaddr offset,
124
@@ -XXX,XX +XXX,XX @@ static void pl031_write(void * opaque, hwaddr offset,
125
{
126
PL031State *s = (PL031State *)opaque;
127
128
+ trace_pl031_write(offset, value);
129
130
switch (offset) {
131
case RTC_LR:
132
@@ -XXX,XX +XXX,XX @@ static void pl031_write(void * opaque, hwaddr offset,
133
break;
134
case RTC_IMSC:
135
s->im = value & 1;
136
- DPRINTF("Interrupt mask %d\n", s->im);
137
pl031_update(s);
138
break;
139
case RTC_ICR:
140
@@ -XXX,XX +XXX,XX @@ static void pl031_write(void * opaque, hwaddr offset,
141
cleared when bit 0 of the written value is set. However the
142
arm926e documentation (DDI0287B) states that the interrupt is
143
cleared when any value is written. */
144
- DPRINTF("Interrupt cleared");
145
s->is = 0;
146
pl031_update(s);
147
break;
148
diff --git a/hw/timer/trace-events b/hw/timer/trace-events
149
index XXXXXXX..XXXXXXX 100644
150
--- a/hw/timer/trace-events
151
+++ b/hw/timer/trace-events
152
@@ -XXX,XX +XXX,XX @@ xlnx_zynqmp_rtc_gettime(int year, int month, int day, int hour, int min, int sec
153
nrf51_timer_read(uint64_t addr, uint32_t value, unsigned size) "read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
154
nrf51_timer_write(uint64_t addr, uint32_t value, unsigned size) "write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
155
156
+# hw/timer/pl031.c
157
+pl031_irq_state(int level) "irq state %d"
158
+pl031_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
159
+pl031_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
160
+pl031_alarm_raised(void) "alarm raised"
161
+pl031_set_alarm(uint32_t ticks) "alarm set for %u ticks"
162
--
163
2.20.1
164
165
diff view generated by jsdifflib
Deleted patch
1
The PL011 UART has six interrupt lines:
2
* RX (receive data)
3
* TX (transmit data)
4
* RT (receive timeout)
5
* MS (modem status)
6
* E (errors)
7
* combined (logical OR of all the above)
8
1
9
So far we have only emulated the combined interrupt line;
10
add support for the others, so that boards that wire them
11
up to different interrupt controller inputs can do so.
12
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
15
---
16
include/hw/char/pl011.h | 2 +-
17
hw/char/pl011.c | 46 +++++++++++++++++++++++++++++++++++++++--
18
2 files changed, 45 insertions(+), 3 deletions(-)
19
20
diff --git a/include/hw/char/pl011.h b/include/hw/char/pl011.h
21
index XXXXXXX..XXXXXXX 100644
22
--- a/include/hw/char/pl011.h
23
+++ b/include/hw/char/pl011.h
24
@@ -XXX,XX +XXX,XX @@ typedef struct PL011State {
25
int read_count;
26
int read_trigger;
27
CharBackend chr;
28
- qemu_irq irq;
29
+ qemu_irq irq[6];
30
const unsigned char *id;
31
} PL011State;
32
33
diff --git a/hw/char/pl011.c b/hw/char/pl011.c
34
index XXXXXXX..XXXXXXX 100644
35
--- a/hw/char/pl011.c
36
+++ b/hw/char/pl011.c
37
@@ -XXX,XX +XXX,XX @@
38
* This code is licensed under the GPL.
39
*/
40
41
+/*
42
+ * QEMU interface:
43
+ * + sysbus MMIO region 0: device registers
44
+ * + sysbus IRQ 0: UARTINTR (combined interrupt line)
45
+ * + sysbus IRQ 1: UARTRXINTR (receive FIFO interrupt line)
46
+ * + sysbus IRQ 2: UARTTXINTR (transmit FIFO interrupt line)
47
+ * + sysbus IRQ 3: UARTRTINTR (receive timeout interrupt line)
48
+ * + sysbus IRQ 4: UARTMSINTR (momem status interrupt line)
49
+ * + sysbus IRQ 5: UARTEINTR (error interrupt line)
50
+ */
51
+
52
#include "qemu/osdep.h"
53
#include "hw/char/pl011.h"
54
#include "hw/sysbus.h"
55
@@ -XXX,XX +XXX,XX @@
56
#define PL011_FLAG_TXFF 0x20
57
#define PL011_FLAG_RXFE 0x10
58
59
+/* Interrupt status bits in UARTRIS, UARTMIS, UARTIMSC */
60
+#define INT_OE (1 << 10)
61
+#define INT_BE (1 << 9)
62
+#define INT_PE (1 << 8)
63
+#define INT_FE (1 << 7)
64
+#define INT_RT (1 << 6)
65
+#define INT_TX (1 << 5)
66
+#define INT_RX (1 << 4)
67
+#define INT_DSR (1 << 3)
68
+#define INT_DCD (1 << 2)
69
+#define INT_CTS (1 << 1)
70
+#define INT_RI (1 << 0)
71
+#define INT_E (INT_OE | INT_BE | INT_PE | INT_FE)
72
+#define INT_MS (INT_RI | INT_DSR | INT_DCD | INT_CTS)
73
+
74
static const unsigned char pl011_id_arm[8] =
75
{ 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
76
static const unsigned char pl011_id_luminary[8] =
77
{ 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
78
79
+/* Which bits in the interrupt status matter for each outbound IRQ line ? */
80
+static const uint32_t irqmask[] = {
81
+ INT_E | INT_MS | INT_RT | INT_TX | INT_RX, /* combined IRQ */
82
+ INT_RX,
83
+ INT_TX,
84
+ INT_RT,
85
+ INT_MS,
86
+ INT_E,
87
+};
88
+
89
static void pl011_update(PL011State *s)
90
{
91
uint32_t flags;
92
+ int i;
93
94
flags = s->int_level & s->int_enabled;
95
trace_pl011_irq_state(flags != 0);
96
- qemu_set_irq(s->irq, flags != 0);
97
+ for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
98
+ qemu_set_irq(s->irq[i], (flags & irqmask[i]) != 0);
99
+ }
100
}
101
102
static uint64_t pl011_read(void *opaque, hwaddr offset,
103
@@ -XXX,XX +XXX,XX @@ static void pl011_init(Object *obj)
104
{
105
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
106
PL011State *s = PL011(obj);
107
+ int i;
108
109
memory_region_init_io(&s->iomem, OBJECT(s), &pl011_ops, s, "pl011", 0x1000);
110
sysbus_init_mmio(sbd, &s->iomem);
111
- sysbus_init_irq(sbd, &s->irq);
112
+ for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
113
+ sysbus_init_irq(sbd, &s->irq[i]);
114
+ }
115
116
s->read_trigger = 1;
117
s->ifl = 0x12;
118
--
119
2.20.1
120
121
diff view generated by jsdifflib
Deleted patch
1
The pl011 logs when the guest makes a bad access. It prints
2
the address offset in hex but confusingly omits the '0x'
3
prefix; add it.
4
1
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
---
9
hw/char/pl011.c | 4 ++--
10
1 file changed, 2 insertions(+), 2 deletions(-)
11
12
diff --git a/hw/char/pl011.c b/hw/char/pl011.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/char/pl011.c
15
+++ b/hw/char/pl011.c
16
@@ -XXX,XX +XXX,XX @@ static uint64_t pl011_read(void *opaque, hwaddr offset,
17
break;
18
default:
19
qemu_log_mask(LOG_GUEST_ERROR,
20
- "pl011_read: Bad offset %x\n", (int)offset);
21
+ "pl011_read: Bad offset 0x%x\n", (int)offset);
22
r = 0;
23
break;
24
}
25
@@ -XXX,XX +XXX,XX @@ static void pl011_write(void *opaque, hwaddr offset,
26
break;
27
default:
28
qemu_log_mask(LOG_GUEST_ERROR,
29
- "pl011_write: Bad offset %x\n", (int)offset);
30
+ "pl011_write: Bad offset 0x%x\n", (int)offset);
31
}
32
}
33
34
--
35
2.20.1
36
37
diff view generated by jsdifflib
Deleted patch
1
In commit 4b635cf7a95e501211 we added a QOM property to the ARMSSE
2
object, but forgot to add it to the documentation comment in the
3
header. Correct the omission.
4
1
5
Fixes: 4b635cf7a95e501211 ("hw/arm/armsse: Make SRAM bank size configurable")
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
---
9
include/hw/arm/armsse.h | 2 ++
10
1 file changed, 2 insertions(+)
11
12
diff --git a/include/hw/arm/armsse.h b/include/hw/arm/armsse.h
13
index XXXXXXX..XXXXXXX 100644
14
--- a/include/hw/arm/armsse.h
15
+++ b/include/hw/arm/armsse.h
16
@@ -XXX,XX +XXX,XX @@
17
* being the same for both, to avoid having to have separate Property
18
* lists for different variants. This restriction can be relaxed later
19
* if necessary.)
20
+ * + QOM property "SRAM_ADDR_WIDTH" sets the number of bits used for the
21
+ * address of each SRAM bank (and thus the total amount of internal SRAM)
22
* + Named GPIO inputs "EXP_IRQ" 0..n are the expansion interrupts for CPU 0,
23
* which are wired to its NVIC lines 32 .. n+32
24
* + Named GPIO inputs "EXP_CPU1_IRQ" 0..n are the expansion interrupts for
25
--
26
2.20.1
27
28
diff view generated by jsdifflib
Deleted patch
1
The Musca-A and Musca-B1 development boards are based on the
2
SSE-200 subsystem for embedded. Implement an initial skeleton
3
model of these boards, which are similar but not identical.
4
1
5
This commit creates the board model with the SSE and the IRQ
6
splitters to wire IRQs up to its two CPUs. As yet there
7
are no devices and no memory: these will be added later.
8
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
11
---
12
hw/arm/Makefile.objs | 1 +
13
hw/arm/musca.c | 197 ++++++++++++++++++++++++++++++++
14
MAINTAINERS | 6 +
15
default-configs/arm-softmmu.mak | 1 +
16
4 files changed, 205 insertions(+)
17
create mode 100644 hw/arm/musca.c
18
19
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
20
index XXXXXXX..XXXXXXX 100644
21
--- a/hw/arm/Makefile.objs
22
+++ b/hw/arm/Makefile.objs
23
@@ -XXX,XX +XXX,XX @@ obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o
24
obj-$(CONFIG_MPS2) += mps2.o
25
obj-$(CONFIG_MPS2) += mps2-tz.o
26
obj-$(CONFIG_MSF2) += msf2-soc.o msf2-som.o
27
+obj-$(CONFIG_MUSCA) += musca.o
28
obj-$(CONFIG_ARMSSE) += armsse.o
29
obj-$(CONFIG_FSL_IMX7) += fsl-imx7.o mcimx7d-sabre.o
30
obj-$(CONFIG_ARM_SMMUV3) += smmu-common.o smmuv3.o
31
diff --git a/hw/arm/musca.c b/hw/arm/musca.c
32
new file mode 100644
33
index XXXXXXX..XXXXXXX
34
--- /dev/null
35
+++ b/hw/arm/musca.c
36
@@ -XXX,XX +XXX,XX @@
37
+/*
38
+ * Arm Musca-B1 test chip board emulation
39
+ *
40
+ * Copyright (c) 2019 Linaro Limited
41
+ * Written by Peter Maydell
42
+ *
43
+ * This program is free software; you can redistribute it and/or modify
44
+ * it under the terms of the GNU General Public License version 2 or
45
+ * (at your option) any later version.
46
+ */
47
+
48
+/*
49
+ * The Musca boards are a reference implementation of a system using
50
+ * the SSE-200 subsystem for embedded:
51
+ * https://developer.arm.com/products/system-design/development-boards/iot-test-chips-and-boards/musca-a-test-chip-board
52
+ * https://developer.arm.com/products/system-design/development-boards/iot-test-chips-and-boards/musca-b-test-chip-board
53
+ * We model the A and B1 variants of this board, as described in the TRMs:
54
+ * http://infocenter.arm.com/help/topic/com.arm.doc.101107_0000_00_en/index.html
55
+ * http://infocenter.arm.com/help/topic/com.arm.doc.101312_0000_00_en/index.html
56
+ */
57
+
58
+#include "qemu/osdep.h"
59
+#include "qemu/error-report.h"
60
+#include "qapi/error.h"
61
+#include "exec/address-spaces.h"
62
+#include "hw/arm/arm.h"
63
+#include "hw/arm/armsse.h"
64
+#include "hw/boards.h"
65
+#include "hw/core/split-irq.h"
66
+
67
+#define MUSCA_NUMIRQ_MAX 96
68
+
69
+typedef enum MuscaType {
70
+ MUSCA_A,
71
+ MUSCA_B1,
72
+} MuscaType;
73
+
74
+typedef struct {
75
+ MachineClass parent;
76
+ MuscaType type;
77
+ uint32_t init_svtor;
78
+ int sram_addr_width;
79
+ int num_irqs;
80
+} MuscaMachineClass;
81
+
82
+typedef struct {
83
+ MachineState parent;
84
+
85
+ ARMSSE sse;
86
+ SplitIRQ cpu_irq_splitter[MUSCA_NUMIRQ_MAX];
87
+} MuscaMachineState;
88
+
89
+#define TYPE_MUSCA_MACHINE "musca"
90
+#define TYPE_MUSCA_A_MACHINE MACHINE_TYPE_NAME("musca-a")
91
+#define TYPE_MUSCA_B1_MACHINE MACHINE_TYPE_NAME("musca-b1")
92
+
93
+#define MUSCA_MACHINE(obj) \
94
+ OBJECT_CHECK(MuscaMachineState, obj, TYPE_MUSCA_MACHINE)
95
+#define MUSCA_MACHINE_GET_CLASS(obj) \
96
+ OBJECT_GET_CLASS(MuscaMachineClass, obj, TYPE_MUSCA_MACHINE)
97
+#define MUSCA_MACHINE_CLASS(klass) \
98
+ OBJECT_CLASS_CHECK(MuscaMachineClass, klass, TYPE_MUSCA_MACHINE)
99
+
100
+/*
101
+ * Main SYSCLK frequency in Hz
102
+ * TODO this should really be different for the two cores, but we
103
+ * don't model that in our SSE-200 model yet.
104
+ */
105
+#define SYSCLK_FRQ 40000000
106
+
107
+static void musca_init(MachineState *machine)
108
+{
109
+ MuscaMachineState *mms = MUSCA_MACHINE(machine);
110
+ MuscaMachineClass *mmc = MUSCA_MACHINE_GET_CLASS(mms);
111
+ MachineClass *mc = MACHINE_GET_CLASS(machine);
112
+ MemoryRegion *system_memory = get_system_memory();
113
+ DeviceState *ssedev;
114
+ int i;
115
+
116
+ assert(mmc->num_irqs <= MUSCA_NUMIRQ_MAX);
117
+
118
+ if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) {
119
+ error_report("This board can only be used with CPU %s",
120
+ mc->default_cpu_type);
121
+ exit(1);
122
+ }
123
+
124
+ sysbus_init_child_obj(OBJECT(machine), "sse-200", &mms->sse,
125
+ sizeof(mms->sse), TYPE_SSE200);
126
+ ssedev = DEVICE(&mms->sse);
127
+ object_property_set_link(OBJECT(&mms->sse), OBJECT(system_memory),
128
+ "memory", &error_fatal);
129
+ qdev_prop_set_uint32(ssedev, "EXP_NUMIRQ", mmc->num_irqs);
130
+ qdev_prop_set_uint32(ssedev, "init-svtor", mmc->init_svtor);
131
+ qdev_prop_set_uint32(ssedev, "SRAM_ADDR_WIDTH", mmc->sram_addr_width);
132
+ qdev_prop_set_uint32(ssedev, "MAINCLK", SYSCLK_FRQ);
133
+ object_property_set_bool(OBJECT(&mms->sse), true, "realized",
134
+ &error_fatal);
135
+
136
+ /*
137
+ * We need to create splitters to feed the IRQ inputs
138
+ * for each CPU in the SSE-200 from each device in the board.
139
+ */
140
+ for (i = 0; i < mmc->num_irqs; i++) {
141
+ char *name = g_strdup_printf("musca-irq-splitter%d", i);
142
+ SplitIRQ *splitter = &mms->cpu_irq_splitter[i];
143
+
144
+ object_initialize_child(OBJECT(machine), name,
145
+ splitter, sizeof(*splitter),
146
+ TYPE_SPLIT_IRQ, &error_fatal, NULL);
147
+ g_free(name);
148
+
149
+ object_property_set_int(OBJECT(splitter), 2, "num-lines",
150
+ &error_fatal);
151
+ object_property_set_bool(OBJECT(splitter), true, "realized",
152
+ &error_fatal);
153
+ qdev_connect_gpio_out(DEVICE(splitter), 0,
154
+ qdev_get_gpio_in_named(ssedev, "EXP_IRQ", i));
155
+ qdev_connect_gpio_out(DEVICE(splitter), 1,
156
+ qdev_get_gpio_in_named(ssedev,
157
+ "EXP_CPU1_IRQ", i));
158
+ }
159
+
160
+ armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, 0x2000000);
161
+}
162
+
163
+static void musca_class_init(ObjectClass *oc, void *data)
164
+{
165
+ MachineClass *mc = MACHINE_CLASS(oc);
166
+
167
+ mc->default_cpus = 2;
168
+ mc->min_cpus = mc->default_cpus;
169
+ mc->max_cpus = mc->default_cpus;
170
+ mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m33");
171
+ mc->init = musca_init;
172
+}
173
+
174
+static void musca_a_class_init(ObjectClass *oc, void *data)
175
+{
176
+ MachineClass *mc = MACHINE_CLASS(oc);
177
+ MuscaMachineClass *mmc = MUSCA_MACHINE_CLASS(oc);
178
+
179
+ mc->desc = "ARM Musca-A board (dual Cortex-M33)";
180
+ mmc->type = MUSCA_A;
181
+ mmc->init_svtor = 0x10200000;
182
+ mmc->sram_addr_width = 15;
183
+ mmc->num_irqs = 64;
184
+}
185
+
186
+static void musca_b1_class_init(ObjectClass *oc, void *data)
187
+{
188
+ MachineClass *mc = MACHINE_CLASS(oc);
189
+ MuscaMachineClass *mmc = MUSCA_MACHINE_CLASS(oc);
190
+
191
+ mc->desc = "ARM Musca-B1 board (dual Cortex-M33)";
192
+ mmc->type = MUSCA_B1;
193
+ /*
194
+ * This matches the DAPlink firmware which boots from QSPI. There
195
+ * is also a firmware blob which boots from the eFlash, which
196
+ * uses init_svtor = 0x1A000000. QEMU doesn't currently support that,
197
+ * though we could in theory expose a machine property on the command
198
+ * line to allow the user to request eFlash boot.
199
+ */
200
+ mmc->init_svtor = 0x10000000;
201
+ mmc->sram_addr_width = 17;
202
+ mmc->num_irqs = 96;
203
+}
204
+
205
+static const TypeInfo musca_info = {
206
+ .name = TYPE_MUSCA_MACHINE,
207
+ .parent = TYPE_MACHINE,
208
+ .abstract = true,
209
+ .instance_size = sizeof(MuscaMachineState),
210
+ .class_size = sizeof(MuscaMachineClass),
211
+ .class_init = musca_class_init,
212
+};
213
+
214
+static const TypeInfo musca_a_info = {
215
+ .name = TYPE_MUSCA_A_MACHINE,
216
+ .parent = TYPE_MUSCA_MACHINE,
217
+ .class_init = musca_a_class_init,
218
+};
219
+
220
+static const TypeInfo musca_b1_info = {
221
+ .name = TYPE_MUSCA_B1_MACHINE,
222
+ .parent = TYPE_MUSCA_MACHINE,
223
+ .class_init = musca_b1_class_init,
224
+};
225
+
226
+static void musca_machine_init(void)
227
+{
228
+ type_register_static(&musca_info);
229
+ type_register_static(&musca_a_info);
230
+ type_register_static(&musca_b1_info);
231
+}
232
+
233
+type_init(musca_machine_init);
234
diff --git a/MAINTAINERS b/MAINTAINERS
235
index XXXXXXX..XXXXXXX 100644
236
--- a/MAINTAINERS
237
+++ b/MAINTAINERS
238
@@ -XXX,XX +XXX,XX @@ F: include/hw/misc/iotkit-sysinfo.h
239
F: hw/misc/armsse-cpuid.c
240
F: include/hw/misc/armsse-cpuid.h
241
242
+Musca
243
+M: Peter Maydell <peter.maydell@linaro.org>
244
+L: qemu-arm@nongnu.org
245
+S: Maintained
246
+F: hw/arm/musca.c
247
+
248
Musicpal
249
M: Jan Kiszka <jan.kiszka@web.de>
250
M: Peter Maydell <peter.maydell@linaro.org>
251
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
252
index XXXXXXX..XXXXXXX 100644
253
--- a/default-configs/arm-softmmu.mak
254
+++ b/default-configs/arm-softmmu.mak
255
@@ -XXX,XX +XXX,XX @@ CONFIG_TUSB6010=y
256
CONFIG_IMX=y
257
CONFIG_MAINSTONE=y
258
CONFIG_MPS2=y
259
+CONFIG_MUSCA=y
260
CONFIG_NSERIES=y
261
CONFIG_RASPI=y
262
CONFIG_REALVIEW=y
263
--
264
2.20.1
265
266
diff view generated by jsdifflib
Deleted patch
1
Many of the devices on the Musca board live behind TrustZone
2
Peripheral Protection Controllers (PPCs); add models of the
3
PPCs, using a similar scheme to the MPS2 board models.
4
This commit wires up the PPCs with "unimplemented device"
5
stubs behind them in the correct places in the address map.
6
1
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
---
10
hw/arm/musca.c | 289 +++++++++++++++++++++++++++++++++++++++++++++++++
11
1 file changed, 289 insertions(+)
12
13
diff --git a/hw/arm/musca.c b/hw/arm/musca.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/arm/musca.c
16
+++ b/hw/arm/musca.c
17
@@ -XXX,XX +XXX,XX @@
18
#include "hw/arm/armsse.h"
19
#include "hw/boards.h"
20
#include "hw/core/split-irq.h"
21
+#include "hw/misc/tz-ppc.h"
22
+#include "hw/misc/unimp.h"
23
24
#define MUSCA_NUMIRQ_MAX 96
25
+#define MUSCA_PPC_MAX 3
26
27
typedef enum MuscaType {
28
MUSCA_A,
29
@@ -XXX,XX +XXX,XX @@ typedef struct {
30
31
ARMSSE sse;
32
SplitIRQ cpu_irq_splitter[MUSCA_NUMIRQ_MAX];
33
+ SplitIRQ sec_resp_splitter;
34
+ TZPPC ppc[MUSCA_PPC_MAX];
35
+ MemoryRegion container;
36
+ UnimplementedDeviceState eflash[2];
37
+ UnimplementedDeviceState qspi;
38
+ UnimplementedDeviceState mpc[5];
39
+ UnimplementedDeviceState mhu[2];
40
+ UnimplementedDeviceState pwm[3];
41
+ UnimplementedDeviceState i2s;
42
+ UnimplementedDeviceState uart[2];
43
+ UnimplementedDeviceState i2c[2];
44
+ UnimplementedDeviceState spi;
45
+ UnimplementedDeviceState scc;
46
+ UnimplementedDeviceState timer;
47
+ UnimplementedDeviceState rtc;
48
+ UnimplementedDeviceState pvt;
49
+ UnimplementedDeviceState sdio;
50
+ UnimplementedDeviceState gpio;
51
} MuscaMachineState;
52
53
#define TYPE_MUSCA_MACHINE "musca"
54
@@ -XXX,XX +XXX,XX @@ typedef struct {
55
*/
56
#define SYSCLK_FRQ 40000000
57
58
+/*
59
+ * Most of the devices in the Musca board sit behind Peripheral Protection
60
+ * Controllers. These data structures define the layout of which devices
61
+ * sit behind which PPCs.
62
+ * The devfn for each port is a function which creates, configures
63
+ * and initializes the device, returning the MemoryRegion which
64
+ * needs to be plugged into the downstream end of the PPC port.
65
+ */
66
+typedef MemoryRegion *MakeDevFn(MuscaMachineState *mms, void *opaque,
67
+ const char *name, hwaddr size);
68
+
69
+typedef struct PPCPortInfo {
70
+ const char *name;
71
+ MakeDevFn *devfn;
72
+ void *opaque;
73
+ hwaddr addr;
74
+ hwaddr size;
75
+} PPCPortInfo;
76
+
77
+typedef struct PPCInfo {
78
+ const char *name;
79
+ PPCPortInfo ports[TZ_NUM_PORTS];
80
+} PPCInfo;
81
+
82
+static MemoryRegion *make_unimp_dev(MuscaMachineState *mms,
83
+ void *opaque, const char *name, hwaddr size)
84
+{
85
+ /*
86
+ * Initialize, configure and realize a TYPE_UNIMPLEMENTED_DEVICE,
87
+ * and return a pointer to its MemoryRegion.
88
+ */
89
+ UnimplementedDeviceState *uds = opaque;
90
+
91
+ sysbus_init_child_obj(OBJECT(mms), name, uds,
92
+ sizeof(UnimplementedDeviceState),
93
+ TYPE_UNIMPLEMENTED_DEVICE);
94
+ qdev_prop_set_string(DEVICE(uds), "name", name);
95
+ qdev_prop_set_uint64(DEVICE(uds), "size", size);
96
+ object_property_set_bool(OBJECT(uds), true, "realized", &error_fatal);
97
+ return sysbus_mmio_get_region(SYS_BUS_DEVICE(uds), 0);
98
+}
99
+
100
+static MemoryRegion *make_musca_a_devs(MuscaMachineState *mms, void *opaque,
101
+ const char *name, hwaddr size)
102
+{
103
+ /*
104
+ * Create the container MemoryRegion for all the devices that live
105
+ * behind the Musca-A PPC's single port. These devices don't have a PPC
106
+ * port each, but we use the PPCPortInfo struct as a convenient way
107
+ * to describe them. Note that addresses here are relative to the base
108
+ * address of the PPC port region: 0x40100000, and devices appear both
109
+ * at the 0x4... NS region and the 0x5... S region.
110
+ */
111
+ int i;
112
+ MemoryRegion *container = &mms->container;
113
+
114
+ const PPCPortInfo devices[] = {
115
+ { "uart0", make_unimp_dev, &mms->uart[0], 0x1000, 0x1000 },
116
+ { "uart1", make_unimp_dev, &mms->uart[1], 0x2000, 0x1000 },
117
+ { "spi", make_unimp_dev, &mms->spi, 0x3000, 0x1000 },
118
+ { "i2c0", make_unimp_dev, &mms->i2c[0], 0x4000, 0x1000 },
119
+ { "i2c1", make_unimp_dev, &mms->i2c[1], 0x5000, 0x1000 },
120
+ { "i2s", make_unimp_dev, &mms->i2s, 0x6000, 0x1000 },
121
+ { "pwm0", make_unimp_dev, &mms->pwm[0], 0x7000, 0x1000 },
122
+ { "rtc", make_unimp_dev, &mms->rtc, 0x8000, 0x1000 },
123
+ { "qspi", make_unimp_dev, &mms->qspi, 0xa000, 0x1000 },
124
+ { "timer", make_unimp_dev, &mms->timer, 0xb000, 0x1000 },
125
+ { "scc", make_unimp_dev, &mms->scc, 0xc000, 0x1000 },
126
+ { "pwm1", make_unimp_dev, &mms->pwm[1], 0xe000, 0x1000 },
127
+ { "pwm2", make_unimp_dev, &mms->pwm[2], 0xf000, 0x1000 },
128
+ { "gpio", make_unimp_dev, &mms->gpio, 0x10000, 0x1000 },
129
+ { "mpc0", make_unimp_dev, &mms->mpc[0], 0x12000, 0x1000 },
130
+ { "mpc1", make_unimp_dev, &mms->mpc[1], 0x13000, 0x1000 },
131
+ };
132
+
133
+ memory_region_init(container, OBJECT(mms), "musca-device-container", size);
134
+
135
+ for (i = 0; i < ARRAY_SIZE(devices); i++) {
136
+ const PPCPortInfo *pinfo = &devices[i];
137
+ MemoryRegion *mr;
138
+
139
+ mr = pinfo->devfn(mms, pinfo->opaque, pinfo->name, pinfo->size);
140
+ memory_region_add_subregion(container, pinfo->addr, mr);
141
+ }
142
+
143
+ return &mms->container;
144
+}
145
+
146
static void musca_init(MachineState *machine)
147
{
148
MuscaMachineState *mms = MUSCA_MACHINE(machine);
149
@@ -XXX,XX +XXX,XX @@ static void musca_init(MachineState *machine)
150
MachineClass *mc = MACHINE_GET_CLASS(machine);
151
MemoryRegion *system_memory = get_system_memory();
152
DeviceState *ssedev;
153
+ DeviceState *dev_splitter;
154
+ const PPCInfo *ppcs;
155
+ int num_ppcs;
156
int i;
157
158
assert(mmc->num_irqs <= MUSCA_NUMIRQ_MAX);
159
@@ -XXX,XX +XXX,XX @@ static void musca_init(MachineState *machine)
160
"EXP_CPU1_IRQ", i));
161
}
162
163
+ /*
164
+ * The sec_resp_cfg output from the SSE-200 must be split into multiple
165
+ * lines, one for each of the PPCs we create here.
166
+ */
167
+ object_initialize(&mms->sec_resp_splitter, sizeof(mms->sec_resp_splitter),
168
+ TYPE_SPLIT_IRQ);
169
+ object_property_add_child(OBJECT(machine), "sec-resp-splitter",
170
+ OBJECT(&mms->sec_resp_splitter), &error_fatal);
171
+ object_property_set_int(OBJECT(&mms->sec_resp_splitter),
172
+ ARRAY_SIZE(mms->ppc), "num-lines", &error_fatal);
173
+ object_property_set_bool(OBJECT(&mms->sec_resp_splitter), true,
174
+ "realized", &error_fatal);
175
+ dev_splitter = DEVICE(&mms->sec_resp_splitter);
176
+ qdev_connect_gpio_out_named(ssedev, "sec_resp_cfg", 0,
177
+ qdev_get_gpio_in(dev_splitter, 0));
178
+
179
+ /*
180
+ * Most of the devices in the board are behind Peripheral Protection
181
+ * Controllers. The required order for initializing things is:
182
+ * + initialize the PPC
183
+ * + initialize, configure and realize downstream devices
184
+ * + connect downstream device MemoryRegions to the PPC
185
+ * + realize the PPC
186
+ * + map the PPC's MemoryRegions to the places in the address map
187
+ * where the downstream devices should appear
188
+ * + wire up the PPC's control lines to the SSE object
189
+ *
190
+ * The PPC mapping differs for the -A and -B1 variants; the -A version
191
+ * is much simpler, using only a single port of a single PPC and putting
192
+ * all the devices behind that.
193
+ */
194
+ const PPCInfo a_ppcs[] = { {
195
+ .name = "ahb_ppcexp0",
196
+ .ports = {
197
+ { "musca-devices", make_musca_a_devs, 0, 0x40100000, 0x100000 },
198
+ },
199
+ },
200
+ };
201
+
202
+ /*
203
+ * Devices listed with an 0x4.. address appear in both the NS 0x4.. region
204
+ * and the 0x5.. S region. Devices listed with an 0x5.. address appear
205
+ * only in the S region.
206
+ */
207
+ const PPCInfo b1_ppcs[] = { {
208
+ .name = "apb_ppcexp0",
209
+ .ports = {
210
+ { "eflash0", make_unimp_dev, &mms->eflash[0],
211
+ 0x52400000, 0x1000 },
212
+ { "eflash1", make_unimp_dev, &mms->eflash[1],
213
+ 0x52500000, 0x1000 },
214
+ { "qspi", make_unimp_dev, &mms->qspi, 0x42800000, 0x100000 },
215
+ { "mpc0", make_unimp_dev, &mms->mpc[0], 0x52000000, 0x1000 },
216
+ { "mpc1", make_unimp_dev, &mms->mpc[1], 0x52100000, 0x1000 },
217
+ { "mpc2", make_unimp_dev, &mms->mpc[2], 0x52200000, 0x1000 },
218
+ { "mpc3", make_unimp_dev, &mms->mpc[3], 0x52300000, 0x1000 },
219
+ { "mhu0", make_unimp_dev, &mms->mhu[0], 0x42600000, 0x100000 },
220
+ { "mhu1", make_unimp_dev, &mms->mhu[1], 0x42700000, 0x100000 },
221
+ { }, /* port 9: unused */
222
+ { }, /* port 10: unused */
223
+ { }, /* port 11: unused */
224
+ { }, /* port 12: unused */
225
+ { }, /* port 13: unused */
226
+ { "mpc4", make_unimp_dev, &mms->mpc[4], 0x52e00000, 0x1000 },
227
+ },
228
+ }, {
229
+ .name = "apb_ppcexp1",
230
+ .ports = {
231
+ { "pwm0", make_unimp_dev, &mms->pwm[0], 0x40101000, 0x1000 },
232
+ { "pwm1", make_unimp_dev, &mms->pwm[1], 0x40102000, 0x1000 },
233
+ { "pwm2", make_unimp_dev, &mms->pwm[2], 0x40103000, 0x1000 },
234
+ { "i2s", make_unimp_dev, &mms->i2s, 0x40104000, 0x1000 },
235
+ { "uart0", make_unimp_dev, &mms->uart[0], 0x40105000, 0x1000 },
236
+ { "uart1", make_unimp_dev, &mms->uart[1], 0x40106000, 0x1000 },
237
+ { "i2c0", make_unimp_dev, &mms->i2c[0], 0x40108000, 0x1000 },
238
+ { "i2c1", make_unimp_dev, &mms->i2c[1], 0x40109000, 0x1000 },
239
+ { "spi", make_unimp_dev, &mms->spi, 0x4010a000, 0x1000 },
240
+ { "scc", make_unimp_dev, &mms->scc, 0x5010b000, 0x1000 },
241
+ { "timer", make_unimp_dev, &mms->timer, 0x4010c000, 0x1000 },
242
+ { "rtc", make_unimp_dev, &mms->rtc, 0x4010d000, 0x1000 },
243
+ { "pvt", make_unimp_dev, &mms->pvt, 0x4010e000, 0x1000 },
244
+ { "sdio", make_unimp_dev, &mms->sdio, 0x4010f000, 0x1000 },
245
+ },
246
+ }, {
247
+ .name = "ahb_ppcexp0",
248
+ .ports = {
249
+ { }, /* port 0: unused */
250
+ { "gpio", make_unimp_dev, &mms->gpio, 0x41000000, 0x1000 },
251
+ },
252
+ },
253
+ };
254
+
255
+ switch (mmc->type) {
256
+ case MUSCA_A:
257
+ ppcs = a_ppcs;
258
+ num_ppcs = ARRAY_SIZE(a_ppcs);
259
+ break;
260
+ case MUSCA_B1:
261
+ ppcs = b1_ppcs;
262
+ num_ppcs = ARRAY_SIZE(b1_ppcs);
263
+ break;
264
+ default:
265
+ g_assert_not_reached();
266
+ }
267
+ assert(num_ppcs <= MUSCA_PPC_MAX);
268
+
269
+ for (i = 0; i < num_ppcs; i++) {
270
+ const PPCInfo *ppcinfo = &ppcs[i];
271
+ TZPPC *ppc = &mms->ppc[i];
272
+ DeviceState *ppcdev;
273
+ int port;
274
+ char *gpioname;
275
+
276
+ sysbus_init_child_obj(OBJECT(machine), ppcinfo->name, ppc,
277
+ sizeof(TZPPC), TYPE_TZ_PPC);
278
+ ppcdev = DEVICE(ppc);
279
+
280
+ for (port = 0; port < TZ_NUM_PORTS; port++) {
281
+ const PPCPortInfo *pinfo = &ppcinfo->ports[port];
282
+ MemoryRegion *mr;
283
+ char *portname;
284
+
285
+ if (!pinfo->devfn) {
286
+ continue;
287
+ }
288
+
289
+ mr = pinfo->devfn(mms, pinfo->opaque, pinfo->name, pinfo->size);
290
+ portname = g_strdup_printf("port[%d]", port);
291
+ object_property_set_link(OBJECT(ppc), OBJECT(mr),
292
+ portname, &error_fatal);
293
+ g_free(portname);
294
+ }
295
+
296
+ object_property_set_bool(OBJECT(ppc), true, "realized", &error_fatal);
297
+
298
+ for (port = 0; port < TZ_NUM_PORTS; port++) {
299
+ const PPCPortInfo *pinfo = &ppcinfo->ports[port];
300
+
301
+ if (!pinfo->devfn) {
302
+ continue;
303
+ }
304
+ sysbus_mmio_map(SYS_BUS_DEVICE(ppc), port, pinfo->addr);
305
+
306
+ gpioname = g_strdup_printf("%s_nonsec", ppcinfo->name);
307
+ qdev_connect_gpio_out_named(ssedev, gpioname, port,
308
+ qdev_get_gpio_in_named(ppcdev,
309
+ "cfg_nonsec",
310
+ port));
311
+ g_free(gpioname);
312
+ gpioname = g_strdup_printf("%s_ap", ppcinfo->name);
313
+ qdev_connect_gpio_out_named(ssedev, gpioname, port,
314
+ qdev_get_gpio_in_named(ppcdev,
315
+ "cfg_ap", port));
316
+ g_free(gpioname);
317
+ }
318
+
319
+ gpioname = g_strdup_printf("%s_irq_enable", ppcinfo->name);
320
+ qdev_connect_gpio_out_named(ssedev, gpioname, 0,
321
+ qdev_get_gpio_in_named(ppcdev,
322
+ "irq_enable", 0));
323
+ g_free(gpioname);
324
+ gpioname = g_strdup_printf("%s_irq_clear", ppcinfo->name);
325
+ qdev_connect_gpio_out_named(ssedev, gpioname, 0,
326
+ qdev_get_gpio_in_named(ppcdev,
327
+ "irq_clear", 0));
328
+ g_free(gpioname);
329
+ gpioname = g_strdup_printf("%s_irq_status", ppcinfo->name);
330
+ qdev_connect_gpio_out_named(ppcdev, "irq", 0,
331
+ qdev_get_gpio_in_named(ssedev,
332
+ gpioname, 0));
333
+ g_free(gpioname);
334
+
335
+ qdev_connect_gpio_out(dev_splitter, i,
336
+ qdev_get_gpio_in_named(ppcdev,
337
+ "cfg_sec_resp", 0));
338
+ }
339
+
340
armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, 0x2000000);
341
}
342
343
--
344
2.20.1
345
346
diff view generated by jsdifflib
Deleted patch
1
Wire up the PL031 RTC for the Musca board.
2
1
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
---
6
hw/arm/musca.c | 26 +++++++++++++++++++++++---
7
1 file changed, 23 insertions(+), 3 deletions(-)
8
9
diff --git a/hw/arm/musca.c b/hw/arm/musca.c
10
index XXXXXXX..XXXXXXX 100644
11
--- a/hw/arm/musca.c
12
+++ b/hw/arm/musca.c
13
@@ -XXX,XX +XXX,XX @@
14
#include "hw/misc/tz-mpc.h"
15
#include "hw/misc/tz-ppc.h"
16
#include "hw/misc/unimp.h"
17
+#include "hw/timer/pl031.h"
18
19
#define MUSCA_NUMIRQ_MAX 96
20
#define MUSCA_PPC_MAX 3
21
@@ -XXX,XX +XXX,XX @@ typedef struct {
22
UnimplementedDeviceState spi;
23
UnimplementedDeviceState scc;
24
UnimplementedDeviceState timer;
25
- UnimplementedDeviceState rtc;
26
+ PL031State rtc;
27
UnimplementedDeviceState pvt;
28
UnimplementedDeviceState sdio;
29
UnimplementedDeviceState gpio;
30
@@ -XXX,XX +XXX,XX @@ typedef struct {
31
*/
32
#define SYSCLK_FRQ 40000000
33
34
+static qemu_irq get_sse_irq_in(MuscaMachineState *mms, int irqno)
35
+{
36
+ /* Return a qemu_irq which will signal IRQ n to all CPUs in the SSE. */
37
+ assert(irqno < MUSCA_NUMIRQ_MAX);
38
+
39
+ return qdev_get_gpio_in(DEVICE(&mms->cpu_irq_splitter[irqno]), 0);
40
+}
41
+
42
/*
43
* Most of the devices in the Musca board sit behind Peripheral Protection
44
* Controllers. These data structures define the layout of which devices
45
@@ -XXX,XX +XXX,XX @@ static MemoryRegion *make_mpc(MuscaMachineState *mms, void *opaque,
46
return sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 0);
47
}
48
49
+static MemoryRegion *make_rtc(MuscaMachineState *mms, void *opaque,
50
+ const char *name, hwaddr size)
51
+{
52
+ PL031State *rtc = opaque;
53
+
54
+ sysbus_init_child_obj(OBJECT(mms), name, rtc, sizeof(mms->rtc), TYPE_PL031);
55
+ object_property_set_bool(OBJECT(rtc), true, "realized", &error_fatal);
56
+ sysbus_connect_irq(SYS_BUS_DEVICE(rtc), 0, get_sse_irq_in(mms, 39));
57
+ return sysbus_mmio_get_region(SYS_BUS_DEVICE(rtc), 0);
58
+}
59
+
60
static MemoryRegion *make_musca_a_devs(MuscaMachineState *mms, void *opaque,
61
const char *name, hwaddr size)
62
{
63
@@ -XXX,XX +XXX,XX @@ static MemoryRegion *make_musca_a_devs(MuscaMachineState *mms, void *opaque,
64
{ "i2c1", make_unimp_dev, &mms->i2c[1], 0x5000, 0x1000 },
65
{ "i2s", make_unimp_dev, &mms->i2s, 0x6000, 0x1000 },
66
{ "pwm0", make_unimp_dev, &mms->pwm[0], 0x7000, 0x1000 },
67
- { "rtc", make_unimp_dev, &mms->rtc, 0x8000, 0x1000 },
68
+ { "rtc", make_rtc, &mms->rtc, 0x8000, 0x1000 },
69
{ "qspi", make_unimp_dev, &mms->qspi, 0xa000, 0x1000 },
70
{ "timer", make_unimp_dev, &mms->timer, 0xb000, 0x1000 },
71
{ "scc", make_unimp_dev, &mms->scc, 0xc000, 0x1000 },
72
@@ -XXX,XX +XXX,XX @@ static void musca_init(MachineState *machine)
73
{ "spi", make_unimp_dev, &mms->spi, 0x4010a000, 0x1000 },
74
{ "scc", make_unimp_dev, &mms->scc, 0x5010b000, 0x1000 },
75
{ "timer", make_unimp_dev, &mms->timer, 0x4010c000, 0x1000 },
76
- { "rtc", make_unimp_dev, &mms->rtc, 0x4010d000, 0x1000 },
77
+ { "rtc", make_rtc, &mms->rtc, 0x4010d000, 0x1000 },
78
{ "pvt", make_unimp_dev, &mms->pvt, 0x4010e000, 0x1000 },
79
{ "sdio", make_unimp_dev, &mms->sdio, 0x4010f000, 0x1000 },
80
},
81
--
82
2.20.1
83
84
diff view generated by jsdifflib