1
Arm queue; not huge but I figured I might as well send it out since
1
Hi; here's a target-arm pullreq. Mostly this is some decodetree
2
I've been doing code review today and there's no queue of unprocessed
2
conversion patches from me, plus a scattering of other bug fixes.
3
pullreqs...
4
3
5
thanks
4
thanks
6
-- PMM
5
-- PMM
7
6
8
The following changes since commit b3f846c59d8405bb87c551187721fc92ff2f1b92:
7
The following changes since commit e3660cc1e3cb136af50c0eaaeac27943c2438d1d:
9
8
10
Merge remote-tracking branch 'remotes/huth-gitlab/tags/pull-request-2021-01-11v2' into staging (2021-01-11 15:15:35 +0000)
9
Merge tag 'pull-loongarch-20230616' of https://gitlab.com/gaosong/qemu into staging (2023-06-16 12:30:16 +0200)
11
10
12
are available in the Git repository at:
11
are available in the Git repository at:
13
12
14
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20210112
13
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20230619
15
14
16
for you to fetch changes up to 19d131395ccaf503db21dadd8257e6dc9fc1d7de:
15
for you to fetch changes up to 074259c0f2ac40042dce766d870318cc22f388eb:
17
16
18
ui/cocoa: Fix openFile: deprecation on Big Sur (2021-01-12 11:38:37 +0000)
17
hw/misc/bcm2835_property: Handle CORE_CLK_ID firmware property (2023-06-19 15:27:21 +0100)
19
18
20
----------------------------------------------------------------
19
----------------------------------------------------------------
21
target-arm queue:
20
target-arm queue:
22
* arm: Support emulation of ARMv8.4-TTST extension
21
* Fix return value from LDSMIN/LDSMAX 8/16 bit atomics
23
* arm: Update cpu.h ID register field definitions
22
* Return correct result for LDG when ATA=0
24
* arm: Fix breakage of XScale instruction emulation
23
* Conversion of system insns, loads and stores to decodetree
25
* hw/net/lan9118: Fix RX Status FIFO PEEK value
24
* hw/intc/allwinner-a10-pic: Handle IRQ levels other than 0 or 1
26
* npcm7xx: Add ADC and PWM emulation
25
* hw/sd/allwinner-sdhost: Don't send non-boolean IRQ line levels
27
* ui/cocoa: Make "open docs" help menu entry work again when binary
26
* hw/timer/nrf51_timer: Don't lose time when timer is queried in tight loop
28
is run from the build tree
27
* hw/arm/Kconfig: sbsa-ref uses Bochs display
29
* ui/cocoa: Fix openFile: deprecation on Big Sur
28
* imx_serial: set wake bit when we receive a data byte
30
* docs: Add qemu-storage-daemon(1) manpage to meson.build
29
* docs: sbsa: document board to firmware interface
31
* docs: Build and install all the docs in a single manual
30
* hw/misc/bcm2835_property: avoid hard-coded constants
32
31
33
----------------------------------------------------------------
32
----------------------------------------------------------------
34
Hao Wu (6):
33
Marcin Juszkiewicz (2):
35
hw/misc: Add clock converter in NPCM7XX CLK module
34
hw/arm/Kconfig: sbsa-ref uses Bochs display
36
hw/timer: Refactor NPCM7XX Timer to use CLK clock
35
docs: sbsa: document board to firmware interface
37
hw/adc: Add an ADC module for NPCM7XX
38
hw/misc: Add a PWM module for NPCM7XX
39
hw/misc: Add QTest for NPCM7XX PWM Module
40
hw/*: Use type casting for SysBusDevice in NPCM7XX
41
36
42
Leif Lindholm (6):
37
Martin Kaiser (1):
43
target/arm: fix typo in cpu.h ID_AA64PFR1 field name
38
imx_serial: set wake bit when we receive a data byte
44
target/arm: make ARMCPU.clidr 64-bit
45
target/arm: make ARMCPU.ctr 64-bit
46
target/arm: add descriptions of CLIDR_EL1, CCSIDR_EL1, CTR_EL0 to cpu.h
47
target/arm: add aarch64 ID register fields to cpu.h
48
target/arm: add aarch32 ID register fields to cpu.h
49
39
50
Peter Maydell (5):
40
Peter Maydell (26):
51
docs: Add qemu-storage-daemon(1) manpage to meson.build
41
target/arm: Fix return value from LDSMIN/LDSMAX 8/16 bit atomics
52
docs: Build and install all the docs in a single manual
42
target/arm: Return correct result for LDG when ATA=0
53
target/arm: Don't decode insns in the XScale/iWMMXt space as cp insns
43
target/arm: Pass memop to gen_mte_check1_mmuidx() in reg_imm9 decode
54
hw/net/lan9118: Fix RX Status FIFO PEEK value
44
target/arm: Consistently use finalize_memop_asimd() for ASIMD loads/stores
55
hw/net/lan9118: Add symbolic constants for register offsets
45
target/arm: Convert hint instruction space to decodetree
46
target/arm: Convert barrier insns to decodetree
47
target/arm: Convert CFINV, XAFLAG and AXFLAG to decodetree
48
target/arm: Convert MSR (immediate) to decodetree
49
target/arm: Convert MSR (reg), MRS, SYS, SYSL to decodetree
50
target/arm: Convert exception generation instructions to decodetree
51
target/arm: Convert load/store exclusive and ordered to decodetree
52
target/arm: Convert LDXP, STXP, CASP, CAS to decodetree
53
target/arm: Convert load reg (literal) group to decodetree
54
target/arm: Convert load/store-pair to decodetree
55
target/arm: Convert ld/st reg+imm9 insns to decodetree
56
target/arm: Convert LDR/STR with 12-bit immediate to decodetree
57
target/arm: Convert LDR/STR reg+reg to decodetree
58
target/arm: Convert atomic memory ops to decodetree
59
target/arm: Convert load (pointer auth) insns to decodetree
60
target/arm: Convert LDAPR/STLR (imm) to decodetree
61
target/arm: Convert load/store (multiple structures) to decodetree
62
target/arm: Convert load/store single structure to decodetree
63
target/arm: Convert load/store tags insns to decodetree
64
hw/intc/allwinner-a10-pic: Handle IRQ levels other than 0 or 1
65
hw/sd/allwinner-sdhost: Don't send non-boolean IRQ line levels
66
hw/timer/nrf51_timer: Don't lose time when timer is queried in tight loop
56
67
57
Roman Bolshakov (2):
68
Sergey Kambalin (4):
58
ui/cocoa: Update path to docs in build tree
69
hw/arm/raspi: Import Linux raspi definitions as 'raspberrypi-fw-defs.h'
59
ui/cocoa: Fix openFile: deprecation on Big Sur
70
hw/misc/bcm2835_property: Use 'raspberrypi-fw-defs.h' definitions
71
hw/misc/bcm2835_property: Replace magic frequency values by definitions
72
hw/misc/bcm2835_property: Handle CORE_CLK_ID firmware property
60
73
61
Rémi Denis-Courmont (2):
74
docs/system/arm/sbsa.rst | 38 +-
62
target/arm: ARMv8.4-TTST extension
75
include/hw/arm/raspi_platform.h | 10 +
63
target/arm: enable Small Translation tables in max CPU
76
include/hw/char/imx_serial.h | 1 +
64
77
include/hw/misc/raspberrypi-fw-defs.h | 163 ++
65
docs/conf.py | 46 ++-
78
target/arm/tcg/a64.decode | 403 ++++
66
docs/devel/conf.py | 15 -
79
hw/char/imx_serial.c | 5 +-
67
docs/index.html.in | 17 -
80
hw/intc/allwinner-a10-pic.c | 2 +-
68
docs/interop/conf.py | 28 --
81
hw/misc/bcm2835_property.c | 112 +-
69
docs/meson.build | 65 ++--
82
hw/sd/allwinner-sdhost.c | 2 +-
70
docs/specs/conf.py | 16 -
83
hw/timer/nrf51_timer.c | 7 +-
71
docs/system/arm/nuvoton.rst | 4 +-
84
target/arm/tcg/translate-a64.c | 3319 +++++++++++++++------------------
72
docs/system/conf.py | 28 --
85
hw/arm/Kconfig | 1 +
73
docs/tools/conf.py | 37 --
86
12 files changed, 2157 insertions(+), 1906 deletions(-)
74
docs/user/conf.py | 15 -
87
create mode 100644 include/hw/misc/raspberrypi-fw-defs.h
75
meson.build | 1 +
76
hw/adc/trace.h | 1 +
77
include/hw/adc/npcm7xx_adc.h | 69 ++++
78
include/hw/arm/npcm7xx.h | 4 +
79
include/hw/misc/npcm7xx_clk.h | 146 ++++++-
80
include/hw/misc/npcm7xx_pwm.h | 105 +++++
81
include/hw/timer/npcm7xx_timer.h | 1 +
82
target/arm/cpu.h | 85 ++++-
83
hw/adc/npcm7xx_adc.c | 301 +++++++++++++++
84
hw/arm/npcm7xx.c | 55 ++-
85
hw/arm/npcm7xx_boards.c | 2 +-
86
hw/mem/npcm7xx_mc.c | 2 +-
87
hw/misc/npcm7xx_clk.c | 807 ++++++++++++++++++++++++++++++++++++++-
88
hw/misc/npcm7xx_gcr.c | 2 +-
89
hw/misc/npcm7xx_pwm.c | 550 ++++++++++++++++++++++++++
90
hw/misc/npcm7xx_rng.c | 2 +-
91
hw/net/lan9118.c | 26 +-
92
hw/nvram/npcm7xx_otp.c | 2 +-
93
hw/ssi/npcm7xx_fiu.c | 2 +-
94
hw/timer/npcm7xx_timer.c | 39 +-
95
target/arm/cpu64.c | 1 +
96
target/arm/helper.c | 15 +-
97
target/arm/translate.c | 7 +
98
tests/qtest/npcm7xx_adc-test.c | 377 ++++++++++++++++++
99
tests/qtest/npcm7xx_pwm-test.c | 490 ++++++++++++++++++++++++
100
hw/adc/meson.build | 1 +
101
hw/adc/trace-events | 5 +
102
hw/misc/meson.build | 1 +
103
hw/misc/trace-events | 6 +
104
tests/qtest/meson.build | 4 +-
105
ui/cocoa.m | 7 +-
106
41 files changed, 3124 insertions(+), 263 deletions(-)
107
delete mode 100644 docs/devel/conf.py
108
delete mode 100644 docs/index.html.in
109
delete mode 100644 docs/interop/conf.py
110
delete mode 100644 docs/specs/conf.py
111
delete mode 100644 docs/system/conf.py
112
delete mode 100644 docs/tools/conf.py
113
delete mode 100644 docs/user/conf.py
114
create mode 100644 hw/adc/trace.h
115
create mode 100644 include/hw/adc/npcm7xx_adc.h
116
create mode 100644 include/hw/misc/npcm7xx_pwm.h
117
create mode 100644 hw/adc/npcm7xx_adc.c
118
create mode 100644 hw/misc/npcm7xx_pwm.c
119
create mode 100644 tests/qtest/npcm7xx_adc-test.c
120
create mode 100644 tests/qtest/npcm7xx_pwm-test.c
121
create mode 100644 hw/adc/trace-events
122
diff view generated by jsdifflib
New patch
1
The atomic memory operations are supposed to return the old memory
2
data value in the destination register. This value is not
3
sign-extended, even if the operation is the signed minimum or
4
maximum. (In the pseudocode for the instructions the returned data
5
value is passed to ZeroExtend() to create the value in the register.)
1
6
7
We got this wrong because we were doing a 32-to-64 zero extend on the
8
result for 8 and 16 bit data values, rather than the correct amount
9
of zero extension.
10
11
Fix the bug by using ext8u and ext16u for the MO_8 and MO_16 data
12
sizes rather than ext32u.
13
14
Cc: qemu-stable@nongnu.org
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
17
Message-id: 20230602155223.2040685-2-peter.maydell@linaro.org
18
---
19
target/arm/tcg/translate-a64.c | 18 ++++++++++++++++--
20
1 file changed, 16 insertions(+), 2 deletions(-)
21
22
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
23
index XXXXXXX..XXXXXXX 100644
24
--- a/target/arm/tcg/translate-a64.c
25
+++ b/target/arm/tcg/translate-a64.c
26
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn,
27
*/
28
fn(tcg_rt, clean_addr, tcg_rs, get_mem_index(s), mop);
29
30
- if ((mop & MO_SIGN) && size != MO_64) {
31
- tcg_gen_ext32u_i64(tcg_rt, tcg_rt);
32
+ if (mop & MO_SIGN) {
33
+ switch (size) {
34
+ case MO_8:
35
+ tcg_gen_ext8u_i64(tcg_rt, tcg_rt);
36
+ break;
37
+ case MO_16:
38
+ tcg_gen_ext16u_i64(tcg_rt, tcg_rt);
39
+ break;
40
+ case MO_32:
41
+ tcg_gen_ext32u_i64(tcg_rt, tcg_rt);
42
+ break;
43
+ case MO_64:
44
+ break;
45
+ default:
46
+ g_assert_not_reached();
47
+ }
48
}
49
}
50
51
--
52
2.34.1
diff view generated by jsdifflib
New patch
1
The LDG instruction loads the tag from a memory address (identified
2
by [Xn + offset]), and then merges that tag into the destination
3
register Xt. We implemented this correctly for the case when
4
allocation tags are enabled, but didn't get it right when ATA=0:
5
instead of merging the tag bits into Xt, we merged them into the
6
memory address [Xn + offset] and then set Xt to that.
1
7
8
Merge the tag bits into the old Xt value, as they should be.
9
10
Cc: qemu-stable@nongnu.org
11
Fixes: c15294c1e36a7dd9b25 ("target/arm: Implement LDG, STG, ST2G instructions")
12
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
---
15
target/arm/tcg/translate-a64.c | 6 +++++-
16
1 file changed, 5 insertions(+), 1 deletion(-)
17
18
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/target/arm/tcg/translate-a64.c
21
+++ b/target/arm/tcg/translate-a64.c
22
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_tag(DisasContext *s, uint32_t insn)
23
if (s->ata) {
24
gen_helper_ldg(tcg_rt, cpu_env, addr, tcg_rt);
25
} else {
26
+ /*
27
+ * Tag access disabled: we must check for aborts on the load
28
+ * load from [rn+offset], and then insert a 0 tag into rt.
29
+ */
30
clean_addr = clean_data_tbi(s, addr);
31
gen_probe_access(s, clean_addr, MMU_DATA_LOAD, MO_8);
32
- gen_address_with_allocation_tag0(tcg_rt, addr);
33
+ gen_address_with_allocation_tag0(tcg_rt, tcg_rt);
34
}
35
} else {
36
tcg_rt = cpu_reg_sp(s, rt);
37
--
38
2.34.1
diff view generated by jsdifflib
1
From: Leif Lindholm <leif@nuviainc.com>
1
In disas_ldst_reg_imm9() we missed one place where a call to
2
a gen_mte_check* function should now be passed the memop we
3
have created rather than just being passed the size. Fix this.
2
4
3
When FEAT_MTE is implemented, the AArch64 view of CTR_EL0 adds the
5
Fixes: 0a9091424d ("target/arm: Pass memop to gen_mte_check1*")
4
TminLine field in bits [37:32].
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Extend the ctr field to be able to hold this context.
6
7
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
8
Reviewed-by: Hao Wu <wuhaotsh@google.com>
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
8
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
11
Message-id: 20210108185154.8108-4-leif@nuviainc.com
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
9
---
14
target/arm/cpu.h | 2 +-
10
target/arm/tcg/translate-a64.c | 2 +-
15
1 file changed, 1 insertion(+), 1 deletion(-)
11
1 file changed, 1 insertion(+), 1 deletion(-)
16
12
17
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
13
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
18
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/cpu.h
15
--- a/target/arm/tcg/translate-a64.c
20
+++ b/target/arm/cpu.h
16
+++ b/target/arm/tcg/translate-a64.c
21
@@ -XXX,XX +XXX,XX @@ struct ARMCPU {
17
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn,
22
uint64_t midr;
18
23
uint32_t revidr;
19
clean_addr = gen_mte_check1_mmuidx(s, dirty_addr, is_store,
24
uint32_t reset_fpsid;
20
writeback || rn != 31,
25
- uint32_t ctr;
21
- size, is_unpriv, memidx);
26
+ uint64_t ctr;
22
+ memop, is_unpriv, memidx);
27
uint32_t reset_sctlr;
23
28
uint64_t pmceid0;
24
if (is_vector) {
29
uint64_t pmceid1;
25
if (is_store) {
30
--
26
--
31
2.20.1
27
2.34.1
32
28
33
29
diff view generated by jsdifflib
New patch
1
In the recent refactoring we missed a few places which should be
2
calling finalize_memop_asimd() for ASIMD loads and stores but
3
instead are just calling finalize_memop(); fix these.
1
4
5
For the disas_ldst_single_struct() and disas_ldst_multiple_struct()
6
cases, this is not a behaviour change because there the size
7
is never MO_128 and the two finalize functions do the same thing.
8
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
11
---
12
target/arm/tcg/translate-a64.c | 10 ++++++----
13
1 file changed, 6 insertions(+), 4 deletions(-)
14
15
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/tcg/translate-a64.c
18
+++ b/target/arm/tcg/translate-a64.c
19
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn,
20
if (!fp_access_check(s)) {
21
return;
22
}
23
+ memop = finalize_memop_asimd(s, size);
24
} else {
25
if (size == 3 && opc == 2) {
26
/* PRFM - prefetch */
27
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn,
28
is_store = (opc == 0);
29
is_signed = !is_store && extract32(opc, 1, 1);
30
is_extended = (size < 3) && extract32(opc, 0, 1);
31
+ memop = finalize_memop(s, size + is_signed * MO_SIGN);
32
}
33
34
if (rn == 31) {
35
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn,
36
37
tcg_gen_add_i64(dirty_addr, dirty_addr, tcg_rm);
38
39
- memop = finalize_memop(s, size + is_signed * MO_SIGN);
40
clean_addr = gen_mte_check1(s, dirty_addr, is_store, true, memop);
41
42
if (is_vector) {
43
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn,
44
if (!fp_access_check(s)) {
45
return;
46
}
47
+ memop = finalize_memop_asimd(s, size);
48
} else {
49
if (size == 3 && opc == 2) {
50
/* PRFM - prefetch */
51
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn,
52
is_store = (opc == 0);
53
is_signed = !is_store && extract32(opc, 1, 1);
54
is_extended = (size < 3) && extract32(opc, 0, 1);
55
+ memop = finalize_memop(s, size + is_signed * MO_SIGN);
56
}
57
58
if (rn == 31) {
59
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn,
60
offset = imm12 << size;
61
tcg_gen_addi_i64(dirty_addr, dirty_addr, offset);
62
63
- memop = finalize_memop(s, size + is_signed * MO_SIGN);
64
clean_addr = gen_mte_check1(s, dirty_addr, is_store, rn != 31, memop);
65
66
if (is_vector) {
67
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn)
68
* promote consecutive little-endian elements below.
69
*/
70
clean_addr = gen_mte_checkN(s, tcg_rn, is_store, is_postidx || rn != 31,
71
- total, finalize_memop(s, size));
72
+ total, finalize_memop_asimd(s, size));
73
74
/*
75
* Consecutive little-endian elements from a single register
76
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn)
77
total = selem << scale;
78
tcg_rn = cpu_reg_sp(s, rn);
79
80
- mop = finalize_memop(s, scale);
81
+ mop = finalize_memop_asimd(s, scale);
82
83
clean_addr = gen_mte_checkN(s, tcg_rn, !is_load, is_postidx || rn != 31,
84
total, mop);
85
--
86
2.34.1
diff view generated by jsdifflib
New patch
1
Convert the various instructions in the hint instruction space
2
to decodetree.
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20230602155223.2040685-3-peter.maydell@linaro.org
7
---
8
target/arm/tcg/a64.decode | 31 ++++
9
target/arm/tcg/translate-a64.c | 277 ++++++++++++++++++---------------
10
2 files changed, 185 insertions(+), 123 deletions(-)
11
12
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/arm/tcg/a64.decode
15
+++ b/target/arm/tcg/a64.decode
16
@@ -XXX,XX +XXX,XX @@ ERETA 1101011 0100 11111 00001 m:1 11111 11111 &reta # ERETAA, ERETAB
17
# the processor is in halting debug state (which we don't implement).
18
# The pattern is listed here as documentation.
19
# DRPS 1101011 0101 11111 000000 11111 00000
20
+
21
+# Hint instruction group
22
+{
23
+ [
24
+ YIELD 1101 0101 0000 0011 0010 0000 001 11111
25
+ WFE 1101 0101 0000 0011 0010 0000 010 11111
26
+ WFI 1101 0101 0000 0011 0010 0000 011 11111
27
+ # We implement WFE to never block, so our SEV/SEVL are NOPs
28
+ # SEV 1101 0101 0000 0011 0010 0000 100 11111
29
+ # SEVL 1101 0101 0000 0011 0010 0000 101 11111
30
+ # Our DGL is a NOP because we don't merge memory accesses anyway.
31
+ # DGL 1101 0101 0000 0011 0010 0000 110 11111
32
+ XPACLRI 1101 0101 0000 0011 0010 0000 111 11111
33
+ PACIA1716 1101 0101 0000 0011 0010 0001 000 11111
34
+ PACIB1716 1101 0101 0000 0011 0010 0001 010 11111
35
+ AUTIA1716 1101 0101 0000 0011 0010 0001 100 11111
36
+ AUTIB1716 1101 0101 0000 0011 0010 0001 110 11111
37
+ ESB 1101 0101 0000 0011 0010 0010 000 11111
38
+ PACIAZ 1101 0101 0000 0011 0010 0011 000 11111
39
+ PACIASP 1101 0101 0000 0011 0010 0011 001 11111
40
+ PACIBZ 1101 0101 0000 0011 0010 0011 010 11111
41
+ PACIBSP 1101 0101 0000 0011 0010 0011 011 11111
42
+ AUTIAZ 1101 0101 0000 0011 0010 0011 100 11111
43
+ AUTIASP 1101 0101 0000 0011 0010 0011 101 11111
44
+ AUTIBZ 1101 0101 0000 0011 0010 0011 110 11111
45
+ AUTIBSP 1101 0101 0000 0011 0010 0011 111 11111
46
+ ]
47
+ # The canonical NOP has CRm == op2 == 0, but all of the space
48
+ # that isn't specifically allocated to an instruction must NOP
49
+ NOP 1101 0101 0000 0011 0010 ---- --- 11111
50
+}
51
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
52
index XXXXXXX..XXXXXXX 100644
53
--- a/target/arm/tcg/translate-a64.c
54
+++ b/target/arm/tcg/translate-a64.c
55
@@ -XXX,XX +XXX,XX @@ static bool trans_ERETA(DisasContext *s, arg_reta *a)
56
return true;
57
}
58
59
-/* HINT instruction group, including various allocated HINTs */
60
-static void handle_hint(DisasContext *s, uint32_t insn,
61
- unsigned int op1, unsigned int op2, unsigned int crm)
62
+static bool trans_NOP(DisasContext *s, arg_NOP *a)
63
{
64
- unsigned int selector = crm << 3 | op2;
65
+ return true;
66
+}
67
68
- if (op1 != 3) {
69
- unallocated_encoding(s);
70
- return;
71
+static bool trans_YIELD(DisasContext *s, arg_YIELD *a)
72
+{
73
+ /*
74
+ * When running in MTTCG we don't generate jumps to the yield and
75
+ * WFE helpers as it won't affect the scheduling of other vCPUs.
76
+ * If we wanted to more completely model WFE/SEV so we don't busy
77
+ * spin unnecessarily we would need to do something more involved.
78
+ */
79
+ if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
80
+ s->base.is_jmp = DISAS_YIELD;
81
}
82
+ return true;
83
+}
84
85
- switch (selector) {
86
- case 0b00000: /* NOP */
87
- break;
88
- case 0b00011: /* WFI */
89
- s->base.is_jmp = DISAS_WFI;
90
- break;
91
- case 0b00001: /* YIELD */
92
- /* When running in MTTCG we don't generate jumps to the yield and
93
- * WFE helpers as it won't affect the scheduling of other vCPUs.
94
- * If we wanted to more completely model WFE/SEV so we don't busy
95
- * spin unnecessarily we would need to do something more involved.
96
+static bool trans_WFI(DisasContext *s, arg_WFI *a)
97
+{
98
+ s->base.is_jmp = DISAS_WFI;
99
+ return true;
100
+}
101
+
102
+static bool trans_WFE(DisasContext *s, arg_WFI *a)
103
+{
104
+ /*
105
+ * When running in MTTCG we don't generate jumps to the yield and
106
+ * WFE helpers as it won't affect the scheduling of other vCPUs.
107
+ * If we wanted to more completely model WFE/SEV so we don't busy
108
+ * spin unnecessarily we would need to do something more involved.
109
+ */
110
+ if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
111
+ s->base.is_jmp = DISAS_WFE;
112
+ }
113
+ return true;
114
+}
115
+
116
+static bool trans_XPACLRI(DisasContext *s, arg_XPACLRI *a)
117
+{
118
+ if (s->pauth_active) {
119
+ gen_helper_xpaci(cpu_X[30], cpu_env, cpu_X[30]);
120
+ }
121
+ return true;
122
+}
123
+
124
+static bool trans_PACIA1716(DisasContext *s, arg_PACIA1716 *a)
125
+{
126
+ if (s->pauth_active) {
127
+ gen_helper_pacia(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]);
128
+ }
129
+ return true;
130
+}
131
+
132
+static bool trans_PACIB1716(DisasContext *s, arg_PACIB1716 *a)
133
+{
134
+ if (s->pauth_active) {
135
+ gen_helper_pacib(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]);
136
+ }
137
+ return true;
138
+}
139
+
140
+static bool trans_AUTIA1716(DisasContext *s, arg_AUTIA1716 *a)
141
+{
142
+ if (s->pauth_active) {
143
+ gen_helper_autia(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]);
144
+ }
145
+ return true;
146
+}
147
+
148
+static bool trans_AUTIB1716(DisasContext *s, arg_AUTIB1716 *a)
149
+{
150
+ if (s->pauth_active) {
151
+ gen_helper_autib(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]);
152
+ }
153
+ return true;
154
+}
155
+
156
+static bool trans_ESB(DisasContext *s, arg_ESB *a)
157
+{
158
+ /* Without RAS, we must implement this as NOP. */
159
+ if (dc_isar_feature(aa64_ras, s)) {
160
+ /*
161
+ * QEMU does not have a source of physical SErrors,
162
+ * so we are only concerned with virtual SErrors.
163
+ * The pseudocode in the ARM for this case is
164
+ * if PSTATE.EL IN {EL0, EL1} && EL2Enabled() then
165
+ * AArch64.vESBOperation();
166
+ * Most of the condition can be evaluated at translation time.
167
+ * Test for EL2 present, and defer test for SEL2 to runtime.
168
*/
169
- if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
170
- s->base.is_jmp = DISAS_YIELD;
171
+ if (s->current_el <= 1 && arm_dc_feature(s, ARM_FEATURE_EL2)) {
172
+ gen_helper_vesb(cpu_env);
173
}
174
- break;
175
- case 0b00010: /* WFE */
176
- if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
177
- s->base.is_jmp = DISAS_WFE;
178
- }
179
- break;
180
- case 0b00100: /* SEV */
181
- case 0b00101: /* SEVL */
182
- case 0b00110: /* DGH */
183
- /* we treat all as NOP at least for now */
184
- break;
185
- case 0b00111: /* XPACLRI */
186
- if (s->pauth_active) {
187
- gen_helper_xpaci(cpu_X[30], cpu_env, cpu_X[30]);
188
- }
189
- break;
190
- case 0b01000: /* PACIA1716 */
191
- if (s->pauth_active) {
192
- gen_helper_pacia(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]);
193
- }
194
- break;
195
- case 0b01010: /* PACIB1716 */
196
- if (s->pauth_active) {
197
- gen_helper_pacib(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]);
198
- }
199
- break;
200
- case 0b01100: /* AUTIA1716 */
201
- if (s->pauth_active) {
202
- gen_helper_autia(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]);
203
- }
204
- break;
205
- case 0b01110: /* AUTIB1716 */
206
- if (s->pauth_active) {
207
- gen_helper_autib(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]);
208
- }
209
- break;
210
- case 0b10000: /* ESB */
211
- /* Without RAS, we must implement this as NOP. */
212
- if (dc_isar_feature(aa64_ras, s)) {
213
- /*
214
- * QEMU does not have a source of physical SErrors,
215
- * so we are only concerned with virtual SErrors.
216
- * The pseudocode in the ARM for this case is
217
- * if PSTATE.EL IN {EL0, EL1} && EL2Enabled() then
218
- * AArch64.vESBOperation();
219
- * Most of the condition can be evaluated at translation time.
220
- * Test for EL2 present, and defer test for SEL2 to runtime.
221
- */
222
- if (s->current_el <= 1 && arm_dc_feature(s, ARM_FEATURE_EL2)) {
223
- gen_helper_vesb(cpu_env);
224
- }
225
- }
226
- break;
227
- case 0b11000: /* PACIAZ */
228
- if (s->pauth_active) {
229
- gen_helper_pacia(cpu_X[30], cpu_env, cpu_X[30],
230
- tcg_constant_i64(0));
231
- }
232
- break;
233
- case 0b11001: /* PACIASP */
234
- if (s->pauth_active) {
235
- gen_helper_pacia(cpu_X[30], cpu_env, cpu_X[30], cpu_X[31]);
236
- }
237
- break;
238
- case 0b11010: /* PACIBZ */
239
- if (s->pauth_active) {
240
- gen_helper_pacib(cpu_X[30], cpu_env, cpu_X[30],
241
- tcg_constant_i64(0));
242
- }
243
- break;
244
- case 0b11011: /* PACIBSP */
245
- if (s->pauth_active) {
246
- gen_helper_pacib(cpu_X[30], cpu_env, cpu_X[30], cpu_X[31]);
247
- }
248
- break;
249
- case 0b11100: /* AUTIAZ */
250
- if (s->pauth_active) {
251
- gen_helper_autia(cpu_X[30], cpu_env, cpu_X[30],
252
- tcg_constant_i64(0));
253
- }
254
- break;
255
- case 0b11101: /* AUTIASP */
256
- if (s->pauth_active) {
257
- gen_helper_autia(cpu_X[30], cpu_env, cpu_X[30], cpu_X[31]);
258
- }
259
- break;
260
- case 0b11110: /* AUTIBZ */
261
- if (s->pauth_active) {
262
- gen_helper_autib(cpu_X[30], cpu_env, cpu_X[30],
263
- tcg_constant_i64(0));
264
- }
265
- break;
266
- case 0b11111: /* AUTIBSP */
267
- if (s->pauth_active) {
268
- gen_helper_autib(cpu_X[30], cpu_env, cpu_X[30], cpu_X[31]);
269
- }
270
- break;
271
- default:
272
- /* default specified as NOP equivalent */
273
- break;
274
}
275
+ return true;
276
+}
277
+
278
+static bool trans_PACIAZ(DisasContext *s, arg_PACIAZ *a)
279
+{
280
+ if (s->pauth_active) {
281
+ gen_helper_pacia(cpu_X[30], cpu_env, cpu_X[30], tcg_constant_i64(0));
282
+ }
283
+ return true;
284
+}
285
+
286
+static bool trans_PACIASP(DisasContext *s, arg_PACIASP *a)
287
+{
288
+ if (s->pauth_active) {
289
+ gen_helper_pacia(cpu_X[30], cpu_env, cpu_X[30], cpu_X[31]);
290
+ }
291
+ return true;
292
+}
293
+
294
+static bool trans_PACIBZ(DisasContext *s, arg_PACIBZ *a)
295
+{
296
+ if (s->pauth_active) {
297
+ gen_helper_pacib(cpu_X[30], cpu_env, cpu_X[30], tcg_constant_i64(0));
298
+ }
299
+ return true;
300
+}
301
+
302
+static bool trans_PACIBSP(DisasContext *s, arg_PACIBSP *a)
303
+{
304
+ if (s->pauth_active) {
305
+ gen_helper_pacib(cpu_X[30], cpu_env, cpu_X[30], cpu_X[31]);
306
+ }
307
+ return true;
308
+}
309
+
310
+static bool trans_AUTIAZ(DisasContext *s, arg_AUTIAZ *a)
311
+{
312
+ if (s->pauth_active) {
313
+ gen_helper_autia(cpu_X[30], cpu_env, cpu_X[30], tcg_constant_i64(0));
314
+ }
315
+ return true;
316
+}
317
+
318
+static bool trans_AUTIASP(DisasContext *s, arg_AUTIASP *a)
319
+{
320
+ if (s->pauth_active) {
321
+ gen_helper_autia(cpu_X[30], cpu_env, cpu_X[30], cpu_X[31]);
322
+ }
323
+ return true;
324
+}
325
+
326
+static bool trans_AUTIBZ(DisasContext *s, arg_AUTIBZ *a)
327
+{
328
+ if (s->pauth_active) {
329
+ gen_helper_autib(cpu_X[30], cpu_env, cpu_X[30], tcg_constant_i64(0));
330
+ }
331
+ return true;
332
+}
333
+
334
+static bool trans_AUTIBSP(DisasContext *s, arg_AUTIBSP *a)
335
+{
336
+ if (s->pauth_active) {
337
+ gen_helper_autib(cpu_X[30], cpu_env, cpu_X[30], cpu_X[31]);
338
+ }
339
+ return true;
340
}
341
342
static void gen_clrex(DisasContext *s, uint32_t insn)
343
@@ -XXX,XX +XXX,XX @@ static void disas_system(DisasContext *s, uint32_t insn)
344
return;
345
}
346
switch (crn) {
347
- case 2: /* HINT (including allocated hints like NOP, YIELD, etc) */
348
- handle_hint(s, insn, op1, op2, crm);
349
- break;
350
case 3: /* CLREX, DSB, DMB, ISB */
351
handle_sync(s, insn, op1, op2, crm);
352
break;
353
--
354
2.34.1
diff view generated by jsdifflib
1
From: Roman Bolshakov <r.bolshakov@yadro.com>
1
Convert the insns in the "Barriers" instruction class to
2
decodetree: CLREX, DSB, DMB, ISB and SB.
2
3
3
ui/cocoa.m:1188:44: warning: 'openFile:' is deprecated: first deprecated in macOS 11.0 - Use -[NSWorkspace openURL:] instead.
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
[-Wdeprecated-declarations]
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
if ([[NSWorkspace sharedWorkspace] openFile: full_file_path] == YES) {
6
Message-id: 20230602155223.2040685-4-peter.maydell@linaro.org
6
^
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
7
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/AppKit.framework/Headers/NSWorkspace.h:350:1: note:
8
---
8
'openFile:' has been explicitly marked deprecated here
9
target/arm/tcg/a64.decode | 7 +++
9
- (BOOL)openFile:(NSString *)fullPath API_DEPRECATED("Use -[NSWorkspace openURL:] instead.", macos(10.0, 11.0));
10
target/arm/tcg/translate-a64.c | 92 ++++++++++++++--------------------
10
^
11
2 files changed, 46 insertions(+), 53 deletions(-)
11
12
12
Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
13
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
13
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
14
Message-id: 20210102150718.47618-1-r.bolshakov@yadro.com
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
---
17
ui/cocoa.m | 5 ++++-
18
1 file changed, 4 insertions(+), 1 deletion(-)
19
20
diff --git a/ui/cocoa.m b/ui/cocoa.m
21
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
22
--- a/ui/cocoa.m
15
--- a/target/arm/tcg/a64.decode
23
+++ b/ui/cocoa.m
16
+++ b/target/arm/tcg/a64.decode
24
@@ -XXX,XX +XXX,XX @@ QemuCocoaView *cocoaView;
17
@@ -XXX,XX +XXX,XX @@ ERETA 1101011 0100 11111 00001 m:1 11111 11111 &reta # ERETAA, ERETAB
25
/* Where to look for local files */
18
# that isn't specifically allocated to an instruction must NOP
26
NSString *path_array[] = {@"../share/doc/qemu/", @"../doc/qemu/", @"docs/"};
19
NOP 1101 0101 0000 0011 0010 ---- --- 11111
27
NSString *full_file_path;
20
}
28
+ NSURL *full_file_url;
21
+
29
22
+# Barriers
30
/* iterate thru the possible paths until the file is found */
23
+
31
int index;
24
+CLREX 1101 0101 0000 0011 0011 ---- 010 11111
32
@@ -XXX,XX +XXX,XX @@ QemuCocoaView *cocoaView;
25
+DSB_DMB 1101 0101 0000 0011 0011 domain:2 types:2 10- 11111
33
full_file_path = [full_file_path stringByDeletingLastPathComponent];
26
+ISB 1101 0101 0000 0011 0011 ---- 110 11111
34
full_file_path = [NSString stringWithFormat: @"%@/%@%@", full_file_path,
27
+SB 1101 0101 0000 0011 0011 0000 111 11111
35
path_array[index], filename];
28
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
36
- if ([[NSWorkspace sharedWorkspace] openFile: full_file_path] == YES) {
29
index XXXXXXX..XXXXXXX 100644
37
+ full_file_url = [NSURL fileURLWithPath: full_file_path
30
--- a/target/arm/tcg/translate-a64.c
38
+ isDirectory: false];
31
+++ b/target/arm/tcg/translate-a64.c
39
+ if ([[NSWorkspace sharedWorkspace] openURL: full_file_url] == YES) {
32
@@ -XXX,XX +XXX,XX @@ static bool trans_AUTIBSP(DisasContext *s, arg_AUTIBSP *a)
33
return true;
34
}
35
36
-static void gen_clrex(DisasContext *s, uint32_t insn)
37
+static bool trans_CLREX(DisasContext *s, arg_CLREX *a)
38
{
39
tcg_gen_movi_i64(cpu_exclusive_addr, -1);
40
+ return true;
41
}
42
43
-/* CLREX, DSB, DMB, ISB */
44
-static void handle_sync(DisasContext *s, uint32_t insn,
45
- unsigned int op1, unsigned int op2, unsigned int crm)
46
+static bool trans_DSB_DMB(DisasContext *s, arg_DSB_DMB *a)
47
{
48
+ /* We handle DSB and DMB the same way */
49
TCGBar bar;
50
51
- if (op1 != 3) {
52
- unallocated_encoding(s);
53
- return;
54
+ switch (a->types) {
55
+ case 1: /* MBReqTypes_Reads */
56
+ bar = TCG_BAR_SC | TCG_MO_LD_LD | TCG_MO_LD_ST;
57
+ break;
58
+ case 2: /* MBReqTypes_Writes */
59
+ bar = TCG_BAR_SC | TCG_MO_ST_ST;
60
+ break;
61
+ default: /* MBReqTypes_All */
62
+ bar = TCG_BAR_SC | TCG_MO_ALL;
63
+ break;
64
}
65
+ tcg_gen_mb(bar);
66
+ return true;
67
+}
68
69
- switch (op2) {
70
- case 2: /* CLREX */
71
- gen_clrex(s, insn);
72
- return;
73
- case 4: /* DSB */
74
- case 5: /* DMB */
75
- switch (crm & 3) {
76
- case 1: /* MBReqTypes_Reads */
77
- bar = TCG_BAR_SC | TCG_MO_LD_LD | TCG_MO_LD_ST;
78
- break;
79
- case 2: /* MBReqTypes_Writes */
80
- bar = TCG_BAR_SC | TCG_MO_ST_ST;
81
- break;
82
- default: /* MBReqTypes_All */
83
- bar = TCG_BAR_SC | TCG_MO_ALL;
84
- break;
85
- }
86
- tcg_gen_mb(bar);
87
- return;
88
- case 6: /* ISB */
89
- /* We need to break the TB after this insn to execute
90
- * a self-modified code correctly and also to take
91
- * any pending interrupts immediately.
92
- */
93
- reset_btype(s);
94
- gen_goto_tb(s, 0, 4);
95
- return;
96
+static bool trans_ISB(DisasContext *s, arg_ISB *a)
97
+{
98
+ /*
99
+ * We need to break the TB after this insn to execute
100
+ * self-modifying code correctly and also to take
101
+ * any pending interrupts immediately.
102
+ */
103
+ reset_btype(s);
104
+ gen_goto_tb(s, 0, 4);
105
+ return true;
106
+}
107
108
- case 7: /* SB */
109
- if (crm != 0 || !dc_isar_feature(aa64_sb, s)) {
110
- goto do_unallocated;
111
- }
112
- /*
113
- * TODO: There is no speculation barrier opcode for TCG;
114
- * MB and end the TB instead.
115
- */
116
- tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
117
- gen_goto_tb(s, 0, 4);
118
- return;
119
-
120
- default:
121
- do_unallocated:
122
- unallocated_encoding(s);
123
- return;
124
+static bool trans_SB(DisasContext *s, arg_SB *a)
125
+{
126
+ if (!dc_isar_feature(aa64_sb, s)) {
127
+ return false;
128
}
129
+ /*
130
+ * TODO: There is no speculation barrier opcode for TCG;
131
+ * MB and end the TB instead.
132
+ */
133
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
134
+ gen_goto_tb(s, 0, 4);
135
+ return true;
136
}
137
138
static void gen_xaflag(void)
139
@@ -XXX,XX +XXX,XX @@ static void disas_system(DisasContext *s, uint32_t insn)
40
return;
140
return;
41
}
141
}
42
}
142
switch (crn) {
143
- case 3: /* CLREX, DSB, DMB, ISB */
144
- handle_sync(s, insn, op1, op2, crm);
145
- break;
146
case 4: /* MSR (immediate) */
147
handle_msr_i(s, insn, op1, op2, crm);
148
break;
43
--
149
--
44
2.20.1
150
2.34.1
45
151
46
152
diff view generated by jsdifflib
1
From: Hao Wu <wuhaotsh@google.com>
1
Convert the CFINV, XAFLAG and AXFLAG insns to decodetree.
2
The old decoder handles these in handle_msr_i(), but
3
the architecture defines them as separate instructions
4
from MSR (immediate).
2
5
3
This patch allows NPCM7XX CLK module to compute clocks that are used by
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
other NPCM7XX modules.
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20230602155223.2040685-5-peter.maydell@linaro.org
9
---
10
target/arm/tcg/a64.decode | 6 ++++
11
target/arm/tcg/translate-a64.c | 53 +++++++++++++++++-----------------
12
2 files changed, 32 insertions(+), 27 deletions(-)
5
13
6
Add a new struct NPCM7xxClockConverterState which represents a
14
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
7
single converter. Each clock converter in CLK module represents one
8
converter in NPCM7XX CLK Module(PLL, SEL or Divider). Each converter
9
takes one or more input clocks and converts them into one output clock.
10
They form a clock hierarchy in the CLK module and are responsible for
11
outputing clocks for various other modules in an NPCM7XX SoC.
12
13
Each converter has a function pointer called "convert" which represents
14
the unique logic for that converter.
15
16
The clock contains two initialization information: ConverterInitInfo and
17
ConverterConnectionInfo. They represent the vertices and edges in the
18
clock diagram respectively.
19
20
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
21
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
22
Signed-off-by: Hao Wu <wuhaotsh@google.com>
23
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
24
Message-id: 20210108190945.949196-2-wuhaotsh@google.com
25
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
26
---
27
include/hw/misc/npcm7xx_clk.h | 140 +++++-
28
hw/misc/npcm7xx_clk.c | 805 +++++++++++++++++++++++++++++++++-
29
2 files changed, 932 insertions(+), 13 deletions(-)
30
31
diff --git a/include/hw/misc/npcm7xx_clk.h b/include/hw/misc/npcm7xx_clk.h
32
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
33
--- a/include/hw/misc/npcm7xx_clk.h
16
--- a/target/arm/tcg/a64.decode
34
+++ b/include/hw/misc/npcm7xx_clk.h
17
+++ b/target/arm/tcg/a64.decode
35
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@ CLREX 1101 0101 0000 0011 0011 ---- 010 11111
36
#define NPCM7XX_CLK_H
19
DSB_DMB 1101 0101 0000 0011 0011 domain:2 types:2 10- 11111
37
20
ISB 1101 0101 0000 0011 0011 ---- 110 11111
38
#include "exec/memory.h"
21
SB 1101 0101 0000 0011 0011 0000 111 11111
39
+#include "hw/clock.h"
40
#include "hw/sysbus.h"
41
42
/*
43
@@ -XXX,XX +XXX,XX @@
44
45
#define NPCM7XX_WATCHDOG_RESET_GPIO_IN "npcm7xx-clk-watchdog-reset-gpio-in"
46
47
-typedef struct NPCM7xxCLKState {
48
+/* Maximum amount of clock inputs in a SEL module. */
49
+#define NPCM7XX_CLK_SEL_MAX_INPUT 5
50
+
22
+
51
+/* PLLs in CLK module. */
23
+# PSTATE
52
+typedef enum NPCM7xxClockPLL {
53
+ NPCM7XX_CLOCK_PLL0,
54
+ NPCM7XX_CLOCK_PLL1,
55
+ NPCM7XX_CLOCK_PLL2,
56
+ NPCM7XX_CLOCK_PLLG,
57
+ NPCM7XX_CLOCK_NR_PLLS,
58
+} NPCM7xxClockPLL;
59
+
24
+
60
+/* SEL/MUX in CLK module. */
25
+CFINV 1101 0101 0000 0 000 0100 0000 000 11111
61
+typedef enum NPCM7xxClockSEL {
26
+XAFLAG 1101 0101 0000 0 000 0100 0000 001 11111
62
+ NPCM7XX_CLOCK_PIXCKSEL,
27
+AXFLAG 1101 0101 0000 0 000 0100 0000 010 11111
63
+ NPCM7XX_CLOCK_MCCKSEL,
28
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
64
+ NPCM7XX_CLOCK_CPUCKSEL,
29
index XXXXXXX..XXXXXXX 100644
65
+ NPCM7XX_CLOCK_CLKOUTSEL,
30
--- a/target/arm/tcg/translate-a64.c
66
+ NPCM7XX_CLOCK_UARTCKSEL,
31
+++ b/target/arm/tcg/translate-a64.c
67
+ NPCM7XX_CLOCK_TIMCKSEL,
32
@@ -XXX,XX +XXX,XX @@ static bool trans_SB(DisasContext *s, arg_SB *a)
68
+ NPCM7XX_CLOCK_SDCKSEL,
33
return true;
69
+ NPCM7XX_CLOCK_GFXMSEL,
34
}
70
+ NPCM7XX_CLOCK_SUCKSEL,
35
71
+ NPCM7XX_CLOCK_NR_SELS,
36
-static void gen_xaflag(void)
72
+} NPCM7xxClockSEL;
37
+static bool trans_CFINV(DisasContext *s, arg_CFINV *a)
38
{
39
- TCGv_i32 z = tcg_temp_new_i32();
40
+ if (!dc_isar_feature(aa64_condm_4, s)) {
41
+ return false;
42
+ }
43
+ tcg_gen_xori_i32(cpu_CF, cpu_CF, 1);
44
+ return true;
45
+}
73
+
46
+
74
+/* Dividers in CLK module. */
47
+static bool trans_XAFLAG(DisasContext *s, arg_XAFLAG *a)
75
+typedef enum NPCM7xxClockDivider {
48
+{
76
+ NPCM7XX_CLOCK_PLL1D2, /* PLL1/2 */
49
+ TCGv_i32 z;
77
+ NPCM7XX_CLOCK_PLL2D2, /* PLL2/2 */
78
+ NPCM7XX_CLOCK_MC_DIVIDER,
79
+ NPCM7XX_CLOCK_AXI_DIVIDER,
80
+ NPCM7XX_CLOCK_AHB_DIVIDER,
81
+ NPCM7XX_CLOCK_AHB3_DIVIDER,
82
+ NPCM7XX_CLOCK_SPI0_DIVIDER,
83
+ NPCM7XX_CLOCK_SPIX_DIVIDER,
84
+ NPCM7XX_CLOCK_APB1_DIVIDER,
85
+ NPCM7XX_CLOCK_APB2_DIVIDER,
86
+ NPCM7XX_CLOCK_APB3_DIVIDER,
87
+ NPCM7XX_CLOCK_APB4_DIVIDER,
88
+ NPCM7XX_CLOCK_APB5_DIVIDER,
89
+ NPCM7XX_CLOCK_CLKOUT_DIVIDER,
90
+ NPCM7XX_CLOCK_UART_DIVIDER,
91
+ NPCM7XX_CLOCK_TIMER_DIVIDER,
92
+ NPCM7XX_CLOCK_ADC_DIVIDER,
93
+ NPCM7XX_CLOCK_MMC_DIVIDER,
94
+ NPCM7XX_CLOCK_SDHC_DIVIDER,
95
+ NPCM7XX_CLOCK_GFXM_DIVIDER, /* divide by 3 */
96
+ NPCM7XX_CLOCK_UTMI_DIVIDER,
97
+ NPCM7XX_CLOCK_NR_DIVIDERS,
98
+} NPCM7xxClockConverter;
99
+
50
+
100
+typedef struct NPCM7xxCLKState NPCM7xxCLKState;
51
+ if (!dc_isar_feature(aa64_condm_5, s)) {
101
+
52
+ return false;
102
+/**
103
+ * struct NPCM7xxClockPLLState - A PLL module in CLK module.
104
+ * @name: The name of the module.
105
+ * @clk: The CLK module that owns this module.
106
+ * @clock_in: The input clock of this module.
107
+ * @clock_out: The output clock of this module.
108
+ * @reg: The control registers for this PLL module.
109
+ */
110
+typedef struct NPCM7xxClockPLLState {
111
+ DeviceState parent;
112
+
113
+ const char *name;
114
+ NPCM7xxCLKState *clk;
115
+ Clock *clock_in;
116
+ Clock *clock_out;
117
+
118
+ int reg;
119
+} NPCM7xxClockPLLState;
120
+
121
+/**
122
+ * struct NPCM7xxClockSELState - A SEL module in CLK module.
123
+ * @name: The name of the module.
124
+ * @clk: The CLK module that owns this module.
125
+ * @input_size: The size of inputs of this module.
126
+ * @clock_in: The input clocks of this module.
127
+ * @clock_out: The output clocks of this module.
128
+ * @offset: The offset of this module in the control register.
129
+ * @len: The length of this module in the control register.
130
+ */
131
+typedef struct NPCM7xxClockSELState {
132
+ DeviceState parent;
133
+
134
+ const char *name;
135
+ NPCM7xxCLKState *clk;
136
+ uint8_t input_size;
137
+ Clock *clock_in[NPCM7XX_CLK_SEL_MAX_INPUT];
138
+ Clock *clock_out;
139
+
140
+ int offset;
141
+ int len;
142
+} NPCM7xxClockSELState;
143
+
144
+/**
145
+ * struct NPCM7xxClockDividerState - A Divider module in CLK module.
146
+ * @name: The name of the module.
147
+ * @clk: The CLK module that owns this module.
148
+ * @clock_in: The input clock of this module.
149
+ * @clock_out: The output clock of this module.
150
+ * @divide: The function the divider uses to divide the input.
151
+ * @reg: The index of the control register that contains the divisor.
152
+ * @offset: The offset of the divisor in the control register.
153
+ * @len: The length of the divisor in the control register.
154
+ * @divisor: The divisor for a constant divisor
155
+ */
156
+typedef struct NPCM7xxClockDividerState {
157
+ DeviceState parent;
158
+
159
+ const char *name;
160
+ NPCM7xxCLKState *clk;
161
+ Clock *clock_in;
162
+ Clock *clock_out;
163
+
164
+ uint32_t (*divide)(struct NPCM7xxClockDividerState *s);
165
+ union {
166
+ struct {
167
+ int reg;
168
+ int offset;
169
+ int len;
170
+ };
171
+ int divisor;
172
+ };
173
+} NPCM7xxClockDividerState;
174
+
175
+struct NPCM7xxCLKState {
176
SysBusDevice parent;
177
178
MemoryRegion iomem;
179
180
+ /* Clock converters */
181
+ NPCM7xxClockPLLState plls[NPCM7XX_CLOCK_NR_PLLS];
182
+ NPCM7xxClockSELState sels[NPCM7XX_CLOCK_NR_SELS];
183
+ NPCM7xxClockDividerState dividers[NPCM7XX_CLOCK_NR_DIVIDERS];
184
+
185
uint32_t regs[NPCM7XX_CLK_NR_REGS];
186
187
/* Time reference for SECCNT and CNTR25M, initialized by power on reset */
188
int64_t ref_ns;
189
-} NPCM7xxCLKState;
190
+
191
+ /* The incoming reference clock. */
192
+ Clock *clkref;
193
+};
194
195
#define TYPE_NPCM7XX_CLK "npcm7xx-clk"
196
#define NPCM7XX_CLK(obj) OBJECT_CHECK(NPCM7xxCLKState, (obj), TYPE_NPCM7XX_CLK)
197
diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c
198
index XXXXXXX..XXXXXXX 100644
199
--- a/hw/misc/npcm7xx_clk.c
200
+++ b/hw/misc/npcm7xx_clk.c
201
@@ -XXX,XX +XXX,XX @@
202
203
#include "hw/misc/npcm7xx_clk.h"
204
#include "hw/timer/npcm7xx_timer.h"
205
+#include "hw/qdev-clock.h"
206
#include "migration/vmstate.h"
207
#include "qemu/error-report.h"
208
#include "qemu/log.h"
209
@@ -XXX,XX +XXX,XX @@
210
#include "trace.h"
211
#include "sysemu/watchdog.h"
212
213
+/*
214
+ * The reference clock hz, and the SECCNT and CNTR25M registers in this module,
215
+ * is always 25 MHz.
216
+ */
217
+#define NPCM7XX_CLOCK_REF_HZ (25000000)
218
+
219
+/* Register Field Definitions */
220
+#define NPCM7XX_CLK_WDRCR_CA9C BIT(0) /* Cortex A9 Cores */
221
+
222
#define PLLCON_LOKI BIT(31)
223
#define PLLCON_LOKS BIT(30)
224
#define PLLCON_PWDEN BIT(12)
225
+#define PLLCON_FBDV(con) extract32((con), 16, 12)
226
+#define PLLCON_OTDV2(con) extract32((con), 13, 3)
227
+#define PLLCON_OTDV1(con) extract32((con), 8, 3)
228
+#define PLLCON_INDV(con) extract32((con), 0, 6)
229
230
enum NPCM7xxCLKRegisters {
231
NPCM7XX_CLK_CLKEN1,
232
@@ -XXX,XX +XXX,XX @@ static const uint32_t cold_reset_values[NPCM7XX_CLK_NR_REGS] = {
233
[NPCM7XX_CLK_AHBCKFI] = 0x000000c8,
234
};
235
236
-/* Register Field Definitions */
237
-#define NPCM7XX_CLK_WDRCR_CA9C BIT(0) /* Cortex A9 Cores */
238
-
239
/* The number of watchdogs that can trigger a reset. */
240
#define NPCM7XX_NR_WATCHDOGS (3)
241
242
+/* Clock converter functions */
243
+
244
+#define TYPE_NPCM7XX_CLOCK_PLL "npcm7xx-clock-pll"
245
+#define NPCM7XX_CLOCK_PLL(obj) OBJECT_CHECK(NPCM7xxClockPLLState, \
246
+ (obj), TYPE_NPCM7XX_CLOCK_PLL)
247
+#define TYPE_NPCM7XX_CLOCK_SEL "npcm7xx-clock-sel"
248
+#define NPCM7XX_CLOCK_SEL(obj) OBJECT_CHECK(NPCM7xxClockSELState, \
249
+ (obj), TYPE_NPCM7XX_CLOCK_SEL)
250
+#define TYPE_NPCM7XX_CLOCK_DIVIDER "npcm7xx-clock-divider"
251
+#define NPCM7XX_CLOCK_DIVIDER(obj) OBJECT_CHECK(NPCM7xxClockDividerState, \
252
+ (obj), TYPE_NPCM7XX_CLOCK_DIVIDER)
253
+
254
+static void npcm7xx_clk_update_pll(void *opaque)
255
+{
256
+ NPCM7xxClockPLLState *s = opaque;
257
+ uint32_t con = s->clk->regs[s->reg];
258
+ uint64_t freq;
259
+
260
+ /* The PLL is grounded if it is not locked yet. */
261
+ if (con & PLLCON_LOKI) {
262
+ freq = clock_get_hz(s->clock_in);
263
+ freq *= PLLCON_FBDV(con);
264
+ freq /= PLLCON_INDV(con) * PLLCON_OTDV1(con) * PLLCON_OTDV2(con);
265
+ } else {
266
+ freq = 0;
267
+ }
53
+ }
268
+
54
+
269
+ clock_update_hz(s->clock_out, freq);
55
+ z = tcg_temp_new_i32();
270
+}
56
57
tcg_gen_setcondi_i32(TCG_COND_EQ, z, cpu_ZF, 0);
58
59
@@ -XXX,XX +XXX,XX @@ static void gen_xaflag(void)
60
61
/* C | Z */
62
tcg_gen_or_i32(cpu_CF, cpu_CF, z);
271
+
63
+
272
+static void npcm7xx_clk_update_sel(void *opaque)
64
+ return true;
273
+{
65
}
274
+ NPCM7xxClockSELState *s = opaque;
66
275
+ uint32_t index = extract32(s->clk->regs[NPCM7XX_CLK_CLKSEL], s->offset,
67
-static void gen_axflag(void)
276
+ s->len);
68
+static bool trans_AXFLAG(DisasContext *s, arg_AXFLAG *a)
277
+
278
+ if (index >= s->input_size) {
279
+ qemu_log_mask(LOG_GUEST_ERROR,
280
+ "%s: SEL index: %u out of range\n",
281
+ __func__, index);
282
+ index = 0;
283
+ }
284
+ clock_update_hz(s->clock_out, clock_get_hz(s->clock_in[index]));
285
+}
286
+
287
+static void npcm7xx_clk_update_divider(void *opaque)
288
+{
289
+ NPCM7xxClockDividerState *s = opaque;
290
+ uint32_t freq;
291
+
292
+ freq = s->divide(s);
293
+ clock_update_hz(s->clock_out, freq);
294
+}
295
+
296
+static uint32_t divide_by_constant(NPCM7xxClockDividerState *s)
297
+{
298
+ return clock_get_hz(s->clock_in) / s->divisor;
299
+}
300
+
301
+static uint32_t divide_by_reg_divisor(NPCM7xxClockDividerState *s)
302
+{
303
+ return clock_get_hz(s->clock_in) /
304
+ (extract32(s->clk->regs[s->reg], s->offset, s->len) + 1);
305
+}
306
+
307
+static uint32_t divide_by_reg_divisor_times_2(NPCM7xxClockDividerState *s)
308
+{
309
+ return divide_by_reg_divisor(s) / 2;
310
+}
311
+
312
+static uint32_t shift_by_reg_divisor(NPCM7xxClockDividerState *s)
313
+{
314
+ return clock_get_hz(s->clock_in) >>
315
+ extract32(s->clk->regs[s->reg], s->offset, s->len);
316
+}
317
+
318
+static NPCM7xxClockPLL find_pll_by_reg(enum NPCM7xxCLKRegisters reg)
319
+{
320
+ switch (reg) {
321
+ case NPCM7XX_CLK_PLLCON0:
322
+ return NPCM7XX_CLOCK_PLL0;
323
+ case NPCM7XX_CLK_PLLCON1:
324
+ return NPCM7XX_CLOCK_PLL1;
325
+ case NPCM7XX_CLK_PLLCON2:
326
+ return NPCM7XX_CLOCK_PLL2;
327
+ case NPCM7XX_CLK_PLLCONG:
328
+ return NPCM7XX_CLOCK_PLLG;
329
+ default:
330
+ g_assert_not_reached();
331
+ }
332
+}
333
+
334
+static void npcm7xx_clk_update_all_plls(NPCM7xxCLKState *clk)
335
+{
336
+ int i;
337
+
338
+ for (i = 0; i < NPCM7XX_CLOCK_NR_PLLS; ++i) {
339
+ npcm7xx_clk_update_pll(&clk->plls[i]);
340
+ }
341
+}
342
+
343
+static void npcm7xx_clk_update_all_sels(NPCM7xxCLKState *clk)
344
+{
345
+ int i;
346
+
347
+ for (i = 0; i < NPCM7XX_CLOCK_NR_SELS; ++i) {
348
+ npcm7xx_clk_update_sel(&clk->sels[i]);
349
+ }
350
+}
351
+
352
+static void npcm7xx_clk_update_all_dividers(NPCM7xxCLKState *clk)
353
+{
354
+ int i;
355
+
356
+ for (i = 0; i < NPCM7XX_CLOCK_NR_DIVIDERS; ++i) {
357
+ npcm7xx_clk_update_divider(&clk->dividers[i]);
358
+ }
359
+}
360
+
361
+static void npcm7xx_clk_update_all_clocks(NPCM7xxCLKState *clk)
362
+{
363
+ clock_update_hz(clk->clkref, NPCM7XX_CLOCK_REF_HZ);
364
+ npcm7xx_clk_update_all_plls(clk);
365
+ npcm7xx_clk_update_all_sels(clk);
366
+ npcm7xx_clk_update_all_dividers(clk);
367
+}
368
+
369
+/* Types of clock sources. */
370
+typedef enum ClockSrcType {
371
+ CLKSRC_REF,
372
+ CLKSRC_PLL,
373
+ CLKSRC_SEL,
374
+ CLKSRC_DIV,
375
+} ClockSrcType;
376
+
377
+typedef struct PLLInitInfo {
378
+ const char *name;
379
+ ClockSrcType src_type;
380
+ int src_index;
381
+ int reg;
382
+ const char *public_name;
383
+} PLLInitInfo;
384
+
385
+typedef struct SELInitInfo {
386
+ const char *name;
387
+ uint8_t input_size;
388
+ ClockSrcType src_type[NPCM7XX_CLK_SEL_MAX_INPUT];
389
+ int src_index[NPCM7XX_CLK_SEL_MAX_INPUT];
390
+ int offset;
391
+ int len;
392
+ const char *public_name;
393
+} SELInitInfo;
394
+
395
+typedef struct DividerInitInfo {
396
+ const char *name;
397
+ ClockSrcType src_type;
398
+ int src_index;
399
+ uint32_t (*divide)(NPCM7xxClockDividerState *s);
400
+ int reg; /* not used when type == CONSTANT */
401
+ int offset; /* not used when type == CONSTANT */
402
+ int len; /* not used when type == CONSTANT */
403
+ int divisor; /* used only when type == CONSTANT */
404
+ const char *public_name;
405
+} DividerInitInfo;
406
+
407
+static const PLLInitInfo pll_init_info_list[] = {
408
+ [NPCM7XX_CLOCK_PLL0] = {
409
+ .name = "pll0",
410
+ .src_type = CLKSRC_REF,
411
+ .reg = NPCM7XX_CLK_PLLCON0,
412
+ },
413
+ [NPCM7XX_CLOCK_PLL1] = {
414
+ .name = "pll1",
415
+ .src_type = CLKSRC_REF,
416
+ .reg = NPCM7XX_CLK_PLLCON1,
417
+ },
418
+ [NPCM7XX_CLOCK_PLL2] = {
419
+ .name = "pll2",
420
+ .src_type = CLKSRC_REF,
421
+ .reg = NPCM7XX_CLK_PLLCON2,
422
+ },
423
+ [NPCM7XX_CLOCK_PLLG] = {
424
+ .name = "pllg",
425
+ .src_type = CLKSRC_REF,
426
+ .reg = NPCM7XX_CLK_PLLCONG,
427
+ },
428
+};
429
+
430
+static const SELInitInfo sel_init_info_list[] = {
431
+ [NPCM7XX_CLOCK_PIXCKSEL] = {
432
+ .name = "pixcksel",
433
+ .input_size = 2,
434
+ .src_type = {CLKSRC_PLL, CLKSRC_REF},
435
+ .src_index = {NPCM7XX_CLOCK_PLLG, 0},
436
+ .offset = 5,
437
+ .len = 1,
438
+ .public_name = "pixel-clock",
439
+ },
440
+ [NPCM7XX_CLOCK_MCCKSEL] = {
441
+ .name = "mccksel",
442
+ .input_size = 4,
443
+ .src_type = {CLKSRC_DIV, CLKSRC_REF, CLKSRC_REF,
444
+ /*MCBPCK, shouldn't be used in normal operation*/
445
+ CLKSRC_REF},
446
+ .src_index = {NPCM7XX_CLOCK_PLL1D2, 0, 0, 0},
447
+ .offset = 12,
448
+ .len = 2,
449
+ .public_name = "mc-phy-clock",
450
+ },
451
+ [NPCM7XX_CLOCK_CPUCKSEL] = {
452
+ .name = "cpucksel",
453
+ .input_size = 4,
454
+ .src_type = {CLKSRC_PLL, CLKSRC_DIV, CLKSRC_REF,
455
+ /*SYSBPCK, shouldn't be used in normal operation*/
456
+ CLKSRC_REF},
457
+ .src_index = {NPCM7XX_CLOCK_PLL0, NPCM7XX_CLOCK_PLL1D2, 0, 0},
458
+ .offset = 0,
459
+ .len = 2,
460
+ .public_name = "system-clock",
461
+ },
462
+ [NPCM7XX_CLOCK_CLKOUTSEL] = {
463
+ .name = "clkoutsel",
464
+ .input_size = 5,
465
+ .src_type = {CLKSRC_PLL, CLKSRC_DIV, CLKSRC_REF,
466
+ CLKSRC_PLL, CLKSRC_DIV},
467
+ .src_index = {NPCM7XX_CLOCK_PLL0, NPCM7XX_CLOCK_PLL1D2, 0,
468
+ NPCM7XX_CLOCK_PLLG, NPCM7XX_CLOCK_PLL2D2},
469
+ .offset = 18,
470
+ .len = 3,
471
+ .public_name = "tock",
472
+ },
473
+ [NPCM7XX_CLOCK_UARTCKSEL] = {
474
+ .name = "uartcksel",
475
+ .input_size = 4,
476
+ .src_type = {CLKSRC_PLL, CLKSRC_DIV, CLKSRC_REF, CLKSRC_DIV},
477
+ .src_index = {NPCM7XX_CLOCK_PLL0, NPCM7XX_CLOCK_PLL1D2, 0,
478
+ NPCM7XX_CLOCK_PLL2D2},
479
+ .offset = 8,
480
+ .len = 2,
481
+ },
482
+ [NPCM7XX_CLOCK_TIMCKSEL] = {
483
+ .name = "timcksel",
484
+ .input_size = 4,
485
+ .src_type = {CLKSRC_PLL, CLKSRC_DIV, CLKSRC_REF, CLKSRC_DIV},
486
+ .src_index = {NPCM7XX_CLOCK_PLL0, NPCM7XX_CLOCK_PLL1D2, 0,
487
+ NPCM7XX_CLOCK_PLL2D2},
488
+ .offset = 14,
489
+ .len = 2,
490
+ },
491
+ [NPCM7XX_CLOCK_SDCKSEL] = {
492
+ .name = "sdcksel",
493
+ .input_size = 4,
494
+ .src_type = {CLKSRC_PLL, CLKSRC_DIV, CLKSRC_REF, CLKSRC_DIV},
495
+ .src_index = {NPCM7XX_CLOCK_PLL0, NPCM7XX_CLOCK_PLL1D2, 0,
496
+ NPCM7XX_CLOCK_PLL2D2},
497
+ .offset = 6,
498
+ .len = 2,
499
+ },
500
+ [NPCM7XX_CLOCK_GFXMSEL] = {
501
+ .name = "gfxmksel",
502
+ .input_size = 2,
503
+ .src_type = {CLKSRC_REF, CLKSRC_PLL},
504
+ .src_index = {0, NPCM7XX_CLOCK_PLL2},
505
+ .offset = 21,
506
+ .len = 1,
507
+ },
508
+ [NPCM7XX_CLOCK_SUCKSEL] = {
509
+ .name = "sucksel",
510
+ .input_size = 4,
511
+ .src_type = {CLKSRC_PLL, CLKSRC_DIV, CLKSRC_REF, CLKSRC_DIV},
512
+ .src_index = {NPCM7XX_CLOCK_PLL0, NPCM7XX_CLOCK_PLL1D2, 0,
513
+ NPCM7XX_CLOCK_PLL2D2},
514
+ .offset = 10,
515
+ .len = 2,
516
+ },
517
+};
518
+
519
+static const DividerInitInfo divider_init_info_list[] = {
520
+ [NPCM7XX_CLOCK_PLL1D2] = {
521
+ .name = "pll1d2",
522
+ .src_type = CLKSRC_PLL,
523
+ .src_index = NPCM7XX_CLOCK_PLL1,
524
+ .divide = divide_by_constant,
525
+ .divisor = 2,
526
+ },
527
+ [NPCM7XX_CLOCK_PLL2D2] = {
528
+ .name = "pll2d2",
529
+ .src_type = CLKSRC_PLL,
530
+ .src_index = NPCM7XX_CLOCK_PLL2,
531
+ .divide = divide_by_constant,
532
+ .divisor = 2,
533
+ },
534
+ [NPCM7XX_CLOCK_MC_DIVIDER] = {
535
+ .name = "mc-divider",
536
+ .src_type = CLKSRC_SEL,
537
+ .src_index = NPCM7XX_CLOCK_MCCKSEL,
538
+ .divide = divide_by_constant,
539
+ .divisor = 2,
540
+ .public_name = "mc-clock"
541
+ },
542
+ [NPCM7XX_CLOCK_AXI_DIVIDER] = {
543
+ .name = "axi-divider",
544
+ .src_type = CLKSRC_SEL,
545
+ .src_index = NPCM7XX_CLOCK_CPUCKSEL,
546
+ .divide = shift_by_reg_divisor,
547
+ .reg = NPCM7XX_CLK_CLKDIV1,
548
+ .offset = 0,
549
+ .len = 1,
550
+ .public_name = "clk2"
551
+ },
552
+ [NPCM7XX_CLOCK_AHB_DIVIDER] = {
553
+ .name = "ahb-divider",
554
+ .src_type = CLKSRC_DIV,
555
+ .src_index = NPCM7XX_CLOCK_AXI_DIVIDER,
556
+ .divide = divide_by_reg_divisor,
557
+ .reg = NPCM7XX_CLK_CLKDIV1,
558
+ .offset = 26,
559
+ .len = 2,
560
+ .public_name = "clk4"
561
+ },
562
+ [NPCM7XX_CLOCK_AHB3_DIVIDER] = {
563
+ .name = "ahb3-divider",
564
+ .src_type = CLKSRC_DIV,
565
+ .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
566
+ .divide = divide_by_reg_divisor,
567
+ .reg = NPCM7XX_CLK_CLKDIV1,
568
+ .offset = 6,
569
+ .len = 5,
570
+ .public_name = "ahb3-spi3-clock"
571
+ },
572
+ [NPCM7XX_CLOCK_SPI0_DIVIDER] = {
573
+ .name = "spi0-divider",
574
+ .src_type = CLKSRC_DIV,
575
+ .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
576
+ .divide = divide_by_reg_divisor,
577
+ .reg = NPCM7XX_CLK_CLKDIV3,
578
+ .offset = 6,
579
+ .len = 5,
580
+ .public_name = "spi0-clock",
581
+ },
582
+ [NPCM7XX_CLOCK_SPIX_DIVIDER] = {
583
+ .name = "spix-divider",
584
+ .src_type = CLKSRC_DIV,
585
+ .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
586
+ .divide = divide_by_reg_divisor,
587
+ .reg = NPCM7XX_CLK_CLKDIV3,
588
+ .offset = 1,
589
+ .len = 5,
590
+ .public_name = "spix-clock",
591
+ },
592
+ [NPCM7XX_CLOCK_APB1_DIVIDER] = {
593
+ .name = "apb1-divider",
594
+ .src_type = CLKSRC_DIV,
595
+ .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
596
+ .divide = shift_by_reg_divisor,
597
+ .reg = NPCM7XX_CLK_CLKDIV2,
598
+ .offset = 24,
599
+ .len = 2,
600
+ .public_name = "apb1-clock",
601
+ },
602
+ [NPCM7XX_CLOCK_APB2_DIVIDER] = {
603
+ .name = "apb2-divider",
604
+ .src_type = CLKSRC_DIV,
605
+ .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
606
+ .divide = shift_by_reg_divisor,
607
+ .reg = NPCM7XX_CLK_CLKDIV2,
608
+ .offset = 26,
609
+ .len = 2,
610
+ .public_name = "apb2-clock",
611
+ },
612
+ [NPCM7XX_CLOCK_APB3_DIVIDER] = {
613
+ .name = "apb3-divider",
614
+ .src_type = CLKSRC_DIV,
615
+ .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
616
+ .divide = shift_by_reg_divisor,
617
+ .reg = NPCM7XX_CLK_CLKDIV2,
618
+ .offset = 28,
619
+ .len = 2,
620
+ .public_name = "apb3-clock",
621
+ },
622
+ [NPCM7XX_CLOCK_APB4_DIVIDER] = {
623
+ .name = "apb4-divider",
624
+ .src_type = CLKSRC_DIV,
625
+ .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
626
+ .divide = shift_by_reg_divisor,
627
+ .reg = NPCM7XX_CLK_CLKDIV2,
628
+ .offset = 30,
629
+ .len = 2,
630
+ .public_name = "apb4-clock",
631
+ },
632
+ [NPCM7XX_CLOCK_APB5_DIVIDER] = {
633
+ .name = "apb5-divider",
634
+ .src_type = CLKSRC_DIV,
635
+ .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
636
+ .divide = shift_by_reg_divisor,
637
+ .reg = NPCM7XX_CLK_CLKDIV2,
638
+ .offset = 22,
639
+ .len = 2,
640
+ .public_name = "apb5-clock",
641
+ },
642
+ [NPCM7XX_CLOCK_CLKOUT_DIVIDER] = {
643
+ .name = "clkout-divider",
644
+ .src_type = CLKSRC_SEL,
645
+ .src_index = NPCM7XX_CLOCK_CLKOUTSEL,
646
+ .divide = divide_by_reg_divisor,
647
+ .reg = NPCM7XX_CLK_CLKDIV2,
648
+ .offset = 16,
649
+ .len = 5,
650
+ .public_name = "clkout",
651
+ },
652
+ [NPCM7XX_CLOCK_UART_DIVIDER] = {
653
+ .name = "uart-divider",
654
+ .src_type = CLKSRC_SEL,
655
+ .src_index = NPCM7XX_CLOCK_UARTCKSEL,
656
+ .divide = divide_by_reg_divisor,
657
+ .reg = NPCM7XX_CLK_CLKDIV1,
658
+ .offset = 16,
659
+ .len = 5,
660
+ .public_name = "uart-clock",
661
+ },
662
+ [NPCM7XX_CLOCK_TIMER_DIVIDER] = {
663
+ .name = "timer-divider",
664
+ .src_type = CLKSRC_SEL,
665
+ .src_index = NPCM7XX_CLOCK_TIMCKSEL,
666
+ .divide = divide_by_reg_divisor,
667
+ .reg = NPCM7XX_CLK_CLKDIV1,
668
+ .offset = 21,
669
+ .len = 5,
670
+ .public_name = "timer-clock",
671
+ },
672
+ [NPCM7XX_CLOCK_ADC_DIVIDER] = {
673
+ .name = "adc-divider",
674
+ .src_type = CLKSRC_DIV,
675
+ .src_index = NPCM7XX_CLOCK_TIMER_DIVIDER,
676
+ .divide = shift_by_reg_divisor,
677
+ .reg = NPCM7XX_CLK_CLKDIV1,
678
+ .offset = 28,
679
+ .len = 3,
680
+ .public_name = "adc-clock",
681
+ },
682
+ [NPCM7XX_CLOCK_MMC_DIVIDER] = {
683
+ .name = "mmc-divider",
684
+ .src_type = CLKSRC_SEL,
685
+ .src_index = NPCM7XX_CLOCK_SDCKSEL,
686
+ .divide = divide_by_reg_divisor,
687
+ .reg = NPCM7XX_CLK_CLKDIV1,
688
+ .offset = 11,
689
+ .len = 5,
690
+ .public_name = "mmc-clock",
691
+ },
692
+ [NPCM7XX_CLOCK_SDHC_DIVIDER] = {
693
+ .name = "sdhc-divider",
694
+ .src_type = CLKSRC_SEL,
695
+ .src_index = NPCM7XX_CLOCK_SDCKSEL,
696
+ .divide = divide_by_reg_divisor_times_2,
697
+ .reg = NPCM7XX_CLK_CLKDIV2,
698
+ .offset = 0,
699
+ .len = 4,
700
+ .public_name = "sdhc-clock",
701
+ },
702
+ [NPCM7XX_CLOCK_GFXM_DIVIDER] = {
703
+ .name = "gfxm-divider",
704
+ .src_type = CLKSRC_SEL,
705
+ .src_index = NPCM7XX_CLOCK_GFXMSEL,
706
+ .divide = divide_by_constant,
707
+ .divisor = 3,
708
+ .public_name = "gfxm-clock",
709
+ },
710
+ [NPCM7XX_CLOCK_UTMI_DIVIDER] = {
711
+ .name = "utmi-divider",
712
+ .src_type = CLKSRC_SEL,
713
+ .src_index = NPCM7XX_CLOCK_SUCKSEL,
714
+ .divide = divide_by_reg_divisor,
715
+ .reg = NPCM7XX_CLK_CLKDIV2,
716
+ .offset = 8,
717
+ .len = 5,
718
+ .public_name = "utmi-clock",
719
+ },
720
+};
721
+
722
+static void npcm7xx_clk_pll_init(Object *obj)
723
+{
724
+ NPCM7xxClockPLLState *pll = NPCM7XX_CLOCK_PLL(obj);
725
+
726
+ pll->clock_in = qdev_init_clock_in(DEVICE(pll), "clock-in",
727
+ npcm7xx_clk_update_pll, pll);
728
+ pll->clock_out = qdev_init_clock_out(DEVICE(pll), "clock-out");
729
+}
730
+
731
+static void npcm7xx_clk_sel_init(Object *obj)
732
+{
733
+ int i;
734
+ NPCM7xxClockSELState *sel = NPCM7XX_CLOCK_SEL(obj);
735
+
736
+ for (i = 0; i < NPCM7XX_CLK_SEL_MAX_INPUT; ++i) {
737
+ sel->clock_in[i] = qdev_init_clock_in(DEVICE(sel),
738
+ g_strdup_printf("clock-in[%d]", i),
739
+ npcm7xx_clk_update_sel, sel);
740
+ }
741
+ sel->clock_out = qdev_init_clock_out(DEVICE(sel), "clock-out");
742
+}
743
+static void npcm7xx_clk_divider_init(Object *obj)
744
+{
745
+ NPCM7xxClockDividerState *div = NPCM7XX_CLOCK_DIVIDER(obj);
746
+
747
+ div->clock_in = qdev_init_clock_in(DEVICE(div), "clock-in",
748
+ npcm7xx_clk_update_divider, div);
749
+ div->clock_out = qdev_init_clock_out(DEVICE(div), "clock-out");
750
+}
751
+
752
+static void npcm7xx_init_clock_pll(NPCM7xxClockPLLState *pll,
753
+ NPCM7xxCLKState *clk, const PLLInitInfo *init_info)
754
+{
755
+ pll->name = init_info->name;
756
+ pll->clk = clk;
757
+ pll->reg = init_info->reg;
758
+ if (init_info->public_name != NULL) {
759
+ qdev_alias_clock(DEVICE(pll), "clock-out", DEVICE(clk),
760
+ init_info->public_name);
761
+ }
762
+}
763
+
764
+static void npcm7xx_init_clock_sel(NPCM7xxClockSELState *sel,
765
+ NPCM7xxCLKState *clk, const SELInitInfo *init_info)
766
+{
767
+ int input_size = init_info->input_size;
768
+
769
+ sel->name = init_info->name;
770
+ sel->clk = clk;
771
+ sel->input_size = init_info->input_size;
772
+ g_assert(input_size <= NPCM7XX_CLK_SEL_MAX_INPUT);
773
+ sel->offset = init_info->offset;
774
+ sel->len = init_info->len;
775
+ if (init_info->public_name != NULL) {
776
+ qdev_alias_clock(DEVICE(sel), "clock-out", DEVICE(clk),
777
+ init_info->public_name);
778
+ }
779
+}
780
+
781
+static void npcm7xx_init_clock_divider(NPCM7xxClockDividerState *div,
782
+ NPCM7xxCLKState *clk, const DividerInitInfo *init_info)
783
+{
784
+ div->name = init_info->name;
785
+ div->clk = clk;
786
+
787
+ div->divide = init_info->divide;
788
+ if (div->divide == divide_by_constant) {
789
+ div->divisor = init_info->divisor;
790
+ } else {
791
+ div->reg = init_info->reg;
792
+ div->offset = init_info->offset;
793
+ div->len = init_info->len;
794
+ }
795
+ if (init_info->public_name != NULL) {
796
+ qdev_alias_clock(DEVICE(div), "clock-out", DEVICE(clk),
797
+ init_info->public_name);
798
+ }
799
+}
800
+
801
+static Clock *npcm7xx_get_clock(NPCM7xxCLKState *clk, ClockSrcType type,
802
+ int index)
803
+{
804
+ switch (type) {
805
+ case CLKSRC_REF:
806
+ return clk->clkref;
807
+ case CLKSRC_PLL:
808
+ return clk->plls[index].clock_out;
809
+ case CLKSRC_SEL:
810
+ return clk->sels[index].clock_out;
811
+ case CLKSRC_DIV:
812
+ return clk->dividers[index].clock_out;
813
+ default:
814
+ g_assert_not_reached();
815
+ }
816
+}
817
+
818
+static void npcm7xx_connect_clocks(NPCM7xxCLKState *clk)
819
+{
820
+ int i, j;
821
+ Clock *src;
822
+
823
+ for (i = 0; i < NPCM7XX_CLOCK_NR_PLLS; ++i) {
824
+ src = npcm7xx_get_clock(clk, pll_init_info_list[i].src_type,
825
+ pll_init_info_list[i].src_index);
826
+ clock_set_source(clk->plls[i].clock_in, src);
827
+ }
828
+ for (i = 0; i < NPCM7XX_CLOCK_NR_SELS; ++i) {
829
+ for (j = 0; j < sel_init_info_list[i].input_size; ++j) {
830
+ src = npcm7xx_get_clock(clk, sel_init_info_list[i].src_type[j],
831
+ sel_init_info_list[i].src_index[j]);
832
+ clock_set_source(clk->sels[i].clock_in[j], src);
833
+ }
834
+ }
835
+ for (i = 0; i < NPCM7XX_CLOCK_NR_DIVIDERS; ++i) {
836
+ src = npcm7xx_get_clock(clk, divider_init_info_list[i].src_type,
837
+ divider_init_info_list[i].src_index);
838
+ clock_set_source(clk->dividers[i].clock_in, src);
839
+ }
840
+}
841
+
842
static uint64_t npcm7xx_clk_read(void *opaque, hwaddr offset, unsigned size)
843
{
69
{
844
uint32_t reg = offset / sizeof(uint32_t);
70
+ if (!dc_isar_feature(aa64_condm_5, s)) {
845
@@ -XXX,XX +XXX,XX @@ static uint64_t npcm7xx_clk_read(void *opaque, hwaddr offset, unsigned size)
71
+ return false;
846
*
847
* The 4 LSBs are always zero: (1e9 / 640) << 4 = 25000000.
848
*/
849
- value = (((now_ns - s->ref_ns) / 640) << 4) % NPCM7XX_TIMER_REF_HZ;
850
+ value = (((now_ns - s->ref_ns) / 640) << 4) % NPCM7XX_CLOCK_REF_HZ;
851
break;
852
853
default:
854
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_write(void *opaque, hwaddr offset,
855
value |= (value & PLLCON_LOKS);
856
}
857
}
858
+ /* Only update PLL when it is locked. */
859
+ if (value & PLLCON_LOKI) {
860
+ npcm7xx_clk_update_pll(&s->plls[find_pll_by_reg(reg)]);
861
+ }
862
+ break;
863
+
864
+ case NPCM7XX_CLK_CLKSEL:
865
+ npcm7xx_clk_update_all_sels(s);
866
+ break;
867
+
868
+ case NPCM7XX_CLK_CLKDIV1:
869
+ case NPCM7XX_CLK_CLKDIV2:
870
+ case NPCM7XX_CLK_CLKDIV3:
871
+ npcm7xx_clk_update_all_dividers(s);
872
break;
873
874
case NPCM7XX_CLK_CNTR25M:
875
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_enter_reset(Object *obj, ResetType type)
876
case RESET_TYPE_COLD:
877
memcpy(s->regs, cold_reset_values, sizeof(cold_reset_values));
878
s->ref_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
879
+ npcm7xx_clk_update_all_clocks(s);
880
return;
881
}
882
883
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_enter_reset(Object *obj, ResetType type)
884
__func__, type);
885
}
886
887
+static void npcm7xx_clk_init_clock_hierarchy(NPCM7xxCLKState *s)
888
+{
889
+ int i;
890
+
891
+ s->clkref = qdev_init_clock_in(DEVICE(s), "clkref", NULL, NULL);
892
+
893
+ /* First pass: init all converter modules */
894
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(pll_init_info_list) != NPCM7XX_CLOCK_NR_PLLS);
895
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(sel_init_info_list) != NPCM7XX_CLOCK_NR_SELS);
896
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(divider_init_info_list)
897
+ != NPCM7XX_CLOCK_NR_DIVIDERS);
898
+ for (i = 0; i < NPCM7XX_CLOCK_NR_PLLS; ++i) {
899
+ object_initialize_child(OBJECT(s), pll_init_info_list[i].name,
900
+ &s->plls[i], TYPE_NPCM7XX_CLOCK_PLL);
901
+ npcm7xx_init_clock_pll(&s->plls[i], s,
902
+ &pll_init_info_list[i]);
903
+ }
904
+ for (i = 0; i < NPCM7XX_CLOCK_NR_SELS; ++i) {
905
+ object_initialize_child(OBJECT(s), sel_init_info_list[i].name,
906
+ &s->sels[i], TYPE_NPCM7XX_CLOCK_SEL);
907
+ npcm7xx_init_clock_sel(&s->sels[i], s,
908
+ &sel_init_info_list[i]);
909
+ }
910
+ for (i = 0; i < NPCM7XX_CLOCK_NR_DIVIDERS; ++i) {
911
+ object_initialize_child(OBJECT(s), divider_init_info_list[i].name,
912
+ &s->dividers[i], TYPE_NPCM7XX_CLOCK_DIVIDER);
913
+ npcm7xx_init_clock_divider(&s->dividers[i], s,
914
+ &divider_init_info_list[i]);
915
+ }
72
+ }
916
+
73
+
917
+ /* Second pass: connect converter modules */
74
tcg_gen_sari_i32(cpu_VF, cpu_VF, 31); /* V ? -1 : 0 */
918
+ npcm7xx_connect_clocks(s);
75
tcg_gen_andc_i32(cpu_CF, cpu_CF, cpu_VF); /* C & !V */
76
77
@@ -XXX,XX +XXX,XX @@ static void gen_axflag(void)
78
79
tcg_gen_movi_i32(cpu_NF, 0);
80
tcg_gen_movi_i32(cpu_VF, 0);
919
+
81
+
920
+ clock_update_hz(s->clkref, NPCM7XX_CLOCK_REF_HZ);
82
+ return true;
921
+}
922
+
923
static void npcm7xx_clk_init(Object *obj)
924
{
925
NPCM7xxCLKState *s = NPCM7XX_CLK(obj);
926
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_init(Object *obj)
927
memory_region_init_io(&s->iomem, obj, &npcm7xx_clk_ops, s,
928
TYPE_NPCM7XX_CLK, 4 * KiB);
929
sysbus_init_mmio(&s->parent, &s->iomem);
930
- qdev_init_gpio_in_named(DEVICE(s), npcm7xx_clk_perform_watchdog_reset,
931
- NPCM7XX_WATCHDOG_RESET_GPIO_IN, NPCM7XX_NR_WATCHDOGS);
932
}
83
}
933
84
934
-static const VMStateDescription vmstate_npcm7xx_clk = {
85
/* MSR (immediate) - move immediate to processor state field */
935
- .name = "npcm7xx-clk",
86
@@ -XXX,XX +XXX,XX @@ static void handle_msr_i(DisasContext *s, uint32_t insn,
936
+static int npcm7xx_clk_post_load(void *opaque, int version_id)
87
s->base.is_jmp = DISAS_TOO_MANY;
937
+{
88
938
+ if (version_id >= 1) {
89
switch (op) {
939
+ NPCM7xxCLKState *clk = opaque;
90
- case 0x00: /* CFINV */
940
+
91
- if (crm != 0 || !dc_isar_feature(aa64_condm_4, s)) {
941
+ npcm7xx_clk_update_all_clocks(clk);
92
- goto do_unallocated;
942
+ }
93
- }
943
+
94
- tcg_gen_xori_i32(cpu_CF, cpu_CF, 1);
944
+ return 0;
95
- s->base.is_jmp = DISAS_NEXT;
945
+}
96
- break;
946
+
97
-
947
+static void npcm7xx_clk_realize(DeviceState *dev, Error **errp)
98
- case 0x01: /* XAFlag */
948
+{
99
- if (crm != 0 || !dc_isar_feature(aa64_condm_5, s)) {
949
+ int i;
100
- goto do_unallocated;
950
+ NPCM7xxCLKState *s = NPCM7XX_CLK(dev);
101
- }
951
+
102
- gen_xaflag();
952
+ qdev_init_gpio_in_named(DEVICE(s), npcm7xx_clk_perform_watchdog_reset,
103
- s->base.is_jmp = DISAS_NEXT;
953
+ NPCM7XX_WATCHDOG_RESET_GPIO_IN, NPCM7XX_NR_WATCHDOGS);
104
- break;
954
+ npcm7xx_clk_init_clock_hierarchy(s);
105
-
955
+
106
- case 0x02: /* AXFlag */
956
+ /* Realize child devices */
107
- if (crm != 0 || !dc_isar_feature(aa64_condm_5, s)) {
957
+ for (i = 0; i < NPCM7XX_CLOCK_NR_PLLS; ++i) {
108
- goto do_unallocated;
958
+ if (!qdev_realize(DEVICE(&s->plls[i]), NULL, errp)) {
109
- }
959
+ return;
110
- gen_axflag();
960
+ }
111
- s->base.is_jmp = DISAS_NEXT;
961
+ }
112
- break;
962
+ for (i = 0; i < NPCM7XX_CLOCK_NR_SELS; ++i) {
113
-
963
+ if (!qdev_realize(DEVICE(&s->sels[i]), NULL, errp)) {
114
case 0x03: /* UAO */
964
+ return;
115
if (!dc_isar_feature(aa64_uao, s) || s->current_el == 0) {
965
+ }
116
goto do_unallocated;
966
+ }
967
+ for (i = 0; i < NPCM7XX_CLOCK_NR_DIVIDERS; ++i) {
968
+ if (!qdev_realize(DEVICE(&s->dividers[i]), NULL, errp)) {
969
+ return;
970
+ }
971
+ }
972
+}
973
+
974
+static const VMStateDescription vmstate_npcm7xx_clk_pll = {
975
+ .name = "npcm7xx-clock-pll",
976
.version_id = 0,
977
.minimum_version_id = 0,
978
- .fields = (VMStateField[]) {
979
- VMSTATE_UINT32_ARRAY(regs, NPCM7xxCLKState, NPCM7XX_CLK_NR_REGS),
980
- VMSTATE_INT64(ref_ns, NPCM7xxCLKState),
981
+ .fields = (VMStateField[]) {
982
+ VMSTATE_CLOCK(clock_in, NPCM7xxClockPLLState),
983
VMSTATE_END_OF_LIST(),
984
},
985
};
986
987
+static const VMStateDescription vmstate_npcm7xx_clk_sel = {
988
+ .name = "npcm7xx-clock-sel",
989
+ .version_id = 0,
990
+ .minimum_version_id = 0,
991
+ .fields = (VMStateField[]) {
992
+ VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(clock_in, NPCM7xxClockSELState,
993
+ NPCM7XX_CLK_SEL_MAX_INPUT, 0, vmstate_clock, Clock),
994
+ VMSTATE_END_OF_LIST(),
995
+ },
996
+};
997
+
998
+static const VMStateDescription vmstate_npcm7xx_clk_divider = {
999
+ .name = "npcm7xx-clock-divider",
1000
+ .version_id = 0,
1001
+ .minimum_version_id = 0,
1002
+ .fields = (VMStateField[]) {
1003
+ VMSTATE_CLOCK(clock_in, NPCM7xxClockDividerState),
1004
+ VMSTATE_END_OF_LIST(),
1005
+ },
1006
+};
1007
+
1008
+static const VMStateDescription vmstate_npcm7xx_clk = {
1009
+ .name = "npcm7xx-clk",
1010
+ .version_id = 1,
1011
+ .minimum_version_id = 1,
1012
+ .post_load = npcm7xx_clk_post_load,
1013
+ .fields = (VMStateField[]) {
1014
+ VMSTATE_UINT32_ARRAY(regs, NPCM7xxCLKState, NPCM7XX_CLK_NR_REGS),
1015
+ VMSTATE_INT64(ref_ns, NPCM7xxCLKState),
1016
+ VMSTATE_CLOCK(clkref, NPCM7xxCLKState),
1017
+ VMSTATE_END_OF_LIST(),
1018
+ },
1019
+};
1020
+
1021
+static void npcm7xx_clk_pll_class_init(ObjectClass *klass, void *data)
1022
+{
1023
+ DeviceClass *dc = DEVICE_CLASS(klass);
1024
+
1025
+ dc->desc = "NPCM7xx Clock PLL Module";
1026
+ dc->vmsd = &vmstate_npcm7xx_clk_pll;
1027
+}
1028
+
1029
+static void npcm7xx_clk_sel_class_init(ObjectClass *klass, void *data)
1030
+{
1031
+ DeviceClass *dc = DEVICE_CLASS(klass);
1032
+
1033
+ dc->desc = "NPCM7xx Clock SEL Module";
1034
+ dc->vmsd = &vmstate_npcm7xx_clk_sel;
1035
+}
1036
+
1037
+static void npcm7xx_clk_divider_class_init(ObjectClass *klass, void *data)
1038
+{
1039
+ DeviceClass *dc = DEVICE_CLASS(klass);
1040
+
1041
+ dc->desc = "NPCM7xx Clock Divider Module";
1042
+ dc->vmsd = &vmstate_npcm7xx_clk_divider;
1043
+}
1044
+
1045
static void npcm7xx_clk_class_init(ObjectClass *klass, void *data)
1046
{
1047
ResettableClass *rc = RESETTABLE_CLASS(klass);
1048
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_class_init(ObjectClass *klass, void *data)
1049
1050
dc->desc = "NPCM7xx Clock Control Registers";
1051
dc->vmsd = &vmstate_npcm7xx_clk;
1052
+ dc->realize = npcm7xx_clk_realize;
1053
rc->phases.enter = npcm7xx_clk_enter_reset;
1054
}
1055
1056
+static const TypeInfo npcm7xx_clk_pll_info = {
1057
+ .name = TYPE_NPCM7XX_CLOCK_PLL,
1058
+ .parent = TYPE_DEVICE,
1059
+ .instance_size = sizeof(NPCM7xxClockPLLState),
1060
+ .instance_init = npcm7xx_clk_pll_init,
1061
+ .class_init = npcm7xx_clk_pll_class_init,
1062
+};
1063
+
1064
+static const TypeInfo npcm7xx_clk_sel_info = {
1065
+ .name = TYPE_NPCM7XX_CLOCK_SEL,
1066
+ .parent = TYPE_DEVICE,
1067
+ .instance_size = sizeof(NPCM7xxClockSELState),
1068
+ .instance_init = npcm7xx_clk_sel_init,
1069
+ .class_init = npcm7xx_clk_sel_class_init,
1070
+};
1071
+
1072
+static const TypeInfo npcm7xx_clk_divider_info = {
1073
+ .name = TYPE_NPCM7XX_CLOCK_DIVIDER,
1074
+ .parent = TYPE_DEVICE,
1075
+ .instance_size = sizeof(NPCM7xxClockDividerState),
1076
+ .instance_init = npcm7xx_clk_divider_init,
1077
+ .class_init = npcm7xx_clk_divider_class_init,
1078
+};
1079
+
1080
static const TypeInfo npcm7xx_clk_info = {
1081
.name = TYPE_NPCM7XX_CLK,
1082
.parent = TYPE_SYS_BUS_DEVICE,
1083
@@ -XXX,XX +XXX,XX @@ static const TypeInfo npcm7xx_clk_info = {
1084
1085
static void npcm7xx_clk_register_type(void)
1086
{
1087
+ type_register_static(&npcm7xx_clk_pll_info);
1088
+ type_register_static(&npcm7xx_clk_sel_info);
1089
+ type_register_static(&npcm7xx_clk_divider_info);
1090
type_register_static(&npcm7xx_clk_info);
1091
}
1092
type_init(npcm7xx_clk_register_type);
1093
--
117
--
1094
2.20.1
118
2.34.1
1095
1096
diff view generated by jsdifflib
New patch
1
Convert the MSR (immediate) insn to decodetree. Our implementation
2
has basically no commonality between the different destinations,
3
so we decode the destination register in a64.decode.
1
4
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20230602155223.2040685-6-peter.maydell@linaro.org
8
---
9
target/arm/tcg/a64.decode | 13 ++
10
target/arm/tcg/translate-a64.c | 251 ++++++++++++++++-----------------
11
2 files changed, 136 insertions(+), 128 deletions(-)
12
13
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
14
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/tcg/a64.decode
16
+++ b/target/arm/tcg/a64.decode
17
@@ -XXX,XX +XXX,XX @@ SB 1101 0101 0000 0011 0011 0000 111 11111
18
CFINV 1101 0101 0000 0 000 0100 0000 000 11111
19
XAFLAG 1101 0101 0000 0 000 0100 0000 001 11111
20
AXFLAG 1101 0101 0000 0 000 0100 0000 010 11111
21
+
22
+# These are architecturally all "MSR (immediate)"; we decode the destination
23
+# register too because there is no commonality in our implementation.
24
+@msr_i .... .... .... . ... .... imm:4 ... .....
25
+MSR_i_UAO 1101 0101 0000 0 000 0100 .... 011 11111 @msr_i
26
+MSR_i_PAN 1101 0101 0000 0 000 0100 .... 100 11111 @msr_i
27
+MSR_i_SPSEL 1101 0101 0000 0 000 0100 .... 101 11111 @msr_i
28
+MSR_i_SBSS 1101 0101 0000 0 011 0100 .... 001 11111 @msr_i
29
+MSR_i_DIT 1101 0101 0000 0 011 0100 .... 010 11111 @msr_i
30
+MSR_i_TCO 1101 0101 0000 0 011 0100 .... 100 11111 @msr_i
31
+MSR_i_DAIFSET 1101 0101 0000 0 011 0100 .... 110 11111 @msr_i
32
+MSR_i_DAIFCLEAR 1101 0101 0000 0 011 0100 .... 111 11111 @msr_i
33
+MSR_i_SVCR 1101 0101 0000 0 011 0100 0 mask:2 imm:1 011 11111
34
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
35
index XXXXXXX..XXXXXXX 100644
36
--- a/target/arm/tcg/translate-a64.c
37
+++ b/target/arm/tcg/translate-a64.c
38
@@ -XXX,XX +XXX,XX @@ static bool trans_AXFLAG(DisasContext *s, arg_AXFLAG *a)
39
return true;
40
}
41
42
-/* MSR (immediate) - move immediate to processor state field */
43
-static void handle_msr_i(DisasContext *s, uint32_t insn,
44
- unsigned int op1, unsigned int op2, unsigned int crm)
45
+static bool trans_MSR_i_UAO(DisasContext *s, arg_i *a)
46
{
47
- int op = op1 << 3 | op2;
48
-
49
- /* End the TB by default, chaining is ok. */
50
- s->base.is_jmp = DISAS_TOO_MANY;
51
-
52
- switch (op) {
53
- case 0x03: /* UAO */
54
- if (!dc_isar_feature(aa64_uao, s) || s->current_el == 0) {
55
- goto do_unallocated;
56
- }
57
- if (crm & 1) {
58
- set_pstate_bits(PSTATE_UAO);
59
- } else {
60
- clear_pstate_bits(PSTATE_UAO);
61
- }
62
- gen_rebuild_hflags(s);
63
- break;
64
-
65
- case 0x04: /* PAN */
66
- if (!dc_isar_feature(aa64_pan, s) || s->current_el == 0) {
67
- goto do_unallocated;
68
- }
69
- if (crm & 1) {
70
- set_pstate_bits(PSTATE_PAN);
71
- } else {
72
- clear_pstate_bits(PSTATE_PAN);
73
- }
74
- gen_rebuild_hflags(s);
75
- break;
76
-
77
- case 0x05: /* SPSel */
78
- if (s->current_el == 0) {
79
- goto do_unallocated;
80
- }
81
- gen_helper_msr_i_spsel(cpu_env, tcg_constant_i32(crm & PSTATE_SP));
82
- break;
83
-
84
- case 0x19: /* SSBS */
85
- if (!dc_isar_feature(aa64_ssbs, s)) {
86
- goto do_unallocated;
87
- }
88
- if (crm & 1) {
89
- set_pstate_bits(PSTATE_SSBS);
90
- } else {
91
- clear_pstate_bits(PSTATE_SSBS);
92
- }
93
- /* Don't need to rebuild hflags since SSBS is a nop */
94
- break;
95
-
96
- case 0x1a: /* DIT */
97
- if (!dc_isar_feature(aa64_dit, s)) {
98
- goto do_unallocated;
99
- }
100
- if (crm & 1) {
101
- set_pstate_bits(PSTATE_DIT);
102
- } else {
103
- clear_pstate_bits(PSTATE_DIT);
104
- }
105
- /* There's no need to rebuild hflags because DIT is a nop */
106
- break;
107
-
108
- case 0x1e: /* DAIFSet */
109
- gen_helper_msr_i_daifset(cpu_env, tcg_constant_i32(crm));
110
- break;
111
-
112
- case 0x1f: /* DAIFClear */
113
- gen_helper_msr_i_daifclear(cpu_env, tcg_constant_i32(crm));
114
- /* For DAIFClear, exit the cpu loop to re-evaluate pending IRQs. */
115
- s->base.is_jmp = DISAS_UPDATE_EXIT;
116
- break;
117
-
118
- case 0x1c: /* TCO */
119
- if (dc_isar_feature(aa64_mte, s)) {
120
- /* Full MTE is enabled -- set the TCO bit as directed. */
121
- if (crm & 1) {
122
- set_pstate_bits(PSTATE_TCO);
123
- } else {
124
- clear_pstate_bits(PSTATE_TCO);
125
- }
126
- gen_rebuild_hflags(s);
127
- /* Many factors, including TCO, go into MTE_ACTIVE. */
128
- s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
129
- } else if (dc_isar_feature(aa64_mte_insn_reg, s)) {
130
- /* Only "instructions accessible at EL0" -- PSTATE.TCO is WI. */
131
- s->base.is_jmp = DISAS_NEXT;
132
- } else {
133
- goto do_unallocated;
134
- }
135
- break;
136
-
137
- case 0x1b: /* SVCR* */
138
- if (!dc_isar_feature(aa64_sme, s) || crm < 2 || crm > 7) {
139
- goto do_unallocated;
140
- }
141
- if (sme_access_check(s)) {
142
- int old = s->pstate_sm | (s->pstate_za << 1);
143
- int new = (crm & 1) * 3;
144
- int msk = (crm >> 1) & 3;
145
-
146
- if ((old ^ new) & msk) {
147
- /* At least one bit changes. */
148
- gen_helper_set_svcr(cpu_env, tcg_constant_i32(new),
149
- tcg_constant_i32(msk));
150
- } else {
151
- s->base.is_jmp = DISAS_NEXT;
152
- }
153
- }
154
- break;
155
-
156
- default:
157
- do_unallocated:
158
- unallocated_encoding(s);
159
- return;
160
+ if (!dc_isar_feature(aa64_uao, s) || s->current_el == 0) {
161
+ return false;
162
}
163
+ if (a->imm & 1) {
164
+ set_pstate_bits(PSTATE_UAO);
165
+ } else {
166
+ clear_pstate_bits(PSTATE_UAO);
167
+ }
168
+ gen_rebuild_hflags(s);
169
+ s->base.is_jmp = DISAS_TOO_MANY;
170
+ return true;
171
+}
172
+
173
+static bool trans_MSR_i_PAN(DisasContext *s, arg_i *a)
174
+{
175
+ if (!dc_isar_feature(aa64_pan, s) || s->current_el == 0) {
176
+ return false;
177
+ }
178
+ if (a->imm & 1) {
179
+ set_pstate_bits(PSTATE_PAN);
180
+ } else {
181
+ clear_pstate_bits(PSTATE_PAN);
182
+ }
183
+ gen_rebuild_hflags(s);
184
+ s->base.is_jmp = DISAS_TOO_MANY;
185
+ return true;
186
+}
187
+
188
+static bool trans_MSR_i_SPSEL(DisasContext *s, arg_i *a)
189
+{
190
+ if (s->current_el == 0) {
191
+ return false;
192
+ }
193
+ gen_helper_msr_i_spsel(cpu_env, tcg_constant_i32(a->imm & PSTATE_SP));
194
+ s->base.is_jmp = DISAS_TOO_MANY;
195
+ return true;
196
+}
197
+
198
+static bool trans_MSR_i_SBSS(DisasContext *s, arg_i *a)
199
+{
200
+ if (!dc_isar_feature(aa64_ssbs, s)) {
201
+ return false;
202
+ }
203
+ if (a->imm & 1) {
204
+ set_pstate_bits(PSTATE_SSBS);
205
+ } else {
206
+ clear_pstate_bits(PSTATE_SSBS);
207
+ }
208
+ /* Don't need to rebuild hflags since SSBS is a nop */
209
+ s->base.is_jmp = DISAS_TOO_MANY;
210
+ return true;
211
+}
212
+
213
+static bool trans_MSR_i_DIT(DisasContext *s, arg_i *a)
214
+{
215
+ if (!dc_isar_feature(aa64_dit, s)) {
216
+ return false;
217
+ }
218
+ if (a->imm & 1) {
219
+ set_pstate_bits(PSTATE_DIT);
220
+ } else {
221
+ clear_pstate_bits(PSTATE_DIT);
222
+ }
223
+ /* There's no need to rebuild hflags because DIT is a nop */
224
+ s->base.is_jmp = DISAS_TOO_MANY;
225
+ return true;
226
+}
227
+
228
+static bool trans_MSR_i_TCO(DisasContext *s, arg_i *a)
229
+{
230
+ if (dc_isar_feature(aa64_mte, s)) {
231
+ /* Full MTE is enabled -- set the TCO bit as directed. */
232
+ if (a->imm & 1) {
233
+ set_pstate_bits(PSTATE_TCO);
234
+ } else {
235
+ clear_pstate_bits(PSTATE_TCO);
236
+ }
237
+ gen_rebuild_hflags(s);
238
+ /* Many factors, including TCO, go into MTE_ACTIVE. */
239
+ s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
240
+ return true;
241
+ } else if (dc_isar_feature(aa64_mte_insn_reg, s)) {
242
+ /* Only "instructions accessible at EL0" -- PSTATE.TCO is WI. */
243
+ return true;
244
+ } else {
245
+ /* Insn not present */
246
+ return false;
247
+ }
248
+}
249
+
250
+static bool trans_MSR_i_DAIFSET(DisasContext *s, arg_i *a)
251
+{
252
+ gen_helper_msr_i_daifset(cpu_env, tcg_constant_i32(a->imm));
253
+ s->base.is_jmp = DISAS_TOO_MANY;
254
+ return true;
255
+}
256
+
257
+static bool trans_MSR_i_DAIFCLEAR(DisasContext *s, arg_i *a)
258
+{
259
+ gen_helper_msr_i_daifclear(cpu_env, tcg_constant_i32(a->imm));
260
+ /* Exit the cpu loop to re-evaluate pending IRQs. */
261
+ s->base.is_jmp = DISAS_UPDATE_EXIT;
262
+ return true;
263
+}
264
+
265
+static bool trans_MSR_i_SVCR(DisasContext *s, arg_MSR_i_SVCR *a)
266
+{
267
+ if (!dc_isar_feature(aa64_sme, s) || a->mask == 0) {
268
+ return false;
269
+ }
270
+ if (sme_access_check(s)) {
271
+ int old = s->pstate_sm | (s->pstate_za << 1);
272
+ int new = a->imm * 3;
273
+
274
+ if ((old ^ new) & a->mask) {
275
+ /* At least one bit changes. */
276
+ gen_helper_set_svcr(cpu_env, tcg_constant_i32(new),
277
+ tcg_constant_i32(a->mask));
278
+ s->base.is_jmp = DISAS_TOO_MANY;
279
+ }
280
+ }
281
+ return true;
282
}
283
284
static void gen_get_nzcv(TCGv_i64 tcg_rt)
285
@@ -XXX,XX +XXX,XX @@ static void disas_system(DisasContext *s, uint32_t insn)
286
rt = extract32(insn, 0, 5);
287
288
if (op0 == 0) {
289
- if (l || rt != 31) {
290
- unallocated_encoding(s);
291
- return;
292
- }
293
- switch (crn) {
294
- case 4: /* MSR (immediate) */
295
- handle_msr_i(s, insn, op1, op2, crm);
296
- break;
297
- default:
298
- unallocated_encoding(s);
299
- break;
300
- }
301
+ unallocated_encoding(s);
302
return;
303
}
304
handle_sys(s, insn, l, op0, op1, op2, crn, crm, rt);
305
--
306
2.34.1
diff view generated by jsdifflib
1
From: Hao Wu <wuhaotsh@google.com>
1
Convert MSR (reg), MRS, SYS, SYSL to decodetree. For QEMU these are
2
all essentially the same instruction (system register access).
2
3
3
A device shouldn't access its parent object which is QOM internal.
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Instead it should use type cast for this purporse. This patch fixes this
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
issue for all NPCM7XX Devices.
6
Message-id: 20230602155223.2040685-7-peter.maydell@linaro.org
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
8
---
9
target/arm/tcg/a64.decode | 8 ++++++++
10
target/arm/tcg/translate-a64.c | 32 +++++---------------------------
11
2 files changed, 13 insertions(+), 27 deletions(-)
6
12
7
Signed-off-by: Hao Wu <wuhaotsh@google.com>
13
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Message-id: 20210108190945.949196-7-wuhaotsh@google.com
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
12
hw/arm/npcm7xx_boards.c | 2 +-
13
hw/mem/npcm7xx_mc.c | 2 +-
14
hw/misc/npcm7xx_clk.c | 2 +-
15
hw/misc/npcm7xx_gcr.c | 2 +-
16
hw/misc/npcm7xx_rng.c | 2 +-
17
hw/nvram/npcm7xx_otp.c | 2 +-
18
hw/ssi/npcm7xx_fiu.c | 2 +-
19
7 files changed, 7 insertions(+), 7 deletions(-)
20
21
diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c
22
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
23
--- a/hw/arm/npcm7xx_boards.c
15
--- a/target/arm/tcg/a64.decode
24
+++ b/hw/arm/npcm7xx_boards.c
16
+++ b/target/arm/tcg/a64.decode
25
@@ -XXX,XX +XXX,XX @@ static NPCM7xxState *npcm7xx_create_soc(MachineState *machine,
17
@@ -XXX,XX +XXX,XX @@ MSR_i_TCO 1101 0101 0000 0 011 0100 .... 100 11111 @msr_i
26
uint32_t hw_straps)
18
MSR_i_DAIFSET 1101 0101 0000 0 011 0100 .... 110 11111 @msr_i
19
MSR_i_DAIFCLEAR 1101 0101 0000 0 011 0100 .... 111 11111 @msr_i
20
MSR_i_SVCR 1101 0101 0000 0 011 0100 0 mask:2 imm:1 011 11111
21
+
22
+# MRS, MSR (register), SYS, SYSL. These are all essentially the
23
+# same instruction as far as QEMU is concerned.
24
+# NB: op0 is bits [20:19], but op0=0b00 is other insns, so we have
25
+# to hand-decode it.
26
+SYS 1101 0101 00 l:1 01 op1:3 crn:4 crm:4 op2:3 rt:5 op0=1
27
+SYS 1101 0101 00 l:1 10 op1:3 crn:4 crm:4 op2:3 rt:5 op0=2
28
+SYS 1101 0101 00 l:1 11 op1:3 crn:4 crm:4 op2:3 rt:5 op0=3
29
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/target/arm/tcg/translate-a64.c
32
+++ b/target/arm/tcg/translate-a64.c
33
@@ -XXX,XX +XXX,XX @@ static void gen_sysreg_undef(DisasContext *s, bool isread,
34
* These are all essentially the same insn in 'read' and 'write'
35
* versions, with varying op0 fields.
36
*/
37
-static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
38
+static void handle_sys(DisasContext *s, bool isread,
39
unsigned int op0, unsigned int op1, unsigned int op2,
40
unsigned int crn, unsigned int crm, unsigned int rt)
27
{
41
{
28
NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_GET_CLASS(machine);
42
@@ -XXX,XX +XXX,XX @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
29
- MachineClass *mc = &nmc->parent;
43
}
30
+ MachineClass *mc = MACHINE_CLASS(nmc);
31
Object *obj;
32
33
if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) {
34
diff --git a/hw/mem/npcm7xx_mc.c b/hw/mem/npcm7xx_mc.c
35
index XXXXXXX..XXXXXXX 100644
36
--- a/hw/mem/npcm7xx_mc.c
37
+++ b/hw/mem/npcm7xx_mc.c
38
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_mc_realize(DeviceState *dev, Error **errp)
39
40
memory_region_init_io(&s->mmio, OBJECT(s), &npcm7xx_mc_ops, s, "regs",
41
NPCM7XX_MC_REGS_SIZE);
42
- sysbus_init_mmio(&s->parent, &s->mmio);
43
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio);
44
}
44
}
45
45
46
static void npcm7xx_mc_class_init(ObjectClass *klass, void *data)
46
-/* System
47
diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c
47
- * 31 22 21 20 19 18 16 15 12 11 8 7 5 4 0
48
index XXXXXXX..XXXXXXX 100644
48
- * +---------------------+---+-----+-----+-------+-------+-----+------+
49
--- a/hw/misc/npcm7xx_clk.c
49
- * | 1 1 0 1 0 1 0 1 0 0 | L | op0 | op1 | CRn | CRm | op2 | Rt |
50
+++ b/hw/misc/npcm7xx_clk.c
50
- * +---------------------+---+-----+-----+-------+-------+-----+------+
51
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_init(Object *obj)
51
- */
52
52
-static void disas_system(DisasContext *s, uint32_t insn)
53
memory_region_init_io(&s->iomem, obj, &npcm7xx_clk_ops, s,
53
+static bool trans_SYS(DisasContext *s, arg_SYS *a)
54
TYPE_NPCM7XX_CLK, 4 * KiB);
54
{
55
- sysbus_init_mmio(&s->parent, &s->iomem);
55
- unsigned int l, op0, op1, crn, crm, op2, rt;
56
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
56
- l = extract32(insn, 21, 1);
57
- op0 = extract32(insn, 19, 2);
58
- op1 = extract32(insn, 16, 3);
59
- crn = extract32(insn, 12, 4);
60
- crm = extract32(insn, 8, 4);
61
- op2 = extract32(insn, 5, 3);
62
- rt = extract32(insn, 0, 5);
63
-
64
- if (op0 == 0) {
65
- unallocated_encoding(s);
66
- return;
67
- }
68
- handle_sys(s, insn, l, op0, op1, op2, crn, crm, rt);
69
+ handle_sys(s, a->l, a->op0, a->op1, a->op2, a->crn, a->crm, a->rt);
70
+ return true;
57
}
71
}
58
72
59
static int npcm7xx_clk_post_load(void *opaque, int version_id)
73
/* Exception generation
60
diff --git a/hw/misc/npcm7xx_gcr.c b/hw/misc/npcm7xx_gcr.c
74
@@ -XXX,XX +XXX,XX @@ static void disas_b_exc_sys(DisasContext *s, uint32_t insn)
61
index XXXXXXX..XXXXXXX 100644
75
switch (extract32(insn, 25, 7)) {
62
--- a/hw/misc/npcm7xx_gcr.c
76
case 0x6a: /* Exception generation / System */
63
+++ b/hw/misc/npcm7xx_gcr.c
77
if (insn & (1 << 24)) {
64
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_gcr_init(Object *obj)
78
- if (extract32(insn, 22, 2) == 0) {
65
79
- disas_system(s, insn);
66
memory_region_init_io(&s->iomem, obj, &npcm7xx_gcr_ops, s,
80
- } else {
67
TYPE_NPCM7XX_GCR, 4 * KiB);
81
- unallocated_encoding(s);
68
- sysbus_init_mmio(&s->parent, &s->iomem);
82
- }
69
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
83
+ unallocated_encoding(s);
70
}
84
} else {
71
85
disas_exc(s, insn);
72
static const VMStateDescription vmstate_npcm7xx_gcr = {
86
}
73
diff --git a/hw/misc/npcm7xx_rng.c b/hw/misc/npcm7xx_rng.c
74
index XXXXXXX..XXXXXXX 100644
75
--- a/hw/misc/npcm7xx_rng.c
76
+++ b/hw/misc/npcm7xx_rng.c
77
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_rng_init(Object *obj)
78
79
memory_region_init_io(&s->iomem, obj, &npcm7xx_rng_ops, s, "regs",
80
NPCM7XX_RNG_REGS_SIZE);
81
- sysbus_init_mmio(&s->parent, &s->iomem);
82
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
83
}
84
85
static const VMStateDescription vmstate_npcm7xx_rng = {
86
diff --git a/hw/nvram/npcm7xx_otp.c b/hw/nvram/npcm7xx_otp.c
87
index XXXXXXX..XXXXXXX 100644
88
--- a/hw/nvram/npcm7xx_otp.c
89
+++ b/hw/nvram/npcm7xx_otp.c
90
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_otp_realize(DeviceState *dev, Error **errp)
91
{
92
NPCM7xxOTPClass *oc = NPCM7XX_OTP_GET_CLASS(dev);
93
NPCM7xxOTPState *s = NPCM7XX_OTP(dev);
94
- SysBusDevice *sbd = &s->parent;
95
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
96
97
memset(s->array, 0, sizeof(s->array));
98
99
diff --git a/hw/ssi/npcm7xx_fiu.c b/hw/ssi/npcm7xx_fiu.c
100
index XXXXXXX..XXXXXXX 100644
101
--- a/hw/ssi/npcm7xx_fiu.c
102
+++ b/hw/ssi/npcm7xx_fiu.c
103
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_fiu_hold_reset(Object *obj)
104
static void npcm7xx_fiu_realize(DeviceState *dev, Error **errp)
105
{
106
NPCM7xxFIUState *s = NPCM7XX_FIU(dev);
107
- SysBusDevice *sbd = &s->parent;
108
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
109
int i;
110
111
if (s->cs_count <= 0) {
112
--
87
--
113
2.20.1
88
2.34.1
114
89
115
90
diff view generated by jsdifflib
New patch
1
Convert the exception generation instructions SVC, HVC, SMC, BRK and
2
HLT to decodetree.
1
3
4
The old decoder decoded the halting-debug insnns DCPS1, DCPS2 and
5
DCPS3 just in order to then make them UNDEF; as with DRPS, we don't
6
bother to decode them, but document the patterns in a64.decode.
7
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 20230602155223.2040685-8-peter.maydell@linaro.org
11
---
12
target/arm/tcg/a64.decode | 15 +++
13
target/arm/tcg/translate-a64.c | 173 ++++++++++++---------------------
14
2 files changed, 79 insertions(+), 109 deletions(-)
15
16
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
17
index XXXXXXX..XXXXXXX 100644
18
--- a/target/arm/tcg/a64.decode
19
+++ b/target/arm/tcg/a64.decode
20
@@ -XXX,XX +XXX,XX @@ MSR_i_SVCR 1101 0101 0000 0 011 0100 0 mask:2 imm:1 011 11111
21
SYS 1101 0101 00 l:1 01 op1:3 crn:4 crm:4 op2:3 rt:5 op0=1
22
SYS 1101 0101 00 l:1 10 op1:3 crn:4 crm:4 op2:3 rt:5 op0=2
23
SYS 1101 0101 00 l:1 11 op1:3 crn:4 crm:4 op2:3 rt:5 op0=3
24
+
25
+# Exception generation
26
+
27
+@i16 .... .... ... imm:16 ... .. &i
28
+SVC 1101 0100 000 ................ 000 01 @i16
29
+HVC 1101 0100 000 ................ 000 10 @i16
30
+SMC 1101 0100 000 ................ 000 11 @i16
31
+BRK 1101 0100 001 ................ 000 00 @i16
32
+HLT 1101 0100 010 ................ 000 00 @i16
33
+# These insns always UNDEF unless in halting debug state, which
34
+# we don't implement. So we don't need to decode them. The patterns
35
+# are listed here as documentation.
36
+# DCPS1 1101 0100 101 ................ 000 01 @i16
37
+# DCPS2 1101 0100 101 ................ 000 10 @i16
38
+# DCPS3 1101 0100 101 ................ 000 11 @i16
39
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
40
index XXXXXXX..XXXXXXX 100644
41
--- a/target/arm/tcg/translate-a64.c
42
+++ b/target/arm/tcg/translate-a64.c
43
@@ -XXX,XX +XXX,XX @@ static bool trans_SYS(DisasContext *s, arg_SYS *a)
44
return true;
45
}
46
47
-/* Exception generation
48
- *
49
- * 31 24 23 21 20 5 4 2 1 0
50
- * +-----------------+-----+------------------------+-----+----+
51
- * | 1 1 0 1 0 1 0 0 | opc | imm16 | op2 | LL |
52
- * +-----------------------+------------------------+----------+
53
- */
54
-static void disas_exc(DisasContext *s, uint32_t insn)
55
+static bool trans_SVC(DisasContext *s, arg_i *a)
56
{
57
- int opc = extract32(insn, 21, 3);
58
- int op2_ll = extract32(insn, 0, 5);
59
- int imm16 = extract32(insn, 5, 16);
60
- uint32_t syndrome;
61
-
62
- switch (opc) {
63
- case 0:
64
- /* For SVC, HVC and SMC we advance the single-step state
65
- * machine before taking the exception. This is architecturally
66
- * mandated, to ensure that single-stepping a system call
67
- * instruction works properly.
68
- */
69
- switch (op2_ll) {
70
- case 1: /* SVC */
71
- syndrome = syn_aa64_svc(imm16);
72
- if (s->fgt_svc) {
73
- gen_exception_insn_el(s, 0, EXCP_UDEF, syndrome, 2);
74
- break;
75
- }
76
- gen_ss_advance(s);
77
- gen_exception_insn(s, 4, EXCP_SWI, syndrome);
78
- break;
79
- case 2: /* HVC */
80
- if (s->current_el == 0) {
81
- unallocated_encoding(s);
82
- break;
83
- }
84
- /* The pre HVC helper handles cases when HVC gets trapped
85
- * as an undefined insn by runtime configuration.
86
- */
87
- gen_a64_update_pc(s, 0);
88
- gen_helper_pre_hvc(cpu_env);
89
- gen_ss_advance(s);
90
- gen_exception_insn_el(s, 4, EXCP_HVC, syn_aa64_hvc(imm16), 2);
91
- break;
92
- case 3: /* SMC */
93
- if (s->current_el == 0) {
94
- unallocated_encoding(s);
95
- break;
96
- }
97
- gen_a64_update_pc(s, 0);
98
- gen_helper_pre_smc(cpu_env, tcg_constant_i32(syn_aa64_smc(imm16)));
99
- gen_ss_advance(s);
100
- gen_exception_insn_el(s, 4, EXCP_SMC, syn_aa64_smc(imm16), 3);
101
- break;
102
- default:
103
- unallocated_encoding(s);
104
- break;
105
- }
106
- break;
107
- case 1:
108
- if (op2_ll != 0) {
109
- unallocated_encoding(s);
110
- break;
111
- }
112
- /* BRK */
113
- gen_exception_bkpt_insn(s, syn_aa64_bkpt(imm16));
114
- break;
115
- case 2:
116
- if (op2_ll != 0) {
117
- unallocated_encoding(s);
118
- break;
119
- }
120
- /* HLT. This has two purposes.
121
- * Architecturally, it is an external halting debug instruction.
122
- * Since QEMU doesn't implement external debug, we treat this as
123
- * it is required for halting debug disabled: it will UNDEF.
124
- * Secondly, "HLT 0xf000" is the A64 semihosting syscall instruction.
125
- */
126
- if (semihosting_enabled(s->current_el == 0) && imm16 == 0xf000) {
127
- gen_exception_internal_insn(s, EXCP_SEMIHOST);
128
- } else {
129
- unallocated_encoding(s);
130
- }
131
- break;
132
- case 5:
133
- if (op2_ll < 1 || op2_ll > 3) {
134
- unallocated_encoding(s);
135
- break;
136
- }
137
- /* DCPS1, DCPS2, DCPS3 */
138
- unallocated_encoding(s);
139
- break;
140
- default:
141
- unallocated_encoding(s);
142
- break;
143
+ /*
144
+ * For SVC, HVC and SMC we advance the single-step state
145
+ * machine before taking the exception. This is architecturally
146
+ * mandated, to ensure that single-stepping a system call
147
+ * instruction works properly.
148
+ */
149
+ uint32_t syndrome = syn_aa64_svc(a->imm);
150
+ if (s->fgt_svc) {
151
+ gen_exception_insn_el(s, 0, EXCP_UDEF, syndrome, 2);
152
+ return true;
153
}
154
+ gen_ss_advance(s);
155
+ gen_exception_insn(s, 4, EXCP_SWI, syndrome);
156
+ return true;
157
}
158
159
-/* Branches, exception generating and system instructions */
160
-static void disas_b_exc_sys(DisasContext *s, uint32_t insn)
161
+static bool trans_HVC(DisasContext *s, arg_i *a)
162
{
163
- switch (extract32(insn, 25, 7)) {
164
- case 0x6a: /* Exception generation / System */
165
- if (insn & (1 << 24)) {
166
- unallocated_encoding(s);
167
- } else {
168
- disas_exc(s, insn);
169
- }
170
- break;
171
- default:
172
+ if (s->current_el == 0) {
173
unallocated_encoding(s);
174
- break;
175
+ return true;
176
}
177
+ /*
178
+ * The pre HVC helper handles cases when HVC gets trapped
179
+ * as an undefined insn by runtime configuration.
180
+ */
181
+ gen_a64_update_pc(s, 0);
182
+ gen_helper_pre_hvc(cpu_env);
183
+ /* Architecture requires ss advance before we do the actual work */
184
+ gen_ss_advance(s);
185
+ gen_exception_insn_el(s, 4, EXCP_HVC, syn_aa64_hvc(a->imm), 2);
186
+ return true;
187
+}
188
+
189
+static bool trans_SMC(DisasContext *s, arg_i *a)
190
+{
191
+ if (s->current_el == 0) {
192
+ unallocated_encoding(s);
193
+ return true;
194
+ }
195
+ gen_a64_update_pc(s, 0);
196
+ gen_helper_pre_smc(cpu_env, tcg_constant_i32(syn_aa64_smc(a->imm)));
197
+ /* Architecture requires ss advance before we do the actual work */
198
+ gen_ss_advance(s);
199
+ gen_exception_insn_el(s, 4, EXCP_SMC, syn_aa64_smc(a->imm), 3);
200
+ return true;
201
+}
202
+
203
+static bool trans_BRK(DisasContext *s, arg_i *a)
204
+{
205
+ gen_exception_bkpt_insn(s, syn_aa64_bkpt(a->imm));
206
+ return true;
207
+}
208
+
209
+static bool trans_HLT(DisasContext *s, arg_i *a)
210
+{
211
+ /*
212
+ * HLT. This has two purposes.
213
+ * Architecturally, it is an external halting debug instruction.
214
+ * Since QEMU doesn't implement external debug, we treat this as
215
+ * it is required for halting debug disabled: it will UNDEF.
216
+ * Secondly, "HLT 0xf000" is the A64 semihosting syscall instruction.
217
+ */
218
+ if (semihosting_enabled(s->current_el == 0) && a->imm == 0xf000) {
219
+ gen_exception_internal_insn(s, EXCP_SEMIHOST);
220
+ } else {
221
+ unallocated_encoding(s);
222
+ }
223
+ return true;
224
}
225
226
/*
227
@@ -XXX,XX +XXX,XX @@ static bool btype_destination_ok(uint32_t insn, bool bt, int btype)
228
static void disas_a64_legacy(DisasContext *s, uint32_t insn)
229
{
230
switch (extract32(insn, 25, 4)) {
231
- case 0xa: case 0xb: /* Branch, exception generation and system insns */
232
- disas_b_exc_sys(s, insn);
233
- break;
234
case 0x4:
235
case 0x6:
236
case 0xc:
237
--
238
2.34.1
diff view generated by jsdifflib
New patch
1
1
Convert the instructions in the load/store exclusive (STXR,
2
STLXR, LDXR, LDAXR) and load/store ordered (STLR, STLLR,
3
LDAR, LDLAR) to decodetree.
4
5
Note that for STLR, STLLR, LDAR, LDLAR this fixes an under-decoding
6
in the legacy decoder where we were not checking that the RES1 bits
7
in the Rs and Rt2 fields were set.
8
9
The new function ldst_iss_sf() is equivalent to the existing
10
disas_ldst_compute_iss_sf(), but it takes the pre-decoded 'ext' field
11
rather than taking an undecoded two-bit opc field and extracting
12
'ext' from it. Once all the loads and stores have been converted
13
to decodetree disas_ldst_compute_iss_sf() will be unused and
14
can be deleted.
15
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
18
Message-id: 20230602155223.2040685-9-peter.maydell@linaro.org
19
---
20
target/arm/tcg/a64.decode | 11 +++
21
target/arm/tcg/translate-a64.c | 154 ++++++++++++++++++++-------------
22
2 files changed, 103 insertions(+), 62 deletions(-)
23
24
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
25
index XXXXXXX..XXXXXXX 100644
26
--- a/target/arm/tcg/a64.decode
27
+++ b/target/arm/tcg/a64.decode
28
@@ -XXX,XX +XXX,XX @@ HLT 1101 0100 010 ................ 000 00 @i16
29
# DCPS1 1101 0100 101 ................ 000 01 @i16
30
# DCPS2 1101 0100 101 ................ 000 10 @i16
31
# DCPS3 1101 0100 101 ................ 000 11 @i16
32
+
33
+# Loads and stores
34
+
35
+&stxr rn rt rt2 rs sz lasr
36
+&stlr rn rt sz lasr
37
+@stxr sz:2 ...... ... rs:5 lasr:1 rt2:5 rn:5 rt:5 &stxr
38
+@stlr sz:2 ...... ... ..... lasr:1 ..... rn:5 rt:5 &stlr
39
+STXR .. 001000 000 ..... . ..... ..... ..... @stxr # inc STLXR
40
+LDXR .. 001000 010 ..... . ..... ..... ..... @stxr # inc LDAXR
41
+STLR .. 001000 100 11111 . 11111 ..... ..... @stlr # inc STLLR
42
+LDAR .. 001000 110 11111 . 11111 ..... ..... @stlr # inc LDLAR
43
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
44
index XXXXXXX..XXXXXXX 100644
45
--- a/target/arm/tcg/translate-a64.c
46
+++ b/target/arm/tcg/translate-a64.c
47
@@ -XXX,XX +XXX,XX @@ static bool disas_ldst_compute_iss_sf(int size, bool is_signed, int opc)
48
return regsize == 64;
49
}
50
51
+static bool ldst_iss_sf(int size, bool sign, bool ext)
52
+{
53
+
54
+ if (sign) {
55
+ /*
56
+ * Signed loads are 64 bit results if we are not going to
57
+ * do a zero-extend from 32 to 64 after the load.
58
+ * (For a store, sign and ext are always false.)
59
+ */
60
+ return !ext;
61
+ } else {
62
+ /* Unsigned loads/stores work at the specified size */
63
+ return size == MO_64;
64
+ }
65
+}
66
+
67
+static bool trans_STXR(DisasContext *s, arg_stxr *a)
68
+{
69
+ if (a->rn == 31) {
70
+ gen_check_sp_alignment(s);
71
+ }
72
+ if (a->lasr) {
73
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
74
+ }
75
+ gen_store_exclusive(s, a->rs, a->rt, a->rt2, a->rn, a->sz, false);
76
+ return true;
77
+}
78
+
79
+static bool trans_LDXR(DisasContext *s, arg_stxr *a)
80
+{
81
+ if (a->rn == 31) {
82
+ gen_check_sp_alignment(s);
83
+ }
84
+ gen_load_exclusive(s, a->rt, a->rt2, a->rn, a->sz, false);
85
+ if (a->lasr) {
86
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
87
+ }
88
+ return true;
89
+}
90
+
91
+static bool trans_STLR(DisasContext *s, arg_stlr *a)
92
+{
93
+ TCGv_i64 clean_addr;
94
+ MemOp memop;
95
+ bool iss_sf = ldst_iss_sf(a->sz, false, false);
96
+
97
+ /*
98
+ * StoreLORelease is the same as Store-Release for QEMU, but
99
+ * needs the feature-test.
100
+ */
101
+ if (!a->lasr && !dc_isar_feature(aa64_lor, s)) {
102
+ return false;
103
+ }
104
+ /* Generate ISS for non-exclusive accesses including LASR. */
105
+ if (a->rn == 31) {
106
+ gen_check_sp_alignment(s);
107
+ }
108
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
109
+ memop = check_ordered_align(s, a->rn, 0, true, a->sz);
110
+ clean_addr = gen_mte_check1(s, cpu_reg_sp(s, a->rn),
111
+ true, a->rn != 31, memop);
112
+ do_gpr_st(s, cpu_reg(s, a->rt), clean_addr, memop, true, a->rt,
113
+ iss_sf, a->lasr);
114
+ return true;
115
+}
116
+
117
+static bool trans_LDAR(DisasContext *s, arg_stlr *a)
118
+{
119
+ TCGv_i64 clean_addr;
120
+ MemOp memop;
121
+ bool iss_sf = ldst_iss_sf(a->sz, false, false);
122
+
123
+ /* LoadLOAcquire is the same as Load-Acquire for QEMU. */
124
+ if (!a->lasr && !dc_isar_feature(aa64_lor, s)) {
125
+ return false;
126
+ }
127
+ /* Generate ISS for non-exclusive accesses including LASR. */
128
+ if (a->rn == 31) {
129
+ gen_check_sp_alignment(s);
130
+ }
131
+ memop = check_ordered_align(s, a->rn, 0, false, a->sz);
132
+ clean_addr = gen_mte_check1(s, cpu_reg_sp(s, a->rn),
133
+ false, a->rn != 31, memop);
134
+ do_gpr_ld(s, cpu_reg(s, a->rt), clean_addr, memop, false, true,
135
+ a->rt, iss_sf, a->lasr);
136
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
137
+ return true;
138
+}
139
+
140
/* Load/store exclusive
141
*
142
* 31 30 29 24 23 22 21 20 16 15 14 10 9 5 4 0
143
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
144
int is_lasr = extract32(insn, 15, 1);
145
int o2_L_o1_o0 = extract32(insn, 21, 3) * 2 | is_lasr;
146
int size = extract32(insn, 30, 2);
147
- TCGv_i64 clean_addr;
148
- MemOp memop;
149
150
switch (o2_L_o1_o0) {
151
- case 0x0: /* STXR */
152
- case 0x1: /* STLXR */
153
- if (rn == 31) {
154
- gen_check_sp_alignment(s);
155
- }
156
- if (is_lasr) {
157
- tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
158
- }
159
- gen_store_exclusive(s, rs, rt, rt2, rn, size, false);
160
- return;
161
-
162
- case 0x4: /* LDXR */
163
- case 0x5: /* LDAXR */
164
- if (rn == 31) {
165
- gen_check_sp_alignment(s);
166
- }
167
- gen_load_exclusive(s, rt, rt2, rn, size, false);
168
- if (is_lasr) {
169
- tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
170
- }
171
- return;
172
-
173
- case 0x8: /* STLLR */
174
- if (!dc_isar_feature(aa64_lor, s)) {
175
- break;
176
- }
177
- /* StoreLORelease is the same as Store-Release for QEMU. */
178
- /* fall through */
179
- case 0x9: /* STLR */
180
- /* Generate ISS for non-exclusive accesses including LASR. */
181
- if (rn == 31) {
182
- gen_check_sp_alignment(s);
183
- }
184
- tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
185
- memop = check_ordered_align(s, rn, 0, true, size);
186
- clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn),
187
- true, rn != 31, memop);
188
- do_gpr_st(s, cpu_reg(s, rt), clean_addr, memop, true, rt,
189
- disas_ldst_compute_iss_sf(size, false, 0), is_lasr);
190
- return;
191
-
192
- case 0xc: /* LDLAR */
193
- if (!dc_isar_feature(aa64_lor, s)) {
194
- break;
195
- }
196
- /* LoadLOAcquire is the same as Load-Acquire for QEMU. */
197
- /* fall through */
198
- case 0xd: /* LDAR */
199
- /* Generate ISS for non-exclusive accesses including LASR. */
200
- if (rn == 31) {
201
- gen_check_sp_alignment(s);
202
- }
203
- memop = check_ordered_align(s, rn, 0, false, size);
204
- clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn),
205
- false, rn != 31, memop);
206
- do_gpr_ld(s, cpu_reg(s, rt), clean_addr, memop, false, true,
207
- rt, disas_ldst_compute_iss_sf(size, false, 0), is_lasr);
208
- tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
209
- return;
210
-
211
case 0x2: case 0x3: /* CASP / STXP */
212
if (size & 2) { /* STXP / STLXP */
213
if (rn == 31) {
214
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
215
return;
216
}
217
break;
218
+ default:
219
+ /* Handled in decodetree */
220
+ break;
221
}
222
unallocated_encoding(s);
223
}
224
--
225
2.34.1
diff view generated by jsdifflib
1
In commit cd8be50e58f63413c0 we converted the A32 coprocessor
1
Convert the load/store exclusive pair (LDXP, STXP, LDAXP, STLXP),
2
insns to decodetree. This accidentally broke XScale/iWMMXt insns,
2
compare-and-swap pair (CASP, CASPA, CASPAL, CASPL), and compare-and
3
because it moved the handling of "cp insns which are handled
3
swap (CAS, CASA, CASAL, CASL) instructions to decodetree.
4
by looking up the cp register in the hashtable" from after the
5
call to the legacy disas_xscale_insn() decode to before it,
6
with the result that all XScale/iWMMXt insns now UNDEF.
7
4
8
Update valid_cp() so that it knows that on XScale cp 0 and 1
9
are not standard coprocessor instructions; this will cause
10
the decodetree trans_ functions to ignore them, so that
11
execution will correctly get through to the legacy decode again.
12
13
Cc: qemu-stable@nongnu.org
14
Reported-by: Guenter Roeck <linux@roeck-us.net>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
17
Tested-by: Guenter Roeck <linux@roeck-us.net>
7
Message-id: 20230602155223.2040685-10-peter.maydell@linaro.org
18
Message-id: 20210108195157.32067-1-peter.maydell@linaro.org
19
---
8
---
20
target/arm/translate.c | 7 +++++++
9
target/arm/tcg/a64.decode | 11 +++
21
1 file changed, 7 insertions(+)
10
target/arm/tcg/translate-a64.c | 121 ++++++++++++---------------------
11
2 files changed, 53 insertions(+), 79 deletions(-)
22
12
23
diff --git a/target/arm/translate.c b/target/arm/translate.c
13
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
24
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
25
--- a/target/arm/translate.c
15
--- a/target/arm/tcg/a64.decode
26
+++ b/target/arm/translate.c
16
+++ b/target/arm/tcg/a64.decode
27
@@ -XXX,XX +XXX,XX @@ static bool valid_cp(DisasContext *s, int cp)
17
@@ -XXX,XX +XXX,XX @@ HLT 1101 0100 010 ................ 000 00 @i16
28
* only cp14 and cp15 are valid, and other values aren't considered
18
&stlr rn rt sz lasr
29
* to be in the coprocessor-instruction space at all. v8M still
19
@stxr sz:2 ...... ... rs:5 lasr:1 rt2:5 rn:5 rt:5 &stxr
30
* permits coprocessors 0..7.
20
@stlr sz:2 ...... ... ..... lasr:1 ..... rn:5 rt:5 &stlr
31
+ * For XScale, we must not decode the XScale cp0, cp1 space as
21
+%imm1_30_p2 30:1 !function=plus_2
32
+ * a standard coprocessor insn, because we want to fall through to
22
+@stxp .. ...... ... rs:5 lasr:1 rt2:5 rn:5 rt:5 &stxr sz=%imm1_30_p2
33
+ * the legacy disas_xscale_insn() decoder after decodetree is done.
23
STXR .. 001000 000 ..... . ..... ..... ..... @stxr # inc STLXR
34
*/
24
LDXR .. 001000 010 ..... . ..... ..... ..... @stxr # inc LDAXR
35
+ if (arm_dc_feature(s, ARM_FEATURE_XSCALE) && (cp == 0 || cp == 1)) {
25
STLR .. 001000 100 11111 . 11111 ..... ..... @stlr # inc STLLR
26
LDAR .. 001000 110 11111 . 11111 ..... ..... @stlr # inc LDLAR
27
+
28
+STXP 1 . 001000 001 ..... . ..... ..... ..... @stxp # inc STLXP
29
+LDXP 1 . 001000 011 ..... . ..... ..... ..... @stxp # inc LDAXP
30
+
31
+# CASP, CASPA, CASPAL, CASPL (we don't decode the bits that determine
32
+# acquire/release semantics because QEMU's cmpxchg always has those)
33
+CASP 0 . 001000 0 - 1 rs:5 - 11111 rn:5 rt:5 sz=%imm1_30_p2
34
+# CAS, CASA, CASAL, CASL
35
+CAS sz:2 001000 1 - 1 rs:5 - 11111 rn:5 rt:5
36
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
37
index XXXXXXX..XXXXXXX 100644
38
--- a/target/arm/tcg/translate-a64.c
39
+++ b/target/arm/tcg/translate-a64.c
40
@@ -XXX,XX +XXX,XX @@ static bool trans_LDAR(DisasContext *s, arg_stlr *a)
41
return true;
42
}
43
44
-/* Load/store exclusive
45
- *
46
- * 31 30 29 24 23 22 21 20 16 15 14 10 9 5 4 0
47
- * +-----+-------------+----+---+----+------+----+-------+------+------+
48
- * | sz | 0 0 1 0 0 0 | o2 | L | o1 | Rs | o0 | Rt2 | Rn | Rt |
49
- * +-----+-------------+----+---+----+------+----+-------+------+------+
50
- *
51
- * sz: 00 -> 8 bit, 01 -> 16 bit, 10 -> 32 bit, 11 -> 64 bit
52
- * L: 0 -> store, 1 -> load
53
- * o2: 0 -> exclusive, 1 -> not
54
- * o1: 0 -> single register, 1 -> register pair
55
- * o0: 1 -> load-acquire/store-release, 0 -> not
56
- */
57
-static void disas_ldst_excl(DisasContext *s, uint32_t insn)
58
+static bool trans_STXP(DisasContext *s, arg_stxr *a)
59
{
60
- int rt = extract32(insn, 0, 5);
61
- int rn = extract32(insn, 5, 5);
62
- int rt2 = extract32(insn, 10, 5);
63
- int rs = extract32(insn, 16, 5);
64
- int is_lasr = extract32(insn, 15, 1);
65
- int o2_L_o1_o0 = extract32(insn, 21, 3) * 2 | is_lasr;
66
- int size = extract32(insn, 30, 2);
67
-
68
- switch (o2_L_o1_o0) {
69
- case 0x2: case 0x3: /* CASP / STXP */
70
- if (size & 2) { /* STXP / STLXP */
71
- if (rn == 31) {
72
- gen_check_sp_alignment(s);
73
- }
74
- if (is_lasr) {
75
- tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
76
- }
77
- gen_store_exclusive(s, rs, rt, rt2, rn, size, true);
78
- return;
79
- }
80
- if (rt2 == 31
81
- && ((rt | rs) & 1) == 0
82
- && dc_isar_feature(aa64_atomics, s)) {
83
- /* CASP / CASPL */
84
- gen_compare_and_swap_pair(s, rs, rt, rn, size | 2);
85
- return;
86
- }
87
- break;
88
-
89
- case 0x6: case 0x7: /* CASPA / LDXP */
90
- if (size & 2) { /* LDXP / LDAXP */
91
- if (rn == 31) {
92
- gen_check_sp_alignment(s);
93
- }
94
- gen_load_exclusive(s, rt, rt2, rn, size, true);
95
- if (is_lasr) {
96
- tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
97
- }
98
- return;
99
- }
100
- if (rt2 == 31
101
- && ((rt | rs) & 1) == 0
102
- && dc_isar_feature(aa64_atomics, s)) {
103
- /* CASPA / CASPAL */
104
- gen_compare_and_swap_pair(s, rs, rt, rn, size | 2);
105
- return;
106
- }
107
- break;
108
-
109
- case 0xa: /* CAS */
110
- case 0xb: /* CASL */
111
- case 0xe: /* CASA */
112
- case 0xf: /* CASAL */
113
- if (rt2 == 31 && dc_isar_feature(aa64_atomics, s)) {
114
- gen_compare_and_swap(s, rs, rt, rn, size);
115
- return;
116
- }
117
- break;
118
- default:
119
- /* Handled in decodetree */
120
- break;
121
+ if (a->rn == 31) {
122
+ gen_check_sp_alignment(s);
123
}
124
- unallocated_encoding(s);
125
+ if (a->lasr) {
126
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
127
+ }
128
+ gen_store_exclusive(s, a->rs, a->rt, a->rt2, a->rn, a->sz, true);
129
+ return true;
130
+}
131
+
132
+static bool trans_LDXP(DisasContext *s, arg_stxr *a)
133
+{
134
+ if (a->rn == 31) {
135
+ gen_check_sp_alignment(s);
136
+ }
137
+ gen_load_exclusive(s, a->rt, a->rt2, a->rn, a->sz, true);
138
+ if (a->lasr) {
139
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
140
+ }
141
+ return true;
142
+}
143
+
144
+static bool trans_CASP(DisasContext *s, arg_CASP *a)
145
+{
146
+ if (!dc_isar_feature(aa64_atomics, s)) {
147
+ return false;
148
+ }
149
+ if (((a->rt | a->rs) & 1) != 0) {
36
+ return false;
150
+ return false;
37
+ }
151
+ }
38
+
152
+
39
if (arm_dc_feature(s, ARM_FEATURE_V8) &&
153
+ gen_compare_and_swap_pair(s, a->rs, a->rt, a->rn, a->sz);
40
!arm_dc_feature(s, ARM_FEATURE_M)) {
154
+ return true;
41
return cp >= 14;
155
+}
156
+
157
+static bool trans_CAS(DisasContext *s, arg_CAS *a)
158
+{
159
+ if (!dc_isar_feature(aa64_atomics, s)) {
160
+ return false;
161
+ }
162
+ gen_compare_and_swap(s, a->rs, a->rt, a->rn, a->sz);
163
+ return true;
164
}
165
166
/*
167
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_tag(DisasContext *s, uint32_t insn)
168
static void disas_ldst(DisasContext *s, uint32_t insn)
169
{
170
switch (extract32(insn, 24, 6)) {
171
- case 0x08: /* Load/store exclusive */
172
- disas_ldst_excl(s, insn);
173
- break;
174
case 0x18: case 0x1c: /* Load register (literal) */
175
disas_ld_lit(s, insn);
176
break;
42
--
177
--
43
2.20.1
178
2.34.1
44
45
diff view generated by jsdifflib
New patch
1
Convert the "Load register (literal)" instruction class to
2
decodetree.
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20230602155223.2040685-11-peter.maydell@linaro.org
7
---
8
target/arm/tcg/a64.decode | 13 ++++++
9
target/arm/tcg/translate-a64.c | 76 ++++++++++------------------------
10
2 files changed, 35 insertions(+), 54 deletions(-)
11
12
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/arm/tcg/a64.decode
15
+++ b/target/arm/tcg/a64.decode
16
@@ -XXX,XX +XXX,XX @@ LDXP 1 . 001000 011 ..... . ..... ..... ..... @stxp # inc LDAXP
17
CASP 0 . 001000 0 - 1 rs:5 - 11111 rn:5 rt:5 sz=%imm1_30_p2
18
# CAS, CASA, CASAL, CASL
19
CAS sz:2 001000 1 - 1 rs:5 - 11111 rn:5 rt:5
20
+
21
+&ldlit rt imm sz sign
22
+@ldlit .. ... . .. ................... rt:5 &ldlit imm=%imm19
23
+
24
+LD_lit 00 011 0 00 ................... ..... @ldlit sz=2 sign=0
25
+LD_lit 01 011 0 00 ................... ..... @ldlit sz=3 sign=0
26
+LD_lit 10 011 0 00 ................... ..... @ldlit sz=2 sign=1
27
+LD_lit_v 00 011 1 00 ................... ..... @ldlit sz=2 sign=0
28
+LD_lit_v 01 011 1 00 ................... ..... @ldlit sz=3 sign=0
29
+LD_lit_v 10 011 1 00 ................... ..... @ldlit sz=4 sign=0
30
+
31
+# PRFM
32
+NOP 11 011 0 00 ------------------- -----
33
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
34
index XXXXXXX..XXXXXXX 100644
35
--- a/target/arm/tcg/translate-a64.c
36
+++ b/target/arm/tcg/translate-a64.c
37
@@ -XXX,XX +XXX,XX @@ static bool trans_CAS(DisasContext *s, arg_CAS *a)
38
return true;
39
}
40
41
-/*
42
- * Load register (literal)
43
- *
44
- * 31 30 29 27 26 25 24 23 5 4 0
45
- * +-----+-------+---+-----+-------------------+-------+
46
- * | opc | 0 1 1 | V | 0 0 | imm19 | Rt |
47
- * +-----+-------+---+-----+-------------------+-------+
48
- *
49
- * V: 1 -> vector (simd/fp)
50
- * opc (non-vector): 00 -> 32 bit, 01 -> 64 bit,
51
- * 10-> 32 bit signed, 11 -> prefetch
52
- * opc (vector): 00 -> 32 bit, 01 -> 64 bit, 10 -> 128 bit (11 unallocated)
53
- */
54
-static void disas_ld_lit(DisasContext *s, uint32_t insn)
55
+static bool trans_LD_lit(DisasContext *s, arg_ldlit *a)
56
{
57
- int rt = extract32(insn, 0, 5);
58
- int64_t imm = sextract32(insn, 5, 19) << 2;
59
- bool is_vector = extract32(insn, 26, 1);
60
- int opc = extract32(insn, 30, 2);
61
- bool is_signed = false;
62
- int size = 2;
63
- TCGv_i64 tcg_rt, clean_addr;
64
+ bool iss_sf = ldst_iss_sf(a->sz, a->sign, false);
65
+ TCGv_i64 tcg_rt = cpu_reg(s, a->rt);
66
+ TCGv_i64 clean_addr = tcg_temp_new_i64();
67
+ MemOp memop = finalize_memop(s, a->sz + a->sign * MO_SIGN);
68
+
69
+ gen_pc_plus_diff(s, clean_addr, a->imm);
70
+ do_gpr_ld(s, tcg_rt, clean_addr, memop,
71
+ false, true, a->rt, iss_sf, false);
72
+ return true;
73
+}
74
+
75
+static bool trans_LD_lit_v(DisasContext *s, arg_ldlit *a)
76
+{
77
+ /* Load register (literal), vector version */
78
+ TCGv_i64 clean_addr;
79
MemOp memop;
80
81
- if (is_vector) {
82
- if (opc == 3) {
83
- unallocated_encoding(s);
84
- return;
85
- }
86
- size = 2 + opc;
87
- if (!fp_access_check(s)) {
88
- return;
89
- }
90
- memop = finalize_memop_asimd(s, size);
91
- } else {
92
- if (opc == 3) {
93
- /* PRFM (literal) : prefetch */
94
- return;
95
- }
96
- size = 2 + extract32(opc, 0, 1);
97
- is_signed = extract32(opc, 1, 1);
98
- memop = finalize_memop(s, size + is_signed * MO_SIGN);
99
+ if (!fp_access_check(s)) {
100
+ return true;
101
}
102
-
103
- tcg_rt = cpu_reg(s, rt);
104
-
105
+ memop = finalize_memop_asimd(s, a->sz);
106
clean_addr = tcg_temp_new_i64();
107
- gen_pc_plus_diff(s, clean_addr, imm);
108
-
109
- if (is_vector) {
110
- do_fp_ld(s, rt, clean_addr, memop);
111
- } else {
112
- /* Only unsigned 32bit loads target 32bit registers. */
113
- bool iss_sf = opc != 0;
114
- do_gpr_ld(s, tcg_rt, clean_addr, memop, false, true, rt, iss_sf, false);
115
- }
116
+ gen_pc_plus_diff(s, clean_addr, a->imm);
117
+ do_fp_ld(s, a->rt, clean_addr, memop);
118
+ return true;
119
}
120
121
/*
122
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_tag(DisasContext *s, uint32_t insn)
123
static void disas_ldst(DisasContext *s, uint32_t insn)
124
{
125
switch (extract32(insn, 24, 6)) {
126
- case 0x18: case 0x1c: /* Load register (literal) */
127
- disas_ld_lit(s, insn);
128
- break;
129
case 0x28: case 0x29:
130
case 0x2c: case 0x2d: /* Load/store pair (all forms) */
131
disas_ldst_pair(s, insn);
132
--
133
2.34.1
diff view generated by jsdifflib
1
From: Hao Wu <wuhaotsh@google.com>
1
Convert the load/store register pair insns (LDP, STP,
2
LDNP, STNP, LDPSW, STGP) to decodetree.
2
3
3
The PWM module is part of NPCM7XX module. Each NPCM7XX module has two
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
identical PWM modules. Each module contains 4 PWM entries. Each PWM has
5
Message-id: 20230602155223.2040685-12-peter.maydell@linaro.org
5
two outputs: frequency and duty_cycle. Both are computed using inputs
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
from software side.
7
---
8
target/arm/tcg/a64.decode | 61 +++++
9
target/arm/tcg/translate-a64.c | 422 ++++++++++++++++-----------------
10
2 files changed, 268 insertions(+), 215 deletions(-)
7
11
8
This module does not model detail pulse signals since it is expensive.
12
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
9
It also does not model interrupts and watchdogs that are dependant on
10
the detail models. The interfaces for these are left in the module so
11
that anyone in need for these functionalities can implement on their
12
own.
13
14
The user can read the duty cycle and frequency using qom-get command.
15
16
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
17
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
18
Signed-off-by: Hao Wu <wuhaotsh@google.com>
19
Message-id: 20210108190945.949196-5-wuhaotsh@google.com
20
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
22
---
23
docs/system/arm/nuvoton.rst | 2 +-
24
include/hw/arm/npcm7xx.h | 2 +
25
include/hw/misc/npcm7xx_pwm.h | 105 +++++++
26
hw/arm/npcm7xx.c | 26 +-
27
hw/misc/npcm7xx_pwm.c | 550 ++++++++++++++++++++++++++++++++++
28
hw/misc/meson.build | 1 +
29
hw/misc/trace-events | 6 +
30
7 files changed, 689 insertions(+), 3 deletions(-)
31
create mode 100644 include/hw/misc/npcm7xx_pwm.h
32
create mode 100644 hw/misc/npcm7xx_pwm.c
33
34
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
35
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
36
--- a/docs/system/arm/nuvoton.rst
14
--- a/target/arm/tcg/a64.decode
37
+++ b/docs/system/arm/nuvoton.rst
15
+++ b/target/arm/tcg/a64.decode
38
@@ -XXX,XX +XXX,XX @@ Supported devices
16
@@ -XXX,XX +XXX,XX @@ LD_lit_v 10 011 1 00 ................... ..... @ldlit sz=4 sign=0
39
* USB host (USBH)
17
40
* GPIO controller
18
# PRFM
41
* Analog to Digital Converter (ADC)
19
NOP 11 011 0 00 ------------------- -----
42
+ * Pulse Width Modulation (PWM)
20
+
43
21
+&ldstpair rt2 rt rn imm sz sign w p
44
Missing devices
22
+@ldstpair .. ... . ... . imm:s7 rt2:5 rn:5 rt:5 &ldstpair
45
---------------
23
+
46
@@ -XXX,XX +XXX,XX @@ Missing devices
24
+# STNP, LDNP: Signed offset, non-temporal hint. We don't emulate caches
47
* Peripheral SPI controller (PSPI)
25
+# so we ignore hints about data access patterns, and handle these like
48
* SD/MMC host
26
+# plain signed offset.
49
* PECI interface
27
+STP 00 101 0 000 0 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=0 w=0
50
- * Pulse Width Modulation (PWM)
28
+LDP 00 101 0 000 1 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=0 w=0
51
* Tachometer
29
+STP 10 101 0 000 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=0
52
* PCI and PCIe root complex and bridges
30
+LDP 10 101 0 000 1 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=0
53
* VDM and MCTP support
31
+STP_v 00 101 1 000 0 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=0 w=0
54
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
32
+LDP_v 00 101 1 000 1 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=0 w=0
33
+STP_v 01 101 1 000 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=0
34
+LDP_v 01 101 1 000 1 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=0
35
+STP_v 10 101 1 000 0 ....... ..... ..... ..... @ldstpair sz=4 sign=0 p=0 w=0
36
+LDP_v 10 101 1 000 1 ....... ..... ..... ..... @ldstpair sz=4 sign=0 p=0 w=0
37
+
38
+# STP and LDP: post-indexed
39
+STP 00 101 0 001 0 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=1 w=1
40
+LDP 00 101 0 001 1 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=1 w=1
41
+LDP 01 101 0 001 1 ....... ..... ..... ..... @ldstpair sz=2 sign=1 p=1 w=1
42
+STP 10 101 0 001 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=1 w=1
43
+LDP 10 101 0 001 1 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=1 w=1
44
+STP_v 00 101 1 001 0 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=1 w=1
45
+LDP_v 00 101 1 001 1 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=1 w=1
46
+STP_v 01 101 1 001 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=1 w=1
47
+LDP_v 01 101 1 001 1 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=1 w=1
48
+STP_v 10 101 1 001 0 ....... ..... ..... ..... @ldstpair sz=4 sign=0 p=1 w=1
49
+LDP_v 10 101 1 001 1 ....... ..... ..... ..... @ldstpair sz=4 sign=0 p=1 w=1
50
+
51
+# STP and LDP: offset
52
+STP 00 101 0 010 0 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=0 w=0
53
+LDP 00 101 0 010 1 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=0 w=0
54
+LDP 01 101 0 010 1 ....... ..... ..... ..... @ldstpair sz=2 sign=1 p=0 w=0
55
+STP 10 101 0 010 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=0
56
+LDP 10 101 0 010 1 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=0
57
+STP_v 00 101 1 010 0 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=0 w=0
58
+LDP_v 00 101 1 010 1 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=0 w=0
59
+STP_v 01 101 1 010 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=0
60
+LDP_v 01 101 1 010 1 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=0
61
+STP_v 10 101 1 010 0 ....... ..... ..... ..... @ldstpair sz=4 sign=0 p=0 w=0
62
+LDP_v 10 101 1 010 1 ....... ..... ..... ..... @ldstpair sz=4 sign=0 p=0 w=0
63
+
64
+# STP and LDP: pre-indexed
65
+STP 00 101 0 011 0 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=0 w=1
66
+LDP 00 101 0 011 1 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=0 w=1
67
+LDP 01 101 0 011 1 ....... ..... ..... ..... @ldstpair sz=2 sign=1 p=0 w=1
68
+STP 10 101 0 011 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=1
69
+LDP 10 101 0 011 1 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=1
70
+STP_v 00 101 1 011 0 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=0 w=1
71
+LDP_v 00 101 1 011 1 ....... ..... ..... ..... @ldstpair sz=2 sign=0 p=0 w=1
72
+STP_v 01 101 1 011 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=1
73
+LDP_v 01 101 1 011 1 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=1
74
+STP_v 10 101 1 011 0 ....... ..... ..... ..... @ldstpair sz=4 sign=0 p=0 w=1
75
+LDP_v 10 101 1 011 1 ....... ..... ..... ..... @ldstpair sz=4 sign=0 p=0 w=1
76
+
77
+# STGP: store tag and pair
78
+STGP 01 101 0 001 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=1 w=1
79
+STGP 01 101 0 010 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=0
80
+STGP 01 101 0 011 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=1
81
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
55
index XXXXXXX..XXXXXXX 100644
82
index XXXXXXX..XXXXXXX 100644
56
--- a/include/hw/arm/npcm7xx.h
83
--- a/target/arm/tcg/translate-a64.c
57
+++ b/include/hw/arm/npcm7xx.h
84
+++ b/target/arm/tcg/translate-a64.c
58
@@ -XXX,XX +XXX,XX @@
85
@@ -XXX,XX +XXX,XX @@ static bool trans_LD_lit_v(DisasContext *s, arg_ldlit *a)
59
#include "hw/mem/npcm7xx_mc.h"
86
return true;
60
#include "hw/misc/npcm7xx_clk.h"
87
}
61
#include "hw/misc/npcm7xx_gcr.h"
88
62
+#include "hw/misc/npcm7xx_pwm.h"
89
-/*
63
#include "hw/misc/npcm7xx_rng.h"
90
- * LDNP (Load Pair - non-temporal hint)
64
#include "hw/nvram/npcm7xx_otp.h"
91
- * LDP (Load Pair - non vector)
65
#include "hw/timer/npcm7xx_timer.h"
92
- * LDPSW (Load Pair Signed Word - non vector)
66
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
93
- * STNP (Store Pair - non-temporal hint)
67
NPCM7xxCLKState clk;
94
- * STP (Store Pair - non vector)
68
NPCM7xxTimerCtrlState tim[3];
95
- * LDNP (Load Pair of SIMD&FP - non-temporal hint)
69
NPCM7xxADCState adc;
96
- * LDP (Load Pair of SIMD&FP)
70
+ NPCM7xxPWMState pwm[2];
97
- * STNP (Store Pair of SIMD&FP - non-temporal hint)
71
NPCM7xxOTPState key_storage;
98
- * STP (Store Pair of SIMD&FP)
72
NPCM7xxOTPState fuse_array;
99
- *
73
NPCM7xxMCState mc;
100
- * 31 30 29 27 26 25 24 23 22 21 15 14 10 9 5 4 0
74
diff --git a/include/hw/misc/npcm7xx_pwm.h b/include/hw/misc/npcm7xx_pwm.h
101
- * +-----+-------+---+---+-------+---+-----------------------------+
75
new file mode 100644
102
- * | opc | 1 0 1 | V | 0 | index | L | imm7 | Rt2 | Rn | Rt |
76
index XXXXXXX..XXXXXXX
103
- * +-----+-------+---+---+-------+---+-------+-------+------+------+
77
--- /dev/null
104
- *
78
+++ b/include/hw/misc/npcm7xx_pwm.h
105
- * opc: LDP/STP/LDNP/STNP 00 -> 32 bit, 10 -> 64 bit
79
@@ -XXX,XX +XXX,XX @@
106
- * LDPSW/STGP 01
80
+/*
107
- * LDP/STP/LDNP/STNP (SIMD) 00 -> 32 bit, 01 -> 64 bit, 10 -> 128 bit
81
+ * Nuvoton NPCM7xx PWM Module
108
- * V: 0 -> GPR, 1 -> Vector
82
+ *
109
- * idx: 00 -> signed offset with non-temporal hint, 01 -> post-index,
83
+ * Copyright 2020 Google LLC
110
- * 10 -> signed offset, 11 -> pre-index
84
+ *
111
- * L: 0 -> Store 1 -> Load
85
+ * This program is free software; you can redistribute it and/or modify it
112
- *
86
+ * under the terms of the GNU General Public License as published by the
113
- * Rt, Rt2 = GPR or SIMD registers to be stored
87
+ * Free Software Foundation; either version 2 of the License, or
114
- * Rn = general purpose register containing address
88
+ * (at your option) any later version.
115
- * imm7 = signed offset (multiple of 4 or 8 depending on size)
89
+ *
116
- */
90
+ * This program is distributed in the hope that it will be useful, but WITHOUT
117
-static void disas_ldst_pair(DisasContext *s, uint32_t insn)
91
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
118
+static void op_addr_ldstpair_pre(DisasContext *s, arg_ldstpair *a,
92
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
119
+ TCGv_i64 *clean_addr, TCGv_i64 *dirty_addr,
93
+ * for more details.
120
+ uint64_t offset, bool is_store, MemOp mop)
94
+ */
121
{
95
+#ifndef NPCM7XX_PWM_H
122
- int rt = extract32(insn, 0, 5);
96
+#define NPCM7XX_PWM_H
123
- int rn = extract32(insn, 5, 5);
97
+
124
- int rt2 = extract32(insn, 10, 5);
98
+#include "hw/clock.h"
125
- uint64_t offset = sextract64(insn, 15, 7);
99
+#include "hw/sysbus.h"
126
- int index = extract32(insn, 23, 2);
100
+#include "hw/irq.h"
127
- bool is_vector = extract32(insn, 26, 1);
101
+
128
- bool is_load = extract32(insn, 22, 1);
102
+/* Each PWM module holds 4 PWM channels. */
129
- int opc = extract32(insn, 30, 2);
103
+#define NPCM7XX_PWM_PER_MODULE 4
130
- bool is_signed = false;
104
+
131
- bool postindex = false;
105
+/*
132
- bool wback = false;
106
+ * Number of registers in one pwm module. Don't change this without increasing
133
- bool set_tag = false;
107
+ * the version_id in vmstate.
134
- TCGv_i64 clean_addr, dirty_addr;
108
+ */
135
- MemOp mop;
109
+#define NPCM7XX_PWM_NR_REGS (0x54 / sizeof(uint32_t))
136
- int size;
110
+
137
-
111
+/*
138
- if (opc == 3) {
112
+ * The maximum duty values. Each duty unit represents 1/NPCM7XX_PWM_MAX_DUTY
139
- unallocated_encoding(s);
113
+ * cycles. For example, if NPCM7XX_PWM_MAX_DUTY=1,000,000 and a PWM has a duty
140
- return;
114
+ * value of 100,000 the duty cycle for that PWM is 10%.
141
- }
115
+ */
142
-
116
+#define NPCM7XX_PWM_MAX_DUTY 1000000
143
- if (is_vector) {
117
+
144
- size = 2 + opc;
118
+typedef struct NPCM7xxPWMState NPCM7xxPWMState;
145
- } else if (opc == 1 && !is_load) {
119
+
146
- /* STGP */
120
+/**
147
- if (!dc_isar_feature(aa64_mte_insn_reg, s) || index == 0) {
121
+ * struct NPCM7xxPWM - The state of a single PWM channel.
148
- unallocated_encoding(s);
122
+ * @module: The PWM module that contains this channel.
149
- return;
123
+ * @irq: GIC interrupt line to fire on expiration if enabled.
150
- }
124
+ * @running: Whether this PWM channel is generating output.
151
- size = 3;
125
+ * @inverted: Whether this PWM channel is inverted.
152
- set_tag = true;
126
+ * @index: The index of this PWM channel.
153
- } else {
127
+ * @cnr: The counter register.
154
- size = 2 + extract32(opc, 1, 1);
128
+ * @cmr: The comparator register.
155
- is_signed = extract32(opc, 0, 1);
129
+ * @pdr: The data register.
156
- if (!is_load && is_signed) {
130
+ * @pwdr: The watchdog register.
157
- unallocated_encoding(s);
131
+ * @freq: The frequency of this PWM channel.
158
- return;
132
+ * @duty: The duty cycle of this PWM channel. One unit represents
159
- }
133
+ * 1/NPCM7XX_MAX_DUTY cycles.
160
- }
134
+ */
161
-
135
+typedef struct NPCM7xxPWM {
162
- switch (index) {
136
+ NPCM7xxPWMState *module;
163
- case 1: /* post-index */
137
+
164
- postindex = true;
138
+ qemu_irq irq;
165
- wback = true;
139
+
166
- break;
140
+ bool running;
167
- case 0:
141
+ bool inverted;
168
- /* signed offset with "non-temporal" hint. Since we don't emulate
142
+
169
- * caches we don't care about hints to the cache system about
143
+ uint8_t index;
170
- * data access patterns, and handle this identically to plain
144
+ uint32_t cnr;
171
- * signed offset.
145
+ uint32_t cmr;
172
- */
146
+ uint32_t pdr;
173
- if (is_signed) {
147
+ uint32_t pwdr;
174
- /* There is no non-temporal-hint version of LDPSW */
148
+
175
- unallocated_encoding(s);
149
+ uint32_t freq;
176
- return;
150
+ uint32_t duty;
177
- }
151
+} NPCM7xxPWM;
178
- postindex = false;
152
+
179
- break;
153
+/**
180
- case 2: /* signed offset, rn not updated */
154
+ * struct NPCM7xxPWMState - Pulse Width Modulation device state.
181
- postindex = false;
155
+ * @parent: System bus device.
182
- break;
156
+ * @iomem: Memory region through which registers are accessed.
183
- case 3: /* pre-index */
157
+ * @clock: The PWM clock.
184
- postindex = false;
158
+ * @pwm: The PWM channels owned by this module.
185
- wback = true;
159
+ * @ppr: The prescaler register.
186
- break;
160
+ * @csr: The clock selector register.
187
- }
161
+ * @pcr: The control register.
188
-
162
+ * @pier: The interrupt enable register.
189
- if (is_vector && !fp_access_check(s)) {
163
+ * @piir: The interrupt indication register.
190
- return;
164
+ */
191
- }
165
+struct NPCM7xxPWMState {
192
-
166
+ SysBusDevice parent;
193
- offset <<= (set_tag ? LOG2_TAG_GRANULE : size);
167
+
194
-
168
+ MemoryRegion iomem;
195
- if (rn == 31) {
169
+
196
+ if (a->rn == 31) {
170
+ Clock *clock;
197
gen_check_sp_alignment(s);
171
+ NPCM7xxPWM pwm[NPCM7XX_PWM_PER_MODULE];
172
+
173
+ uint32_t ppr;
174
+ uint32_t csr;
175
+ uint32_t pcr;
176
+ uint32_t pier;
177
+ uint32_t piir;
178
+};
179
+
180
+#define TYPE_NPCM7XX_PWM "npcm7xx-pwm"
181
+#define NPCM7XX_PWM(obj) \
182
+ OBJECT_CHECK(NPCM7xxPWMState, (obj), TYPE_NPCM7XX_PWM)
183
+
184
+#endif /* NPCM7XX_PWM_H */
185
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
186
index XXXXXXX..XXXXXXX 100644
187
--- a/hw/arm/npcm7xx.c
188
+++ b/hw/arm/npcm7xx.c
189
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxInterrupt {
190
NPCM7XX_WDG2_IRQ, /* Timer Module 2 Watchdog */
191
NPCM7XX_EHCI_IRQ = 61,
192
NPCM7XX_OHCI_IRQ = 62,
193
+ NPCM7XX_PWM0_IRQ = 93, /* PWM module 0 */
194
+ NPCM7XX_PWM1_IRQ, /* PWM module 1 */
195
NPCM7XX_GPIO0_IRQ = 116,
196
NPCM7XX_GPIO1_IRQ,
197
NPCM7XX_GPIO2_IRQ,
198
@@ -XXX,XX +XXX,XX @@ static const hwaddr npcm7xx_fiu3_flash_addr[] = {
199
0xb8000000, /* CS3 */
200
};
201
202
+/* Register base address for each PWM Module */
203
+static const hwaddr npcm7xx_pwm_addr[] = {
204
+ 0xf0103000,
205
+ 0xf0104000,
206
+};
207
+
208
static const struct {
209
hwaddr regs_addr;
210
uint32_t unconnected_pins;
211
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
212
object_initialize_child(obj, npcm7xx_fiu[i].name, &s->fiu[i],
213
TYPE_NPCM7XX_FIU);
214
}
198
}
215
+
199
216
+ for (i = 0; i < ARRAY_SIZE(s->pwm); i++) {
200
- dirty_addr = read_cpu_reg_sp(s, rn, 1);
217
+ object_initialize_child(obj, "pwm[*]", &s->pwm[i], TYPE_NPCM7XX_PWM);
201
- if (!postindex) {
218
+ }
202
+ *dirty_addr = read_cpu_reg_sp(s, a->rn, 1);
219
}
203
+ if (!a->p) {
220
204
+ tcg_gen_addi_i64(*dirty_addr, *dirty_addr, offset);
221
static void npcm7xx_realize(DeviceState *dev, Error **errp)
205
+ }
222
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
206
+
223
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ohci), 0,
207
+ *clean_addr = gen_mte_checkN(s, *dirty_addr, is_store,
224
npcm7xx_irq(s, NPCM7XX_OHCI_IRQ));
208
+ (a->w || a->rn != 31), 2 << a->sz, mop);
225
209
+}
226
+ /* PWM Modules. Cannot fail. */
210
+
227
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_pwm_addr) != ARRAY_SIZE(s->pwm));
211
+static void op_addr_ldstpair_post(DisasContext *s, arg_ldstpair *a,
228
+ for (i = 0; i < ARRAY_SIZE(s->pwm); i++) {
212
+ TCGv_i64 dirty_addr, uint64_t offset)
229
+ SysBusDevice *sbd = SYS_BUS_DEVICE(&s->pwm[i]);
230
+
231
+ qdev_connect_clock_in(DEVICE(&s->pwm[i]), "clock", qdev_get_clock_out(
232
+ DEVICE(&s->clk), "apb3-clock"));
233
+ sysbus_realize(sbd, &error_abort);
234
+ sysbus_mmio_map(sbd, 0, npcm7xx_pwm_addr[i]);
235
+ sysbus_connect_irq(sbd, i, npcm7xx_irq(s, NPCM7XX_PWM0_IRQ + i));
236
+ }
237
+
238
/*
239
* Flash Interface Unit (FIU). Can fail if incorrect number of chip selects
240
* specified, but this is a programming error.
241
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
242
create_unimplemented_device("npcm7xx.peci", 0xf0100000, 4 * KiB);
243
create_unimplemented_device("npcm7xx.siox[1]", 0xf0101000, 4 * KiB);
244
create_unimplemented_device("npcm7xx.siox[2]", 0xf0102000, 4 * KiB);
245
- create_unimplemented_device("npcm7xx.pwm[0]", 0xf0103000, 4 * KiB);
246
- create_unimplemented_device("npcm7xx.pwm[1]", 0xf0104000, 4 * KiB);
247
create_unimplemented_device("npcm7xx.mft[0]", 0xf0180000, 4 * KiB);
248
create_unimplemented_device("npcm7xx.mft[1]", 0xf0181000, 4 * KiB);
249
create_unimplemented_device("npcm7xx.mft[2]", 0xf0182000, 4 * KiB);
250
diff --git a/hw/misc/npcm7xx_pwm.c b/hw/misc/npcm7xx_pwm.c
251
new file mode 100644
252
index XXXXXXX..XXXXXXX
253
--- /dev/null
254
+++ b/hw/misc/npcm7xx_pwm.c
255
@@ -XXX,XX +XXX,XX @@
256
+/*
257
+ * Nuvoton NPCM7xx PWM Module
258
+ *
259
+ * Copyright 2020 Google LLC
260
+ *
261
+ * This program is free software; you can redistribute it and/or modify it
262
+ * under the terms of the GNU General Public License as published by the
263
+ * Free Software Foundation; either version 2 of the License, or
264
+ * (at your option) any later version.
265
+ *
266
+ * This program is distributed in the hope that it will be useful, but WITHOUT
267
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
268
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
269
+ * for more details.
270
+ */
271
+
272
+#include "qemu/osdep.h"
273
+#include "hw/irq.h"
274
+#include "hw/qdev-clock.h"
275
+#include "hw/qdev-properties.h"
276
+#include "hw/misc/npcm7xx_pwm.h"
277
+#include "hw/registerfields.h"
278
+#include "migration/vmstate.h"
279
+#include "qemu/bitops.h"
280
+#include "qemu/error-report.h"
281
+#include "qemu/log.h"
282
+#include "qemu/module.h"
283
+#include "qemu/units.h"
284
+#include "trace.h"
285
+
286
+REG32(NPCM7XX_PWM_PPR, 0x00);
287
+REG32(NPCM7XX_PWM_CSR, 0x04);
288
+REG32(NPCM7XX_PWM_PCR, 0x08);
289
+REG32(NPCM7XX_PWM_CNR0, 0x0c);
290
+REG32(NPCM7XX_PWM_CMR0, 0x10);
291
+REG32(NPCM7XX_PWM_PDR0, 0x14);
292
+REG32(NPCM7XX_PWM_CNR1, 0x18);
293
+REG32(NPCM7XX_PWM_CMR1, 0x1c);
294
+REG32(NPCM7XX_PWM_PDR1, 0x20);
295
+REG32(NPCM7XX_PWM_CNR2, 0x24);
296
+REG32(NPCM7XX_PWM_CMR2, 0x28);
297
+REG32(NPCM7XX_PWM_PDR2, 0x2c);
298
+REG32(NPCM7XX_PWM_CNR3, 0x30);
299
+REG32(NPCM7XX_PWM_CMR3, 0x34);
300
+REG32(NPCM7XX_PWM_PDR3, 0x38);
301
+REG32(NPCM7XX_PWM_PIER, 0x3c);
302
+REG32(NPCM7XX_PWM_PIIR, 0x40);
303
+REG32(NPCM7XX_PWM_PWDR0, 0x44);
304
+REG32(NPCM7XX_PWM_PWDR1, 0x48);
305
+REG32(NPCM7XX_PWM_PWDR2, 0x4c);
306
+REG32(NPCM7XX_PWM_PWDR3, 0x50);
307
+
308
+/* Register field definitions. */
309
+#define NPCM7XX_PPR(rv, index) extract32((rv), npcm7xx_ppr_base[index], 8)
310
+#define NPCM7XX_CSR(rv, index) extract32((rv), npcm7xx_csr_base[index], 3)
311
+#define NPCM7XX_CH(rv, index) extract32((rv), npcm7xx_ch_base[index], 4)
312
+#define NPCM7XX_CH_EN BIT(0)
313
+#define NPCM7XX_CH_INV BIT(2)
314
+#define NPCM7XX_CH_MOD BIT(3)
315
+
316
+/* Offset of each PWM channel's prescaler in the PPR register. */
317
+static const int npcm7xx_ppr_base[] = { 0, 0, 8, 8 };
318
+/* Offset of each PWM channel's clock selector in the CSR register. */
319
+static const int npcm7xx_csr_base[] = { 0, 4, 8, 12 };
320
+/* Offset of each PWM channel's control variable in the PCR register. */
321
+static const int npcm7xx_ch_base[] = { 0, 8, 12, 16 };
322
+
323
+static uint32_t npcm7xx_pwm_calculate_freq(NPCM7xxPWM *p)
324
+{
213
+{
325
+ uint32_t ppr;
214
+ if (a->w) {
326
+ uint32_t csr;
215
+ if (a->p) {
327
+ uint32_t freq;
216
+ tcg_gen_addi_i64(dirty_addr, dirty_addr, offset);
328
+
217
+ }
329
+ if (!p->running) {
218
+ tcg_gen_mov_i64(cpu_reg_sp(s, a->rn), dirty_addr);
330
+ return 0;
219
+ }
331
+ }
332
+
333
+ csr = NPCM7XX_CSR(p->module->csr, p->index);
334
+ ppr = NPCM7XX_PPR(p->module->ppr, p->index);
335
+ freq = clock_get_hz(p->module->clock);
336
+ freq /= ppr + 1;
337
+ /* csr can only be 0~4 */
338
+ if (csr > 4) {
339
+ qemu_log_mask(LOG_GUEST_ERROR,
340
+ "%s: invalid csr value %u\n",
341
+ __func__, csr);
342
+ csr = 4;
343
+ }
344
+ /* freq won't be changed if csr == 4. */
345
+ if (csr < 4) {
346
+ freq >>= csr + 1;
347
+ }
348
+
349
+ return freq / (p->cnr + 1);
350
+}
220
+}
351
+
221
+
352
+static uint32_t npcm7xx_pwm_calculate_duty(NPCM7xxPWM *p)
222
+static bool trans_STP(DisasContext *s, arg_ldstpair *a)
353
+{
223
+{
354
+ uint64_t duty;
224
+ uint64_t offset = a->imm << a->sz;
355
+
225
+ TCGv_i64 clean_addr, dirty_addr, tcg_rt, tcg_rt2;
356
+ if (p->running) {
226
+ MemOp mop = finalize_memop(s, a->sz);
357
+ if (p->cnr == 0) {
227
+
358
+ duty = 0;
228
+ op_addr_ldstpair_pre(s, a, &clean_addr, &dirty_addr, offset, true, mop);
359
+ } else if (p->cmr >= p->cnr) {
229
+ tcg_rt = cpu_reg(s, a->rt);
360
+ duty = NPCM7XX_PWM_MAX_DUTY;
230
+ tcg_rt2 = cpu_reg(s, a->rt2);
231
+ /*
232
+ * We built mop above for the single logical access -- rebuild it
233
+ * now for the paired operation.
234
+ *
235
+ * With LSE2, non-sign-extending pairs are treated atomically if
236
+ * aligned, and if unaligned one of the pair will be completely
237
+ * within a 16-byte block and that element will be atomic.
238
+ * Otherwise each element is separately atomic.
239
+ * In all cases, issue one operation with the correct atomicity.
240
+ */
241
+ mop = a->sz + 1;
242
+ if (s->align_mem) {
243
+ mop |= (a->sz == 2 ? MO_ALIGN_4 : MO_ALIGN_8);
244
+ }
245
+ mop = finalize_memop_pair(s, mop);
246
+ if (a->sz == 2) {
247
+ TCGv_i64 tmp = tcg_temp_new_i64();
248
+
249
+ if (s->be_data == MO_LE) {
250
+ tcg_gen_concat32_i64(tmp, tcg_rt, tcg_rt2);
361
+ } else {
251
+ } else {
362
+ duty = NPCM7XX_PWM_MAX_DUTY * (p->cmr + 1) / (p->cnr + 1);
252
+ tcg_gen_concat32_i64(tmp, tcg_rt2, tcg_rt);
253
+ }
254
+ tcg_gen_qemu_st_i64(tmp, clean_addr, get_mem_index(s), mop);
255
+ } else {
256
+ TCGv_i128 tmp = tcg_temp_new_i128();
257
+
258
+ if (s->be_data == MO_LE) {
259
+ tcg_gen_concat_i64_i128(tmp, tcg_rt, tcg_rt2);
260
+ } else {
261
+ tcg_gen_concat_i64_i128(tmp, tcg_rt2, tcg_rt);
262
+ }
263
+ tcg_gen_qemu_st_i128(tmp, clean_addr, get_mem_index(s), mop);
264
+ }
265
+ op_addr_ldstpair_post(s, a, dirty_addr, offset);
266
+ return true;
267
+}
268
+
269
+static bool trans_LDP(DisasContext *s, arg_ldstpair *a)
270
+{
271
+ uint64_t offset = a->imm << a->sz;
272
+ TCGv_i64 clean_addr, dirty_addr, tcg_rt, tcg_rt2;
273
+ MemOp mop = finalize_memop(s, a->sz);
274
+
275
+ op_addr_ldstpair_pre(s, a, &clean_addr, &dirty_addr, offset, false, mop);
276
+ tcg_rt = cpu_reg(s, a->rt);
277
+ tcg_rt2 = cpu_reg(s, a->rt2);
278
+
279
+ /*
280
+ * We built mop above for the single logical access -- rebuild it
281
+ * now for the paired operation.
282
+ *
283
+ * With LSE2, non-sign-extending pairs are treated atomically if
284
+ * aligned, and if unaligned one of the pair will be completely
285
+ * within a 16-byte block and that element will be atomic.
286
+ * Otherwise each element is separately atomic.
287
+ * In all cases, issue one operation with the correct atomicity.
288
+ *
289
+ * This treats sign-extending loads like zero-extending loads,
290
+ * since that reuses the most code below.
291
+ */
292
+ mop = a->sz + 1;
293
+ if (s->align_mem) {
294
+ mop |= (a->sz == 2 ? MO_ALIGN_4 : MO_ALIGN_8);
295
+ }
296
+ mop = finalize_memop_pair(s, mop);
297
+ if (a->sz == 2) {
298
+ int o2 = s->be_data == MO_LE ? 32 : 0;
299
+ int o1 = o2 ^ 32;
300
+
301
+ tcg_gen_qemu_ld_i64(tcg_rt, clean_addr, get_mem_index(s), mop);
302
+ if (a->sign) {
303
+ tcg_gen_sextract_i64(tcg_rt2, tcg_rt, o2, 32);
304
+ tcg_gen_sextract_i64(tcg_rt, tcg_rt, o1, 32);
305
+ } else {
306
+ tcg_gen_extract_i64(tcg_rt2, tcg_rt, o2, 32);
307
+ tcg_gen_extract_i64(tcg_rt, tcg_rt, o1, 32);
363
+ }
308
+ }
364
+ } else {
309
+ } else {
365
+ duty = 0;
310
+ TCGv_i128 tmp = tcg_temp_new_i128();
366
+ }
311
+
367
+
312
+ tcg_gen_qemu_ld_i128(tmp, clean_addr, get_mem_index(s), mop);
368
+ if (p->inverted) {
313
+ if (s->be_data == MO_LE) {
369
+ duty = NPCM7XX_PWM_MAX_DUTY - duty;
314
+ tcg_gen_extr_i128_i64(tcg_rt, tcg_rt2, tmp);
370
+ }
315
+ } else {
371
+
316
+ tcg_gen_extr_i128_i64(tcg_rt2, tcg_rt, tmp);
372
+ return duty;
317
+ }
318
+ }
319
+ op_addr_ldstpair_post(s, a, dirty_addr, offset);
320
+ return true;
373
+}
321
+}
374
+
322
+
375
+static void npcm7xx_pwm_update_freq(NPCM7xxPWM *p)
323
+static bool trans_STP_v(DisasContext *s, arg_ldstpair *a)
376
+{
324
+{
377
+ uint32_t freq = npcm7xx_pwm_calculate_freq(p);
325
+ uint64_t offset = a->imm << a->sz;
378
+
326
+ TCGv_i64 clean_addr, dirty_addr;
379
+ if (freq != p->freq) {
327
+ MemOp mop;
380
+ trace_npcm7xx_pwm_update_freq(DEVICE(p->module)->canonical_path,
328
+
381
+ p->index, p->freq, freq);
329
+ if (!fp_access_check(s)) {
382
+ p->freq = freq;
330
+ return true;
383
+ }
331
+ }
332
+
333
+ /* LSE2 does not merge FP pairs; leave these as separate operations. */
334
+ mop = finalize_memop_asimd(s, a->sz);
335
+ op_addr_ldstpair_pre(s, a, &clean_addr, &dirty_addr, offset, true, mop);
336
+ do_fp_st(s, a->rt, clean_addr, mop);
337
+ tcg_gen_addi_i64(clean_addr, clean_addr, 1 << a->sz);
338
+ do_fp_st(s, a->rt2, clean_addr, mop);
339
+ op_addr_ldstpair_post(s, a, dirty_addr, offset);
340
+ return true;
384
+}
341
+}
385
+
342
+
386
+static void npcm7xx_pwm_update_duty(NPCM7xxPWM *p)
343
+static bool trans_LDP_v(DisasContext *s, arg_ldstpair *a)
387
+{
344
+{
388
+ uint32_t duty = npcm7xx_pwm_calculate_duty(p);
345
+ uint64_t offset = a->imm << a->sz;
389
+
346
+ TCGv_i64 clean_addr, dirty_addr;
390
+ if (duty != p->duty) {
347
+ MemOp mop;
391
+ trace_npcm7xx_pwm_update_duty(DEVICE(p->module)->canonical_path,
348
+
392
+ p->index, p->duty, duty);
349
+ if (!fp_access_check(s)) {
393
+ p->duty = duty;
350
+ return true;
394
+ }
351
+ }
352
+
353
+ /* LSE2 does not merge FP pairs; leave these as separate operations. */
354
+ mop = finalize_memop_asimd(s, a->sz);
355
+ op_addr_ldstpair_pre(s, a, &clean_addr, &dirty_addr, offset, false, mop);
356
+ do_fp_ld(s, a->rt, clean_addr, mop);
357
+ tcg_gen_addi_i64(clean_addr, clean_addr, 1 << a->sz);
358
+ do_fp_ld(s, a->rt2, clean_addr, mop);
359
+ op_addr_ldstpair_post(s, a, dirty_addr, offset);
360
+ return true;
395
+}
361
+}
396
+
362
+
397
+static void npcm7xx_pwm_update_output(NPCM7xxPWM *p)
363
+static bool trans_STGP(DisasContext *s, arg_ldstpair *a)
398
+{
364
+{
399
+ npcm7xx_pwm_update_freq(p);
365
+ TCGv_i64 clean_addr, dirty_addr, tcg_rt, tcg_rt2;
400
+ npcm7xx_pwm_update_duty(p);
366
+ uint64_t offset = a->imm << LOG2_TAG_GRANULE;
401
+}
367
+ MemOp mop;
402
+
368
+ TCGv_i128 tmp;
403
+static void npcm7xx_pwm_write_ppr(NPCM7xxPWMState *s, uint32_t new_ppr)
369
+
404
+{
370
+ if (!dc_isar_feature(aa64_mte_insn_reg, s)) {
405
+ int i;
371
+ return false;
406
+ uint32_t old_ppr = s->ppr;
372
+ }
407
+
373
+
408
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_ppr_base) != NPCM7XX_PWM_PER_MODULE);
374
+ if (a->rn == 31) {
409
+ s->ppr = new_ppr;
375
+ gen_check_sp_alignment(s);
410
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) {
376
+ }
411
+ if (NPCM7XX_PPR(old_ppr, i) != NPCM7XX_PPR(new_ppr, i)) {
377
+
412
+ npcm7xx_pwm_update_freq(&s->pwm[i]);
378
+ dirty_addr = read_cpu_reg_sp(s, a->rn, 1);
413
+ }
379
+ if (!a->p) {
414
+ }
380
tcg_gen_addi_i64(dirty_addr, dirty_addr, offset);
415
+}
381
}
416
+
382
417
+static void npcm7xx_pwm_write_csr(NPCM7xxPWMState *s, uint32_t new_csr)
383
- if (set_tag) {
418
+{
384
- if (!s->ata) {
419
+ int i;
385
- /*
420
+ uint32_t old_csr = s->csr;
386
- * TODO: We could rely on the stores below, at least for
421
+
387
- * system mode, if we arrange to add MO_ALIGN_16.
422
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_csr_base) != NPCM7XX_PWM_PER_MODULE);
388
- */
423
+ s->csr = new_csr;
389
- gen_helper_stg_stub(cpu_env, dirty_addr);
424
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) {
390
- } else if (tb_cflags(s->base.tb) & CF_PARALLEL) {
425
+ if (NPCM7XX_CSR(old_csr, i) != NPCM7XX_CSR(new_csr, i)) {
391
- gen_helper_stg_parallel(cpu_env, dirty_addr, dirty_addr);
426
+ npcm7xx_pwm_update_freq(&s->pwm[i]);
392
- } else {
427
+ }
393
- gen_helper_stg(cpu_env, dirty_addr, dirty_addr);
428
+ }
394
- }
429
+}
395
- }
430
+
396
-
431
+static void npcm7xx_pwm_write_pcr(NPCM7xxPWMState *s, uint32_t new_pcr)
397
- if (is_vector) {
432
+{
398
- mop = finalize_memop_asimd(s, size);
433
+ int i;
399
- } else {
434
+ bool inverted;
400
- mop = finalize_memop(s, size);
435
+ uint32_t pcr;
401
- }
436
+ NPCM7xxPWM *p;
402
- clean_addr = gen_mte_checkN(s, dirty_addr, !is_load,
437
+
403
- (wback || rn != 31) && !set_tag,
438
+ s->pcr = new_pcr;
404
- 2 << size, mop);
439
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_ch_base) != NPCM7XX_PWM_PER_MODULE);
405
-
440
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) {
406
- if (is_vector) {
441
+ p = &s->pwm[i];
407
- /* LSE2 does not merge FP pairs; leave these as separate operations. */
442
+ pcr = NPCM7XX_CH(new_pcr, i);
408
- if (is_load) {
443
+ inverted = pcr & NPCM7XX_CH_INV;
409
- do_fp_ld(s, rt, clean_addr, mop);
444
+
410
- } else {
445
+ /*
411
- do_fp_st(s, rt, clean_addr, mop);
446
+ * We only run a PWM channel with toggle mode. Single-shot mode does not
412
- }
447
+ * generate frequency and duty-cycle values.
413
- tcg_gen_addi_i64(clean_addr, clean_addr, 1 << size);
448
+ */
414
- if (is_load) {
449
+ if ((pcr & NPCM7XX_CH_EN) && (pcr & NPCM7XX_CH_MOD)) {
415
- do_fp_ld(s, rt2, clean_addr, mop);
450
+ if (p->running) {
416
- } else {
451
+ /* Re-run this PWM channel if inverted changed. */
417
- do_fp_st(s, rt2, clean_addr, mop);
452
+ if (p->inverted ^ inverted) {
418
- }
453
+ p->inverted = inverted;
419
- } else {
454
+ npcm7xx_pwm_update_duty(p);
420
- TCGv_i64 tcg_rt = cpu_reg(s, rt);
455
+ }
421
- TCGv_i64 tcg_rt2 = cpu_reg(s, rt2);
456
+ } else {
422
-
457
+ /* Run this PWM channel. */
423
+ if (!s->ata) {
458
+ p->running = true;
424
/*
459
+ p->inverted = inverted;
425
- * We built mop above for the single logical access -- rebuild it
460
+ npcm7xx_pwm_update_output(p);
426
- * now for the paired operation.
461
+ }
427
- *
462
+ } else {
428
- * With LSE2, non-sign-extending pairs are treated atomically if
463
+ /* Clear this PWM channel. */
429
- * aligned, and if unaligned one of the pair will be completely
464
+ p->running = false;
430
- * within a 16-byte block and that element will be atomic.
465
+ p->inverted = inverted;
431
- * Otherwise each element is separately atomic.
466
+ npcm7xx_pwm_update_output(p);
432
- * In all cases, issue one operation with the correct atomicity.
467
+ }
433
- *
468
+ }
434
- * This treats sign-extending loads like zero-extending loads,
469
+
435
- * since that reuses the most code below.
470
+}
436
+ * TODO: We could rely on the stores below, at least for
471
+
437
+ * system mode, if we arrange to add MO_ALIGN_16.
472
+static hwaddr npcm7xx_cnr_index(hwaddr offset)
438
*/
473
+{
439
- mop = size + 1;
474
+ switch (offset) {
440
- if (s->align_mem) {
475
+ case A_NPCM7XX_PWM_CNR0:
441
- mop |= (size == 2 ? MO_ALIGN_4 : MO_ALIGN_8);
476
+ return 0;
442
- }
477
+ case A_NPCM7XX_PWM_CNR1:
443
- mop = finalize_memop_pair(s, mop);
478
+ return 1;
444
-
479
+ case A_NPCM7XX_PWM_CNR2:
445
- if (is_load) {
480
+ return 2;
446
- if (size == 2) {
481
+ case A_NPCM7XX_PWM_CNR3:
447
- int o2 = s->be_data == MO_LE ? 32 : 0;
482
+ return 3;
448
- int o1 = o2 ^ 32;
483
+ default:
449
-
484
+ g_assert_not_reached();
450
- tcg_gen_qemu_ld_i64(tcg_rt, clean_addr, get_mem_index(s), mop);
485
+ }
451
- if (is_signed) {
486
+}
452
- tcg_gen_sextract_i64(tcg_rt2, tcg_rt, o2, 32);
487
+
453
- tcg_gen_sextract_i64(tcg_rt, tcg_rt, o1, 32);
488
+static hwaddr npcm7xx_cmr_index(hwaddr offset)
454
- } else {
489
+{
455
- tcg_gen_extract_i64(tcg_rt2, tcg_rt, o2, 32);
490
+ switch (offset) {
456
- tcg_gen_extract_i64(tcg_rt, tcg_rt, o1, 32);
491
+ case A_NPCM7XX_PWM_CMR0:
457
- }
492
+ return 0;
458
- } else {
493
+ case A_NPCM7XX_PWM_CMR1:
459
- TCGv_i128 tmp = tcg_temp_new_i128();
494
+ return 1;
460
-
495
+ case A_NPCM7XX_PWM_CMR2:
461
- tcg_gen_qemu_ld_i128(tmp, clean_addr, get_mem_index(s), mop);
496
+ return 2;
462
- if (s->be_data == MO_LE) {
497
+ case A_NPCM7XX_PWM_CMR3:
463
- tcg_gen_extr_i128_i64(tcg_rt, tcg_rt2, tmp);
498
+ return 3;
464
- } else {
499
+ default:
465
- tcg_gen_extr_i128_i64(tcg_rt2, tcg_rt, tmp);
500
+ g_assert_not_reached();
466
- }
501
+ }
467
- }
502
+}
468
- } else {
503
+
469
- if (size == 2) {
504
+static hwaddr npcm7xx_pdr_index(hwaddr offset)
470
- TCGv_i64 tmp = tcg_temp_new_i64();
505
+{
471
-
506
+ switch (offset) {
472
- if (s->be_data == MO_LE) {
507
+ case A_NPCM7XX_PWM_PDR0:
473
- tcg_gen_concat32_i64(tmp, tcg_rt, tcg_rt2);
508
+ return 0;
474
- } else {
509
+ case A_NPCM7XX_PWM_PDR1:
475
- tcg_gen_concat32_i64(tmp, tcg_rt2, tcg_rt);
510
+ return 1;
476
- }
511
+ case A_NPCM7XX_PWM_PDR2:
477
- tcg_gen_qemu_st_i64(tmp, clean_addr, get_mem_index(s), mop);
512
+ return 2;
478
- } else {
513
+ case A_NPCM7XX_PWM_PDR3:
479
- TCGv_i128 tmp = tcg_temp_new_i128();
514
+ return 3;
480
-
515
+ default:
481
- if (s->be_data == MO_LE) {
516
+ g_assert_not_reached();
482
- tcg_gen_concat_i64_i128(tmp, tcg_rt, tcg_rt2);
517
+ }
483
- } else {
518
+}
484
- tcg_gen_concat_i64_i128(tmp, tcg_rt2, tcg_rt);
519
+
485
- }
520
+static hwaddr npcm7xx_pwdr_index(hwaddr offset)
486
- tcg_gen_qemu_st_i128(tmp, clean_addr, get_mem_index(s), mop);
521
+{
487
- }
522
+ switch (offset) {
488
- }
523
+ case A_NPCM7XX_PWM_PWDR0:
489
+ gen_helper_stg_stub(cpu_env, dirty_addr);
524
+ return 0;
490
+ } else if (tb_cflags(s->base.tb) & CF_PARALLEL) {
525
+ case A_NPCM7XX_PWM_PWDR1:
491
+ gen_helper_stg_parallel(cpu_env, dirty_addr, dirty_addr);
526
+ return 1;
492
+ } else {
527
+ case A_NPCM7XX_PWM_PWDR2:
493
+ gen_helper_stg(cpu_env, dirty_addr, dirty_addr);
528
+ return 2;
494
}
529
+ case A_NPCM7XX_PWM_PWDR3:
495
530
+ return 3;
496
- if (wback) {
531
+ default:
497
- if (postindex) {
532
+ g_assert_not_reached();
498
- tcg_gen_addi_i64(dirty_addr, dirty_addr, offset);
533
+ }
499
- }
534
+}
500
- tcg_gen_mov_i64(cpu_reg_sp(s, rn), dirty_addr);
535
+
501
+ mop = finalize_memop(s, a->sz);
536
+static uint64_t npcm7xx_pwm_read(void *opaque, hwaddr offset, unsigned size)
502
+ clean_addr = gen_mte_checkN(s, dirty_addr, true, false, 2 << a->sz, mop);
537
+{
503
+
538
+ NPCM7xxPWMState *s = opaque;
504
+ tcg_rt = cpu_reg(s, a->rt);
539
+ uint64_t value = 0;
505
+ tcg_rt2 = cpu_reg(s, a->rt2);
540
+
506
+
541
+ switch (offset) {
507
+ assert(a->sz == 3);
542
+ case A_NPCM7XX_PWM_CNR0:
508
+
543
+ case A_NPCM7XX_PWM_CNR1:
509
+ tmp = tcg_temp_new_i128();
544
+ case A_NPCM7XX_PWM_CNR2:
510
+ if (s->be_data == MO_LE) {
545
+ case A_NPCM7XX_PWM_CNR3:
511
+ tcg_gen_concat_i64_i128(tmp, tcg_rt, tcg_rt2);
546
+ value = s->pwm[npcm7xx_cnr_index(offset)].cnr;
512
+ } else {
547
+ break;
513
+ tcg_gen_concat_i64_i128(tmp, tcg_rt2, tcg_rt);
548
+
514
}
549
+ case A_NPCM7XX_PWM_CMR0:
515
+ tcg_gen_qemu_st_i128(tmp, clean_addr, get_mem_index(s), mop);
550
+ case A_NPCM7XX_PWM_CMR1:
516
+
551
+ case A_NPCM7XX_PWM_CMR2:
517
+ op_addr_ldstpair_post(s, a, dirty_addr, offset);
552
+ case A_NPCM7XX_PWM_CMR3:
518
+ return true;
553
+ value = s->pwm[npcm7xx_cmr_index(offset)].cmr;
519
}
554
+ break;
520
555
+
521
/*
556
+ case A_NPCM7XX_PWM_PDR0:
522
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_tag(DisasContext *s, uint32_t insn)
557
+ case A_NPCM7XX_PWM_PDR1:
523
static void disas_ldst(DisasContext *s, uint32_t insn)
558
+ case A_NPCM7XX_PWM_PDR2:
524
{
559
+ case A_NPCM7XX_PWM_PDR3:
525
switch (extract32(insn, 24, 6)) {
560
+ value = s->pwm[npcm7xx_pdr_index(offset)].pdr;
526
- case 0x28: case 0x29:
561
+ break;
527
- case 0x2c: case 0x2d: /* Load/store pair (all forms) */
562
+
528
- disas_ldst_pair(s, insn);
563
+ case A_NPCM7XX_PWM_PWDR0:
529
- break;
564
+ case A_NPCM7XX_PWM_PWDR1:
530
case 0x38: case 0x39:
565
+ case A_NPCM7XX_PWM_PWDR2:
531
case 0x3c: case 0x3d: /* Load/store register (all forms) */
566
+ case A_NPCM7XX_PWM_PWDR3:
532
disas_ldst_reg(s, insn);
567
+ value = s->pwm[npcm7xx_pwdr_index(offset)].pwdr;
568
+ break;
569
+
570
+ case A_NPCM7XX_PWM_PPR:
571
+ value = s->ppr;
572
+ break;
573
+
574
+ case A_NPCM7XX_PWM_CSR:
575
+ value = s->csr;
576
+ break;
577
+
578
+ case A_NPCM7XX_PWM_PCR:
579
+ value = s->pcr;
580
+ break;
581
+
582
+ case A_NPCM7XX_PWM_PIER:
583
+ value = s->pier;
584
+ break;
585
+
586
+ case A_NPCM7XX_PWM_PIIR:
587
+ value = s->piir;
588
+ break;
589
+
590
+ default:
591
+ qemu_log_mask(LOG_GUEST_ERROR,
592
+ "%s: invalid offset 0x%04" HWADDR_PRIx "\n",
593
+ __func__, offset);
594
+ break;
595
+ }
596
+
597
+ trace_npcm7xx_pwm_read(DEVICE(s)->canonical_path, offset, value);
598
+ return value;
599
+}
600
+
601
+static void npcm7xx_pwm_write(void *opaque, hwaddr offset,
602
+ uint64_t v, unsigned size)
603
+{
604
+ NPCM7xxPWMState *s = opaque;
605
+ NPCM7xxPWM *p;
606
+ uint32_t value = v;
607
+
608
+ trace_npcm7xx_pwm_write(DEVICE(s)->canonical_path, offset, value);
609
+ switch (offset) {
610
+ case A_NPCM7XX_PWM_CNR0:
611
+ case A_NPCM7XX_PWM_CNR1:
612
+ case A_NPCM7XX_PWM_CNR2:
613
+ case A_NPCM7XX_PWM_CNR3:
614
+ p = &s->pwm[npcm7xx_cnr_index(offset)];
615
+ p->cnr = value;
616
+ npcm7xx_pwm_update_output(p);
617
+ break;
618
+
619
+ case A_NPCM7XX_PWM_CMR0:
620
+ case A_NPCM7XX_PWM_CMR1:
621
+ case A_NPCM7XX_PWM_CMR2:
622
+ case A_NPCM7XX_PWM_CMR3:
623
+ p = &s->pwm[npcm7xx_cmr_index(offset)];
624
+ p->cmr = value;
625
+ npcm7xx_pwm_update_output(p);
626
+ break;
627
+
628
+ case A_NPCM7XX_PWM_PDR0:
629
+ case A_NPCM7XX_PWM_PDR1:
630
+ case A_NPCM7XX_PWM_PDR2:
631
+ case A_NPCM7XX_PWM_PDR3:
632
+ qemu_log_mask(LOG_GUEST_ERROR,
633
+ "%s: register @ 0x%04" HWADDR_PRIx " is read-only\n",
634
+ __func__, offset);
635
+ break;
636
+
637
+ case A_NPCM7XX_PWM_PWDR0:
638
+ case A_NPCM7XX_PWM_PWDR1:
639
+ case A_NPCM7XX_PWM_PWDR2:
640
+ case A_NPCM7XX_PWM_PWDR3:
641
+ qemu_log_mask(LOG_UNIMP,
642
+ "%s: register @ 0x%04" HWADDR_PRIx " is not implemented\n",
643
+ __func__, offset);
644
+ break;
645
+
646
+ case A_NPCM7XX_PWM_PPR:
647
+ npcm7xx_pwm_write_ppr(s, value);
648
+ break;
649
+
650
+ case A_NPCM7XX_PWM_CSR:
651
+ npcm7xx_pwm_write_csr(s, value);
652
+ break;
653
+
654
+ case A_NPCM7XX_PWM_PCR:
655
+ npcm7xx_pwm_write_pcr(s, value);
656
+ break;
657
+
658
+ case A_NPCM7XX_PWM_PIER:
659
+ qemu_log_mask(LOG_UNIMP,
660
+ "%s: register @ 0x%04" HWADDR_PRIx " is not implemented\n",
661
+ __func__, offset);
662
+ break;
663
+
664
+ case A_NPCM7XX_PWM_PIIR:
665
+ qemu_log_mask(LOG_UNIMP,
666
+ "%s: register @ 0x%04" HWADDR_PRIx " is not implemented\n",
667
+ __func__, offset);
668
+ break;
669
+
670
+ default:
671
+ qemu_log_mask(LOG_GUEST_ERROR,
672
+ "%s: invalid offset 0x%04" HWADDR_PRIx "\n",
673
+ __func__, offset);
674
+ break;
675
+ }
676
+}
677
+
678
+static const struct MemoryRegionOps npcm7xx_pwm_ops = {
679
+ .read = npcm7xx_pwm_read,
680
+ .write = npcm7xx_pwm_write,
681
+ .endianness = DEVICE_LITTLE_ENDIAN,
682
+ .valid = {
683
+ .min_access_size = 4,
684
+ .max_access_size = 4,
685
+ .unaligned = false,
686
+ },
687
+};
688
+
689
+static void npcm7xx_pwm_enter_reset(Object *obj, ResetType type)
690
+{
691
+ NPCM7xxPWMState *s = NPCM7XX_PWM(obj);
692
+ int i;
693
+
694
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; i++) {
695
+ NPCM7xxPWM *p = &s->pwm[i];
696
+
697
+ p->cnr = 0x00000000;
698
+ p->cmr = 0x00000000;
699
+ p->pdr = 0x00000000;
700
+ p->pwdr = 0x00000000;
701
+ }
702
+
703
+ s->ppr = 0x00000000;
704
+ s->csr = 0x00000000;
705
+ s->pcr = 0x00000000;
706
+ s->pier = 0x00000000;
707
+ s->piir = 0x00000000;
708
+}
709
+
710
+static void npcm7xx_pwm_hold_reset(Object *obj)
711
+{
712
+ NPCM7xxPWMState *s = NPCM7XX_PWM(obj);
713
+ int i;
714
+
715
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; i++) {
716
+ qemu_irq_lower(s->pwm[i].irq);
717
+ }
718
+}
719
+
720
+static void npcm7xx_pwm_init(Object *obj)
721
+{
722
+ NPCM7xxPWMState *s = NPCM7XX_PWM(obj);
723
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
724
+ int i;
725
+
726
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; i++) {
727
+ NPCM7xxPWM *p = &s->pwm[i];
728
+ p->module = s;
729
+ p->index = i;
730
+ sysbus_init_irq(sbd, &p->irq);
731
+ }
732
+
733
+ memory_region_init_io(&s->iomem, obj, &npcm7xx_pwm_ops, s,
734
+ TYPE_NPCM7XX_PWM, 4 * KiB);
735
+ sysbus_init_mmio(sbd, &s->iomem);
736
+ s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL);
737
+
738
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) {
739
+ object_property_add_uint32_ptr(obj, "freq[*]",
740
+ &s->pwm[i].freq, OBJ_PROP_FLAG_READ);
741
+ object_property_add_uint32_ptr(obj, "duty[*]",
742
+ &s->pwm[i].duty, OBJ_PROP_FLAG_READ);
743
+ }
744
+}
745
+
746
+static const VMStateDescription vmstate_npcm7xx_pwm = {
747
+ .name = "npcm7xx-pwm",
748
+ .version_id = 0,
749
+ .minimum_version_id = 0,
750
+ .fields = (VMStateField[]) {
751
+ VMSTATE_BOOL(running, NPCM7xxPWM),
752
+ VMSTATE_BOOL(inverted, NPCM7xxPWM),
753
+ VMSTATE_UINT8(index, NPCM7xxPWM),
754
+ VMSTATE_UINT32(cnr, NPCM7xxPWM),
755
+ VMSTATE_UINT32(cmr, NPCM7xxPWM),
756
+ VMSTATE_UINT32(pdr, NPCM7xxPWM),
757
+ VMSTATE_UINT32(pwdr, NPCM7xxPWM),
758
+ VMSTATE_UINT32(freq, NPCM7xxPWM),
759
+ VMSTATE_UINT32(duty, NPCM7xxPWM),
760
+ VMSTATE_END_OF_LIST(),
761
+ },
762
+};
763
+
764
+static const VMStateDescription vmstate_npcm7xx_pwm_module = {
765
+ .name = "npcm7xx-pwm-module",
766
+ .version_id = 0,
767
+ .minimum_version_id = 0,
768
+ .fields = (VMStateField[]) {
769
+ VMSTATE_CLOCK(clock, NPCM7xxPWMState),
770
+ VMSTATE_STRUCT_ARRAY(pwm, NPCM7xxPWMState,
771
+ NPCM7XX_PWM_PER_MODULE, 0, vmstate_npcm7xx_pwm,
772
+ NPCM7xxPWM),
773
+ VMSTATE_UINT32(ppr, NPCM7xxPWMState),
774
+ VMSTATE_UINT32(csr, NPCM7xxPWMState),
775
+ VMSTATE_UINT32(pcr, NPCM7xxPWMState),
776
+ VMSTATE_UINT32(pier, NPCM7xxPWMState),
777
+ VMSTATE_UINT32(piir, NPCM7xxPWMState),
778
+ VMSTATE_END_OF_LIST(),
779
+ },
780
+};
781
+
782
+static void npcm7xx_pwm_class_init(ObjectClass *klass, void *data)
783
+{
784
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
785
+ DeviceClass *dc = DEVICE_CLASS(klass);
786
+
787
+ dc->desc = "NPCM7xx PWM Controller";
788
+ dc->vmsd = &vmstate_npcm7xx_pwm_module;
789
+ rc->phases.enter = npcm7xx_pwm_enter_reset;
790
+ rc->phases.hold = npcm7xx_pwm_hold_reset;
791
+}
792
+
793
+static const TypeInfo npcm7xx_pwm_info = {
794
+ .name = TYPE_NPCM7XX_PWM,
795
+ .parent = TYPE_SYS_BUS_DEVICE,
796
+ .instance_size = sizeof(NPCM7xxPWMState),
797
+ .class_init = npcm7xx_pwm_class_init,
798
+ .instance_init = npcm7xx_pwm_init,
799
+};
800
+
801
+static void npcm7xx_pwm_register_type(void)
802
+{
803
+ type_register_static(&npcm7xx_pwm_info);
804
+}
805
+type_init(npcm7xx_pwm_register_type);
806
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
807
index XXXXXXX..XXXXXXX 100644
808
--- a/hw/misc/meson.build
809
+++ b/hw/misc/meson.build
810
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_MAINSTONE', if_true: files('mst_fpga.c'))
811
softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files(
812
'npcm7xx_clk.c',
813
'npcm7xx_gcr.c',
814
+ 'npcm7xx_pwm.c',
815
'npcm7xx_rng.c',
816
))
817
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files(
818
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
819
index XXXXXXX..XXXXXXX 100644
820
--- a/hw/misc/trace-events
821
+++ b/hw/misc/trace-events
822
@@ -XXX,XX +XXX,XX @@ npcm7xx_gcr_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " valu
823
npcm7xx_rng_read(uint64_t offset, uint64_t value, unsigned size) "offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
824
npcm7xx_rng_write(uint64_t offset, uint64_t value, unsigned size) "offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
825
826
+# npcm7xx_pwm.c
827
+npcm7xx_pwm_read(const char *id, uint64_t offset, uint32_t value) "%s offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
828
+npcm7xx_pwm_write(const char *id, uint64_t offset, uint32_t value) "%s offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
829
+npcm7xx_pwm_update_freq(const char *id, uint8_t index, uint32_t old_value, uint32_t new_value) "%s pwm[%u] Update Freq: old_freq: %u, new_freq: %u"
830
+npcm7xx_pwm_update_duty(const char *id, uint8_t index, uint32_t old_value, uint32_t new_value) "%s pwm[%u] Update Duty: old_duty: %u, new_duty: %u"
831
+
832
# stm32f4xx_syscfg.c
833
stm32f4xx_syscfg_set_irq(int gpio, int line, int level) "Interupt: GPIO: %d, Line: %d; Level: %d"
834
stm32f4xx_pulse_exti(int irq) "Pulse EXTI: %d"
835
--
533
--
836
2.20.1
534
2.34.1
837
838
diff view generated by jsdifflib
New patch
1
Convert the load and store instructions which use a 9-bit
2
immediate offset to decodetree.
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20230602155223.2040685-13-peter.maydell@linaro.org
7
---
8
target/arm/tcg/a64.decode | 69 +++++++++++
9
target/arm/tcg/translate-a64.c | 206 ++++++++++++++-------------------
10
2 files changed, 153 insertions(+), 122 deletions(-)
11
12
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/arm/tcg/a64.decode
15
+++ b/target/arm/tcg/a64.decode
16
@@ -XXX,XX +XXX,XX @@ LDP_v 10 101 1 011 1 ....... ..... ..... ..... @ldstpair sz=4 sign=0 p
17
STGP 01 101 0 001 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=1 w=1
18
STGP 01 101 0 010 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=0
19
STGP 01 101 0 011 0 ....... ..... ..... ..... @ldstpair sz=3 sign=0 p=0 w=1
20
+
21
+# Load/store register (unscaled immediate)
22
+&ldst_imm rt rn imm sz sign w p unpriv ext
23
+@ldst_imm .. ... . .. .. . imm:s9 .. rn:5 rt:5 &ldst_imm unpriv=0 p=0 w=0
24
+@ldst_imm_pre .. ... . .. .. . imm:s9 .. rn:5 rt:5 &ldst_imm unpriv=0 p=0 w=1
25
+@ldst_imm_post .. ... . .. .. . imm:s9 .. rn:5 rt:5 &ldst_imm unpriv=0 p=1 w=1
26
+@ldst_imm_user .. ... . .. .. . imm:s9 .. rn:5 rt:5 &ldst_imm unpriv=1 p=0 w=0
27
+
28
+STR_i sz:2 111 0 00 00 0 ......... 00 ..... ..... @ldst_imm sign=0 ext=0
29
+LDR_i 00 111 0 00 01 0 ......... 00 ..... ..... @ldst_imm sign=0 ext=1 sz=0
30
+LDR_i 01 111 0 00 01 0 ......... 00 ..... ..... @ldst_imm sign=0 ext=1 sz=1
31
+LDR_i 10 111 0 00 01 0 ......... 00 ..... ..... @ldst_imm sign=0 ext=1 sz=2
32
+LDR_i 11 111 0 00 01 0 ......... 00 ..... ..... @ldst_imm sign=0 ext=0 sz=3
33
+LDR_i 00 111 0 00 10 0 ......... 00 ..... ..... @ldst_imm sign=1 ext=0 sz=0
34
+LDR_i 01 111 0 00 10 0 ......... 00 ..... ..... @ldst_imm sign=1 ext=0 sz=1
35
+LDR_i 10 111 0 00 10 0 ......... 00 ..... ..... @ldst_imm sign=1 ext=0 sz=2
36
+LDR_i 00 111 0 00 11 0 ......... 00 ..... ..... @ldst_imm sign=1 ext=1 sz=0
37
+LDR_i 01 111 0 00 11 0 ......... 00 ..... ..... @ldst_imm sign=1 ext=1 sz=1
38
+
39
+STR_i sz:2 111 0 00 00 0 ......... 01 ..... ..... @ldst_imm_post sign=0 ext=0
40
+LDR_i 00 111 0 00 01 0 ......... 01 ..... ..... @ldst_imm_post sign=0 ext=1 sz=0
41
+LDR_i 01 111 0 00 01 0 ......... 01 ..... ..... @ldst_imm_post sign=0 ext=1 sz=1
42
+LDR_i 10 111 0 00 01 0 ......... 01 ..... ..... @ldst_imm_post sign=0 ext=1 sz=2
43
+LDR_i 11 111 0 00 01 0 ......... 01 ..... ..... @ldst_imm_post sign=0 ext=0 sz=3
44
+LDR_i 00 111 0 00 10 0 ......... 01 ..... ..... @ldst_imm_post sign=1 ext=0 sz=0
45
+LDR_i 01 111 0 00 10 0 ......... 01 ..... ..... @ldst_imm_post sign=1 ext=0 sz=1
46
+LDR_i 10 111 0 00 10 0 ......... 01 ..... ..... @ldst_imm_post sign=1 ext=0 sz=2
47
+LDR_i 00 111 0 00 11 0 ......... 01 ..... ..... @ldst_imm_post sign=1 ext=1 sz=0
48
+LDR_i 01 111 0 00 11 0 ......... 01 ..... ..... @ldst_imm_post sign=1 ext=1 sz=1
49
+
50
+STR_i sz:2 111 0 00 00 0 ......... 10 ..... ..... @ldst_imm_user sign=0 ext=0
51
+LDR_i 00 111 0 00 01 0 ......... 10 ..... ..... @ldst_imm_user sign=0 ext=1 sz=0
52
+LDR_i 01 111 0 00 01 0 ......... 10 ..... ..... @ldst_imm_user sign=0 ext=1 sz=1
53
+LDR_i 10 111 0 00 01 0 ......... 10 ..... ..... @ldst_imm_user sign=0 ext=1 sz=2
54
+LDR_i 11 111 0 00 01 0 ......... 10 ..... ..... @ldst_imm_user sign=0 ext=0 sz=3
55
+LDR_i 00 111 0 00 10 0 ......... 10 ..... ..... @ldst_imm_user sign=1 ext=0 sz=0
56
+LDR_i 01 111 0 00 10 0 ......... 10 ..... ..... @ldst_imm_user sign=1 ext=0 sz=1
57
+LDR_i 10 111 0 00 10 0 ......... 10 ..... ..... @ldst_imm_user sign=1 ext=0 sz=2
58
+LDR_i 00 111 0 00 11 0 ......... 10 ..... ..... @ldst_imm_user sign=1 ext=1 sz=0
59
+LDR_i 01 111 0 00 11 0 ......... 10 ..... ..... @ldst_imm_user sign=1 ext=1 sz=1
60
+
61
+STR_i sz:2 111 0 00 00 0 ......... 11 ..... ..... @ldst_imm_pre sign=0 ext=0
62
+LDR_i 00 111 0 00 01 0 ......... 11 ..... ..... @ldst_imm_pre sign=0 ext=1 sz=0
63
+LDR_i 01 111 0 00 01 0 ......... 11 ..... ..... @ldst_imm_pre sign=0 ext=1 sz=1
64
+LDR_i 10 111 0 00 01 0 ......... 11 ..... ..... @ldst_imm_pre sign=0 ext=1 sz=2
65
+LDR_i 11 111 0 00 01 0 ......... 11 ..... ..... @ldst_imm_pre sign=0 ext=0 sz=3
66
+LDR_i 00 111 0 00 10 0 ......... 11 ..... ..... @ldst_imm_pre sign=1 ext=0 sz=0
67
+LDR_i 01 111 0 00 10 0 ......... 11 ..... ..... @ldst_imm_pre sign=1 ext=0 sz=1
68
+LDR_i 10 111 0 00 10 0 ......... 11 ..... ..... @ldst_imm_pre sign=1 ext=0 sz=2
69
+LDR_i 00 111 0 00 11 0 ......... 11 ..... ..... @ldst_imm_pre sign=1 ext=1 sz=0
70
+LDR_i 01 111 0 00 11 0 ......... 11 ..... ..... @ldst_imm_pre sign=1 ext=1 sz=1
71
+
72
+# PRFM : prefetch memory: a no-op for QEMU
73
+NOP 11 111 0 00 10 0 --------- 00 ----- -----
74
+
75
+STR_v_i sz:2 111 1 00 00 0 ......... 00 ..... ..... @ldst_imm sign=0 ext=0
76
+STR_v_i 00 111 1 00 10 0 ......... 00 ..... ..... @ldst_imm sign=0 ext=0 sz=4
77
+LDR_v_i sz:2 111 1 00 01 0 ......... 00 ..... ..... @ldst_imm sign=0 ext=0
78
+LDR_v_i 00 111 1 00 11 0 ......... 00 ..... ..... @ldst_imm sign=0 ext=0 sz=4
79
+
80
+STR_v_i sz:2 111 1 00 00 0 ......... 01 ..... ..... @ldst_imm_post sign=0 ext=0
81
+STR_v_i 00 111 1 00 10 0 ......... 01 ..... ..... @ldst_imm_post sign=0 ext=0 sz=4
82
+LDR_v_i sz:2 111 1 00 01 0 ......... 01 ..... ..... @ldst_imm_post sign=0 ext=0
83
+LDR_v_i 00 111 1 00 11 0 ......... 01 ..... ..... @ldst_imm_post sign=0 ext=0 sz=4
84
+
85
+STR_v_i sz:2 111 1 00 00 0 ......... 11 ..... ..... @ldst_imm_pre sign=0 ext=0
86
+STR_v_i 00 111 1 00 10 0 ......... 11 ..... ..... @ldst_imm_pre sign=0 ext=0 sz=4
87
+LDR_v_i sz:2 111 1 00 01 0 ......... 11 ..... ..... @ldst_imm_pre sign=0 ext=0
88
+LDR_v_i 00 111 1 00 11 0 ......... 11 ..... ..... @ldst_imm_pre sign=0 ext=0 sz=4
89
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
90
index XXXXXXX..XXXXXXX 100644
91
--- a/target/arm/tcg/translate-a64.c
92
+++ b/target/arm/tcg/translate-a64.c
93
@@ -XXX,XX +XXX,XX @@ static bool trans_STGP(DisasContext *s, arg_ldstpair *a)
94
return true;
95
}
96
97
-/*
98
- * Load/store (immediate post-indexed)
99
- * Load/store (immediate pre-indexed)
100
- * Load/store (unscaled immediate)
101
- *
102
- * 31 30 29 27 26 25 24 23 22 21 20 12 11 10 9 5 4 0
103
- * +----+-------+---+-----+-----+---+--------+-----+------+------+
104
- * |size| 1 1 1 | V | 0 0 | opc | 0 | imm9 | idx | Rn | Rt |
105
- * +----+-------+---+-----+-----+---+--------+-----+------+------+
106
- *
107
- * idx = 01 -> post-indexed, 11 pre-indexed, 00 unscaled imm. (no writeback)
108
- 10 -> unprivileged
109
- * V = 0 -> non-vector
110
- * size: 00 -> 8 bit, 01 -> 16 bit, 10 -> 32 bit, 11 -> 64bit
111
- * opc: 00 -> store, 01 -> loadu, 10 -> loads 64, 11 -> loads 32
112
- */
113
-static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn,
114
- int opc,
115
- int size,
116
- int rt,
117
- bool is_vector)
118
+static void op_addr_ldst_imm_pre(DisasContext *s, arg_ldst_imm *a,
119
+ TCGv_i64 *clean_addr, TCGv_i64 *dirty_addr,
120
+ uint64_t offset, bool is_store, MemOp mop)
121
{
122
- int rn = extract32(insn, 5, 5);
123
- int imm9 = sextract32(insn, 12, 9);
124
- int idx = extract32(insn, 10, 2);
125
- bool is_signed = false;
126
- bool is_store = false;
127
- bool is_extended = false;
128
- bool is_unpriv = (idx == 2);
129
- bool iss_valid;
130
- bool post_index;
131
- bool writeback;
132
int memidx;
133
- MemOp memop;
134
- TCGv_i64 clean_addr, dirty_addr;
135
136
- if (is_vector) {
137
- size |= (opc & 2) << 1;
138
- if (size > 4 || is_unpriv) {
139
- unallocated_encoding(s);
140
- return;
141
- }
142
- is_store = ((opc & 1) == 0);
143
- if (!fp_access_check(s)) {
144
- return;
145
- }
146
- memop = finalize_memop_asimd(s, size);
147
- } else {
148
- if (size == 3 && opc == 2) {
149
- /* PRFM - prefetch */
150
- if (idx != 0) {
151
- unallocated_encoding(s);
152
- return;
153
- }
154
- return;
155
- }
156
- if (opc == 3 && size > 1) {
157
- unallocated_encoding(s);
158
- return;
159
- }
160
- is_store = (opc == 0);
161
- is_signed = !is_store && extract32(opc, 1, 1);
162
- is_extended = (size < 3) && extract32(opc, 0, 1);
163
- memop = finalize_memop(s, size + is_signed * MO_SIGN);
164
- }
165
-
166
- switch (idx) {
167
- case 0:
168
- case 2:
169
- post_index = false;
170
- writeback = false;
171
- break;
172
- case 1:
173
- post_index = true;
174
- writeback = true;
175
- break;
176
- case 3:
177
- post_index = false;
178
- writeback = true;
179
- break;
180
- default:
181
- g_assert_not_reached();
182
- }
183
-
184
- iss_valid = !is_vector && !writeback;
185
-
186
- if (rn == 31) {
187
+ if (a->rn == 31) {
188
gen_check_sp_alignment(s);
189
}
190
191
- dirty_addr = read_cpu_reg_sp(s, rn, 1);
192
- if (!post_index) {
193
- tcg_gen_addi_i64(dirty_addr, dirty_addr, imm9);
194
+ *dirty_addr = read_cpu_reg_sp(s, a->rn, 1);
195
+ if (!a->p) {
196
+ tcg_gen_addi_i64(*dirty_addr, *dirty_addr, offset);
197
}
198
+ memidx = a->unpriv ? get_a64_user_mem_index(s) : get_mem_index(s);
199
+ *clean_addr = gen_mte_check1_mmuidx(s, *dirty_addr, is_store,
200
+ a->w || a->rn != 31,
201
+ mop, a->unpriv, memidx);
202
+}
203
204
- memidx = is_unpriv ? get_a64_user_mem_index(s) : get_mem_index(s);
205
-
206
- clean_addr = gen_mte_check1_mmuidx(s, dirty_addr, is_store,
207
- writeback || rn != 31,
208
- memop, is_unpriv, memidx);
209
-
210
- if (is_vector) {
211
- if (is_store) {
212
- do_fp_st(s, rt, clean_addr, memop);
213
- } else {
214
- do_fp_ld(s, rt, clean_addr, memop);
215
- }
216
- } else {
217
- TCGv_i64 tcg_rt = cpu_reg(s, rt);
218
- bool iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc);
219
-
220
- if (is_store) {
221
- do_gpr_st_memidx(s, tcg_rt, clean_addr, memop, memidx,
222
- iss_valid, rt, iss_sf, false);
223
- } else {
224
- do_gpr_ld_memidx(s, tcg_rt, clean_addr, memop,
225
- is_extended, memidx,
226
- iss_valid, rt, iss_sf, false);
227
+static void op_addr_ldst_imm_post(DisasContext *s, arg_ldst_imm *a,
228
+ TCGv_i64 dirty_addr, uint64_t offset)
229
+{
230
+ if (a->w) {
231
+ if (a->p) {
232
+ tcg_gen_addi_i64(dirty_addr, dirty_addr, offset);
233
}
234
+ tcg_gen_mov_i64(cpu_reg_sp(s, a->rn), dirty_addr);
235
}
236
+}
237
238
- if (writeback) {
239
- TCGv_i64 tcg_rn = cpu_reg_sp(s, rn);
240
- if (post_index) {
241
- tcg_gen_addi_i64(dirty_addr, dirty_addr, imm9);
242
- }
243
- tcg_gen_mov_i64(tcg_rn, dirty_addr);
244
+static bool trans_STR_i(DisasContext *s, arg_ldst_imm *a)
245
+{
246
+ bool iss_sf, iss_valid = !a->w;
247
+ TCGv_i64 clean_addr, dirty_addr, tcg_rt;
248
+ int memidx = a->unpriv ? get_a64_user_mem_index(s) : get_mem_index(s);
249
+ MemOp mop = finalize_memop(s, a->sz + a->sign * MO_SIGN);
250
+
251
+ op_addr_ldst_imm_pre(s, a, &clean_addr, &dirty_addr, a->imm, true, mop);
252
+
253
+ tcg_rt = cpu_reg(s, a->rt);
254
+ iss_sf = ldst_iss_sf(a->sz, a->sign, a->ext);
255
+
256
+ do_gpr_st_memidx(s, tcg_rt, clean_addr, mop, memidx,
257
+ iss_valid, a->rt, iss_sf, false);
258
+ op_addr_ldst_imm_post(s, a, dirty_addr, a->imm);
259
+ return true;
260
+}
261
+
262
+static bool trans_LDR_i(DisasContext *s, arg_ldst_imm *a)
263
+{
264
+ bool iss_sf, iss_valid = !a->w;
265
+ TCGv_i64 clean_addr, dirty_addr, tcg_rt;
266
+ int memidx = a->unpriv ? get_a64_user_mem_index(s) : get_mem_index(s);
267
+ MemOp mop = finalize_memop(s, a->sz + a->sign * MO_SIGN);
268
+
269
+ op_addr_ldst_imm_pre(s, a, &clean_addr, &dirty_addr, a->imm, false, mop);
270
+
271
+ tcg_rt = cpu_reg(s, a->rt);
272
+ iss_sf = ldst_iss_sf(a->sz, a->sign, a->ext);
273
+
274
+ do_gpr_ld_memidx(s, tcg_rt, clean_addr, mop,
275
+ a->ext, memidx, iss_valid, a->rt, iss_sf, false);
276
+ op_addr_ldst_imm_post(s, a, dirty_addr, a->imm);
277
+ return true;
278
+}
279
+
280
+static bool trans_STR_v_i(DisasContext *s, arg_ldst_imm *a)
281
+{
282
+ TCGv_i64 clean_addr, dirty_addr;
283
+ MemOp mop;
284
+
285
+ if (!fp_access_check(s)) {
286
+ return true;
287
}
288
+ mop = finalize_memop_asimd(s, a->sz);
289
+ op_addr_ldst_imm_pre(s, a, &clean_addr, &dirty_addr, a->imm, true, mop);
290
+ do_fp_st(s, a->rt, clean_addr, mop);
291
+ op_addr_ldst_imm_post(s, a, dirty_addr, a->imm);
292
+ return true;
293
+}
294
+
295
+static bool trans_LDR_v_i(DisasContext *s, arg_ldst_imm *a)
296
+{
297
+ TCGv_i64 clean_addr, dirty_addr;
298
+ MemOp mop;
299
+
300
+ if (!fp_access_check(s)) {
301
+ return true;
302
+ }
303
+ mop = finalize_memop_asimd(s, a->sz);
304
+ op_addr_ldst_imm_pre(s, a, &clean_addr, &dirty_addr, a->imm, false, mop);
305
+ do_fp_ld(s, a->rt, clean_addr, mop);
306
+ op_addr_ldst_imm_post(s, a, dirty_addr, a->imm);
307
+ return true;
308
}
309
310
/*
311
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg(DisasContext *s, uint32_t insn)
312
switch (extract32(insn, 24, 2)) {
313
case 0:
314
if (extract32(insn, 21, 1) == 0) {
315
- /* Load/store register (unscaled immediate)
316
- * Load/store immediate pre/post-indexed
317
- * Load/store register unprivileged
318
- */
319
- disas_ldst_reg_imm9(s, insn, opc, size, rt, is_vector);
320
- return;
321
+ break;
322
}
323
switch (extract32(insn, 10, 2)) {
324
case 0:
325
--
326
2.34.1
diff view generated by jsdifflib
New patch
1
Convert the LDR and STR instructions which use a 12-bit immediate
2
offset to decodetree. We can reuse the existing LDR and STR
3
trans functions for these.
1
4
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20230602155223.2040685-14-peter.maydell@linaro.org
8
---
9
target/arm/tcg/a64.decode | 25 ++++++++
10
target/arm/tcg/translate-a64.c | 104 +++++----------------------------
11
2 files changed, 41 insertions(+), 88 deletions(-)
12
13
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
14
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/tcg/a64.decode
16
+++ b/target/arm/tcg/a64.decode
17
@@ -XXX,XX +XXX,XX @@ STR_v_i sz:2 111 1 00 00 0 ......... 11 ..... ..... @ldst_imm_pre sign=0
18
STR_v_i 00 111 1 00 10 0 ......... 11 ..... ..... @ldst_imm_pre sign=0 ext=0 sz=4
19
LDR_v_i sz:2 111 1 00 01 0 ......... 11 ..... ..... @ldst_imm_pre sign=0 ext=0
20
LDR_v_i 00 111 1 00 11 0 ......... 11 ..... ..... @ldst_imm_pre sign=0 ext=0 sz=4
21
+
22
+# Load/store with an unsigned 12 bit immediate, which is scaled by the
23
+# element size. The function gets the sz:imm and returns the scaled immediate.
24
+%uimm_scaled 10:12 sz:3 !function=uimm_scaled
25
+
26
+@ldst_uimm .. ... . .. .. ............ rn:5 rt:5 &ldst_imm unpriv=0 p=0 w=0 imm=%uimm_scaled
27
+
28
+STR_i sz:2 111 0 01 00 ............ ..... ..... @ldst_uimm sign=0 ext=0
29
+LDR_i 00 111 0 01 01 ............ ..... ..... @ldst_uimm sign=0 ext=1 sz=0
30
+LDR_i 01 111 0 01 01 ............ ..... ..... @ldst_uimm sign=0 ext=1 sz=1
31
+LDR_i 10 111 0 01 01 ............ ..... ..... @ldst_uimm sign=0 ext=1 sz=2
32
+LDR_i 11 111 0 01 01 ............ ..... ..... @ldst_uimm sign=0 ext=0 sz=3
33
+LDR_i 00 111 0 01 10 ............ ..... ..... @ldst_uimm sign=1 ext=0 sz=0
34
+LDR_i 01 111 0 01 10 ............ ..... ..... @ldst_uimm sign=1 ext=0 sz=1
35
+LDR_i 10 111 0 01 10 ............ ..... ..... @ldst_uimm sign=1 ext=0 sz=2
36
+LDR_i 00 111 0 01 11 ............ ..... ..... @ldst_uimm sign=1 ext=1 sz=0
37
+LDR_i 01 111 0 01 11 ............ ..... ..... @ldst_uimm sign=1 ext=1 sz=1
38
+
39
+# PRFM
40
+NOP 11 111 0 01 10 ------------ ----- -----
41
+
42
+STR_v_i sz:2 111 1 01 00 ............ ..... ..... @ldst_uimm sign=0 ext=0
43
+STR_v_i 00 111 1 01 10 ............ ..... ..... @ldst_uimm sign=0 ext=0 sz=4
44
+LDR_v_i sz:2 111 1 01 01 ............ ..... ..... @ldst_uimm sign=0 ext=0
45
+LDR_v_i 00 111 1 01 11 ............ ..... ..... @ldst_uimm sign=0 ext=0 sz=4
46
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
47
index XXXXXXX..XXXXXXX 100644
48
--- a/target/arm/tcg/translate-a64.c
49
+++ b/target/arm/tcg/translate-a64.c
50
@@ -XXX,XX +XXX,XX @@ enum a64_shift_type {
51
A64_SHIFT_TYPE_ROR = 3
52
};
53
54
+/*
55
+ * Helpers for extracting complex instruction fields
56
+ */
57
+
58
+/*
59
+ * For load/store with an unsigned 12 bit immediate scaled by the element
60
+ * size. The input has the immediate field in bits [14:3] and the element
61
+ * size in [2:0].
62
+ */
63
+static int uimm_scaled(DisasContext *s, int x)
64
+{
65
+ unsigned imm = x >> 3;
66
+ unsigned scale = extract32(x, 0, 3);
67
+ return imm << scale;
68
+}
69
+
70
/*
71
* Include the generated decoders.
72
*/
73
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn,
74
}
75
}
76
77
-/*
78
- * Load/store (unsigned immediate)
79
- *
80
- * 31 30 29 27 26 25 24 23 22 21 10 9 5
81
- * +----+-------+---+-----+-----+------------+-------+------+
82
- * |size| 1 1 1 | V | 0 1 | opc | imm12 | Rn | Rt |
83
- * +----+-------+---+-----+-----+------------+-------+------+
84
- *
85
- * For non-vector:
86
- * size: 00-> byte, 01 -> 16 bit, 10 -> 32bit, 11 -> 64bit
87
- * opc: 00 -> store, 01 -> loadu, 10 -> loads 64, 11 -> loads 32
88
- * For vector:
89
- * size is opc<1>:size<1:0> so 100 -> 128 bit; 110 and 111 unallocated
90
- * opc<0>: 0 -> store, 1 -> load
91
- * Rn: base address register (inc SP)
92
- * Rt: target register
93
- */
94
-static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn,
95
- int opc,
96
- int size,
97
- int rt,
98
- bool is_vector)
99
-{
100
- int rn = extract32(insn, 5, 5);
101
- unsigned int imm12 = extract32(insn, 10, 12);
102
- unsigned int offset;
103
- TCGv_i64 clean_addr, dirty_addr;
104
- bool is_store;
105
- bool is_signed = false;
106
- bool is_extended = false;
107
- MemOp memop;
108
-
109
- if (is_vector) {
110
- size |= (opc & 2) << 1;
111
- if (size > 4) {
112
- unallocated_encoding(s);
113
- return;
114
- }
115
- is_store = !extract32(opc, 0, 1);
116
- if (!fp_access_check(s)) {
117
- return;
118
- }
119
- memop = finalize_memop_asimd(s, size);
120
- } else {
121
- if (size == 3 && opc == 2) {
122
- /* PRFM - prefetch */
123
- return;
124
- }
125
- if (opc == 3 && size > 1) {
126
- unallocated_encoding(s);
127
- return;
128
- }
129
- is_store = (opc == 0);
130
- is_signed = !is_store && extract32(opc, 1, 1);
131
- is_extended = (size < 3) && extract32(opc, 0, 1);
132
- memop = finalize_memop(s, size + is_signed * MO_SIGN);
133
- }
134
-
135
- if (rn == 31) {
136
- gen_check_sp_alignment(s);
137
- }
138
- dirty_addr = read_cpu_reg_sp(s, rn, 1);
139
- offset = imm12 << size;
140
- tcg_gen_addi_i64(dirty_addr, dirty_addr, offset);
141
-
142
- clean_addr = gen_mte_check1(s, dirty_addr, is_store, rn != 31, memop);
143
-
144
- if (is_vector) {
145
- if (is_store) {
146
- do_fp_st(s, rt, clean_addr, memop);
147
- } else {
148
- do_fp_ld(s, rt, clean_addr, memop);
149
- }
150
- } else {
151
- TCGv_i64 tcg_rt = cpu_reg(s, rt);
152
- bool iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc);
153
- if (is_store) {
154
- do_gpr_st(s, tcg_rt, clean_addr, memop, true, rt, iss_sf, false);
155
- } else {
156
- do_gpr_ld(s, tcg_rt, clean_addr, memop,
157
- is_extended, true, rt, iss_sf, false);
158
- }
159
- }
160
-}
161
-
162
/* Atomic memory operations
163
*
164
* 31 30 27 26 24 22 21 16 15 12 10 5 0
165
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg(DisasContext *s, uint32_t insn)
166
return;
167
}
168
break;
169
- case 1:
170
- disas_ldst_reg_unsigned_imm(s, insn, opc, size, rt, is_vector);
171
- return;
172
}
173
unallocated_encoding(s);
174
}
175
--
176
2.34.1
diff view generated by jsdifflib
New patch
1
Convert the LDR and STR instructions which take a register
2
plus register offset to decodetree.
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20230602155223.2040685-15-peter.maydell@linaro.org
7
---
8
target/arm/tcg/a64.decode | 22 +++++
9
target/arm/tcg/translate-a64.c | 173 +++++++++++++++------------------
10
2 files changed, 103 insertions(+), 92 deletions(-)
11
12
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/arm/tcg/a64.decode
15
+++ b/target/arm/tcg/a64.decode
16
@@ -XXX,XX +XXX,XX @@ STR_v_i sz:2 111 1 01 00 ............ ..... ..... @ldst_uimm sign=0 ext=
17
STR_v_i 00 111 1 01 10 ............ ..... ..... @ldst_uimm sign=0 ext=0 sz=4
18
LDR_v_i sz:2 111 1 01 01 ............ ..... ..... @ldst_uimm sign=0 ext=0
19
LDR_v_i 00 111 1 01 11 ............ ..... ..... @ldst_uimm sign=0 ext=0 sz=4
20
+
21
+# Load/store with register offset
22
+&ldst rm rn rt sign ext sz opt s
23
+@ldst .. ... . .. .. . rm:5 opt:3 s:1 .. rn:5 rt:5 &ldst
24
+STR sz:2 111 0 00 00 1 ..... ... . 10 ..... ..... @ldst sign=0 ext=0
25
+LDR 00 111 0 00 01 1 ..... ... . 10 ..... ..... @ldst sign=0 ext=1 sz=0
26
+LDR 01 111 0 00 01 1 ..... ... . 10 ..... ..... @ldst sign=0 ext=1 sz=1
27
+LDR 10 111 0 00 01 1 ..... ... . 10 ..... ..... @ldst sign=0 ext=1 sz=2
28
+LDR 11 111 0 00 01 1 ..... ... . 10 ..... ..... @ldst sign=0 ext=0 sz=3
29
+LDR 00 111 0 00 10 1 ..... ... . 10 ..... ..... @ldst sign=1 ext=0 sz=0
30
+LDR 01 111 0 00 10 1 ..... ... . 10 ..... ..... @ldst sign=1 ext=0 sz=1
31
+LDR 10 111 0 00 10 1 ..... ... . 10 ..... ..... @ldst sign=1 ext=0 sz=2
32
+LDR 00 111 0 00 11 1 ..... ... . 10 ..... ..... @ldst sign=1 ext=1 sz=0
33
+LDR 01 111 0 00 11 1 ..... ... . 10 ..... ..... @ldst sign=1 ext=1 sz=1
34
+
35
+# PRFM
36
+NOP 11 111 0 00 10 1 ----- -1- - 10 ----- -----
37
+
38
+STR_v sz:2 111 1 00 00 1 ..... ... . 10 ..... ..... @ldst sign=0 ext=0
39
+STR_v 00 111 1 00 10 1 ..... ... . 10 ..... ..... @ldst sign=0 ext=0 sz=4
40
+LDR_v sz:2 111 1 00 01 1 ..... ... . 10 ..... ..... @ldst sign=0 ext=0
41
+LDR_v 00 111 1 00 11 1 ..... ... . 10 ..... ..... @ldst sign=0 ext=0 sz=4
42
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
43
index XXXXXXX..XXXXXXX 100644
44
--- a/target/arm/tcg/translate-a64.c
45
+++ b/target/arm/tcg/translate-a64.c
46
@@ -XXX,XX +XXX,XX @@ static bool trans_LDR_v_i(DisasContext *s, arg_ldst_imm *a)
47
return true;
48
}
49
50
-/*
51
- * Load/store (register offset)
52
- *
53
- * 31 30 29 27 26 25 24 23 22 21 20 16 15 13 12 11 10 9 5 4 0
54
- * +----+-------+---+-----+-----+---+------+-----+--+-----+----+----+
55
- * |size| 1 1 1 | V | 0 0 | opc | 1 | Rm | opt | S| 1 0 | Rn | Rt |
56
- * +----+-------+---+-----+-----+---+------+-----+--+-----+----+----+
57
- *
58
- * For non-vector:
59
- * size: 00-> byte, 01 -> 16 bit, 10 -> 32bit, 11 -> 64bit
60
- * opc: 00 -> store, 01 -> loadu, 10 -> loads 64, 11 -> loads 32
61
- * For vector:
62
- * size is opc<1>:size<1:0> so 100 -> 128 bit; 110 and 111 unallocated
63
- * opc<0>: 0 -> store, 1 -> load
64
- * V: 1 -> vector/simd
65
- * opt: extend encoding (see DecodeRegExtend)
66
- * S: if S=1 then scale (essentially index by sizeof(size))
67
- * Rt: register to transfer into/out of
68
- * Rn: address register or SP for base
69
- * Rm: offset register or ZR for offset
70
- */
71
-static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn,
72
- int opc,
73
- int size,
74
- int rt,
75
- bool is_vector)
76
+static void op_addr_ldst_pre(DisasContext *s, arg_ldst *a,
77
+ TCGv_i64 *clean_addr, TCGv_i64 *dirty_addr,
78
+ bool is_store, MemOp memop)
79
{
80
- int rn = extract32(insn, 5, 5);
81
- int shift = extract32(insn, 12, 1);
82
- int rm = extract32(insn, 16, 5);
83
- int opt = extract32(insn, 13, 3);
84
- bool is_signed = false;
85
- bool is_store = false;
86
- bool is_extended = false;
87
- TCGv_i64 tcg_rm, clean_addr, dirty_addr;
88
- MemOp memop;
89
+ TCGv_i64 tcg_rm;
90
91
- if (extract32(opt, 1, 1) == 0) {
92
- unallocated_encoding(s);
93
- return;
94
- }
95
-
96
- if (is_vector) {
97
- size |= (opc & 2) << 1;
98
- if (size > 4) {
99
- unallocated_encoding(s);
100
- return;
101
- }
102
- is_store = !extract32(opc, 0, 1);
103
- if (!fp_access_check(s)) {
104
- return;
105
- }
106
- memop = finalize_memop_asimd(s, size);
107
- } else {
108
- if (size == 3 && opc == 2) {
109
- /* PRFM - prefetch */
110
- return;
111
- }
112
- if (opc == 3 && size > 1) {
113
- unallocated_encoding(s);
114
- return;
115
- }
116
- is_store = (opc == 0);
117
- is_signed = !is_store && extract32(opc, 1, 1);
118
- is_extended = (size < 3) && extract32(opc, 0, 1);
119
- memop = finalize_memop(s, size + is_signed * MO_SIGN);
120
- }
121
-
122
- if (rn == 31) {
123
+ if (a->rn == 31) {
124
gen_check_sp_alignment(s);
125
}
126
- dirty_addr = read_cpu_reg_sp(s, rn, 1);
127
+ *dirty_addr = read_cpu_reg_sp(s, a->rn, 1);
128
129
- tcg_rm = read_cpu_reg(s, rm, 1);
130
- ext_and_shift_reg(tcg_rm, tcg_rm, opt, shift ? size : 0);
131
+ tcg_rm = read_cpu_reg(s, a->rm, 1);
132
+ ext_and_shift_reg(tcg_rm, tcg_rm, a->opt, a->s ? a->sz : 0);
133
134
- tcg_gen_add_i64(dirty_addr, dirty_addr, tcg_rm);
135
+ tcg_gen_add_i64(*dirty_addr, *dirty_addr, tcg_rm);
136
+ *clean_addr = gen_mte_check1(s, *dirty_addr, is_store, true, memop);
137
+}
138
139
- clean_addr = gen_mte_check1(s, dirty_addr, is_store, true, memop);
140
+static bool trans_LDR(DisasContext *s, arg_ldst *a)
141
+{
142
+ TCGv_i64 clean_addr, dirty_addr, tcg_rt;
143
+ bool iss_sf = ldst_iss_sf(a->sz, a->sign, a->ext);
144
+ MemOp memop;
145
146
- if (is_vector) {
147
- if (is_store) {
148
- do_fp_st(s, rt, clean_addr, memop);
149
- } else {
150
- do_fp_ld(s, rt, clean_addr, memop);
151
- }
152
- } else {
153
- TCGv_i64 tcg_rt = cpu_reg(s, rt);
154
- bool iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc);
155
-
156
- if (is_store) {
157
- do_gpr_st(s, tcg_rt, clean_addr, memop,
158
- true, rt, iss_sf, false);
159
- } else {
160
- do_gpr_ld(s, tcg_rt, clean_addr, memop,
161
- is_extended, true, rt, iss_sf, false);
162
- }
163
+ if (extract32(a->opt, 1, 1) == 0) {
164
+ return false;
165
}
166
+
167
+ memop = finalize_memop(s, a->sz + a->sign * MO_SIGN);
168
+ op_addr_ldst_pre(s, a, &clean_addr, &dirty_addr, false, memop);
169
+ tcg_rt = cpu_reg(s, a->rt);
170
+ do_gpr_ld(s, tcg_rt, clean_addr, memop,
171
+ a->ext, true, a->rt, iss_sf, false);
172
+ return true;
173
+}
174
+
175
+static bool trans_STR(DisasContext *s, arg_ldst *a)
176
+{
177
+ TCGv_i64 clean_addr, dirty_addr, tcg_rt;
178
+ bool iss_sf = ldst_iss_sf(a->sz, a->sign, a->ext);
179
+ MemOp memop;
180
+
181
+ if (extract32(a->opt, 1, 1) == 0) {
182
+ return false;
183
+ }
184
+
185
+ memop = finalize_memop(s, a->sz);
186
+ op_addr_ldst_pre(s, a, &clean_addr, &dirty_addr, true, memop);
187
+ tcg_rt = cpu_reg(s, a->rt);
188
+ do_gpr_st(s, tcg_rt, clean_addr, memop, true, a->rt, iss_sf, false);
189
+ return true;
190
+}
191
+
192
+static bool trans_LDR_v(DisasContext *s, arg_ldst *a)
193
+{
194
+ TCGv_i64 clean_addr, dirty_addr;
195
+ MemOp memop;
196
+
197
+ if (extract32(a->opt, 1, 1) == 0) {
198
+ return false;
199
+ }
200
+
201
+ if (!fp_access_check(s)) {
202
+ return true;
203
+ }
204
+
205
+ memop = finalize_memop_asimd(s, a->sz);
206
+ op_addr_ldst_pre(s, a, &clean_addr, &dirty_addr, false, memop);
207
+ do_fp_ld(s, a->rt, clean_addr, memop);
208
+ return true;
209
+}
210
+
211
+static bool trans_STR_v(DisasContext *s, arg_ldst *a)
212
+{
213
+ TCGv_i64 clean_addr, dirty_addr;
214
+ MemOp memop;
215
+
216
+ if (extract32(a->opt, 1, 1) == 0) {
217
+ return false;
218
+ }
219
+
220
+ if (!fp_access_check(s)) {
221
+ return true;
222
+ }
223
+
224
+ memop = finalize_memop_asimd(s, a->sz);
225
+ op_addr_ldst_pre(s, a, &clean_addr, &dirty_addr, true, memop);
226
+ do_fp_st(s, a->rt, clean_addr, memop);
227
+ return true;
228
}
229
230
/* Atomic memory operations
231
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_ldapr_stlr(DisasContext *s, uint32_t insn)
232
static void disas_ldst_reg(DisasContext *s, uint32_t insn)
233
{
234
int rt = extract32(insn, 0, 5);
235
- int opc = extract32(insn, 22, 2);
236
bool is_vector = extract32(insn, 26, 1);
237
int size = extract32(insn, 30, 2);
238
239
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg(DisasContext *s, uint32_t insn)
240
disas_ldst_atomic(s, insn, size, rt, is_vector);
241
return;
242
case 2:
243
- disas_ldst_reg_roffset(s, insn, opc, size, rt, is_vector);
244
- return;
245
+ break;
246
default:
247
disas_ldst_pac(s, insn, size, rt, is_vector);
248
return;
249
--
250
2.34.1
diff view generated by jsdifflib
New patch
1
Convert the insns in the atomic memory operations group to
2
decodetree.
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20230602155223.2040685-16-peter.maydell@linaro.org
7
---
8
target/arm/tcg/a64.decode | 15 ++++
9
target/arm/tcg/translate-a64.c | 153 ++++++++++++---------------------
10
2 files changed, 70 insertions(+), 98 deletions(-)
11
12
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/arm/tcg/a64.decode
15
+++ b/target/arm/tcg/a64.decode
16
@@ -XXX,XX +XXX,XX @@ STR_v sz:2 111 1 00 00 1 ..... ... . 10 ..... ..... @ldst sign=0 ext=0
17
STR_v 00 111 1 00 10 1 ..... ... . 10 ..... ..... @ldst sign=0 ext=0 sz=4
18
LDR_v sz:2 111 1 00 01 1 ..... ... . 10 ..... ..... @ldst sign=0 ext=0
19
LDR_v 00 111 1 00 11 1 ..... ... . 10 ..... ..... @ldst sign=0 ext=0 sz=4
20
+
21
+# Atomic memory operations
22
+&atomic rs rn rt a r sz
23
+@atomic sz:2 ... . .. a:1 r:1 . rs:5 . ... .. rn:5 rt:5 &atomic
24
+LDADD .. 111 0 00 . . 1 ..... 0000 00 ..... ..... @atomic
25
+LDCLR .. 111 0 00 . . 1 ..... 0001 00 ..... ..... @atomic
26
+LDEOR .. 111 0 00 . . 1 ..... 0010 00 ..... ..... @atomic
27
+LDSET .. 111 0 00 . . 1 ..... 0011 00 ..... ..... @atomic
28
+LDSMAX .. 111 0 00 . . 1 ..... 0100 00 ..... ..... @atomic
29
+LDSMIN .. 111 0 00 . . 1 ..... 0101 00 ..... ..... @atomic
30
+LDUMAX .. 111 0 00 . . 1 ..... 0110 00 ..... ..... @atomic
31
+LDUMIN .. 111 0 00 . . 1 ..... 0111 00 ..... ..... @atomic
32
+SWP .. 111 0 00 . . 1 ..... 1000 00 ..... ..... @atomic
33
+
34
+LDAPR sz:2 111 0 00 1 0 1 11111 1100 00 rn:5 rt:5
35
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
36
index XXXXXXX..XXXXXXX 100644
37
--- a/target/arm/tcg/translate-a64.c
38
+++ b/target/arm/tcg/translate-a64.c
39
@@ -XXX,XX +XXX,XX @@ static bool trans_STR_v(DisasContext *s, arg_ldst *a)
40
return true;
41
}
42
43
-/* Atomic memory operations
44
- *
45
- * 31 30 27 26 24 22 21 16 15 12 10 5 0
46
- * +------+-------+---+-----+-----+---+----+----+-----+-----+----+-----+
47
- * | size | 1 1 1 | V | 0 0 | A R | 1 | Rs | o3 | opc | 0 0 | Rn | Rt |
48
- * +------+-------+---+-----+-----+--------+----+-----+-----+----+-----+
49
- *
50
- * Rt: the result register
51
- * Rn: base address or SP
52
- * Rs: the source register for the operation
53
- * V: vector flag (always 0 as of v8.3)
54
- * A: acquire flag
55
- * R: release flag
56
- */
57
-static void disas_ldst_atomic(DisasContext *s, uint32_t insn,
58
- int size, int rt, bool is_vector)
59
+
60
+static bool do_atomic_ld(DisasContext *s, arg_atomic *a, AtomicThreeOpFn *fn,
61
+ int sign, bool invert)
62
{
63
- int rs = extract32(insn, 16, 5);
64
- int rn = extract32(insn, 5, 5);
65
- int o3_opc = extract32(insn, 12, 4);
66
- bool r = extract32(insn, 22, 1);
67
- bool a = extract32(insn, 23, 1);
68
- TCGv_i64 tcg_rs, tcg_rt, clean_addr;
69
- AtomicThreeOpFn *fn = NULL;
70
- MemOp mop = size;
71
+ MemOp mop = a->sz | sign;
72
+ TCGv_i64 clean_addr, tcg_rs, tcg_rt;
73
74
- if (is_vector || !dc_isar_feature(aa64_atomics, s)) {
75
- unallocated_encoding(s);
76
- return;
77
- }
78
- switch (o3_opc) {
79
- case 000: /* LDADD */
80
- fn = tcg_gen_atomic_fetch_add_i64;
81
- break;
82
- case 001: /* LDCLR */
83
- fn = tcg_gen_atomic_fetch_and_i64;
84
- break;
85
- case 002: /* LDEOR */
86
- fn = tcg_gen_atomic_fetch_xor_i64;
87
- break;
88
- case 003: /* LDSET */
89
- fn = tcg_gen_atomic_fetch_or_i64;
90
- break;
91
- case 004: /* LDSMAX */
92
- fn = tcg_gen_atomic_fetch_smax_i64;
93
- mop |= MO_SIGN;
94
- break;
95
- case 005: /* LDSMIN */
96
- fn = tcg_gen_atomic_fetch_smin_i64;
97
- mop |= MO_SIGN;
98
- break;
99
- case 006: /* LDUMAX */
100
- fn = tcg_gen_atomic_fetch_umax_i64;
101
- break;
102
- case 007: /* LDUMIN */
103
- fn = tcg_gen_atomic_fetch_umin_i64;
104
- break;
105
- case 010: /* SWP */
106
- fn = tcg_gen_atomic_xchg_i64;
107
- break;
108
- case 014: /* LDAPR, LDAPRH, LDAPRB */
109
- if (!dc_isar_feature(aa64_rcpc_8_3, s) ||
110
- rs != 31 || a != 1 || r != 0) {
111
- unallocated_encoding(s);
112
- return;
113
- }
114
- break;
115
- default:
116
- unallocated_encoding(s);
117
- return;
118
- }
119
-
120
- if (rn == 31) {
121
+ if (a->rn == 31) {
122
gen_check_sp_alignment(s);
123
}
124
-
125
- mop = check_atomic_align(s, rn, mop);
126
- clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn), false, rn != 31, mop);
127
-
128
- if (o3_opc == 014) {
129
- /*
130
- * LDAPR* are a special case because they are a simple load, not a
131
- * fetch-and-do-something op.
132
- * The architectural consistency requirements here are weaker than
133
- * full load-acquire (we only need "load-acquire processor consistent"),
134
- * but we choose to implement them as full LDAQ.
135
- */
136
- do_gpr_ld(s, cpu_reg(s, rt), clean_addr, mop, false,
137
- true, rt, disas_ldst_compute_iss_sf(size, false, 0), true);
138
- tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
139
- return;
140
- }
141
-
142
- tcg_rs = read_cpu_reg(s, rs, true);
143
- tcg_rt = cpu_reg(s, rt);
144
-
145
- if (o3_opc == 1) { /* LDCLR */
146
+ mop = check_atomic_align(s, a->rn, mop);
147
+ clean_addr = gen_mte_check1(s, cpu_reg_sp(s, a->rn), false,
148
+ a->rn != 31, mop);
149
+ tcg_rs = read_cpu_reg(s, a->rs, true);
150
+ tcg_rt = cpu_reg(s, a->rt);
151
+ if (invert) {
152
tcg_gen_not_i64(tcg_rs, tcg_rs);
153
}
154
-
155
- /* The tcg atomic primitives are all full barriers. Therefore we
156
+ /*
157
+ * The tcg atomic primitives are all full barriers. Therefore we
158
* can ignore the Acquire and Release bits of this instruction.
159
*/
160
fn(tcg_rt, clean_addr, tcg_rs, get_mem_index(s), mop);
161
162
if (mop & MO_SIGN) {
163
- switch (size) {
164
+ switch (a->sz) {
165
case MO_8:
166
tcg_gen_ext8u_i64(tcg_rt, tcg_rt);
167
break;
168
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn,
169
g_assert_not_reached();
170
}
171
}
172
+ return true;
173
+}
174
+
175
+TRANS_FEAT(LDADD, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_fetch_add_i64, 0, false)
176
+TRANS_FEAT(LDCLR, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_fetch_and_i64, 0, true)
177
+TRANS_FEAT(LDEOR, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_fetch_xor_i64, 0, false)
178
+TRANS_FEAT(LDSET, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_fetch_or_i64, 0, false)
179
+TRANS_FEAT(LDSMAX, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_fetch_smax_i64, MO_SIGN, false)
180
+TRANS_FEAT(LDSMIN, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_fetch_smin_i64, MO_SIGN, false)
181
+TRANS_FEAT(LDUMAX, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_fetch_umax_i64, 0, false)
182
+TRANS_FEAT(LDUMIN, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_fetch_umin_i64, 0, false)
183
+TRANS_FEAT(SWP, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_xchg_i64, 0, false)
184
+
185
+static bool trans_LDAPR(DisasContext *s, arg_LDAPR *a)
186
+{
187
+ bool iss_sf = ldst_iss_sf(a->sz, false, false);
188
+ TCGv_i64 clean_addr;
189
+ MemOp mop;
190
+
191
+ if (!dc_isar_feature(aa64_atomics, s) ||
192
+ !dc_isar_feature(aa64_rcpc_8_3, s)) {
193
+ return false;
194
+ }
195
+ if (a->rn == 31) {
196
+ gen_check_sp_alignment(s);
197
+ }
198
+ mop = check_atomic_align(s, a->rn, a->sz);
199
+ clean_addr = gen_mte_check1(s, cpu_reg_sp(s, a->rn), false,
200
+ a->rn != 31, mop);
201
+ /*
202
+ * LDAPR* are a special case because they are a simple load, not a
203
+ * fetch-and-do-something op.
204
+ * The architectural consistency requirements here are weaker than
205
+ * full load-acquire (we only need "load-acquire processor consistent"),
206
+ * but we choose to implement them as full LDAQ.
207
+ */
208
+ do_gpr_ld(s, cpu_reg(s, a->rt), clean_addr, mop, false,
209
+ true, a->rt, iss_sf, true);
210
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
211
+ return true;
212
}
213
214
/*
215
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg(DisasContext *s, uint32_t insn)
216
}
217
switch (extract32(insn, 10, 2)) {
218
case 0:
219
- disas_ldst_atomic(s, insn, size, rt, is_vector);
220
- return;
221
case 2:
222
break;
223
default:
224
--
225
2.34.1
diff view generated by jsdifflib
1
The lan9118 code mostly uses symbolic constants for register offsets;
1
Convert the instructions in the load/store register (pointer
2
the exceptions are those which the datasheet doesn't give an official
2
authentication) group ot decodetree: LDRAA, LDRAB.
3
symbolic name to.
4
5
Add some names for the registers which don't already have them, based
6
on the longer names they are given in the memory map.
7
3
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
5
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
10
Message-id: 20210108180401.2263-3-peter.maydell@linaro.org
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20230602155223.2040685-17-peter.maydell@linaro.org
11
---
8
---
12
hw/net/lan9118.c | 24 ++++++++++++++++++------
9
target/arm/tcg/a64.decode | 7 +++
13
1 file changed, 18 insertions(+), 6 deletions(-)
10
target/arm/tcg/translate-a64.c | 83 +++++++---------------------------
11
2 files changed, 23 insertions(+), 67 deletions(-)
14
12
15
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
13
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
16
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/net/lan9118.c
15
--- a/target/arm/tcg/a64.decode
18
+++ b/hw/net/lan9118.c
16
+++ b/target/arm/tcg/a64.decode
19
@@ -XXX,XX +XXX,XX @@ do { hw_error("lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
17
@@ -XXX,XX +XXX,XX @@ LDUMIN .. 111 0 00 . . 1 ..... 0111 00 ..... ..... @atomic
20
do { fprintf(stderr, "lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
18
SWP .. 111 0 00 . . 1 ..... 1000 00 ..... ..... @atomic
21
#endif
19
22
20
LDAPR sz:2 111 0 00 1 0 1 11111 1100 00 rn:5 rt:5
23
+/* The tx and rx fifo ports are a range of aliased 32-bit registers */
24
+#define RX_DATA_FIFO_PORT_FIRST 0x00
25
+#define RX_DATA_FIFO_PORT_LAST 0x1f
26
+#define TX_DATA_FIFO_PORT_FIRST 0x20
27
+#define TX_DATA_FIFO_PORT_LAST 0x3f
28
+
21
+
29
+#define RX_STATUS_FIFO_PORT 0x40
22
+# Load/store register (pointer authentication)
30
+#define RX_STATUS_FIFO_PEEK 0x44
31
+#define TX_STATUS_FIFO_PORT 0x48
32
+#define TX_STATUS_FIFO_PEEK 0x4c
33
+
23
+
34
#define CSR_ID_REV 0x50
24
+# LDRA immediate is 10 bits signed and scaled, but the bits aren't all contiguous
35
#define CSR_IRQ_CFG 0x54
25
+%ldra_imm 22:s1 12:9 !function=times_2
36
#define CSR_INT_STS 0x58
26
+
37
@@ -XXX,XX +XXX,XX @@ static void lan9118_writel(void *opaque, hwaddr offset,
27
+LDRA 11 111 0 00 m:1 . 1 ......... w:1 1 rn:5 rt:5 imm=%ldra_imm
38
offset &= 0xff;
28
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
39
29
index XXXXXXX..XXXXXXX 100644
40
//DPRINTF("Write reg 0x%02x = 0x%08x\n", (int)offset, val);
30
--- a/target/arm/tcg/translate-a64.c
41
- if (offset >= 0x20 && offset < 0x40) {
31
+++ b/target/arm/tcg/translate-a64.c
42
+ if (offset >= TX_DATA_FIFO_PORT_FIRST &&
32
@@ -XXX,XX +XXX,XX @@ static bool trans_LDAPR(DisasContext *s, arg_LDAPR *a)
43
+ offset <= TX_DATA_FIFO_PORT_LAST) {
33
return true;
44
/* TX FIFO */
34
}
45
tx_fifo_push(s, val);
35
46
return;
36
-/*
47
@@ -XXX,XX +XXX,XX @@ static uint64_t lan9118_readl(void *opaque, hwaddr offset,
37
- * PAC memory operations
48
lan9118_state *s = (lan9118_state *)opaque;
38
- *
49
39
- * 31 30 27 26 24 22 21 12 11 10 5 0
50
//DPRINTF("Read reg 0x%02x\n", (int)offset);
40
- * +------+-------+---+-----+-----+---+--------+---+---+----+-----+
51
- if (offset < 0x20) {
41
- * | size | 1 1 1 | V | 0 0 | M S | 1 | imm9 | W | 1 | Rn | Rt |
52
+ if (offset <= RX_DATA_FIFO_PORT_LAST) {
42
- * +------+-------+---+-----+-----+---+--------+---+---+----+-----+
53
/* RX FIFO */
43
- *
54
return rx_fifo_pop(s);
44
- * Rt: the result register
45
- * Rn: base address or SP
46
- * V: vector flag (always 0 as of v8.3)
47
- * M: clear for key DA, set for key DB
48
- * W: pre-indexing flag
49
- * S: sign for imm9.
50
- */
51
-static void disas_ldst_pac(DisasContext *s, uint32_t insn,
52
- int size, int rt, bool is_vector)
53
+static bool trans_LDRA(DisasContext *s, arg_LDRA *a)
54
{
55
- int rn = extract32(insn, 5, 5);
56
- bool is_wback = extract32(insn, 11, 1);
57
- bool use_key_a = !extract32(insn, 23, 1);
58
- int offset;
59
TCGv_i64 clean_addr, dirty_addr, tcg_rt;
60
MemOp memop;
61
62
- if (size != 3 || is_vector || !dc_isar_feature(aa64_pauth, s)) {
63
- unallocated_encoding(s);
64
- return;
65
+ /* Load with pointer authentication */
66
+ if (!dc_isar_feature(aa64_pauth, s)) {
67
+ return false;
55
}
68
}
56
switch (offset) {
69
57
- case 0x40:
70
- if (rn == 31) {
58
+ case RX_STATUS_FIFO_PORT:
71
+ if (a->rn == 31) {
59
return rx_status_fifo_pop(s);
72
gen_check_sp_alignment(s);
60
- case 0x44:
73
}
61
+ case RX_STATUS_FIFO_PEEK:
74
- dirty_addr = read_cpu_reg_sp(s, rn, 1);
62
return s->rx_status_fifo[s->rx_status_fifo_head];
75
+ dirty_addr = read_cpu_reg_sp(s, a->rn, 1);
63
- case 0x48:
76
64
+ case TX_STATUS_FIFO_PORT:
77
if (s->pauth_active) {
65
return tx_status_fifo_pop(s);
78
- if (use_key_a) {
66
- case 0x4c:
79
+ if (!a->m) {
67
+ case TX_STATUS_FIFO_PEEK:
80
gen_helper_autda(dirty_addr, cpu_env, dirty_addr,
68
return s->tx_status_fifo[s->tx_status_fifo_head];
81
tcg_constant_i64(0));
69
case CSR_ID_REV:
82
} else {
70
return 0x01180001;
83
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_pac(DisasContext *s, uint32_t insn,
84
}
85
}
86
87
- /* Form the 10-bit signed, scaled offset. */
88
- offset = (extract32(insn, 22, 1) << 9) | extract32(insn, 12, 9);
89
- offset = sextract32(offset << size, 0, 10 + size);
90
- tcg_gen_addi_i64(dirty_addr, dirty_addr, offset);
91
+ tcg_gen_addi_i64(dirty_addr, dirty_addr, a->imm);
92
93
- memop = finalize_memop(s, size);
94
+ memop = finalize_memop(s, MO_64);
95
96
/* Note that "clean" and "dirty" here refer to TBI not PAC. */
97
clean_addr = gen_mte_check1(s, dirty_addr, false,
98
- is_wback || rn != 31, memop);
99
+ a->w || a->rn != 31, memop);
100
101
- tcg_rt = cpu_reg(s, rt);
102
+ tcg_rt = cpu_reg(s, a->rt);
103
do_gpr_ld(s, tcg_rt, clean_addr, memop,
104
- /* extend */ false, /* iss_valid */ !is_wback,
105
- /* iss_srt */ rt, /* iss_sf */ true, /* iss_ar */ false);
106
+ /* extend */ false, /* iss_valid */ !a->w,
107
+ /* iss_srt */ a->rt, /* iss_sf */ true, /* iss_ar */ false);
108
109
- if (is_wback) {
110
- tcg_gen_mov_i64(cpu_reg_sp(s, rn), dirty_addr);
111
+ if (a->w) {
112
+ tcg_gen_mov_i64(cpu_reg_sp(s, a->rn), dirty_addr);
113
}
114
+ return true;
115
}
116
117
/*
118
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_ldapr_stlr(DisasContext *s, uint32_t insn)
119
}
120
}
121
122
-/* Load/store register (all forms) */
123
-static void disas_ldst_reg(DisasContext *s, uint32_t insn)
124
-{
125
- int rt = extract32(insn, 0, 5);
126
- bool is_vector = extract32(insn, 26, 1);
127
- int size = extract32(insn, 30, 2);
128
-
129
- switch (extract32(insn, 24, 2)) {
130
- case 0:
131
- if (extract32(insn, 21, 1) == 0) {
132
- break;
133
- }
134
- switch (extract32(insn, 10, 2)) {
135
- case 0:
136
- case 2:
137
- break;
138
- default:
139
- disas_ldst_pac(s, insn, size, rt, is_vector);
140
- return;
141
- }
142
- break;
143
- }
144
- unallocated_encoding(s);
145
-}
146
-
147
/* AdvSIMD load/store multiple structures
148
*
149
* 31 30 29 23 22 21 16 15 12 11 10 9 5 4 0
150
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_tag(DisasContext *s, uint32_t insn)
151
static void disas_ldst(DisasContext *s, uint32_t insn)
152
{
153
switch (extract32(insn, 24, 6)) {
154
- case 0x38: case 0x39:
155
- case 0x3c: case 0x3d: /* Load/store register (all forms) */
156
- disas_ldst_reg(s, insn);
157
- break;
158
case 0x0c: /* AdvSIMD load/store multiple structures */
159
disas_ldst_multiple_struct(s, insn);
160
break;
71
--
161
--
72
2.20.1
162
2.34.1
73
163
74
164
diff view generated by jsdifflib
1
From: Hao Wu <wuhaotsh@google.com>
1
Convert the instructions in the LDAPR/STLR (unscaled immediate)
2
group to decodetree.
2
3
3
This patch makes NPCM7XX Timer to use a the timer clock generated by the
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
CLK module instead of the magic number TIMER_REF_HZ.
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20230602155223.2040685-18-peter.maydell@linaro.org
7
---
8
target/arm/tcg/a64.decode | 10 +++
9
target/arm/tcg/translate-a64.c | 132 ++++++++++++---------------------
10
2 files changed, 56 insertions(+), 86 deletions(-)
5
11
6
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
12
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
7
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
8
Signed-off-by: Hao Wu <wuhaotsh@google.com>
9
Message-id: 20210108190945.949196-3-wuhaotsh@google.com
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
13
include/hw/misc/npcm7xx_clk.h | 6 -----
14
include/hw/timer/npcm7xx_timer.h | 1 +
15
hw/arm/npcm7xx.c | 5 ++++
16
hw/timer/npcm7xx_timer.c | 39 +++++++++++++++-----------------
17
4 files changed, 24 insertions(+), 27 deletions(-)
18
19
diff --git a/include/hw/misc/npcm7xx_clk.h b/include/hw/misc/npcm7xx_clk.h
20
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
21
--- a/include/hw/misc/npcm7xx_clk.h
14
--- a/target/arm/tcg/a64.decode
22
+++ b/include/hw/misc/npcm7xx_clk.h
15
+++ b/target/arm/tcg/a64.decode
23
@@ -XXX,XX +XXX,XX @@
16
@@ -XXX,XX +XXX,XX @@ LDAPR sz:2 111 0 00 1 0 1 11111 1100 00 rn:5 rt:5
24
#include "hw/clock.h"
17
%ldra_imm 22:s1 12:9 !function=times_2
25
#include "hw/sysbus.h"
18
19
LDRA 11 111 0 00 m:1 . 1 ......... w:1 1 rn:5 rt:5 imm=%ldra_imm
20
+
21
+&ldapr_stlr_i rn rt imm sz sign ext
22
+@ldapr_stlr_i .. ...... .. . imm:9 .. rn:5 rt:5 &ldapr_stlr_i
23
+STLR_i sz:2 011001 00 0 ......... 00 ..... ..... @ldapr_stlr_i sign=0 ext=0
24
+LDAPR_i sz:2 011001 01 0 ......... 00 ..... ..... @ldapr_stlr_i sign=0 ext=0
25
+LDAPR_i 00 011001 10 0 ......... 00 ..... ..... @ldapr_stlr_i sign=1 ext=0 sz=0
26
+LDAPR_i 01 011001 10 0 ......... 00 ..... ..... @ldapr_stlr_i sign=1 ext=0 sz=1
27
+LDAPR_i 10 011001 10 0 ......... 00 ..... ..... @ldapr_stlr_i sign=1 ext=0 sz=2
28
+LDAPR_i 00 011001 11 0 ......... 00 ..... ..... @ldapr_stlr_i sign=1 ext=1 sz=0
29
+LDAPR_i 01 011001 11 0 ......... 00 ..... ..... @ldapr_stlr_i sign=1 ext=1 sz=1
30
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/target/arm/tcg/translate-a64.c
33
+++ b/target/arm/tcg/translate-a64.c
34
@@ -XXX,XX +XXX,XX @@ static void gen_compare_and_swap_pair(DisasContext *s, int rs, int rt,
35
}
36
}
37
38
-/* Update the Sixty-Four bit (SF) registersize. This logic is derived
39
+/*
40
+ * Compute the ISS.SF bit for syndrome information if an exception
41
+ * is taken on a load or store. This indicates whether the instruction
42
+ * is accessing a 32-bit or 64-bit register. This logic is derived
43
* from the ARMv8 specs for LDR (Shared decode for all encodings).
44
*/
45
-static bool disas_ldst_compute_iss_sf(int size, bool is_signed, int opc)
46
-{
47
- int opc0 = extract32(opc, 0, 1);
48
- int regsize;
49
-
50
- if (is_signed) {
51
- regsize = opc0 ? 32 : 64;
52
- } else {
53
- regsize = size == 3 ? 64 : 32;
54
- }
55
- return regsize == 64;
56
-}
57
-
58
static bool ldst_iss_sf(int size, bool sign, bool ext)
59
{
60
61
@@ -XXX,XX +XXX,XX @@ static bool trans_LDRA(DisasContext *s, arg_LDRA *a)
62
return true;
63
}
26
64
27
-/*
65
-/*
28
- * The reference clock frequency for the timer modules, and the SECCNT and
66
- * LDAPR/STLR (unscaled immediate)
29
- * CNTR25M registers in this module, is always 25 MHz.
67
- *
68
- * 31 30 24 22 21 12 10 5 0
69
- * +------+-------------+-----+---+--------+-----+----+-----+
70
- * | size | 0 1 1 0 0 1 | opc | 0 | imm9 | 0 0 | Rn | Rt |
71
- * +------+-------------+-----+---+--------+-----+----+-----+
72
- *
73
- * Rt: source or destination register
74
- * Rn: base register
75
- * imm9: unscaled immediate offset
76
- * opc: 00: STLUR*, 01/10/11: various LDAPUR*
77
- * size: size of load/store
30
- */
78
- */
31
-#define NPCM7XX_TIMER_REF_HZ (25000000)
79
-static void disas_ldst_ldapr_stlr(DisasContext *s, uint32_t insn)
32
-
80
+static bool trans_LDAPR_i(DisasContext *s, arg_ldapr_stlr_i *a)
33
/*
34
* Number of registers in our device state structure. Don't change this without
35
* incrementing the version_id in the vmstate.
36
diff --git a/include/hw/timer/npcm7xx_timer.h b/include/hw/timer/npcm7xx_timer.h
37
index XXXXXXX..XXXXXXX 100644
38
--- a/include/hw/timer/npcm7xx_timer.h
39
+++ b/include/hw/timer/npcm7xx_timer.h
40
@@ -XXX,XX +XXX,XX @@ struct NPCM7xxTimerCtrlState {
41
42
uint32_t tisr;
43
44
+ Clock *clock;
45
NPCM7xxTimer timer[NPCM7XX_TIMERS_PER_CTRL];
46
NPCM7xxWatchdogTimer watchdog_timer;
47
};
48
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
49
index XXXXXXX..XXXXXXX 100644
50
--- a/hw/arm/npcm7xx.c
51
+++ b/hw/arm/npcm7xx.c
52
@@ -XXX,XX +XXX,XX @@
53
#include "hw/char/serial.h"
54
#include "hw/loader.h"
55
#include "hw/misc/unimp.h"
56
+#include "hw/qdev-clock.h"
57
#include "hw/qdev-properties.h"
58
#include "qapi/error.h"
59
#include "qemu/units.h"
60
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
61
int first_irq;
62
int j;
63
64
+ /* Connect the timer clock. */
65
+ qdev_connect_clock_in(DEVICE(&s->tim[i]), "clock", qdev_get_clock_out(
66
+ DEVICE(&s->clk), "timer-clock"));
67
+
68
sysbus_realize(sbd, &error_abort);
69
sysbus_mmio_map(sbd, 0, npcm7xx_tim_addr[i]);
70
71
diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c
72
index XXXXXXX..XXXXXXX 100644
73
--- a/hw/timer/npcm7xx_timer.c
74
+++ b/hw/timer/npcm7xx_timer.c
75
@@ -XXX,XX +XXX,XX @@
76
#include "qemu/osdep.h"
77
78
#include "hw/irq.h"
79
+#include "hw/qdev-clock.h"
80
#include "hw/qdev-properties.h"
81
-#include "hw/misc/npcm7xx_clk.h"
82
#include "hw/timer/npcm7xx_timer.h"
83
#include "migration/vmstate.h"
84
#include "qemu/bitops.h"
85
@@ -XXX,XX +XXX,XX @@ static uint32_t npcm7xx_tcsr_prescaler(uint32_t tcsr)
86
/* Convert a timer cycle count to a time interval in nanoseconds. */
87
static int64_t npcm7xx_timer_count_to_ns(NPCM7xxTimer *t, uint32_t count)
88
{
81
{
89
- int64_t ns = count;
82
- int rt = extract32(insn, 0, 5);
90
+ int64_t ticks = count;
83
- int rn = extract32(insn, 5, 5);
91
84
- int offset = sextract32(insn, 12, 9);
92
- ns *= NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ;
85
- int opc = extract32(insn, 22, 2);
93
- ns *= npcm7xx_tcsr_prescaler(t->tcsr);
86
- int size = extract32(insn, 30, 2);
94
+ ticks *= npcm7xx_tcsr_prescaler(t->tcsr);
87
TCGv_i64 clean_addr, dirty_addr;
95
88
- bool is_store = false;
96
- return ns;
89
- bool extend = false;
97
+ return clock_ticks_to_ns(t->ctrl->clock, ticks);
90
- bool iss_sf;
91
- MemOp mop = size;
92
+ MemOp mop = a->sz | (a->sign ? MO_SIGN : 0);
93
+ bool iss_sf = ldst_iss_sf(a->sz, a->sign, a->ext);
94
95
if (!dc_isar_feature(aa64_rcpc_8_4, s)) {
96
- unallocated_encoding(s);
97
- return;
98
+ return false;
99
}
100
101
- switch (opc) {
102
- case 0: /* STLURB */
103
- is_store = true;
104
- break;
105
- case 1: /* LDAPUR* */
106
- break;
107
- case 2: /* LDAPURS* 64-bit variant */
108
- if (size == 3) {
109
- unallocated_encoding(s);
110
- return;
111
- }
112
- mop |= MO_SIGN;
113
- break;
114
- case 3: /* LDAPURS* 32-bit variant */
115
- if (size > 1) {
116
- unallocated_encoding(s);
117
- return;
118
- }
119
- mop |= MO_SIGN;
120
- extend = true; /* zero-extend 32->64 after signed load */
121
- break;
122
- default:
123
- g_assert_not_reached();
124
- }
125
-
126
- iss_sf = disas_ldst_compute_iss_sf(size, (mop & MO_SIGN) != 0, opc);
127
-
128
- if (rn == 31) {
129
+ if (a->rn == 31) {
130
gen_check_sp_alignment(s);
131
}
132
133
- mop = check_ordered_align(s, rn, offset, is_store, mop);
134
-
135
- dirty_addr = read_cpu_reg_sp(s, rn, 1);
136
- tcg_gen_addi_i64(dirty_addr, dirty_addr, offset);
137
+ mop = check_ordered_align(s, a->rn, a->imm, false, mop);
138
+ dirty_addr = read_cpu_reg_sp(s, a->rn, 1);
139
+ tcg_gen_addi_i64(dirty_addr, dirty_addr, a->imm);
140
clean_addr = clean_data_tbi(s, dirty_addr);
141
142
- if (is_store) {
143
- /* Store-Release semantics */
144
- tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
145
- do_gpr_st(s, cpu_reg(s, rt), clean_addr, mop, true, rt, iss_sf, true);
146
- } else {
147
- /*
148
- * Load-AcquirePC semantics; we implement as the slightly more
149
- * restrictive Load-Acquire.
150
- */
151
- do_gpr_ld(s, cpu_reg(s, rt), clean_addr, mop,
152
- extend, true, rt, iss_sf, true);
153
- tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
154
+ /*
155
+ * Load-AcquirePC semantics; we implement as the slightly more
156
+ * restrictive Load-Acquire.
157
+ */
158
+ do_gpr_ld(s, cpu_reg(s, a->rt), clean_addr, mop, a->ext, true,
159
+ a->rt, iss_sf, true);
160
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
161
+ return true;
162
+}
163
+
164
+static bool trans_STLR_i(DisasContext *s, arg_ldapr_stlr_i *a)
165
+{
166
+ TCGv_i64 clean_addr, dirty_addr;
167
+ MemOp mop = a->sz;
168
+ bool iss_sf = ldst_iss_sf(a->sz, a->sign, a->ext);
169
+
170
+ if (!dc_isar_feature(aa64_rcpc_8_4, s)) {
171
+ return false;
172
}
173
+
174
+ /* TODO: ARMv8.4-LSE SCTLR.nAA */
175
+
176
+ if (a->rn == 31) {
177
+ gen_check_sp_alignment(s);
178
+ }
179
+
180
+ mop = check_ordered_align(s, a->rn, a->imm, true, mop);
181
+ dirty_addr = read_cpu_reg_sp(s, a->rn, 1);
182
+ tcg_gen_addi_i64(dirty_addr, dirty_addr, a->imm);
183
+ clean_addr = clean_data_tbi(s, dirty_addr);
184
+
185
+ /* Store-Release semantics */
186
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
187
+ do_gpr_st(s, cpu_reg(s, a->rt), clean_addr, mop, true, a->rt, iss_sf, true);
188
+ return true;
98
}
189
}
99
190
100
/* Convert a time interval in nanoseconds to a timer cycle count. */
191
/* AdvSIMD load/store multiple structures
101
static uint32_t npcm7xx_timer_ns_to_count(NPCM7xxTimer *t, int64_t ns)
192
@@ -XXX,XX +XXX,XX @@ static void disas_ldst(DisasContext *s, uint32_t insn)
102
{
193
case 0x19:
103
- int64_t count;
194
if (extract32(insn, 21, 1) != 0) {
104
-
195
disas_ldst_tag(s, insn);
105
- count = ns / (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ);
196
- } else if (extract32(insn, 10, 2) == 0) {
106
- count /= npcm7xx_tcsr_prescaler(t->tcsr);
197
- disas_ldst_ldapr_stlr(s, insn);
107
-
198
} else {
108
- return count;
199
unallocated_encoding(s);
109
+ return ns / clock_ticks_to_ns(t->ctrl->clock,
200
}
110
+ npcm7xx_tcsr_prescaler(t->tcsr));
111
}
112
113
static uint32_t npcm7xx_watchdog_timer_prescaler(const NPCM7xxWatchdogTimer *t)
114
@@ -XXX,XX +XXX,XX @@ static uint32_t npcm7xx_watchdog_timer_prescaler(const NPCM7xxWatchdogTimer *t)
115
static void npcm7xx_watchdog_timer_reset_cycles(NPCM7xxWatchdogTimer *t,
116
int64_t cycles)
117
{
118
- uint32_t prescaler = npcm7xx_watchdog_timer_prescaler(t);
119
- int64_t ns = (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ) * cycles;
120
+ int64_t ticks = cycles * npcm7xx_watchdog_timer_prescaler(t);
121
+ int64_t ns = clock_ticks_to_ns(t->ctrl->clock, ticks);
122
123
/*
124
* The reset function always clears the current timer. The caller of the
125
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_watchdog_timer_reset_cycles(NPCM7xxWatchdogTimer *t,
126
*/
127
npcm7xx_timer_clear(&t->base_timer);
128
129
- ns *= prescaler;
130
t->base_timer.remaining_ns = ns;
131
}
132
133
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_hold_reset(Object *obj)
134
qemu_irq_lower(s->watchdog_timer.irq);
135
}
136
137
-static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
138
+static void npcm7xx_timer_init(Object *obj)
139
{
140
- NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(dev);
141
- SysBusDevice *sbd = &s->parent;
142
+ NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(obj);
143
+ DeviceState *dev = DEVICE(obj);
144
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
145
int i;
146
NPCM7xxWatchdogTimer *w;
147
148
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
149
npcm7xx_watchdog_timer_expired, w);
150
sysbus_init_irq(sbd, &w->irq);
151
152
- memory_region_init_io(&s->iomem, OBJECT(s), &npcm7xx_timer_ops, s,
153
+ memory_region_init_io(&s->iomem, obj, &npcm7xx_timer_ops, s,
154
TYPE_NPCM7XX_TIMER, 4 * KiB);
155
sysbus_init_mmio(sbd, &s->iomem);
156
qdev_init_gpio_out_named(dev, &w->reset_signal,
157
NPCM7XX_WATCHDOG_RESET_GPIO_OUT, 1);
158
+ s->clock = qdev_init_clock_in(dev, "clock", NULL, NULL);
159
}
160
161
static const VMStateDescription vmstate_npcm7xx_base_timer = {
162
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_npcm7xx_watchdog_timer = {
163
164
static const VMStateDescription vmstate_npcm7xx_timer_ctrl = {
165
.name = "npcm7xx-timer-ctrl",
166
- .version_id = 1,
167
- .minimum_version_id = 1,
168
+ .version_id = 2,
169
+ .minimum_version_id = 2,
170
.fields = (VMStateField[]) {
171
VMSTATE_UINT32(tisr, NPCM7xxTimerCtrlState),
172
+ VMSTATE_CLOCK(clock, NPCM7xxTimerCtrlState),
173
VMSTATE_STRUCT_ARRAY(timer, NPCM7xxTimerCtrlState,
174
NPCM7XX_TIMERS_PER_CTRL, 0, vmstate_npcm7xx_timer,
175
NPCM7xxTimer),
176
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_class_init(ObjectClass *klass, void *data)
177
QEMU_BUILD_BUG_ON(NPCM7XX_TIMER_REGS_END > NPCM7XX_TIMER_NR_REGS);
178
179
dc->desc = "NPCM7xx Timer Controller";
180
- dc->realize = npcm7xx_timer_realize;
181
dc->vmsd = &vmstate_npcm7xx_timer_ctrl;
182
rc->phases.enter = npcm7xx_timer_enter_reset;
183
rc->phases.hold = npcm7xx_timer_hold_reset;
184
@@ -XXX,XX +XXX,XX @@ static const TypeInfo npcm7xx_timer_info = {
185
.parent = TYPE_SYS_BUS_DEVICE,
186
.instance_size = sizeof(NPCM7xxTimerCtrlState),
187
.class_init = npcm7xx_timer_class_init,
188
+ .instance_init = npcm7xx_timer_init,
189
};
190
191
static void npcm7xx_timer_register_type(void)
192
--
201
--
193
2.20.1
202
2.34.1
194
195
diff view generated by jsdifflib
1
When we first converted our documentation to Sphinx, we split it into
1
Convert the instructions in the ASIMD load/store multiple structures
2
multiple manuals (system, interop, tools, etc), which are all built
2
instruction classes to decodetree.
3
separately. The primary driver for this was wanting to be able to
4
avoid shipping the 'devel' manual to end-users. However, this is
5
working against the grain of the way Sphinx wants to be used and
6
causes some annoyances:
7
* Cross-references between documents become much harder or
8
possibly impossible
9
* There is no single index to the whole documentation
10
* Within one manual there's no links or table-of-contents info
11
that lets you easily navigate to the others
12
* The devel manual doesn't get published on the QEMU website
13
(it would be nice to able to refer to it there)
14
15
Merely hiding our developer documentation from end users seems like
16
it's not enough benefit for these costs. Combine all the
17
documentation into a single manual (the same way that the readthedocs
18
site builds it) and install the whole thing. The previous manual
19
divisions remain as the new top level sections in the manual.
20
21
* The per-manual conf.py files are no longer needed
22
* The man_pages[] specifications previously in each per-manual
23
conf.py move to the top level conf.py
24
* docs/meson.build logic is simplified as we now only need to run
25
Sphinx once for the HTML and then once for the manpages5B
26
* The old index.html.in that produced the top-level page with
27
links to each manual is no longer needed
28
29
Unfortunately this means that we now have to build the HTML
30
documentation into docs/manual in the build tree rather than directly
31
into docs/; otherwise it is too awkward to ensure we install only the
32
built manual and not also the dependency info, stamp file, etc. The
33
manual still ends up in the same place in the final installed
34
directory, but anybody who was consulting documentation from within
35
the build tree will have to adjust where they're looking.
36
3
37
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
38
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
39
Message-id: 20210108161416.21129-3-peter.maydell@linaro.org
6
Message-id: 20230602155223.2040685-19-peter.maydell@linaro.org
40
---
7
---
41
docs/conf.py | 46 ++++++++++++++++++++++++++++++-
8
target/arm/tcg/a64.decode | 20 +++
42
docs/devel/conf.py | 15 -----------
9
target/arm/tcg/translate-a64.c | 222 ++++++++++++++++-----------------
43
docs/index.html.in | 17 ------------
10
2 files changed, 131 insertions(+), 111 deletions(-)
44
docs/interop/conf.py | 28 -------------------
45
docs/meson.build | 64 +++++++++++++++++---------------------------
46
docs/specs/conf.py | 16 -----------
47
docs/system/conf.py | 28 -------------------
48
docs/tools/conf.py | 37 -------------------------
49
docs/user/conf.py | 15 -----------
50
9 files changed, 70 insertions(+), 196 deletions(-)
51
delete mode 100644 docs/devel/conf.py
52
delete mode 100644 docs/index.html.in
53
delete mode 100644 docs/interop/conf.py
54
delete mode 100644 docs/specs/conf.py
55
delete mode 100644 docs/system/conf.py
56
delete mode 100644 docs/tools/conf.py
57
delete mode 100644 docs/user/conf.py
58
11
59
diff --git a/docs/conf.py b/docs/conf.py
12
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
60
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
61
--- a/docs/conf.py
14
--- a/target/arm/tcg/a64.decode
62
+++ b/docs/conf.py
15
+++ b/target/arm/tcg/a64.decode
63
@@ -XXX,XX +XXX,XX @@ latex_documents = [
16
@@ -XXX,XX +XXX,XX @@ LDAPR_i 01 011001 10 0 ......... 00 ..... ..... @ldapr_stlr_i sign=1 ext
64
17
LDAPR_i 10 011001 10 0 ......... 00 ..... ..... @ldapr_stlr_i sign=1 ext=0 sz=2
65
# -- Options for manual page output ---------------------------------------
18
LDAPR_i 00 011001 11 0 ......... 00 ..... ..... @ldapr_stlr_i sign=1 ext=1 sz=0
66
# Individual manual/conf.py can override this to create man pages
19
LDAPR_i 01 011001 11 0 ......... 00 ..... ..... @ldapr_stlr_i sign=1 ext=1 sz=1
67
-man_pages = []
20
+
68
+man_pages = [
21
+# Load/store multiple structures
69
+ ('interop/qemu-ga', 'qemu-ga',
22
+# The 4-bit opcode in [15:12] encodes repeat count and structure elements
70
+ 'QEMU Guest Agent',
23
+&ldst_mult rm rn rt sz q p rpt selem
71
+ ['Michael Roth <mdroth@linux.vnet.ibm.com>'], 8),
24
+@ldst_mult . q:1 ...... p:1 . . rm:5 .... sz:2 rn:5 rt:5 &ldst_mult
72
+ ('interop/qemu-ga-ref', 'qemu-ga-ref',
25
+ST_mult 0 . 001100 . 0 0 ..... 0000 .. ..... ..... @ldst_mult rpt=1 selem=4
73
+ 'QEMU Guest Agent Protocol Reference',
26
+ST_mult 0 . 001100 . 0 0 ..... 0010 .. ..... ..... @ldst_mult rpt=4 selem=1
74
+ [], 7),
27
+ST_mult 0 . 001100 . 0 0 ..... 0100 .. ..... ..... @ldst_mult rpt=1 selem=3
75
+ ('interop/qemu-qmp-ref', 'qemu-qmp-ref',
28
+ST_mult 0 . 001100 . 0 0 ..... 0110 .. ..... ..... @ldst_mult rpt=3 selem=1
76
+ 'QEMU QMP Reference Manual',
29
+ST_mult 0 . 001100 . 0 0 ..... 0111 .. ..... ..... @ldst_mult rpt=1 selem=1
77
+ [], 7),
30
+ST_mult 0 . 001100 . 0 0 ..... 1000 .. ..... ..... @ldst_mult rpt=1 selem=2
78
+ ('interop/qemu-storage-daemon-qmp-ref', 'qemu-storage-daemon-qmp-ref',
31
+ST_mult 0 . 001100 . 0 0 ..... 1010 .. ..... ..... @ldst_mult rpt=2 selem=1
79
+ 'QEMU Storage Daemon QMP Reference Manual',
32
+
80
+ [], 7),
33
+LD_mult 0 . 001100 . 1 0 ..... 0000 .. ..... ..... @ldst_mult rpt=1 selem=4
81
+ ('system/qemu-manpage', 'qemu',
34
+LD_mult 0 . 001100 . 1 0 ..... 0010 .. ..... ..... @ldst_mult rpt=4 selem=1
82
+ 'QEMU User Documentation',
35
+LD_mult 0 . 001100 . 1 0 ..... 0100 .. ..... ..... @ldst_mult rpt=1 selem=3
83
+ ['Fabrice Bellard'], 1),
36
+LD_mult 0 . 001100 . 1 0 ..... 0110 .. ..... ..... @ldst_mult rpt=3 selem=1
84
+ ('system/qemu-block-drivers', 'qemu-block-drivers',
37
+LD_mult 0 . 001100 . 1 0 ..... 0111 .. ..... ..... @ldst_mult rpt=1 selem=1
85
+ 'QEMU block drivers reference',
38
+LD_mult 0 . 001100 . 1 0 ..... 1000 .. ..... ..... @ldst_mult rpt=1 selem=2
86
+ ['Fabrice Bellard and the QEMU Project developers'], 7),
39
+LD_mult 0 . 001100 . 1 0 ..... 1010 .. ..... ..... @ldst_mult rpt=2 selem=1
87
+ ('system/qemu-cpu-models', 'qemu-cpu-models',
40
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
88
+ 'QEMU CPU Models',
41
index XXXXXXX..XXXXXXX 100644
89
+ ['The QEMU Project developers'], 7),
42
--- a/target/arm/tcg/translate-a64.c
90
+ ('tools/qemu-img', 'qemu-img',
43
+++ b/target/arm/tcg/translate-a64.c
91
+ 'QEMU disk image utility',
44
@@ -XXX,XX +XXX,XX @@ static bool trans_STLR_i(DisasContext *s, arg_ldapr_stlr_i *a)
92
+ ['Fabrice Bellard'], 1),
45
return true;
93
+ ('tools/qemu-nbd', 'qemu-nbd',
46
}
94
+ 'QEMU Disk Network Block Device Server',
47
95
+ ['Anthony Liguori <anthony@codemonkey.ws>'], 8),
48
-/* AdvSIMD load/store multiple structures
96
+ ('tools/qemu-pr-helper', 'qemu-pr-helper',
49
- *
97
+ 'QEMU persistent reservation helper',
50
- * 31 30 29 23 22 21 16 15 12 11 10 9 5 4 0
98
+ [], 8),
51
- * +---+---+---------------+---+-------------+--------+------+------+------+
99
+ ('tools/qemu-storage-daemon', 'qemu-storage-daemon',
52
- * | 0 | Q | 0 0 1 1 0 0 0 | L | 0 0 0 0 0 0 | opcode | size | Rn | Rt |
100
+ 'QEMU storage daemon',
53
- * +---+---+---------------+---+-------------+--------+------+------+------+
101
+ [], 1),
54
- *
102
+ ('tools/qemu-trace-stap', 'qemu-trace-stap',
55
- * AdvSIMD load/store multiple structures (post-indexed)
103
+ 'QEMU SystemTap trace tool',
56
- *
104
+ [], 1),
57
- * 31 30 29 23 22 21 20 16 15 12 11 10 9 5 4 0
105
+ ('tools/virtfs-proxy-helper', 'virtfs-proxy-helper',
58
- * +---+---+---------------+---+---+---------+--------+------+------+------+
106
+ 'QEMU 9p virtfs proxy filesystem helper',
59
- * | 0 | Q | 0 0 1 1 0 0 1 | L | 0 | Rm | opcode | size | Rn | Rt |
107
+ ['M. Mohan Kumar'], 1),
60
- * +---+---+---------------+---+---+---------+--------+------+------+------+
108
+ ('tools/virtiofsd', 'virtiofsd',
61
- *
109
+ 'QEMU virtio-fs shared file system daemon',
62
- * Rt: first (or only) SIMD&FP register to be transferred
110
+ ['Stefan Hajnoczi <stefanha@redhat.com>',
63
- * Rn: base address or SP
111
+ 'Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>'], 1),
64
- * Rm (post-index only): post-index register (when !31) or size dependent #imm
112
+]
65
- */
113
66
-static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn)
114
# -- Options for Texinfo output -------------------------------------------
67
+static bool trans_LD_mult(DisasContext *s, arg_ldst_mult *a)
115
68
{
116
diff --git a/docs/devel/conf.py b/docs/devel/conf.py
69
- int rt = extract32(insn, 0, 5);
117
deleted file mode 100644
70
- int rn = extract32(insn, 5, 5);
118
index XXXXXXX..XXXXXXX
71
- int rm = extract32(insn, 16, 5);
119
--- a/docs/devel/conf.py
72
- int size = extract32(insn, 10, 2);
120
+++ /dev/null
73
- int opcode = extract32(insn, 12, 4);
121
@@ -XXX,XX +XXX,XX @@
74
- bool is_store = !extract32(insn, 22, 1);
122
-# -*- coding: utf-8 -*-
75
- bool is_postidx = extract32(insn, 23, 1);
123
-#
76
- bool is_q = extract32(insn, 30, 1);
124
-# QEMU documentation build configuration file for the 'devel' manual.
77
TCGv_i64 clean_addr, tcg_rn, tcg_ebytes;
125
-#
78
MemOp endian, align, mop;
126
-# This includes the top level conf file and then makes any necessary tweaks.
79
127
-import sys
80
int total; /* total bytes */
128
-import os
81
int elements; /* elements per vector */
82
- int rpt; /* num iterations */
83
- int selem; /* structure elements */
84
int r;
85
+ int size = a->sz;
86
87
- if (extract32(insn, 31, 1) || extract32(insn, 21, 1)) {
88
- unallocated_encoding(s);
89
- return;
90
+ if (!a->p && a->rm != 0) {
91
+ /* For non-postindexed accesses the Rm field must be 0 */
92
+ return false;
93
}
129
-
94
-
130
-qemu_docdir = os.path.abspath("..")
95
- if (!is_postidx && rm != 0) {
131
-parent_config = os.path.join(qemu_docdir, "conf.py")
96
- unallocated_encoding(s);
132
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
97
- return;
98
+ if (size == 3 && !a->q && a->selem != 1) {
99
+ return false;
100
}
133
-
101
-
134
-# This slightly misuses the 'description', but is the best way to get
102
- /* From the shared decode logic */
135
-# the manual title to appear in the sidebar.
103
- switch (opcode) {
136
-html_theme_options['description'] = u'Developer''s Guide'
104
- case 0x0:
137
diff --git a/docs/index.html.in b/docs/index.html.in
105
- rpt = 1;
138
deleted file mode 100644
106
- selem = 4;
139
index XXXXXXX..XXXXXXX
107
- break;
140
--- a/docs/index.html.in
108
- case 0x2:
141
+++ /dev/null
109
- rpt = 4;
142
@@ -XXX,XX +XXX,XX @@
110
- selem = 1;
143
-<!DOCTYPE html>
111
- break;
144
-<html lang="en">
112
- case 0x4:
145
- <head>
113
- rpt = 1;
146
- <meta charset="UTF-8">
114
- selem = 3;
147
- <title>QEMU @VERSION@ Documentation</title>
115
- break;
148
- </head>
116
- case 0x6:
149
- <body>
117
- rpt = 3;
150
- <h1>QEMU @VERSION@ Documentation</h1>
118
- selem = 1;
151
- <ul>
119
- break;
152
- <li><a href="system/index.html">System Emulation User's Guide</a></li>
120
- case 0x7:
153
- <li><a href="user/index.html">User Mode Emulation User's Guide</a></li>
121
- rpt = 1;
154
- <li><a href="tools/index.html">Tools Guide</a></li>
122
- selem = 1;
155
- <li><a href="interop/index.html">System Emulation Management and Interoperability Guide</a></li>
123
- break;
156
- <li><a href="specs/index.html">System Emulation Guest Hardware Specifications</a></li>
124
- case 0x8:
157
- </ul>
125
- rpt = 1;
158
- </body>
126
- selem = 2;
159
-</html>
127
- break;
160
diff --git a/docs/interop/conf.py b/docs/interop/conf.py
128
- case 0xa:
161
deleted file mode 100644
129
- rpt = 2;
162
index XXXXXXX..XXXXXXX
130
- selem = 1;
163
--- a/docs/interop/conf.py
131
- break;
164
+++ /dev/null
132
- default:
165
@@ -XXX,XX +XXX,XX @@
133
- unallocated_encoding(s);
166
-# -*- coding: utf-8 -*-
134
- return;
167
-#
135
- }
168
-# QEMU documentation build configuration file for the 'interop' manual.
169
-#
170
-# This includes the top level conf file and then makes any necessary tweaks.
171
-import sys
172
-import os
173
-
136
-
174
-qemu_docdir = os.path.abspath("..")
137
- if (size == 3 && !is_q && selem != 1) {
175
-parent_config = os.path.join(qemu_docdir, "conf.py")
138
- /* reserved */
176
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
139
- unallocated_encoding(s);
140
- return;
141
- }
177
-
142
-
178
-# This slightly misuses the 'description', but is the best way to get
143
if (!fp_access_check(s)) {
179
-# the manual title to appear in the sidebar.
144
- return;
180
-html_theme_options['description'] = u'System Emulation Management and Interoperability Guide'
145
+ return true;
181
-
146
}
182
-# One entry per manual page. List of tuples
147
183
-# (source start file, name, description, authors, manual section).
148
- if (rn == 31) {
184
-man_pages = [
149
+ if (a->rn == 31) {
185
- ('qemu-ga', 'qemu-ga', u'QEMU Guest Agent',
150
gen_check_sp_alignment(s);
186
- ['Michael Roth <mdroth@linux.vnet.ibm.com>'], 8),
151
}
187
- ('qemu-ga-ref', 'qemu-ga-ref', 'QEMU Guest Agent Protocol Reference',
152
188
- [], 7),
153
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn)
189
- ('qemu-qmp-ref', 'qemu-qmp-ref', 'QEMU QMP Reference Manual',
154
endian = MO_LE;
190
- [], 7),
155
}
191
- ('qemu-storage-daemon-qmp-ref', 'qemu-storage-daemon-qmp-ref',
156
192
- 'QEMU Storage Daemon QMP Reference Manual', [], 7),
157
- total = rpt * selem * (is_q ? 16 : 8);
193
-]
158
- tcg_rn = cpu_reg_sp(s, rn);
194
diff --git a/docs/meson.build b/docs/meson.build
159
+ total = a->rpt * a->selem * (a->q ? 16 : 8);
195
index XXXXXXX..XXXXXXX 100644
160
+ tcg_rn = cpu_reg_sp(s, a->rn);
196
--- a/docs/meson.build
161
197
+++ b/docs/meson.build
162
/*
198
@@ -XXX,XX +XXX,XX @@ if build_docs
163
* Issue the MTE check vs the logical repeat count, before we
199
meson.source_root() / 'docs/sphinx/qmp_lexer.py',
164
* promote consecutive little-endian elements below.
200
qapi_gen_depends ]
165
*/
201
166
- clean_addr = gen_mte_checkN(s, tcg_rn, is_store, is_postidx || rn != 31,
202
- configure_file(output: 'index.html',
167
- total, finalize_memop_asimd(s, size));
203
- input: files('index.html.in'),
168
+ clean_addr = gen_mte_checkN(s, tcg_rn, false, a->p || a->rn != 31, total,
204
- configuration: {'VERSION': meson.project_version()},
169
+ finalize_memop_asimd(s, size));
205
- install_dir: qemu_docdir)
170
206
- manuals = [ 'devel', 'interop', 'tools', 'specs', 'system', 'user' ]
171
/*
207
man_pages = {
172
* Consecutive little-endian elements from a single register
208
- 'interop' : {
173
* can be promoted to a larger little-endian operation.
209
'qemu-ga.8': (have_tools ? 'man8' : ''),
174
*/
210
'qemu-ga-ref.7': 'man7',
175
align = MO_ALIGN;
211
'qemu-qmp-ref.7': 'man7',
176
- if (selem == 1 && endian == MO_LE) {
212
'qemu-storage-daemon-qmp-ref.7': (have_tools ? 'man7' : ''),
177
+ if (a->selem == 1 && endian == MO_LE) {
213
- },
178
align = pow2_align(size);
214
- 'tools': {
179
size = 3;
215
'qemu-img.1': (have_tools ? 'man1' : ''),
180
}
216
'qemu-nbd.8': (have_tools ? 'man8' : ''),
181
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn)
217
'qemu-pr-helper.8': (have_tools ? 'man8' : ''),
182
}
218
@@ -XXX,XX +XXX,XX @@ if build_docs
183
mop = endian | size | align;
219
'qemu-trace-stap.1': (config_host.has_key('CONFIG_TRACE_SYSTEMTAP') ? 'man1' : ''),
184
220
'virtfs-proxy-helper.1': (have_virtfs_proxy_helper ? 'man1' : ''),
185
- elements = (is_q ? 16 : 8) >> size;
221
'virtiofsd.1': (have_virtiofsd ? 'man1' : ''),
186
+ elements = (a->q ? 16 : 8) >> size;
222
- },
187
tcg_ebytes = tcg_constant_i64(1 << size);
223
- 'system': {
188
- for (r = 0; r < rpt; r++) {
224
'qemu.1': 'man1',
189
+ for (r = 0; r < a->rpt; r++) {
225
'qemu-block-drivers.7': 'man7',
190
int e;
226
'qemu-cpu-models.7': 'man7'
191
for (e = 0; e < elements; e++) {
227
- },
192
int xs;
228
}
193
- for (xs = 0; xs < selem; xs++) {
229
194
- int tt = (rt + r + xs) % 32;
230
sphinxdocs = []
195
- if (is_store) {
231
sphinxmans = []
196
- do_vec_st(s, tt, e, clean_addr, mop);
232
- foreach manual : manuals
197
- } else {
233
- private_dir = meson.current_build_dir() / (manual + '.p')
198
- do_vec_ld(s, tt, e, clean_addr, mop);
234
- output_dir = meson.current_build_dir() / manual
199
- }
235
- input_dir = meson.current_source_dir() / manual
200
+ for (xs = 0; xs < a->selem; xs++) {
236
201
+ int tt = (a->rt + r + xs) % 32;
237
- this_manual = custom_target(manual + ' manual',
202
+ do_vec_ld(s, tt, e, clean_addr, mop);
238
+ private_dir = meson.current_build_dir() / 'manual.p'
203
tcg_gen_add_i64(clean_addr, clean_addr, tcg_ebytes);
239
+ output_dir = meson.current_build_dir() / 'manual'
204
}
240
+ input_dir = meson.current_source_dir()
205
}
241
+
206
}
242
+ this_manual = custom_target('QEMU manual',
207
243
build_by_default: build_docs,
208
- if (!is_store) {
244
- output: [manual + '.stamp'],
209
- /* For non-quad operations, setting a slice of the low
245
- input: [files('conf.py'), files(manual / 'conf.py')],
210
- * 64 bits of the register clears the high 64 bits (in
246
- depfile: manual + '.d',
211
- * the ARM ARM pseudocode this is implicit in the fact
247
+ output: 'docs.stamp',
212
- * that 'rval' is a 64 bit wide variable).
248
+ input: files('conf.py'),
213
- * For quad operations, we might still need to zero the
249
+ depfile: 'docs.d',
214
- * high bits of SVE.
250
depend_files: sphinx_extn_depends,
215
- */
251
command: [SPHINX_ARGS, '-Ddepfile=@DEPFILE@',
216
- for (r = 0; r < rpt * selem; r++) {
252
'-Ddepfile_stamp=@OUTPUT0@',
217
- int tt = (rt + r) % 32;
253
'-b', 'html', '-d', private_dir,
218
- clear_vec_high(s, is_q, tt);
254
input_dir, output_dir])
219
+ /*
255
- sphinxdocs += this_manual
220
+ * For non-quad operations, setting a slice of the low 64 bits of
256
- if build_docs and manual != 'devel'
221
+ * the register clears the high 64 bits (in the ARM ARM pseudocode
257
- install_subdir(output_dir, install_dir: qemu_docdir)
222
+ * this is implicit in the fact that 'rval' is a 64 bit wide
258
- endif
223
+ * variable). For quad operations, we might still need to zero
259
+ sphinxdocs += this_manual
224
+ * the high bits of SVE.
260
+ install_subdir(output_dir, install_dir: qemu_docdir, strip_directory: true)
225
+ */
261
226
+ for (r = 0; r < a->rpt * a->selem; r++) {
262
- these_man_pages = []
227
+ int tt = (a->rt + r) % 32;
263
- install_dirs = []
228
+ clear_vec_high(s, a->q, tt);
264
- foreach page, section : man_pages.get(manual, {})
229
+ }
265
- these_man_pages += page
230
+
266
- install_dirs += section == '' ? false : get_option('mandir') / section
231
+ if (a->p) {
267
- endforeach
232
+ if (a->rm == 31) {
268
- if these_man_pages.length() > 0
233
+ tcg_gen_addi_i64(tcg_rn, tcg_rn, total);
269
- sphinxmans += custom_target(manual + ' man pages',
234
+ } else {
270
- build_by_default: build_docs,
235
+ tcg_gen_add_i64(tcg_rn, tcg_rn, cpu_reg(s, a->rm));
271
- output: these_man_pages,
236
+ }
272
- input: this_manual,
237
+ }
273
- install: build_docs,
238
+ return true;
274
- install_dir: install_dirs,
239
+}
275
- command: [SPHINX_ARGS, '-b', 'man', '-d', private_dir,
240
+
276
- input_dir, meson.current_build_dir()])
241
+static bool trans_ST_mult(DisasContext *s, arg_ldst_mult *a)
277
- endif
242
+{
278
+ these_man_pages = []
243
+ TCGv_i64 clean_addr, tcg_rn, tcg_ebytes;
279
+ install_dirs = []
244
+ MemOp endian, align, mop;
280
+ foreach page, section : man_pages
245
+
281
+ these_man_pages += page
246
+ int total; /* total bytes */
282
+ install_dirs += section == '' ? false : get_option('mandir') / section
247
+ int elements; /* elements per vector */
283
endforeach
248
+ int r;
284
+
249
+ int size = a->sz;
285
+ sphinxmans += custom_target('QEMU man pages',
250
+
286
+ build_by_default: build_docs,
251
+ if (!a->p && a->rm != 0) {
287
+ output: these_man_pages,
252
+ /* For non-postindexed accesses the Rm field must be 0 */
288
+ input: this_manual,
253
+ return false;
289
+ install: build_docs,
254
+ }
290
+ install_dir: install_dirs,
255
+ if (size == 3 && !a->q && a->selem != 1) {
291
+ command: [SPHINX_ARGS, '-b', 'man', '-d', private_dir,
256
+ return false;
292
+ input_dir, meson.current_build_dir()])
257
+ }
293
+
258
+ if (!fp_access_check(s)) {
294
alias_target('sphinxdocs', sphinxdocs)
259
+ return true;
295
alias_target('html', sphinxdocs)
260
+ }
296
alias_target('man', sphinxmans)
261
+
297
diff --git a/docs/specs/conf.py b/docs/specs/conf.py
262
+ if (a->rn == 31) {
298
deleted file mode 100644
263
+ gen_check_sp_alignment(s);
299
index XXXXXXX..XXXXXXX
264
+ }
300
--- a/docs/specs/conf.py
265
+
301
+++ /dev/null
266
+ /* For our purposes, bytes are always little-endian. */
302
@@ -XXX,XX +XXX,XX @@
267
+ endian = s->be_data;
303
-# -*- coding: utf-8 -*-
268
+ if (size == 0) {
304
-#
269
+ endian = MO_LE;
305
-# QEMU documentation build configuration file for the 'specs' manual.
270
+ }
306
-#
271
+
307
-# This includes the top level conf file and then makes any necessary tweaks.
272
+ total = a->rpt * a->selem * (a->q ? 16 : 8);
308
-import sys
273
+ tcg_rn = cpu_reg_sp(s, a->rn);
309
-import os
274
+
310
-
275
+ /*
311
-qemu_docdir = os.path.abspath("..")
276
+ * Issue the MTE check vs the logical repeat count, before we
312
-parent_config = os.path.join(qemu_docdir, "conf.py")
277
+ * promote consecutive little-endian elements below.
313
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
278
+ */
314
-
279
+ clean_addr = gen_mte_checkN(s, tcg_rn, true, a->p || a->rn != 31, total,
315
-# This slightly misuses the 'description', but is the best way to get
280
+ finalize_memop_asimd(s, size));
316
-# the manual title to appear in the sidebar.
281
+
317
-html_theme_options['description'] = \
282
+ /*
318
- u'System Emulation Guest Hardware Specifications'
283
+ * Consecutive little-endian elements from a single register
319
diff --git a/docs/system/conf.py b/docs/system/conf.py
284
+ * can be promoted to a larger little-endian operation.
320
deleted file mode 100644
285
+ */
321
index XXXXXXX..XXXXXXX
286
+ align = MO_ALIGN;
322
--- a/docs/system/conf.py
287
+ if (a->selem == 1 && endian == MO_LE) {
323
+++ /dev/null
288
+ align = pow2_align(size);
324
@@ -XXX,XX +XXX,XX @@
289
+ size = 3;
325
-# -*- coding: utf-8 -*-
290
+ }
326
-#
291
+ if (!s->align_mem) {
327
-# QEMU documentation build configuration file for the 'system' manual.
292
+ align = 0;
328
-#
293
+ }
329
-# This includes the top level conf file and then makes any necessary tweaks.
294
+ mop = endian | size | align;
330
-import sys
295
+
331
-import os
296
+ elements = (a->q ? 16 : 8) >> size;
332
-
297
+ tcg_ebytes = tcg_constant_i64(1 << size);
333
-qemu_docdir = os.path.abspath("..")
298
+ for (r = 0; r < a->rpt; r++) {
334
-parent_config = os.path.join(qemu_docdir, "conf.py")
299
+ int e;
335
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
300
+ for (e = 0; e < elements; e++) {
336
-
301
+ int xs;
337
-# This slightly misuses the 'description', but is the best way to get
302
+ for (xs = 0; xs < a->selem; xs++) {
338
-# the manual title to appear in the sidebar.
303
+ int tt = (a->rt + r + xs) % 32;
339
-html_theme_options['description'] = u'System Emulation User''s Guide'
304
+ do_vec_st(s, tt, e, clean_addr, mop);
340
-
305
+ tcg_gen_add_i64(clean_addr, clean_addr, tcg_ebytes);
341
-# One entry per manual page. List of tuples
306
+ }
342
-# (source start file, name, description, authors, manual section).
307
}
343
-man_pages = [
308
}
344
- ('qemu-manpage', 'qemu', u'QEMU User Documentation',
309
345
- ['Fabrice Bellard'], 1),
310
- if (is_postidx) {
346
- ('qemu-block-drivers', 'qemu-block-drivers',
311
- if (rm == 31) {
347
- u'QEMU block drivers reference',
312
+ if (a->p) {
348
- ['Fabrice Bellard and the QEMU Project developers'], 7),
313
+ if (a->rm == 31) {
349
- ('qemu-cpu-models', 'qemu-cpu-models',
314
tcg_gen_addi_i64(tcg_rn, tcg_rn, total);
350
- u'QEMU CPU Models',
315
} else {
351
- ['The QEMU Project developers'], 7)
316
- tcg_gen_add_i64(tcg_rn, tcg_rn, cpu_reg(s, rm));
352
-]
317
+ tcg_gen_add_i64(tcg_rn, tcg_rn, cpu_reg(s, a->rm));
353
diff --git a/docs/tools/conf.py b/docs/tools/conf.py
318
}
354
deleted file mode 100644
319
}
355
index XXXXXXX..XXXXXXX
320
+ return true;
356
--- a/docs/tools/conf.py
321
}
357
+++ /dev/null
322
358
@@ -XXX,XX +XXX,XX @@
323
/* AdvSIMD load/store single structure
359
-# -*- coding: utf-8 -*-
324
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_tag(DisasContext *s, uint32_t insn)
360
-#
325
static void disas_ldst(DisasContext *s, uint32_t insn)
361
-# QEMU documentation build configuration file for the 'tools' manual.
326
{
362
-#
327
switch (extract32(insn, 24, 6)) {
363
-# This includes the top level conf file and then makes any necessary tweaks.
328
- case 0x0c: /* AdvSIMD load/store multiple structures */
364
-import sys
329
- disas_ldst_multiple_struct(s, insn);
365
-import os
330
- break;
366
-
331
case 0x0d: /* AdvSIMD load/store single structure */
367
-qemu_docdir = os.path.abspath("..")
332
disas_ldst_single_struct(s, insn);
368
-parent_config = os.path.join(qemu_docdir, "conf.py")
333
break;
369
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
370
-
371
-# This slightly misuses the 'description', but is the best way to get
372
-# the manual title to appear in the sidebar.
373
-html_theme_options['description'] = \
374
- u'Tools Guide'
375
-
376
-# One entry per manual page. List of tuples
377
-# (source start file, name, description, authors, manual section).
378
-man_pages = [
379
- ('qemu-img', 'qemu-img', u'QEMU disk image utility',
380
- ['Fabrice Bellard'], 1),
381
- ('qemu-storage-daemon', 'qemu-storage-daemon', u'QEMU storage daemon',
382
- [], 1),
383
- ('qemu-nbd', 'qemu-nbd', u'QEMU Disk Network Block Device Server',
384
- ['Anthony Liguori <anthony@codemonkey.ws>'], 8),
385
- ('qemu-pr-helper', 'qemu-pr-helper', 'QEMU persistent reservation helper',
386
- [], 8),
387
- ('qemu-trace-stap', 'qemu-trace-stap', u'QEMU SystemTap trace tool',
388
- [], 1),
389
- ('virtfs-proxy-helper', 'virtfs-proxy-helper',
390
- u'QEMU 9p virtfs proxy filesystem helper',
391
- ['M. Mohan Kumar'], 1),
392
- ('virtiofsd', 'virtiofsd', u'QEMU virtio-fs shared file system daemon',
393
- ['Stefan Hajnoczi <stefanha@redhat.com>',
394
- 'Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>'], 1),
395
-]
396
diff --git a/docs/user/conf.py b/docs/user/conf.py
397
deleted file mode 100644
398
index XXXXXXX..XXXXXXX
399
--- a/docs/user/conf.py
400
+++ /dev/null
401
@@ -XXX,XX +XXX,XX @@
402
-# -*- coding: utf-8 -*-
403
-#
404
-# QEMU documentation build configuration file for the 'user' manual.
405
-#
406
-# This includes the top level conf file and then makes any necessary tweaks.
407
-import sys
408
-import os
409
-
410
-qemu_docdir = os.path.abspath("..")
411
-parent_config = os.path.join(qemu_docdir, "conf.py")
412
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
413
-
414
-# This slightly misuses the 'description', but is the best way to get
415
-# the manual title to appear in the sidebar.
416
-html_theme_options['description'] = u'User Mode Emulation User''s Guide'
417
--
334
--
418
2.20.1
335
2.34.1
419
420
diff view generated by jsdifflib
1
In commit 1982e1602d15 we added a new qemu-storage-daemon(1) manpage.
1
Convert the ASIMD load/store single structure insns to decodetree.
2
At the moment new manpages have to be listed both in the conf.py for
3
Sphinx and also in docs/meson.build for Meson. We forgot the second
4
of those -- correct the omission.
5
2
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
4
Message-id: 20230602155223.2040685-20-peter.maydell@linaro.org
8
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20210108161416.21129-2-peter.maydell@linaro.org
10
---
6
---
11
docs/meson.build | 1 +
7
target/arm/tcg/a64.decode | 34 +++++
12
1 file changed, 1 insertion(+)
8
target/arm/tcg/translate-a64.c | 219 +++++++++++++++------------------
9
2 files changed, 136 insertions(+), 117 deletions(-)
13
10
14
diff --git a/docs/meson.build b/docs/meson.build
11
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
15
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
16
--- a/docs/meson.build
13
--- a/target/arm/tcg/a64.decode
17
+++ b/docs/meson.build
14
+++ b/target/arm/tcg/a64.decode
18
@@ -XXX,XX +XXX,XX @@ if build_docs
15
@@ -XXX,XX +XXX,XX @@ LD_mult 0 . 001100 . 1 0 ..... 0110 .. ..... ..... @ldst_mult rpt=3 sele
19
'qemu-img.1': (have_tools ? 'man1' : ''),
16
LD_mult 0 . 001100 . 1 0 ..... 0111 .. ..... ..... @ldst_mult rpt=1 selem=1
20
'qemu-nbd.8': (have_tools ? 'man8' : ''),
17
LD_mult 0 . 001100 . 1 0 ..... 1000 .. ..... ..... @ldst_mult rpt=1 selem=2
21
'qemu-pr-helper.8': (have_tools ? 'man8' : ''),
18
LD_mult 0 . 001100 . 1 0 ..... 1010 .. ..... ..... @ldst_mult rpt=2 selem=1
22
+ 'qemu-storage-daemon.1': (have_tools ? 'man1' : ''),
19
+
23
'qemu-trace-stap.1': (config_host.has_key('CONFIG_TRACE_SYSTEMTAP') ? 'man1' : ''),
20
+# Load/store single structure
24
'virtfs-proxy-helper.1': (have_virtfs_proxy_helper ? 'man1' : ''),
21
+&ldst_single rm rn rt p selem index scale
25
'virtiofsd.1': (have_virtiofsd ? 'man1' : ''),
22
+
23
+%ldst_single_selem 13:1 21:1 !function=plus_1
24
+
25
+%ldst_single_index_b 30:1 10:3
26
+%ldst_single_index_h 30:1 11:2
27
+%ldst_single_index_s 30:1 12:1
28
+
29
+@ldst_single_b .. ...... p:1 .. rm:5 ...... rn:5 rt:5 \
30
+ &ldst_single scale=0 selem=%ldst_single_selem \
31
+ index=%ldst_single_index_b
32
+@ldst_single_h .. ...... p:1 .. rm:5 ...... rn:5 rt:5 \
33
+ &ldst_single scale=1 selem=%ldst_single_selem \
34
+ index=%ldst_single_index_h
35
+@ldst_single_s .. ...... p:1 .. rm:5 ...... rn:5 rt:5 \
36
+ &ldst_single scale=2 selem=%ldst_single_selem \
37
+ index=%ldst_single_index_s
38
+@ldst_single_d . index:1 ...... p:1 .. rm:5 ...... rn:5 rt:5 \
39
+ &ldst_single scale=3 selem=%ldst_single_selem
40
+
41
+ST_single 0 . 001101 . 0 . ..... 00 . ... ..... ..... @ldst_single_b
42
+ST_single 0 . 001101 . 0 . ..... 01 . ..0 ..... ..... @ldst_single_h
43
+ST_single 0 . 001101 . 0 . ..... 10 . .00 ..... ..... @ldst_single_s
44
+ST_single 0 . 001101 . 0 . ..... 10 . 001 ..... ..... @ldst_single_d
45
+
46
+LD_single 0 . 001101 . 1 . ..... 00 . ... ..... ..... @ldst_single_b
47
+LD_single 0 . 001101 . 1 . ..... 01 . ..0 ..... ..... @ldst_single_h
48
+LD_single 0 . 001101 . 1 . ..... 10 . .00 ..... ..... @ldst_single_s
49
+LD_single 0 . 001101 . 1 . ..... 10 . 001 ..... ..... @ldst_single_d
50
+
51
+# Replicating load case
52
+LD_single_repl 0 q:1 001101 p:1 1 . rm:5 11 . 0 scale:2 rn:5 rt:5 selem=%ldst_single_selem
53
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
54
index XXXXXXX..XXXXXXX 100644
55
--- a/target/arm/tcg/translate-a64.c
56
+++ b/target/arm/tcg/translate-a64.c
57
@@ -XXX,XX +XXX,XX @@ static bool trans_ST_mult(DisasContext *s, arg_ldst_mult *a)
58
return true;
59
}
60
61
-/* AdvSIMD load/store single structure
62
- *
63
- * 31 30 29 23 22 21 20 16 15 13 12 11 10 9 5 4 0
64
- * +---+---+---------------+-----+-----------+-----+---+------+------+------+
65
- * | 0 | Q | 0 0 1 1 0 1 0 | L R | 0 0 0 0 0 | opc | S | size | Rn | Rt |
66
- * +---+---+---------------+-----+-----------+-----+---+------+------+------+
67
- *
68
- * AdvSIMD load/store single structure (post-indexed)
69
- *
70
- * 31 30 29 23 22 21 20 16 15 13 12 11 10 9 5 4 0
71
- * +---+---+---------------+-----+-----------+-----+---+------+------+------+
72
- * | 0 | Q | 0 0 1 1 0 1 1 | L R | Rm | opc | S | size | Rn | Rt |
73
- * +---+---+---------------+-----+-----------+-----+---+------+------+------+
74
- *
75
- * Rt: first (or only) SIMD&FP register to be transferred
76
- * Rn: base address or SP
77
- * Rm (post-index only): post-index register (when !31) or size dependent #imm
78
- * index = encoded in Q:S:size dependent on size
79
- *
80
- * lane_size = encoded in R, opc
81
- * transfer width = encoded in opc, S, size
82
- */
83
-static void disas_ldst_single_struct(DisasContext *s, uint32_t insn)
84
+static bool trans_ST_single(DisasContext *s, arg_ldst_single *a)
85
{
86
- int rt = extract32(insn, 0, 5);
87
- int rn = extract32(insn, 5, 5);
88
- int rm = extract32(insn, 16, 5);
89
- int size = extract32(insn, 10, 2);
90
- int S = extract32(insn, 12, 1);
91
- int opc = extract32(insn, 13, 3);
92
- int R = extract32(insn, 21, 1);
93
- int is_load = extract32(insn, 22, 1);
94
- int is_postidx = extract32(insn, 23, 1);
95
- int is_q = extract32(insn, 30, 1);
96
-
97
- int scale = extract32(opc, 1, 2);
98
- int selem = (extract32(opc, 0, 1) << 1 | R) + 1;
99
- bool replicate = false;
100
- int index = is_q << 3 | S << 2 | size;
101
- int xs, total;
102
+ int xs, total, rt;
103
TCGv_i64 clean_addr, tcg_rn, tcg_ebytes;
104
MemOp mop;
105
106
- if (extract32(insn, 31, 1)) {
107
- unallocated_encoding(s);
108
- return;
109
+ if (!a->p && a->rm != 0) {
110
+ return false;
111
}
112
- if (!is_postidx && rm != 0) {
113
- unallocated_encoding(s);
114
- return;
115
- }
116
-
117
- switch (scale) {
118
- case 3:
119
- if (!is_load || S) {
120
- unallocated_encoding(s);
121
- return;
122
- }
123
- scale = size;
124
- replicate = true;
125
- break;
126
- case 0:
127
- break;
128
- case 1:
129
- if (extract32(size, 0, 1)) {
130
- unallocated_encoding(s);
131
- return;
132
- }
133
- index >>= 1;
134
- break;
135
- case 2:
136
- if (extract32(size, 1, 1)) {
137
- unallocated_encoding(s);
138
- return;
139
- }
140
- if (!extract32(size, 0, 1)) {
141
- index >>= 2;
142
- } else {
143
- if (S) {
144
- unallocated_encoding(s);
145
- return;
146
- }
147
- index >>= 3;
148
- scale = 3;
149
- }
150
- break;
151
- default:
152
- g_assert_not_reached();
153
- }
154
-
155
if (!fp_access_check(s)) {
156
- return;
157
+ return true;
158
}
159
160
- if (rn == 31) {
161
+ if (a->rn == 31) {
162
gen_check_sp_alignment(s);
163
}
164
165
- total = selem << scale;
166
- tcg_rn = cpu_reg_sp(s, rn);
167
+ total = a->selem << a->scale;
168
+ tcg_rn = cpu_reg_sp(s, a->rn);
169
170
- mop = finalize_memop_asimd(s, scale);
171
-
172
- clean_addr = gen_mte_checkN(s, tcg_rn, !is_load, is_postidx || rn != 31,
173
+ mop = finalize_memop_asimd(s, a->scale);
174
+ clean_addr = gen_mte_checkN(s, tcg_rn, true, a->p || a->rn != 31,
175
total, mop);
176
177
- tcg_ebytes = tcg_constant_i64(1 << scale);
178
- for (xs = 0; xs < selem; xs++) {
179
- if (replicate) {
180
- /* Load and replicate to all elements */
181
- TCGv_i64 tcg_tmp = tcg_temp_new_i64();
182
-
183
- tcg_gen_qemu_ld_i64(tcg_tmp, clean_addr, get_mem_index(s), mop);
184
- tcg_gen_gvec_dup_i64(scale, vec_full_reg_offset(s, rt),
185
- (is_q + 1) * 8, vec_full_reg_size(s),
186
- tcg_tmp);
187
- } else {
188
- /* Load/store one element per register */
189
- if (is_load) {
190
- do_vec_ld(s, rt, index, clean_addr, mop);
191
- } else {
192
- do_vec_st(s, rt, index, clean_addr, mop);
193
- }
194
- }
195
+ tcg_ebytes = tcg_constant_i64(1 << a->scale);
196
+ for (xs = 0, rt = a->rt; xs < a->selem; xs++, rt = (rt + 1) % 32) {
197
+ do_vec_st(s, rt, a->index, clean_addr, mop);
198
tcg_gen_add_i64(clean_addr, clean_addr, tcg_ebytes);
199
- rt = (rt + 1) % 32;
200
}
201
202
- if (is_postidx) {
203
- if (rm == 31) {
204
+ if (a->p) {
205
+ if (a->rm == 31) {
206
tcg_gen_addi_i64(tcg_rn, tcg_rn, total);
207
} else {
208
- tcg_gen_add_i64(tcg_rn, tcg_rn, cpu_reg(s, rm));
209
+ tcg_gen_add_i64(tcg_rn, tcg_rn, cpu_reg(s, a->rm));
210
}
211
}
212
+ return true;
213
+}
214
+
215
+static bool trans_LD_single(DisasContext *s, arg_ldst_single *a)
216
+{
217
+ int xs, total, rt;
218
+ TCGv_i64 clean_addr, tcg_rn, tcg_ebytes;
219
+ MemOp mop;
220
+
221
+ if (!a->p && a->rm != 0) {
222
+ return false;
223
+ }
224
+ if (!fp_access_check(s)) {
225
+ return true;
226
+ }
227
+
228
+ if (a->rn == 31) {
229
+ gen_check_sp_alignment(s);
230
+ }
231
+
232
+ total = a->selem << a->scale;
233
+ tcg_rn = cpu_reg_sp(s, a->rn);
234
+
235
+ mop = finalize_memop_asimd(s, a->scale);
236
+ clean_addr = gen_mte_checkN(s, tcg_rn, false, a->p || a->rn != 31,
237
+ total, mop);
238
+
239
+ tcg_ebytes = tcg_constant_i64(1 << a->scale);
240
+ for (xs = 0, rt = a->rt; xs < a->selem; xs++, rt = (rt + 1) % 32) {
241
+ do_vec_ld(s, rt, a->index, clean_addr, mop);
242
+ tcg_gen_add_i64(clean_addr, clean_addr, tcg_ebytes);
243
+ }
244
+
245
+ if (a->p) {
246
+ if (a->rm == 31) {
247
+ tcg_gen_addi_i64(tcg_rn, tcg_rn, total);
248
+ } else {
249
+ tcg_gen_add_i64(tcg_rn, tcg_rn, cpu_reg(s, a->rm));
250
+ }
251
+ }
252
+ return true;
253
+}
254
+
255
+static bool trans_LD_single_repl(DisasContext *s, arg_LD_single_repl *a)
256
+{
257
+ int xs, total, rt;
258
+ TCGv_i64 clean_addr, tcg_rn, tcg_ebytes;
259
+ MemOp mop;
260
+
261
+ if (!a->p && a->rm != 0) {
262
+ return false;
263
+ }
264
+ if (!fp_access_check(s)) {
265
+ return true;
266
+ }
267
+
268
+ if (a->rn == 31) {
269
+ gen_check_sp_alignment(s);
270
+ }
271
+
272
+ total = a->selem << a->scale;
273
+ tcg_rn = cpu_reg_sp(s, a->rn);
274
+
275
+ mop = finalize_memop_asimd(s, a->scale);
276
+ clean_addr = gen_mte_checkN(s, tcg_rn, false, a->p || a->rn != 31,
277
+ total, mop);
278
+
279
+ tcg_ebytes = tcg_constant_i64(1 << a->scale);
280
+ for (xs = 0, rt = a->rt; xs < a->selem; xs++, rt = (rt + 1) % 32) {
281
+ /* Load and replicate to all elements */
282
+ TCGv_i64 tcg_tmp = tcg_temp_new_i64();
283
+
284
+ tcg_gen_qemu_ld_i64(tcg_tmp, clean_addr, get_mem_index(s), mop);
285
+ tcg_gen_gvec_dup_i64(a->scale, vec_full_reg_offset(s, rt),
286
+ (a->q + 1) * 8, vec_full_reg_size(s), tcg_tmp);
287
+ tcg_gen_add_i64(clean_addr, clean_addr, tcg_ebytes);
288
+ }
289
+
290
+ if (a->p) {
291
+ if (a->rm == 31) {
292
+ tcg_gen_addi_i64(tcg_rn, tcg_rn, total);
293
+ } else {
294
+ tcg_gen_add_i64(tcg_rn, tcg_rn, cpu_reg(s, a->rm));
295
+ }
296
+ }
297
+ return true;
298
}
299
300
/*
301
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_tag(DisasContext *s, uint32_t insn)
302
static void disas_ldst(DisasContext *s, uint32_t insn)
303
{
304
switch (extract32(insn, 24, 6)) {
305
- case 0x0d: /* AdvSIMD load/store single structure */
306
- disas_ldst_single_struct(s, insn);
307
- break;
308
case 0x19:
309
if (extract32(insn, 21, 1) != 0) {
310
disas_ldst_tag(s, insn);
26
--
311
--
27
2.20.1
312
2.34.1
28
29
diff view generated by jsdifflib
1
From: Hao Wu <wuhaotsh@google.com>
1
Convert the instructions in the load/store memory tags instruction
2
group to decodetree.
2
3
3
The ADC is part of NPCM7XX Module. Its behavior is controled by the
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
ADC_CON register. It converts one of the eight analog inputs into a
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
digital input and stores it in the ADC_DATA register when enabled.
6
Message-id: 20230602155223.2040685-21-peter.maydell@linaro.org
7
---
8
target/arm/tcg/a64.decode | 25 +++
9
target/arm/tcg/translate-a64.c | 360 ++++++++++++++++-----------------
10
2 files changed, 199 insertions(+), 186 deletions(-)
6
11
7
Users can alter input value by using qom-set QMP command.
12
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
8
9
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
10
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
11
Signed-off-by: Hao Wu <wuhaotsh@google.com>
12
Message-id: 20210108190945.949196-4-wuhaotsh@google.com
13
[PMM: Added missing hw/adc/trace.h file]
14
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
---
17
docs/system/arm/nuvoton.rst | 2 +-
18
meson.build | 1 +
19
hw/adc/trace.h | 1 +
20
include/hw/adc/npcm7xx_adc.h | 69 ++++++
21
include/hw/arm/npcm7xx.h | 2 +
22
hw/adc/npcm7xx_adc.c | 301 ++++++++++++++++++++++++++
23
hw/arm/npcm7xx.c | 24 ++-
24
tests/qtest/npcm7xx_adc-test.c | 377 +++++++++++++++++++++++++++++++++
25
hw/adc/meson.build | 1 +
26
hw/adc/trace-events | 5 +
27
tests/qtest/meson.build | 3 +-
28
11 files changed, 783 insertions(+), 3 deletions(-)
29
create mode 100644 hw/adc/trace.h
30
create mode 100644 include/hw/adc/npcm7xx_adc.h
31
create mode 100644 hw/adc/npcm7xx_adc.c
32
create mode 100644 tests/qtest/npcm7xx_adc-test.c
33
create mode 100644 hw/adc/trace-events
34
35
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
36
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
37
--- a/docs/system/arm/nuvoton.rst
14
--- a/target/arm/tcg/a64.decode
38
+++ b/docs/system/arm/nuvoton.rst
15
+++ b/target/arm/tcg/a64.decode
39
@@ -XXX,XX +XXX,XX @@ Supported devices
16
@@ -XXX,XX +XXX,XX @@ LD_single 0 . 001101 . 1 . ..... 10 . 001 ..... ..... @ldst_single_d
40
* Random Number Generator (RNG)
17
41
* USB host (USBH)
18
# Replicating load case
42
* GPIO controller
19
LD_single_repl 0 q:1 001101 p:1 1 . rm:5 11 . 0 scale:2 rn:5 rt:5 selem=%ldst_single_selem
43
+ * Analog to Digital Converter (ADC)
20
+
44
21
+%tag_offset 12:s9 !function=scale_by_log2_tag_granule
45
Missing devices
22
+&ldst_tag rn rt imm p w
46
---------------
23
+@ldst_tag ........ .. . ......... .. rn:5 rt:5 &ldst_tag imm=%tag_offset
47
@@ -XXX,XX +XXX,XX @@ Missing devices
24
+@ldst_tag_mult ........ .. . 000000000 .. rn:5 rt:5 &ldst_tag imm=0
48
* USB device (USBD)
25
+
49
* SMBus controller (SMBF)
26
+STZGM 11011001 00 1 ......... 00 ..... ..... @ldst_tag_mult p=0 w=0
50
* Peripheral SPI controller (PSPI)
27
+STG 11011001 00 1 ......... 01 ..... ..... @ldst_tag p=1 w=1
51
- * Analog to Digital Converter (ADC)
28
+STG 11011001 00 1 ......... 10 ..... ..... @ldst_tag p=0 w=0
52
* SD/MMC host
29
+STG 11011001 00 1 ......... 11 ..... ..... @ldst_tag p=0 w=1
53
* PECI interface
30
+
54
* Pulse Width Modulation (PWM)
31
+LDG 11011001 01 1 ......... 00 ..... ..... @ldst_tag p=0 w=0
55
diff --git a/meson.build b/meson.build
32
+STZG 11011001 01 1 ......... 01 ..... ..... @ldst_tag p=1 w=1
33
+STZG 11011001 01 1 ......... 10 ..... ..... @ldst_tag p=0 w=0
34
+STZG 11011001 01 1 ......... 11 ..... ..... @ldst_tag p=0 w=1
35
+
36
+STGM 11011001 10 1 ......... 00 ..... ..... @ldst_tag_mult p=0 w=0
37
+ST2G 11011001 10 1 ......... 01 ..... ..... @ldst_tag p=1 w=1
38
+ST2G 11011001 10 1 ......... 10 ..... ..... @ldst_tag p=0 w=0
39
+ST2G 11011001 10 1 ......... 11 ..... ..... @ldst_tag p=0 w=1
40
+
41
+LDGM 11011001 11 1 ......... 00 ..... ..... @ldst_tag_mult p=0 w=0
42
+STZ2G 11011001 11 1 ......... 01 ..... ..... @ldst_tag p=1 w=1
43
+STZ2G 11011001 11 1 ......... 10 ..... ..... @ldst_tag p=0 w=0
44
+STZ2G 11011001 11 1 ......... 11 ..... ..... @ldst_tag p=0 w=1
45
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
56
index XXXXXXX..XXXXXXX 100644
46
index XXXXXXX..XXXXXXX 100644
57
--- a/meson.build
47
--- a/target/arm/tcg/translate-a64.c
58
+++ b/meson.build
48
+++ b/target/arm/tcg/translate-a64.c
59
@@ -XXX,XX +XXX,XX @@ if have_system
49
@@ -XXX,XX +XXX,XX @@ static int uimm_scaled(DisasContext *s, int x)
60
'chardev',
50
return imm << scale;
61
'hw/9pfs',
51
}
62
'hw/acpi',
52
63
+ 'hw/adc',
53
+/* For load/store memory tags: scale offset by LOG2_TAG_GRANULE */
64
'hw/alpha',
54
+static int scale_by_log2_tag_granule(DisasContext *s, int x)
65
'hw/arm',
66
'hw/audio',
67
diff --git a/hw/adc/trace.h b/hw/adc/trace.h
68
new file mode 100644
69
index XXXXXXX..XXXXXXX
70
--- /dev/null
71
+++ b/hw/adc/trace.h
72
@@ -0,0 +1 @@
73
+#include "trace/trace-hw_adc.h"
74
diff --git a/include/hw/adc/npcm7xx_adc.h b/include/hw/adc/npcm7xx_adc.h
75
new file mode 100644
76
index XXXXXXX..XXXXXXX
77
--- /dev/null
78
+++ b/include/hw/adc/npcm7xx_adc.h
79
@@ -XXX,XX +XXX,XX @@
80
+/*
81
+ * Nuvoton NPCM7xx ADC Module
82
+ *
83
+ * Copyright 2020 Google LLC
84
+ *
85
+ * This program is free software; you can redistribute it and/or modify it
86
+ * under the terms of the GNU General Public License as published by the
87
+ * Free Software Foundation; either version 2 of the License, or
88
+ * (at your option) any later version.
89
+ *
90
+ * This program is distributed in the hope that it will be useful, but WITHOUT
91
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
92
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
93
+ * for more details.
94
+ */
95
+#ifndef NPCM7XX_ADC_H
96
+#define NPCM7XX_ADC_H
97
+
98
+#include "hw/clock.h"
99
+#include "hw/irq.h"
100
+#include "hw/sysbus.h"
101
+#include "qemu/timer.h"
102
+
103
+#define NPCM7XX_ADC_NUM_INPUTS 8
104
+/**
105
+ * This value should not be changed unless write_adc_calibration function in
106
+ * hw/arm/npcm7xx.c is also changed.
107
+ */
108
+#define NPCM7XX_ADC_NUM_CALIB 2
109
+
110
+/**
111
+ * struct NPCM7xxADCState - Analog to Digital Converter Module device state.
112
+ * @parent: System bus device.
113
+ * @iomem: Memory region through which registers are accessed.
114
+ * @conv_timer: The timer counts down remaining cycles for the conversion.
115
+ * @irq: GIC interrupt line to fire on expiration (if enabled).
116
+ * @con: The Control Register.
117
+ * @data: The Data Buffer.
118
+ * @clock: The ADC Clock.
119
+ * @adci: The input voltage in units of uV. 1uv = 1e-6V.
120
+ * @vref: The external reference voltage.
121
+ * @iref: The internal reference voltage, initialized at launch time.
122
+ * @rv: The calibrated output values of 0.5V and 1.5V for the ADC.
123
+ */
124
+typedef struct {
125
+ SysBusDevice parent;
126
+
127
+ MemoryRegion iomem;
128
+
129
+ QEMUTimer conv_timer;
130
+
131
+ qemu_irq irq;
132
+ uint32_t con;
133
+ uint32_t data;
134
+ Clock *clock;
135
+
136
+ /* Voltages are in unit of uV. 1V = 1000000uV. */
137
+ uint32_t adci[NPCM7XX_ADC_NUM_INPUTS];
138
+ uint32_t vref;
139
+ uint32_t iref;
140
+
141
+ uint16_t calibration_r_values[NPCM7XX_ADC_NUM_CALIB];
142
+} NPCM7xxADCState;
143
+
144
+#define TYPE_NPCM7XX_ADC "npcm7xx-adc"
145
+#define NPCM7XX_ADC(obj) \
146
+ OBJECT_CHECK(NPCM7xxADCState, (obj), TYPE_NPCM7XX_ADC)
147
+
148
+#endif /* NPCM7XX_ADC_H */
149
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
150
index XXXXXXX..XXXXXXX 100644
151
--- a/include/hw/arm/npcm7xx.h
152
+++ b/include/hw/arm/npcm7xx.h
153
@@ -XXX,XX +XXX,XX @@
154
#define NPCM7XX_H
155
156
#include "hw/boards.h"
157
+#include "hw/adc/npcm7xx_adc.h"
158
#include "hw/cpu/a9mpcore.h"
159
#include "hw/gpio/npcm7xx_gpio.h"
160
#include "hw/mem/npcm7xx_mc.h"
161
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
162
NPCM7xxGCRState gcr;
163
NPCM7xxCLKState clk;
164
NPCM7xxTimerCtrlState tim[3];
165
+ NPCM7xxADCState adc;
166
NPCM7xxOTPState key_storage;
167
NPCM7xxOTPState fuse_array;
168
NPCM7xxMCState mc;
169
diff --git a/hw/adc/npcm7xx_adc.c b/hw/adc/npcm7xx_adc.c
170
new file mode 100644
171
index XXXXXXX..XXXXXXX
172
--- /dev/null
173
+++ b/hw/adc/npcm7xx_adc.c
174
@@ -XXX,XX +XXX,XX @@
175
+/*
176
+ * Nuvoton NPCM7xx ADC Module
177
+ *
178
+ * Copyright 2020 Google LLC
179
+ *
180
+ * This program is free software; you can redistribute it and/or modify it
181
+ * under the terms of the GNU General Public License as published by the
182
+ * Free Software Foundation; either version 2 of the License, or
183
+ * (at your option) any later version.
184
+ *
185
+ * This program is distributed in the hope that it will be useful, but WITHOUT
186
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
187
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
188
+ * for more details.
189
+ */
190
+
191
+#include "qemu/osdep.h"
192
+#include "hw/adc/npcm7xx_adc.h"
193
+#include "hw/qdev-clock.h"
194
+#include "hw/qdev-properties.h"
195
+#include "hw/registerfields.h"
196
+#include "migration/vmstate.h"
197
+#include "qemu/log.h"
198
+#include "qemu/module.h"
199
+#include "qemu/timer.h"
200
+#include "qemu/units.h"
201
+#include "trace.h"
202
+
203
+REG32(NPCM7XX_ADC_CON, 0x0)
204
+REG32(NPCM7XX_ADC_DATA, 0x4)
205
+
206
+/* Register field definitions. */
207
+#define NPCM7XX_ADC_CON_MUX(rv) extract32(rv, 24, 4)
208
+#define NPCM7XX_ADC_CON_INT_EN BIT(21)
209
+#define NPCM7XX_ADC_CON_REFSEL BIT(19)
210
+#define NPCM7XX_ADC_CON_INT BIT(18)
211
+#define NPCM7XX_ADC_CON_EN BIT(17)
212
+#define NPCM7XX_ADC_CON_RST BIT(16)
213
+#define NPCM7XX_ADC_CON_CONV BIT(14)
214
+#define NPCM7XX_ADC_CON_DIV(rv) extract32(rv, 1, 8)
215
+
216
+#define NPCM7XX_ADC_MAX_RESULT 1023
217
+#define NPCM7XX_ADC_DEFAULT_IREF 2000000
218
+#define NPCM7XX_ADC_CONV_CYCLES 20
219
+#define NPCM7XX_ADC_RESET_CYCLES 10
220
+#define NPCM7XX_ADC_R0_INPUT 500000
221
+#define NPCM7XX_ADC_R1_INPUT 1500000
222
+
223
+static void npcm7xx_adc_reset(NPCM7xxADCState *s)
224
+{
55
+{
225
+ timer_del(&s->conv_timer);
56
+ return x << LOG2_TAG_GRANULE;
226
+ s->con = 0x000c0001;
227
+ s->data = 0x00000000;
228
+}
57
+}
229
+
58
+
230
+static uint32_t npcm7xx_adc_convert(uint32_t input, uint32_t ref)
59
/*
60
* Include the generated decoders.
61
*/
62
@@ -XXX,XX +XXX,XX @@ static bool trans_LD_single_repl(DisasContext *s, arg_LD_single_repl *a)
63
return true;
64
}
65
66
-/*
67
- * Load/Store memory tags
68
- *
69
- * 31 30 29 24 22 21 12 10 5 0
70
- * +-----+-------------+-----+---+------+-----+------+------+
71
- * | 1 1 | 0 1 1 0 0 1 | op1 | 1 | imm9 | op2 | Rn | Rt |
72
- * +-----+-------------+-----+---+------+-----+------+------+
73
- */
74
-static void disas_ldst_tag(DisasContext *s, uint32_t insn)
75
+static bool trans_STZGM(DisasContext *s, arg_ldst_tag *a)
76
{
77
- int rt = extract32(insn, 0, 5);
78
- int rn = extract32(insn, 5, 5);
79
- uint64_t offset = sextract64(insn, 12, 9) << LOG2_TAG_GRANULE;
80
- int op2 = extract32(insn, 10, 2);
81
- int op1 = extract32(insn, 22, 2);
82
- bool is_load = false, is_pair = false, is_zero = false, is_mult = false;
83
- int index = 0;
84
TCGv_i64 addr, clean_addr, tcg_rt;
85
+ int size = 4 << s->dcz_blocksize;
86
87
- /* We checked insn bits [29:24,21] in the caller. */
88
- if (extract32(insn, 30, 2) != 3) {
89
- goto do_unallocated;
90
+ if (!dc_isar_feature(aa64_mte, s)) {
91
+ return false;
92
+ }
93
+ if (s->current_el == 0) {
94
+ return false;
95
}
96
97
- /*
98
- * @index is a tri-state variable which has 3 states:
99
- * < 0 : post-index, writeback
100
- * = 0 : signed offset
101
- * > 0 : pre-index, writeback
102
- */
103
- switch (op1) {
104
- case 0:
105
- if (op2 != 0) {
106
- /* STG */
107
- index = op2 - 2;
108
- } else {
109
- /* STZGM */
110
- if (s->current_el == 0 || offset != 0) {
111
- goto do_unallocated;
112
- }
113
- is_mult = is_zero = true;
114
- }
115
- break;
116
- case 1:
117
- if (op2 != 0) {
118
- /* STZG */
119
- is_zero = true;
120
- index = op2 - 2;
121
- } else {
122
- /* LDG */
123
- is_load = true;
124
- }
125
- break;
126
- case 2:
127
- if (op2 != 0) {
128
- /* ST2G */
129
- is_pair = true;
130
- index = op2 - 2;
131
- } else {
132
- /* STGM */
133
- if (s->current_el == 0 || offset != 0) {
134
- goto do_unallocated;
135
- }
136
- is_mult = true;
137
- }
138
- break;
139
- case 3:
140
- if (op2 != 0) {
141
- /* STZ2G */
142
- is_pair = is_zero = true;
143
- index = op2 - 2;
144
- } else {
145
- /* LDGM */
146
- if (s->current_el == 0 || offset != 0) {
147
- goto do_unallocated;
148
- }
149
- is_mult = is_load = true;
150
- }
151
- break;
152
-
153
- default:
154
- do_unallocated:
155
- unallocated_encoding(s);
156
- return;
157
- }
158
-
159
- if (is_mult
160
- ? !dc_isar_feature(aa64_mte, s)
161
- : !dc_isar_feature(aa64_mte_insn_reg, s)) {
162
- goto do_unallocated;
163
- }
164
-
165
- if (rn == 31) {
166
+ if (a->rn == 31) {
167
gen_check_sp_alignment(s);
168
}
169
170
- addr = read_cpu_reg_sp(s, rn, true);
171
- if (index >= 0) {
172
+ addr = read_cpu_reg_sp(s, a->rn, true);
173
+ tcg_gen_addi_i64(addr, addr, a->imm);
174
+ tcg_rt = cpu_reg(s, a->rt);
175
+
176
+ if (s->ata) {
177
+ gen_helper_stzgm_tags(cpu_env, addr, tcg_rt);
178
+ }
179
+ /*
180
+ * The non-tags portion of STZGM is mostly like DC_ZVA,
181
+ * except the alignment happens before the access.
182
+ */
183
+ clean_addr = clean_data_tbi(s, addr);
184
+ tcg_gen_andi_i64(clean_addr, clean_addr, -size);
185
+ gen_helper_dc_zva(cpu_env, clean_addr);
186
+ return true;
187
+}
188
+
189
+static bool trans_STGM(DisasContext *s, arg_ldst_tag *a)
231
+{
190
+{
232
+ uint32_t result;
191
+ TCGv_i64 addr, clean_addr, tcg_rt;
233
+
192
+
234
+ result = input * (NPCM7XX_ADC_MAX_RESULT + 1) / ref;
193
+ if (!dc_isar_feature(aa64_mte, s)) {
235
+ if (result > NPCM7XX_ADC_MAX_RESULT) {
194
+ return false;
236
+ result = NPCM7XX_ADC_MAX_RESULT;
195
+ }
237
+ }
196
+ if (s->current_el == 0) {
238
+
197
+ return false;
239
+ return result;
198
+ }
199
+
200
+ if (a->rn == 31) {
201
+ gen_check_sp_alignment(s);
202
+ }
203
+
204
+ addr = read_cpu_reg_sp(s, a->rn, true);
205
+ tcg_gen_addi_i64(addr, addr, a->imm);
206
+ tcg_rt = cpu_reg(s, a->rt);
207
+
208
+ if (s->ata) {
209
+ gen_helper_stgm(cpu_env, addr, tcg_rt);
210
+ } else {
211
+ MMUAccessType acc = MMU_DATA_STORE;
212
+ int size = 4 << GMID_EL1_BS;
213
+
214
+ clean_addr = clean_data_tbi(s, addr);
215
+ tcg_gen_andi_i64(clean_addr, clean_addr, -size);
216
+ gen_probe_access(s, clean_addr, acc, size);
217
+ }
218
+ return true;
240
+}
219
+}
241
+
220
+
242
+static uint32_t npcm7xx_adc_prescaler(NPCM7xxADCState *s)
221
+static bool trans_LDGM(DisasContext *s, arg_ldst_tag *a)
243
+{
222
+{
244
+ return 2 * (NPCM7XX_ADC_CON_DIV(s->con) + 1);
223
+ TCGv_i64 addr, clean_addr, tcg_rt;
224
+
225
+ if (!dc_isar_feature(aa64_mte, s)) {
226
+ return false;
227
+ }
228
+ if (s->current_el == 0) {
229
+ return false;
230
+ }
231
+
232
+ if (a->rn == 31) {
233
+ gen_check_sp_alignment(s);
234
+ }
235
+
236
+ addr = read_cpu_reg_sp(s, a->rn, true);
237
+ tcg_gen_addi_i64(addr, addr, a->imm);
238
+ tcg_rt = cpu_reg(s, a->rt);
239
+
240
+ if (s->ata) {
241
+ gen_helper_ldgm(tcg_rt, cpu_env, addr);
242
+ } else {
243
+ MMUAccessType acc = MMU_DATA_LOAD;
244
+ int size = 4 << GMID_EL1_BS;
245
+
246
+ clean_addr = clean_data_tbi(s, addr);
247
+ tcg_gen_andi_i64(clean_addr, clean_addr, -size);
248
+ gen_probe_access(s, clean_addr, acc, size);
249
+ /* The result tags are zeros. */
250
+ tcg_gen_movi_i64(tcg_rt, 0);
251
+ }
252
+ return true;
245
+}
253
+}
246
+
254
+
247
+static void npcm7xx_adc_start_timer(Clock *clk, QEMUTimer *timer,
255
+static bool trans_LDG(DisasContext *s, arg_ldst_tag *a)
248
+ uint32_t cycles, uint32_t prescaler)
249
+{
256
+{
250
+ int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
257
+ TCGv_i64 addr, clean_addr, tcg_rt;
251
+ int64_t ticks = cycles;
258
+
252
+ int64_t ns;
259
+ if (!dc_isar_feature(aa64_mte_insn_reg, s)) {
253
+
260
+ return false;
254
+ ticks *= prescaler;
261
+ }
255
+ ns = clock_ticks_to_ns(clk, ticks);
262
+
256
+ ns += now;
263
+ if (a->rn == 31) {
257
+ timer_mod(timer, ns);
264
+ gen_check_sp_alignment(s);
265
+ }
266
+
267
+ addr = read_cpu_reg_sp(s, a->rn, true);
268
+ if (!a->p) {
269
/* pre-index or signed offset */
270
- tcg_gen_addi_i64(addr, addr, offset);
271
+ tcg_gen_addi_i64(addr, addr, a->imm);
272
}
273
274
- if (is_mult) {
275
- tcg_rt = cpu_reg(s, rt);
276
+ tcg_gen_andi_i64(addr, addr, -TAG_GRANULE);
277
+ tcg_rt = cpu_reg(s, a->rt);
278
+ if (s->ata) {
279
+ gen_helper_ldg(tcg_rt, cpu_env, addr, tcg_rt);
280
+ } else {
281
+ /*
282
+ * Tag access disabled: we must check for aborts on the load
283
+ * load from [rn+offset], and then insert a 0 tag into rt.
284
+ */
285
+ clean_addr = clean_data_tbi(s, addr);
286
+ gen_probe_access(s, clean_addr, MMU_DATA_LOAD, MO_8);
287
+ gen_address_with_allocation_tag0(tcg_rt, tcg_rt);
288
+ }
289
290
- if (is_zero) {
291
- int size = 4 << s->dcz_blocksize;
292
-
293
- if (s->ata) {
294
- gen_helper_stzgm_tags(cpu_env, addr, tcg_rt);
295
- }
296
- /*
297
- * The non-tags portion of STZGM is mostly like DC_ZVA,
298
- * except the alignment happens before the access.
299
- */
300
- clean_addr = clean_data_tbi(s, addr);
301
- tcg_gen_andi_i64(clean_addr, clean_addr, -size);
302
- gen_helper_dc_zva(cpu_env, clean_addr);
303
- } else if (s->ata) {
304
- if (is_load) {
305
- gen_helper_ldgm(tcg_rt, cpu_env, addr);
306
- } else {
307
- gen_helper_stgm(cpu_env, addr, tcg_rt);
308
- }
309
- } else {
310
- MMUAccessType acc = is_load ? MMU_DATA_LOAD : MMU_DATA_STORE;
311
- int size = 4 << GMID_EL1_BS;
312
-
313
- clean_addr = clean_data_tbi(s, addr);
314
- tcg_gen_andi_i64(clean_addr, clean_addr, -size);
315
- gen_probe_access(s, clean_addr, acc, size);
316
-
317
- if (is_load) {
318
- /* The result tags are zeros. */
319
- tcg_gen_movi_i64(tcg_rt, 0);
320
- }
321
+ if (a->w) {
322
+ /* pre-index or post-index */
323
+ if (a->p) {
324
+ /* post-index */
325
+ tcg_gen_addi_i64(addr, addr, a->imm);
326
}
327
- return;
328
+ tcg_gen_mov_i64(cpu_reg_sp(s, a->rn), addr);
329
+ }
330
+ return true;
258
+}
331
+}
259
+
332
+
260
+static void npcm7xx_adc_start_convert(NPCM7xxADCState *s)
333
+static bool do_STG(DisasContext *s, arg_ldst_tag *a, bool is_zero, bool is_pair)
261
+{
334
+{
262
+ uint32_t prescaler = npcm7xx_adc_prescaler(s);
335
+ TCGv_i64 addr, tcg_rt;
263
+
336
+
264
+ npcm7xx_adc_start_timer(s->clock, &s->conv_timer, NPCM7XX_ADC_CONV_CYCLES,
337
+ if (a->rn == 31) {
265
+ prescaler);
338
+ gen_check_sp_alignment(s);
266
+}
339
}
267
+
340
268
+static void npcm7xx_adc_convert_done(void *opaque)
341
- if (is_load) {
269
+{
342
- tcg_gen_andi_i64(addr, addr, -TAG_GRANULE);
270
+ NPCM7xxADCState *s = opaque;
343
- tcg_rt = cpu_reg(s, rt);
271
+ uint32_t input = NPCM7XX_ADC_CON_MUX(s->con);
344
- if (s->ata) {
272
+ uint32_t ref = (s->con & NPCM7XX_ADC_CON_REFSEL)
345
- gen_helper_ldg(tcg_rt, cpu_env, addr, tcg_rt);
273
+ ? s->iref : s->vref;
346
+ addr = read_cpu_reg_sp(s, a->rn, true);
274
+
347
+ if (!a->p) {
275
+ if (input >= NPCM7XX_ADC_NUM_INPUTS) {
348
+ /* pre-index or signed offset */
276
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid input: %u\n",
349
+ tcg_gen_addi_i64(addr, addr, a->imm);
277
+ __func__, input);
350
+ }
278
+ return;
351
+ tcg_rt = cpu_reg_sp(s, a->rt);
279
+ }
352
+ if (!s->ata) {
280
+ s->data = npcm7xx_adc_convert(s->adci[input], ref);
353
+ /*
281
+ if (s->con & NPCM7XX_ADC_CON_INT_EN) {
354
+ * For STG and ST2G, we need to check alignment and probe memory.
282
+ s->con |= NPCM7XX_ADC_CON_INT;
355
+ * TODO: For STZG and STZ2G, we could rely on the stores below,
283
+ qemu_irq_raise(s->irq);
356
+ * at least for system mode; user-only won't enforce alignment.
284
+ }
357
+ */
285
+ s->con &= ~NPCM7XX_ADC_CON_CONV;
358
+ if (is_pair) {
286
+}
359
+ gen_helper_st2g_stub(cpu_env, addr);
287
+
360
} else {
288
+static void npcm7xx_adc_calibrate(NPCM7xxADCState *adc)
361
- /*
289
+{
362
- * Tag access disabled: we must check for aborts on the load
290
+ adc->calibration_r_values[0] = npcm7xx_adc_convert(NPCM7XX_ADC_R0_INPUT,
363
- * load from [rn+offset], and then insert a 0 tag into rt.
291
+ adc->iref);
364
- */
292
+ adc->calibration_r_values[1] = npcm7xx_adc_convert(NPCM7XX_ADC_R1_INPUT,
365
- clean_addr = clean_data_tbi(s, addr);
293
+ adc->iref);
366
- gen_probe_access(s, clean_addr, MMU_DATA_LOAD, MO_8);
294
+}
367
- gen_address_with_allocation_tag0(tcg_rt, tcg_rt);
295
+
368
+ gen_helper_stg_stub(cpu_env, addr);
296
+static void npcm7xx_adc_write_con(NPCM7xxADCState *s, uint32_t new_con)
369
+ }
297
+{
370
+ } else if (tb_cflags(s->base.tb) & CF_PARALLEL) {
298
+ uint32_t old_con = s->con;
371
+ if (is_pair) {
299
+
372
+ gen_helper_st2g_parallel(cpu_env, addr, tcg_rt);
300
+ /* Write ADC_INT to 1 to clear it */
301
+ if (new_con & NPCM7XX_ADC_CON_INT) {
302
+ new_con &= ~NPCM7XX_ADC_CON_INT;
303
+ qemu_irq_lower(s->irq);
304
+ } else if (old_con & NPCM7XX_ADC_CON_INT) {
305
+ new_con |= NPCM7XX_ADC_CON_INT;
306
+ }
307
+
308
+ s->con = new_con;
309
+
310
+ if (s->con & NPCM7XX_ADC_CON_RST) {
311
+ npcm7xx_adc_reset(s);
312
+ return;
313
+ }
314
+
315
+ if ((s->con & NPCM7XX_ADC_CON_EN)) {
316
+ if (s->con & NPCM7XX_ADC_CON_CONV) {
317
+ if (!(old_con & NPCM7XX_ADC_CON_CONV)) {
318
+ npcm7xx_adc_start_convert(s);
319
+ }
320
+ } else {
373
+ } else {
321
+ timer_del(&s->conv_timer);
374
+ gen_helper_stg_parallel(cpu_env, addr, tcg_rt);
322
+ }
375
}
323
+ }
376
} else {
324
+}
377
- tcg_rt = cpu_reg_sp(s, rt);
325
+
378
- if (!s->ata) {
326
+static uint64_t npcm7xx_adc_read(void *opaque, hwaddr offset, unsigned size)
379
- /*
327
+{
380
- * For STG and ST2G, we need to check alignment and probe memory.
328
+ uint64_t value = 0;
381
- * TODO: For STZG and STZ2G, we could rely on the stores below,
329
+ NPCM7xxADCState *s = opaque;
382
- * at least for system mode; user-only won't enforce alignment.
330
+
383
- */
331
+ switch (offset) {
384
- if (is_pair) {
332
+ case A_NPCM7XX_ADC_CON:
385
- gen_helper_st2g_stub(cpu_env, addr);
333
+ value = s->con;
386
- } else {
334
+ break;
387
- gen_helper_stg_stub(cpu_env, addr);
335
+
388
- }
336
+ case A_NPCM7XX_ADC_DATA:
389
- } else if (tb_cflags(s->base.tb) & CF_PARALLEL) {
337
+ value = s->data;
390
- if (is_pair) {
338
+ break;
391
- gen_helper_st2g_parallel(cpu_env, addr, tcg_rt);
339
+
392
- } else {
340
+ default:
393
- gen_helper_stg_parallel(cpu_env, addr, tcg_rt);
341
+ qemu_log_mask(LOG_GUEST_ERROR,
394
- }
342
+ "%s: invalid offset 0x%04" HWADDR_PRIx "\n",
395
+ if (is_pair) {
343
+ __func__, offset);
396
+ gen_helper_st2g(cpu_env, addr, tcg_rt);
344
+ break;
397
} else {
345
+ }
398
- if (is_pair) {
346
+
399
- gen_helper_st2g(cpu_env, addr, tcg_rt);
347
+ trace_npcm7xx_adc_read(DEVICE(s)->canonical_path, offset, value);
400
- } else {
348
+ return value;
401
- gen_helper_stg(cpu_env, addr, tcg_rt);
349
+}
402
- }
350
+
403
+ gen_helper_stg(cpu_env, addr, tcg_rt);
351
+static void npcm7xx_adc_write(void *opaque, hwaddr offset, uint64_t v,
404
}
352
+ unsigned size)
405
}
353
+{
406
354
+ NPCM7xxADCState *s = opaque;
407
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_tag(DisasContext *s, uint32_t insn)
355
+
408
}
356
+ trace_npcm7xx_adc_write(DEVICE(s)->canonical_path, offset, v);
409
}
357
+ switch (offset) {
410
358
+ case A_NPCM7XX_ADC_CON:
411
- if (index != 0) {
359
+ npcm7xx_adc_write_con(s, v);
412
+ if (a->w) {
360
+ break;
413
/* pre-index or post-index */
361
+
414
- if (index < 0) {
362
+ case A_NPCM7XX_ADC_DATA:
415
+ if (a->p) {
363
+ qemu_log_mask(LOG_GUEST_ERROR,
416
/* post-index */
364
+ "%s: register @ 0x%04" HWADDR_PRIx " is read-only\n",
417
- tcg_gen_addi_i64(addr, addr, offset);
365
+ __func__, offset);
418
+ tcg_gen_addi_i64(addr, addr, a->imm);
366
+ break;
419
}
367
+
420
- tcg_gen_mov_i64(cpu_reg_sp(s, rn), addr);
368
+ default:
421
+ tcg_gen_mov_i64(cpu_reg_sp(s, a->rn), addr);
369
+ qemu_log_mask(LOG_GUEST_ERROR,
422
}
370
+ "%s: invalid offset 0x%04" HWADDR_PRIx "\n",
423
+ return true;
371
+ __func__, offset);
372
+ break;
373
+ }
374
+
375
+}
376
+
377
+static const struct MemoryRegionOps npcm7xx_adc_ops = {
378
+ .read = npcm7xx_adc_read,
379
+ .write = npcm7xx_adc_write,
380
+ .endianness = DEVICE_LITTLE_ENDIAN,
381
+ .valid = {
382
+ .min_access_size = 4,
383
+ .max_access_size = 4,
384
+ .unaligned = false,
385
+ },
386
+};
387
+
388
+static void npcm7xx_adc_enter_reset(Object *obj, ResetType type)
389
+{
390
+ NPCM7xxADCState *s = NPCM7XX_ADC(obj);
391
+
392
+ npcm7xx_adc_reset(s);
393
+}
394
+
395
+static void npcm7xx_adc_hold_reset(Object *obj)
396
+{
397
+ NPCM7xxADCState *s = NPCM7XX_ADC(obj);
398
+
399
+ qemu_irq_lower(s->irq);
400
+}
401
+
402
+static void npcm7xx_adc_init(Object *obj)
403
+{
404
+ NPCM7xxADCState *s = NPCM7XX_ADC(obj);
405
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
406
+ int i;
407
+
408
+ sysbus_init_irq(sbd, &s->irq);
409
+
410
+ timer_init_ns(&s->conv_timer, QEMU_CLOCK_VIRTUAL,
411
+ npcm7xx_adc_convert_done, s);
412
+ memory_region_init_io(&s->iomem, obj, &npcm7xx_adc_ops, s,
413
+ TYPE_NPCM7XX_ADC, 4 * KiB);
414
+ sysbus_init_mmio(sbd, &s->iomem);
415
+ s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL);
416
+
417
+ for (i = 0; i < NPCM7XX_ADC_NUM_INPUTS; ++i) {
418
+ object_property_add_uint32_ptr(obj, "adci[*]",
419
+ &s->adci[i], OBJ_PROP_FLAG_WRITE);
420
+ }
421
+ object_property_add_uint32_ptr(obj, "vref",
422
+ &s->vref, OBJ_PROP_FLAG_WRITE);
423
+ npcm7xx_adc_calibrate(s);
424
+}
425
+
426
+static const VMStateDescription vmstate_npcm7xx_adc = {
427
+ .name = "npcm7xx-adc",
428
+ .version_id = 0,
429
+ .minimum_version_id = 0,
430
+ .fields = (VMStateField[]) {
431
+ VMSTATE_TIMER(conv_timer, NPCM7xxADCState),
432
+ VMSTATE_UINT32(con, NPCM7xxADCState),
433
+ VMSTATE_UINT32(data, NPCM7xxADCState),
434
+ VMSTATE_CLOCK(clock, NPCM7xxADCState),
435
+ VMSTATE_UINT32_ARRAY(adci, NPCM7xxADCState, NPCM7XX_ADC_NUM_INPUTS),
436
+ VMSTATE_UINT32(vref, NPCM7xxADCState),
437
+ VMSTATE_UINT32(iref, NPCM7xxADCState),
438
+ VMSTATE_UINT16_ARRAY(calibration_r_values, NPCM7xxADCState,
439
+ NPCM7XX_ADC_NUM_CALIB),
440
+ VMSTATE_END_OF_LIST(),
441
+ },
442
+};
443
+
444
+static Property npcm7xx_timer_properties[] = {
445
+ DEFINE_PROP_UINT32("iref", NPCM7xxADCState, iref, NPCM7XX_ADC_DEFAULT_IREF),
446
+ DEFINE_PROP_END_OF_LIST(),
447
+};
448
+
449
+static void npcm7xx_adc_class_init(ObjectClass *klass, void *data)
450
+{
451
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
452
+ DeviceClass *dc = DEVICE_CLASS(klass);
453
+
454
+ dc->desc = "NPCM7xx ADC Module";
455
+ dc->vmsd = &vmstate_npcm7xx_adc;
456
+ rc->phases.enter = npcm7xx_adc_enter_reset;
457
+ rc->phases.hold = npcm7xx_adc_hold_reset;
458
+
459
+ device_class_set_props(dc, npcm7xx_timer_properties);
460
+}
461
+
462
+static const TypeInfo npcm7xx_adc_info = {
463
+ .name = TYPE_NPCM7XX_ADC,
464
+ .parent = TYPE_SYS_BUS_DEVICE,
465
+ .instance_size = sizeof(NPCM7xxADCState),
466
+ .class_init = npcm7xx_adc_class_init,
467
+ .instance_init = npcm7xx_adc_init,
468
+};
469
+
470
+static void npcm7xx_adc_register_types(void)
471
+{
472
+ type_register_static(&npcm7xx_adc_info);
473
+}
474
+
475
+type_init(npcm7xx_adc_register_types);
476
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
477
index XXXXXXX..XXXXXXX 100644
478
--- a/hw/arm/npcm7xx.c
479
+++ b/hw/arm/npcm7xx.c
480
@@ -XXX,XX +XXX,XX @@
481
#define NPCM7XX_EHCI_BA (0xf0806000)
482
#define NPCM7XX_OHCI_BA (0xf0807000)
483
484
+/* ADC Module */
485
+#define NPCM7XX_ADC_BA (0xf000c000)
486
+
487
/* Internal AHB SRAM */
488
#define NPCM7XX_RAM3_BA (0xc0008000)
489
#define NPCM7XX_RAM3_SZ (4 * KiB)
490
@@ -XXX,XX +XXX,XX @@
491
#define NPCM7XX_ROM_BA (0xffff0000)
492
#define NPCM7XX_ROM_SZ (64 * KiB)
493
494
+
495
/* Clock configuration values to be fixed up when bypassing bootloader */
496
497
/* Run PLL1 at 1600 MHz */
498
@@ -XXX,XX +XXX,XX @@
499
* interrupts.
500
*/
501
enum NPCM7xxInterrupt {
502
+ NPCM7XX_ADC_IRQ = 0,
503
NPCM7XX_UART0_IRQ = 2,
504
NPCM7XX_UART1_IRQ,
505
NPCM7XX_UART2_IRQ,
506
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init_fuses(NPCM7xxState *s)
507
sizeof(value));
508
}
424
}
509
425
510
+static void npcm7xx_write_adc_calibration(NPCM7xxState *s)
426
-/* Loads and stores */
511
+{
427
-static void disas_ldst(DisasContext *s, uint32_t insn)
512
+ /* Both ADC and the fuse array must have realized. */
428
-{
513
+ QEMU_BUILD_BUG_ON(sizeof(s->adc.calibration_r_values) != 4);
429
- switch (extract32(insn, 24, 6)) {
514
+ npcm7xx_otp_array_write(&s->fuse_array, s->adc.calibration_r_values,
430
- case 0x19:
515
+ NPCM7XX_FUSE_ADC_CALIB, sizeof(s->adc.calibration_r_values));
431
- if (extract32(insn, 21, 1) != 0) {
516
+}
432
- disas_ldst_tag(s, insn);
517
+
433
- } else {
518
static qemu_irq npcm7xx_irq(NPCM7xxState *s, int n)
434
- unallocated_encoding(s);
435
- }
436
- break;
437
- default:
438
- unallocated_encoding(s);
439
- break;
440
- }
441
-}
442
+TRANS_FEAT(STG, aa64_mte_insn_reg, do_STG, a, false, false)
443
+TRANS_FEAT(STZG, aa64_mte_insn_reg, do_STG, a, true, false)
444
+TRANS_FEAT(ST2G, aa64_mte_insn_reg, do_STG, a, false, true)
445
+TRANS_FEAT(STZ2G, aa64_mte_insn_reg, do_STG, a, true, true)
446
447
typedef void ArithTwoOp(TCGv_i64, TCGv_i64, TCGv_i64);
448
449
@@ -XXX,XX +XXX,XX @@ static bool btype_destination_ok(uint32_t insn, bool bt, int btype)
450
static void disas_a64_legacy(DisasContext *s, uint32_t insn)
519
{
451
{
520
return qdev_get_gpio_in(DEVICE(&s->a9mpcore), n);
452
switch (extract32(insn, 25, 4)) {
521
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
453
- case 0x4:
522
TYPE_NPCM7XX_FUSE_ARRAY);
454
- case 0x6:
523
object_initialize_child(obj, "mc", &s->mc, TYPE_NPCM7XX_MC);
455
- case 0xc:
524
object_initialize_child(obj, "rng", &s->rng, TYPE_NPCM7XX_RNG);
456
- case 0xe: /* Loads and stores */
525
+ object_initialize_child(obj, "adc", &s->adc, TYPE_NPCM7XX_ADC);
457
- disas_ldst(s, insn);
526
458
- break;
527
for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
459
case 0x5:
528
object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER);
460
case 0xd: /* Data processing - register */
529
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
461
disas_data_proc_reg(s, insn);
530
sysbus_realize(SYS_BUS_DEVICE(&s->mc), &error_abort);
531
sysbus_mmio_map(SYS_BUS_DEVICE(&s->mc), 0, NPCM7XX_MC_BA);
532
533
+ /* ADC Modules. Cannot fail. */
534
+ qdev_connect_clock_in(DEVICE(&s->adc), "clock", qdev_get_clock_out(
535
+ DEVICE(&s->clk), "adc-clock"));
536
+ sysbus_realize(SYS_BUS_DEVICE(&s->adc), &error_abort);
537
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->adc), 0, NPCM7XX_ADC_BA);
538
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0,
539
+ npcm7xx_irq(s, NPCM7XX_ADC_IRQ));
540
+ npcm7xx_write_adc_calibration(s);
541
+
542
/* Timer Modules (TIM). Cannot fail. */
543
QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_tim_addr) != ARRAY_SIZE(s->tim));
544
for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
545
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
546
create_unimplemented_device("npcm7xx.vdmx", 0xe0800000, 4 * KiB);
547
create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * KiB);
548
create_unimplemented_device("npcm7xx.kcs", 0xf0007000, 4 * KiB);
549
- create_unimplemented_device("npcm7xx.adc", 0xf000c000, 4 * KiB);
550
create_unimplemented_device("npcm7xx.gfxi", 0xf000e000, 4 * KiB);
551
create_unimplemented_device("npcm7xx.gpio[0]", 0xf0010000, 4 * KiB);
552
create_unimplemented_device("npcm7xx.gpio[1]", 0xf0011000, 4 * KiB);
553
diff --git a/tests/qtest/npcm7xx_adc-test.c b/tests/qtest/npcm7xx_adc-test.c
554
new file mode 100644
555
index XXXXXXX..XXXXXXX
556
--- /dev/null
557
+++ b/tests/qtest/npcm7xx_adc-test.c
558
@@ -XXX,XX +XXX,XX @@
559
+/*
560
+ * QTests for Nuvoton NPCM7xx ADCModules.
561
+ *
562
+ * Copyright 2020 Google LLC
563
+ *
564
+ * This program is free software; you can redistribute it and/or modify it
565
+ * under the terms of the GNU General Public License as published by the
566
+ * Free Software Foundation; either version 2 of the License, or
567
+ * (at your option) any later version.
568
+ *
569
+ * This program is distributed in the hope that it will be useful, but WITHOUT
570
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
571
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
572
+ * for more details.
573
+ */
574
+
575
+#include "qemu/osdep.h"
576
+#include "qemu/bitops.h"
577
+#include "qemu/timer.h"
578
+#include "libqos/libqtest.h"
579
+#include "qapi/qmp/qdict.h"
580
+
581
+#define REF_HZ (25000000)
582
+
583
+#define CON_OFFSET 0x0
584
+#define DATA_OFFSET 0x4
585
+
586
+#define NUM_INPUTS 8
587
+#define DEFAULT_IREF 2000000
588
+#define CONV_CYCLES 20
589
+#define RESET_CYCLES 10
590
+#define R0_INPUT 500000
591
+#define R1_INPUT 1500000
592
+#define MAX_RESULT 1023
593
+
594
+#define DEFAULT_CLKDIV 5
595
+
596
+#define FUSE_ARRAY_BA 0xf018a000
597
+#define FCTL_OFFSET 0x14
598
+#define FST_OFFSET 0x0
599
+#define FADDR_OFFSET 0x4
600
+#define FDATA_OFFSET 0x8
601
+#define ADC_CALIB_ADDR 24
602
+#define FUSE_READ 0x2
603
+
604
+/* Register field definitions. */
605
+#define CON_MUX(rv) ((rv) << 24)
606
+#define CON_INT_EN BIT(21)
607
+#define CON_REFSEL BIT(19)
608
+#define CON_INT BIT(18)
609
+#define CON_EN BIT(17)
610
+#define CON_RST BIT(16)
611
+#define CON_CONV BIT(14)
612
+#define CON_DIV(rv) extract32(rv, 1, 8)
613
+
614
+#define FST_RDST BIT(1)
615
+#define FDATA_MASK 0xff
616
+
617
+#define MAX_ERROR 10000
618
+#define MIN_CALIB_INPUT 100000
619
+#define MAX_CALIB_INPUT 1800000
620
+
621
+static const uint32_t input_list[] = {
622
+ 100000,
623
+ 500000,
624
+ 1000000,
625
+ 1500000,
626
+ 1800000,
627
+ 2000000,
628
+};
629
+
630
+static const uint32_t vref_list[] = {
631
+ 2000000,
632
+ 2200000,
633
+ 2500000,
634
+};
635
+
636
+static const uint32_t iref_list[] = {
637
+ 1800000,
638
+ 1900000,
639
+ 2000000,
640
+ 2100000,
641
+ 2200000,
642
+};
643
+
644
+static const uint32_t div_list[] = {0, 1, 3, 7, 15};
645
+
646
+typedef struct ADC {
647
+ int irq;
648
+ uint64_t base_addr;
649
+} ADC;
650
+
651
+ADC adc = {
652
+ .irq = 0,
653
+ .base_addr = 0xf000c000
654
+};
655
+
656
+static uint32_t adc_read_con(QTestState *qts, const ADC *adc)
657
+{
658
+ return qtest_readl(qts, adc->base_addr + CON_OFFSET);
659
+}
660
+
661
+static void adc_write_con(QTestState *qts, const ADC *adc, uint32_t value)
662
+{
663
+ qtest_writel(qts, adc->base_addr + CON_OFFSET, value);
664
+}
665
+
666
+static uint32_t adc_read_data(QTestState *qts, const ADC *adc)
667
+{
668
+ return qtest_readl(qts, adc->base_addr + DATA_OFFSET);
669
+}
670
+
671
+static uint32_t adc_calibrate(uint32_t measured, uint32_t *rv)
672
+{
673
+ return R0_INPUT + (R1_INPUT - R0_INPUT) * (int32_t)(measured - rv[0])
674
+ / (int32_t)(rv[1] - rv[0]);
675
+}
676
+
677
+static void adc_qom_set(QTestState *qts, const ADC *adc,
678
+ const char *name, uint32_t value)
679
+{
680
+ QDict *response;
681
+ const char *path = "/machine/soc/adc";
682
+
683
+ g_test_message("Setting properties %s of %s with value %u",
684
+ name, path, value);
685
+ response = qtest_qmp(qts, "{ 'execute': 'qom-set',"
686
+ " 'arguments': { 'path': %s, 'property': %s, 'value': %u}}",
687
+ path, name, value);
688
+ /* The qom set message returns successfully. */
689
+ g_assert_true(qdict_haskey(response, "return"));
690
+}
691
+
692
+static void adc_write_input(QTestState *qts, const ADC *adc,
693
+ uint32_t index, uint32_t value)
694
+{
695
+ char name[100];
696
+
697
+ sprintf(name, "adci[%u]", index);
698
+ adc_qom_set(qts, adc, name, value);
699
+}
700
+
701
+static void adc_write_vref(QTestState *qts, const ADC *adc, uint32_t value)
702
+{
703
+ adc_qom_set(qts, adc, "vref", value);
704
+}
705
+
706
+static uint32_t adc_calculate_output(uint32_t input, uint32_t ref)
707
+{
708
+ uint32_t output;
709
+
710
+ g_assert_cmpuint(input, <=, ref);
711
+ output = (input * (MAX_RESULT + 1)) / ref;
712
+ if (output > MAX_RESULT) {
713
+ output = MAX_RESULT;
714
+ }
715
+
716
+ return output;
717
+}
718
+
719
+static uint32_t adc_prescaler(QTestState *qts, const ADC *adc)
720
+{
721
+ uint32_t div = extract32(adc_read_con(qts, adc), 1, 8);
722
+
723
+ return 2 * (div + 1);
724
+}
725
+
726
+static int64_t adc_calculate_steps(uint32_t cycles, uint32_t prescale,
727
+ uint32_t clkdiv)
728
+{
729
+ return (NANOSECONDS_PER_SECOND / (REF_HZ >> clkdiv)) * cycles * prescale;
730
+}
731
+
732
+static void adc_wait_conv_finished(QTestState *qts, const ADC *adc,
733
+ uint32_t clkdiv)
734
+{
735
+ uint32_t prescaler = adc_prescaler(qts, adc);
736
+
737
+ /*
738
+ * ADC should takes roughly 20 cycles to convert one sample. So we assert it
739
+ * should take 10~30 cycles here.
740
+ */
741
+ qtest_clock_step(qts, adc_calculate_steps(CONV_CYCLES / 2, prescaler,
742
+ clkdiv));
743
+ /* ADC is still converting. */
744
+ g_assert_true(adc_read_con(qts, adc) & CON_CONV);
745
+ qtest_clock_step(qts, adc_calculate_steps(CONV_CYCLES, prescaler, clkdiv));
746
+ /* ADC has finished conversion. */
747
+ g_assert_false(adc_read_con(qts, adc) & CON_CONV);
748
+}
749
+
750
+/* Check ADC can be reset to default value. */
751
+static void test_init(gconstpointer adc_p)
752
+{
753
+ const ADC *adc = adc_p;
754
+
755
+ QTestState *qts = qtest_init("-machine quanta-gsj");
756
+ adc_write_con(qts, adc, CON_REFSEL | CON_INT);
757
+ g_assert_cmphex(adc_read_con(qts, adc), ==, CON_REFSEL);
758
+ qtest_quit(qts);
759
+}
760
+
761
+/* Check ADC can convert from an internal reference. */
762
+static void test_convert_internal(gconstpointer adc_p)
763
+{
764
+ const ADC *adc = adc_p;
765
+ uint32_t index, input, output, expected_output;
766
+ QTestState *qts = qtest_init("-machine quanta-gsj");
767
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
768
+
769
+ for (index = 0; index < NUM_INPUTS; ++index) {
770
+ for (size_t i = 0; i < ARRAY_SIZE(input_list); ++i) {
771
+ input = input_list[i];
772
+ expected_output = adc_calculate_output(input, DEFAULT_IREF);
773
+
774
+ adc_write_input(qts, adc, index, input);
775
+ adc_write_con(qts, adc, CON_MUX(index) | CON_REFSEL | CON_INT |
776
+ CON_EN | CON_CONV);
777
+ adc_wait_conv_finished(qts, adc, DEFAULT_CLKDIV);
778
+ g_assert_cmphex(adc_read_con(qts, adc), ==, CON_MUX(index) |
779
+ CON_REFSEL | CON_EN);
780
+ g_assert_false(qtest_get_irq(qts, adc->irq));
781
+ output = adc_read_data(qts, adc);
782
+ g_assert_cmpuint(output, ==, expected_output);
783
+ }
784
+ }
785
+
786
+ qtest_quit(qts);
787
+}
788
+
789
+/* Check ADC can convert from an external reference. */
790
+static void test_convert_external(gconstpointer adc_p)
791
+{
792
+ const ADC *adc = adc_p;
793
+ uint32_t index, input, vref, output, expected_output;
794
+ QTestState *qts = qtest_init("-machine quanta-gsj");
795
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
796
+
797
+ for (index = 0; index < NUM_INPUTS; ++index) {
798
+ for (size_t i = 0; i < ARRAY_SIZE(input_list); ++i) {
799
+ for (size_t j = 0; j < ARRAY_SIZE(vref_list); ++j) {
800
+ input = input_list[i];
801
+ vref = vref_list[j];
802
+ expected_output = adc_calculate_output(input, vref);
803
+
804
+ adc_write_input(qts, adc, index, input);
805
+ adc_write_vref(qts, adc, vref);
806
+ adc_write_con(qts, adc, CON_MUX(index) | CON_INT | CON_EN |
807
+ CON_CONV);
808
+ adc_wait_conv_finished(qts, adc, DEFAULT_CLKDIV);
809
+ g_assert_cmphex(adc_read_con(qts, adc), ==,
810
+ CON_MUX(index) | CON_EN);
811
+ g_assert_false(qtest_get_irq(qts, adc->irq));
812
+ output = adc_read_data(qts, adc);
813
+ g_assert_cmpuint(output, ==, expected_output);
814
+ }
815
+ }
816
+ }
817
+
818
+ qtest_quit(qts);
819
+}
820
+
821
+/* Check ADC interrupt files if and only if CON_INT_EN is set. */
822
+static void test_interrupt(gconstpointer adc_p)
823
+{
824
+ const ADC *adc = adc_p;
825
+ uint32_t index, input, output, expected_output;
826
+ QTestState *qts = qtest_init("-machine quanta-gsj");
827
+
828
+ index = 1;
829
+ input = input_list[1];
830
+ expected_output = adc_calculate_output(input, DEFAULT_IREF);
831
+
832
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
833
+ adc_write_input(qts, adc, index, input);
834
+ g_assert_false(qtest_get_irq(qts, adc->irq));
835
+ adc_write_con(qts, adc, CON_MUX(index) | CON_INT_EN | CON_REFSEL | CON_INT
836
+ | CON_EN | CON_CONV);
837
+ adc_wait_conv_finished(qts, adc, DEFAULT_CLKDIV);
838
+ g_assert_cmphex(adc_read_con(qts, adc), ==, CON_MUX(index) | CON_INT_EN
839
+ | CON_REFSEL | CON_INT | CON_EN);
840
+ g_assert_true(qtest_get_irq(qts, adc->irq));
841
+ output = adc_read_data(qts, adc);
842
+ g_assert_cmpuint(output, ==, expected_output);
843
+
844
+ qtest_quit(qts);
845
+}
846
+
847
+/* Check ADC is reset after setting ADC_RST for 10 ADC cycles. */
848
+static void test_reset(gconstpointer adc_p)
849
+{
850
+ const ADC *adc = adc_p;
851
+ QTestState *qts = qtest_init("-machine quanta-gsj");
852
+
853
+ for (size_t i = 0; i < ARRAY_SIZE(div_list); ++i) {
854
+ uint32_t div = div_list[i];
855
+
856
+ adc_write_con(qts, adc, CON_INT | CON_EN | CON_RST | CON_DIV(div));
857
+ qtest_clock_step(qts, adc_calculate_steps(RESET_CYCLES,
858
+ adc_prescaler(qts, adc), DEFAULT_CLKDIV));
859
+ g_assert_false(adc_read_con(qts, adc) & CON_EN);
860
+ }
861
+ qtest_quit(qts);
862
+}
863
+
864
+/* Check ADC Calibration works as desired. */
865
+static void test_calibrate(gconstpointer adc_p)
866
+{
867
+ int i, j;
868
+ const ADC *adc = adc_p;
869
+
870
+ for (j = 0; j < ARRAY_SIZE(iref_list); ++j) {
871
+ uint32_t iref = iref_list[j];
872
+ uint32_t expected_rv[] = {
873
+ adc_calculate_output(R0_INPUT, iref),
874
+ adc_calculate_output(R1_INPUT, iref),
875
+ };
876
+ char buf[100];
877
+ QTestState *qts;
878
+
879
+ sprintf(buf, "-machine quanta-gsj -global npcm7xx-adc.iref=%u", iref);
880
+ qts = qtest_init(buf);
881
+
882
+ /* Check the converted value is correct using the calibration value. */
883
+ for (i = 0; i < ARRAY_SIZE(input_list); ++i) {
884
+ uint32_t input;
885
+ uint32_t output;
886
+ uint32_t expected_output;
887
+ uint32_t calibrated_voltage;
888
+ uint32_t index = 0;
889
+
890
+ input = input_list[i];
891
+ /* Calibration only works for input range 0.1V ~ 1.8V. */
892
+ if (input < MIN_CALIB_INPUT || input > MAX_CALIB_INPUT) {
893
+ continue;
894
+ }
895
+ expected_output = adc_calculate_output(input, iref);
896
+
897
+ adc_write_input(qts, adc, index, input);
898
+ adc_write_con(qts, adc, CON_MUX(index) | CON_REFSEL | CON_INT |
899
+ CON_EN | CON_CONV);
900
+ adc_wait_conv_finished(qts, adc, DEFAULT_CLKDIV);
901
+ g_assert_cmphex(adc_read_con(qts, adc), ==,
902
+ CON_REFSEL | CON_MUX(index) | CON_EN);
903
+ output = adc_read_data(qts, adc);
904
+ g_assert_cmpuint(output, ==, expected_output);
905
+
906
+ calibrated_voltage = adc_calibrate(output, expected_rv);
907
+ g_assert_cmpuint(calibrated_voltage, >, input - MAX_ERROR);
908
+ g_assert_cmpuint(calibrated_voltage, <, input + MAX_ERROR);
909
+ }
910
+
911
+ qtest_quit(qts);
912
+ }
913
+}
914
+
915
+static void adc_add_test(const char *name, const ADC* wd,
916
+ GTestDataFunc fn)
917
+{
918
+ g_autofree char *full_name = g_strdup_printf("npcm7xx_adc/%s", name);
919
+ qtest_add_data_func(full_name, wd, fn);
920
+}
921
+#define add_test(name, td) adc_add_test(#name, td, test_##name)
922
+
923
+int main(int argc, char **argv)
924
+{
925
+ g_test_init(&argc, &argv, NULL);
926
+
927
+ add_test(init, &adc);
928
+ add_test(convert_internal, &adc);
929
+ add_test(convert_external, &adc);
930
+ add_test(interrupt, &adc);
931
+ add_test(reset, &adc);
932
+ add_test(calibrate, &adc);
933
+
934
+ return g_test_run();
935
+}
936
diff --git a/hw/adc/meson.build b/hw/adc/meson.build
937
index XXXXXXX..XXXXXXX 100644
938
--- a/hw/adc/meson.build
939
+++ b/hw/adc/meson.build
940
@@ -1 +1,2 @@
941
softmmu_ss.add(when: 'CONFIG_STM32F2XX_ADC', if_true: files('stm32f2xx_adc.c'))
942
+softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_adc.c'))
943
diff --git a/hw/adc/trace-events b/hw/adc/trace-events
944
new file mode 100644
945
index XXXXXXX..XXXXXXX
946
--- /dev/null
947
+++ b/hw/adc/trace-events
948
@@ -XXX,XX +XXX,XX @@
949
+# See docs/devel/tracing.txt for syntax documentation.
950
+
951
+# npcm7xx_adc.c
952
+npcm7xx_adc_read(const char *id, uint64_t offset, uint32_t value) " %s offset: 0x%04" PRIx64 " value 0x%04" PRIx32
953
+npcm7xx_adc_write(const char *id, uint64_t offset, uint32_t value) "%s offset: 0x%04" PRIx64 " value 0x%04" PRIx32
954
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
955
index XXXXXXX..XXXXXXX 100644
956
--- a/tests/qtest/meson.build
957
+++ b/tests/qtest/meson.build
958
@@ -XXX,XX +XXX,XX @@ qtests_sparc64 = \
959
['prom-env-test', 'boot-serial-test']
960
961
qtests_npcm7xx = \
962
- ['npcm7xx_gpio-test',
963
+ ['npcm7xx_adc-test',
964
+ 'npcm7xx_gpio-test',
965
'npcm7xx_rng-test',
966
'npcm7xx_timer-test',
967
'npcm7xx_watchdog_timer-test']
968
--
462
--
969
2.20.1
463
2.34.1
970
971
diff view generated by jsdifflib
1
From: Leif Lindholm <leif@nuviainc.com>
1
In commit 2c5fa0778c3b430 we fixed an endianness bug in the Allwinner
2
A10 PIC model; however in the process we introduced a regression.
3
This is because the old code was robust against the incoming 'level'
4
argument being something other than 0 or 1, whereas the new code was
5
not.
2
6
3
SBSS -> SSBS
7
In particular, the allwinner-sdhost code treats its IRQ line
8
as 0-vs-non-0 rather than 0-vs-1, so when the SD controller
9
set its IRQ line for any reason other than transmit the
10
interrupt controller would ignore it. The observed effect
11
was a guest timeout when rebooting the guest kernel.
4
12
5
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
13
Handle level values other than 0 or 1, to restore the old
6
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
14
behaviour.
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
15
8
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
16
Fixes: 2c5fa0778c3b430 ("hw/intc/allwinner-a10-pic: Don't use set_bit()/clear_bit()")
9
Message-id: 20210108185154.8108-2-leif@nuviainc.com
17
Cc: qemu-stable@nongnu.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
18
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
19
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
20
Tested-by: Guenter Roeck <linux@roeck-us.net>
21
Message-id: 20230606104609.3692557-2-peter.maydell@linaro.org
11
---
22
---
12
target/arm/cpu.h | 2 +-
23
hw/intc/allwinner-a10-pic.c | 2 +-
13
1 file changed, 1 insertion(+), 1 deletion(-)
24
1 file changed, 1 insertion(+), 1 deletion(-)
14
25
15
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
26
diff --git a/hw/intc/allwinner-a10-pic.c b/hw/intc/allwinner-a10-pic.c
16
index XXXXXXX..XXXXXXX 100644
27
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/cpu.h
28
--- a/hw/intc/allwinner-a10-pic.c
18
+++ b/target/arm/cpu.h
29
+++ b/hw/intc/allwinner-a10-pic.c
19
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64PFR0, RAS, 28, 4)
30
@@ -XXX,XX +XXX,XX @@ static void aw_a10_pic_set_irq(void *opaque, int irq, int level)
20
FIELD(ID_AA64PFR0, SVE, 32, 4)
31
AwA10PICState *s = opaque;
21
32
uint32_t *pending_reg = &s->irq_pending[irq / 32];
22
FIELD(ID_AA64PFR1, BT, 0, 4)
33
23
-FIELD(ID_AA64PFR1, SBSS, 4, 4)
34
- *pending_reg = deposit32(*pending_reg, irq % 32, 1, level);
24
+FIELD(ID_AA64PFR1, SSBS, 4, 4)
35
+ *pending_reg = deposit32(*pending_reg, irq % 32, 1, !!level);
25
FIELD(ID_AA64PFR1, MTE, 8, 4)
36
aw_a10_pic_update(s);
26
FIELD(ID_AA64PFR1, RAS_FRAC, 12, 4)
37
}
27
38
28
--
39
--
29
2.20.1
40
2.34.1
30
41
31
42
diff view generated by jsdifflib
1
From: Leif Lindholm <leif@nuviainc.com>
1
QEMU allows qemu_irq lines to transfer arbitrary integers. However
2
the convention is that for a simple IRQ line the values transferred
3
are always 0 and 1. The A10 SD controller device instead assumes a
4
0-vs-non-0 convention, which happens to work with the interrupt
5
controller it is wired up to.
2
6
3
The AArch64 view of CLIDR_EL1 extends the ICB field to include also bit
7
Coerce the value to boolean to follow our usual convention.
4
32, as well as adding a Ttype<n> field when FEAT_MTE is implemented.
5
Extend the clidr field to be able to hold this context.
6
8
7
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
11
Message-id: 20210108185154.8108-3-leif@nuviainc.com
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
11
Tested-by: Guenter Roeck <linux@roeck-us.net>
12
Message-id: 20230606104609.3692557-3-peter.maydell@linaro.org
13
---
13
---
14
target/arm/cpu.h | 2 +-
14
hw/sd/allwinner-sdhost.c | 2 +-
15
1 file changed, 1 insertion(+), 1 deletion(-)
15
1 file changed, 1 insertion(+), 1 deletion(-)
16
16
17
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
17
diff --git a/hw/sd/allwinner-sdhost.c b/hw/sd/allwinner-sdhost.c
18
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/cpu.h
19
--- a/hw/sd/allwinner-sdhost.c
20
+++ b/target/arm/cpu.h
20
+++ b/hw/sd/allwinner-sdhost.c
21
@@ -XXX,XX +XXX,XX @@ struct ARMCPU {
21
@@ -XXX,XX +XXX,XX @@ static void allwinner_sdhost_update_irq(AwSdHostState *s)
22
uint32_t id_afr0;
22
}
23
uint64_t id_aa64afr0;
23
24
uint64_t id_aa64afr1;
24
trace_allwinner_sdhost_update_irq(irq);
25
- uint32_t clidr;
25
- qemu_set_irq(s->irq, irq);
26
+ uint64_t clidr;
26
+ qemu_set_irq(s->irq, !!irq);
27
uint64_t mp_affinity; /* MP ID without feature bits */
27
}
28
/* The elements of this array are the CCSIDR values for each cache,
28
29
* in the order L1DCache, L1ICache, L2DCache, L2ICache, etc.
29
static void allwinner_sdhost_update_transfer_cnt(AwSdHostState *s,
30
--
30
--
31
2.20.1
31
2.34.1
32
32
33
33
diff view generated by jsdifflib
1
A copy-and-paste error meant that the return value for register offset 0x44
1
The nrf51_timer has a free-running counter which we implement using
2
(the RX Status FIFO PEEK register) returned a byte from a bogus offset in
2
the pattern of using two fields (update_counter_ns, counter) to track
3
the rx status FIFO. Fix the typo.
3
the last point at which we calculated the counter value, and the
4
counter value at that time. Then we can find the current counter
5
value by converting the difference in wall-clock time between then
6
and now to a tick count that we need to add to the counter value.
7
8
Unfortunately the nrf51_timer's implementation of this has a bug
9
which means it loses time every time update_counter() is called.
10
After updating s->counter it always sets s->update_counter_ns to
11
'now', even though the actual point when s->counter hit the new value
12
will be some point in the past (half a tick, say). In the worst case
13
(guest code in a tight loop reading the counter, icount mode) the
14
counter is continually queried less than a tick after it was last
15
read, so s->counter never advances but s->update_counter_ns does, and
16
the guest never makes forward progress.
17
18
The fix for this is to only advance update_counter_ns to the
19
timestamp of the last tick, not all the way to 'now'. (This is the
20
pattern used in hw/misc/mps2-fpgaio.c's counter.)
4
21
5
Cc: qemu-stable@nongnu.org
22
Cc: qemu-stable@nongnu.org
6
Fixes: https://bugs.launchpad.net/qemu/+bug/1904954
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
23
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
24
Reviewed-by: Joel Stanley <joel@jms.id.au>
9
Message-id: 20210108180401.2263-2-peter.maydell@linaro.org
25
Message-id: 20230606134917.3782215-1-peter.maydell@linaro.org
10
---
26
---
11
hw/net/lan9118.c | 2 +-
27
hw/timer/nrf51_timer.c | 7 ++++++-
12
1 file changed, 1 insertion(+), 1 deletion(-)
28
1 file changed, 6 insertions(+), 1 deletion(-)
13
29
14
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
30
diff --git a/hw/timer/nrf51_timer.c b/hw/timer/nrf51_timer.c
15
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/net/lan9118.c
32
--- a/hw/timer/nrf51_timer.c
17
+++ b/hw/net/lan9118.c
33
+++ b/hw/timer/nrf51_timer.c
18
@@ -XXX,XX +XXX,XX @@ static uint64_t lan9118_readl(void *opaque, hwaddr offset,
34
@@ -XXX,XX +XXX,XX @@ static uint32_t update_counter(NRF51TimerState *s, int64_t now)
19
case 0x40:
35
uint32_t ticks = ns_to_ticks(s, now - s->update_counter_ns);
20
return rx_status_fifo_pop(s);
36
21
case 0x44:
37
s->counter = (s->counter + ticks) % BIT(bitwidths[s->bitmode]);
22
- return s->rx_status_fifo[s->tx_status_fifo_head];
38
- s->update_counter_ns = now;
23
+ return s->rx_status_fifo[s->rx_status_fifo_head];
39
+ /*
24
case 0x48:
40
+ * Only advance the sync time to the timestamp of the last tick,
25
return tx_status_fifo_pop(s);
41
+ * not all the way to 'now', so we don't lose time if we do
26
case 0x4c:
42
+ * multiple resyncs in a single tick.
43
+ */
44
+ s->update_counter_ns += ticks_to_ns(s, ticks);
45
return ticks;
46
}
47
27
--
48
--
28
2.20.1
49
2.34.1
29
30
diff view generated by jsdifflib
1
From: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
1
From: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
2
2
3
Signed-off-by: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
3
Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
4
Reviewed-by: Thomas Huth <thuth@redhat.com>
5
Message-id: 20230607092112.655098-1-marcin.juszkiewicz@linaro.org
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
---
7
---
7
target/arm/cpu64.c | 1 +
8
hw/arm/Kconfig | 1 +
8
1 file changed, 1 insertion(+)
9
1 file changed, 1 insertion(+)
9
10
10
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
11
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
11
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
12
--- a/target/arm/cpu64.c
13
--- a/hw/arm/Kconfig
13
+++ b/target/arm/cpu64.c
14
+++ b/hw/arm/Kconfig
14
@@ -XXX,XX +XXX,XX @@ static void aarch64_max_initfn(Object *obj)
15
@@ -XXX,XX +XXX,XX @@ config SBSA_REF
15
t = cpu->isar.id_aa64mmfr2;
16
select PL061 # GPIO
16
t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1);
17
select USB_EHCI_SYSBUS
17
t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1); /* TTCNP */
18
select WDT_SBSA
18
+ t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* TTST */
19
+ select BOCHS_DISPLAY
19
cpu->isar.id_aa64mmfr2 = t;
20
20
21
config SABRELITE
21
/* Replicate the same data to the 32-bit id registers. */
22
bool
22
--
23
--
23
2.20.1
24
2.34.1
24
25
diff view generated by jsdifflib
1
From: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
1
From: Martin Kaiser <martin@kaiser.cx>
2
2
3
This adds for the Small Translation tables extension in AArch64 state.
3
The Linux kernel added a flood check for RX data recently in commit
4
496a4471b7c3 ("serial: imx: work-around for hardware RX flood"). This
5
check uses the wake bit in the UART status register 2. The wake bit
6
indicates that the receiver detected a start bit on the RX line. If the
7
kernel sees a number of RX interrupts without the wake bit being set, it
8
treats this as spurious data and resets the UART port. imx_serial does
9
never set the wake bit and triggers the kernel's flood check.
4
10
5
Signed-off-by: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
11
This patch adds support for the wake bit. wake is set when we receive a
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
12
new character (it's not set for break events). It seems that wake is
13
cleared by the kernel driver, the hardware does not have to clear it
14
automatically after data was read.
15
16
The wake bit can be configured as an interrupt source. Support this
17
mechanism as well.
18
19
Co-developed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
20
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
21
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
22
Signed-off-by: Martin Kaiser <martin@kaiser.cx>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
23
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
---
24
---
9
target/arm/cpu.h | 5 +++++
25
include/hw/char/imx_serial.h | 1 +
10
target/arm/helper.c | 15 +++++++++++++--
26
hw/char/imx_serial.c | 5 ++++-
11
2 files changed, 18 insertions(+), 2 deletions(-)
27
2 files changed, 5 insertions(+), 1 deletion(-)
12
28
13
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
29
diff --git a/include/hw/char/imx_serial.h b/include/hw/char/imx_serial.h
14
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/cpu.h
31
--- a/include/hw/char/imx_serial.h
16
+++ b/target/arm/cpu.h
32
+++ b/include/hw/char/imx_serial.h
17
@@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_uao(const ARMISARegisters *id)
33
@@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_SIMPLE_TYPE(IMXSerialState, IMX_SERIAL)
18
return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, UAO) != 0;
34
35
#define UCR4_DREN BIT(0) /* Receive Data Ready interrupt enable */
36
#define UCR4_TCEN BIT(3) /* TX complete interrupt enable */
37
+#define UCR4_WKEN BIT(7) /* WAKE interrupt enable */
38
39
#define UTS1_TXEMPTY (1<<6)
40
#define UTS1_RXEMPTY (1<<5)
41
diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c
42
index XXXXXXX..XXXXXXX 100644
43
--- a/hw/char/imx_serial.c
44
+++ b/hw/char/imx_serial.c
45
@@ -XXX,XX +XXX,XX @@ static void imx_update(IMXSerialState *s)
46
* TCEN and TXDC are both bit 3
47
* RDR and DREN are both bit 0
48
*/
49
- mask |= s->ucr4 & (UCR4_TCEN | UCR4_DREN);
50
+ mask |= s->ucr4 & (UCR4_WKEN | UCR4_TCEN | UCR4_DREN);
51
52
usr2 = s->usr2 & mask;
53
54
@@ -XXX,XX +XXX,XX @@ static void imx_put_data(void *opaque, uint32_t value)
55
56
static void imx_receive(void *opaque, const uint8_t *buf, int size)
57
{
58
+ IMXSerialState *s = (IMXSerialState *)opaque;
59
+
60
+ s->usr2 |= USR2_WAKE;
61
imx_put_data(opaque, *buf);
19
}
62
}
20
63
21
+static inline bool isar_feature_aa64_st(const ARMISARegisters *id)
22
+{
23
+ return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, ST) != 0;
24
+}
25
+
26
static inline bool isar_feature_aa64_bti(const ARMISARegisters *id)
27
{
28
return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0;
29
diff --git a/target/arm/helper.c b/target/arm/helper.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/target/arm/helper.c
32
+++ b/target/arm/helper.c
33
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
34
{
35
uint64_t tcr = regime_tcr(env, mmu_idx)->raw_tcr;
36
bool epd, hpd, using16k, using64k;
37
- int select, tsz, tbi;
38
+ int select, tsz, tbi, max_tsz;
39
40
if (!regime_has_2_ranges(mmu_idx)) {
41
select = 0;
42
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
43
hpd = extract64(tcr, 42, 1);
44
}
45
}
46
- tsz = MIN(tsz, 39); /* TODO: ARMv8.4-TTST */
47
+
48
+ if (cpu_isar_feature(aa64_st, env_archcpu(env))) {
49
+ max_tsz = 48 - using64k;
50
+ } else {
51
+ max_tsz = 39;
52
+ }
53
+
54
+ tsz = MIN(tsz, max_tsz);
55
tsz = MAX(tsz, 16); /* TODO: ARMv8.2-LVA */
56
57
/* Present TBI as a composite with TBID. */
58
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
59
if (!aarch64 || stride == 9) {
60
/* AArch32 or 4KB pages */
61
startlevel = 2 - sl0;
62
+
63
+ if (cpu_isar_feature(aa64_st, cpu)) {
64
+ startlevel &= 3;
65
+ }
66
} else {
67
/* 16KB or 64KB pages */
68
startlevel = 3 - sl0;
69
--
64
--
70
2.20.1
65
2.34.1
71
66
72
67
diff view generated by jsdifflib
1
From: Leif Lindholm <leif@nuviainc.com>
1
From: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
2
2
3
Add entries present in ARM DDI 0487F.c (August 2020).
3
We plan to add more hardware information into DeviceTree to limit amount
4
of hardcoded values in firmware.
4
5
5
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
6
Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
7
Message-id: 20230531171834.236569-1-marcin.juszkiewicz@linaro.org
8
[PMM: fix format nits, add text about platform version fields from
9
a comment in the C source file]
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
8
Message-id: 20210108185154.8108-7-leif@nuviainc.com
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
12
---
11
target/arm/cpu.h | 28 ++++++++++++++++++++++++++++
13
docs/system/arm/sbsa.rst | 38 +++++++++++++++++++++++++++++++-------
12
1 file changed, 28 insertions(+)
14
1 file changed, 31 insertions(+), 7 deletions(-)
13
15
14
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
16
diff --git a/docs/system/arm/sbsa.rst b/docs/system/arm/sbsa.rst
15
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/cpu.h
18
--- a/docs/system/arm/sbsa.rst
17
+++ b/target/arm/cpu.h
19
+++ b/docs/system/arm/sbsa.rst
18
@@ -XXX,XX +XXX,XX @@ FIELD(ID_ISAR6, DP, 4, 4)
20
@@ -XXX,XX +XXX,XX @@ any real hardware the ``sbsa-ref`` board intends to look like real
19
FIELD(ID_ISAR6, FHM, 8, 4)
21
hardware. The `Server Base System Architecture
20
FIELD(ID_ISAR6, SB, 12, 4)
22
<https://developer.arm.com/documentation/den0029/latest>`_ defines a
21
FIELD(ID_ISAR6, SPECRES, 16, 4)
23
minimum base line of hardware support and importantly how the firmware
22
+FIELD(ID_ISAR6, BF16, 20, 4)
24
-reports that to any operating system. It is a static system that
23
+FIELD(ID_ISAR6, I8MM, 24, 4)
25
-reports a very minimal DT to the firmware for non-discoverable
24
26
-information about components affected by the qemu command line (i.e.
25
FIELD(ID_MMFR0, VMSA, 0, 4)
27
-cpus and memory). As a result it must have a firmware specifically
26
FIELD(ID_MMFR0, PMSA, 4, 4)
28
-built to expect a certain hardware layout (as you would in a real
27
@@ -XXX,XX +XXX,XX @@ FIELD(ID_MMFR0, AUXREG, 20, 4)
29
-machine).
28
FIELD(ID_MMFR0, FCSE, 24, 4)
30
+reports that to any operating system.
29
FIELD(ID_MMFR0, INNERSHR, 28, 4)
31
30
32
It is intended to be a machine for developing firmware and testing
31
+FIELD(ID_MMFR1, L1HVDVA, 0, 4)
33
standards compliance with operating systems.
32
+FIELD(ID_MMFR1, L1UNIVA, 4, 4)
34
@@ -XXX,XX +XXX,XX @@ standards compliance with operating systems.
33
+FIELD(ID_MMFR1, L1HVDSW, 8, 4)
35
Supported devices
34
+FIELD(ID_MMFR1, L1UNISW, 12, 4)
36
"""""""""""""""""
35
+FIELD(ID_MMFR1, L1HVD, 16, 4)
37
36
+FIELD(ID_MMFR1, L1UNI, 20, 4)
38
-The sbsa-ref board supports:
37
+FIELD(ID_MMFR1, L1TSTCLN, 24, 4)
39
+The ``sbsa-ref`` board supports:
38
+FIELD(ID_MMFR1, BPRED, 28, 4)
40
41
- A configurable number of AArch64 CPUs
42
- GIC version 3
43
@@ -XXX,XX +XXX,XX @@ The sbsa-ref board supports:
44
- Bochs display adapter on PCIe bus
45
- A generic SBSA watchdog device
46
39
+
47
+
40
+FIELD(ID_MMFR2, L1HVDFG, 0, 4)
48
+Board to firmware interface
41
+FIELD(ID_MMFR2, L1HVDBG, 4, 4)
49
+"""""""""""""""""""""""""""
42
+FIELD(ID_MMFR2, L1HVDRNG, 8, 4)
43
+FIELD(ID_MMFR2, HVDTLB, 12, 4)
44
+FIELD(ID_MMFR2, UNITLB, 16, 4)
45
+FIELD(ID_MMFR2, MEMBARR, 20, 4)
46
+FIELD(ID_MMFR2, WFISTALL, 24, 4)
47
+FIELD(ID_MMFR2, HWACCFLG, 28, 4)
48
+
50
+
49
FIELD(ID_MMFR3, CMAINTVA, 0, 4)
51
+``sbsa-ref`` is a static system that reports a very minimal devicetree to the
50
FIELD(ID_MMFR3, CMAINTSW, 4, 4)
52
+firmware for non-discoverable information about system components. This
51
FIELD(ID_MMFR3, BPMAINT, 8, 4)
53
+includes both internal hardware and parts affected by the qemu command line
52
@@ -XXX,XX +XXX,XX @@ FIELD(ID_MMFR4, LSM, 20, 4)
54
+(i.e. CPUs and memory). As a result it must have a firmware specifically built
53
FIELD(ID_MMFR4, CCIDX, 24, 4)
55
+to expect a certain hardware layout (as you would in a real machine).
54
FIELD(ID_MMFR4, EVT, 28, 4)
55
56
+FIELD(ID_MMFR5, ETS, 0, 4)
57
+
56
+
58
FIELD(ID_PFR0, STATE0, 0, 4)
57
+DeviceTree information
59
FIELD(ID_PFR0, STATE1, 4, 4)
58
+''''''''''''''''''''''
60
FIELD(ID_PFR0, STATE2, 8, 4)
61
@@ -XXX,XX +XXX,XX @@ FIELD(ID_PFR1, SEC_FRAC, 20, 4)
62
FIELD(ID_PFR1, VIRT_FRAC, 24, 4)
63
FIELD(ID_PFR1, GIC, 28, 4)
64
65
+FIELD(ID_PFR2, CSV3, 0, 4)
66
+FIELD(ID_PFR2, SSBS, 4, 4)
67
+FIELD(ID_PFR2, RAS_FRAC, 8, 4)
68
+
59
+
69
FIELD(ID_AA64ISAR0, AES, 4, 4)
60
+The devicetree provided by the board model to the firmware is not intended
70
FIELD(ID_AA64ISAR0, SHA1, 8, 4)
61
+to be a complete compliant DT. It currently reports:
71
FIELD(ID_AA64ISAR0, SHA2, 12, 4)
72
@@ -XXX,XX +XXX,XX @@ FIELD(ID_DFR0, MPROFDBG, 20, 4)
73
FIELD(ID_DFR0, PERFMON, 24, 4)
74
FIELD(ID_DFR0, TRACEFILT, 28, 4)
75
76
+FIELD(ID_DFR1, MTPMU, 0, 4)
77
+
62
+
78
FIELD(DBGDIDR, SE_IMP, 12, 1)
63
+ - CPUs
79
FIELD(DBGDIDR, NSUHD_IMP, 14, 1)
64
+ - memory
80
FIELD(DBGDIDR, VERSION, 16, 4)
65
+ - platform version
66
+ - GIC addresses
67
+
68
+The platform version is only for informing platform firmware about
69
+what kind of ``sbsa-ref`` board it is running on. It is neither
70
+a QEMU versioned machine type nor a reflection of the level of the
71
+SBSA/SystemReady SR support provided.
72
+
73
+The ``machine-version-major`` value is updated when changes breaking
74
+fw compatibility are introduced. The ``machine-version-minor`` value
75
+is updated when features are added that don't break fw compatibility.
81
--
76
--
82
2.20.1
77
2.34.1
83
84
diff view generated by jsdifflib
1
From: Hao Wu <wuhaotsh@google.com>
1
From: Sergey Kambalin <sergey.kambalin@auriga.com>
2
2
3
We add a qtest for the PWM in the previous patch. It proves it works as
3
Signed-off-by: Sergey Kambalin <sergey.kambalin@auriga.com>
4
expected.
4
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
5
5
Acked-by: Richard Henderson <richard.henderson@linaro.org>
6
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
6
Message-id: 20230612223456.33824-2-philmd@linaro.org
7
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
7
Message-Id: <20230531155258.8361-1-sergey.kambalin@auriga.com>
8
Signed-off-by: Hao Wu <wuhaotsh@google.com>
8
[PMD: Split from bigger patch: 1/4]
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
10
Message-id: 20210108190945.949196-6-wuhaotsh@google.com
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
11
---
13
tests/qtest/npcm7xx_pwm-test.c | 490 +++++++++++++++++++++++++++++++++
12
include/hw/misc/raspberrypi-fw-defs.h | 163 ++++++++++++++++++++++++++
14
tests/qtest/meson.build | 1 +
13
1 file changed, 163 insertions(+)
15
2 files changed, 491 insertions(+)
14
create mode 100644 include/hw/misc/raspberrypi-fw-defs.h
16
create mode 100644 tests/qtest/npcm7xx_pwm-test.c
17
15
18
diff --git a/tests/qtest/npcm7xx_pwm-test.c b/tests/qtest/npcm7xx_pwm-test.c
16
diff --git a/include/hw/misc/raspberrypi-fw-defs.h b/include/hw/misc/raspberrypi-fw-defs.h
19
new file mode 100644
17
new file mode 100644
20
index XXXXXXX..XXXXXXX
18
index XXXXXXX..XXXXXXX
21
--- /dev/null
19
--- /dev/null
22
+++ b/tests/qtest/npcm7xx_pwm-test.c
20
+++ b/include/hw/misc/raspberrypi-fw-defs.h
23
@@ -XXX,XX +XXX,XX @@
21
@@ -XXX,XX +XXX,XX @@
24
+/*
22
+/*
25
+ * QTests for Nuvoton NPCM7xx PWM Modules.
23
+ * Raspberry Pi firmware definitions
26
+ *
24
+ *
27
+ * Copyright 2020 Google LLC
25
+ * Copyright (C) 2022 Auriga LLC, based on Linux kernel
26
+ * `include/soc/bcm2835/raspberrypi-firmware.h` (Copyright © 2015 Broadcom)
28
+ *
27
+ *
29
+ * This program is free software; you can redistribute it and/or modify it
28
+ * SPDX-License-Identifier: GPL-2.0-or-later
30
+ * under the terms of the GNU General Public License as published by the
31
+ * Free Software Foundation; either version 2 of the License, or
32
+ * (at your option) any later version.
33
+ *
34
+ * This program is distributed in the hope that it will be useful, but WITHOUT
35
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
36
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
37
+ * for more details.
38
+ */
29
+ */
39
+
30
+
31
+#ifndef INCLUDE_HW_MISC_RASPBERRYPI_FW_DEFS_H_
32
+#define INCLUDE_HW_MISC_RASPBERRYPI_FW_DEFS_H_
33
+
40
+#include "qemu/osdep.h"
34
+#include "qemu/osdep.h"
41
+#include "qemu/bitops.h"
42
+#include "libqos/libqtest.h"
43
+#include "qapi/qmp/qdict.h"
44
+#include "qapi/qmp/qnum.h"
45
+
35
+
46
+#define REF_HZ 25000000
36
+enum rpi_firmware_property_tag {
37
+ RPI_FWREQ_PROPERTY_END = 0,
38
+ RPI_FWREQ_GET_FIRMWARE_REVISION = 0x00000001,
39
+ RPI_FWREQ_GET_FIRMWARE_VARIANT = 0x00000002,
40
+ RPI_FWREQ_GET_FIRMWARE_HASH = 0x00000003,
47
+
41
+
48
+/* Register field definitions. */
42
+ RPI_FWREQ_SET_CURSOR_INFO = 0x00008010,
49
+#define CH_EN BIT(0)
43
+ RPI_FWREQ_SET_CURSOR_STATE = 0x00008011,
50
+#define CH_INV BIT(2)
51
+#define CH_MOD BIT(3)
52
+
44
+
53
+/* Registers shared between all PWMs in a module */
45
+ RPI_FWREQ_GET_BOARD_MODEL = 0x00010001,
54
+#define PPR 0x00
46
+ RPI_FWREQ_GET_BOARD_REVISION = 0x00010002,
55
+#define CSR 0x04
47
+ RPI_FWREQ_GET_BOARD_MAC_ADDRESS = 0x00010003,
56
+#define PCR 0x08
48
+ RPI_FWREQ_GET_BOARD_SERIAL = 0x00010004,
57
+#define PIER 0x3c
49
+ RPI_FWREQ_GET_ARM_MEMORY = 0x00010005,
58
+#define PIIR 0x40
50
+ RPI_FWREQ_GET_VC_MEMORY = 0x00010006,
51
+ RPI_FWREQ_GET_CLOCKS = 0x00010007,
52
+ RPI_FWREQ_GET_POWER_STATE = 0x00020001,
53
+ RPI_FWREQ_GET_TIMING = 0x00020002,
54
+ RPI_FWREQ_SET_POWER_STATE = 0x00028001,
55
+ RPI_FWREQ_GET_CLOCK_STATE = 0x00030001,
56
+ RPI_FWREQ_GET_CLOCK_RATE = 0x00030002,
57
+ RPI_FWREQ_GET_VOLTAGE = 0x00030003,
58
+ RPI_FWREQ_GET_MAX_CLOCK_RATE = 0x00030004,
59
+ RPI_FWREQ_GET_MAX_VOLTAGE = 0x00030005,
60
+ RPI_FWREQ_GET_TEMPERATURE = 0x00030006,
61
+ RPI_FWREQ_GET_MIN_CLOCK_RATE = 0x00030007,
62
+ RPI_FWREQ_GET_MIN_VOLTAGE = 0x00030008,
63
+ RPI_FWREQ_GET_TURBO = 0x00030009,
64
+ RPI_FWREQ_GET_MAX_TEMPERATURE = 0x0003000a,
65
+ RPI_FWREQ_GET_STC = 0x0003000b,
66
+ RPI_FWREQ_ALLOCATE_MEMORY = 0x0003000c,
67
+ RPI_FWREQ_LOCK_MEMORY = 0x0003000d,
68
+ RPI_FWREQ_UNLOCK_MEMORY = 0x0003000e,
69
+ RPI_FWREQ_RELEASE_MEMORY = 0x0003000f,
70
+ RPI_FWREQ_EXECUTE_CODE = 0x00030010,
71
+ RPI_FWREQ_EXECUTE_QPU = 0x00030011,
72
+ RPI_FWREQ_SET_ENABLE_QPU = 0x00030012,
73
+ RPI_FWREQ_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014,
74
+ RPI_FWREQ_GET_EDID_BLOCK = 0x00030020,
75
+ RPI_FWREQ_GET_CUSTOMER_OTP = 0x00030021,
76
+ RPI_FWREQ_GET_EDID_BLOCK_DISPLAY = 0x00030023,
77
+ RPI_FWREQ_GET_DOMAIN_STATE = 0x00030030,
78
+ RPI_FWREQ_GET_THROTTLED = 0x00030046,
79
+ RPI_FWREQ_GET_CLOCK_MEASURED = 0x00030047,
80
+ RPI_FWREQ_NOTIFY_REBOOT = 0x00030048,
81
+ RPI_FWREQ_SET_CLOCK_STATE = 0x00038001,
82
+ RPI_FWREQ_SET_CLOCK_RATE = 0x00038002,
83
+ RPI_FWREQ_SET_VOLTAGE = 0x00038003,
84
+ RPI_FWREQ_SET_MAX_CLOCK_RATE = 0x00038004,
85
+ RPI_FWREQ_SET_MIN_CLOCK_RATE = 0x00038007,
86
+ RPI_FWREQ_SET_TURBO = 0x00038009,
87
+ RPI_FWREQ_SET_CUSTOMER_OTP = 0x00038021,
88
+ RPI_FWREQ_SET_DOMAIN_STATE = 0x00038030,
89
+ RPI_FWREQ_GET_GPIO_STATE = 0x00030041,
90
+ RPI_FWREQ_SET_GPIO_STATE = 0x00038041,
91
+ RPI_FWREQ_SET_SDHOST_CLOCK = 0x00038042,
92
+ RPI_FWREQ_GET_GPIO_CONFIG = 0x00030043,
93
+ RPI_FWREQ_SET_GPIO_CONFIG = 0x00038043,
94
+ RPI_FWREQ_GET_PERIPH_REG = 0x00030045,
95
+ RPI_FWREQ_SET_PERIPH_REG = 0x00038045,
96
+ RPI_FWREQ_GET_POE_HAT_VAL = 0x00030049,
97
+ RPI_FWREQ_SET_POE_HAT_VAL = 0x00038049,
98
+ RPI_FWREQ_SET_POE_HAT_VAL_OLD = 0x00030050,
99
+ RPI_FWREQ_NOTIFY_XHCI_RESET = 0x00030058,
100
+ RPI_FWREQ_GET_REBOOT_FLAGS = 0x00030064,
101
+ RPI_FWREQ_SET_REBOOT_FLAGS = 0x00038064,
102
+ RPI_FWREQ_NOTIFY_DISPLAY_DONE = 0x00030066,
59
+
103
+
60
+/* CLK module related */
104
+ /* Dispmanx TAGS */
61
+#define CLK_BA 0xf0801000
105
+ RPI_FWREQ_FRAMEBUFFER_ALLOCATE = 0x00040001,
62
+#define CLKSEL 0x04
106
+ RPI_FWREQ_FRAMEBUFFER_BLANK = 0x00040002,
63
+#define CLKDIV1 0x08
107
+ RPI_FWREQ_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT = 0x00040003,
64
+#define CLKDIV2 0x2c
108
+ RPI_FWREQ_FRAMEBUFFER_GET_VIRTUAL_WIDTH_HEIGHT = 0x00040004,
65
+#define PLLCON0 0x0c
109
+ RPI_FWREQ_FRAMEBUFFER_GET_DEPTH = 0x00040005,
66
+#define PLLCON1 0x10
110
+ RPI_FWREQ_FRAMEBUFFER_GET_PIXEL_ORDER = 0x00040006,
67
+#define PLL_INDV(rv) extract32((rv), 0, 6)
111
+ RPI_FWREQ_FRAMEBUFFER_GET_ALPHA_MODE = 0x00040007,
68
+#define PLL_FBDV(rv) extract32((rv), 16, 12)
112
+ RPI_FWREQ_FRAMEBUFFER_GET_PITCH = 0x00040008,
69
+#define PLL_OTDV1(rv) extract32((rv), 8, 3)
113
+ RPI_FWREQ_FRAMEBUFFER_GET_VIRTUAL_OFFSET = 0x00040009,
70
+#define PLL_OTDV2(rv) extract32((rv), 13, 3)
114
+ RPI_FWREQ_FRAMEBUFFER_GET_OVERSCAN = 0x0004000a,
71
+#define APB3CKDIV(rv) extract32((rv), 28, 2)
115
+ RPI_FWREQ_FRAMEBUFFER_GET_PALETTE = 0x0004000b,
72
+#define CLK2CKDIV(rv) extract32((rv), 0, 1)
116
+ RPI_FWREQ_FRAMEBUFFER_GET_LAYER = 0x0004000c,
73
+#define CLK4CKDIV(rv) extract32((rv), 26, 2)
117
+ RPI_FWREQ_FRAMEBUFFER_GET_TRANSFORM = 0x0004000d,
74
+#define CPUCKSEL(rv) extract32((rv), 0, 2)
118
+ RPI_FWREQ_FRAMEBUFFER_GET_VSYNC = 0x0004000e,
119
+ RPI_FWREQ_FRAMEBUFFER_GET_TOUCHBUF = 0x0004000f,
120
+ RPI_FWREQ_FRAMEBUFFER_GET_GPIOVIRTBUF = 0x00040010,
121
+ RPI_FWREQ_FRAMEBUFFER_RELEASE = 0x00048001,
122
+ RPI_FWREQ_FRAMEBUFFER_GET_DISPLAY_ID = 0x00040016,
123
+ RPI_FWREQ_FRAMEBUFFER_SET_DISPLAY_NUM = 0x00048013,
124
+ RPI_FWREQ_FRAMEBUFFER_GET_NUM_DISPLAYS = 0x00040013,
125
+ RPI_FWREQ_FRAMEBUFFER_GET_DISPLAY_SETTINGS = 0x00040014,
126
+ RPI_FWREQ_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT = 0x00044003,
127
+ RPI_FWREQ_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT = 0x00044004,
128
+ RPI_FWREQ_FRAMEBUFFER_TEST_DEPTH = 0x00044005,
129
+ RPI_FWREQ_FRAMEBUFFER_TEST_PIXEL_ORDER = 0x00044006,
130
+ RPI_FWREQ_FRAMEBUFFER_TEST_ALPHA_MODE = 0x00044007,
131
+ RPI_FWREQ_FRAMEBUFFER_TEST_VIRTUAL_OFFSET = 0x00044009,
132
+ RPI_FWREQ_FRAMEBUFFER_TEST_OVERSCAN = 0x0004400a,
133
+ RPI_FWREQ_FRAMEBUFFER_TEST_PALETTE = 0x0004400b,
134
+ RPI_FWREQ_FRAMEBUFFER_TEST_LAYER = 0x0004400c,
135
+ RPI_FWREQ_FRAMEBUFFER_TEST_TRANSFORM = 0x0004400d,
136
+ RPI_FWREQ_FRAMEBUFFER_TEST_VSYNC = 0x0004400e,
137
+ RPI_FWREQ_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT = 0x00048003,
138
+ RPI_FWREQ_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT = 0x00048004,
139
+ RPI_FWREQ_FRAMEBUFFER_SET_DEPTH = 0x00048005,
140
+ RPI_FWREQ_FRAMEBUFFER_SET_PIXEL_ORDER = 0x00048006,
141
+ RPI_FWREQ_FRAMEBUFFER_SET_ALPHA_MODE = 0x00048007,
142
+ RPI_FWREQ_FRAMEBUFFER_SET_PITCH = 0x00048008,
143
+ RPI_FWREQ_FRAMEBUFFER_SET_VIRTUAL_OFFSET = 0x00048009,
144
+ RPI_FWREQ_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a,
145
+ RPI_FWREQ_FRAMEBUFFER_SET_PALETTE = 0x0004800b,
75
+
146
+
76
+#define MAX_DUTY 1000000
147
+ RPI_FWREQ_FRAMEBUFFER_SET_TOUCHBUF = 0x0004801f,
148
+ RPI_FWREQ_FRAMEBUFFER_SET_GPIOVIRTBUF = 0x00048020,
149
+ RPI_FWREQ_FRAMEBUFFER_SET_VSYNC = 0x0004800e,
150
+ RPI_FWREQ_FRAMEBUFFER_SET_LAYER = 0x0004800c,
151
+ RPI_FWREQ_FRAMEBUFFER_SET_TRANSFORM = 0x0004800d,
152
+ RPI_FWREQ_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f,
77
+
153
+
78
+typedef struct PWMModule {
154
+ RPI_FWREQ_VCHIQ_INIT = 0x00048010,
79
+ int irq;
80
+ uint64_t base_addr;
81
+} PWMModule;
82
+
155
+
83
+typedef struct PWM {
156
+ RPI_FWREQ_SET_PLANE = 0x00048015,
84
+ uint32_t cnr_offset;
157
+ RPI_FWREQ_GET_DISPLAY_TIMING = 0x00040017,
85
+ uint32_t cmr_offset;
158
+ RPI_FWREQ_SET_TIMING = 0x00048017,
86
+ uint32_t pdr_offset;
159
+ RPI_FWREQ_GET_DISPLAY_CFG = 0x00040018,
87
+ uint32_t pwdr_offset;
160
+ RPI_FWREQ_SET_DISPLAY_POWER = 0x00048019,
88
+} PWM;
161
+ RPI_FWREQ_GET_COMMAND_LINE = 0x00050001,
89
+
162
+ RPI_FWREQ_GET_DMA_CHANNELS = 0x00060001,
90
+typedef struct TestData {
91
+ const PWMModule *module;
92
+ const PWM *pwm;
93
+} TestData;
94
+
95
+static const PWMModule pwm_module_list[] = {
96
+ {
97
+ .irq = 93,
98
+ .base_addr = 0xf0103000
99
+ },
100
+ {
101
+ .irq = 94,
102
+ .base_addr = 0xf0104000
103
+ }
104
+};
163
+};
105
+
164
+
106
+static const PWM pwm_list[] = {
165
+enum rpi_firmware_clk_id {
107
+ {
166
+ RPI_FIRMWARE_EMMC_CLK_ID = 1,
108
+ .cnr_offset = 0x0c,
167
+ RPI_FIRMWARE_UART_CLK_ID,
109
+ .cmr_offset = 0x10,
168
+ RPI_FIRMWARE_ARM_CLK_ID,
110
+ .pdr_offset = 0x14,
169
+ RPI_FIRMWARE_CORE_CLK_ID,
111
+ .pwdr_offset = 0x44,
170
+ RPI_FIRMWARE_V3D_CLK_ID,
112
+ },
171
+ RPI_FIRMWARE_H264_CLK_ID,
113
+ {
172
+ RPI_FIRMWARE_ISP_CLK_ID,
114
+ .cnr_offset = 0x18,
173
+ RPI_FIRMWARE_SDRAM_CLK_ID,
115
+ .cmr_offset = 0x1c,
174
+ RPI_FIRMWARE_PIXEL_CLK_ID,
116
+ .pdr_offset = 0x20,
175
+ RPI_FIRMWARE_PWM_CLK_ID,
117
+ .pwdr_offset = 0x48,
176
+ RPI_FIRMWARE_HEVC_CLK_ID,
118
+ },
177
+ RPI_FIRMWARE_EMMC2_CLK_ID,
119
+ {
178
+ RPI_FIRMWARE_M2MC_CLK_ID,
120
+ .cnr_offset = 0x24,
179
+ RPI_FIRMWARE_PIXEL_BVB_CLK_ID,
121
+ .cmr_offset = 0x28,
180
+ RPI_FIRMWARE_VEC_CLK_ID,
122
+ .pdr_offset = 0x2c,
181
+ RPI_FIRMWARE_NUM_CLK_ID,
123
+ .pwdr_offset = 0x4c,
124
+ },
125
+ {
126
+ .cnr_offset = 0x30,
127
+ .cmr_offset = 0x34,
128
+ .pdr_offset = 0x38,
129
+ .pwdr_offset = 0x50,
130
+ },
131
+};
182
+};
132
+
183
+
133
+static const int ppr_base[] = { 0, 0, 8, 8 };
184
+#endif /* INCLUDE_HW_MISC_RASPBERRYPI_FW_DEFS_H_ */
134
+static const int csr_base[] = { 0, 4, 8, 12 };
135
+static const int pcr_base[] = { 0, 8, 12, 16 };
136
+
137
+static const uint32_t ppr_list[] = {
138
+ 0,
139
+ 1,
140
+ 10,
141
+ 100,
142
+ 255, /* Max possible value. */
143
+};
144
+
145
+static const uint32_t csr_list[] = {
146
+ 0,
147
+ 1,
148
+ 2,
149
+ 3,
150
+ 4, /* Max possible value. */
151
+};
152
+
153
+static const uint32_t cnr_list[] = {
154
+ 0,
155
+ 1,
156
+ 50,
157
+ 100,
158
+ 150,
159
+ 200,
160
+ 1000,
161
+ 10000,
162
+ 65535, /* Max possible value. */
163
+};
164
+
165
+static const uint32_t cmr_list[] = {
166
+ 0,
167
+ 1,
168
+ 10,
169
+ 50,
170
+ 100,
171
+ 150,
172
+ 200,
173
+ 1000,
174
+ 10000,
175
+ 65535, /* Max possible value. */
176
+};
177
+
178
+/* Returns the index of the PWM module. */
179
+static int pwm_module_index(const PWMModule *module)
180
+{
181
+ ptrdiff_t diff = module - pwm_module_list;
182
+
183
+ g_assert_true(diff >= 0 && diff < ARRAY_SIZE(pwm_module_list));
184
+
185
+ return diff;
186
+}
187
+
188
+/* Returns the index of the PWM entry. */
189
+static int pwm_index(const PWM *pwm)
190
+{
191
+ ptrdiff_t diff = pwm - pwm_list;
192
+
193
+ g_assert_true(diff >= 0 && diff < ARRAY_SIZE(pwm_list));
194
+
195
+ return diff;
196
+}
197
+
198
+static uint64_t pwm_qom_get(QTestState *qts, const char *path, const char *name)
199
+{
200
+ QDict *response;
201
+
202
+ g_test_message("Getting properties %s from %s", name, path);
203
+ response = qtest_qmp(qts, "{ 'execute': 'qom-get',"
204
+ " 'arguments': { 'path': %s, 'property': %s}}",
205
+ path, name);
206
+ /* The qom set message returns successfully. */
207
+ g_assert_true(qdict_haskey(response, "return"));
208
+ return qnum_get_uint(qobject_to(QNum, qdict_get(response, "return")));
209
+}
210
+
211
+static uint64_t pwm_get_freq(QTestState *qts, int module_index, int pwm_index)
212
+{
213
+ char path[100];
214
+ char name[100];
215
+
216
+ sprintf(path, "/machine/soc/pwm[%d]", module_index);
217
+ sprintf(name, "freq[%d]", pwm_index);
218
+
219
+ return pwm_qom_get(qts, path, name);
220
+}
221
+
222
+static uint64_t pwm_get_duty(QTestState *qts, int module_index, int pwm_index)
223
+{
224
+ char path[100];
225
+ char name[100];
226
+
227
+ sprintf(path, "/machine/soc/pwm[%d]", module_index);
228
+ sprintf(name, "duty[%d]", pwm_index);
229
+
230
+ return pwm_qom_get(qts, path, name);
231
+}
232
+
233
+static uint32_t get_pll(uint32_t con)
234
+{
235
+ return REF_HZ * PLL_FBDV(con) / (PLL_INDV(con) * PLL_OTDV1(con)
236
+ * PLL_OTDV2(con));
237
+}
238
+
239
+static uint64_t read_pclk(QTestState *qts)
240
+{
241
+ uint64_t freq = REF_HZ;
242
+ uint32_t clksel = qtest_readl(qts, CLK_BA + CLKSEL);
243
+ uint32_t pllcon;
244
+ uint32_t clkdiv1 = qtest_readl(qts, CLK_BA + CLKDIV1);
245
+ uint32_t clkdiv2 = qtest_readl(qts, CLK_BA + CLKDIV2);
246
+
247
+ switch (CPUCKSEL(clksel)) {
248
+ case 0:
249
+ pllcon = qtest_readl(qts, CLK_BA + PLLCON0);
250
+ freq = get_pll(pllcon);
251
+ break;
252
+ case 1:
253
+ pllcon = qtest_readl(qts, CLK_BA + PLLCON1);
254
+ freq = get_pll(pllcon);
255
+ break;
256
+ case 2:
257
+ break;
258
+ case 3:
259
+ break;
260
+ default:
261
+ g_assert_not_reached();
262
+ }
263
+
264
+ freq >>= (CLK2CKDIV(clkdiv1) + CLK4CKDIV(clkdiv1) + APB3CKDIV(clkdiv2));
265
+
266
+ return freq;
267
+}
268
+
269
+static uint32_t pwm_selector(uint32_t csr)
270
+{
271
+ switch (csr) {
272
+ case 0:
273
+ return 2;
274
+ case 1:
275
+ return 4;
276
+ case 2:
277
+ return 8;
278
+ case 3:
279
+ return 16;
280
+ case 4:
281
+ return 1;
282
+ default:
283
+ g_assert_not_reached();
284
+ }
285
+}
286
+
287
+static uint64_t pwm_compute_freq(QTestState *qts, uint32_t ppr, uint32_t csr,
288
+ uint32_t cnr)
289
+{
290
+ return read_pclk(qts) / ((ppr + 1) * pwm_selector(csr) * (cnr + 1));
291
+}
292
+
293
+static uint64_t pwm_compute_duty(uint32_t cnr, uint32_t cmr, bool inverted)
294
+{
295
+ uint64_t duty;
296
+
297
+ if (cnr == 0) {
298
+ /* PWM is stopped. */
299
+ duty = 0;
300
+ } else if (cmr >= cnr) {
301
+ duty = MAX_DUTY;
302
+ } else {
303
+ duty = MAX_DUTY * (cmr + 1) / (cnr + 1);
304
+ }
305
+
306
+ if (inverted) {
307
+ duty = MAX_DUTY - duty;
308
+ }
309
+
310
+ return duty;
311
+}
312
+
313
+static uint32_t pwm_read(QTestState *qts, const TestData *td, unsigned offset)
314
+{
315
+ return qtest_readl(qts, td->module->base_addr + offset);
316
+}
317
+
318
+static void pwm_write(QTestState *qts, const TestData *td, unsigned offset,
319
+ uint32_t value)
320
+{
321
+ qtest_writel(qts, td->module->base_addr + offset, value);
322
+}
323
+
324
+static uint32_t pwm_read_ppr(QTestState *qts, const TestData *td)
325
+{
326
+ return extract32(pwm_read(qts, td, PPR), ppr_base[pwm_index(td->pwm)], 8);
327
+}
328
+
329
+static void pwm_write_ppr(QTestState *qts, const TestData *td, uint32_t value)
330
+{
331
+ pwm_write(qts, td, PPR, value << ppr_base[pwm_index(td->pwm)]);
332
+}
333
+
334
+static uint32_t pwm_read_csr(QTestState *qts, const TestData *td)
335
+{
336
+ return extract32(pwm_read(qts, td, CSR), csr_base[pwm_index(td->pwm)], 3);
337
+}
338
+
339
+static void pwm_write_csr(QTestState *qts, const TestData *td, uint32_t value)
340
+{
341
+ pwm_write(qts, td, CSR, value << csr_base[pwm_index(td->pwm)]);
342
+}
343
+
344
+static uint32_t pwm_read_pcr(QTestState *qts, const TestData *td)
345
+{
346
+ return extract32(pwm_read(qts, td, PCR), pcr_base[pwm_index(td->pwm)], 4);
347
+}
348
+
349
+static void pwm_write_pcr(QTestState *qts, const TestData *td, uint32_t value)
350
+{
351
+ pwm_write(qts, td, PCR, value << pcr_base[pwm_index(td->pwm)]);
352
+}
353
+
354
+static uint32_t pwm_read_cnr(QTestState *qts, const TestData *td)
355
+{
356
+ return pwm_read(qts, td, td->pwm->cnr_offset);
357
+}
358
+
359
+static void pwm_write_cnr(QTestState *qts, const TestData *td, uint32_t value)
360
+{
361
+ pwm_write(qts, td, td->pwm->cnr_offset, value);
362
+}
363
+
364
+static uint32_t pwm_read_cmr(QTestState *qts, const TestData *td)
365
+{
366
+ return pwm_read(qts, td, td->pwm->cmr_offset);
367
+}
368
+
369
+static void pwm_write_cmr(QTestState *qts, const TestData *td, uint32_t value)
370
+{
371
+ pwm_write(qts, td, td->pwm->cmr_offset, value);
372
+}
373
+
374
+/* Check pwm registers can be reset to default value */
375
+static void test_init(gconstpointer test_data)
376
+{
377
+ const TestData *td = test_data;
378
+ QTestState *qts = qtest_init("-machine quanta-gsj");
379
+ int module = pwm_module_index(td->module);
380
+ int pwm = pwm_index(td->pwm);
381
+
382
+ g_assert_cmpuint(pwm_get_freq(qts, module, pwm), ==, 0);
383
+ g_assert_cmpuint(pwm_get_duty(qts, module, pwm), ==, 0);
384
+
385
+ qtest_quit(qts);
386
+}
387
+
388
+/* One-shot mode should not change frequency and duty cycle. */
389
+static void test_oneshot(gconstpointer test_data)
390
+{
391
+ const TestData *td = test_data;
392
+ QTestState *qts = qtest_init("-machine quanta-gsj");
393
+ int module = pwm_module_index(td->module);
394
+ int pwm = pwm_index(td->pwm);
395
+ uint32_t ppr, csr, pcr;
396
+ int i, j;
397
+
398
+ pcr = CH_EN;
399
+ for (i = 0; i < ARRAY_SIZE(ppr_list); ++i) {
400
+ ppr = ppr_list[i];
401
+ pwm_write_ppr(qts, td, ppr);
402
+
403
+ for (j = 0; j < ARRAY_SIZE(csr_list); ++j) {
404
+ csr = csr_list[j];
405
+ pwm_write_csr(qts, td, csr);
406
+ pwm_write_pcr(qts, td, pcr);
407
+
408
+ g_assert_cmpuint(pwm_read_ppr(qts, td), ==, ppr);
409
+ g_assert_cmpuint(pwm_read_csr(qts, td), ==, csr);
410
+ g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr);
411
+ g_assert_cmpuint(pwm_get_freq(qts, module, pwm), ==, 0);
412
+ g_assert_cmpuint(pwm_get_duty(qts, module, pwm), ==, 0);
413
+ }
414
+ }
415
+
416
+ qtest_quit(qts);
417
+}
418
+
419
+/* In toggle mode, the PWM generates correct outputs. */
420
+static void test_toggle(gconstpointer test_data)
421
+{
422
+ const TestData *td = test_data;
423
+ QTestState *qts = qtest_init("-machine quanta-gsj");
424
+ int module = pwm_module_index(td->module);
425
+ int pwm = pwm_index(td->pwm);
426
+ uint32_t ppr, csr, pcr, cnr, cmr;
427
+ int i, j, k, l;
428
+ uint64_t expected_freq, expected_duty;
429
+
430
+ pcr = CH_EN | CH_MOD;
431
+ for (i = 0; i < ARRAY_SIZE(ppr_list); ++i) {
432
+ ppr = ppr_list[i];
433
+ pwm_write_ppr(qts, td, ppr);
434
+
435
+ for (j = 0; j < ARRAY_SIZE(csr_list); ++j) {
436
+ csr = csr_list[j];
437
+ pwm_write_csr(qts, td, csr);
438
+
439
+ for (k = 0; k < ARRAY_SIZE(cnr_list); ++k) {
440
+ cnr = cnr_list[k];
441
+ pwm_write_cnr(qts, td, cnr);
442
+
443
+ for (l = 0; l < ARRAY_SIZE(cmr_list); ++l) {
444
+ cmr = cmr_list[l];
445
+ pwm_write_cmr(qts, td, cmr);
446
+ expected_freq = pwm_compute_freq(qts, ppr, csr, cnr);
447
+ expected_duty = pwm_compute_duty(cnr, cmr, false);
448
+
449
+ pwm_write_pcr(qts, td, pcr);
450
+ g_assert_cmpuint(pwm_read_ppr(qts, td), ==, ppr);
451
+ g_assert_cmpuint(pwm_read_csr(qts, td), ==, csr);
452
+ g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr);
453
+ g_assert_cmpuint(pwm_read_cnr(qts, td), ==, cnr);
454
+ g_assert_cmpuint(pwm_read_cmr(qts, td), ==, cmr);
455
+ g_assert_cmpuint(pwm_get_duty(qts, module, pwm),
456
+ ==, expected_duty);
457
+ if (expected_duty != 0 && expected_duty != 100) {
458
+ /* Duty cycle with 0 or 100 doesn't need frequency. */
459
+ g_assert_cmpuint(pwm_get_freq(qts, module, pwm),
460
+ ==, expected_freq);
461
+ }
462
+
463
+ /* Test inverted mode */
464
+ expected_duty = pwm_compute_duty(cnr, cmr, true);
465
+ pwm_write_pcr(qts, td, pcr | CH_INV);
466
+ g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr | CH_INV);
467
+ g_assert_cmpuint(pwm_get_duty(qts, module, pwm),
468
+ ==, expected_duty);
469
+ if (expected_duty != 0 && expected_duty != 100) {
470
+ /* Duty cycle with 0 or 100 doesn't need frequency. */
471
+ g_assert_cmpuint(pwm_get_freq(qts, module, pwm),
472
+ ==, expected_freq);
473
+ }
474
+
475
+ }
476
+ }
477
+ }
478
+ }
479
+
480
+ qtest_quit(qts);
481
+}
482
+
483
+static void pwm_add_test(const char *name, const TestData* td,
484
+ GTestDataFunc fn)
485
+{
486
+ g_autofree char *full_name = g_strdup_printf(
487
+ "npcm7xx_pwm/module[%d]/pwm[%d]/%s", pwm_module_index(td->module),
488
+ pwm_index(td->pwm), name);
489
+ qtest_add_data_func(full_name, td, fn);
490
+}
491
+#define add_test(name, td) pwm_add_test(#name, td, test_##name)
492
+
493
+int main(int argc, char **argv)
494
+{
495
+ TestData test_data_list[ARRAY_SIZE(pwm_module_list) * ARRAY_SIZE(pwm_list)];
496
+
497
+ g_test_init(&argc, &argv, NULL);
498
+
499
+ for (int i = 0; i < ARRAY_SIZE(pwm_module_list); ++i) {
500
+ for (int j = 0; j < ARRAY_SIZE(pwm_list); ++j) {
501
+ TestData *td = &test_data_list[i * ARRAY_SIZE(pwm_list) + j];
502
+
503
+ td->module = &pwm_module_list[i];
504
+ td->pwm = &pwm_list[j];
505
+
506
+ add_test(init, td);
507
+ add_test(oneshot, td);
508
+ add_test(toggle, td);
509
+ }
510
+ }
511
+
512
+ return g_test_run();
513
+}
514
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
515
index XXXXXXX..XXXXXXX 100644
516
--- a/tests/qtest/meson.build
517
+++ b/tests/qtest/meson.build
518
@@ -XXX,XX +XXX,XX @@ qtests_sparc64 = \
519
qtests_npcm7xx = \
520
['npcm7xx_adc-test',
521
'npcm7xx_gpio-test',
522
+ 'npcm7xx_pwm-test',
523
'npcm7xx_rng-test',
524
'npcm7xx_timer-test',
525
'npcm7xx_watchdog_timer-test']
526
--
185
--
527
2.20.1
186
2.34.1
528
187
529
188
diff view generated by jsdifflib
1
From: Leif Lindholm <leif@nuviainc.com>
1
From: Sergey Kambalin <sergey.kambalin@auriga.com>
2
2
3
Add entries present in ARM DDI 0487F.c (August 2020).
3
Replace magic property values by a proper definition,
4
4
removing redundant comments.
5
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
5
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Sergey Kambalin <sergey.kambalin@auriga.com>
7
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
7
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
8
Message-id: 20210108185154.8108-6-leif@nuviainc.com
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20230612223456.33824-3-philmd@linaro.org
10
Message-Id: <20230531155258.8361-1-sergey.kambalin@auriga.com>
11
[PMD: Split from bigger patch: 2/4]
12
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
14
---
11
target/arm/cpu.h | 15 +++++++++++++++
15
hw/misc/bcm2835_property.c | 101 +++++++++++++++++++------------------
12
1 file changed, 15 insertions(+)
16
1 file changed, 51 insertions(+), 50 deletions(-)
13
17
14
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
18
diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c
15
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/cpu.h
20
--- a/hw/misc/bcm2835_property.c
17
+++ b/target/arm/cpu.h
21
+++ b/hw/misc/bcm2835_property.c
18
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64ISAR1, GPI, 28, 4)
22
@@ -XXX,XX +XXX,XX @@
19
FIELD(ID_AA64ISAR1, FRINTTS, 32, 4)
23
#include "migration/vmstate.h"
20
FIELD(ID_AA64ISAR1, SB, 36, 4)
24
#include "hw/irq.h"
21
FIELD(ID_AA64ISAR1, SPECRES, 40, 4)
25
#include "hw/misc/bcm2835_mbox_defs.h"
22
+FIELD(ID_AA64ISAR1, BF16, 44, 4)
26
+#include "hw/misc/raspberrypi-fw-defs.h"
23
+FIELD(ID_AA64ISAR1, DGH, 48, 4)
27
#include "sysemu/dma.h"
24
+FIELD(ID_AA64ISAR1, I8MM, 52, 4)
28
#include "qemu/log.h"
25
29
#include "qemu/module.h"
26
FIELD(ID_AA64PFR0, EL0, 0, 4)
30
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
27
FIELD(ID_AA64PFR0, EL1, 4, 4)
31
/* @(value + 8) : Request/response indicator */
28
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64PFR0, ADVSIMD, 20, 4)
32
resplen = 0;
29
FIELD(ID_AA64PFR0, GIC, 24, 4)
33
switch (tag) {
30
FIELD(ID_AA64PFR0, RAS, 28, 4)
34
- case 0x00000000: /* End tag */
31
FIELD(ID_AA64PFR0, SVE, 32, 4)
35
+ case RPI_FWREQ_PROPERTY_END:
32
+FIELD(ID_AA64PFR0, SEL2, 36, 4)
36
break;
33
+FIELD(ID_AA64PFR0, MPAM, 40, 4)
37
- case 0x00000001: /* Get firmware revision */
34
+FIELD(ID_AA64PFR0, AMU, 44, 4)
38
+ case RPI_FWREQ_GET_FIRMWARE_REVISION:
35
+FIELD(ID_AA64PFR0, DIT, 48, 4)
39
stl_le_phys(&s->dma_as, value + 12, 346337);
36
+FIELD(ID_AA64PFR0, CSV2, 56, 4)
40
resplen = 4;
37
+FIELD(ID_AA64PFR0, CSV3, 60, 4)
41
break;
38
42
- case 0x00010001: /* Get board model */
39
FIELD(ID_AA64PFR1, BT, 0, 4)
43
+ case RPI_FWREQ_GET_BOARD_MODEL:
40
FIELD(ID_AA64PFR1, SSBS, 4, 4)
44
qemu_log_mask(LOG_UNIMP,
41
FIELD(ID_AA64PFR1, MTE, 8, 4)
45
"bcm2835_property: 0x%08x get board model NYI\n",
42
FIELD(ID_AA64PFR1, RAS_FRAC, 12, 4)
46
tag);
43
+FIELD(ID_AA64PFR1, MPAM_FRAC, 16, 4)
47
resplen = 4;
44
48
break;
45
FIELD(ID_AA64MMFR0, PARANGE, 0, 4)
49
- case 0x00010002: /* Get board revision */
46
FIELD(ID_AA64MMFR0, ASIDBITS, 4, 4)
50
+ case RPI_FWREQ_GET_BOARD_REVISION:
47
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64MMFR0, TGRAN16_2, 32, 4)
51
stl_le_phys(&s->dma_as, value + 12, s->board_rev);
48
FIELD(ID_AA64MMFR0, TGRAN64_2, 36, 4)
52
resplen = 4;
49
FIELD(ID_AA64MMFR0, TGRAN4_2, 40, 4)
53
break;
50
FIELD(ID_AA64MMFR0, EXS, 44, 4)
54
- case 0x00010003: /* Get board MAC address */
51
+FIELD(ID_AA64MMFR0, FGT, 56, 4)
55
+ case RPI_FWREQ_GET_BOARD_MAC_ADDRESS:
52
+FIELD(ID_AA64MMFR0, ECV, 60, 4)
56
resplen = sizeof(s->macaddr.a);
53
57
dma_memory_write(&s->dma_as, value + 12, s->macaddr.a, resplen,
54
FIELD(ID_AA64MMFR1, HAFDBS, 0, 4)
58
MEMTXATTRS_UNSPECIFIED);
55
FIELD(ID_AA64MMFR1, VMIDBITS, 4, 4)
59
break;
56
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64MMFR1, LO, 16, 4)
60
- case 0x00010004: /* Get board serial */
57
FIELD(ID_AA64MMFR1, PAN, 20, 4)
61
+ case RPI_FWREQ_GET_BOARD_SERIAL:
58
FIELD(ID_AA64MMFR1, SPECSEI, 24, 4)
62
qemu_log_mask(LOG_UNIMP,
59
FIELD(ID_AA64MMFR1, XNX, 28, 4)
63
"bcm2835_property: 0x%08x get board serial NYI\n",
60
+FIELD(ID_AA64MMFR1, TWED, 32, 4)
64
tag);
61
+FIELD(ID_AA64MMFR1, ETS, 36, 4)
65
resplen = 8;
62
66
break;
63
FIELD(ID_AA64MMFR2, CNP, 0, 4)
67
- case 0x00010005: /* Get ARM memory */
64
FIELD(ID_AA64MMFR2, UAO, 4, 4)
68
+ case RPI_FWREQ_GET_ARM_MEMORY:
65
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64DFR0, CTX_CMPS, 28, 4)
69
/* base */
66
FIELD(ID_AA64DFR0, PMSVER, 32, 4)
70
stl_le_phys(&s->dma_as, value + 12, 0);
67
FIELD(ID_AA64DFR0, DOUBLELOCK, 36, 4)
71
/* size */
68
FIELD(ID_AA64DFR0, TRACEFILT, 40, 4)
72
stl_le_phys(&s->dma_as, value + 16, s->fbdev->vcram_base);
69
+FIELD(ID_AA64DFR0, MTPMU, 48, 4)
73
resplen = 8;
70
74
break;
71
FIELD(ID_DFR0, COPDBG, 0, 4)
75
- case 0x00010006: /* Get VC memory */
72
FIELD(ID_DFR0, COPSDBG, 4, 4)
76
+ case RPI_FWREQ_GET_VC_MEMORY:
77
/* base */
78
stl_le_phys(&s->dma_as, value + 12, s->fbdev->vcram_base);
79
/* size */
80
stl_le_phys(&s->dma_as, value + 16, s->fbdev->vcram_size);
81
resplen = 8;
82
break;
83
- case 0x00028001: /* Set power state */
84
+ case RPI_FWREQ_SET_POWER_STATE:
85
/* Assume that whatever device they asked for exists,
86
* and we'll just claim we set it to the desired state
87
*/
88
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
89
90
/* Clocks */
91
92
- case 0x00030001: /* Get clock state */
93
+ case RPI_FWREQ_GET_CLOCK_STATE:
94
stl_le_phys(&s->dma_as, value + 16, 0x1);
95
resplen = 8;
96
break;
97
98
- case 0x00038001: /* Set clock state */
99
+ case RPI_FWREQ_SET_CLOCK_STATE:
100
qemu_log_mask(LOG_UNIMP,
101
"bcm2835_property: 0x%08x set clock state NYI\n",
102
tag);
103
resplen = 8;
104
break;
105
106
- case 0x00030002: /* Get clock rate */
107
- case 0x00030004: /* Get max clock rate */
108
- case 0x00030007: /* Get min clock rate */
109
+ case RPI_FWREQ_GET_CLOCK_RATE:
110
+ case RPI_FWREQ_GET_MAX_CLOCK_RATE:
111
+ case RPI_FWREQ_GET_MIN_CLOCK_RATE:
112
switch (ldl_le_phys(&s->dma_as, value + 12)) {
113
- case 1: /* EMMC */
114
+ case RPI_FIRMWARE_EMMC_CLK_ID:
115
stl_le_phys(&s->dma_as, value + 16, 50000000);
116
break;
117
- case 2: /* UART */
118
+ case RPI_FIRMWARE_UART_CLK_ID:
119
stl_le_phys(&s->dma_as, value + 16, 3000000);
120
break;
121
default:
122
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
123
resplen = 8;
124
break;
125
126
- case 0x00038002: /* Set clock rate */
127
- case 0x00038004: /* Set max clock rate */
128
- case 0x00038007: /* Set min clock rate */
129
+ case RPI_FWREQ_SET_CLOCK_RATE:
130
+ case RPI_FWREQ_SET_MAX_CLOCK_RATE:
131
+ case RPI_FWREQ_SET_MIN_CLOCK_RATE:
132
qemu_log_mask(LOG_UNIMP,
133
"bcm2835_property: 0x%08x set clock rate NYI\n",
134
tag);
135
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
136
137
/* Temperature */
138
139
- case 0x00030006: /* Get temperature */
140
+ case RPI_FWREQ_GET_TEMPERATURE:
141
stl_le_phys(&s->dma_as, value + 16, 25000);
142
resplen = 8;
143
break;
144
145
- case 0x0003000A: /* Get max temperature */
146
+ case RPI_FWREQ_GET_MAX_TEMPERATURE:
147
stl_le_phys(&s->dma_as, value + 16, 99000);
148
resplen = 8;
149
break;
150
151
/* Frame buffer */
152
153
- case 0x00040001: /* Allocate buffer */
154
+ case RPI_FWREQ_FRAMEBUFFER_ALLOCATE:
155
stl_le_phys(&s->dma_as, value + 12, fbconfig.base);
156
stl_le_phys(&s->dma_as, value + 16,
157
bcm2835_fb_get_size(&fbconfig));
158
resplen = 8;
159
break;
160
- case 0x00048001: /* Release buffer */
161
+ case RPI_FWREQ_FRAMEBUFFER_RELEASE:
162
resplen = 0;
163
break;
164
- case 0x00040002: /* Blank screen */
165
+ case RPI_FWREQ_FRAMEBUFFER_BLANK:
166
resplen = 4;
167
break;
168
- case 0x00044003: /* Test physical display width/height */
169
- case 0x00044004: /* Test virtual display width/height */
170
+ case RPI_FWREQ_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT:
171
+ case RPI_FWREQ_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT:
172
resplen = 8;
173
break;
174
- case 0x00048003: /* Set physical display width/height */
175
+ case RPI_FWREQ_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT:
176
fbconfig.xres = ldl_le_phys(&s->dma_as, value + 12);
177
fbconfig.yres = ldl_le_phys(&s->dma_as, value + 16);
178
bcm2835_fb_validate_config(&fbconfig);
179
fbconfig_updated = true;
180
/* fall through */
181
- case 0x00040003: /* Get physical display width/height */
182
+ case RPI_FWREQ_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT:
183
stl_le_phys(&s->dma_as, value + 12, fbconfig.xres);
184
stl_le_phys(&s->dma_as, value + 16, fbconfig.yres);
185
resplen = 8;
186
break;
187
- case 0x00048004: /* Set virtual display width/height */
188
+ case RPI_FWREQ_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT:
189
fbconfig.xres_virtual = ldl_le_phys(&s->dma_as, value + 12);
190
fbconfig.yres_virtual = ldl_le_phys(&s->dma_as, value + 16);
191
bcm2835_fb_validate_config(&fbconfig);
192
fbconfig_updated = true;
193
/* fall through */
194
- case 0x00040004: /* Get virtual display width/height */
195
+ case RPI_FWREQ_FRAMEBUFFER_GET_VIRTUAL_WIDTH_HEIGHT:
196
stl_le_phys(&s->dma_as, value + 12, fbconfig.xres_virtual);
197
stl_le_phys(&s->dma_as, value + 16, fbconfig.yres_virtual);
198
resplen = 8;
199
break;
200
- case 0x00044005: /* Test depth */
201
+ case RPI_FWREQ_FRAMEBUFFER_TEST_DEPTH:
202
resplen = 4;
203
break;
204
- case 0x00048005: /* Set depth */
205
+ case RPI_FWREQ_FRAMEBUFFER_SET_DEPTH:
206
fbconfig.bpp = ldl_le_phys(&s->dma_as, value + 12);
207
bcm2835_fb_validate_config(&fbconfig);
208
fbconfig_updated = true;
209
/* fall through */
210
- case 0x00040005: /* Get depth */
211
+ case RPI_FWREQ_FRAMEBUFFER_GET_DEPTH:
212
stl_le_phys(&s->dma_as, value + 12, fbconfig.bpp);
213
resplen = 4;
214
break;
215
- case 0x00044006: /* Test pixel order */
216
+ case RPI_FWREQ_FRAMEBUFFER_TEST_PIXEL_ORDER:
217
resplen = 4;
218
break;
219
- case 0x00048006: /* Set pixel order */
220
+ case RPI_FWREQ_FRAMEBUFFER_SET_PIXEL_ORDER:
221
fbconfig.pixo = ldl_le_phys(&s->dma_as, value + 12);
222
bcm2835_fb_validate_config(&fbconfig);
223
fbconfig_updated = true;
224
/* fall through */
225
- case 0x00040006: /* Get pixel order */
226
+ case RPI_FWREQ_FRAMEBUFFER_GET_PIXEL_ORDER:
227
stl_le_phys(&s->dma_as, value + 12, fbconfig.pixo);
228
resplen = 4;
229
break;
230
- case 0x00044007: /* Test pixel alpha */
231
+ case RPI_FWREQ_FRAMEBUFFER_TEST_ALPHA_MODE:
232
resplen = 4;
233
break;
234
- case 0x00048007: /* Set alpha */
235
+ case RPI_FWREQ_FRAMEBUFFER_SET_ALPHA_MODE:
236
fbconfig.alpha = ldl_le_phys(&s->dma_as, value + 12);
237
bcm2835_fb_validate_config(&fbconfig);
238
fbconfig_updated = true;
239
/* fall through */
240
- case 0x00040007: /* Get alpha */
241
+ case RPI_FWREQ_FRAMEBUFFER_GET_ALPHA_MODE:
242
stl_le_phys(&s->dma_as, value + 12, fbconfig.alpha);
243
resplen = 4;
244
break;
245
- case 0x00040008: /* Get pitch */
246
+ case RPI_FWREQ_FRAMEBUFFER_GET_PITCH:
247
stl_le_phys(&s->dma_as, value + 12,
248
bcm2835_fb_get_pitch(&fbconfig));
249
resplen = 4;
250
break;
251
- case 0x00044009: /* Test virtual offset */
252
+ case RPI_FWREQ_FRAMEBUFFER_TEST_VIRTUAL_OFFSET:
253
resplen = 8;
254
break;
255
- case 0x00048009: /* Set virtual offset */
256
+ case RPI_FWREQ_FRAMEBUFFER_SET_VIRTUAL_OFFSET:
257
fbconfig.xoffset = ldl_le_phys(&s->dma_as, value + 12);
258
fbconfig.yoffset = ldl_le_phys(&s->dma_as, value + 16);
259
bcm2835_fb_validate_config(&fbconfig);
260
fbconfig_updated = true;
261
/* fall through */
262
- case 0x00040009: /* Get virtual offset */
263
+ case RPI_FWREQ_FRAMEBUFFER_GET_VIRTUAL_OFFSET:
264
stl_le_phys(&s->dma_as, value + 12, fbconfig.xoffset);
265
stl_le_phys(&s->dma_as, value + 16, fbconfig.yoffset);
266
resplen = 8;
267
break;
268
- case 0x0004000a: /* Get/Test/Set overscan */
269
- case 0x0004400a:
270
- case 0x0004800a:
271
+ case RPI_FWREQ_FRAMEBUFFER_GET_OVERSCAN:
272
+ case RPI_FWREQ_FRAMEBUFFER_TEST_OVERSCAN:
273
+ case RPI_FWREQ_FRAMEBUFFER_SET_OVERSCAN:
274
stl_le_phys(&s->dma_as, value + 12, 0);
275
stl_le_phys(&s->dma_as, value + 16, 0);
276
stl_le_phys(&s->dma_as, value + 20, 0);
277
stl_le_phys(&s->dma_as, value + 24, 0);
278
resplen = 16;
279
break;
280
- case 0x0004800b: /* Set palette */
281
+ case RPI_FWREQ_FRAMEBUFFER_SET_PALETTE:
282
offset = ldl_le_phys(&s->dma_as, value + 12);
283
length = ldl_le_phys(&s->dma_as, value + 16);
284
n = 0;
285
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
286
stl_le_phys(&s->dma_as, value + 12, 0);
287
resplen = 4;
288
break;
289
- case 0x00040013: /* Get number of displays */
290
+ case RPI_FWREQ_FRAMEBUFFER_GET_NUM_DISPLAYS:
291
stl_le_phys(&s->dma_as, value + 12, 1);
292
resplen = 4;
293
break;
294
295
- case 0x00060001: /* Get DMA channels */
296
+ case RPI_FWREQ_GET_DMA_CHANNELS:
297
/* channels 2-5 */
298
stl_le_phys(&s->dma_as, value + 12, 0x003C);
299
resplen = 4;
300
break;
301
302
- case 0x00050001: /* Get command line */
303
+ case RPI_FWREQ_GET_COMMAND_LINE:
304
/*
305
* We follow the firmware behaviour: no NUL terminator is
306
* written to the buffer, and if the buffer is too short
73
--
307
--
74
2.20.1
308
2.34.1
75
309
76
310
diff view generated by jsdifflib
1
From: Leif Lindholm <leif@nuviainc.com>
1
From: Sergey Kambalin <sergey.kambalin@auriga.com>
2
2
3
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
3
Signed-off-by: Sergey Kambalin <sergey.kambalin@auriga.com>
4
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
4
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
5
Message-id: 20210108185154.8108-5-leif@nuviainc.com
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20230612223456.33824-4-philmd@linaro.org
7
Message-Id: <20230531155258.8361-1-sergey.kambalin@auriga.com>
8
[PMD: Split from bigger patch: 4/4]
9
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
---
11
---
8
target/arm/cpu.h | 31 +++++++++++++++++++++++++++++++
12
include/hw/arm/raspi_platform.h | 5 +++++
9
1 file changed, 31 insertions(+)
13
hw/misc/bcm2835_property.c | 8 +++++---
14
2 files changed, 10 insertions(+), 3 deletions(-)
10
15
11
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
16
diff --git a/include/hw/arm/raspi_platform.h b/include/hw/arm/raspi_platform.h
12
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
13
--- a/target/arm/cpu.h
18
--- a/include/hw/arm/raspi_platform.h
14
+++ b/target/arm/cpu.h
19
+++ b/include/hw/arm/raspi_platform.h
15
@@ -XXX,XX +XXX,XX @@ FIELD(V7M_FPCCR, ASPEN, 31, 1)
20
@@ -XXX,XX +XXX,XX @@
16
/*
21
#define INTERRUPT_ILLEGAL_TYPE0 6
17
* System register ID fields.
22
#define INTERRUPT_ILLEGAL_TYPE1 7
18
*/
23
19
+FIELD(CLIDR_EL1, CTYPE1, 0, 3)
24
+/* Clock rates */
20
+FIELD(CLIDR_EL1, CTYPE2, 3, 3)
25
+#define RPI_FIRMWARE_EMMC_CLK_RATE 50000000
21
+FIELD(CLIDR_EL1, CTYPE3, 6, 3)
26
+#define RPI_FIRMWARE_UART_CLK_RATE 3000000
22
+FIELD(CLIDR_EL1, CTYPE4, 9, 3)
27
+#define RPI_FIRMWARE_DEFAULT_CLK_RATE 700000000
23
+FIELD(CLIDR_EL1, CTYPE5, 12, 3)
24
+FIELD(CLIDR_EL1, CTYPE6, 15, 3)
25
+FIELD(CLIDR_EL1, CTYPE7, 18, 3)
26
+FIELD(CLIDR_EL1, LOUIS, 21, 3)
27
+FIELD(CLIDR_EL1, LOC, 24, 3)
28
+FIELD(CLIDR_EL1, LOUU, 27, 3)
29
+FIELD(CLIDR_EL1, ICB, 30, 3)
30
+
28
+
31
+/* When FEAT_CCIDX is implemented */
29
#endif
32
+FIELD(CCSIDR_EL1, CCIDX_LINESIZE, 0, 3)
30
diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c
33
+FIELD(CCSIDR_EL1, CCIDX_ASSOCIATIVITY, 3, 21)
31
index XXXXXXX..XXXXXXX 100644
34
+FIELD(CCSIDR_EL1, CCIDX_NUMSETS, 32, 24)
32
--- a/hw/misc/bcm2835_property.c
35
+
33
+++ b/hw/misc/bcm2835_property.c
36
+/* When FEAT_CCIDX is not implemented */
34
@@ -XXX,XX +XXX,XX @@
37
+FIELD(CCSIDR_EL1, LINESIZE, 0, 3)
35
#include "qemu/log.h"
38
+FIELD(CCSIDR_EL1, ASSOCIATIVITY, 3, 10)
36
#include "qemu/module.h"
39
+FIELD(CCSIDR_EL1, NUMSETS, 13, 15)
37
#include "trace.h"
40
+
38
+#include "hw/arm/raspi_platform.h"
41
+FIELD(CTR_EL0, IMINLINE, 0, 4)
39
42
+FIELD(CTR_EL0, L1IP, 14, 2)
40
/* https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface */
43
+FIELD(CTR_EL0, DMINLINE, 16, 4)
41
44
+FIELD(CTR_EL0, ERG, 20, 4)
42
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
45
+FIELD(CTR_EL0, CWG, 24, 4)
43
case RPI_FWREQ_GET_MIN_CLOCK_RATE:
46
+FIELD(CTR_EL0, IDC, 28, 1)
44
switch (ldl_le_phys(&s->dma_as, value + 12)) {
47
+FIELD(CTR_EL0, DIC, 29, 1)
45
case RPI_FIRMWARE_EMMC_CLK_ID:
48
+FIELD(CTR_EL0, TMINLINE, 32, 6)
46
- stl_le_phys(&s->dma_as, value + 16, 50000000);
49
+
47
+ stl_le_phys(&s->dma_as, value + 16, RPI_FIRMWARE_EMMC_CLK_RATE);
50
FIELD(MIDR_EL1, REVISION, 0, 4)
48
break;
51
FIELD(MIDR_EL1, PARTNUM, 4, 12)
49
case RPI_FIRMWARE_UART_CLK_ID:
52
FIELD(MIDR_EL1, ARCHITECTURE, 16, 4)
50
- stl_le_phys(&s->dma_as, value + 16, 3000000);
51
+ stl_le_phys(&s->dma_as, value + 16, RPI_FIRMWARE_UART_CLK_RATE);
52
break;
53
default:
54
- stl_le_phys(&s->dma_as, value + 16, 700000000);
55
+ stl_le_phys(&s->dma_as, value + 16,
56
+ RPI_FIRMWARE_DEFAULT_CLK_RATE);
57
break;
58
}
59
resplen = 8;
53
--
60
--
54
2.20.1
61
2.34.1
55
62
56
63
diff view generated by jsdifflib
1
From: Roman Bolshakov <r.bolshakov@yadro.com>
1
From: Sergey Kambalin <sergey.kambalin@auriga.com>
2
2
3
QEMU documentation can't be opened if QEMU is run from build tree
3
Signed-off-by: Sergey Kambalin <sergey.kambalin@auriga.com>
4
because executables are placed in the top of build tree after conversion
4
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
5
to meson.
5
Message-id: 20230612223456.33824-5-philmd@linaro.org
6
6
Message-Id: <20230531155258.8361-1-sergey.kambalin@auriga.com>
7
Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
7
[PMD: Split from bigger patch: 3/4]
8
Reported-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
9
Message-id: 20210108213815.64678-1-r.bolshakov@yadro.com
9
[PMM: added a comment about RPI_FIRMWARE_CORE_CLK_RATE
10
really being SoC-specific]
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
13
---
13
ui/cocoa.m | 2 +-
14
include/hw/arm/raspi_platform.h | 5 +++++
14
1 file changed, 1 insertion(+), 1 deletion(-)
15
hw/misc/bcm2835_property.c | 3 +++
16
2 files changed, 8 insertions(+)
15
17
16
diff --git a/ui/cocoa.m b/ui/cocoa.m
18
diff --git a/include/hw/arm/raspi_platform.h b/include/hw/arm/raspi_platform.h
17
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
18
--- a/ui/cocoa.m
20
--- a/include/hw/arm/raspi_platform.h
19
+++ b/ui/cocoa.m
21
+++ b/include/hw/arm/raspi_platform.h
20
@@ -XXX,XX +XXX,XX @@ QemuCocoaView *cocoaView;
22
@@ -XXX,XX +XXX,XX @@
21
- (void) openDocumentation: (NSString *) filename
23
/* Clock rates */
22
{
24
#define RPI_FIRMWARE_EMMC_CLK_RATE 50000000
23
/* Where to look for local files */
25
#define RPI_FIRMWARE_UART_CLK_RATE 3000000
24
- NSString *path_array[] = {@"../share/doc/qemu/", @"../doc/qemu/", @"../docs/"};
26
+/*
25
+ NSString *path_array[] = {@"../share/doc/qemu/", @"../doc/qemu/", @"docs/"};
27
+ * TODO: this is really SoC-specific; we might want to
26
NSString *full_file_path;
28
+ * set it per-SoC if it turns out any guests care.
27
29
+ */
28
/* iterate thru the possible paths until the file is found */
30
+#define RPI_FIRMWARE_CORE_CLK_RATE 350000000
31
#define RPI_FIRMWARE_DEFAULT_CLK_RATE 700000000
32
33
#endif
34
diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c
35
index XXXXXXX..XXXXXXX 100644
36
--- a/hw/misc/bcm2835_property.c
37
+++ b/hw/misc/bcm2835_property.c
38
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
39
case RPI_FIRMWARE_UART_CLK_ID:
40
stl_le_phys(&s->dma_as, value + 16, RPI_FIRMWARE_UART_CLK_RATE);
41
break;
42
+ case RPI_FIRMWARE_CORE_CLK_ID:
43
+ stl_le_phys(&s->dma_as, value + 16, RPI_FIRMWARE_CORE_CLK_RATE);
44
+ break;
45
default:
46
stl_le_phys(&s->dma_as, value + 16,
47
RPI_FIRMWARE_DEFAULT_CLK_RATE);
29
--
48
--
30
2.20.1
49
2.34.1
31
50
32
51
diff view generated by jsdifflib