1
Arm queue; not huge but I figured I might as well send it out since
1
Hi; here's the latest arm pullreq. This is mostly patches from
2
I've been doing code review today and there's no queue of unprocessed
2
RTH, plus a couple of other more minor things. Switching to
3
pullreqs...
3
PCREL is the big one, hopefully should improve performance.
4
4
5
thanks
5
thanks
6
-- PMM
6
-- PMM
7
7
8
The following changes since commit b3f846c59d8405bb87c551187721fc92ff2f1b92:
8
The following changes since commit 214a8da23651f2472b296b3293e619fd58d9e212:
9
9
10
Merge remote-tracking branch 'remotes/huth-gitlab/tags/pull-request-2021-01-11v2' into staging (2021-01-11 15:15:35 +0000)
10
Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging (2022-10-18 11:14:31 -0400)
11
11
12
are available in the Git repository at:
12
are available in the Git repository at:
13
13
14
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20210112
14
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20221020
15
15
16
for you to fetch changes up to 19d131395ccaf503db21dadd8257e6dc9fc1d7de:
16
for you to fetch changes up to 5db899303799e49209016a93289b8694afa1449e:
17
17
18
ui/cocoa: Fix openFile: deprecation on Big Sur (2021-01-12 11:38:37 +0000)
18
hw/ide/microdrive: Use device_cold_reset() for self-resets (2022-10-20 12:11:53 +0100)
19
19
20
----------------------------------------------------------------
20
----------------------------------------------------------------
21
target-arm queue:
21
target-arm queue:
22
* arm: Support emulation of ARMv8.4-TTST extension
22
* Switch to TARGET_TB_PCREL
23
* arm: Update cpu.h ID register field definitions
23
* More pagetable-walk refactoring preparatory to HAFDBS
24
* arm: Fix breakage of XScale instruction emulation
24
* update the cortex-a15 MIDR to latest rev
25
* hw/net/lan9118: Fix RX Status FIFO PEEK value
25
* hw/char/pl011: fix baud rate calculation
26
* npcm7xx: Add ADC and PWM emulation
26
* hw/ide/microdrive: Use device_cold_reset() for self-resets
27
* ui/cocoa: Make "open docs" help menu entry work again when binary
28
is run from the build tree
29
* ui/cocoa: Fix openFile: deprecation on Big Sur
30
* docs: Add qemu-storage-daemon(1) manpage to meson.build
31
* docs: Build and install all the docs in a single manual
32
27
33
----------------------------------------------------------------
28
----------------------------------------------------------------
34
Hao Wu (6):
29
Alex Bennée (1):
35
hw/misc: Add clock converter in NPCM7XX CLK module
30
target/arm: update the cortex-a15 MIDR to latest rev
36
hw/timer: Refactor NPCM7XX Timer to use CLK clock
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
31
42
Leif Lindholm (6):
32
Baruch Siach (1):
43
target/arm: fix typo in cpu.h ID_AA64PFR1 field name
33
hw/char/pl011: fix baud rate calculation
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
34
50
Peter Maydell (5):
35
Peter Maydell (1):
51
docs: Add qemu-storage-daemon(1) manpage to meson.build
36
hw/ide/microdrive: Use device_cold_reset() for self-resets
52
docs: Build and install all the docs in a single manual
53
target/arm: Don't decode insns in the XScale/iWMMXt space as cp insns
54
hw/net/lan9118: Fix RX Status FIFO PEEK value
55
hw/net/lan9118: Add symbolic constants for register offsets
56
37
57
Roman Bolshakov (2):
38
Richard Henderson (21):
58
ui/cocoa: Update path to docs in build tree
39
target/arm: Enable TARGET_PAGE_ENTRY_EXTRA
59
ui/cocoa: Fix openFile: deprecation on Big Sur
40
target/arm: Use probe_access_full for MTE
41
target/arm: Use probe_access_full for BTI
42
target/arm: Add ARMMMUIdx_Phys_{S,NS}
43
target/arm: Move ARMMMUIdx_Stage2 to a real tlb mmu_idx
44
target/arm: Restrict tlb flush from vttbr_write to vmid change
45
target/arm: Split out S1Translate type
46
target/arm: Plumb debug into S1Translate
47
target/arm: Move be test for regime into S1TranslateResult
48
target/arm: Use softmmu tlbs for page table walking
49
target/arm: Split out get_phys_addr_twostage
50
target/arm: Use bool consistently for get_phys_addr subroutines
51
target/arm: Introduce curr_insn_len
52
target/arm: Change gen_goto_tb to work on displacements
53
target/arm: Change gen_*set_pc_im to gen_*update_pc
54
target/arm: Change gen_exception_insn* to work on displacements
55
target/arm: Remove gen_exception_internal_insn pc argument
56
target/arm: Change gen_jmp* to work on displacements
57
target/arm: Introduce gen_pc_plus_diff for aarch64
58
target/arm: Introduce gen_pc_plus_diff for aarch32
59
target/arm: Enable TARGET_TB_PCREL
60
60
61
Rémi Denis-Courmont (2):
61
target/arm/cpu-param.h | 17 +-
62
target/arm: ARMv8.4-TTST extension
62
target/arm/cpu.h | 47 ++--
63
target/arm: enable Small Translation tables in max CPU
63
target/arm/internals.h | 1 +
64
target/arm/sve_ldst_internal.h | 1 +
65
target/arm/translate-a32.h | 2 +-
66
target/arm/translate.h | 66 ++++-
67
hw/char/pl011.c | 2 +-
68
hw/ide/microdrive.c | 8 +-
69
target/arm/cpu.c | 23 +-
70
target/arm/cpu_tcg.c | 4 +-
71
target/arm/helper.c | 155 +++++++++---
72
target/arm/mte_helper.c | 62 ++---
73
target/arm/ptw.c | 535 +++++++++++++++++++++++++----------------
74
target/arm/sve_helper.c | 54 ++---
75
target/arm/tlb_helper.c | 24 +-
76
target/arm/translate-a64.c | 220 ++++++++++-------
77
target/arm/translate-m-nocp.c | 8 +-
78
target/arm/translate-mve.c | 2 +-
79
target/arm/translate-vfp.c | 10 +-
80
target/arm/translate.c | 284 +++++++++++++---------
81
20 files changed, 918 insertions(+), 607 deletions(-)
64
82
65
docs/conf.py | 46 ++-
66
docs/devel/conf.py | 15 -
67
docs/index.html.in | 17 -
68
docs/interop/conf.py | 28 --
69
docs/meson.build | 65 ++--
70
docs/specs/conf.py | 16 -
71
docs/system/arm/nuvoton.rst | 4 +-
72
docs/system/conf.py | 28 --
73
docs/tools/conf.py | 37 --
74
docs/user/conf.py | 15 -
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
1
From: Roman Bolshakov <r.bolshakov@yadro.com>
1
From: Baruch Siach <baruch@tkos.co.il>
2
2
3
QEMU documentation can't be opened if QEMU is run from build tree
3
The PL011 TRM says that "UARTIBRD = 0 is invalid and UARTFBRD is ignored
4
because executables are placed in the top of build tree after conversion
4
when this is the case". But the code looks at FBRD for the invalid case.
5
to meson.
5
Fix this.
6
6
7
Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
7
Signed-off-by: Baruch Siach <baruch@tkos.co.il>
8
Reported-by: Peter Maydell <peter.maydell@linaro.org>
8
Message-id: 1408f62a2e45665816527d4845ffde650957d5ab.1665051588.git.baruchs-c@neureality.ai
9
Message-id: 20210108213815.64678-1-r.bolshakov@yadro.com
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
11
---
13
ui/cocoa.m | 2 +-
12
hw/char/pl011.c | 2 +-
14
1 file changed, 1 insertion(+), 1 deletion(-)
13
1 file changed, 1 insertion(+), 1 deletion(-)
15
14
16
diff --git a/ui/cocoa.m b/ui/cocoa.m
15
diff --git a/hw/char/pl011.c b/hw/char/pl011.c
17
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
18
--- a/ui/cocoa.m
17
--- a/hw/char/pl011.c
19
+++ b/ui/cocoa.m
18
+++ b/hw/char/pl011.c
20
@@ -XXX,XX +XXX,XX @@ QemuCocoaView *cocoaView;
19
@@ -XXX,XX +XXX,XX @@ static unsigned int pl011_get_baudrate(const PL011State *s)
21
- (void) openDocumentation: (NSString *) filename
22
{
20
{
23
/* Where to look for local files */
21
uint64_t clk;
24
- NSString *path_array[] = {@"../share/doc/qemu/", @"../doc/qemu/", @"../docs/"};
22
25
+ NSString *path_array[] = {@"../share/doc/qemu/", @"../doc/qemu/", @"docs/"};
23
- if (s->fbrd == 0) {
26
NSString *full_file_path;
24
+ if (s->ibrd == 0) {
27
25
return 0;
28
/* iterate thru the possible paths until the file is found */
26
}
27
29
--
28
--
30
2.20.1
29
2.25.1
31
32
diff view generated by jsdifflib
1
From: Leif Lindholm <leif@nuviainc.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Add entries present in ARM DDI 0487F.c (August 2020).
3
The CPUTLBEntryFull structure now stores the original pte attributes, as
4
well as the physical address. Therefore, we no longer need a separate
5
bit in MemTxAttrs, nor do we need to walk the tree of memory regions.
4
6
5
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20210108185154.8108-7-leif@nuviainc.com
9
Message-id: 20221011031911.2408754-3-richard.henderson@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
---
11
target/arm/cpu.h | 28 ++++++++++++++++++++++++++++
12
target/arm/cpu.h | 1 -
12
1 file changed, 28 insertions(+)
13
target/arm/sve_ldst_internal.h | 1 +
14
target/arm/mte_helper.c | 62 ++++++++++------------------------
15
target/arm/sve_helper.c | 54 ++++++++++-------------------
16
target/arm/tlb_helper.c | 4 ---
17
5 files changed, 36 insertions(+), 86 deletions(-)
13
18
14
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
19
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
15
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/cpu.h
21
--- a/target/arm/cpu.h
17
+++ b/target/arm/cpu.h
22
+++ b/target/arm/cpu.h
18
@@ -XXX,XX +XXX,XX @@ FIELD(ID_ISAR6, DP, 4, 4)
23
@@ -XXX,XX +XXX,XX @@ static inline MemTxAttrs *typecheck_memtxattrs(MemTxAttrs *x)
19
FIELD(ID_ISAR6, FHM, 8, 4)
24
* generic target bits directly.
20
FIELD(ID_ISAR6, SB, 12, 4)
25
*/
21
FIELD(ID_ISAR6, SPECRES, 16, 4)
26
#define arm_tlb_bti_gp(x) (typecheck_memtxattrs(x)->target_tlb_bit0)
22
+FIELD(ID_ISAR6, BF16, 20, 4)
27
-#define arm_tlb_mte_tagged(x) (typecheck_memtxattrs(x)->target_tlb_bit1)
23
+FIELD(ID_ISAR6, I8MM, 24, 4)
28
24
29
/*
25
FIELD(ID_MMFR0, VMSA, 0, 4)
30
* AArch64 usage of the PAGE_TARGET_* bits for linux-user.
26
FIELD(ID_MMFR0, PMSA, 4, 4)
31
diff --git a/target/arm/sve_ldst_internal.h b/target/arm/sve_ldst_internal.h
27
@@ -XXX,XX +XXX,XX @@ FIELD(ID_MMFR0, AUXREG, 20, 4)
32
index XXXXXXX..XXXXXXX 100644
28
FIELD(ID_MMFR0, FCSE, 24, 4)
33
--- a/target/arm/sve_ldst_internal.h
29
FIELD(ID_MMFR0, INNERSHR, 28, 4)
34
+++ b/target/arm/sve_ldst_internal.h
30
35
@@ -XXX,XX +XXX,XX @@ typedef struct {
31
+FIELD(ID_MMFR1, L1HVDVA, 0, 4)
36
void *host;
32
+FIELD(ID_MMFR1, L1UNIVA, 4, 4)
37
int flags;
33
+FIELD(ID_MMFR1, L1HVDSW, 8, 4)
38
MemTxAttrs attrs;
34
+FIELD(ID_MMFR1, L1UNISW, 12, 4)
39
+ bool tagged;
35
+FIELD(ID_MMFR1, L1HVD, 16, 4)
40
} SVEHostPage;
36
+FIELD(ID_MMFR1, L1UNI, 20, 4)
41
37
+FIELD(ID_MMFR1, L1TSTCLN, 24, 4)
42
bool sve_probe_page(SVEHostPage *info, bool nofault, CPUARMState *env,
38
+FIELD(ID_MMFR1, BPRED, 28, 4)
43
diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c
44
index XXXXXXX..XXXXXXX 100644
45
--- a/target/arm/mte_helper.c
46
+++ b/target/arm/mte_helper.c
47
@@ -XXX,XX +XXX,XX @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx,
48
TARGET_PAGE_BITS - LOG2_TAG_GRANULE - 1);
49
return tags + index;
50
#else
51
- uintptr_t index;
52
CPUTLBEntryFull *full;
53
+ MemTxAttrs attrs;
54
int in_page, flags;
55
- ram_addr_t ptr_ra;
56
hwaddr ptr_paddr, tag_paddr, xlat;
57
MemoryRegion *mr;
58
ARMASIdx tag_asi;
59
@@ -XXX,XX +XXX,XX @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx,
60
* valid. Indicate to probe_access_flags no-fault, then assert that
61
* we received a valid page.
62
*/
63
- flags = probe_access_flags(env, ptr, ptr_access, ptr_mmu_idx,
64
- ra == 0, &host, ra);
65
+ flags = probe_access_full(env, ptr, ptr_access, ptr_mmu_idx,
66
+ ra == 0, &host, &full, ra);
67
assert(!(flags & TLB_INVALID_MASK));
68
69
- /*
70
- * Find the CPUTLBEntryFull for ptr. This *must* be present in the TLB
71
- * because we just found the mapping.
72
- * TODO: Perhaps there should be a cputlb helper that returns a
73
- * matching tlb entry + iotlb entry.
74
- */
75
- index = tlb_index(env, ptr_mmu_idx, ptr);
76
-# ifdef CONFIG_DEBUG_TCG
77
- {
78
- CPUTLBEntry *entry = tlb_entry(env, ptr_mmu_idx, ptr);
79
- target_ulong comparator = (ptr_access == MMU_DATA_LOAD
80
- ? entry->addr_read
81
- : tlb_addr_write(entry));
82
- g_assert(tlb_hit(comparator, ptr));
83
- }
84
-# endif
85
- full = &env_tlb(env)->d[ptr_mmu_idx].fulltlb[index];
86
-
87
/* If the virtual page MemAttr != Tagged, access unchecked. */
88
- if (!arm_tlb_mte_tagged(&full->attrs)) {
89
+ if (full->pte_attrs != 0xf0) {
90
return NULL;
91
}
92
93
@@ -XXX,XX +XXX,XX @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx,
94
return NULL;
95
}
96
97
+ /*
98
+ * Remember these values across the second lookup below,
99
+ * which may invalidate this pointer via tlb resize.
100
+ */
101
+ ptr_paddr = full->phys_addr;
102
+ attrs = full->attrs;
103
+ full = NULL;
39
+
104
+
40
+FIELD(ID_MMFR2, L1HVDFG, 0, 4)
105
/*
41
+FIELD(ID_MMFR2, L1HVDBG, 4, 4)
106
* The Normal memory access can extend to the next page. E.g. a single
42
+FIELD(ID_MMFR2, L1HVDRNG, 8, 4)
107
* 8-byte access to the last byte of a page will check only the last
43
+FIELD(ID_MMFR2, HVDTLB, 12, 4)
108
@@ -XXX,XX +XXX,XX @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx,
44
+FIELD(ID_MMFR2, UNITLB, 16, 4)
109
*/
45
+FIELD(ID_MMFR2, MEMBARR, 20, 4)
110
in_page = -(ptr | TARGET_PAGE_MASK);
46
+FIELD(ID_MMFR2, WFISTALL, 24, 4)
111
if (unlikely(ptr_size > in_page)) {
47
+FIELD(ID_MMFR2, HWACCFLG, 28, 4)
112
- void *ignore;
48
+
113
- flags |= probe_access_flags(env, ptr + in_page, ptr_access,
49
FIELD(ID_MMFR3, CMAINTVA, 0, 4)
114
- ptr_mmu_idx, ra == 0, &ignore, ra);
50
FIELD(ID_MMFR3, CMAINTSW, 4, 4)
115
+ flags |= probe_access_full(env, ptr + in_page, ptr_access,
51
FIELD(ID_MMFR3, BPMAINT, 8, 4)
116
+ ptr_mmu_idx, ra == 0, &host, &full, ra);
52
@@ -XXX,XX +XXX,XX @@ FIELD(ID_MMFR4, LSM, 20, 4)
117
assert(!(flags & TLB_INVALID_MASK));
53
FIELD(ID_MMFR4, CCIDX, 24, 4)
118
}
54
FIELD(ID_MMFR4, EVT, 28, 4)
119
55
120
@@ -XXX,XX +XXX,XX @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx,
56
+FIELD(ID_MMFR5, ETS, 0, 4)
121
if (unlikely(flags & TLB_WATCHPOINT)) {
57
+
122
int wp = ptr_access == MMU_DATA_LOAD ? BP_MEM_READ : BP_MEM_WRITE;
58
FIELD(ID_PFR0, STATE0, 0, 4)
123
assert(ra != 0);
59
FIELD(ID_PFR0, STATE1, 4, 4)
124
- cpu_check_watchpoint(env_cpu(env), ptr, ptr_size,
60
FIELD(ID_PFR0, STATE2, 8, 4)
125
- full->attrs, wp, ra);
61
@@ -XXX,XX +XXX,XX @@ FIELD(ID_PFR1, SEC_FRAC, 20, 4)
126
+ cpu_check_watchpoint(env_cpu(env), ptr, ptr_size, attrs, wp, ra);
62
FIELD(ID_PFR1, VIRT_FRAC, 24, 4)
127
}
63
FIELD(ID_PFR1, GIC, 28, 4)
128
64
129
- /*
65
+FIELD(ID_PFR2, CSV3, 0, 4)
130
- * Find the physical address within the normal mem space.
66
+FIELD(ID_PFR2, SSBS, 4, 4)
131
- * The memory region lookup must succeed because TLB_MMIO was
67
+FIELD(ID_PFR2, RAS_FRAC, 8, 4)
132
- * not set in the cputlb lookup above.
68
+
133
- */
69
FIELD(ID_AA64ISAR0, AES, 4, 4)
134
- mr = memory_region_from_host(host, &ptr_ra);
70
FIELD(ID_AA64ISAR0, SHA1, 8, 4)
135
- tcg_debug_assert(mr != NULL);
71
FIELD(ID_AA64ISAR0, SHA2, 12, 4)
136
- tcg_debug_assert(memory_region_is_ram(mr));
72
@@ -XXX,XX +XXX,XX @@ FIELD(ID_DFR0, MPROFDBG, 20, 4)
137
- ptr_paddr = ptr_ra;
73
FIELD(ID_DFR0, PERFMON, 24, 4)
138
- do {
74
FIELD(ID_DFR0, TRACEFILT, 28, 4)
139
- ptr_paddr += mr->addr;
75
140
- mr = mr->container;
76
+FIELD(ID_DFR1, MTPMU, 0, 4)
141
- } while (mr);
77
+
142
-
78
FIELD(DBGDIDR, SE_IMP, 12, 1)
143
/* Convert to the physical address in tag space. */
79
FIELD(DBGDIDR, NSUHD_IMP, 14, 1)
144
tag_paddr = ptr_paddr >> (LOG2_TAG_GRANULE + 1);
80
FIELD(DBGDIDR, VERSION, 16, 4)
145
146
/* Look up the address in tag space. */
147
- tag_asi = full->attrs.secure ? ARMASIdx_TagS : ARMASIdx_TagNS;
148
+ tag_asi = attrs.secure ? ARMASIdx_TagS : ARMASIdx_TagNS;
149
tag_as = cpu_get_address_space(env_cpu(env), tag_asi);
150
mr = address_space_translate(tag_as, tag_paddr, &xlat, NULL,
151
- tag_access == MMU_DATA_STORE,
152
- full->attrs);
153
+ tag_access == MMU_DATA_STORE, attrs);
154
155
/*
156
* Note that @mr will never be NULL. If there is nothing in the address
157
diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c
158
index XXXXXXX..XXXXXXX 100644
159
--- a/target/arm/sve_helper.c
160
+++ b/target/arm/sve_helper.c
161
@@ -XXX,XX +XXX,XX @@ bool sve_probe_page(SVEHostPage *info, bool nofault, CPUARMState *env,
162
*/
163
addr = useronly_clean_ptr(addr);
164
165
+#ifdef CONFIG_USER_ONLY
166
flags = probe_access_flags(env, addr, access_type, mmu_idx, nofault,
167
&info->host, retaddr);
168
+ memset(&info->attrs, 0, sizeof(info->attrs));
169
+ /* Require both ANON and MTE; see allocation_tag_mem(). */
170
+ info->tagged = (flags & PAGE_ANON) && (flags & PAGE_MTE);
171
+#else
172
+ CPUTLBEntryFull *full;
173
+ flags = probe_access_full(env, addr, access_type, mmu_idx, nofault,
174
+ &info->host, &full, retaddr);
175
+ info->attrs = full->attrs;
176
+ info->tagged = full->pte_attrs == 0xf0;
177
+#endif
178
info->flags = flags;
179
180
if (flags & TLB_INVALID_MASK) {
181
@@ -XXX,XX +XXX,XX @@ bool sve_probe_page(SVEHostPage *info, bool nofault, CPUARMState *env,
182
183
/* Ensure that info->host[] is relative to addr, not addr + mem_off. */
184
info->host -= mem_off;
185
-
186
-#ifdef CONFIG_USER_ONLY
187
- memset(&info->attrs, 0, sizeof(info->attrs));
188
- /* Require both MAP_ANON and PROT_MTE -- see allocation_tag_mem. */
189
- arm_tlb_mte_tagged(&info->attrs) =
190
- (flags & PAGE_ANON) && (flags & PAGE_MTE);
191
-#else
192
- /*
193
- * Find the iotlbentry for addr and return the transaction attributes.
194
- * This *must* be present in the TLB because we just found the mapping.
195
- */
196
- {
197
- uintptr_t index = tlb_index(env, mmu_idx, addr);
198
-
199
-# ifdef CONFIG_DEBUG_TCG
200
- CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr);
201
- target_ulong comparator = (access_type == MMU_DATA_LOAD
202
- ? entry->addr_read
203
- : tlb_addr_write(entry));
204
- g_assert(tlb_hit(comparator, addr));
205
-# endif
206
-
207
- CPUTLBEntryFull *full = &env_tlb(env)->d[mmu_idx].fulltlb[index];
208
- info->attrs = full->attrs;
209
- }
210
-#endif
211
-
212
return true;
213
}
214
215
@@ -XXX,XX +XXX,XX @@ void sve_cont_ldst_mte_check(SVEContLdSt *info, CPUARMState *env,
216
intptr_t mem_off, reg_off, reg_last;
217
218
/* Process the page only if MemAttr == Tagged. */
219
- if (arm_tlb_mte_tagged(&info->page[0].attrs)) {
220
+ if (info->page[0].tagged) {
221
mem_off = info->mem_off_first[0];
222
reg_off = info->reg_off_first[0];
223
reg_last = info->reg_off_split;
224
@@ -XXX,XX +XXX,XX @@ void sve_cont_ldst_mte_check(SVEContLdSt *info, CPUARMState *env,
225
}
226
227
mem_off = info->mem_off_first[1];
228
- if (mem_off >= 0 && arm_tlb_mte_tagged(&info->page[1].attrs)) {
229
+ if (mem_off >= 0 && info->page[1].tagged) {
230
reg_off = info->reg_off_first[1];
231
reg_last = info->reg_off_last[1];
232
233
@@ -XXX,XX +XXX,XX @@ void sve_ldnfff1_r(CPUARMState *env, void *vg, const target_ulong addr,
234
* Disable MTE checking if the Tagged bit is not set. Since TBI must
235
* be set within MTEDESC for MTE, !mtedesc => !mte_active.
236
*/
237
- if (!arm_tlb_mte_tagged(&info.page[0].attrs)) {
238
+ if (!info.page[0].tagged) {
239
mtedesc = 0;
240
}
241
242
@@ -XXX,XX +XXX,XX @@ void sve_ld1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm,
243
cpu_check_watchpoint(env_cpu(env), addr, msize,
244
info.attrs, BP_MEM_READ, retaddr);
245
}
246
- if (mtedesc && arm_tlb_mte_tagged(&info.attrs)) {
247
+ if (mtedesc && info.tagged) {
248
mte_check(env, mtedesc, addr, retaddr);
249
}
250
if (unlikely(info.flags & TLB_MMIO)) {
251
@@ -XXX,XX +XXX,XX @@ void sve_ld1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm,
252
msize, info.attrs,
253
BP_MEM_READ, retaddr);
254
}
255
- if (mtedesc && arm_tlb_mte_tagged(&info.attrs)) {
256
+ if (mtedesc && info.tagged) {
257
mte_check(env, mtedesc, addr, retaddr);
258
}
259
tlb_fn(env, &scratch, reg_off, addr, retaddr);
260
@@ -XXX,XX +XXX,XX @@ void sve_ldff1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm,
261
(env_cpu(env), addr, msize) & BP_MEM_READ)) {
262
goto fault;
263
}
264
- if (mtedesc &&
265
- arm_tlb_mte_tagged(&info.attrs) &&
266
- !mte_probe(env, mtedesc, addr)) {
267
+ if (mtedesc && info.tagged && !mte_probe(env, mtedesc, addr)) {
268
goto fault;
269
}
270
271
@@ -XXX,XX +XXX,XX @@ void sve_st1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm,
272
info.attrs, BP_MEM_WRITE, retaddr);
273
}
274
275
- if (mtedesc && arm_tlb_mte_tagged(&info.attrs)) {
276
+ if (mtedesc && info.tagged) {
277
mte_check(env, mtedesc, addr, retaddr);
278
}
279
}
280
diff --git a/target/arm/tlb_helper.c b/target/arm/tlb_helper.c
281
index XXXXXXX..XXXXXXX 100644
282
--- a/target/arm/tlb_helper.c
283
+++ b/target/arm/tlb_helper.c
284
@@ -XXX,XX +XXX,XX @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
285
res.f.phys_addr &= TARGET_PAGE_MASK;
286
address &= TARGET_PAGE_MASK;
287
}
288
- /* Notice and record tagged memory. */
289
- if (cpu_isar_feature(aa64_mte, cpu) && res.cacheattrs.attrs == 0xf0) {
290
- arm_tlb_mte_tagged(&res.f.attrs) = true;
291
- }
292
293
res.f.pte_attrs = res.cacheattrs.attrs;
294
res.f.shareability = res.cacheattrs.shareability;
81
--
295
--
82
2.20.1
296
2.25.1
83
84
diff view generated by jsdifflib
1
From: Leif Lindholm <leif@nuviainc.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
SBSS -> SSBS
3
Add a field to TARGET_PAGE_ENTRY_EXTRA to hold the guarded bit.
4
In is_guarded_page, use probe_access_full instead of just guessing
5
that the tlb entry is still present. Also handles the FIXME about
6
executing from device memory.
4
7
5
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
6
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
9
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20210108185154.8108-2-leif@nuviainc.com
10
Message-id: 20221011031911.2408754-4-richard.henderson@linaro.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
12
---
12
target/arm/cpu.h | 2 +-
13
target/arm/cpu-param.h | 9 +++++----
13
1 file changed, 1 insertion(+), 1 deletion(-)
14
target/arm/cpu.h | 13 -------------
15
target/arm/internals.h | 1 +
16
target/arm/ptw.c | 7 ++++---
17
target/arm/translate-a64.c | 21 ++++++++++-----------
18
5 files changed, 20 insertions(+), 31 deletions(-)
14
19
20
diff --git a/target/arm/cpu-param.h b/target/arm/cpu-param.h
21
index XXXXXXX..XXXXXXX 100644
22
--- a/target/arm/cpu-param.h
23
+++ b/target/arm/cpu-param.h
24
@@ -XXX,XX +XXX,XX @@
25
*
26
* For ARMMMUIdx_Stage2*, pte_attrs is the S2 descriptor bits [5:2].
27
* Otherwise, pte_attrs is the same as the MAIR_EL1 8-bit format.
28
- * For shareability, as in the SH field of the VMSAv8-64 PTEs.
29
+ * For shareability and guarded, as in the SH and GP fields respectively
30
+ * of the VMSAv8-64 PTEs.
31
*/
32
# define TARGET_PAGE_ENTRY_EXTRA \
33
- uint8_t pte_attrs; \
34
- uint8_t shareability;
35
-
36
+ uint8_t pte_attrs; \
37
+ uint8_t shareability; \
38
+ bool guarded;
39
#endif
40
41
#define NB_MMU_MODES 8
15
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
42
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
16
index XXXXXXX..XXXXXXX 100644
43
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/cpu.h
44
--- a/target/arm/cpu.h
18
+++ b/target/arm/cpu.h
45
+++ b/target/arm/cpu.h
19
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64PFR0, RAS, 28, 4)
46
@@ -XXX,XX +XXX,XX @@ static inline uint64_t *aa64_vfp_qreg(CPUARMState *env, unsigned regno)
20
FIELD(ID_AA64PFR0, SVE, 32, 4)
47
/* Shared between translate-sve.c and sve_helper.c. */
21
48
extern const uint64_t pred_esz_masks[5];
22
FIELD(ID_AA64PFR1, BT, 0, 4)
49
23
-FIELD(ID_AA64PFR1, SBSS, 4, 4)
50
-/* Helper for the macros below, validating the argument type. */
24
+FIELD(ID_AA64PFR1, SSBS, 4, 4)
51
-static inline MemTxAttrs *typecheck_memtxattrs(MemTxAttrs *x)
25
FIELD(ID_AA64PFR1, MTE, 8, 4)
52
-{
26
FIELD(ID_AA64PFR1, RAS_FRAC, 12, 4)
53
- return x;
54
-}
55
-
56
-/*
57
- * Lvalue macros for ARM TLB bits that we must cache in the TCG TLB.
58
- * Using these should be a bit more self-documenting than using the
59
- * generic target bits directly.
60
- */
61
-#define arm_tlb_bti_gp(x) (typecheck_memtxattrs(x)->target_tlb_bit0)
62
-
63
/*
64
* AArch64 usage of the PAGE_TARGET_* bits for linux-user.
65
* Note that with the Linux kernel, PROT_MTE may not be cleared by mprotect
66
diff --git a/target/arm/internals.h b/target/arm/internals.h
67
index XXXXXXX..XXXXXXX 100644
68
--- a/target/arm/internals.h
69
+++ b/target/arm/internals.h
70
@@ -XXX,XX +XXX,XX @@ typedef struct ARMCacheAttrs {
71
unsigned int attrs:8;
72
unsigned int shareability:2; /* as in the SH field of the VMSAv8-64 PTEs */
73
bool is_s2_format:1;
74
+ bool guarded:1; /* guarded bit of the v8-64 PTE */
75
} ARMCacheAttrs;
76
77
/* Fields that are valid upon success. */
78
diff --git a/target/arm/ptw.c b/target/arm/ptw.c
79
index XXXXXXX..XXXXXXX 100644
80
--- a/target/arm/ptw.c
81
+++ b/target/arm/ptw.c
82
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
83
*/
84
result->f.attrs.secure = false;
85
}
86
- /* When in aarch64 mode, and BTI is enabled, remember GP in the IOTLB. */
87
- if (aarch64 && guarded && cpu_isar_feature(aa64_bti, cpu)) {
88
- arm_tlb_bti_gp(&result->f.attrs) = true;
89
+
90
+ /* When in aarch64 mode, and BTI is enabled, remember GP in the TLB. */
91
+ if (aarch64 && cpu_isar_feature(aa64_bti, cpu)) {
92
+ result->f.guarded = guarded;
93
}
94
95
if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) {
96
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
97
index XXXXXXX..XXXXXXX 100644
98
--- a/target/arm/translate-a64.c
99
+++ b/target/arm/translate-a64.c
100
@@ -XXX,XX +XXX,XX @@ static bool is_guarded_page(CPUARMState *env, DisasContext *s)
101
#ifdef CONFIG_USER_ONLY
102
return page_get_flags(addr) & PAGE_BTI;
103
#else
104
+ CPUTLBEntryFull *full;
105
+ void *host;
106
int mmu_idx = arm_to_core_mmu_idx(s->mmu_idx);
107
- unsigned int index = tlb_index(env, mmu_idx, addr);
108
- CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr);
109
+ int flags;
110
111
/*
112
* We test this immediately after reading an insn, which means
113
- * that any normal page must be in the TLB. The only exception
114
- * would be for executing from flash or device memory, which
115
- * does not retain the TLB entry.
116
- *
117
- * FIXME: Assume false for those, for now. We could use
118
- * arm_cpu_get_phys_page_attrs_debug to re-read the page
119
- * table entry even for that case.
120
+ * that the TLB entry must be present and valid, and thus this
121
+ * access will never raise an exception.
122
*/
123
- return (tlb_hit(entry->addr_code, addr) &&
124
- arm_tlb_bti_gp(&env_tlb(env)->d[mmu_idx].fulltlb[index].attrs));
125
+ flags = probe_access_full(env, addr, MMU_INST_FETCH, mmu_idx,
126
+ false, &host, &full, 0);
127
+ assert(!(flags & TLB_INVALID_MASK));
128
+
129
+ return full->guarded;
130
#endif
131
}
27
132
28
--
133
--
29
2.20.1
134
2.25.1
30
31
diff view generated by jsdifflib
1
From: Leif Lindholm <leif@nuviainc.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Add entries present in ARM DDI 0487F.c (August 2020).
3
Not yet used, but add mmu indexes for 1-1 mapping
4
to physical addresses.
4
5
5
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20210108185154.8108-6-leif@nuviainc.com
8
Message-id: 20221011031911.2408754-5-richard.henderson@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
10
---
11
target/arm/cpu.h | 15 +++++++++++++++
11
target/arm/cpu-param.h | 2 +-
12
1 file changed, 15 insertions(+)
12
target/arm/cpu.h | 7 ++++++-
13
target/arm/ptw.c | 19 +++++++++++++++++--
14
3 files changed, 24 insertions(+), 4 deletions(-)
13
15
16
diff --git a/target/arm/cpu-param.h b/target/arm/cpu-param.h
17
index XXXXXXX..XXXXXXX 100644
18
--- a/target/arm/cpu-param.h
19
+++ b/target/arm/cpu-param.h
20
@@ -XXX,XX +XXX,XX @@
21
bool guarded;
22
#endif
23
24
-#define NB_MMU_MODES 8
25
+#define NB_MMU_MODES 10
26
27
#endif
14
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
28
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
15
index XXXXXXX..XXXXXXX 100644
29
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/cpu.h
30
--- a/target/arm/cpu.h
17
+++ b/target/arm/cpu.h
31
+++ b/target/arm/cpu.h
18
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64ISAR1, GPI, 28, 4)
32
@@ -XXX,XX +XXX,XX @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync);
19
FIELD(ID_AA64ISAR1, FRINTTS, 32, 4)
33
* EL2 EL2&0 +PAN
20
FIELD(ID_AA64ISAR1, SB, 36, 4)
34
* EL2 (aka NS PL2)
21
FIELD(ID_AA64ISAR1, SPECRES, 40, 4)
35
* EL3 (aka S PL1)
22
+FIELD(ID_AA64ISAR1, BF16, 44, 4)
36
+ * Physical (NS & S)
23
+FIELD(ID_AA64ISAR1, DGH, 48, 4)
37
*
24
+FIELD(ID_AA64ISAR1, I8MM, 52, 4)
38
- * for a total of 8 different mmu_idx.
25
39
+ * for a total of 10 different mmu_idx.
26
FIELD(ID_AA64PFR0, EL0, 0, 4)
40
*
27
FIELD(ID_AA64PFR0, EL1, 4, 4)
41
* R profile CPUs have an MPU, but can use the same set of MMU indexes
28
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64PFR0, ADVSIMD, 20, 4)
42
* as A profile. They only need to distinguish EL0 and EL1 (and
29
FIELD(ID_AA64PFR0, GIC, 24, 4)
43
@@ -XXX,XX +XXX,XX @@ typedef enum ARMMMUIdx {
30
FIELD(ID_AA64PFR0, RAS, 28, 4)
44
ARMMMUIdx_E2 = 6 | ARM_MMU_IDX_A,
31
FIELD(ID_AA64PFR0, SVE, 32, 4)
45
ARMMMUIdx_E3 = 7 | ARM_MMU_IDX_A,
32
+FIELD(ID_AA64PFR0, SEL2, 36, 4)
46
33
+FIELD(ID_AA64PFR0, MPAM, 40, 4)
47
+ /* TLBs with 1-1 mapping to the physical address spaces. */
34
+FIELD(ID_AA64PFR0, AMU, 44, 4)
48
+ ARMMMUIdx_Phys_NS = 8 | ARM_MMU_IDX_A,
35
+FIELD(ID_AA64PFR0, DIT, 48, 4)
49
+ ARMMMUIdx_Phys_S = 9 | ARM_MMU_IDX_A,
36
+FIELD(ID_AA64PFR0, CSV2, 56, 4)
50
+
37
+FIELD(ID_AA64PFR0, CSV3, 60, 4)
51
/*
38
52
* These are not allocated TLBs and are used only for AT system
39
FIELD(ID_AA64PFR1, BT, 0, 4)
53
* instructions or for the first stage of an S12 page table walk.
40
FIELD(ID_AA64PFR1, SSBS, 4, 4)
54
diff --git a/target/arm/ptw.c b/target/arm/ptw.c
41
FIELD(ID_AA64PFR1, MTE, 8, 4)
55
index XXXXXXX..XXXXXXX 100644
42
FIELD(ID_AA64PFR1, RAS_FRAC, 12, 4)
56
--- a/target/arm/ptw.c
43
+FIELD(ID_AA64PFR1, MPAM_FRAC, 16, 4)
57
+++ b/target/arm/ptw.c
44
58
@@ -XXX,XX +XXX,XX @@ static bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx,
45
FIELD(ID_AA64MMFR0, PARANGE, 0, 4)
59
case ARMMMUIdx_E3:
46
FIELD(ID_AA64MMFR0, ASIDBITS, 4, 4)
60
break;
47
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64MMFR0, TGRAN16_2, 32, 4)
61
48
FIELD(ID_AA64MMFR0, TGRAN64_2, 36, 4)
62
+ case ARMMMUIdx_Phys_NS:
49
FIELD(ID_AA64MMFR0, TGRAN4_2, 40, 4)
63
+ case ARMMMUIdx_Phys_S:
50
FIELD(ID_AA64MMFR0, EXS, 44, 4)
64
+ /* No translation for physical address spaces. */
51
+FIELD(ID_AA64MMFR0, FGT, 56, 4)
65
+ return true;
52
+FIELD(ID_AA64MMFR0, ECV, 60, 4)
66
+
53
67
default:
54
FIELD(ID_AA64MMFR1, HAFDBS, 0, 4)
68
g_assert_not_reached();
55
FIELD(ID_AA64MMFR1, VMIDBITS, 4, 4)
69
}
56
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64MMFR1, LO, 16, 4)
70
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_disabled(CPUARMState *env, target_ulong address,
57
FIELD(ID_AA64MMFR1, PAN, 20, 4)
71
{
58
FIELD(ID_AA64MMFR1, SPECSEI, 24, 4)
72
uint8_t memattr = 0x00; /* Device nGnRnE */
59
FIELD(ID_AA64MMFR1, XNX, 28, 4)
73
uint8_t shareability = 0; /* non-sharable */
60
+FIELD(ID_AA64MMFR1, TWED, 32, 4)
74
+ int r_el;
61
+FIELD(ID_AA64MMFR1, ETS, 36, 4)
75
62
76
- if (mmu_idx != ARMMMUIdx_Stage2 && mmu_idx != ARMMMUIdx_Stage2_S) {
63
FIELD(ID_AA64MMFR2, CNP, 0, 4)
77
- int r_el = regime_el(env, mmu_idx);
64
FIELD(ID_AA64MMFR2, UAO, 4, 4)
78
+ switch (mmu_idx) {
65
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64DFR0, CTX_CMPS, 28, 4)
79
+ case ARMMMUIdx_Stage2:
66
FIELD(ID_AA64DFR0, PMSVER, 32, 4)
80
+ case ARMMMUIdx_Stage2_S:
67
FIELD(ID_AA64DFR0, DOUBLELOCK, 36, 4)
81
+ case ARMMMUIdx_Phys_NS:
68
FIELD(ID_AA64DFR0, TRACEFILT, 40, 4)
82
+ case ARMMMUIdx_Phys_S:
69
+FIELD(ID_AA64DFR0, MTPMU, 48, 4)
83
+ break;
70
84
71
FIELD(ID_DFR0, COPDBG, 0, 4)
85
+ default:
72
FIELD(ID_DFR0, COPSDBG, 4, 4)
86
+ r_el = regime_el(env, mmu_idx);
87
if (arm_el_is_aa64(env, r_el)) {
88
int pamax = arm_pamax(env_archcpu(env));
89
uint64_t tcr = env->cp15.tcr_el[r_el];
90
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_disabled(CPUARMState *env, target_ulong address,
91
shareability = 2; /* outer sharable */
92
}
93
result->cacheattrs.is_s2_format = false;
94
+ break;
95
}
96
97
result->f.phys_addr = address;
98
@@ -XXX,XX +XXX,XX @@ bool get_phys_addr(CPUARMState *env, target_ulong address,
99
is_secure = arm_is_secure_below_el3(env);
100
break;
101
case ARMMMUIdx_Stage2:
102
+ case ARMMMUIdx_Phys_NS:
103
case ARMMMUIdx_MPrivNegPri:
104
case ARMMMUIdx_MUserNegPri:
105
case ARMMMUIdx_MPriv:
106
@@ -XXX,XX +XXX,XX @@ bool get_phys_addr(CPUARMState *env, target_ulong address,
107
break;
108
case ARMMMUIdx_E3:
109
case ARMMMUIdx_Stage2_S:
110
+ case ARMMMUIdx_Phys_S:
111
case ARMMMUIdx_MSPrivNegPri:
112
case ARMMMUIdx_MSUserNegPri:
113
case ARMMMUIdx_MSPriv:
73
--
114
--
74
2.20.1
115
2.25.1
75
76
diff view generated by jsdifflib
1
From: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
This adds for the Small Translation tables extension in AArch64 state.
3
We had been marking this ARM_MMU_IDX_NOTLB, move it to a real tlb.
4
Flush the tlb when invalidating stage 1+2 translations. Re-use
5
alle1_tlbmask() for other instances of EL1&0 + Stage2.
4
6
5
Signed-off-by: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Message-id: 20221011031911.2408754-6-richard.henderson@linaro.org
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
---
11
---
9
target/arm/cpu.h | 5 +++++
12
target/arm/cpu-param.h | 2 +-
10
target/arm/helper.c | 15 +++++++++++++--
13
target/arm/cpu.h | 23 ++++---
11
2 files changed, 18 insertions(+), 2 deletions(-)
14
target/arm/helper.c | 151 ++++++++++++++++++++++++++++++-----------
15
3 files changed, 127 insertions(+), 49 deletions(-)
12
16
17
diff --git a/target/arm/cpu-param.h b/target/arm/cpu-param.h
18
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/cpu-param.h
20
+++ b/target/arm/cpu-param.h
21
@@ -XXX,XX +XXX,XX @@
22
bool guarded;
23
#endif
24
25
-#define NB_MMU_MODES 10
26
+#define NB_MMU_MODES 12
27
28
#endif
13
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
29
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
14
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/cpu.h
31
--- a/target/arm/cpu.h
16
+++ b/target/arm/cpu.h
32
+++ b/target/arm/cpu.h
17
@@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_uao(const ARMISARegisters *id)
33
@@ -XXX,XX +XXX,XX @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync);
18
return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, UAO) != 0;
34
* EL2 (aka NS PL2)
19
}
35
* EL3 (aka S PL1)
20
36
* Physical (NS & S)
21
+static inline bool isar_feature_aa64_st(const ARMISARegisters *id)
37
+ * Stage2 (NS & S)
22
+{
38
*
23
+ return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, ST) != 0;
39
- * for a total of 10 different mmu_idx.
24
+}
40
+ * for a total of 12 different mmu_idx.
25
+
41
*
26
static inline bool isar_feature_aa64_bti(const ARMISARegisters *id)
42
* R profile CPUs have an MPU, but can use the same set of MMU indexes
27
{
43
* as A profile. They only need to distinguish EL0 and EL1 (and
28
return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0;
44
@@ -XXX,XX +XXX,XX @@ typedef enum ARMMMUIdx {
45
ARMMMUIdx_Phys_NS = 8 | ARM_MMU_IDX_A,
46
ARMMMUIdx_Phys_S = 9 | ARM_MMU_IDX_A,
47
48
+ /*
49
+ * Used for second stage of an S12 page table walk, or for descriptor
50
+ * loads during first stage of an S1 page table walk. Note that both
51
+ * are in use simultaneously for SecureEL2: the security state for
52
+ * the S2 ptw is selected by the NS bit from the S1 ptw.
53
+ */
54
+ ARMMMUIdx_Stage2 = 10 | ARM_MMU_IDX_A,
55
+ ARMMMUIdx_Stage2_S = 11 | ARM_MMU_IDX_A,
56
+
57
/*
58
* These are not allocated TLBs and are used only for AT system
59
* instructions or for the first stage of an S12 page table walk.
60
@@ -XXX,XX +XXX,XX @@ typedef enum ARMMMUIdx {
61
ARMMMUIdx_Stage1_E0 = 0 | ARM_MMU_IDX_NOTLB,
62
ARMMMUIdx_Stage1_E1 = 1 | ARM_MMU_IDX_NOTLB,
63
ARMMMUIdx_Stage1_E1_PAN = 2 | ARM_MMU_IDX_NOTLB,
64
- /*
65
- * Not allocated a TLB: used only for second stage of an S12 page
66
- * table walk, or for descriptor loads during first stage of an S1
67
- * page table walk. Note that if we ever want to have a TLB for this
68
- * then various TLB flush insns which currently are no-ops or flush
69
- * only stage 1 MMU indexes will need to change to flush stage 2.
70
- */
71
- ARMMMUIdx_Stage2 = 3 | ARM_MMU_IDX_NOTLB,
72
- ARMMMUIdx_Stage2_S = 4 | ARM_MMU_IDX_NOTLB,
73
74
/*
75
* M-profile.
76
@@ -XXX,XX +XXX,XX @@ typedef enum ARMMMUIdxBit {
77
TO_CORE_BIT(E20_2),
78
TO_CORE_BIT(E20_2_PAN),
79
TO_CORE_BIT(E3),
80
+ TO_CORE_BIT(Stage2),
81
+ TO_CORE_BIT(Stage2_S),
82
83
TO_CORE_BIT(MUser),
84
TO_CORE_BIT(MPriv),
29
diff --git a/target/arm/helper.c b/target/arm/helper.c
85
diff --git a/target/arm/helper.c b/target/arm/helper.c
30
index XXXXXXX..XXXXXXX 100644
86
index XXXXXXX..XXXXXXX 100644
31
--- a/target/arm/helper.c
87
--- a/target/arm/helper.c
32
+++ b/target/arm/helper.c
88
+++ b/target/arm/helper.c
33
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
89
@@ -XXX,XX +XXX,XX @@ static void contextidr_write(CPUARMState *env, const ARMCPRegInfo *ri,
90
raw_write(env, ri, value);
91
}
92
93
+static int alle1_tlbmask(CPUARMState *env)
94
+{
95
+ /*
96
+ * Note that the 'ALL' scope must invalidate both stage 1 and
97
+ * stage 2 translations, whereas most other scopes only invalidate
98
+ * stage 1 translations.
99
+ */
100
+ return (ARMMMUIdxBit_E10_1 |
101
+ ARMMMUIdxBit_E10_1_PAN |
102
+ ARMMMUIdxBit_E10_0 |
103
+ ARMMMUIdxBit_Stage2 |
104
+ ARMMMUIdxBit_Stage2_S);
105
+}
106
+
107
+
108
/* IS variants of TLB operations must affect all cores */
109
static void tlbiall_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
110
uint64_t value)
111
@@ -XXX,XX +XXX,XX @@ static void tlbiall_nsnh_write(CPUARMState *env, const ARMCPRegInfo *ri,
34
{
112
{
35
uint64_t tcr = regime_tcr(env, mmu_idx)->raw_tcr;
113
CPUState *cs = env_cpu(env);
36
bool epd, hpd, using16k, using64k;
114
37
- int select, tsz, tbi;
115
- tlb_flush_by_mmuidx(cs,
38
+ int select, tsz, tbi, max_tsz;
116
- ARMMMUIdxBit_E10_1 |
39
117
- ARMMMUIdxBit_E10_1_PAN |
40
if (!regime_has_2_ranges(mmu_idx)) {
118
- ARMMMUIdxBit_E10_0);
41
select = 0;
119
+ tlb_flush_by_mmuidx(cs, alle1_tlbmask(env));
42
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
120
}
43
hpd = extract64(tcr, 42, 1);
121
44
}
122
static void tlbiall_nsnh_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
123
@@ -XXX,XX +XXX,XX @@ static void tlbiall_nsnh_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
124
{
125
CPUState *cs = env_cpu(env);
126
127
- tlb_flush_by_mmuidx_all_cpus_synced(cs,
128
- ARMMMUIdxBit_E10_1 |
129
- ARMMMUIdxBit_E10_1_PAN |
130
- ARMMMUIdxBit_E10_0);
131
+ tlb_flush_by_mmuidx_all_cpus_synced(cs, alle1_tlbmask(env));
132
}
133
134
135
@@ -XXX,XX +XXX,XX @@ static void tlbimva_hyp_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
136
ARMMMUIdxBit_E2);
137
}
138
139
+static void tlbiipas2_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri,
140
+ uint64_t value)
141
+{
142
+ CPUState *cs = env_cpu(env);
143
+ uint64_t pageaddr = (value & MAKE_64BIT_MASK(0, 28)) << 12;
144
+
145
+ tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_Stage2);
146
+}
147
+
148
+static void tlbiipas2is_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri,
149
+ uint64_t value)
150
+{
151
+ CPUState *cs = env_cpu(env);
152
+ uint64_t pageaddr = (value & MAKE_64BIT_MASK(0, 28)) << 12;
153
+
154
+ tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, ARMMMUIdxBit_Stage2);
155
+}
156
+
157
static const ARMCPRegInfo cp_reginfo[] = {
158
/* Define the secure and non-secure FCSE identifier CP registers
159
* separately because there is no secure bank in V8 (no _EL3). This allows
160
@@ -XXX,XX +XXX,XX @@ static void vttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
161
162
/*
163
* A change in VMID to the stage2 page table (Stage2) invalidates
164
- * the combined stage 1&2 tlbs (EL10_1 and EL10_0).
165
+ * the stage2 and combined stage 1&2 tlbs (EL10_1 and EL10_0).
166
*/
167
if (raw_read(env, ri) != value) {
168
- uint16_t mask = ARMMMUIdxBit_E10_1 |
169
- ARMMMUIdxBit_E10_1_PAN |
170
- ARMMMUIdxBit_E10_0;
171
- tlb_flush_by_mmuidx(cs, mask);
172
+ tlb_flush_by_mmuidx(cs, alle1_tlbmask(env));
173
raw_write(env, ri, value);
45
}
174
}
46
- tsz = MIN(tsz, 39); /* TODO: ARMv8.4-TTST */
175
}
47
+
176
@@ -XXX,XX +XXX,XX @@ static void tlbi_aa64_vmalle1_write(CPUARMState *env, const ARMCPRegInfo *ri,
48
+ if (cpu_isar_feature(aa64_st, env_archcpu(env))) {
177
}
49
+ max_tsz = 48 - using64k;
178
}
179
180
-static int alle1_tlbmask(CPUARMState *env)
181
-{
182
- /*
183
- * Note that the 'ALL' scope must invalidate both stage 1 and
184
- * stage 2 translations, whereas most other scopes only invalidate
185
- * stage 1 translations.
186
- */
187
- return (ARMMMUIdxBit_E10_1 |
188
- ARMMMUIdxBit_E10_1_PAN |
189
- ARMMMUIdxBit_E10_0);
190
-}
191
-
192
static int e2_tlbmask(CPUARMState *env)
193
{
194
return (ARMMMUIdxBit_E20_0 |
195
@@ -XXX,XX +XXX,XX @@ static void tlbi_aa64_vae3is_write(CPUARMState *env, const ARMCPRegInfo *ri,
196
ARMMMUIdxBit_E3, bits);
197
}
198
199
+static int ipas2e1_tlbmask(CPUARMState *env, int64_t value)
200
+{
201
+ /*
202
+ * The MSB of value is the NS field, which only applies if SEL2
203
+ * is implemented and SCR_EL3.NS is not set (i.e. in secure mode).
204
+ */
205
+ return (value >= 0
206
+ && cpu_isar_feature(aa64_sel2, env_archcpu(env))
207
+ && arm_is_secure_below_el3(env)
208
+ ? ARMMMUIdxBit_Stage2_S
209
+ : ARMMMUIdxBit_Stage2);
210
+}
211
+
212
+static void tlbi_aa64_ipas2e1_write(CPUARMState *env, const ARMCPRegInfo *ri,
213
+ uint64_t value)
214
+{
215
+ CPUState *cs = env_cpu(env);
216
+ int mask = ipas2e1_tlbmask(env, value);
217
+ uint64_t pageaddr = sextract64(value << 12, 0, 56);
218
+
219
+ if (tlb_force_broadcast(env)) {
220
+ tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, mask);
50
+ } else {
221
+ } else {
51
+ max_tsz = 39;
222
+ tlb_flush_page_by_mmuidx(cs, pageaddr, mask);
52
+ }
223
+ }
53
+
224
+}
54
+ tsz = MIN(tsz, max_tsz);
225
+
55
tsz = MAX(tsz, 16); /* TODO: ARMv8.2-LVA */
226
+static void tlbi_aa64_ipas2e1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
56
227
+ uint64_t value)
57
/* Present TBI as a composite with TBID. */
228
+{
58
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
229
+ CPUState *cs = env_cpu(env);
59
if (!aarch64 || stride == 9) {
230
+ int mask = ipas2e1_tlbmask(env, value);
60
/* AArch32 or 4KB pages */
231
+ uint64_t pageaddr = sextract64(value << 12, 0, 56);
61
startlevel = 2 - sl0;
232
+
62
+
233
+ tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, mask);
63
+ if (cpu_isar_feature(aa64_st, cpu)) {
234
+}
64
+ startlevel &= 3;
235
+
65
+ }
236
#ifdef TARGET_AARCH64
66
} else {
237
typedef struct {
67
/* 16KB or 64KB pages */
238
uint64_t base;
68
startlevel = 3 - sl0;
239
@@ -XXX,XX +XXX,XX @@ static void tlbi_aa64_rvae3is_write(CPUARMState *env,
240
241
do_rvae_write(env, value, ARMMMUIdxBit_E3, true);
242
}
243
+
244
+static void tlbi_aa64_ripas2e1_write(CPUARMState *env, const ARMCPRegInfo *ri,
245
+ uint64_t value)
246
+{
247
+ do_rvae_write(env, value, ipas2e1_tlbmask(env, value),
248
+ tlb_force_broadcast(env));
249
+}
250
+
251
+static void tlbi_aa64_ripas2e1is_write(CPUARMState *env,
252
+ const ARMCPRegInfo *ri,
253
+ uint64_t value)
254
+{
255
+ do_rvae_write(env, value, ipas2e1_tlbmask(env, value), true);
256
+}
257
#endif
258
259
static CPAccessResult aa64_zva_access(CPUARMState *env, const ARMCPRegInfo *ri,
260
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
261
.writefn = tlbi_aa64_vae1_write },
262
{ .name = "TLBI_IPAS2E1IS", .state = ARM_CP_STATE_AA64,
263
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 1,
264
- .access = PL2_W, .type = ARM_CP_NOP },
265
+ .access = PL2_W, .type = ARM_CP_NO_RAW,
266
+ .writefn = tlbi_aa64_ipas2e1is_write },
267
{ .name = "TLBI_IPAS2LE1IS", .state = ARM_CP_STATE_AA64,
268
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 5,
269
- .access = PL2_W, .type = ARM_CP_NOP },
270
+ .access = PL2_W, .type = ARM_CP_NO_RAW,
271
+ .writefn = tlbi_aa64_ipas2e1is_write },
272
{ .name = "TLBI_ALLE1IS", .state = ARM_CP_STATE_AA64,
273
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 4,
274
.access = PL2_W, .type = ARM_CP_NO_RAW,
275
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
276
.writefn = tlbi_aa64_alle1is_write },
277
{ .name = "TLBI_IPAS2E1", .state = ARM_CP_STATE_AA64,
278
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 1,
279
- .access = PL2_W, .type = ARM_CP_NOP },
280
+ .access = PL2_W, .type = ARM_CP_NO_RAW,
281
+ .writefn = tlbi_aa64_ipas2e1_write },
282
{ .name = "TLBI_IPAS2LE1", .state = ARM_CP_STATE_AA64,
283
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 5,
284
- .access = PL2_W, .type = ARM_CP_NOP },
285
+ .access = PL2_W, .type = ARM_CP_NO_RAW,
286
+ .writefn = tlbi_aa64_ipas2e1_write },
287
{ .name = "TLBI_ALLE1", .state = ARM_CP_STATE_AA64,
288
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 4,
289
.access = PL2_W, .type = ARM_CP_NO_RAW,
290
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
291
.writefn = tlbimva_hyp_is_write },
292
{ .name = "TLBIIPAS2",
293
.cp = 15, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 1,
294
- .type = ARM_CP_NOP, .access = PL2_W },
295
+ .type = ARM_CP_NO_RAW, .access = PL2_W,
296
+ .writefn = tlbiipas2_hyp_write },
297
{ .name = "TLBIIPAS2IS",
298
.cp = 15, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 1,
299
- .type = ARM_CP_NOP, .access = PL2_W },
300
+ .type = ARM_CP_NO_RAW, .access = PL2_W,
301
+ .writefn = tlbiipas2is_hyp_write },
302
{ .name = "TLBIIPAS2L",
303
.cp = 15, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 5,
304
- .type = ARM_CP_NOP, .access = PL2_W },
305
+ .type = ARM_CP_NO_RAW, .access = PL2_W,
306
+ .writefn = tlbiipas2_hyp_write },
307
{ .name = "TLBIIPAS2LIS",
308
.cp = 15, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 5,
309
- .type = ARM_CP_NOP, .access = PL2_W },
310
+ .type = ARM_CP_NO_RAW, .access = PL2_W,
311
+ .writefn = tlbiipas2is_hyp_write },
312
/* 32 bit cache operations */
313
{ .name = "ICIALLUIS", .cp = 15, .opc1 = 0, .crn = 7, .crm = 1, .opc2 = 0,
314
.type = ARM_CP_NOP, .access = PL1_W, .accessfn = aa64_cacheop_pou_access },
315
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo tlbirange_reginfo[] = {
316
.writefn = tlbi_aa64_rvae1_write },
317
{ .name = "TLBI_RIPAS2E1IS", .state = ARM_CP_STATE_AA64,
318
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 2,
319
- .access = PL2_W, .type = ARM_CP_NOP },
320
+ .access = PL2_W, .type = ARM_CP_NO_RAW,
321
+ .writefn = tlbi_aa64_ripas2e1is_write },
322
{ .name = "TLBI_RIPAS2LE1IS", .state = ARM_CP_STATE_AA64,
323
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 6,
324
- .access = PL2_W, .type = ARM_CP_NOP },
325
+ .access = PL2_W, .type = ARM_CP_NO_RAW,
326
+ .writefn = tlbi_aa64_ripas2e1is_write },
327
{ .name = "TLBI_RVAE2IS", .state = ARM_CP_STATE_AA64,
328
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 2, .opc2 = 1,
329
.access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
330
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo tlbirange_reginfo[] = {
331
.writefn = tlbi_aa64_rvae2is_write },
332
{ .name = "TLBI_RIPAS2E1", .state = ARM_CP_STATE_AA64,
333
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 2,
334
- .access = PL2_W, .type = ARM_CP_NOP },
335
- { .name = "TLBI_RIPAS2LE1", .state = ARM_CP_STATE_AA64,
336
+ .access = PL2_W, .type = ARM_CP_NO_RAW,
337
+ .writefn = tlbi_aa64_ripas2e1_write },
338
+ { .name = "TLBI_RIPAS2LE1", .state = ARM_CP_STATE_AA64,
339
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 4, .opc2 = 6,
340
- .access = PL2_W, .type = ARM_CP_NOP },
341
+ .access = PL2_W, .type = ARM_CP_NO_RAW,
342
+ .writefn = tlbi_aa64_ripas2e1_write },
343
{ .name = "TLBI_RVAE2OS", .state = ARM_CP_STATE_AA64,
344
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 5, .opc2 = 1,
345
.access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_EL3_NO_EL2_UNDEF,
69
--
346
--
70
2.20.1
347
2.25.1
71
72
diff view generated by jsdifflib
New patch
1
From: Richard Henderson <richard.henderson@linaro.org>
1
2
3
Compare only the VMID field when considering whether we need to flush.
4
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Message-id: 20221011031911.2408754-7-richard.henderson@linaro.org
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
10
target/arm/helper.c | 4 ++--
11
1 file changed, 2 insertions(+), 2 deletions(-)
12
13
diff --git a/target/arm/helper.c b/target/arm/helper.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/helper.c
16
+++ b/target/arm/helper.c
17
@@ -XXX,XX +XXX,XX @@ static void vttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
18
* A change in VMID to the stage2 page table (Stage2) invalidates
19
* the stage2 and combined stage 1&2 tlbs (EL10_1 and EL10_0).
20
*/
21
- if (raw_read(env, ri) != value) {
22
+ if (extract64(raw_read(env, ri) ^ value, 48, 16) != 0) {
23
tlb_flush_by_mmuidx(cs, alle1_tlbmask(env));
24
- raw_write(env, ri, value);
25
}
26
+ raw_write(env, ri, value);
27
}
28
29
static const ARMCPRegInfo vmsa_pmsa_cp_reginfo[] = {
30
--
31
2.25.1
diff view generated by jsdifflib
1
A copy-and-paste error meant that the return value for register offset 0x44
1
From: Richard Henderson <richard.henderson@linaro.org>
2
(the RX Status FIFO PEEK register) returned a byte from a bogus offset in
3
the rx status FIFO. Fix the typo.
4
2
5
Cc: qemu-stable@nongnu.org
3
Consolidate most of the inputs and outputs of S1_ptw_translate
6
Fixes: https://bugs.launchpad.net/qemu/+bug/1904954
4
into a single structure. Plumb this through arm_ld*_ptw from
5
the controlling get_phys_addr_* routine.
6
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Message-id: 20221011031911.2408754-8-richard.henderson@linaro.org
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Message-id: 20210108180401.2263-2-peter.maydell@linaro.org
10
---
11
---
11
hw/net/lan9118.c | 2 +-
12
target/arm/ptw.c | 140 ++++++++++++++++++++++++++---------------------
12
1 file changed, 1 insertion(+), 1 deletion(-)
13
1 file changed, 79 insertions(+), 61 deletions(-)
13
14
14
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
15
diff --git a/target/arm/ptw.c b/target/arm/ptw.c
15
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/net/lan9118.c
17
--- a/target/arm/ptw.c
17
+++ b/hw/net/lan9118.c
18
+++ b/target/arm/ptw.c
18
@@ -XXX,XX +XXX,XX @@ static uint64_t lan9118_readl(void *opaque, hwaddr offset,
19
@@ -XXX,XX +XXX,XX @@
19
case 0x40:
20
#include "idau.h"
20
return rx_status_fifo_pop(s);
21
21
case 0x44:
22
22
- return s->rx_status_fifo[s->tx_status_fifo_head];
23
-static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
23
+ return s->rx_status_fifo[s->rx_status_fifo_head];
24
- MMUAccessType access_type, ARMMMUIdx mmu_idx,
24
case 0x48:
25
- bool is_secure, bool s1_is_el0,
25
return tx_status_fifo_pop(s);
26
+typedef struct S1Translate {
26
case 0x4c:
27
+ ARMMMUIdx in_mmu_idx;
28
+ bool in_secure;
29
+ bool out_secure;
30
+ hwaddr out_phys;
31
+} S1Translate;
32
+
33
+static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw,
34
+ uint64_t address,
35
+ MMUAccessType access_type, bool s1_is_el0,
36
GetPhysAddrResult *result, ARMMMUFaultInfo *fi)
37
__attribute__((nonnull));
38
39
@@ -XXX,XX +XXX,XX @@ static bool ptw_attrs_are_device(uint64_t hcr, ARMCacheAttrs cacheattrs)
40
}
41
42
/* Translate a S1 pagetable walk through S2 if needed. */
43
-static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx,
44
- hwaddr addr, bool *is_secure_ptr,
45
- ARMMMUFaultInfo *fi)
46
+static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw,
47
+ hwaddr addr, ARMMMUFaultInfo *fi)
48
{
49
- bool is_secure = *is_secure_ptr;
50
+ bool is_secure = ptw->in_secure;
51
ARMMMUIdx s2_mmu_idx = is_secure ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2;
52
53
- if (arm_mmu_idx_is_stage1_of_2(mmu_idx) &&
54
+ if (arm_mmu_idx_is_stage1_of_2(ptw->in_mmu_idx) &&
55
!regime_translation_disabled(env, s2_mmu_idx, is_secure)) {
56
GetPhysAddrResult s2 = {};
57
+ S1Translate s2ptw = {
58
+ .in_mmu_idx = s2_mmu_idx,
59
+ .in_secure = is_secure,
60
+ };
61
uint64_t hcr;
62
int ret;
63
64
- ret = get_phys_addr_lpae(env, addr, MMU_DATA_LOAD, s2_mmu_idx,
65
- is_secure, false, &s2, fi);
66
+ ret = get_phys_addr_lpae(env, &s2ptw, addr, MMU_DATA_LOAD,
67
+ false, &s2, fi);
68
if (ret) {
69
assert(fi->type != ARMFault_None);
70
fi->s2addr = addr;
71
fi->stage2 = true;
72
fi->s1ptw = true;
73
fi->s1ns = !is_secure;
74
- return ~0;
75
+ return false;
76
}
77
78
hcr = arm_hcr_el2_eff_secstate(env, is_secure);
79
@@ -XXX,XX +XXX,XX @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx,
80
fi->stage2 = true;
81
fi->s1ptw = true;
82
fi->s1ns = !is_secure;
83
- return ~0;
84
+ return false;
85
}
86
87
if (arm_is_secure_below_el3(env)) {
88
@@ -XXX,XX +XXX,XX @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx,
89
} else {
90
is_secure = !(env->cp15.vtcr_el2 & VTCR_NSW);
91
}
92
- *is_secure_ptr = is_secure;
93
} else {
94
assert(!is_secure);
95
}
96
97
addr = s2.f.phys_addr;
98
}
99
- return addr;
100
+
101
+ ptw->out_secure = is_secure;
102
+ ptw->out_phys = addr;
103
+ return true;
104
}
105
106
/* All loads done in the course of a page table walk go through here. */
107
-static uint32_t arm_ldl_ptw(CPUARMState *env, hwaddr addr, bool is_secure,
108
- ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi)
109
+static uint32_t arm_ldl_ptw(CPUARMState *env, S1Translate *ptw, hwaddr addr,
110
+ ARMMMUFaultInfo *fi)
111
{
112
CPUState *cs = env_cpu(env);
113
MemTxAttrs attrs = {};
114
@@ -XXX,XX +XXX,XX @@ static uint32_t arm_ldl_ptw(CPUARMState *env, hwaddr addr, bool is_secure,
115
AddressSpace *as;
116
uint32_t data;
117
118
- addr = S1_ptw_translate(env, mmu_idx, addr, &is_secure, fi);
119
- attrs.secure = is_secure;
120
- as = arm_addressspace(cs, attrs);
121
- if (fi->s1ptw) {
122
+ if (!S1_ptw_translate(env, ptw, addr, fi)) {
123
return 0;
124
}
125
- if (regime_translation_big_endian(env, mmu_idx)) {
126
+ addr = ptw->out_phys;
127
+ attrs.secure = ptw->out_secure;
128
+ as = arm_addressspace(cs, attrs);
129
+ if (regime_translation_big_endian(env, ptw->in_mmu_idx)) {
130
data = address_space_ldl_be(as, addr, attrs, &result);
131
} else {
132
data = address_space_ldl_le(as, addr, attrs, &result);
133
@@ -XXX,XX +XXX,XX @@ static uint32_t arm_ldl_ptw(CPUARMState *env, hwaddr addr, bool is_secure,
134
return 0;
135
}
136
137
-static uint64_t arm_ldq_ptw(CPUARMState *env, hwaddr addr, bool is_secure,
138
- ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi)
139
+static uint64_t arm_ldq_ptw(CPUARMState *env, S1Translate *ptw, hwaddr addr,
140
+ ARMMMUFaultInfo *fi)
141
{
142
CPUState *cs = env_cpu(env);
143
MemTxAttrs attrs = {};
144
@@ -XXX,XX +XXX,XX @@ static uint64_t arm_ldq_ptw(CPUARMState *env, hwaddr addr, bool is_secure,
145
AddressSpace *as;
146
uint64_t data;
147
148
- addr = S1_ptw_translate(env, mmu_idx, addr, &is_secure, fi);
149
- attrs.secure = is_secure;
150
- as = arm_addressspace(cs, attrs);
151
- if (fi->s1ptw) {
152
+ if (!S1_ptw_translate(env, ptw, addr, fi)) {
153
return 0;
154
}
155
- if (regime_translation_big_endian(env, mmu_idx)) {
156
+ addr = ptw->out_phys;
157
+ attrs.secure = ptw->out_secure;
158
+ as = arm_addressspace(cs, attrs);
159
+ if (regime_translation_big_endian(env, ptw->in_mmu_idx)) {
160
data = address_space_ldq_be(as, addr, attrs, &result);
161
} else {
162
data = address_space_ldq_le(as, addr, attrs, &result);
163
@@ -XXX,XX +XXX,XX @@ static int simple_ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap)
164
return simple_ap_to_rw_prot_is_user(ap, regime_is_user(env, mmu_idx));
165
}
166
167
-static bool get_phys_addr_v5(CPUARMState *env, uint32_t address,
168
- MMUAccessType access_type, ARMMMUIdx mmu_idx,
169
- bool is_secure, GetPhysAddrResult *result,
170
- ARMMMUFaultInfo *fi)
171
+static bool get_phys_addr_v5(CPUARMState *env, S1Translate *ptw,
172
+ uint32_t address, MMUAccessType access_type,
173
+ GetPhysAddrResult *result, ARMMMUFaultInfo *fi)
174
{
175
int level = 1;
176
uint32_t table;
177
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address,
178
179
/* Pagetable walk. */
180
/* Lookup l1 descriptor. */
181
- if (!get_level1_table_address(env, mmu_idx, &table, address)) {
182
+ if (!get_level1_table_address(env, ptw->in_mmu_idx, &table, address)) {
183
/* Section translation fault if page walk is disabled by PD0 or PD1 */
184
fi->type = ARMFault_Translation;
185
goto do_fault;
186
}
187
- desc = arm_ldl_ptw(env, table, is_secure, mmu_idx, fi);
188
+ desc = arm_ldl_ptw(env, ptw, table, fi);
189
if (fi->type != ARMFault_None) {
190
goto do_fault;
191
}
192
type = (desc & 3);
193
domain = (desc >> 5) & 0x0f;
194
- if (regime_el(env, mmu_idx) == 1) {
195
+ if (regime_el(env, ptw->in_mmu_idx) == 1) {
196
dacr = env->cp15.dacr_ns;
197
} else {
198
dacr = env->cp15.dacr_s;
199
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address,
200
/* Fine pagetable. */
201
table = (desc & 0xfffff000) | ((address >> 8) & 0xffc);
202
}
203
- desc = arm_ldl_ptw(env, table, is_secure, mmu_idx, fi);
204
+ desc = arm_ldl_ptw(env, ptw, table, fi);
205
if (fi->type != ARMFault_None) {
206
goto do_fault;
207
}
208
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address,
209
g_assert_not_reached();
210
}
211
}
212
- result->f.prot = ap_to_rw_prot(env, mmu_idx, ap, domain_prot);
213
+ result->f.prot = ap_to_rw_prot(env, ptw->in_mmu_idx, ap, domain_prot);
214
result->f.prot |= result->f.prot ? PAGE_EXEC : 0;
215
if (!(result->f.prot & (1 << access_type))) {
216
/* Access permission fault. */
217
@@ -XXX,XX +XXX,XX @@ do_fault:
218
return true;
219
}
220
221
-static bool get_phys_addr_v6(CPUARMState *env, uint32_t address,
222
- MMUAccessType access_type, ARMMMUIdx mmu_idx,
223
- bool is_secure, GetPhysAddrResult *result,
224
- ARMMMUFaultInfo *fi)
225
+static bool get_phys_addr_v6(CPUARMState *env, S1Translate *ptw,
226
+ uint32_t address, MMUAccessType access_type,
227
+ GetPhysAddrResult *result, ARMMMUFaultInfo *fi)
228
{
229
ARMCPU *cpu = env_archcpu(env);
230
+ ARMMMUIdx mmu_idx = ptw->in_mmu_idx;
231
int level = 1;
232
uint32_t table;
233
uint32_t desc;
234
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address,
235
fi->type = ARMFault_Translation;
236
goto do_fault;
237
}
238
- desc = arm_ldl_ptw(env, table, is_secure, mmu_idx, fi);
239
+ desc = arm_ldl_ptw(env, ptw, table, fi);
240
if (fi->type != ARMFault_None) {
241
goto do_fault;
242
}
243
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address,
244
ns = extract32(desc, 3, 1);
245
/* Lookup l2 entry. */
246
table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc);
247
- desc = arm_ldl_ptw(env, table, is_secure, mmu_idx, fi);
248
+ desc = arm_ldl_ptw(env, ptw, table, fi);
249
if (fi->type != ARMFault_None) {
250
goto do_fault;
251
}
252
@@ -XXX,XX +XXX,XX @@ static bool check_s2_mmu_setup(ARMCPU *cpu, bool is_aa64, int level,
253
* the WnR bit is never set (the caller must do this).
254
*
255
* @env: CPUARMState
256
+ * @ptw: Current and next stage parameters for the walk.
257
* @address: virtual address to get physical address for
258
* @access_type: MMU_DATA_LOAD, MMU_DATA_STORE or MMU_INST_FETCH
259
- * @mmu_idx: MMU index indicating required translation regime
260
- * @s1_is_el0: if @mmu_idx is ARMMMUIdx_Stage2 (so this is a stage 2 page
261
- * table walk), must be true if this is stage 2 of a stage 1+2
262
+ * @s1_is_el0: if @ptw->in_mmu_idx is ARMMMUIdx_Stage2
263
+ * (so this is a stage 2 page table walk),
264
+ * must be true if this is stage 2 of a stage 1+2
265
* walk for an EL0 access. If @mmu_idx is anything else,
266
* @s1_is_el0 is ignored.
267
* @result: set on translation success,
268
* @fi: set to fault info if the translation fails
269
*/
270
-static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
271
- MMUAccessType access_type, ARMMMUIdx mmu_idx,
272
- bool is_secure, bool s1_is_el0,
273
+static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw,
274
+ uint64_t address,
275
+ MMUAccessType access_type, bool s1_is_el0,
276
GetPhysAddrResult *result, ARMMMUFaultInfo *fi)
277
{
278
ARMCPU *cpu = env_archcpu(env);
279
+ ARMMMUIdx mmu_idx = ptw->in_mmu_idx;
280
+ bool is_secure = ptw->in_secure;
281
/* Read an LPAE long-descriptor translation table. */
282
ARMFaultType fault_type = ARMFault_Translation;
283
uint32_t level;
284
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
285
descaddr |= (address >> (stride * (4 - level))) & indexmask;
286
descaddr &= ~7ULL;
287
nstable = extract32(tableattrs, 4, 1);
288
- descriptor = arm_ldq_ptw(env, descaddr, !nstable, mmu_idx, fi);
289
+ ptw->in_secure = !nstable;
290
+ descriptor = arm_ldq_ptw(env, ptw, descaddr, fi);
291
if (fi->type != ARMFault_None) {
292
goto do_fault;
293
}
294
@@ -XXX,XX +XXX,XX @@ bool get_phys_addr_with_secure(CPUARMState *env, target_ulong address,
295
ARMMMUFaultInfo *fi)
296
{
297
ARMMMUIdx s1_mmu_idx = stage_1_mmu_idx(mmu_idx);
298
+ S1Translate ptw;
299
300
if (mmu_idx != s1_mmu_idx) {
301
/*
302
@@ -XXX,XX +XXX,XX @@ bool get_phys_addr_with_secure(CPUARMState *env, target_ulong address,
303
int ret;
304
bool ipa_secure, s2walk_secure;
305
ARMCacheAttrs cacheattrs1;
306
- ARMMMUIdx s2_mmu_idx;
307
bool is_el0;
308
uint64_t hcr;
309
310
@@ -XXX,XX +XXX,XX @@ bool get_phys_addr_with_secure(CPUARMState *env, target_ulong address,
311
s2walk_secure = false;
312
}
313
314
- s2_mmu_idx = (s2walk_secure
315
- ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2);
316
+ ptw.in_mmu_idx =
317
+ s2walk_secure ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2;
318
+ ptw.in_secure = s2walk_secure;
319
is_el0 = mmu_idx == ARMMMUIdx_E10_0;
320
321
/*
322
@@ -XXX,XX +XXX,XX @@ bool get_phys_addr_with_secure(CPUARMState *env, target_ulong address,
323
cacheattrs1 = result->cacheattrs;
324
memset(result, 0, sizeof(*result));
325
326
- ret = get_phys_addr_lpae(env, ipa, access_type, s2_mmu_idx,
327
- s2walk_secure, is_el0, result, fi);
328
+ ret = get_phys_addr_lpae(env, &ptw, ipa, access_type,
329
+ is_el0, result, fi);
330
fi->s2addr = ipa;
331
332
/* Combine the S1 and S2 perms. */
333
@@ -XXX,XX +XXX,XX @@ bool get_phys_addr_with_secure(CPUARMState *env, target_ulong address,
334
return get_phys_addr_disabled(env, address, access_type, mmu_idx,
335
is_secure, result, fi);
336
}
337
+
338
+ ptw.in_mmu_idx = mmu_idx;
339
+ ptw.in_secure = is_secure;
340
+
341
if (regime_using_lpae_format(env, mmu_idx)) {
342
- return get_phys_addr_lpae(env, address, access_type, mmu_idx,
343
- is_secure, false, result, fi);
344
+ return get_phys_addr_lpae(env, &ptw, address, access_type, false,
345
+ result, fi);
346
} else if (regime_sctlr(env, mmu_idx) & SCTLR_XP) {
347
- return get_phys_addr_v6(env, address, access_type, mmu_idx,
348
- is_secure, result, fi);
349
+ return get_phys_addr_v6(env, &ptw, address, access_type, result, fi);
350
} else {
351
- return get_phys_addr_v5(env, address, access_type, mmu_idx,
352
- is_secure, result, fi);
353
+ return get_phys_addr_v5(env, &ptw, address, access_type, result, fi);
354
}
355
}
356
27
--
357
--
28
2.20.1
358
2.25.1
29
30
diff view generated by jsdifflib
1
From: Hao Wu <wuhaotsh@google.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
We add a qtest for the PWM in the previous patch. It proves it works as
3
Before using softmmu page tables for the ptw, plumb down
4
expected.
4
a debug parameter so that we can query page table entries
5
from gdbstub without modifying cpu state.
5
6
6
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
7
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
8
Signed-off-by: Hao Wu <wuhaotsh@google.com>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Message-id: 20210108190945.949196-6-wuhaotsh@google.com
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20221011031911.2408754-9-richard.henderson@linaro.org
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
target/arm/ptw.c | 55 ++++++++++++++++++++++++++++++++----------------
14
tests/qtest/meson.build | 1 +
13
1 file changed, 37 insertions(+), 18 deletions(-)
15
2 files changed, 491 insertions(+)
16
create mode 100644 tests/qtest/npcm7xx_pwm-test.c
17
14
18
diff --git a/tests/qtest/npcm7xx_pwm-test.c b/tests/qtest/npcm7xx_pwm-test.c
15
diff --git a/target/arm/ptw.c b/target/arm/ptw.c
19
new file mode 100644
16
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX
17
--- a/target/arm/ptw.c
21
--- /dev/null
18
+++ b/target/arm/ptw.c
22
+++ b/tests/qtest/npcm7xx_pwm-test.c
23
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@
24
+/*
20
typedef struct S1Translate {
25
+ * QTests for Nuvoton NPCM7xx PWM Modules.
21
ARMMMUIdx in_mmu_idx;
26
+ *
22
bool in_secure;
27
+ * Copyright 2020 Google LLC
23
+ bool in_debug;
28
+ *
24
bool out_secure;
29
+ * This program is free software; you can redistribute it and/or modify it
25
hwaddr out_phys;
30
+ * under the terms of the GNU General Public License as published by the
26
} S1Translate;
31
+ * Free Software Foundation; either version 2 of the License, or
27
@@ -XXX,XX +XXX,XX @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw,
32
+ * (at your option) any later version.
28
S1Translate s2ptw = {
33
+ *
29
.in_mmu_idx = s2_mmu_idx,
34
+ * This program is distributed in the hope that it will be useful, but WITHOUT
30
.in_secure = is_secure,
35
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
31
+ .in_debug = ptw->in_debug,
36
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
32
};
37
+ * for more details.
33
uint64_t hcr;
38
+ */
34
int ret;
39
+
35
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_disabled(CPUARMState *env, target_ulong address,
40
+#include "qemu/osdep.h"
36
return 0;
41
+#include "qemu/bitops.h"
37
}
42
+#include "libqos/libqtest.h"
38
43
+#include "qapi/qmp/qdict.h"
39
-bool get_phys_addr_with_secure(CPUARMState *env, target_ulong address,
44
+#include "qapi/qmp/qnum.h"
40
- MMUAccessType access_type, ARMMMUIdx mmu_idx,
45
+
41
- bool is_secure, GetPhysAddrResult *result,
46
+#define REF_HZ 25000000
42
- ARMMMUFaultInfo *fi)
47
+
43
+static bool get_phys_addr_with_struct(CPUARMState *env, S1Translate *ptw,
48
+/* Register field definitions. */
44
+ target_ulong address,
49
+#define CH_EN BIT(0)
45
+ MMUAccessType access_type,
50
+#define CH_INV BIT(2)
46
+ GetPhysAddrResult *result,
51
+#define CH_MOD BIT(3)
47
+ ARMMMUFaultInfo *fi)
52
+
48
{
53
+/* Registers shared between all PWMs in a module */
49
+ ARMMMUIdx mmu_idx = ptw->in_mmu_idx;
54
+#define PPR 0x00
50
ARMMMUIdx s1_mmu_idx = stage_1_mmu_idx(mmu_idx);
55
+#define CSR 0x04
51
- S1Translate ptw;
56
+#define PCR 0x08
52
+ bool is_secure = ptw->in_secure;
57
+#define PIER 0x3c
53
58
+#define PIIR 0x40
54
if (mmu_idx != s1_mmu_idx) {
59
+
55
/*
60
+/* CLK module related */
56
@@ -XXX,XX +XXX,XX @@ bool get_phys_addr_with_secure(CPUARMState *env, target_ulong address,
61
+#define CLK_BA 0xf0801000
57
bool is_el0;
62
+#define CLKSEL 0x04
58
uint64_t hcr;
63
+#define CLKDIV1 0x08
59
64
+#define CLKDIV2 0x2c
60
- ret = get_phys_addr_with_secure(env, address, access_type,
65
+#define PLLCON0 0x0c
61
- s1_mmu_idx, is_secure, result, fi);
66
+#define PLLCON1 0x10
62
+ ptw->in_mmu_idx = s1_mmu_idx;
67
+#define PLL_INDV(rv) extract32((rv), 0, 6)
63
+ ret = get_phys_addr_with_struct(env, ptw, address, access_type,
68
+#define PLL_FBDV(rv) extract32((rv), 16, 12)
64
+ result, fi);
69
+#define PLL_OTDV1(rv) extract32((rv), 8, 3)
65
70
+#define PLL_OTDV2(rv) extract32((rv), 13, 3)
66
/* If S1 fails or S2 is disabled, return early. */
71
+#define APB3CKDIV(rv) extract32((rv), 28, 2)
67
if (ret || regime_translation_disabled(env, ARMMMUIdx_Stage2,
72
+#define CLK2CKDIV(rv) extract32((rv), 0, 1)
68
@@ -XXX,XX +XXX,XX @@ bool get_phys_addr_with_secure(CPUARMState *env, target_ulong address,
73
+#define CLK4CKDIV(rv) extract32((rv), 26, 2)
69
s2walk_secure = false;
74
+#define CPUCKSEL(rv) extract32((rv), 0, 2)
70
}
75
+
71
76
+#define MAX_DUTY 1000000
72
- ptw.in_mmu_idx =
77
+
73
+ ptw->in_mmu_idx =
78
+typedef struct PWMModule {
74
s2walk_secure ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2;
79
+ int irq;
75
- ptw.in_secure = s2walk_secure;
80
+ uint64_t base_addr;
76
+ ptw->in_secure = s2walk_secure;
81
+} PWMModule;
77
is_el0 = mmu_idx == ARMMMUIdx_E10_0;
82
+
78
83
+typedef struct PWM {
79
/*
84
+ uint32_t cnr_offset;
80
@@ -XXX,XX +XXX,XX @@ bool get_phys_addr_with_secure(CPUARMState *env, target_ulong address,
85
+ uint32_t cmr_offset;
81
cacheattrs1 = result->cacheattrs;
86
+ uint32_t pdr_offset;
82
memset(result, 0, sizeof(*result));
87
+ uint32_t pwdr_offset;
83
88
+} PWM;
84
- ret = get_phys_addr_lpae(env, &ptw, ipa, access_type,
89
+
85
+ ret = get_phys_addr_lpae(env, ptw, ipa, access_type,
90
+typedef struct TestData {
86
is_el0, result, fi);
91
+ const PWMModule *module;
87
fi->s2addr = ipa;
92
+ const PWM *pwm;
88
93
+} TestData;
89
@@ -XXX,XX +XXX,XX @@ bool get_phys_addr_with_secure(CPUARMState *env, target_ulong address,
94
+
90
is_secure, result, fi);
95
+static const PWMModule pwm_module_list[] = {
91
}
96
+ {
92
97
+ .irq = 93,
93
- ptw.in_mmu_idx = mmu_idx;
98
+ .base_addr = 0xf0103000
94
- ptw.in_secure = is_secure;
99
+ },
95
-
100
+ {
96
if (regime_using_lpae_format(env, mmu_idx)) {
101
+ .irq = 94,
97
- return get_phys_addr_lpae(env, &ptw, address, access_type, false,
102
+ .base_addr = 0xf0104000
98
+ return get_phys_addr_lpae(env, ptw, address, access_type, false,
103
+ }
99
result, fi);
104
+};
100
} else if (regime_sctlr(env, mmu_idx) & SCTLR_XP) {
105
+
101
- return get_phys_addr_v6(env, &ptw, address, access_type, result, fi);
106
+static const PWM pwm_list[] = {
102
+ return get_phys_addr_v6(env, ptw, address, access_type, result, fi);
107
+ {
103
} else {
108
+ .cnr_offset = 0x0c,
104
- return get_phys_addr_v5(env, &ptw, address, access_type, result, fi);
109
+ .cmr_offset = 0x10,
105
+ return get_phys_addr_v5(env, ptw, address, access_type, result, fi);
110
+ .pdr_offset = 0x14,
106
}
111
+ .pwdr_offset = 0x44,
107
}
112
+ },
108
113
+ {
109
+bool get_phys_addr_with_secure(CPUARMState *env, target_ulong address,
114
+ .cnr_offset = 0x18,
110
+ MMUAccessType access_type, ARMMMUIdx mmu_idx,
115
+ .cmr_offset = 0x1c,
111
+ bool is_secure, GetPhysAddrResult *result,
116
+ .pdr_offset = 0x20,
112
+ ARMMMUFaultInfo *fi)
117
+ .pwdr_offset = 0x48,
118
+ },
119
+ {
120
+ .cnr_offset = 0x24,
121
+ .cmr_offset = 0x28,
122
+ .pdr_offset = 0x2c,
123
+ .pwdr_offset = 0x4c,
124
+ },
125
+ {
126
+ .cnr_offset = 0x30,
127
+ .cmr_offset = 0x34,
128
+ .pdr_offset = 0x38,
129
+ .pwdr_offset = 0x50,
130
+ },
131
+};
132
+
133
+static const int ppr_base[] = { 0, 0, 8, 8 };
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
+{
113
+{
181
+ ptrdiff_t diff = module - pwm_module_list;
114
+ S1Translate ptw = {
182
+
115
+ .in_mmu_idx = mmu_idx,
183
+ g_assert_true(diff >= 0 && diff < ARRAY_SIZE(pwm_module_list));
116
+ .in_secure = is_secure,
184
+
117
+ };
185
+ return diff;
118
+ return get_phys_addr_with_struct(env, &ptw, address, access_type,
119
+ result, fi);
186
+}
120
+}
187
+
121
+
188
+/* Returns the index of the PWM entry. */
122
bool get_phys_addr(CPUARMState *env, target_ulong address,
189
+static int pwm_index(const PWM *pwm)
123
MMUAccessType access_type, ARMMMUIdx mmu_idx,
190
+{
124
GetPhysAddrResult *result, ARMMMUFaultInfo *fi)
191
+ ptrdiff_t diff = pwm - pwm_list;
125
@@ -XXX,XX +XXX,XX @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr,
192
+
126
{
193
+ g_assert_true(diff >= 0 && diff < ARRAY_SIZE(pwm_list));
127
ARMCPU *cpu = ARM_CPU(cs);
194
+
128
CPUARMState *env = &cpu->env;
195
+ return diff;
129
+ S1Translate ptw = {
196
+}
130
+ .in_mmu_idx = arm_mmu_idx(env),
197
+
131
+ .in_secure = arm_is_secure(env),
198
+static uint64_t pwm_qom_get(QTestState *qts, const char *path, const char *name)
132
+ .in_debug = true,
199
+{
133
+ };
200
+ QDict *response;
134
GetPhysAddrResult res = {};
201
+
135
ARMMMUFaultInfo fi = {};
202
+ g_test_message("Getting properties %s from %s", name, path);
136
- ARMMMUIdx mmu_idx = arm_mmu_idx(env);
203
+ response = qtest_qmp(qts, "{ 'execute': 'qom-get',"
137
bool ret;
204
+ " 'arguments': { 'path': %s, 'property': %s}}",
138
205
+ path, name);
139
- ret = get_phys_addr(env, addr, MMU_DATA_LOAD, mmu_idx, &res, &fi);
206
+ /* The qom set message returns successfully. */
140
+ ret = get_phys_addr_with_struct(env, &ptw, addr, MMU_DATA_LOAD, &res, &fi);
207
+ g_assert_true(qdict_haskey(response, "return"));
141
*attrs = res.f.attrs;
208
+ return qnum_get_uint(qobject_to(QNum, qdict_get(response, "return")));
142
209
+}
143
if (ret) {
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
--
144
--
527
2.20.1
145
2.25.1
528
529
diff view generated by jsdifflib
1
From: Leif Lindholm <leif@nuviainc.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
When FEAT_MTE is implemented, the AArch64 view of CTR_EL0 adds the
3
Hoist this test out of arm_ld[lq]_ptw into S1_ptw_translate.
4
TminLine field in bits [37:32].
5
Extend the ctr field to be able to hold this context.
6
4
7
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
5
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Hao Wu <wuhaotsh@google.com>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20221011031911.2408754-10-richard.henderson@linaro.org
10
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
11
Message-id: 20210108185154.8108-4-leif@nuviainc.com
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
9
---
14
target/arm/cpu.h | 2 +-
10
target/arm/ptw.c | 6 ++++--
15
1 file changed, 1 insertion(+), 1 deletion(-)
11
1 file changed, 4 insertions(+), 2 deletions(-)
16
12
17
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
13
diff --git a/target/arm/ptw.c b/target/arm/ptw.c
18
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/cpu.h
15
--- a/target/arm/ptw.c
20
+++ b/target/arm/cpu.h
16
+++ b/target/arm/ptw.c
21
@@ -XXX,XX +XXX,XX @@ struct ARMCPU {
17
@@ -XXX,XX +XXX,XX @@ typedef struct S1Translate {
22
uint64_t midr;
18
bool in_secure;
23
uint32_t revidr;
19
bool in_debug;
24
uint32_t reset_fpsid;
20
bool out_secure;
25
- uint32_t ctr;
21
+ bool out_be;
26
+ uint64_t ctr;
22
hwaddr out_phys;
27
uint32_t reset_sctlr;
23
} S1Translate;
28
uint64_t pmceid0;
24
29
uint64_t pmceid1;
25
@@ -XXX,XX +XXX,XX @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw,
26
27
ptw->out_secure = is_secure;
28
ptw->out_phys = addr;
29
+ ptw->out_be = regime_translation_big_endian(env, ptw->in_mmu_idx);
30
return true;
31
}
32
33
@@ -XXX,XX +XXX,XX @@ static uint32_t arm_ldl_ptw(CPUARMState *env, S1Translate *ptw, hwaddr addr,
34
addr = ptw->out_phys;
35
attrs.secure = ptw->out_secure;
36
as = arm_addressspace(cs, attrs);
37
- if (regime_translation_big_endian(env, ptw->in_mmu_idx)) {
38
+ if (ptw->out_be) {
39
data = address_space_ldl_be(as, addr, attrs, &result);
40
} else {
41
data = address_space_ldl_le(as, addr, attrs, &result);
42
@@ -XXX,XX +XXX,XX @@ static uint64_t arm_ldq_ptw(CPUARMState *env, S1Translate *ptw, hwaddr addr,
43
addr = ptw->out_phys;
44
attrs.secure = ptw->out_secure;
45
as = arm_addressspace(cs, attrs);
46
- if (regime_translation_big_endian(env, ptw->in_mmu_idx)) {
47
+ if (ptw->out_be) {
48
data = address_space_ldq_be(as, addr, attrs, &result);
49
} else {
50
data = address_space_ldq_le(as, addr, attrs, &result);
30
--
51
--
31
2.20.1
52
2.25.1
32
33
diff view generated by jsdifflib
1
From: Leif Lindholm <leif@nuviainc.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
3
So far, limit the change to S1_ptw_translate, arm_ldl_ptw, and
4
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
4
arm_ldq_ptw. Use probe_access_full to find the host address,
5
Message-id: 20210108185154.8108-5-leif@nuviainc.com
5
and if so use a host load. If the probe fails, we've got our
6
fault info already. On the off chance that page tables are not
7
in RAM, continue to use the address_space_ld* functions.
8
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
11
Message-id: 20221011031911.2408754-11-richard.henderson@linaro.org
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
---
13
---
8
target/arm/cpu.h | 31 +++++++++++++++++++++++++++++++
14
target/arm/cpu.h | 5 +
9
1 file changed, 31 insertions(+)
15
target/arm/ptw.c | 196 +++++++++++++++++++++++++---------------
16
target/arm/tlb_helper.c | 17 +++-
17
3 files changed, 144 insertions(+), 74 deletions(-)
10
18
11
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
19
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
12
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
13
--- a/target/arm/cpu.h
21
--- a/target/arm/cpu.h
14
+++ b/target/arm/cpu.h
22
+++ b/target/arm/cpu.h
15
@@ -XXX,XX +XXX,XX @@ FIELD(V7M_FPCCR, ASPEN, 31, 1)
23
@@ -XXX,XX +XXX,XX @@ typedef struct CPUARMTBFlags {
16
/*
24
target_ulong flags2;
17
* System register ID fields.
25
} CPUARMTBFlags;
18
*/
26
19
+FIELD(CLIDR_EL1, CTYPE1, 0, 3)
27
+typedef struct ARMMMUFaultInfo ARMMMUFaultInfo;
20
+FIELD(CLIDR_EL1, CTYPE2, 3, 3)
28
+
21
+FIELD(CLIDR_EL1, CTYPE3, 6, 3)
29
typedef struct CPUArchState {
22
+FIELD(CLIDR_EL1, CTYPE4, 9, 3)
30
/* Regs for current mode. */
23
+FIELD(CLIDR_EL1, CTYPE5, 12, 3)
31
uint32_t regs[16];
24
+FIELD(CLIDR_EL1, CTYPE6, 15, 3)
32
@@ -XXX,XX +XXX,XX @@ typedef struct CPUArchState {
25
+FIELD(CLIDR_EL1, CTYPE7, 18, 3)
33
struct CPUBreakpoint *cpu_breakpoint[16];
26
+FIELD(CLIDR_EL1, LOUIS, 21, 3)
34
struct CPUWatchpoint *cpu_watchpoint[16];
27
+FIELD(CLIDR_EL1, LOC, 24, 3)
35
28
+FIELD(CLIDR_EL1, LOUU, 27, 3)
36
+ /* Optional fault info across tlb lookup. */
29
+FIELD(CLIDR_EL1, ICB, 30, 3)
37
+ ARMMMUFaultInfo *tlb_fi;
30
+
38
+
31
+/* When FEAT_CCIDX is implemented */
39
/* Fields up to this point are cleared by a CPU reset */
32
+FIELD(CCSIDR_EL1, CCIDX_LINESIZE, 0, 3)
40
struct {} end_reset_fields;
33
+FIELD(CCSIDR_EL1, CCIDX_ASSOCIATIVITY, 3, 21)
41
34
+FIELD(CCSIDR_EL1, CCIDX_NUMSETS, 32, 24)
42
diff --git a/target/arm/ptw.c b/target/arm/ptw.c
35
+
43
index XXXXXXX..XXXXXXX 100644
36
+/* When FEAT_CCIDX is not implemented */
44
--- a/target/arm/ptw.c
37
+FIELD(CCSIDR_EL1, LINESIZE, 0, 3)
45
+++ b/target/arm/ptw.c
38
+FIELD(CCSIDR_EL1, ASSOCIATIVITY, 3, 10)
46
@@ -XXX,XX +XXX,XX @@
39
+FIELD(CCSIDR_EL1, NUMSETS, 13, 15)
47
#include "qemu/osdep.h"
40
+
48
#include "qemu/log.h"
41
+FIELD(CTR_EL0, IMINLINE, 0, 4)
49
#include "qemu/range.h"
42
+FIELD(CTR_EL0, L1IP, 14, 2)
50
+#include "exec/exec-all.h"
43
+FIELD(CTR_EL0, DMINLINE, 16, 4)
51
#include "cpu.h"
44
+FIELD(CTR_EL0, ERG, 20, 4)
52
#include "internals.h"
45
+FIELD(CTR_EL0, CWG, 24, 4)
53
#include "idau.h"
46
+FIELD(CTR_EL0, IDC, 28, 1)
54
@@ -XXX,XX +XXX,XX @@ typedef struct S1Translate {
47
+FIELD(CTR_EL0, DIC, 29, 1)
55
bool out_secure;
48
+FIELD(CTR_EL0, TMINLINE, 32, 6)
56
bool out_be;
49
+
57
hwaddr out_phys;
50
FIELD(MIDR_EL1, REVISION, 0, 4)
58
+ void *out_host;
51
FIELD(MIDR_EL1, PARTNUM, 4, 12)
59
} S1Translate;
52
FIELD(MIDR_EL1, ARCHITECTURE, 16, 4)
60
61
static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw,
62
@@ -XXX,XX +XXX,XX @@ static bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx,
63
return (regime_sctlr(env, mmu_idx) & SCTLR_M) == 0;
64
}
65
66
-static bool ptw_attrs_are_device(uint64_t hcr, ARMCacheAttrs cacheattrs)
67
+static bool S2_attrs_are_device(uint64_t hcr, uint8_t attrs)
68
{
69
/*
70
* For an S1 page table walk, the stage 1 attributes are always
71
@@ -XXX,XX +XXX,XX @@ static bool ptw_attrs_are_device(uint64_t hcr, ARMCacheAttrs cacheattrs)
72
* With HCR_EL2.FWB == 1 this is when descriptor bit [4] is 0, ie
73
* when cacheattrs.attrs bit [2] is 0.
74
*/
75
- assert(cacheattrs.is_s2_format);
76
if (hcr & HCR_FWB) {
77
- return (cacheattrs.attrs & 0x4) == 0;
78
+ return (attrs & 0x4) == 0;
79
} else {
80
- return (cacheattrs.attrs & 0xc) == 0;
81
+ return (attrs & 0xc) == 0;
82
}
83
}
84
85
@@ -XXX,XX +XXX,XX @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw,
86
hwaddr addr, ARMMMUFaultInfo *fi)
87
{
88
bool is_secure = ptw->in_secure;
89
+ ARMMMUIdx mmu_idx = ptw->in_mmu_idx;
90
ARMMMUIdx s2_mmu_idx = is_secure ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2;
91
+ bool s2_phys = false;
92
+ uint8_t pte_attrs;
93
+ bool pte_secure;
94
95
- if (arm_mmu_idx_is_stage1_of_2(ptw->in_mmu_idx) &&
96
- !regime_translation_disabled(env, s2_mmu_idx, is_secure)) {
97
- GetPhysAddrResult s2 = {};
98
- S1Translate s2ptw = {
99
- .in_mmu_idx = s2_mmu_idx,
100
- .in_secure = is_secure,
101
- .in_debug = ptw->in_debug,
102
- };
103
- uint64_t hcr;
104
- int ret;
105
+ if (!arm_mmu_idx_is_stage1_of_2(mmu_idx)
106
+ || regime_translation_disabled(env, s2_mmu_idx, is_secure)) {
107
+ s2_mmu_idx = is_secure ? ARMMMUIdx_Phys_S : ARMMMUIdx_Phys_NS;
108
+ s2_phys = true;
109
+ }
110
111
- ret = get_phys_addr_lpae(env, &s2ptw, addr, MMU_DATA_LOAD,
112
- false, &s2, fi);
113
- if (ret) {
114
- assert(fi->type != ARMFault_None);
115
- fi->s2addr = addr;
116
- fi->stage2 = true;
117
- fi->s1ptw = true;
118
- fi->s1ns = !is_secure;
119
- return false;
120
+ if (unlikely(ptw->in_debug)) {
121
+ /*
122
+ * From gdbstub, do not use softmmu so that we don't modify the
123
+ * state of the cpu at all, including softmmu tlb contents.
124
+ */
125
+ if (s2_phys) {
126
+ ptw->out_phys = addr;
127
+ pte_attrs = 0;
128
+ pte_secure = is_secure;
129
+ } else {
130
+ S1Translate s2ptw = {
131
+ .in_mmu_idx = s2_mmu_idx,
132
+ .in_secure = is_secure,
133
+ .in_debug = true,
134
+ };
135
+ GetPhysAddrResult s2 = { };
136
+ if (!get_phys_addr_lpae(env, &s2ptw, addr, MMU_DATA_LOAD,
137
+ false, &s2, fi)) {
138
+ goto fail;
139
+ }
140
+ ptw->out_phys = s2.f.phys_addr;
141
+ pte_attrs = s2.cacheattrs.attrs;
142
+ pte_secure = s2.f.attrs.secure;
143
}
144
+ ptw->out_host = NULL;
145
+ } else {
146
+ CPUTLBEntryFull *full;
147
+ int flags;
148
149
- hcr = arm_hcr_el2_eff_secstate(env, is_secure);
150
- if ((hcr & HCR_PTW) && ptw_attrs_are_device(hcr, s2.cacheattrs)) {
151
+ env->tlb_fi = fi;
152
+ flags = probe_access_full(env, addr, MMU_DATA_LOAD,
153
+ arm_to_core_mmu_idx(s2_mmu_idx),
154
+ true, &ptw->out_host, &full, 0);
155
+ env->tlb_fi = NULL;
156
+
157
+ if (unlikely(flags & TLB_INVALID_MASK)) {
158
+ goto fail;
159
+ }
160
+ ptw->out_phys = full->phys_addr;
161
+ pte_attrs = full->pte_attrs;
162
+ pte_secure = full->attrs.secure;
163
+ }
164
+
165
+ if (!s2_phys) {
166
+ uint64_t hcr = arm_hcr_el2_eff_secstate(env, is_secure);
167
+
168
+ if ((hcr & HCR_PTW) && S2_attrs_are_device(hcr, pte_attrs)) {
169
/*
170
* PTW set and S1 walk touched S2 Device memory:
171
* generate Permission fault.
172
@@ -XXX,XX +XXX,XX @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw,
173
fi->s1ns = !is_secure;
174
return false;
175
}
176
-
177
- if (arm_is_secure_below_el3(env)) {
178
- /* Check if page table walk is to secure or non-secure PA space. */
179
- if (is_secure) {
180
- is_secure = !(env->cp15.vstcr_el2 & VSTCR_SW);
181
- } else {
182
- is_secure = !(env->cp15.vtcr_el2 & VTCR_NSW);
183
- }
184
- } else {
185
- assert(!is_secure);
186
- }
187
-
188
- addr = s2.f.phys_addr;
189
}
190
191
- ptw->out_secure = is_secure;
192
- ptw->out_phys = addr;
193
- ptw->out_be = regime_translation_big_endian(env, ptw->in_mmu_idx);
194
+ /* Check if page table walk is to secure or non-secure PA space. */
195
+ ptw->out_secure = (is_secure
196
+ && !(pte_secure
197
+ ? env->cp15.vstcr_el2 & VSTCR_SW
198
+ : env->cp15.vtcr_el2 & VTCR_NSW));
199
+ ptw->out_be = regime_translation_big_endian(env, mmu_idx);
200
return true;
201
+
202
+ fail:
203
+ assert(fi->type != ARMFault_None);
204
+ fi->s2addr = addr;
205
+ fi->stage2 = true;
206
+ fi->s1ptw = true;
207
+ fi->s1ns = !is_secure;
208
+ return false;
209
}
210
211
/* All loads done in the course of a page table walk go through here. */
212
@@ -XXX,XX +XXX,XX @@ static uint32_t arm_ldl_ptw(CPUARMState *env, S1Translate *ptw, hwaddr addr,
213
ARMMMUFaultInfo *fi)
214
{
215
CPUState *cs = env_cpu(env);
216
- MemTxAttrs attrs = {};
217
- MemTxResult result = MEMTX_OK;
218
- AddressSpace *as;
219
uint32_t data;
220
221
if (!S1_ptw_translate(env, ptw, addr, fi)) {
222
+ /* Failure. */
223
+ assert(fi->s1ptw);
224
return 0;
225
}
226
- addr = ptw->out_phys;
227
- attrs.secure = ptw->out_secure;
228
- as = arm_addressspace(cs, attrs);
229
- if (ptw->out_be) {
230
- data = address_space_ldl_be(as, addr, attrs, &result);
231
+
232
+ if (likely(ptw->out_host)) {
233
+ /* Page tables are in RAM, and we have the host address. */
234
+ if (ptw->out_be) {
235
+ data = ldl_be_p(ptw->out_host);
236
+ } else {
237
+ data = ldl_le_p(ptw->out_host);
238
+ }
239
} else {
240
- data = address_space_ldl_le(as, addr, attrs, &result);
241
+ /* Page tables are in MMIO. */
242
+ MemTxAttrs attrs = { .secure = ptw->out_secure };
243
+ AddressSpace *as = arm_addressspace(cs, attrs);
244
+ MemTxResult result = MEMTX_OK;
245
+
246
+ if (ptw->out_be) {
247
+ data = address_space_ldl_be(as, ptw->out_phys, attrs, &result);
248
+ } else {
249
+ data = address_space_ldl_le(as, ptw->out_phys, attrs, &result);
250
+ }
251
+ if (unlikely(result != MEMTX_OK)) {
252
+ fi->type = ARMFault_SyncExternalOnWalk;
253
+ fi->ea = arm_extabort_type(result);
254
+ return 0;
255
+ }
256
}
257
- if (result == MEMTX_OK) {
258
- return data;
259
- }
260
- fi->type = ARMFault_SyncExternalOnWalk;
261
- fi->ea = arm_extabort_type(result);
262
- return 0;
263
+ return data;
264
}
265
266
static uint64_t arm_ldq_ptw(CPUARMState *env, S1Translate *ptw, hwaddr addr,
267
ARMMMUFaultInfo *fi)
268
{
269
CPUState *cs = env_cpu(env);
270
- MemTxAttrs attrs = {};
271
- MemTxResult result = MEMTX_OK;
272
- AddressSpace *as;
273
uint64_t data;
274
275
if (!S1_ptw_translate(env, ptw, addr, fi)) {
276
+ /* Failure. */
277
+ assert(fi->s1ptw);
278
return 0;
279
}
280
- addr = ptw->out_phys;
281
- attrs.secure = ptw->out_secure;
282
- as = arm_addressspace(cs, attrs);
283
- if (ptw->out_be) {
284
- data = address_space_ldq_be(as, addr, attrs, &result);
285
+
286
+ if (likely(ptw->out_host)) {
287
+ /* Page tables are in RAM, and we have the host address. */
288
+ if (ptw->out_be) {
289
+ data = ldq_be_p(ptw->out_host);
290
+ } else {
291
+ data = ldq_le_p(ptw->out_host);
292
+ }
293
} else {
294
- data = address_space_ldq_le(as, addr, attrs, &result);
295
+ /* Page tables are in MMIO. */
296
+ MemTxAttrs attrs = { .secure = ptw->out_secure };
297
+ AddressSpace *as = arm_addressspace(cs, attrs);
298
+ MemTxResult result = MEMTX_OK;
299
+
300
+ if (ptw->out_be) {
301
+ data = address_space_ldq_be(as, ptw->out_phys, attrs, &result);
302
+ } else {
303
+ data = address_space_ldq_le(as, ptw->out_phys, attrs, &result);
304
+ }
305
+ if (unlikely(result != MEMTX_OK)) {
306
+ fi->type = ARMFault_SyncExternalOnWalk;
307
+ fi->ea = arm_extabort_type(result);
308
+ return 0;
309
+ }
310
}
311
- if (result == MEMTX_OK) {
312
- return data;
313
- }
314
- fi->type = ARMFault_SyncExternalOnWalk;
315
- fi->ea = arm_extabort_type(result);
316
- return 0;
317
+ return data;
318
}
319
320
static bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx,
321
diff --git a/target/arm/tlb_helper.c b/target/arm/tlb_helper.c
322
index XXXXXXX..XXXXXXX 100644
323
--- a/target/arm/tlb_helper.c
324
+++ b/target/arm/tlb_helper.c
325
@@ -XXX,XX +XXX,XX @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
326
bool probe, uintptr_t retaddr)
327
{
328
ARMCPU *cpu = ARM_CPU(cs);
329
- ARMMMUFaultInfo fi = {};
330
GetPhysAddrResult res = {};
331
+ ARMMMUFaultInfo local_fi, *fi;
332
int ret;
333
334
+ /*
335
+ * Allow S1_ptw_translate to see any fault generated here.
336
+ * Since this may recurse, read and clear.
337
+ */
338
+ fi = cpu->env.tlb_fi;
339
+ if (fi) {
340
+ cpu->env.tlb_fi = NULL;
341
+ } else {
342
+ fi = memset(&local_fi, 0, sizeof(local_fi));
343
+ }
344
+
345
/*
346
* Walk the page table and (if the mapping exists) add the page
347
* to the TLB. On success, return true. Otherwise, if probing,
348
@@ -XXX,XX +XXX,XX @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
349
*/
350
ret = get_phys_addr(&cpu->env, address, access_type,
351
core_to_arm_mmu_idx(&cpu->env, mmu_idx),
352
- &res, &fi);
353
+ &res, fi);
354
if (likely(!ret)) {
355
/*
356
* Map a single [sub]page. Regions smaller than our declared
357
@@ -XXX,XX +XXX,XX @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
358
} else {
359
/* now we have a real cpu fault */
360
cpu_restore_state(cs, retaddr, true);
361
- arm_deliver_fault(cpu, address, access_type, mmu_idx, &fi);
362
+ arm_deliver_fault(cpu, address, access_type, mmu_idx, fi);
363
}
364
}
365
#else
53
--
366
--
54
2.20.1
367
2.25.1
55
56
diff view generated by jsdifflib
1
The lan9118 code mostly uses symbolic constants for register offsets;
1
From: Richard Henderson <richard.henderson@linaro.org>
2
the exceptions are those which the datasheet doesn't give an official
3
symbolic name to.
4
2
5
Add some names for the registers which don't already have them, based
3
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
on the longer names they are given in the memory map.
4
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20221011031911.2408754-12-richard.henderson@linaro.org
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
---
8
target/arm/ptw.c | 191 +++++++++++++++++++++++++----------------------
9
1 file changed, 100 insertions(+), 91 deletions(-)
7
10
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
diff --git a/target/arm/ptw.c b/target/arm/ptw.c
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
10
Message-id: 20210108180401.2263-3-peter.maydell@linaro.org
11
---
12
hw/net/lan9118.c | 24 ++++++++++++++++++------
13
1 file changed, 18 insertions(+), 6 deletions(-)
14
15
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
16
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/net/lan9118.c
13
--- a/target/arm/ptw.c
18
+++ b/hw/net/lan9118.c
14
+++ b/target/arm/ptw.c
19
@@ -XXX,XX +XXX,XX @@ do { hw_error("lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
15
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw,
20
do { fprintf(stderr, "lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
16
GetPhysAddrResult *result, ARMMMUFaultInfo *fi)
21
#endif
17
__attribute__((nonnull));
22
18
23
+/* The tx and rx fifo ports are a range of aliased 32-bit registers */
19
+static bool get_phys_addr_with_struct(CPUARMState *env, S1Translate *ptw,
24
+#define RX_DATA_FIFO_PORT_FIRST 0x00
20
+ target_ulong address,
25
+#define RX_DATA_FIFO_PORT_LAST 0x1f
21
+ MMUAccessType access_type,
26
+#define TX_DATA_FIFO_PORT_FIRST 0x20
22
+ GetPhysAddrResult *result,
27
+#define TX_DATA_FIFO_PORT_LAST 0x3f
23
+ ARMMMUFaultInfo *fi)
28
+
24
+ __attribute__((nonnull));
29
+#define RX_STATUS_FIFO_PORT 0x40
25
+
30
+#define RX_STATUS_FIFO_PEEK 0x44
26
/* This mapping is common between ID_AA64MMFR0.PARANGE and TCR_ELx.{I}PS. */
31
+#define TX_STATUS_FIFO_PORT 0x48
27
static const uint8_t pamax_map[] = {
32
+#define TX_STATUS_FIFO_PEEK 0x4c
28
[0] = 32,
33
+
29
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_disabled(CPUARMState *env, target_ulong address,
34
#define CSR_ID_REV 0x50
30
return 0;
35
#define CSR_IRQ_CFG 0x54
31
}
36
#define CSR_INT_STS 0x58
32
37
@@ -XXX,XX +XXX,XX @@ static void lan9118_writel(void *opaque, hwaddr offset,
33
+static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw,
38
offset &= 0xff;
34
+ target_ulong address,
39
35
+ MMUAccessType access_type,
40
//DPRINTF("Write reg 0x%02x = 0x%08x\n", (int)offset, val);
36
+ GetPhysAddrResult *result,
41
- if (offset >= 0x20 && offset < 0x40) {
37
+ ARMMMUFaultInfo *fi)
42
+ if (offset >= TX_DATA_FIFO_PORT_FIRST &&
38
+{
43
+ offset <= TX_DATA_FIFO_PORT_LAST) {
39
+ hwaddr ipa;
44
/* TX FIFO */
40
+ int s1_prot;
45
tx_fifo_push(s, val);
41
+ int ret;
46
return;
42
+ bool is_secure = ptw->in_secure;
47
@@ -XXX,XX +XXX,XX @@ static uint64_t lan9118_readl(void *opaque, hwaddr offset,
43
+ bool ipa_secure, s2walk_secure;
48
lan9118_state *s = (lan9118_state *)opaque;
44
+ ARMCacheAttrs cacheattrs1;
49
45
+ bool is_el0;
50
//DPRINTF("Read reg 0x%02x\n", (int)offset);
46
+ uint64_t hcr;
51
- if (offset < 0x20) {
47
+
52
+ if (offset <= RX_DATA_FIFO_PORT_LAST) {
48
+ ret = get_phys_addr_with_struct(env, ptw, address, access_type, result, fi);
53
/* RX FIFO */
49
+
54
return rx_fifo_pop(s);
50
+ /* If S1 fails or S2 is disabled, return early. */
51
+ if (ret || regime_translation_disabled(env, ARMMMUIdx_Stage2, is_secure)) {
52
+ return ret;
53
+ }
54
+
55
+ ipa = result->f.phys_addr;
56
+ ipa_secure = result->f.attrs.secure;
57
+ if (is_secure) {
58
+ /* Select TCR based on the NS bit from the S1 walk. */
59
+ s2walk_secure = !(ipa_secure
60
+ ? env->cp15.vstcr_el2 & VSTCR_SW
61
+ : env->cp15.vtcr_el2 & VTCR_NSW);
62
+ } else {
63
+ assert(!ipa_secure);
64
+ s2walk_secure = false;
65
+ }
66
+
67
+ is_el0 = ptw->in_mmu_idx == ARMMMUIdx_Stage1_E0;
68
+ ptw->in_mmu_idx = s2walk_secure ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2;
69
+ ptw->in_secure = s2walk_secure;
70
+
71
+ /*
72
+ * S1 is done, now do S2 translation.
73
+ * Save the stage1 results so that we may merge prot and cacheattrs later.
74
+ */
75
+ s1_prot = result->f.prot;
76
+ cacheattrs1 = result->cacheattrs;
77
+ memset(result, 0, sizeof(*result));
78
+
79
+ ret = get_phys_addr_lpae(env, ptw, ipa, access_type, is_el0, result, fi);
80
+ fi->s2addr = ipa;
81
+
82
+ /* Combine the S1 and S2 perms. */
83
+ result->f.prot &= s1_prot;
84
+
85
+ /* If S2 fails, return early. */
86
+ if (ret) {
87
+ return ret;
88
+ }
89
+
90
+ /* Combine the S1 and S2 cache attributes. */
91
+ hcr = arm_hcr_el2_eff_secstate(env, is_secure);
92
+ if (hcr & HCR_DC) {
93
+ /*
94
+ * HCR.DC forces the first stage attributes to
95
+ * Normal Non-Shareable,
96
+ * Inner Write-Back Read-Allocate Write-Allocate,
97
+ * Outer Write-Back Read-Allocate Write-Allocate.
98
+ * Do not overwrite Tagged within attrs.
99
+ */
100
+ if (cacheattrs1.attrs != 0xf0) {
101
+ cacheattrs1.attrs = 0xff;
102
+ }
103
+ cacheattrs1.shareability = 0;
104
+ }
105
+ result->cacheattrs = combine_cacheattrs(hcr, cacheattrs1,
106
+ result->cacheattrs);
107
+
108
+ /*
109
+ * Check if IPA translates to secure or non-secure PA space.
110
+ * Note that VSTCR overrides VTCR and {N}SW overrides {N}SA.
111
+ */
112
+ result->f.attrs.secure =
113
+ (is_secure
114
+ && !(env->cp15.vstcr_el2 & (VSTCR_SA | VSTCR_SW))
115
+ && (ipa_secure
116
+ || !(env->cp15.vtcr_el2 & (VTCR_NSA | VTCR_NSW))));
117
+
118
+ return 0;
119
+}
120
+
121
static bool get_phys_addr_with_struct(CPUARMState *env, S1Translate *ptw,
122
target_ulong address,
123
MMUAccessType access_type,
124
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_with_struct(CPUARMState *env, S1Translate *ptw,
125
if (mmu_idx != s1_mmu_idx) {
126
/*
127
* Call ourselves recursively to do the stage 1 and then stage 2
128
- * translations if mmu_idx is a two-stage regime.
129
+ * translations if mmu_idx is a two-stage regime, and EL2 present.
130
+ * Otherwise, a stage1+stage2 translation is just stage 1.
131
*/
132
+ ptw->in_mmu_idx = mmu_idx = s1_mmu_idx;
133
if (arm_feature(env, ARM_FEATURE_EL2)) {
134
- hwaddr ipa;
135
- int s1_prot;
136
- int ret;
137
- bool ipa_secure, s2walk_secure;
138
- ARMCacheAttrs cacheattrs1;
139
- bool is_el0;
140
- uint64_t hcr;
141
-
142
- ptw->in_mmu_idx = s1_mmu_idx;
143
- ret = get_phys_addr_with_struct(env, ptw, address, access_type,
144
- result, fi);
145
-
146
- /* If S1 fails or S2 is disabled, return early. */
147
- if (ret || regime_translation_disabled(env, ARMMMUIdx_Stage2,
148
- is_secure)) {
149
- return ret;
150
- }
151
-
152
- ipa = result->f.phys_addr;
153
- ipa_secure = result->f.attrs.secure;
154
- if (is_secure) {
155
- /* Select TCR based on the NS bit from the S1 walk. */
156
- s2walk_secure = !(ipa_secure
157
- ? env->cp15.vstcr_el2 & VSTCR_SW
158
- : env->cp15.vtcr_el2 & VTCR_NSW);
159
- } else {
160
- assert(!ipa_secure);
161
- s2walk_secure = false;
162
- }
163
-
164
- ptw->in_mmu_idx =
165
- s2walk_secure ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2;
166
- ptw->in_secure = s2walk_secure;
167
- is_el0 = mmu_idx == ARMMMUIdx_E10_0;
168
-
169
- /*
170
- * S1 is done, now do S2 translation.
171
- * Save the stage1 results so that we may merge
172
- * prot and cacheattrs later.
173
- */
174
- s1_prot = result->f.prot;
175
- cacheattrs1 = result->cacheattrs;
176
- memset(result, 0, sizeof(*result));
177
-
178
- ret = get_phys_addr_lpae(env, ptw, ipa, access_type,
179
- is_el0, result, fi);
180
- fi->s2addr = ipa;
181
-
182
- /* Combine the S1 and S2 perms. */
183
- result->f.prot &= s1_prot;
184
-
185
- /* If S2 fails, return early. */
186
- if (ret) {
187
- return ret;
188
- }
189
-
190
- /* Combine the S1 and S2 cache attributes. */
191
- hcr = arm_hcr_el2_eff_secstate(env, is_secure);
192
- if (hcr & HCR_DC) {
193
- /*
194
- * HCR.DC forces the first stage attributes to
195
- * Normal Non-Shareable,
196
- * Inner Write-Back Read-Allocate Write-Allocate,
197
- * Outer Write-Back Read-Allocate Write-Allocate.
198
- * Do not overwrite Tagged within attrs.
199
- */
200
- if (cacheattrs1.attrs != 0xf0) {
201
- cacheattrs1.attrs = 0xff;
202
- }
203
- cacheattrs1.shareability = 0;
204
- }
205
- result->cacheattrs = combine_cacheattrs(hcr, cacheattrs1,
206
- result->cacheattrs);
207
-
208
- /*
209
- * Check if IPA translates to secure or non-secure PA space.
210
- * Note that VSTCR overrides VTCR and {N}SW overrides {N}SA.
211
- */
212
- result->f.attrs.secure =
213
- (is_secure
214
- && !(env->cp15.vstcr_el2 & (VSTCR_SA | VSTCR_SW))
215
- && (ipa_secure
216
- || !(env->cp15.vtcr_el2 & (VTCR_NSA | VTCR_NSW))));
217
-
218
- return 0;
219
- } else {
220
- /*
221
- * For non-EL2 CPUs a stage1+stage2 translation is just stage 1.
222
- */
223
- mmu_idx = stage_1_mmu_idx(mmu_idx);
224
+ return get_phys_addr_twostage(env, ptw, address, access_type,
225
+ result, fi);
226
}
55
}
227
}
56
switch (offset) {
228
57
- case 0x40:
58
+ case RX_STATUS_FIFO_PORT:
59
return rx_status_fifo_pop(s);
60
- case 0x44:
61
+ case RX_STATUS_FIFO_PEEK:
62
return s->rx_status_fifo[s->rx_status_fifo_head];
63
- case 0x48:
64
+ case TX_STATUS_FIFO_PORT:
65
return tx_status_fifo_pop(s);
66
- case 0x4c:
67
+ case TX_STATUS_FIFO_PEEK:
68
return s->tx_status_fifo[s->tx_status_fifo_head];
69
case CSR_ID_REV:
70
return 0x01180001;
71
--
229
--
72
2.20.1
230
2.25.1
73
74
diff view generated by jsdifflib
1
From: Hao Wu <wuhaotsh@google.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
A device shouldn't access its parent object which is QOM internal.
3
The return type of the functions is already bool, but in a few
4
Instead it should use type cast for this purporse. This patch fixes this
4
instances we used an integer type with the return statement.
5
issue for all NPCM7XX Devices.
6
5
7
Signed-off-by: Hao Wu <wuhaotsh@google.com>
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Message-id: 20210108190945.949196-7-wuhaotsh@google.com
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20221011031911.2408754-13-richard.henderson@linaro.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
10
---
12
hw/arm/npcm7xx_boards.c | 2 +-
11
target/arm/ptw.c | 7 +++----
13
hw/mem/npcm7xx_mc.c | 2 +-
12
1 file changed, 3 insertions(+), 4 deletions(-)
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
13
21
diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c
14
diff --git a/target/arm/ptw.c b/target/arm/ptw.c
22
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
23
--- a/hw/arm/npcm7xx_boards.c
16
--- a/target/arm/ptw.c
24
+++ b/hw/arm/npcm7xx_boards.c
17
+++ b/target/arm/ptw.c
25
@@ -XXX,XX +XXX,XX @@ static NPCM7xxState *npcm7xx_create_soc(MachineState *machine,
18
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_disabled(CPUARMState *env, target_ulong address,
26
uint32_t hw_straps)
19
result->f.lg_page_size = TARGET_PAGE_BITS;
20
result->cacheattrs.shareability = shareability;
21
result->cacheattrs.attrs = memattr;
22
- return 0;
23
+ return false;
24
}
25
26
static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw,
27
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw,
27
{
28
{
28
NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_GET_CLASS(machine);
29
hwaddr ipa;
29
- MachineClass *mc = &nmc->parent;
30
int s1_prot;
30
+ MachineClass *mc = MACHINE_CLASS(nmc);
31
- int ret;
31
Object *obj;
32
bool is_secure = ptw->in_secure;
32
33
- bool ipa_secure, s2walk_secure;
33
if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) {
34
+ bool ret, ipa_secure, s2walk_secure;
34
diff --git a/hw/mem/npcm7xx_mc.c b/hw/mem/npcm7xx_mc.c
35
ARMCacheAttrs cacheattrs1;
35
index XXXXXXX..XXXXXXX 100644
36
bool is_el0;
36
--- a/hw/mem/npcm7xx_mc.c
37
uint64_t hcr;
37
+++ b/hw/mem/npcm7xx_mc.c
38
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw,
38
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_mc_realize(DeviceState *dev, Error **errp)
39
&& (ipa_secure
39
40
|| !(env->cp15.vtcr_el2 & (VTCR_NSA | VTCR_NSW))));
40
memory_region_init_io(&s->mmio, OBJECT(s), &npcm7xx_mc_ops, s, "regs",
41
41
NPCM7XX_MC_REGS_SIZE);
42
- return 0;
42
- sysbus_init_mmio(&s->parent, &s->mmio);
43
+ return false;
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
static bool get_phys_addr_with_struct(CPUARMState *env, S1Translate *ptw,
47
diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/hw/misc/npcm7xx_clk.c
50
+++ b/hw/misc/npcm7xx_clk.c
51
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_init(Object *obj)
52
53
memory_region_init_io(&s->iomem, obj, &npcm7xx_clk_ops, s,
54
TYPE_NPCM7XX_CLK, 4 * KiB);
55
- sysbus_init_mmio(&s->parent, &s->iomem);
56
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
57
}
58
59
static int npcm7xx_clk_post_load(void *opaque, int version_id)
60
diff --git a/hw/misc/npcm7xx_gcr.c b/hw/misc/npcm7xx_gcr.c
61
index XXXXXXX..XXXXXXX 100644
62
--- a/hw/misc/npcm7xx_gcr.c
63
+++ b/hw/misc/npcm7xx_gcr.c
64
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_gcr_init(Object *obj)
65
66
memory_region_init_io(&s->iomem, obj, &npcm7xx_gcr_ops, s,
67
TYPE_NPCM7XX_GCR, 4 * KiB);
68
- sysbus_init_mmio(&s->parent, &s->iomem);
69
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
70
}
71
72
static const VMStateDescription vmstate_npcm7xx_gcr = {
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
--
47
--
113
2.20.1
48
2.25.1
114
115
diff view generated by jsdifflib
1
From: Hao Wu <wuhaotsh@google.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
The PWM module is part of NPCM7XX module. Each NPCM7XX module has two
3
A simple helper to retrieve the length of the current insn.
4
identical PWM modules. Each module contains 4 PWM entries. Each PWM has
5
two outputs: frequency and duty_cycle. Both are computed using inputs
6
from software side.
7
4
8
This module does not model detail pulse signals since it is expensive.
5
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
It also does not model interrupts and watchdogs that are dependant on
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
10
the detail models. The interfaces for these are left in the module so
7
Message-id: 20221020030641.2066807-2-richard.henderson@linaro.org
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>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
22
---
9
---
23
docs/system/arm/nuvoton.rst | 2 +-
10
target/arm/translate.h | 5 +++++
24
include/hw/arm/npcm7xx.h | 2 +
11
target/arm/translate-vfp.c | 2 +-
25
include/hw/misc/npcm7xx_pwm.h | 105 +++++++
12
target/arm/translate.c | 5 ++---
26
hw/arm/npcm7xx.c | 26 +-
13
3 files changed, 8 insertions(+), 4 deletions(-)
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
14
34
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
15
diff --git a/target/arm/translate.h b/target/arm/translate.h
35
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
36
--- a/docs/system/arm/nuvoton.rst
17
--- a/target/arm/translate.h
37
+++ b/docs/system/arm/nuvoton.rst
18
+++ b/target/arm/translate.h
38
@@ -XXX,XX +XXX,XX @@ Supported devices
19
@@ -XXX,XX +XXX,XX @@ static inline void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
39
* USB host (USBH)
20
s->insn_start = NULL;
40
* GPIO controller
41
* Analog to Digital Converter (ADC)
42
+ * Pulse Width Modulation (PWM)
43
44
Missing devices
45
---------------
46
@@ -XXX,XX +XXX,XX @@ Missing devices
47
* Peripheral SPI controller (PSPI)
48
* SD/MMC host
49
* PECI interface
50
- * Pulse Width Modulation (PWM)
51
* Tachometer
52
* PCI and PCIe root complex and bridges
53
* VDM and MCTP support
54
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
55
index XXXXXXX..XXXXXXX 100644
56
--- a/include/hw/arm/npcm7xx.h
57
+++ b/include/hw/arm/npcm7xx.h
58
@@ -XXX,XX +XXX,XX @@
59
#include "hw/mem/npcm7xx_mc.h"
60
#include "hw/misc/npcm7xx_clk.h"
61
#include "hw/misc/npcm7xx_gcr.h"
62
+#include "hw/misc/npcm7xx_pwm.h"
63
#include "hw/misc/npcm7xx_rng.h"
64
#include "hw/nvram/npcm7xx_otp.h"
65
#include "hw/timer/npcm7xx_timer.h"
66
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
67
NPCM7xxCLKState clk;
68
NPCM7xxTimerCtrlState tim[3];
69
NPCM7xxADCState adc;
70
+ NPCM7xxPWMState pwm[2];
71
NPCM7xxOTPState key_storage;
72
NPCM7xxOTPState fuse_array;
73
NPCM7xxMCState mc;
74
diff --git a/include/hw/misc/npcm7xx_pwm.h b/include/hw/misc/npcm7xx_pwm.h
75
new file mode 100644
76
index XXXXXXX..XXXXXXX
77
--- /dev/null
78
+++ b/include/hw/misc/npcm7xx_pwm.h
79
@@ -XXX,XX +XXX,XX @@
80
+/*
81
+ * Nuvoton NPCM7xx PWM 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_PWM_H
96
+#define NPCM7XX_PWM_H
97
+
98
+#include "hw/clock.h"
99
+#include "hw/sysbus.h"
100
+#include "hw/irq.h"
101
+
102
+/* Each PWM module holds 4 PWM channels. */
103
+#define NPCM7XX_PWM_PER_MODULE 4
104
+
105
+/*
106
+ * Number of registers in one pwm module. Don't change this without increasing
107
+ * the version_id in vmstate.
108
+ */
109
+#define NPCM7XX_PWM_NR_REGS (0x54 / sizeof(uint32_t))
110
+
111
+/*
112
+ * The maximum duty values. Each duty unit represents 1/NPCM7XX_PWM_MAX_DUTY
113
+ * cycles. For example, if NPCM7XX_PWM_MAX_DUTY=1,000,000 and a PWM has a duty
114
+ * value of 100,000 the duty cycle for that PWM is 10%.
115
+ */
116
+#define NPCM7XX_PWM_MAX_DUTY 1000000
117
+
118
+typedef struct NPCM7xxPWMState NPCM7xxPWMState;
119
+
120
+/**
121
+ * struct NPCM7xxPWM - The state of a single PWM channel.
122
+ * @module: The PWM module that contains this channel.
123
+ * @irq: GIC interrupt line to fire on expiration if enabled.
124
+ * @running: Whether this PWM channel is generating output.
125
+ * @inverted: Whether this PWM channel is inverted.
126
+ * @index: The index of this PWM channel.
127
+ * @cnr: The counter register.
128
+ * @cmr: The comparator register.
129
+ * @pdr: The data register.
130
+ * @pwdr: The watchdog register.
131
+ * @freq: The frequency of this PWM channel.
132
+ * @duty: The duty cycle of this PWM channel. One unit represents
133
+ * 1/NPCM7XX_MAX_DUTY cycles.
134
+ */
135
+typedef struct NPCM7xxPWM {
136
+ NPCM7xxPWMState *module;
137
+
138
+ qemu_irq irq;
139
+
140
+ bool running;
141
+ bool inverted;
142
+
143
+ uint8_t index;
144
+ uint32_t cnr;
145
+ uint32_t cmr;
146
+ uint32_t pdr;
147
+ uint32_t pwdr;
148
+
149
+ uint32_t freq;
150
+ uint32_t duty;
151
+} NPCM7xxPWM;
152
+
153
+/**
154
+ * struct NPCM7xxPWMState - Pulse Width Modulation device state.
155
+ * @parent: System bus device.
156
+ * @iomem: Memory region through which registers are accessed.
157
+ * @clock: The PWM clock.
158
+ * @pwm: The PWM channels owned by this module.
159
+ * @ppr: The prescaler register.
160
+ * @csr: The clock selector register.
161
+ * @pcr: The control register.
162
+ * @pier: The interrupt enable register.
163
+ * @piir: The interrupt indication register.
164
+ */
165
+struct NPCM7xxPWMState {
166
+ SysBusDevice parent;
167
+
168
+ MemoryRegion iomem;
169
+
170
+ Clock *clock;
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
}
215
+
216
+ for (i = 0; i < ARRAY_SIZE(s->pwm); i++) {
217
+ object_initialize_child(obj, "pwm[*]", &s->pwm[i], TYPE_NPCM7XX_PWM);
218
+ }
219
}
21
}
220
22
221
static void npcm7xx_realize(DeviceState *dev, Error **errp)
23
+static inline int curr_insn_len(DisasContext *s)
222
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
223
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ohci), 0,
224
npcm7xx_irq(s, NPCM7XX_OHCI_IRQ));
225
226
+ /* PWM Modules. Cannot fail. */
227
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_pwm_addr) != ARRAY_SIZE(s->pwm));
228
+ for (i = 0; i < ARRAY_SIZE(s->pwm); i++) {
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
+{
24
+{
325
+ uint32_t ppr;
25
+ return s->base.pc_next - s->pc_curr;
326
+ uint32_t csr;
327
+ uint32_t freq;
328
+
329
+ if (!p->running) {
330
+ return 0;
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
+}
26
+}
351
+
27
+
352
+static uint32_t npcm7xx_pwm_calculate_duty(NPCM7xxPWM *p)
28
/* is_jmp field values */
353
+{
29
#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
354
+ uint64_t duty;
30
/* CPU state was modified dynamically; exit to main loop for interrupts. */
355
+
31
diff --git a/target/arm/translate-vfp.c b/target/arm/translate-vfp.c
356
+ if (p->running) {
357
+ if (p->cnr == 0) {
358
+ duty = 0;
359
+ } else if (p->cmr >= p->cnr) {
360
+ duty = NPCM7XX_PWM_MAX_DUTY;
361
+ } else {
362
+ duty = NPCM7XX_PWM_MAX_DUTY * (p->cmr + 1) / (p->cnr + 1);
363
+ }
364
+ } else {
365
+ duty = 0;
366
+ }
367
+
368
+ if (p->inverted) {
369
+ duty = NPCM7XX_PWM_MAX_DUTY - duty;
370
+ }
371
+
372
+ return duty;
373
+}
374
+
375
+static void npcm7xx_pwm_update_freq(NPCM7xxPWM *p)
376
+{
377
+ uint32_t freq = npcm7xx_pwm_calculate_freq(p);
378
+
379
+ if (freq != p->freq) {
380
+ trace_npcm7xx_pwm_update_freq(DEVICE(p->module)->canonical_path,
381
+ p->index, p->freq, freq);
382
+ p->freq = freq;
383
+ }
384
+}
385
+
386
+static void npcm7xx_pwm_update_duty(NPCM7xxPWM *p)
387
+{
388
+ uint32_t duty = npcm7xx_pwm_calculate_duty(p);
389
+
390
+ if (duty != p->duty) {
391
+ trace_npcm7xx_pwm_update_duty(DEVICE(p->module)->canonical_path,
392
+ p->index, p->duty, duty);
393
+ p->duty = duty;
394
+ }
395
+}
396
+
397
+static void npcm7xx_pwm_update_output(NPCM7xxPWM *p)
398
+{
399
+ npcm7xx_pwm_update_freq(p);
400
+ npcm7xx_pwm_update_duty(p);
401
+}
402
+
403
+static void npcm7xx_pwm_write_ppr(NPCM7xxPWMState *s, uint32_t new_ppr)
404
+{
405
+ int i;
406
+ uint32_t old_ppr = s->ppr;
407
+
408
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_ppr_base) != NPCM7XX_PWM_PER_MODULE);
409
+ s->ppr = new_ppr;
410
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) {
411
+ if (NPCM7XX_PPR(old_ppr, i) != NPCM7XX_PPR(new_ppr, i)) {
412
+ npcm7xx_pwm_update_freq(&s->pwm[i]);
413
+ }
414
+ }
415
+}
416
+
417
+static void npcm7xx_pwm_write_csr(NPCM7xxPWMState *s, uint32_t new_csr)
418
+{
419
+ int i;
420
+ uint32_t old_csr = s->csr;
421
+
422
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_csr_base) != NPCM7XX_PWM_PER_MODULE);
423
+ s->csr = new_csr;
424
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) {
425
+ if (NPCM7XX_CSR(old_csr, i) != NPCM7XX_CSR(new_csr, i)) {
426
+ npcm7xx_pwm_update_freq(&s->pwm[i]);
427
+ }
428
+ }
429
+}
430
+
431
+static void npcm7xx_pwm_write_pcr(NPCM7xxPWMState *s, uint32_t new_pcr)
432
+{
433
+ int i;
434
+ bool inverted;
435
+ uint32_t pcr;
436
+ NPCM7xxPWM *p;
437
+
438
+ s->pcr = new_pcr;
439
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_ch_base) != NPCM7XX_PWM_PER_MODULE);
440
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) {
441
+ p = &s->pwm[i];
442
+ pcr = NPCM7XX_CH(new_pcr, i);
443
+ inverted = pcr & NPCM7XX_CH_INV;
444
+
445
+ /*
446
+ * We only run a PWM channel with toggle mode. Single-shot mode does not
447
+ * generate frequency and duty-cycle values.
448
+ */
449
+ if ((pcr & NPCM7XX_CH_EN) && (pcr & NPCM7XX_CH_MOD)) {
450
+ if (p->running) {
451
+ /* Re-run this PWM channel if inverted changed. */
452
+ if (p->inverted ^ inverted) {
453
+ p->inverted = inverted;
454
+ npcm7xx_pwm_update_duty(p);
455
+ }
456
+ } else {
457
+ /* Run this PWM channel. */
458
+ p->running = true;
459
+ p->inverted = inverted;
460
+ npcm7xx_pwm_update_output(p);
461
+ }
462
+ } else {
463
+ /* Clear this PWM channel. */
464
+ p->running = false;
465
+ p->inverted = inverted;
466
+ npcm7xx_pwm_update_output(p);
467
+ }
468
+ }
469
+
470
+}
471
+
472
+static hwaddr npcm7xx_cnr_index(hwaddr offset)
473
+{
474
+ switch (offset) {
475
+ case A_NPCM7XX_PWM_CNR0:
476
+ return 0;
477
+ case A_NPCM7XX_PWM_CNR1:
478
+ return 1;
479
+ case A_NPCM7XX_PWM_CNR2:
480
+ return 2;
481
+ case A_NPCM7XX_PWM_CNR3:
482
+ return 3;
483
+ default:
484
+ g_assert_not_reached();
485
+ }
486
+}
487
+
488
+static hwaddr npcm7xx_cmr_index(hwaddr offset)
489
+{
490
+ switch (offset) {
491
+ case A_NPCM7XX_PWM_CMR0:
492
+ return 0;
493
+ case A_NPCM7XX_PWM_CMR1:
494
+ return 1;
495
+ case A_NPCM7XX_PWM_CMR2:
496
+ return 2;
497
+ case A_NPCM7XX_PWM_CMR3:
498
+ return 3;
499
+ default:
500
+ g_assert_not_reached();
501
+ }
502
+}
503
+
504
+static hwaddr npcm7xx_pdr_index(hwaddr offset)
505
+{
506
+ switch (offset) {
507
+ case A_NPCM7XX_PWM_PDR0:
508
+ return 0;
509
+ case A_NPCM7XX_PWM_PDR1:
510
+ return 1;
511
+ case A_NPCM7XX_PWM_PDR2:
512
+ return 2;
513
+ case A_NPCM7XX_PWM_PDR3:
514
+ return 3;
515
+ default:
516
+ g_assert_not_reached();
517
+ }
518
+}
519
+
520
+static hwaddr npcm7xx_pwdr_index(hwaddr offset)
521
+{
522
+ switch (offset) {
523
+ case A_NPCM7XX_PWM_PWDR0:
524
+ return 0;
525
+ case A_NPCM7XX_PWM_PWDR1:
526
+ return 1;
527
+ case A_NPCM7XX_PWM_PWDR2:
528
+ return 2;
529
+ case A_NPCM7XX_PWM_PWDR3:
530
+ return 3;
531
+ default:
532
+ g_assert_not_reached();
533
+ }
534
+}
535
+
536
+static uint64_t npcm7xx_pwm_read(void *opaque, hwaddr offset, unsigned size)
537
+{
538
+ NPCM7xxPWMState *s = opaque;
539
+ uint64_t value = 0;
540
+
541
+ switch (offset) {
542
+ case A_NPCM7XX_PWM_CNR0:
543
+ case A_NPCM7XX_PWM_CNR1:
544
+ case A_NPCM7XX_PWM_CNR2:
545
+ case A_NPCM7XX_PWM_CNR3:
546
+ value = s->pwm[npcm7xx_cnr_index(offset)].cnr;
547
+ break;
548
+
549
+ case A_NPCM7XX_PWM_CMR0:
550
+ case A_NPCM7XX_PWM_CMR1:
551
+ case A_NPCM7XX_PWM_CMR2:
552
+ case A_NPCM7XX_PWM_CMR3:
553
+ value = s->pwm[npcm7xx_cmr_index(offset)].cmr;
554
+ break;
555
+
556
+ case A_NPCM7XX_PWM_PDR0:
557
+ case A_NPCM7XX_PWM_PDR1:
558
+ case A_NPCM7XX_PWM_PDR2:
559
+ case A_NPCM7XX_PWM_PDR3:
560
+ value = s->pwm[npcm7xx_pdr_index(offset)].pdr;
561
+ break;
562
+
563
+ case A_NPCM7XX_PWM_PWDR0:
564
+ case A_NPCM7XX_PWM_PWDR1:
565
+ case A_NPCM7XX_PWM_PWDR2:
566
+ case A_NPCM7XX_PWM_PWDR3:
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
32
index XXXXXXX..XXXXXXX 100644
808
--- a/hw/misc/meson.build
33
--- a/target/arm/translate-vfp.c
809
+++ b/hw/misc/meson.build
34
+++ b/target/arm/translate-vfp.c
810
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_MAINSTONE', if_true: files('mst_fpga.c'))
35
@@ -XXX,XX +XXX,XX @@ static bool vfp_access_check_a(DisasContext *s, bool ignore_vfp_enabled)
811
softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files(
36
if (s->sme_trap_nonstreaming) {
812
'npcm7xx_clk.c',
37
gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
813
'npcm7xx_gcr.c',
38
syn_smetrap(SME_ET_Streaming,
814
+ 'npcm7xx_pwm.c',
39
- s->base.pc_next - s->pc_curr == 2));
815
'npcm7xx_rng.c',
40
+ curr_insn_len(s) == 2));
816
))
41
return false;
817
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files(
42
}
818
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
43
44
diff --git a/target/arm/translate.c b/target/arm/translate.c
819
index XXXXXXX..XXXXXXX 100644
45
index XXXXXXX..XXXXXXX 100644
820
--- a/hw/misc/trace-events
46
--- a/target/arm/translate.c
821
+++ b/hw/misc/trace-events
47
+++ b/target/arm/translate.c
822
@@ -XXX,XX +XXX,XX @@ npcm7xx_gcr_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " valu
48
@@ -XXX,XX +XXX,XX @@ static ISSInfo make_issinfo(DisasContext *s, int rd, bool p, bool w)
823
npcm7xx_rng_read(uint64_t offset, uint64_t value, unsigned size) "offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
49
/* ISS not valid if writeback */
824
npcm7xx_rng_write(uint64_t offset, uint64_t value, unsigned size) "offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
50
if (p && !w) {
825
51
ret = rd;
826
+# npcm7xx_pwm.c
52
- if (s->base.pc_next - s->pc_curr == 2) {
827
+npcm7xx_pwm_read(const char *id, uint64_t offset, uint32_t value) "%s offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
53
+ if (curr_insn_len(s) == 2) {
828
+npcm7xx_pwm_write(const char *id, uint64_t offset, uint32_t value) "%s offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
54
ret |= ISSIs16Bit;
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"
55
}
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"
56
} else {
831
+
57
@@ -XXX,XX +XXX,XX @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
832
# stm32f4xx_syscfg.c
58
/* nothing more to generate */
833
stm32f4xx_syscfg_set_irq(int gpio, int line, int level) "Interupt: GPIO: %d, Line: %d; Level: %d"
59
break;
834
stm32f4xx_pulse_exti(int irq) "Pulse EXTI: %d"
60
case DISAS_WFI:
61
- gen_helper_wfi(cpu_env,
62
- tcg_constant_i32(dc->base.pc_next - dc->pc_curr));
63
+ gen_helper_wfi(cpu_env, tcg_constant_i32(curr_insn_len(dc)));
64
/*
65
* The helper doesn't necessarily throw an exception, but we
66
* must go back to the main loop to check for interrupts anyway.
835
--
67
--
836
2.20.1
68
2.25.1
837
69
838
70
diff view generated by jsdifflib
1
From: Roman Bolshakov <r.bolshakov@yadro.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
ui/cocoa.m:1188:44: warning: 'openFile:' is deprecated: first deprecated in macOS 11.0 - Use -[NSWorkspace openURL:] instead.
3
In preparation for TARGET_TB_PCREL, reduce reliance on absolute values.
4
[-Wdeprecated-declarations]
5
if ([[NSWorkspace sharedWorkspace] openFile: full_file_path] == YES) {
6
^
7
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/AppKit.framework/Headers/NSWorkspace.h:350:1: note:
8
'openFile:' has been explicitly marked deprecated here
9
- (BOOL)openFile:(NSString *)fullPath API_DEPRECATED("Use -[NSWorkspace openURL:] instead.", macos(10.0, 11.0));
10
^
11
4
12
Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
13
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
14
Message-id: 20210102150718.47618-1-r.bolshakov@yadro.com
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20221020030641.2066807-3-richard.henderson@linaro.org
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
---
9
---
17
ui/cocoa.m | 5 ++++-
10
target/arm/translate-a64.c | 40 ++++++++++++++++++++------------------
18
1 file changed, 4 insertions(+), 1 deletion(-)
11
target/arm/translate.c | 10 ++++++----
12
2 files changed, 27 insertions(+), 23 deletions(-)
19
13
20
diff --git a/ui/cocoa.m b/ui/cocoa.m
14
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
21
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
22
--- a/ui/cocoa.m
16
--- a/target/arm/translate-a64.c
23
+++ b/ui/cocoa.m
17
+++ b/target/arm/translate-a64.c
24
@@ -XXX,XX +XXX,XX @@ QemuCocoaView *cocoaView;
18
@@ -XXX,XX +XXX,XX @@ static inline bool use_goto_tb(DisasContext *s, uint64_t dest)
25
/* Where to look for local files */
19
return translator_use_goto_tb(&s->base, dest);
26
NSString *path_array[] = {@"../share/doc/qemu/", @"../doc/qemu/", @"docs/"};
20
}
27
NSString *full_file_path;
21
28
+ NSURL *full_file_url;
22
-static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
29
23
+static void gen_goto_tb(DisasContext *s, int n, int64_t diff)
30
/* iterate thru the possible paths until the file is found */
24
{
31
int index;
25
+ uint64_t dest = s->pc_curr + diff;
32
@@ -XXX,XX +XXX,XX @@ QemuCocoaView *cocoaView;
26
+
33
full_file_path = [full_file_path stringByDeletingLastPathComponent];
27
if (use_goto_tb(s, dest)) {
34
full_file_path = [NSString stringWithFormat: @"%@/%@%@", full_file_path,
28
tcg_gen_goto_tb(n);
35
path_array[index], filename];
29
gen_a64_set_pc_im(dest);
36
- if ([[NSWorkspace sharedWorkspace] openFile: full_file_path] == YES) {
30
@@ -XXX,XX +XXX,XX @@ static inline AArch64DecodeFn *lookup_disas_fn(const AArch64DecodeTable *table,
37
+ full_file_url = [NSURL fileURLWithPath: full_file_path
31
*/
38
+ isDirectory: false];
32
static void disas_uncond_b_imm(DisasContext *s, uint32_t insn)
39
+ if ([[NSWorkspace sharedWorkspace] openURL: full_file_url] == YES) {
33
{
40
return;
34
- uint64_t addr = s->pc_curr + sextract32(insn, 0, 26) * 4;
35
+ int64_t diff = sextract32(insn, 0, 26) * 4;
36
37
if (insn & (1U << 31)) {
38
/* BL Branch with link */
39
@@ -XXX,XX +XXX,XX @@ static void disas_uncond_b_imm(DisasContext *s, uint32_t insn)
40
41
/* B Branch / BL Branch with link */
42
reset_btype(s);
43
- gen_goto_tb(s, 0, addr);
44
+ gen_goto_tb(s, 0, diff);
45
}
46
47
/* Compare and branch (immediate)
48
@@ -XXX,XX +XXX,XX @@ static void disas_uncond_b_imm(DisasContext *s, uint32_t insn)
49
static void disas_comp_b_imm(DisasContext *s, uint32_t insn)
50
{
51
unsigned int sf, op, rt;
52
- uint64_t addr;
53
+ int64_t diff;
54
TCGLabel *label_match;
55
TCGv_i64 tcg_cmp;
56
57
sf = extract32(insn, 31, 1);
58
op = extract32(insn, 24, 1); /* 0: CBZ; 1: CBNZ */
59
rt = extract32(insn, 0, 5);
60
- addr = s->pc_curr + sextract32(insn, 5, 19) * 4;
61
+ diff = sextract32(insn, 5, 19) * 4;
62
63
tcg_cmp = read_cpu_reg(s, rt, sf);
64
label_match = gen_new_label();
65
@@ -XXX,XX +XXX,XX @@ static void disas_comp_b_imm(DisasContext *s, uint32_t insn)
66
tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ,
67
tcg_cmp, 0, label_match);
68
69
- gen_goto_tb(s, 0, s->base.pc_next);
70
+ gen_goto_tb(s, 0, 4);
71
gen_set_label(label_match);
72
- gen_goto_tb(s, 1, addr);
73
+ gen_goto_tb(s, 1, diff);
74
}
75
76
/* Test and branch (immediate)
77
@@ -XXX,XX +XXX,XX @@ static void disas_comp_b_imm(DisasContext *s, uint32_t insn)
78
static void disas_test_b_imm(DisasContext *s, uint32_t insn)
79
{
80
unsigned int bit_pos, op, rt;
81
- uint64_t addr;
82
+ int64_t diff;
83
TCGLabel *label_match;
84
TCGv_i64 tcg_cmp;
85
86
bit_pos = (extract32(insn, 31, 1) << 5) | extract32(insn, 19, 5);
87
op = extract32(insn, 24, 1); /* 0: TBZ; 1: TBNZ */
88
- addr = s->pc_curr + sextract32(insn, 5, 14) * 4;
89
+ diff = sextract32(insn, 5, 14) * 4;
90
rt = extract32(insn, 0, 5);
91
92
tcg_cmp = tcg_temp_new_i64();
93
@@ -XXX,XX +XXX,XX @@ static void disas_test_b_imm(DisasContext *s, uint32_t insn)
94
tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ,
95
tcg_cmp, 0, label_match);
96
tcg_temp_free_i64(tcg_cmp);
97
- gen_goto_tb(s, 0, s->base.pc_next);
98
+ gen_goto_tb(s, 0, 4);
99
gen_set_label(label_match);
100
- gen_goto_tb(s, 1, addr);
101
+ gen_goto_tb(s, 1, diff);
102
}
103
104
/* Conditional branch (immediate)
105
@@ -XXX,XX +XXX,XX @@ static void disas_test_b_imm(DisasContext *s, uint32_t insn)
106
static void disas_cond_b_imm(DisasContext *s, uint32_t insn)
107
{
108
unsigned int cond;
109
- uint64_t addr;
110
+ int64_t diff;
111
112
if ((insn & (1 << 4)) || (insn & (1 << 24))) {
113
unallocated_encoding(s);
114
return;
115
}
116
- addr = s->pc_curr + sextract32(insn, 5, 19) * 4;
117
+ diff = sextract32(insn, 5, 19) * 4;
118
cond = extract32(insn, 0, 4);
119
120
reset_btype(s);
121
@@ -XXX,XX +XXX,XX @@ static void disas_cond_b_imm(DisasContext *s, uint32_t insn)
122
/* genuinely conditional branches */
123
TCGLabel *label_match = gen_new_label();
124
arm_gen_test_cc(cond, label_match);
125
- gen_goto_tb(s, 0, s->base.pc_next);
126
+ gen_goto_tb(s, 0, 4);
127
gen_set_label(label_match);
128
- gen_goto_tb(s, 1, addr);
129
+ gen_goto_tb(s, 1, diff);
130
} else {
131
/* 0xe and 0xf are both "always" conditions */
132
- gen_goto_tb(s, 0, addr);
133
+ gen_goto_tb(s, 0, diff);
134
}
135
}
136
137
@@ -XXX,XX +XXX,XX @@ static void handle_sync(DisasContext *s, uint32_t insn,
138
* any pending interrupts immediately.
139
*/
140
reset_btype(s);
141
- gen_goto_tb(s, 0, s->base.pc_next);
142
+ gen_goto_tb(s, 0, 4);
143
return;
144
145
case 7: /* SB */
146
@@ -XXX,XX +XXX,XX @@ static void handle_sync(DisasContext *s, uint32_t insn,
147
* MB and end the TB instead.
148
*/
149
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
150
- gen_goto_tb(s, 0, s->base.pc_next);
151
+ gen_goto_tb(s, 0, 4);
152
return;
153
154
default:
155
@@ -XXX,XX +XXX,XX @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
156
switch (dc->base.is_jmp) {
157
case DISAS_NEXT:
158
case DISAS_TOO_MANY:
159
- gen_goto_tb(dc, 1, dc->base.pc_next);
160
+ gen_goto_tb(dc, 1, 4);
161
break;
162
default:
163
case DISAS_UPDATE_EXIT:
164
diff --git a/target/arm/translate.c b/target/arm/translate.c
165
index XXXXXXX..XXXXXXX 100644
166
--- a/target/arm/translate.c
167
+++ b/target/arm/translate.c
168
@@ -XXX,XX +XXX,XX @@ static void gen_goto_ptr(void)
169
* cpu_loop_exec. Any live exit_requests will be processed as we
170
* enter the next TB.
171
*/
172
-static void gen_goto_tb(DisasContext *s, int n, target_ulong dest)
173
+static void gen_goto_tb(DisasContext *s, int n, int diff)
174
{
175
+ target_ulong dest = s->pc_curr + diff;
176
+
177
if (translator_use_goto_tb(&s->base, dest)) {
178
tcg_gen_goto_tb(n);
179
gen_set_pc_im(s, dest);
180
@@ -XXX,XX +XXX,XX @@ static inline void gen_jmp_tb(DisasContext *s, uint32_t dest, int tbno)
181
* gen_jmp();
182
* on the second call to gen_jmp().
183
*/
184
- gen_goto_tb(s, tbno, dest);
185
+ gen_goto_tb(s, tbno, dest - s->pc_curr);
186
break;
187
case DISAS_UPDATE_NOCHAIN:
188
case DISAS_UPDATE_EXIT:
189
@@ -XXX,XX +XXX,XX @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
190
switch (dc->base.is_jmp) {
191
case DISAS_NEXT:
192
case DISAS_TOO_MANY:
193
- gen_goto_tb(dc, 1, dc->base.pc_next);
194
+ gen_goto_tb(dc, 1, curr_insn_len(dc));
195
break;
196
case DISAS_UPDATE_NOCHAIN:
197
gen_set_pc_im(dc, dc->base.pc_next);
198
@@ -XXX,XX +XXX,XX @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
199
gen_set_pc_im(dc, dc->base.pc_next);
200
gen_singlestep_exception(dc);
201
} else {
202
- gen_goto_tb(dc, 1, dc->base.pc_next);
203
+ gen_goto_tb(dc, 1, curr_insn_len(dc));
41
}
204
}
42
}
205
}
206
}
43
--
207
--
44
2.20.1
208
2.25.1
45
46
diff view generated by jsdifflib
1
From: Leif Lindholm <leif@nuviainc.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
The AArch64 view of CLIDR_EL1 extends the ICB field to include also bit
3
In preparation for TARGET_TB_PCREL, reduce reliance on
4
32, as well as adding a Ttype<n> field when FEAT_MTE is implemented.
4
absolute values by passing in pc difference.
5
Extend the clidr field to be able to hold this context.
6
5
7
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
10
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
8
Message-id: 20221020030641.2066807-4-richard.henderson@linaro.org
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>
13
---
10
---
14
target/arm/cpu.h | 2 +-
11
target/arm/translate-a32.h | 2 +-
15
1 file changed, 1 insertion(+), 1 deletion(-)
12
target/arm/translate.h | 6 ++--
13
target/arm/translate-a64.c | 32 +++++++++---------
14
target/arm/translate-vfp.c | 2 +-
15
target/arm/translate.c | 68 ++++++++++++++++++++------------------
16
5 files changed, 56 insertions(+), 54 deletions(-)
16
17
17
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
18
diff --git a/target/arm/translate-a32.h b/target/arm/translate-a32.h
18
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/cpu.h
20
--- a/target/arm/translate-a32.h
20
+++ b/target/arm/cpu.h
21
+++ b/target/arm/translate-a32.h
21
@@ -XXX,XX +XXX,XX @@ struct ARMCPU {
22
@@ -XXX,XX +XXX,XX @@ void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop);
22
uint32_t id_afr0;
23
TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs);
23
uint64_t id_aa64afr0;
24
void gen_set_cpsr(TCGv_i32 var, uint32_t mask);
24
uint64_t id_aa64afr1;
25
void gen_set_condexec(DisasContext *s);
25
- uint32_t clidr;
26
-void gen_set_pc_im(DisasContext *s, target_ulong val);
26
+ uint64_t clidr;
27
+void gen_update_pc(DisasContext *s, target_long diff);
27
uint64_t mp_affinity; /* MP ID without feature bits */
28
void gen_lookup_tb(DisasContext *s);
28
/* The elements of this array are the CCSIDR values for each cache,
29
long vfp_reg_offset(bool dp, unsigned reg);
29
* in the order L1DCache, L1ICache, L2DCache, L2ICache, etc.
30
long neon_full_reg_offset(unsigned reg);
31
diff --git a/target/arm/translate.h b/target/arm/translate.h
32
index XXXXXXX..XXXXXXX 100644
33
--- a/target/arm/translate.h
34
+++ b/target/arm/translate.h
35
@@ -XXX,XX +XXX,XX @@ static inline int curr_insn_len(DisasContext *s)
36
* For instructions which want an immediate exit to the main loop, as opposed
37
* to attempting to use lookup_and_goto_ptr. Unlike DISAS_UPDATE_EXIT, this
38
* doesn't write the PC on exiting the translation loop so you need to ensure
39
- * something (gen_a64_set_pc_im or runtime helper) has done so before we reach
40
+ * something (gen_a64_update_pc or runtime helper) has done so before we reach
41
* return from cpu_tb_exec.
42
*/
43
#define DISAS_EXIT DISAS_TARGET_9
44
@@ -XXX,XX +XXX,XX @@ static inline int curr_insn_len(DisasContext *s)
45
46
#ifdef TARGET_AARCH64
47
void a64_translate_init(void);
48
-void gen_a64_set_pc_im(uint64_t val);
49
+void gen_a64_update_pc(DisasContext *s, target_long diff);
50
extern const TranslatorOps aarch64_translator_ops;
51
#else
52
static inline void a64_translate_init(void)
53
{
54
}
55
56
-static inline void gen_a64_set_pc_im(uint64_t val)
57
+static inline void gen_a64_update_pc(DisasContext *s, target_long diff)
58
{
59
}
60
#endif
61
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
62
index XXXXXXX..XXXXXXX 100644
63
--- a/target/arm/translate-a64.c
64
+++ b/target/arm/translate-a64.c
65
@@ -XXX,XX +XXX,XX @@ static void reset_btype(DisasContext *s)
66
}
67
}
68
69
-void gen_a64_set_pc_im(uint64_t val)
70
+void gen_a64_update_pc(DisasContext *s, target_long diff)
71
{
72
- tcg_gen_movi_i64(cpu_pc, val);
73
+ tcg_gen_movi_i64(cpu_pc, s->pc_curr + diff);
74
}
75
76
/*
77
@@ -XXX,XX +XXX,XX @@ static void gen_exception_internal(int excp)
78
79
static void gen_exception_internal_insn(DisasContext *s, uint64_t pc, int excp)
80
{
81
- gen_a64_set_pc_im(pc);
82
+ gen_a64_update_pc(s, pc - s->pc_curr);
83
gen_exception_internal(excp);
84
s->base.is_jmp = DISAS_NORETURN;
85
}
86
87
static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syndrome)
88
{
89
- gen_a64_set_pc_im(s->pc_curr);
90
+ gen_a64_update_pc(s, 0);
91
gen_helper_exception_bkpt_insn(cpu_env, tcg_constant_i32(syndrome));
92
s->base.is_jmp = DISAS_NORETURN;
93
}
94
@@ -XXX,XX +XXX,XX @@ static void gen_goto_tb(DisasContext *s, int n, int64_t diff)
95
96
if (use_goto_tb(s, dest)) {
97
tcg_gen_goto_tb(n);
98
- gen_a64_set_pc_im(dest);
99
+ gen_a64_update_pc(s, diff);
100
tcg_gen_exit_tb(s->base.tb, n);
101
s->base.is_jmp = DISAS_NORETURN;
102
} else {
103
- gen_a64_set_pc_im(dest);
104
+ gen_a64_update_pc(s, diff);
105
if (s->ss_active) {
106
gen_step_complete_exception(s);
107
} else {
108
@@ -XXX,XX +XXX,XX @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
109
uint32_t syndrome;
110
111
syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread);
112
- gen_a64_set_pc_im(s->pc_curr);
113
+ gen_a64_update_pc(s, 0);
114
gen_helper_access_check_cp_reg(cpu_env,
115
tcg_constant_ptr(ri),
116
tcg_constant_i32(syndrome),
117
@@ -XXX,XX +XXX,XX @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
118
* The readfn or writefn might raise an exception;
119
* synchronize the CPU state in case it does.
120
*/
121
- gen_a64_set_pc_im(s->pc_curr);
122
+ gen_a64_update_pc(s, 0);
123
}
124
125
/* Handle special cases first */
126
@@ -XXX,XX +XXX,XX @@ static void disas_exc(DisasContext *s, uint32_t insn)
127
/* The pre HVC helper handles cases when HVC gets trapped
128
* as an undefined insn by runtime configuration.
129
*/
130
- gen_a64_set_pc_im(s->pc_curr);
131
+ gen_a64_update_pc(s, 0);
132
gen_helper_pre_hvc(cpu_env);
133
gen_ss_advance(s);
134
gen_exception_insn_el(s, s->base.pc_next, EXCP_HVC,
135
@@ -XXX,XX +XXX,XX @@ static void disas_exc(DisasContext *s, uint32_t insn)
136
unallocated_encoding(s);
137
break;
138
}
139
- gen_a64_set_pc_im(s->pc_curr);
140
+ gen_a64_update_pc(s, 0);
141
gen_helper_pre_smc(cpu_env, tcg_constant_i32(syn_aa64_smc(imm16)));
142
gen_ss_advance(s);
143
gen_exception_insn_el(s, s->base.pc_next, EXCP_SMC,
144
@@ -XXX,XX +XXX,XX @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
145
*/
146
switch (dc->base.is_jmp) {
147
default:
148
- gen_a64_set_pc_im(dc->base.pc_next);
149
+ gen_a64_update_pc(dc, 4);
150
/* fall through */
151
case DISAS_EXIT:
152
case DISAS_JUMP:
153
@@ -XXX,XX +XXX,XX @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
154
break;
155
default:
156
case DISAS_UPDATE_EXIT:
157
- gen_a64_set_pc_im(dc->base.pc_next);
158
+ gen_a64_update_pc(dc, 4);
159
/* fall through */
160
case DISAS_EXIT:
161
tcg_gen_exit_tb(NULL, 0);
162
break;
163
case DISAS_UPDATE_NOCHAIN:
164
- gen_a64_set_pc_im(dc->base.pc_next);
165
+ gen_a64_update_pc(dc, 4);
166
/* fall through */
167
case DISAS_JUMP:
168
tcg_gen_lookup_and_goto_ptr();
169
@@ -XXX,XX +XXX,XX @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
170
case DISAS_SWI:
171
break;
172
case DISAS_WFE:
173
- gen_a64_set_pc_im(dc->base.pc_next);
174
+ gen_a64_update_pc(dc, 4);
175
gen_helper_wfe(cpu_env);
176
break;
177
case DISAS_YIELD:
178
- gen_a64_set_pc_im(dc->base.pc_next);
179
+ gen_a64_update_pc(dc, 4);
180
gen_helper_yield(cpu_env);
181
break;
182
case DISAS_WFI:
183
@@ -XXX,XX +XXX,XX @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
184
* This is a special case because we don't want to just halt
185
* the CPU if trying to debug across a WFI.
186
*/
187
- gen_a64_set_pc_im(dc->base.pc_next);
188
+ gen_a64_update_pc(dc, 4);
189
gen_helper_wfi(cpu_env, tcg_constant_i32(4));
190
/*
191
* The helper doesn't necessarily throw an exception, but we
192
diff --git a/target/arm/translate-vfp.c b/target/arm/translate-vfp.c
193
index XXXXXXX..XXXXXXX 100644
194
--- a/target/arm/translate-vfp.c
195
+++ b/target/arm/translate-vfp.c
196
@@ -XXX,XX +XXX,XX @@ static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a)
197
case ARM_VFP_FPSID:
198
if (s->current_el == 1) {
199
gen_set_condexec(s);
200
- gen_set_pc_im(s, s->pc_curr);
201
+ gen_update_pc(s, 0);
202
gen_helper_check_hcr_el2_trap(cpu_env,
203
tcg_constant_i32(a->rt),
204
tcg_constant_i32(a->reg));
205
diff --git a/target/arm/translate.c b/target/arm/translate.c
206
index XXXXXXX..XXXXXXX 100644
207
--- a/target/arm/translate.c
208
+++ b/target/arm/translate.c
209
@@ -XXX,XX +XXX,XX @@ void gen_set_condexec(DisasContext *s)
210
}
211
}
212
213
-void gen_set_pc_im(DisasContext *s, target_ulong val)
214
+void gen_update_pc(DisasContext *s, target_long diff)
215
{
216
- tcg_gen_movi_i32(cpu_R[15], val);
217
+ tcg_gen_movi_i32(cpu_R[15], s->pc_curr + diff);
218
}
219
220
/* Set PC and Thumb state from var. var is marked as dead. */
221
@@ -XXX,XX +XXX,XX @@ static inline void gen_bxns(DisasContext *s, int rm)
222
223
/* The bxns helper may raise an EXCEPTION_EXIT exception, so in theory
224
* we need to sync state before calling it, but:
225
- * - we don't need to do gen_set_pc_im() because the bxns helper will
226
+ * - we don't need to do gen_update_pc() because the bxns helper will
227
* always set the PC itself
228
* - we don't need to do gen_set_condexec() because BXNS is UNPREDICTABLE
229
* unless it's outside an IT block or the last insn in an IT block,
230
@@ -XXX,XX +XXX,XX @@ static inline void gen_blxns(DisasContext *s, int rm)
231
* We do however need to set the PC, because the blxns helper reads it.
232
* The blxns helper may throw an exception.
233
*/
234
- gen_set_pc_im(s, s->base.pc_next);
235
+ gen_update_pc(s, curr_insn_len(s));
236
gen_helper_v7m_blxns(cpu_env, var);
237
tcg_temp_free_i32(var);
238
s->base.is_jmp = DISAS_EXIT;
239
@@ -XXX,XX +XXX,XX @@ static inline void gen_hvc(DisasContext *s, int imm16)
240
* as an undefined insn by runtime configuration (ie before
241
* the insn really executes).
242
*/
243
- gen_set_pc_im(s, s->pc_curr);
244
+ gen_update_pc(s, 0);
245
gen_helper_pre_hvc(cpu_env);
246
/* Otherwise we will treat this as a real exception which
247
* happens after execution of the insn. (The distinction matters
248
@@ -XXX,XX +XXX,XX @@ static inline void gen_hvc(DisasContext *s, int imm16)
249
* for single stepping.)
250
*/
251
s->svc_imm = imm16;
252
- gen_set_pc_im(s, s->base.pc_next);
253
+ gen_update_pc(s, curr_insn_len(s));
254
s->base.is_jmp = DISAS_HVC;
255
}
256
257
@@ -XXX,XX +XXX,XX @@ static inline void gen_smc(DisasContext *s)
258
/* As with HVC, we may take an exception either before or after
259
* the insn executes.
260
*/
261
- gen_set_pc_im(s, s->pc_curr);
262
+ gen_update_pc(s, 0);
263
gen_helper_pre_smc(cpu_env, tcg_constant_i32(syn_aa32_smc()));
264
- gen_set_pc_im(s, s->base.pc_next);
265
+ gen_update_pc(s, curr_insn_len(s));
266
s->base.is_jmp = DISAS_SMC;
267
}
268
269
static void gen_exception_internal_insn(DisasContext *s, uint32_t pc, int excp)
270
{
271
gen_set_condexec(s);
272
- gen_set_pc_im(s, pc);
273
+ gen_update_pc(s, pc - s->pc_curr);
274
gen_exception_internal(excp);
275
s->base.is_jmp = DISAS_NORETURN;
276
}
277
@@ -XXX,XX +XXX,XX @@ static void gen_exception_insn_el_v(DisasContext *s, uint64_t pc, int excp,
278
uint32_t syn, TCGv_i32 tcg_el)
279
{
280
if (s->aarch64) {
281
- gen_a64_set_pc_im(pc);
282
+ gen_a64_update_pc(s, pc - s->pc_curr);
283
} else {
284
gen_set_condexec(s);
285
- gen_set_pc_im(s, pc);
286
+ gen_update_pc(s, pc - s->pc_curr);
287
}
288
gen_exception_el_v(excp, syn, tcg_el);
289
s->base.is_jmp = DISAS_NORETURN;
290
@@ -XXX,XX +XXX,XX @@ void gen_exception_insn_el(DisasContext *s, uint64_t pc, int excp,
291
void gen_exception_insn(DisasContext *s, uint64_t pc, int excp, uint32_t syn)
292
{
293
if (s->aarch64) {
294
- gen_a64_set_pc_im(pc);
295
+ gen_a64_update_pc(s, pc - s->pc_curr);
296
} else {
297
gen_set_condexec(s);
298
- gen_set_pc_im(s, pc);
299
+ gen_update_pc(s, pc - s->pc_curr);
300
}
301
gen_exception(excp, syn);
302
s->base.is_jmp = DISAS_NORETURN;
303
@@ -XXX,XX +XXX,XX @@ void gen_exception_insn(DisasContext *s, uint64_t pc, int excp, uint32_t syn)
304
static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syn)
305
{
306
gen_set_condexec(s);
307
- gen_set_pc_im(s, s->pc_curr);
308
+ gen_update_pc(s, 0);
309
gen_helper_exception_bkpt_insn(cpu_env, tcg_constant_i32(syn));
310
s->base.is_jmp = DISAS_NORETURN;
311
}
312
@@ -XXX,XX +XXX,XX @@ static void gen_goto_tb(DisasContext *s, int n, int diff)
313
314
if (translator_use_goto_tb(&s->base, dest)) {
315
tcg_gen_goto_tb(n);
316
- gen_set_pc_im(s, dest);
317
+ gen_update_pc(s, diff);
318
tcg_gen_exit_tb(s->base.tb, n);
319
} else {
320
- gen_set_pc_im(s, dest);
321
+ gen_update_pc(s, diff);
322
gen_goto_ptr();
323
}
324
s->base.is_jmp = DISAS_NORETURN;
325
@@ -XXX,XX +XXX,XX @@ static void gen_goto_tb(DisasContext *s, int n, int diff)
326
/* Jump, specifying which TB number to use if we gen_goto_tb() */
327
static inline void gen_jmp_tb(DisasContext *s, uint32_t dest, int tbno)
328
{
329
+ int diff = dest - s->pc_curr;
330
+
331
if (unlikely(s->ss_active)) {
332
/* An indirect jump so that we still trigger the debug exception. */
333
- gen_set_pc_im(s, dest);
334
+ gen_update_pc(s, diff);
335
s->base.is_jmp = DISAS_JUMP;
336
return;
337
}
338
@@ -XXX,XX +XXX,XX @@ static inline void gen_jmp_tb(DisasContext *s, uint32_t dest, int tbno)
339
* gen_jmp();
340
* on the second call to gen_jmp().
341
*/
342
- gen_goto_tb(s, tbno, dest - s->pc_curr);
343
+ gen_goto_tb(s, tbno, diff);
344
break;
345
case DISAS_UPDATE_NOCHAIN:
346
case DISAS_UPDATE_EXIT:
347
@@ -XXX,XX +XXX,XX @@ static inline void gen_jmp_tb(DisasContext *s, uint32_t dest, int tbno)
348
* Avoid using goto_tb so we really do exit back to the main loop
349
* and don't chain to another TB.
350
*/
351
- gen_set_pc_im(s, dest);
352
+ gen_update_pc(s, diff);
353
gen_goto_ptr();
354
s->base.is_jmp = DISAS_NORETURN;
355
break;
356
@@ -XXX,XX +XXX,XX @@ static void gen_msr_banked(DisasContext *s, int r, int sysm, int rn)
357
358
/* Sync state because msr_banked() can raise exceptions */
359
gen_set_condexec(s);
360
- gen_set_pc_im(s, s->pc_curr);
361
+ gen_update_pc(s, 0);
362
tcg_reg = load_reg(s, rn);
363
gen_helper_msr_banked(cpu_env, tcg_reg,
364
tcg_constant_i32(tgtmode),
365
@@ -XXX,XX +XXX,XX @@ static void gen_mrs_banked(DisasContext *s, int r, int sysm, int rn)
366
367
/* Sync state because mrs_banked() can raise exceptions */
368
gen_set_condexec(s);
369
- gen_set_pc_im(s, s->pc_curr);
370
+ gen_update_pc(s, 0);
371
tcg_reg = tcg_temp_new_i32();
372
gen_helper_mrs_banked(tcg_reg, cpu_env,
373
tcg_constant_i32(tgtmode),
374
@@ -XXX,XX +XXX,XX @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
375
}
376
377
gen_set_condexec(s);
378
- gen_set_pc_im(s, s->pc_curr);
379
+ gen_update_pc(s, 0);
380
gen_helper_access_check_cp_reg(cpu_env,
381
tcg_constant_ptr(ri),
382
tcg_constant_i32(syndrome),
383
@@ -XXX,XX +XXX,XX @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
384
* synchronize the CPU state in case it does.
385
*/
386
gen_set_condexec(s);
387
- gen_set_pc_im(s, s->pc_curr);
388
+ gen_update_pc(s, 0);
389
}
390
391
/* Handle special cases first */
392
@@ -XXX,XX +XXX,XX @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
393
unallocated_encoding(s);
394
return;
395
}
396
- gen_set_pc_im(s, s->base.pc_next);
397
+ gen_update_pc(s, curr_insn_len(s));
398
s->base.is_jmp = DISAS_WFI;
399
return;
400
default:
401
@@ -XXX,XX +XXX,XX @@ static void gen_srs(DisasContext *s,
402
addr = tcg_temp_new_i32();
403
/* get_r13_banked() will raise an exception if called from System mode */
404
gen_set_condexec(s);
405
- gen_set_pc_im(s, s->pc_curr);
406
+ gen_update_pc(s, 0);
407
gen_helper_get_r13_banked(addr, cpu_env, tcg_constant_i32(mode));
408
switch (amode) {
409
case 0: /* DA */
410
@@ -XXX,XX +XXX,XX @@ static bool trans_YIELD(DisasContext *s, arg_YIELD *a)
411
* scheduling of other vCPUs.
412
*/
413
if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
414
- gen_set_pc_im(s, s->base.pc_next);
415
+ gen_update_pc(s, curr_insn_len(s));
416
s->base.is_jmp = DISAS_YIELD;
417
}
418
return true;
419
@@ -XXX,XX +XXX,XX @@ static bool trans_WFE(DisasContext *s, arg_WFE *a)
420
* implemented so we can't sleep like WFI does.
421
*/
422
if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
423
- gen_set_pc_im(s, s->base.pc_next);
424
+ gen_update_pc(s, curr_insn_len(s));
425
s->base.is_jmp = DISAS_WFE;
426
}
427
return true;
428
@@ -XXX,XX +XXX,XX @@ static bool trans_WFE(DisasContext *s, arg_WFE *a)
429
static bool trans_WFI(DisasContext *s, arg_WFI *a)
430
{
431
/* For WFI, halt the vCPU until an IRQ. */
432
- gen_set_pc_im(s, s->base.pc_next);
433
+ gen_update_pc(s, curr_insn_len(s));
434
s->base.is_jmp = DISAS_WFI;
435
return true;
436
}
437
@@ -XXX,XX +XXX,XX @@ static bool trans_SVC(DisasContext *s, arg_SVC *a)
438
(a->imm == semihost_imm)) {
439
gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST);
440
} else {
441
- gen_set_pc_im(s, s->base.pc_next);
442
+ gen_update_pc(s, curr_insn_len(s));
443
s->svc_imm = a->imm;
444
s->base.is_jmp = DISAS_SWI;
445
}
446
@@ -XXX,XX +XXX,XX @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
447
case DISAS_TOO_MANY:
448
case DISAS_UPDATE_EXIT:
449
case DISAS_UPDATE_NOCHAIN:
450
- gen_set_pc_im(dc, dc->base.pc_next);
451
+ gen_update_pc(dc, curr_insn_len(dc));
452
/* fall through */
453
default:
454
/* FIXME: Single stepping a WFI insn will not halt the CPU. */
455
@@ -XXX,XX +XXX,XX @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
456
gen_goto_tb(dc, 1, curr_insn_len(dc));
457
break;
458
case DISAS_UPDATE_NOCHAIN:
459
- gen_set_pc_im(dc, dc->base.pc_next);
460
+ gen_update_pc(dc, curr_insn_len(dc));
461
/* fall through */
462
case DISAS_JUMP:
463
gen_goto_ptr();
464
break;
465
case DISAS_UPDATE_EXIT:
466
- gen_set_pc_im(dc, dc->base.pc_next);
467
+ gen_update_pc(dc, curr_insn_len(dc));
468
/* fall through */
469
default:
470
/* indicate that the hash table must be used to find the next TB */
471
@@ -XXX,XX +XXX,XX @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
472
gen_set_label(dc->condlabel);
473
gen_set_condexec(dc);
474
if (unlikely(dc->ss_active)) {
475
- gen_set_pc_im(dc, dc->base.pc_next);
476
+ gen_update_pc(dc, curr_insn_len(dc));
477
gen_singlestep_exception(dc);
478
} else {
479
gen_goto_tb(dc, 1, curr_insn_len(dc));
30
--
480
--
31
2.20.1
481
2.25.1
32
482
33
483
diff view generated by jsdifflib
1
When we first converted our documentation to Sphinx, we split it into
1
From: Richard Henderson <richard.henderson@linaro.org>
2
multiple manuals (system, interop, tools, etc), which are all built
2
3
separately. The primary driver for this was wanting to be able to
3
In preparation for TARGET_TB_PCREL, reduce reliance on absolute values.
4
avoid shipping the 'devel' manual to end-users. However, this is
4
5
working against the grain of the way Sphinx wants to be used and
5
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
causes some annoyances:
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
* Cross-references between documents become much harder or
7
Message-id: 20221020030641.2066807-5-richard.henderson@linaro.org
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
37
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
38
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
39
Message-id: 20210108161416.21129-3-peter.maydell@linaro.org
40
---
9
---
41
docs/conf.py | 46 ++++++++++++++++++++++++++++++-
10
target/arm/translate.h | 5 +++--
42
docs/devel/conf.py | 15 -----------
11
target/arm/translate-a64.c | 28 ++++++++++-------------
43
docs/index.html.in | 17 ------------
12
target/arm/translate-m-nocp.c | 6 ++---
44
docs/interop/conf.py | 28 -------------------
13
target/arm/translate-mve.c | 2 +-
45
docs/meson.build | 64 +++++++++++++++++---------------------------
14
target/arm/translate-vfp.c | 6 ++---
46
docs/specs/conf.py | 16 -----------
15
target/arm/translate.c | 42 +++++++++++++++++------------------
47
docs/system/conf.py | 28 -------------------
16
6 files changed, 43 insertions(+), 46 deletions(-)
48
docs/tools/conf.py | 37 -------------------------
17
49
docs/user/conf.py | 15 -----------
18
diff --git a/target/arm/translate.h b/target/arm/translate.h
50
9 files changed, 70 insertions(+), 196 deletions(-)
19
index XXXXXXX..XXXXXXX 100644
51
delete mode 100644 docs/devel/conf.py
20
--- a/target/arm/translate.h
52
delete mode 100644 docs/index.html.in
21
+++ b/target/arm/translate.h
53
delete mode 100644 docs/interop/conf.py
22
@@ -XXX,XX +XXX,XX @@ void arm_jump_cc(DisasCompare *cmp, TCGLabel *label);
54
delete mode 100644 docs/specs/conf.py
23
void arm_gen_test_cc(int cc, TCGLabel *label);
55
delete mode 100644 docs/system/conf.py
24
MemOp pow2_align(unsigned i);
56
delete mode 100644 docs/tools/conf.py
25
void unallocated_encoding(DisasContext *s);
57
delete mode 100644 docs/user/conf.py
26
-void gen_exception_insn_el(DisasContext *s, uint64_t pc, int excp,
58
27
+void gen_exception_insn_el(DisasContext *s, target_long pc_diff, int excp,
59
diff --git a/docs/conf.py b/docs/conf.py
28
uint32_t syn, uint32_t target_el);
60
index XXXXXXX..XXXXXXX 100644
29
-void gen_exception_insn(DisasContext *s, uint64_t pc, int excp, uint32_t syn);
61
--- a/docs/conf.py
30
+void gen_exception_insn(DisasContext *s, target_long pc_diff,
62
+++ b/docs/conf.py
31
+ int excp, uint32_t syn);
63
@@ -XXX,XX +XXX,XX @@ latex_documents = [
32
64
33
/* Return state of Alternate Half-precision flag, caller frees result */
65
# -- Options for manual page output ---------------------------------------
34
static inline TCGv_i32 get_ahp_flag(void)
66
# Individual manual/conf.py can override this to create man pages
35
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
67
-man_pages = []
36
index XXXXXXX..XXXXXXX 100644
68
+man_pages = [
37
--- a/target/arm/translate-a64.c
69
+ ('interop/qemu-ga', 'qemu-ga',
38
+++ b/target/arm/translate-a64.c
70
+ 'QEMU Guest Agent',
39
@@ -XXX,XX +XXX,XX @@ static bool fp_access_check_only(DisasContext *s)
71
+ ['Michael Roth <mdroth@linux.vnet.ibm.com>'], 8),
40
assert(!s->fp_access_checked);
72
+ ('interop/qemu-ga-ref', 'qemu-ga-ref',
41
s->fp_access_checked = true;
73
+ 'QEMU Guest Agent Protocol Reference',
42
74
+ [], 7),
43
- gen_exception_insn_el(s, s->pc_curr, EXCP_UDEF,
75
+ ('interop/qemu-qmp-ref', 'qemu-qmp-ref',
44
+ gen_exception_insn_el(s, 0, EXCP_UDEF,
76
+ 'QEMU QMP Reference Manual',
45
syn_fp_access_trap(1, 0xe, false, 0),
77
+ [], 7),
46
s->fp_excp_el);
78
+ ('interop/qemu-storage-daemon-qmp-ref', 'qemu-storage-daemon-qmp-ref',
47
return false;
79
+ 'QEMU Storage Daemon QMP Reference Manual',
48
@@ -XXX,XX +XXX,XX @@ static bool fp_access_check(DisasContext *s)
80
+ [], 7),
49
return false;
81
+ ('system/qemu-manpage', 'qemu',
50
}
82
+ 'QEMU User Documentation',
51
if (s->sme_trap_nonstreaming && s->is_nonstreaming) {
83
+ ['Fabrice Bellard'], 1),
52
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
84
+ ('system/qemu-block-drivers', 'qemu-block-drivers',
53
+ gen_exception_insn(s, 0, EXCP_UDEF,
85
+ 'QEMU block drivers reference',
54
syn_smetrap(SME_ET_Streaming, false));
86
+ ['Fabrice Bellard and the QEMU Project developers'], 7),
55
return false;
87
+ ('system/qemu-cpu-models', 'qemu-cpu-models',
56
}
88
+ 'QEMU CPU Models',
57
@@ -XXX,XX +XXX,XX @@ bool sve_access_check(DisasContext *s)
89
+ ['The QEMU Project developers'], 7),
58
goto fail_exit;
90
+ ('tools/qemu-img', 'qemu-img',
59
}
91
+ 'QEMU disk image utility',
60
} else if (s->sve_excp_el) {
92
+ ['Fabrice Bellard'], 1),
61
- gen_exception_insn_el(s, s->pc_curr, EXCP_UDEF,
93
+ ('tools/qemu-nbd', 'qemu-nbd',
62
+ gen_exception_insn_el(s, 0, EXCP_UDEF,
94
+ 'QEMU Disk Network Block Device Server',
63
syn_sve_access_trap(), s->sve_excp_el);
95
+ ['Anthony Liguori <anthony@codemonkey.ws>'], 8),
64
goto fail_exit;
96
+ ('tools/qemu-pr-helper', 'qemu-pr-helper',
65
}
97
+ 'QEMU persistent reservation helper',
66
@@ -XXX,XX +XXX,XX @@ bool sve_access_check(DisasContext *s)
98
+ [], 8),
67
static bool sme_access_check(DisasContext *s)
99
+ ('tools/qemu-storage-daemon', 'qemu-storage-daemon',
68
{
100
+ 'QEMU storage daemon',
69
if (s->sme_excp_el) {
101
+ [], 1),
70
- gen_exception_insn_el(s, s->pc_curr, EXCP_UDEF,
102
+ ('tools/qemu-trace-stap', 'qemu-trace-stap',
71
+ gen_exception_insn_el(s, 0, EXCP_UDEF,
103
+ 'QEMU SystemTap trace tool',
72
syn_smetrap(SME_ET_AccessTrap, false),
104
+ [], 1),
73
s->sme_excp_el);
105
+ ('tools/virtfs-proxy-helper', 'virtfs-proxy-helper',
74
return false;
106
+ 'QEMU 9p virtfs proxy filesystem helper',
75
@@ -XXX,XX +XXX,XX @@ bool sme_enabled_check_with_svcr(DisasContext *s, unsigned req)
107
+ ['M. Mohan Kumar'], 1),
76
return false;
108
+ ('tools/virtiofsd', 'virtiofsd',
77
}
109
+ 'QEMU virtio-fs shared file system daemon',
78
if (FIELD_EX64(req, SVCR, SM) && !s->pstate_sm) {
110
+ ['Stefan Hajnoczi <stefanha@redhat.com>',
79
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
111
+ 'Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>'], 1),
80
+ gen_exception_insn(s, 0, EXCP_UDEF,
112
+]
81
syn_smetrap(SME_ET_NotStreaming, false));
113
82
return false;
114
# -- Options for Texinfo output -------------------------------------------
83
}
115
84
if (FIELD_EX64(req, SVCR, ZA) && !s->pstate_za) {
116
diff --git a/docs/devel/conf.py b/docs/devel/conf.py
85
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
117
deleted file mode 100644
86
+ gen_exception_insn(s, 0, EXCP_UDEF,
118
index XXXXXXX..XXXXXXX
87
syn_smetrap(SME_ET_InactiveZA, false));
119
--- a/docs/devel/conf.py
88
return false;
120
+++ /dev/null
89
}
121
@@ -XXX,XX +XXX,XX @@
90
@@ -XXX,XX +XXX,XX @@ static void gen_sysreg_undef(DisasContext *s, bool isread,
122
-# -*- coding: utf-8 -*-
91
} else {
123
-#
92
syndrome = syn_uncategorized();
124
-# QEMU documentation build configuration file for the 'devel' manual.
93
}
125
-#
94
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syndrome);
126
-# This includes the top level conf file and then makes any necessary tweaks.
95
+ gen_exception_insn(s, 0, EXCP_UDEF, syndrome);
127
-import sys
96
}
128
-import os
97
129
-
98
/* MRS - move from system register
130
-qemu_docdir = os.path.abspath("..")
99
@@ -XXX,XX +XXX,XX @@ static void disas_exc(DisasContext *s, uint32_t insn)
131
-parent_config = os.path.join(qemu_docdir, "conf.py")
100
switch (op2_ll) {
132
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
101
case 1: /* SVC */
133
-
102
gen_ss_advance(s);
134
-# This slightly misuses the 'description', but is the best way to get
103
- gen_exception_insn(s, s->base.pc_next, EXCP_SWI,
135
-# the manual title to appear in the sidebar.
104
- syn_aa64_svc(imm16));
136
-html_theme_options['description'] = u'Developer''s Guide'
105
+ gen_exception_insn(s, 4, EXCP_SWI, syn_aa64_svc(imm16));
137
diff --git a/docs/index.html.in b/docs/index.html.in
106
break;
138
deleted file mode 100644
107
case 2: /* HVC */
139
index XXXXXXX..XXXXXXX
108
if (s->current_el == 0) {
140
--- a/docs/index.html.in
109
@@ -XXX,XX +XXX,XX @@ static void disas_exc(DisasContext *s, uint32_t insn)
141
+++ /dev/null
110
gen_a64_update_pc(s, 0);
142
@@ -XXX,XX +XXX,XX @@
111
gen_helper_pre_hvc(cpu_env);
143
-<!DOCTYPE html>
112
gen_ss_advance(s);
144
-<html lang="en">
113
- gen_exception_insn_el(s, s->base.pc_next, EXCP_HVC,
145
- <head>
114
- syn_aa64_hvc(imm16), 2);
146
- <meta charset="UTF-8">
115
+ gen_exception_insn_el(s, 4, EXCP_HVC, syn_aa64_hvc(imm16), 2);
147
- <title>QEMU @VERSION@ Documentation</title>
116
break;
148
- </head>
117
case 3: /* SMC */
149
- <body>
118
if (s->current_el == 0) {
150
- <h1>QEMU @VERSION@ Documentation</h1>
119
@@ -XXX,XX +XXX,XX @@ static void disas_exc(DisasContext *s, uint32_t insn)
151
- <ul>
120
gen_a64_update_pc(s, 0);
152
- <li><a href="system/index.html">System Emulation User's Guide</a></li>
121
gen_helper_pre_smc(cpu_env, tcg_constant_i32(syn_aa64_smc(imm16)));
153
- <li><a href="user/index.html">User Mode Emulation User's Guide</a></li>
122
gen_ss_advance(s);
154
- <li><a href="tools/index.html">Tools Guide</a></li>
123
- gen_exception_insn_el(s, s->base.pc_next, EXCP_SMC,
155
- <li><a href="interop/index.html">System Emulation Management and Interoperability Guide</a></li>
124
- syn_aa64_smc(imm16), 3);
156
- <li><a href="specs/index.html">System Emulation Guest Hardware Specifications</a></li>
125
+ gen_exception_insn_el(s, 4, EXCP_SMC, syn_aa64_smc(imm16), 3);
157
- </ul>
126
break;
158
- </body>
127
default:
159
-</html>
128
unallocated_encoding(s);
160
diff --git a/docs/interop/conf.py b/docs/interop/conf.py
129
@@ -XXX,XX +XXX,XX @@ static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
161
deleted file mode 100644
130
* Illegal execution state. This has priority over BTI
162
index XXXXXXX..XXXXXXX
131
* exceptions, but comes after instruction abort exceptions.
163
--- a/docs/interop/conf.py
132
*/
164
+++ /dev/null
133
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syn_illegalstate());
165
@@ -XXX,XX +XXX,XX @@
134
+ gen_exception_insn(s, 0, EXCP_UDEF, syn_illegalstate());
166
-# -*- coding: utf-8 -*-
135
return;
167
-#
136
}
168
-# QEMU documentation build configuration file for the 'interop' manual.
137
169
-#
138
@@ -XXX,XX +XXX,XX @@ static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
170
-# This includes the top level conf file and then makes any necessary tweaks.
139
if (s->btype != 0
171
-import sys
140
&& s->guarded_page
172
-import os
141
&& !btype_destination_ok(insn, s->bt, s->btype)) {
173
-
142
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
174
-qemu_docdir = os.path.abspath("..")
143
- syn_btitrap(s->btype));
175
-parent_config = os.path.join(qemu_docdir, "conf.py")
144
+ gen_exception_insn(s, 0, EXCP_UDEF, syn_btitrap(s->btype));
176
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
145
return;
177
-
146
}
178
-# This slightly misuses the 'description', but is the best way to get
147
} else {
179
-# the manual title to appear in the sidebar.
148
diff --git a/target/arm/translate-m-nocp.c b/target/arm/translate-m-nocp.c
180
-html_theme_options['description'] = u'System Emulation Management and Interoperability Guide'
149
index XXXXXXX..XXXXXXX 100644
181
-
150
--- a/target/arm/translate-m-nocp.c
182
-# One entry per manual page. List of tuples
151
+++ b/target/arm/translate-m-nocp.c
183
-# (source start file, name, description, authors, manual section).
152
@@ -XXX,XX +XXX,XX @@ static bool trans_VSCCLRM(DisasContext *s, arg_VSCCLRM *a)
184
-man_pages = [
153
tcg_gen_brcondi_i32(TCG_COND_EQ, sfpa, 0, s->condlabel);
185
- ('qemu-ga', 'qemu-ga', u'QEMU Guest Agent',
154
186
- ['Michael Roth <mdroth@linux.vnet.ibm.com>'], 8),
155
if (s->fp_excp_el != 0) {
187
- ('qemu-ga-ref', 'qemu-ga-ref', 'QEMU Guest Agent Protocol Reference',
156
- gen_exception_insn_el(s, s->pc_curr, EXCP_NOCP,
188
- [], 7),
157
+ gen_exception_insn_el(s, 0, EXCP_NOCP,
189
- ('qemu-qmp-ref', 'qemu-qmp-ref', 'QEMU QMP Reference Manual',
158
syn_uncategorized(), s->fp_excp_el);
190
- [], 7),
159
return true;
191
- ('qemu-storage-daemon-qmp-ref', 'qemu-storage-daemon-qmp-ref',
160
}
192
- 'QEMU Storage Daemon QMP Reference Manual', [], 7),
161
@@ -XXX,XX +XXX,XX @@ static bool trans_NOCP(DisasContext *s, arg_nocp *a)
193
-]
162
}
194
diff --git a/docs/meson.build b/docs/meson.build
163
195
index XXXXXXX..XXXXXXX 100644
164
if (a->cp != 10) {
196
--- a/docs/meson.build
165
- gen_exception_insn(s, s->pc_curr, EXCP_NOCP, syn_uncategorized());
197
+++ b/docs/meson.build
166
+ gen_exception_insn(s, 0, EXCP_NOCP, syn_uncategorized());
198
@@ -XXX,XX +XXX,XX @@ if build_docs
167
return true;
199
meson.source_root() / 'docs/sphinx/qmp_lexer.py',
168
}
200
qapi_gen_depends ]
169
201
170
if (s->fp_excp_el != 0) {
202
- configure_file(output: 'index.html',
171
- gen_exception_insn_el(s, s->pc_curr, EXCP_NOCP,
203
- input: files('index.html.in'),
172
+ gen_exception_insn_el(s, 0, EXCP_NOCP,
204
- configuration: {'VERSION': meson.project_version()},
173
syn_uncategorized(), s->fp_excp_el);
205
- install_dir: qemu_docdir)
174
return true;
206
- manuals = [ 'devel', 'interop', 'tools', 'specs', 'system', 'user' ]
175
}
207
man_pages = {
176
diff --git a/target/arm/translate-mve.c b/target/arm/translate-mve.c
208
- 'interop' : {
177
index XXXXXXX..XXXXXXX 100644
209
'qemu-ga.8': (have_tools ? 'man8' : ''),
178
--- a/target/arm/translate-mve.c
210
'qemu-ga-ref.7': 'man7',
179
+++ b/target/arm/translate-mve.c
211
'qemu-qmp-ref.7': 'man7',
180
@@ -XXX,XX +XXX,XX @@ bool mve_eci_check(DisasContext *s)
212
'qemu-storage-daemon-qmp-ref.7': (have_tools ? 'man7' : ''),
181
return true;
213
- },
182
default:
214
- 'tools': {
183
/* Reserved value: INVSTATE UsageFault */
215
'qemu-img.1': (have_tools ? 'man1' : ''),
184
- gen_exception_insn(s, s->pc_curr, EXCP_INVSTATE, syn_uncategorized());
216
'qemu-nbd.8': (have_tools ? 'man8' : ''),
185
+ gen_exception_insn(s, 0, EXCP_INVSTATE, syn_uncategorized());
217
'qemu-pr-helper.8': (have_tools ? 'man8' : ''),
186
return false;
218
@@ -XXX,XX +XXX,XX @@ if build_docs
187
}
219
'qemu-trace-stap.1': (config_host.has_key('CONFIG_TRACE_SYSTEMTAP') ? 'man1' : ''),
188
}
220
'virtfs-proxy-helper.1': (have_virtfs_proxy_helper ? 'man1' : ''),
189
diff --git a/target/arm/translate-vfp.c b/target/arm/translate-vfp.c
221
'virtiofsd.1': (have_virtiofsd ? 'man1' : ''),
190
index XXXXXXX..XXXXXXX 100644
222
- },
191
--- a/target/arm/translate-vfp.c
223
- 'system': {
192
+++ b/target/arm/translate-vfp.c
224
'qemu.1': 'man1',
193
@@ -XXX,XX +XXX,XX @@ static bool vfp_access_check_a(DisasContext *s, bool ignore_vfp_enabled)
225
'qemu-block-drivers.7': 'man7',
194
int coproc = arm_dc_feature(s, ARM_FEATURE_V8) ? 0 : 0xa;
226
'qemu-cpu-models.7': 'man7'
195
uint32_t syn = syn_fp_access_trap(1, 0xe, false, coproc);
227
- },
196
228
}
197
- gen_exception_insn_el(s, s->pc_curr, EXCP_UDEF, syn, s->fp_excp_el);
229
198
+ gen_exception_insn_el(s, 0, EXCP_UDEF, syn, s->fp_excp_el);
230
sphinxdocs = []
199
return false;
231
sphinxmans = []
200
}
232
- foreach manual : manuals
201
233
- private_dir = meson.current_build_dir() / (manual + '.p')
202
@@ -XXX,XX +XXX,XX @@ static bool vfp_access_check_a(DisasContext *s, bool ignore_vfp_enabled)
234
- output_dir = meson.current_build_dir() / manual
203
* appear to be any insns which touch VFP which are allowed.
235
- input_dir = meson.current_source_dir() / manual
204
*/
236
205
if (s->sme_trap_nonstreaming) {
237
- this_manual = custom_target(manual + ' manual',
206
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
238
+ private_dir = meson.current_build_dir() / 'manual.p'
207
+ gen_exception_insn(s, 0, EXCP_UDEF,
239
+ output_dir = meson.current_build_dir() / 'manual'
208
syn_smetrap(SME_ET_Streaming,
240
+ input_dir = meson.current_source_dir()
209
curr_insn_len(s) == 2));
241
+
210
return false;
242
+ this_manual = custom_target('QEMU manual',
211
@@ -XXX,XX +XXX,XX @@ bool vfp_access_check_m(DisasContext *s, bool skip_context_update)
243
build_by_default: build_docs,
212
* the encoding space handled by the patterns in m-nocp.decode,
244
- output: [manual + '.stamp'],
213
* and for them we may need to raise NOCP here.
245
- input: [files('conf.py'), files(manual / 'conf.py')],
214
*/
246
- depfile: manual + '.d',
215
- gen_exception_insn_el(s, s->pc_curr, EXCP_NOCP,
247
+ output: 'docs.stamp',
216
+ gen_exception_insn_el(s, 0, EXCP_NOCP,
248
+ input: files('conf.py'),
217
syn_uncategorized(), s->fp_excp_el);
249
+ depfile: 'docs.d',
218
return false;
250
depend_files: sphinx_extn_depends,
219
}
251
command: [SPHINX_ARGS, '-Ddepfile=@DEPFILE@',
220
diff --git a/target/arm/translate.c b/target/arm/translate.c
252
'-Ddepfile_stamp=@OUTPUT0@',
221
index XXXXXXX..XXXXXXX 100644
253
'-b', 'html', '-d', private_dir,
222
--- a/target/arm/translate.c
254
input_dir, output_dir])
223
+++ b/target/arm/translate.c
255
- sphinxdocs += this_manual
224
@@ -XXX,XX +XXX,XX @@ static void gen_exception(int excp, uint32_t syndrome)
256
- if build_docs and manual != 'devel'
225
tcg_constant_i32(syndrome));
257
- install_subdir(output_dir, install_dir: qemu_docdir)
226
}
258
- endif
227
259
+ sphinxdocs += this_manual
228
-static void gen_exception_insn_el_v(DisasContext *s, uint64_t pc, int excp,
260
+ install_subdir(output_dir, install_dir: qemu_docdir, strip_directory: true)
229
- uint32_t syn, TCGv_i32 tcg_el)
261
230
+static void gen_exception_insn_el_v(DisasContext *s, target_long pc_diff,
262
- these_man_pages = []
231
+ int excp, uint32_t syn, TCGv_i32 tcg_el)
263
- install_dirs = []
232
{
264
- foreach page, section : man_pages.get(manual, {})
233
if (s->aarch64) {
265
- these_man_pages += page
234
- gen_a64_update_pc(s, pc - s->pc_curr);
266
- install_dirs += section == '' ? false : get_option('mandir') / section
235
+ gen_a64_update_pc(s, pc_diff);
267
- endforeach
236
} else {
268
- if these_man_pages.length() > 0
237
gen_set_condexec(s);
269
- sphinxmans += custom_target(manual + ' man pages',
238
- gen_update_pc(s, pc - s->pc_curr);
270
- build_by_default: build_docs,
239
+ gen_update_pc(s, pc_diff);
271
- output: these_man_pages,
240
}
272
- input: this_manual,
241
gen_exception_el_v(excp, syn, tcg_el);
273
- install: build_docs,
242
s->base.is_jmp = DISAS_NORETURN;
274
- install_dir: install_dirs,
243
}
275
- command: [SPHINX_ARGS, '-b', 'man', '-d', private_dir,
244
276
- input_dir, meson.current_build_dir()])
245
-void gen_exception_insn_el(DisasContext *s, uint64_t pc, int excp,
277
- endif
246
+void gen_exception_insn_el(DisasContext *s, target_long pc_diff, int excp,
278
+ these_man_pages = []
247
uint32_t syn, uint32_t target_el)
279
+ install_dirs = []
248
{
280
+ foreach page, section : man_pages
249
- gen_exception_insn_el_v(s, pc, excp, syn, tcg_constant_i32(target_el));
281
+ these_man_pages += page
250
+ gen_exception_insn_el_v(s, pc_diff, excp, syn,
282
+ install_dirs += section == '' ? false : get_option('mandir') / section
251
+ tcg_constant_i32(target_el));
283
endforeach
252
}
284
+
253
285
+ sphinxmans += custom_target('QEMU man pages',
254
-void gen_exception_insn(DisasContext *s, uint64_t pc, int excp, uint32_t syn)
286
+ build_by_default: build_docs,
255
+void gen_exception_insn(DisasContext *s, target_long pc_diff,
287
+ output: these_man_pages,
256
+ int excp, uint32_t syn)
288
+ input: this_manual,
257
{
289
+ install: build_docs,
258
if (s->aarch64) {
290
+ install_dir: install_dirs,
259
- gen_a64_update_pc(s, pc - s->pc_curr);
291
+ command: [SPHINX_ARGS, '-b', 'man', '-d', private_dir,
260
+ gen_a64_update_pc(s, pc_diff);
292
+ input_dir, meson.current_build_dir()])
261
} else {
293
+
262
gen_set_condexec(s);
294
alias_target('sphinxdocs', sphinxdocs)
263
- gen_update_pc(s, pc - s->pc_curr);
295
alias_target('html', sphinxdocs)
264
+ gen_update_pc(s, pc_diff);
296
alias_target('man', sphinxmans)
265
}
297
diff --git a/docs/specs/conf.py b/docs/specs/conf.py
266
gen_exception(excp, syn);
298
deleted file mode 100644
267
s->base.is_jmp = DISAS_NORETURN;
299
index XXXXXXX..XXXXXXX
268
@@ -XXX,XX +XXX,XX @@ static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syn)
300
--- a/docs/specs/conf.py
269
void unallocated_encoding(DisasContext *s)
301
+++ /dev/null
270
{
302
@@ -XXX,XX +XXX,XX @@
271
/* Unallocated and reserved encodings are uncategorized */
303
-# -*- coding: utf-8 -*-
272
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syn_uncategorized());
304
-#
273
+ gen_exception_insn(s, 0, EXCP_UDEF, syn_uncategorized());
305
-# QEMU documentation build configuration file for the 'specs' manual.
274
}
306
-#
275
307
-# This includes the top level conf file and then makes any necessary tweaks.
276
/* Force a TB lookup after an instruction that changes the CPU state. */
308
-import sys
277
@@ -XXX,XX +XXX,XX @@ static bool msr_banked_access_decode(DisasContext *s, int r, int sysm, int rn,
309
-import os
278
tcg_el = tcg_constant_i32(3);
310
-
279
}
311
-qemu_docdir = os.path.abspath("..")
280
312
-parent_config = os.path.join(qemu_docdir, "conf.py")
281
- gen_exception_insn_el_v(s, s->pc_curr, EXCP_UDEF,
313
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
282
+ gen_exception_insn_el_v(s, 0, EXCP_UDEF,
314
-
283
syn_uncategorized(), tcg_el);
315
-# This slightly misuses the 'description', but is the best way to get
284
tcg_temp_free_i32(tcg_el);
316
-# the manual title to appear in the sidebar.
285
return false;
317
-html_theme_options['description'] = \
286
@@ -XXX,XX +XXX,XX @@ static bool msr_banked_access_decode(DisasContext *s, int r, int sysm, int rn,
318
- u'System Emulation Guest Hardware Specifications'
287
319
diff --git a/docs/system/conf.py b/docs/system/conf.py
288
undef:
320
deleted file mode 100644
289
/* If we get here then some access check did not pass */
321
index XXXXXXX..XXXXXXX
290
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syn_uncategorized());
322
--- a/docs/system/conf.py
291
+ gen_exception_insn(s, 0, EXCP_UDEF, syn_uncategorized());
323
+++ /dev/null
292
return false;
324
@@ -XXX,XX +XXX,XX @@
293
}
325
-# -*- coding: utf-8 -*-
294
326
-#
295
@@ -XXX,XX +XXX,XX @@ static void gen_srs(DisasContext *s,
327
-# QEMU documentation build configuration file for the 'system' manual.
296
* For the UNPREDICTABLE cases we choose to UNDEF.
328
-#
297
*/
329
-# This includes the top level conf file and then makes any necessary tweaks.
298
if (s->current_el == 1 && !s->ns && mode == ARM_CPU_MODE_MON) {
330
-import sys
299
- gen_exception_insn_el(s, s->pc_curr, EXCP_UDEF,
331
-import os
300
- syn_uncategorized(), 3);
332
-
301
+ gen_exception_insn_el(s, 0, EXCP_UDEF, syn_uncategorized(), 3);
333
-qemu_docdir = os.path.abspath("..")
302
return;
334
-parent_config = os.path.join(qemu_docdir, "conf.py")
303
}
335
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
304
336
-
305
@@ -XXX,XX +XXX,XX @@ static bool trans_WLS(DisasContext *s, arg_WLS *a)
337
-# This slightly misuses the 'description', but is the best way to get
306
* Do the check-and-raise-exception by hand.
338
-# the manual title to appear in the sidebar.
307
*/
339
-html_theme_options['description'] = u'System Emulation User''s Guide'
308
if (s->fp_excp_el) {
340
-
309
- gen_exception_insn_el(s, s->pc_curr, EXCP_NOCP,
341
-# One entry per manual page. List of tuples
310
+ gen_exception_insn_el(s, 0, EXCP_NOCP,
342
-# (source start file, name, description, authors, manual section).
311
syn_uncategorized(), s->fp_excp_el);
343
-man_pages = [
312
return true;
344
- ('qemu-manpage', 'qemu', u'QEMU User Documentation',
313
}
345
- ['Fabrice Bellard'], 1),
314
@@ -XXX,XX +XXX,XX @@ static bool trans_LE(DisasContext *s, arg_LE *a)
346
- ('qemu-block-drivers', 'qemu-block-drivers',
315
tmp = load_cpu_field(v7m.ltpsize);
347
- u'QEMU block drivers reference',
316
tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 4, skipexc);
348
- ['Fabrice Bellard and the QEMU Project developers'], 7),
317
tcg_temp_free_i32(tmp);
349
- ('qemu-cpu-models', 'qemu-cpu-models',
318
- gen_exception_insn(s, s->pc_curr, EXCP_INVSTATE, syn_uncategorized());
350
- u'QEMU CPU Models',
319
+ gen_exception_insn(s, 0, EXCP_INVSTATE, syn_uncategorized());
351
- ['The QEMU Project developers'], 7)
320
gen_set_label(skipexc);
352
-]
321
}
353
diff --git a/docs/tools/conf.py b/docs/tools/conf.py
322
354
deleted file mode 100644
323
@@ -XXX,XX +XXX,XX @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
355
index XXXXXXX..XXXXXXX
324
* UsageFault exception.
356
--- a/docs/tools/conf.py
325
*/
357
+++ /dev/null
326
if (arm_dc_feature(s, ARM_FEATURE_M)) {
358
@@ -XXX,XX +XXX,XX @@
327
- gen_exception_insn(s, s->pc_curr, EXCP_INVSTATE, syn_uncategorized());
359
-# -*- coding: utf-8 -*-
328
+ gen_exception_insn(s, 0, EXCP_INVSTATE, syn_uncategorized());
360
-#
329
return;
361
-# QEMU documentation build configuration file for the 'tools' manual.
330
}
362
-#
331
363
-# This includes the top level conf file and then makes any necessary tweaks.
332
@@ -XXX,XX +XXX,XX @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
364
-import sys
333
* Illegal execution state. This has priority over BTI
365
-import os
334
* exceptions, but comes after instruction abort exceptions.
366
-
335
*/
367
-qemu_docdir = os.path.abspath("..")
336
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syn_illegalstate());
368
-parent_config = os.path.join(qemu_docdir, "conf.py")
337
+ gen_exception_insn(s, 0, EXCP_UDEF, syn_illegalstate());
369
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
338
return;
370
-
339
}
371
-# This slightly misuses the 'description', but is the best way to get
340
372
-# the manual title to appear in the sidebar.
341
@@ -XXX,XX +XXX,XX @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
373
-html_theme_options['description'] = \
342
* Illegal execution state. This has priority over BTI
374
- u'Tools Guide'
343
* exceptions, but comes after instruction abort exceptions.
375
-
344
*/
376
-# One entry per manual page. List of tuples
345
- gen_exception_insn(dc, dc->pc_curr, EXCP_UDEF, syn_illegalstate());
377
-# (source start file, name, description, authors, manual section).
346
+ gen_exception_insn(dc, 0, EXCP_UDEF, syn_illegalstate());
378
-man_pages = [
347
return;
379
- ('qemu-img', 'qemu-img', u'QEMU disk image utility',
348
}
380
- ['Fabrice Bellard'], 1),
349
381
- ('qemu-storage-daemon', 'qemu-storage-daemon', u'QEMU storage daemon',
350
@@ -XXX,XX +XXX,XX @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
382
- [], 1),
351
*/
383
- ('qemu-nbd', 'qemu-nbd', u'QEMU Disk Network Block Device Server',
352
tcg_remove_ops_after(dc->insn_eci_rewind);
384
- ['Anthony Liguori <anthony@codemonkey.ws>'], 8),
353
dc->condjmp = 0;
385
- ('qemu-pr-helper', 'qemu-pr-helper', 'QEMU persistent reservation helper',
354
- gen_exception_insn(dc, dc->pc_curr, EXCP_INVSTATE,
386
- [], 8),
355
- syn_uncategorized());
387
- ('qemu-trace-stap', 'qemu-trace-stap', u'QEMU SystemTap trace tool',
356
+ gen_exception_insn(dc, 0, EXCP_INVSTATE, syn_uncategorized());
388
- [], 1),
357
}
389
- ('virtfs-proxy-helper', 'virtfs-proxy-helper',
358
390
- u'QEMU 9p virtfs proxy filesystem helper',
359
arm_post_translate_insn(dc);
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
--
360
--
418
2.20.1
361
2.25.1
419
362
420
363
diff view generated by jsdifflib
1
From: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Signed-off-by: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
3
In preparation for TARGET_TB_PCREL, reduce reliance on absolute values.
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
4
Since we always pass dc->pc_curr, fold the arithmetic to zero displacement.
5
6
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20221020030641.2066807-6-richard.henderson@linaro.org
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
---
10
---
7
target/arm/cpu64.c | 1 +
11
target/arm/translate-a64.c | 6 +++---
8
1 file changed, 1 insertion(+)
12
target/arm/translate.c | 10 +++++-----
13
2 files changed, 8 insertions(+), 8 deletions(-)
9
14
10
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
15
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
11
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
12
--- a/target/arm/cpu64.c
17
--- a/target/arm/translate-a64.c
13
+++ b/target/arm/cpu64.c
18
+++ b/target/arm/translate-a64.c
14
@@ -XXX,XX +XXX,XX @@ static void aarch64_max_initfn(Object *obj)
19
@@ -XXX,XX +XXX,XX @@ static void gen_exception_internal(int excp)
15
t = cpu->isar.id_aa64mmfr2;
20
gen_helper_exception_internal(cpu_env, tcg_constant_i32(excp));
16
t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1);
21
}
17
t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1); /* TTCNP */
22
18
+ t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* TTST */
23
-static void gen_exception_internal_insn(DisasContext *s, uint64_t pc, int excp)
19
cpu->isar.id_aa64mmfr2 = t;
24
+static void gen_exception_internal_insn(DisasContext *s, int excp)
20
25
{
21
/* Replicate the same data to the 32-bit id registers. */
26
- gen_a64_update_pc(s, pc - s->pc_curr);
27
+ gen_a64_update_pc(s, 0);
28
gen_exception_internal(excp);
29
s->base.is_jmp = DISAS_NORETURN;
30
}
31
@@ -XXX,XX +XXX,XX @@ static void disas_exc(DisasContext *s, uint32_t insn)
32
* Secondly, "HLT 0xf000" is the A64 semihosting syscall instruction.
33
*/
34
if (semihosting_enabled(s->current_el == 0) && imm16 == 0xf000) {
35
- gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST);
36
+ gen_exception_internal_insn(s, EXCP_SEMIHOST);
37
} else {
38
unallocated_encoding(s);
39
}
40
diff --git a/target/arm/translate.c b/target/arm/translate.c
41
index XXXXXXX..XXXXXXX 100644
42
--- a/target/arm/translate.c
43
+++ b/target/arm/translate.c
44
@@ -XXX,XX +XXX,XX @@ static inline void gen_smc(DisasContext *s)
45
s->base.is_jmp = DISAS_SMC;
46
}
47
48
-static void gen_exception_internal_insn(DisasContext *s, uint32_t pc, int excp)
49
+static void gen_exception_internal_insn(DisasContext *s, int excp)
50
{
51
gen_set_condexec(s);
52
- gen_update_pc(s, pc - s->pc_curr);
53
+ gen_update_pc(s, 0);
54
gen_exception_internal(excp);
55
s->base.is_jmp = DISAS_NORETURN;
56
}
57
@@ -XXX,XX +XXX,XX @@ static inline void gen_hlt(DisasContext *s, int imm)
58
*/
59
if (semihosting_enabled(s->current_el != 0) &&
60
(imm == (s->thumb ? 0x3c : 0xf000))) {
61
- gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST);
62
+ gen_exception_internal_insn(s, EXCP_SEMIHOST);
63
return;
64
}
65
66
@@ -XXX,XX +XXX,XX @@ static bool trans_BKPT(DisasContext *s, arg_BKPT *a)
67
if (arm_dc_feature(s, ARM_FEATURE_M) &&
68
semihosting_enabled(s->current_el == 0) &&
69
(a->imm == 0xab)) {
70
- gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST);
71
+ gen_exception_internal_insn(s, EXCP_SEMIHOST);
72
} else {
73
gen_exception_bkpt_insn(s, syn_aa32_bkpt(a->imm, false));
74
}
75
@@ -XXX,XX +XXX,XX @@ static bool trans_SVC(DisasContext *s, arg_SVC *a)
76
if (!arm_dc_feature(s, ARM_FEATURE_M) &&
77
semihosting_enabled(s->current_el == 0) &&
78
(a->imm == semihost_imm)) {
79
- gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST);
80
+ gen_exception_internal_insn(s, EXCP_SEMIHOST);
81
} else {
82
gen_update_pc(s, curr_insn_len(s));
83
s->svc_imm = a->imm;
22
--
84
--
23
2.20.1
85
2.25.1
24
86
25
87
diff view generated by jsdifflib
1
From: Hao Wu <wuhaotsh@google.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
This patch makes NPCM7XX Timer to use a the timer clock generated by the
3
In preparation for TARGET_TB_PCREL, reduce reliance on absolute values.
4
CLK module instead of the magic number TIMER_REF_HZ.
5
4
6
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
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>
5
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20221020030641.2066807-7-richard.henderson@linaro.org
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
9
---
13
include/hw/misc/npcm7xx_clk.h | 6 -----
10
target/arm/translate.c | 37 +++++++++++++++++++++----------------
14
include/hw/timer/npcm7xx_timer.h | 1 +
11
1 file changed, 21 insertions(+), 16 deletions(-)
15
hw/arm/npcm7xx.c | 5 ++++
16
hw/timer/npcm7xx_timer.c | 39 +++++++++++++++-----------------
17
4 files changed, 24 insertions(+), 27 deletions(-)
18
12
19
diff --git a/include/hw/misc/npcm7xx_clk.h b/include/hw/misc/npcm7xx_clk.h
13
diff --git a/target/arm/translate.c b/target/arm/translate.c
20
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
21
--- a/include/hw/misc/npcm7xx_clk.h
15
--- a/target/arm/translate.c
22
+++ b/include/hw/misc/npcm7xx_clk.h
16
+++ b/target/arm/translate.c
23
@@ -XXX,XX +XXX,XX @@
17
@@ -XXX,XX +XXX,XX @@ static uint32_t read_pc(DisasContext *s)
24
#include "hw/clock.h"
18
return s->pc_curr + (s->thumb ? 4 : 8);
25
#include "hw/sysbus.h"
19
}
26
20
27
-/*
21
+/* The pc_curr difference for an architectural jump. */
28
- * The reference clock frequency for the timer modules, and the SECCNT and
22
+static target_long jmp_diff(DisasContext *s, target_long diff)
29
- * CNTR25M registers in this module, is always 25 MHz.
23
+{
30
- */
24
+ return diff + (s->thumb ? 4 : 8);
31
-#define NPCM7XX_TIMER_REF_HZ (25000000)
25
+}
26
+
27
/* Set a variable to the value of a CPU register. */
28
void load_reg_var(DisasContext *s, TCGv_i32 var, int reg)
29
{
30
@@ -XXX,XX +XXX,XX @@ static void gen_goto_ptr(void)
31
* cpu_loop_exec. Any live exit_requests will be processed as we
32
* enter the next TB.
33
*/
34
-static void gen_goto_tb(DisasContext *s, int n, int diff)
35
+static void gen_goto_tb(DisasContext *s, int n, target_long diff)
36
{
37
target_ulong dest = s->pc_curr + diff;
38
39
@@ -XXX,XX +XXX,XX @@ static void gen_goto_tb(DisasContext *s, int n, int diff)
40
}
41
42
/* Jump, specifying which TB number to use if we gen_goto_tb() */
43
-static inline void gen_jmp_tb(DisasContext *s, uint32_t dest, int tbno)
44
+static void gen_jmp_tb(DisasContext *s, target_long diff, int tbno)
45
{
46
- int diff = dest - s->pc_curr;
32
-
47
-
33
/*
48
if (unlikely(s->ss_active)) {
34
* Number of registers in our device state structure. Don't change this without
49
/* An indirect jump so that we still trigger the debug exception. */
35
* incrementing the version_id in the vmstate.
50
gen_update_pc(s, diff);
36
diff --git a/include/hw/timer/npcm7xx_timer.h b/include/hw/timer/npcm7xx_timer.h
51
@@ -XXX,XX +XXX,XX @@ static inline void gen_jmp_tb(DisasContext *s, uint32_t dest, int tbno)
37
index XXXXXXX..XXXXXXX 100644
52
}
38
--- a/include/hw/timer/npcm7xx_timer.h
53
}
39
+++ b/include/hw/timer/npcm7xx_timer.h
54
40
@@ -XXX,XX +XXX,XX @@ struct NPCM7xxTimerCtrlState {
55
-static inline void gen_jmp(DisasContext *s, uint32_t dest)
41
56
+static inline void gen_jmp(DisasContext *s, target_long diff)
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
{
57
{
89
- int64_t ns = count;
58
- gen_jmp_tb(s, dest, 0);
90
+ int64_t ticks = count;
59
+ gen_jmp_tb(s, diff, 0);
91
92
- ns *= NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ;
93
- ns *= npcm7xx_tcsr_prescaler(t->tcsr);
94
+ ticks *= npcm7xx_tcsr_prescaler(t->tcsr);
95
96
- return ns;
97
+ return clock_ticks_to_ns(t->ctrl->clock, ticks);
98
}
60
}
99
61
100
/* Convert a time interval in nanoseconds to a timer cycle count. */
62
static inline void gen_mulxy(TCGv_i32 t0, TCGv_i32 t1, int x, int y)
101
static uint32_t npcm7xx_timer_ns_to_count(NPCM7xxTimer *t, int64_t ns)
63
@@ -XXX,XX +XXX,XX @@ static bool trans_CLRM(DisasContext *s, arg_CLRM *a)
64
65
static bool trans_B(DisasContext *s, arg_i *a)
102
{
66
{
103
- int64_t count;
67
- gen_jmp(s, read_pc(s) + a->imm);
104
-
68
+ gen_jmp(s, jmp_diff(s, a->imm));
105
- count = ns / (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ);
69
return true;
106
- count /= npcm7xx_tcsr_prescaler(t->tcsr);
107
-
108
- return count;
109
+ return ns / clock_ticks_to_ns(t->ctrl->clock,
110
+ npcm7xx_tcsr_prescaler(t->tcsr));
111
}
70
}
112
71
113
static uint32_t npcm7xx_watchdog_timer_prescaler(const NPCM7xxWatchdogTimer *t)
72
@@ -XXX,XX +XXX,XX @@ static bool trans_B_cond_thumb(DisasContext *s, arg_ci *a)
114
@@ -XXX,XX +XXX,XX @@ static uint32_t npcm7xx_watchdog_timer_prescaler(const NPCM7xxWatchdogTimer *t)
73
return true;
115
static void npcm7xx_watchdog_timer_reset_cycles(NPCM7xxWatchdogTimer *t,
74
}
116
int64_t cycles)
75
arm_skip_unless(s, a->cond);
76
- gen_jmp(s, read_pc(s) + a->imm);
77
+ gen_jmp(s, jmp_diff(s, a->imm));
78
return true;
79
}
80
81
static bool trans_BL(DisasContext *s, arg_i *a)
117
{
82
{
118
- uint32_t prescaler = npcm7xx_watchdog_timer_prescaler(t);
83
tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | s->thumb);
119
- int64_t ns = (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ) * cycles;
84
- gen_jmp(s, read_pc(s) + a->imm);
120
+ int64_t ticks = cycles * npcm7xx_watchdog_timer_prescaler(t);
85
+ gen_jmp(s, jmp_diff(s, a->imm));
121
+ int64_t ns = clock_ticks_to_ns(t->ctrl->clock, ticks);
86
return true;
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
}
87
}
132
88
133
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_hold_reset(Object *obj)
89
@@ -XXX,XX +XXX,XX @@ static bool trans_BLX_i(DisasContext *s, arg_BLX_i *a)
134
qemu_irq_lower(s->watchdog_timer.irq);
90
}
91
tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | s->thumb);
92
store_cpu_field_constant(!s->thumb, thumb);
93
- gen_jmp(s, (read_pc(s) & ~3) + a->imm);
94
+ /* This jump is computed from an aligned PC: subtract off the low bits. */
95
+ gen_jmp(s, jmp_diff(s, a->imm - (s->pc_curr & 3)));
96
return true;
135
}
97
}
136
98
137
-static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
99
@@ -XXX,XX +XXX,XX @@ static bool trans_WLS(DisasContext *s, arg_WLS *a)
138
+static void npcm7xx_timer_init(Object *obj)
100
* when we take this upcoming exit from this TB, so gen_jmp_tb() is OK.
139
{
101
*/
140
- NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(dev);
102
}
141
- SysBusDevice *sbd = &s->parent;
103
- gen_jmp_tb(s, s->base.pc_next, 1);
142
+ NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(obj);
104
+ gen_jmp_tb(s, curr_insn_len(s), 1);
143
+ DeviceState *dev = DEVICE(obj);
105
144
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
106
gen_set_label(nextlabel);
145
int i;
107
- gen_jmp(s, read_pc(s) + a->imm);
146
NPCM7xxWatchdogTimer *w;
108
+ gen_jmp(s, jmp_diff(s, a->imm));
147
109
return true;
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
}
110
}
160
111
161
static const VMStateDescription vmstate_npcm7xx_base_timer = {
112
@@ -XXX,XX +XXX,XX @@ static bool trans_LE(DisasContext *s, arg_LE *a)
162
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_npcm7xx_watchdog_timer = {
113
163
114
if (a->f) {
164
static const VMStateDescription vmstate_npcm7xx_timer_ctrl = {
115
/* Loop-forever: just jump back to the loop start */
165
.name = "npcm7xx-timer-ctrl",
116
- gen_jmp(s, read_pc(s) - a->imm);
166
- .version_id = 1,
117
+ gen_jmp(s, jmp_diff(s, -a->imm));
167
- .minimum_version_id = 1,
118
return true;
168
+ .version_id = 2,
119
}
169
+ .minimum_version_id = 2,
120
170
.fields = (VMStateField[]) {
121
@@ -XXX,XX +XXX,XX @@ static bool trans_LE(DisasContext *s, arg_LE *a)
171
VMSTATE_UINT32(tisr, NPCM7xxTimerCtrlState),
122
tcg_temp_free_i32(decr);
172
+ VMSTATE_CLOCK(clock, NPCM7xxTimerCtrlState),
123
}
173
VMSTATE_STRUCT_ARRAY(timer, NPCM7xxTimerCtrlState,
124
/* Jump back to the loop start */
174
NPCM7XX_TIMERS_PER_CTRL, 0, vmstate_npcm7xx_timer,
125
- gen_jmp(s, read_pc(s) - a->imm);
175
NPCM7xxTimer),
126
+ gen_jmp(s, jmp_diff(s, -a->imm));
176
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_class_init(ObjectClass *klass, void *data)
127
177
QEMU_BUILD_BUG_ON(NPCM7XX_TIMER_REGS_END > NPCM7XX_TIMER_NR_REGS);
128
gen_set_label(loopend);
178
129
if (a->tp) {
179
dc->desc = "NPCM7xx Timer Controller";
130
@@ -XXX,XX +XXX,XX @@ static bool trans_LE(DisasContext *s, arg_LE *a)
180
- dc->realize = npcm7xx_timer_realize;
131
store_cpu_field(tcg_constant_i32(4), v7m.ltpsize);
181
dc->vmsd = &vmstate_npcm7xx_timer_ctrl;
132
}
182
rc->phases.enter = npcm7xx_timer_enter_reset;
133
/* End TB, continuing to following insn */
183
rc->phases.hold = npcm7xx_timer_hold_reset;
134
- gen_jmp_tb(s, s->base.pc_next, 1);
184
@@ -XXX,XX +XXX,XX @@ static const TypeInfo npcm7xx_timer_info = {
135
+ gen_jmp_tb(s, curr_insn_len(s), 1);
185
.parent = TYPE_SYS_BUS_DEVICE,
136
return true;
186
.instance_size = sizeof(NPCM7xxTimerCtrlState),
137
}
187
.class_init = npcm7xx_timer_class_init,
138
188
+ .instance_init = npcm7xx_timer_init,
139
@@ -XXX,XX +XXX,XX @@ static bool trans_CBZ(DisasContext *s, arg_CBZ *a)
189
};
140
tcg_gen_brcondi_i32(a->nz ? TCG_COND_EQ : TCG_COND_NE,
190
141
tmp, 0, s->condlabel);
191
static void npcm7xx_timer_register_type(void)
142
tcg_temp_free_i32(tmp);
143
- gen_jmp(s, read_pc(s) + a->imm);
144
+ gen_jmp(s, jmp_diff(s, a->imm));
145
return true;
146
}
147
192
--
148
--
193
2.20.1
149
2.25.1
194
195
diff view generated by jsdifflib
1
From: Hao Wu <wuhaotsh@google.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
This patch allows NPCM7XX CLK module to compute clocks that are used by
3
In preparation for TARGET_TB_PCREL, reduce reliance on absolute values.
4
other NPCM7XX modules.
5
4
6
Add a new struct NPCM7xxClockConverterState which represents a
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>
5
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
24
Message-id: 20210108190945.949196-2-wuhaotsh@google.com
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20221020030641.2066807-8-richard.henderson@linaro.org
25
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
26
---
9
---
27
include/hw/misc/npcm7xx_clk.h | 140 +++++-
10
target/arm/translate-a64.c | 41 +++++++++++++++++++++++++++-----------
28
hw/misc/npcm7xx_clk.c | 805 +++++++++++++++++++++++++++++++++-
11
1 file changed, 29 insertions(+), 12 deletions(-)
29
2 files changed, 932 insertions(+), 13 deletions(-)
30
12
31
diff --git a/include/hw/misc/npcm7xx_clk.h b/include/hw/misc/npcm7xx_clk.h
13
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
32
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
33
--- a/include/hw/misc/npcm7xx_clk.h
15
--- a/target/arm/translate-a64.c
34
+++ b/include/hw/misc/npcm7xx_clk.h
16
+++ b/target/arm/translate-a64.c
35
@@ -XXX,XX +XXX,XX @@
17
@@ -XXX,XX +XXX,XX @@ static void reset_btype(DisasContext *s)
36
#define NPCM7XX_CLK_H
18
}
37
19
}
38
#include "exec/memory.h"
20
39
+#include "hw/clock.h"
21
+static void gen_pc_plus_diff(DisasContext *s, TCGv_i64 dest, target_long diff)
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
+
51
+/* PLLs in CLK module. */
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
+
60
+/* SEL/MUX in CLK module. */
61
+typedef enum NPCM7xxClockSEL {
62
+ NPCM7XX_CLOCK_PIXCKSEL,
63
+ NPCM7XX_CLOCK_MCCKSEL,
64
+ NPCM7XX_CLOCK_CPUCKSEL,
65
+ NPCM7XX_CLOCK_CLKOUTSEL,
66
+ NPCM7XX_CLOCK_UARTCKSEL,
67
+ NPCM7XX_CLOCK_TIMCKSEL,
68
+ NPCM7XX_CLOCK_SDCKSEL,
69
+ NPCM7XX_CLOCK_GFXMSEL,
70
+ NPCM7XX_CLOCK_SUCKSEL,
71
+ NPCM7XX_CLOCK_NR_SELS,
72
+} NPCM7xxClockSEL;
73
+
74
+/* Dividers in CLK module. */
75
+typedef enum NPCM7xxClockDivider {
76
+ NPCM7XX_CLOCK_PLL1D2, /* PLL1/2 */
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
+
100
+typedef struct NPCM7xxCLKState NPCM7xxCLKState;
101
+
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
+{
22
+{
256
+ NPCM7xxClockPLLState *s = opaque;
23
+ tcg_gen_movi_i64(dest, s->pc_curr + diff);
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
+ }
268
+
269
+ clock_update_hz(s->clock_out, freq);
270
+}
24
+}
271
+
25
+
272
+static void npcm7xx_clk_update_sel(void *opaque)
26
void gen_a64_update_pc(DisasContext *s, target_long diff)
273
+{
274
+ NPCM7xxClockSELState *s = opaque;
275
+ uint32_t index = extract32(s->clk->regs[NPCM7XX_CLK_CLKSEL], s->offset,
276
+ s->len);
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
{
27
{
844
uint32_t reg = offset / sizeof(uint32_t);
28
- tcg_gen_movi_i64(cpu_pc, s->pc_curr + diff);
845
@@ -XXX,XX +XXX,XX @@ static uint64_t npcm7xx_clk_read(void *opaque, hwaddr offset, unsigned size)
29
+ gen_pc_plus_diff(s, cpu_pc, diff);
846
*
30
}
847
* The 4 LSBs are always zero: (1e9 / 640) << 4 = 25000000.
31
848
*/
32
/*
849
- value = (((now_ns - s->ref_ns) / 640) << 4) % NPCM7XX_TIMER_REF_HZ;
33
@@ -XXX,XX +XXX,XX @@ static void disas_uncond_b_imm(DisasContext *s, uint32_t insn)
850
+ value = (((now_ns - s->ref_ns) / 640) << 4) % NPCM7XX_CLOCK_REF_HZ;
34
35
if (insn & (1U << 31)) {
36
/* BL Branch with link */
37
- tcg_gen_movi_i64(cpu_reg(s, 30), s->base.pc_next);
38
+ gen_pc_plus_diff(s, cpu_reg(s, 30), curr_insn_len(s));
39
}
40
41
/* B Branch / BL Branch with link */
42
@@ -XXX,XX +XXX,XX @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
43
default:
44
goto do_unallocated;
45
}
46
- gen_a64_set_pc(s, dst);
47
/* BLR also needs to load return address */
48
if (opc == 1) {
49
- tcg_gen_movi_i64(cpu_reg(s, 30), s->base.pc_next);
50
+ TCGv_i64 lr = cpu_reg(s, 30);
51
+ if (dst == lr) {
52
+ TCGv_i64 tmp = new_tmp_a64(s);
53
+ tcg_gen_mov_i64(tmp, dst);
54
+ dst = tmp;
55
+ }
56
+ gen_pc_plus_diff(s, lr, curr_insn_len(s));
57
}
58
+ gen_a64_set_pc(s, dst);
851
break;
59
break;
852
60
853
default:
61
case 8: /* BRAA */
854
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_write(void *opaque, hwaddr offset,
62
@@ -XXX,XX +XXX,XX @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
855
value |= (value & PLLCON_LOKS);
63
} else {
856
}
64
dst = cpu_reg(s, rn);
857
}
65
}
858
+ /* Only update PLL when it is locked. */
66
- gen_a64_set_pc(s, dst);
859
+ if (value & PLLCON_LOKI) {
67
/* BLRAA also needs to load return address */
860
+ npcm7xx_clk_update_pll(&s->plls[find_pll_by_reg(reg)]);
68
if (opc == 9) {
861
+ }
69
- tcg_gen_movi_i64(cpu_reg(s, 30), s->base.pc_next);
862
+ break;
70
+ TCGv_i64 lr = cpu_reg(s, 30);
863
+
71
+ if (dst == lr) {
864
+ case NPCM7XX_CLK_CLKSEL:
72
+ TCGv_i64 tmp = new_tmp_a64(s);
865
+ npcm7xx_clk_update_all_sels(s);
73
+ tcg_gen_mov_i64(tmp, dst);
866
+ break;
74
+ dst = tmp;
867
+
75
+ }
868
+ case NPCM7XX_CLK_CLKDIV1:
76
+ gen_pc_plus_diff(s, lr, curr_insn_len(s));
869
+ case NPCM7XX_CLK_CLKDIV2:
77
}
870
+ case NPCM7XX_CLK_CLKDIV3:
78
+ gen_a64_set_pc(s, dst);
871
+ npcm7xx_clk_update_all_dividers(s);
872
break;
79
break;
873
80
874
case NPCM7XX_CLK_CNTR25M:
81
case 4: /* ERET */
875
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_enter_reset(Object *obj, ResetType type)
82
@@ -XXX,XX +XXX,XX @@ static void disas_ld_lit(DisasContext *s, uint32_t insn)
876
case RESET_TYPE_COLD:
83
877
memcpy(s->regs, cold_reset_values, sizeof(cold_reset_values));
84
tcg_rt = cpu_reg(s, rt);
878
s->ref_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
85
879
+ npcm7xx_clk_update_all_clocks(s);
86
- clean_addr = tcg_constant_i64(s->pc_curr + imm);
880
return;
87
+ clean_addr = new_tmp_a64(s);
88
+ gen_pc_plus_diff(s, clean_addr, imm);
89
if (is_vector) {
90
do_fp_ld(s, rt, clean_addr, size);
91
} else {
92
@@ -XXX,XX +XXX,XX @@ static void disas_ldst(DisasContext *s, uint32_t insn)
93
static void disas_pc_rel_adr(DisasContext *s, uint32_t insn)
94
{
95
unsigned int page, rd;
96
- uint64_t base;
97
- uint64_t offset;
98
+ int64_t offset;
99
100
page = extract32(insn, 31, 1);
101
/* SignExtend(immhi:immlo) -> offset */
102
offset = sextract64(insn, 5, 19);
103
offset = offset << 2 | extract32(insn, 29, 2);
104
rd = extract32(insn, 0, 5);
105
- base = s->pc_curr;
106
107
if (page) {
108
/* ADRP (page based) */
109
- base &= ~0xfff;
110
offset <<= 12;
111
+ /* The page offset is ok for TARGET_TB_PCREL. */
112
+ offset -= s->pc_curr & 0xfff;
881
}
113
}
882
114
883
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_enter_reset(Object *obj, ResetType type)
115
- tcg_gen_movi_i64(cpu_reg(s, rd), base + offset);
884
__func__, type);
116
+ gen_pc_plus_diff(s, cpu_reg(s, rd), offset);
885
}
117
}
886
118
887
+static void npcm7xx_clk_init_clock_hierarchy(NPCM7xxCLKState *s)
119
/*
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
+ }
916
+
917
+ /* Second pass: connect converter modules */
918
+ npcm7xx_connect_clocks(s);
919
+
920
+ clock_update_hz(s->clkref, NPCM7XX_CLOCK_REF_HZ);
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
}
933
934
-static const VMStateDescription vmstate_npcm7xx_clk = {
935
- .name = "npcm7xx-clk",
936
+static int npcm7xx_clk_post_load(void *opaque, int version_id)
937
+{
938
+ if (version_id >= 1) {
939
+ NPCM7xxCLKState *clk = opaque;
940
+
941
+ npcm7xx_clk_update_all_clocks(clk);
942
+ }
943
+
944
+ return 0;
945
+}
946
+
947
+static void npcm7xx_clk_realize(DeviceState *dev, Error **errp)
948
+{
949
+ int i;
950
+ NPCM7xxCLKState *s = NPCM7XX_CLK(dev);
951
+
952
+ qdev_init_gpio_in_named(DEVICE(s), npcm7xx_clk_perform_watchdog_reset,
953
+ NPCM7XX_WATCHDOG_RESET_GPIO_IN, NPCM7XX_NR_WATCHDOGS);
954
+ npcm7xx_clk_init_clock_hierarchy(s);
955
+
956
+ /* Realize child devices */
957
+ for (i = 0; i < NPCM7XX_CLOCK_NR_PLLS; ++i) {
958
+ if (!qdev_realize(DEVICE(&s->plls[i]), NULL, errp)) {
959
+ return;
960
+ }
961
+ }
962
+ for (i = 0; i < NPCM7XX_CLOCK_NR_SELS; ++i) {
963
+ if (!qdev_realize(DEVICE(&s->sels[i]), NULL, errp)) {
964
+ return;
965
+ }
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
--
120
--
1094
2.20.1
121
2.25.1
1095
1096
diff view generated by jsdifflib
1
In commit cd8be50e58f63413c0 we converted the A32 coprocessor
1
From: Richard Henderson <richard.henderson@linaro.org>
2
insns to decodetree. This accidentally broke XScale/iWMMXt insns,
3
because it moved the handling of "cp insns which are handled
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
2
8
Update valid_cp() so that it knows that on XScale cp 0 and 1
3
In preparation for TARGET_TB_PCREL, reduce reliance on absolute values.
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
4
13
Cc: qemu-stable@nongnu.org
5
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
14
Reported-by: Guenter Roeck <linux@roeck-us.net>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20221020030641.2066807-9-richard.henderson@linaro.org
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
17
Tested-by: Guenter Roeck <linux@roeck-us.net>
18
Message-id: 20210108195157.32067-1-peter.maydell@linaro.org
19
---
9
---
20
target/arm/translate.c | 7 +++++++
10
target/arm/translate.c | 38 +++++++++++++++++++++-----------------
21
1 file changed, 7 insertions(+)
11
1 file changed, 21 insertions(+), 17 deletions(-)
22
12
23
diff --git a/target/arm/translate.c b/target/arm/translate.c
13
diff --git a/target/arm/translate.c b/target/arm/translate.c
24
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
25
--- a/target/arm/translate.c
15
--- a/target/arm/translate.c
26
+++ b/target/arm/translate.c
16
+++ b/target/arm/translate.c
27
@@ -XXX,XX +XXX,XX @@ static bool valid_cp(DisasContext *s, int cp)
17
@@ -XXX,XX +XXX,XX @@ static inline int get_a32_user_mem_index(DisasContext *s)
28
* only cp14 and cp15 are valid, and other values aren't considered
18
}
29
* to be in the coprocessor-instruction space at all. v8M still
19
}
30
* permits coprocessors 0..7.
20
31
+ * For XScale, we must not decode the XScale cp0, cp1 space as
21
-/* The architectural value of PC. */
32
+ * a standard coprocessor insn, because we want to fall through to
22
-static uint32_t read_pc(DisasContext *s)
33
+ * the legacy disas_xscale_insn() decoder after decodetree is done.
23
-{
34
*/
24
- return s->pc_curr + (s->thumb ? 4 : 8);
35
+ if (arm_dc_feature(s, ARM_FEATURE_XSCALE) && (cp == 0 || cp == 1)) {
25
-}
36
+ return false;
26
-
37
+ }
27
/* The pc_curr difference for an architectural jump. */
28
static target_long jmp_diff(DisasContext *s, target_long diff)
29
{
30
return diff + (s->thumb ? 4 : 8);
31
}
32
33
+static void gen_pc_plus_diff(DisasContext *s, TCGv_i32 var, target_long diff)
34
+{
35
+ tcg_gen_movi_i32(var, s->pc_curr + diff);
36
+}
38
+
37
+
39
if (arm_dc_feature(s, ARM_FEATURE_V8) &&
38
/* Set a variable to the value of a CPU register. */
40
!arm_dc_feature(s, ARM_FEATURE_M)) {
39
void load_reg_var(DisasContext *s, TCGv_i32 var, int reg)
41
return cp >= 14;
40
{
41
if (reg == 15) {
42
- tcg_gen_movi_i32(var, read_pc(s));
43
+ gen_pc_plus_diff(s, var, jmp_diff(s, 0));
44
} else {
45
tcg_gen_mov_i32(var, cpu_R[reg]);
46
}
47
@@ -XXX,XX +XXX,XX @@ TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs)
48
TCGv_i32 tmp = tcg_temp_new_i32();
49
50
if (reg == 15) {
51
- tcg_gen_movi_i32(tmp, (read_pc(s) & ~3) + ofs);
52
+ /*
53
+ * This address is computed from an aligned PC:
54
+ * subtract off the low bits.
55
+ */
56
+ gen_pc_plus_diff(s, tmp, jmp_diff(s, ofs - (s->pc_curr & 3)));
57
} else {
58
tcg_gen_addi_i32(tmp, cpu_R[reg], ofs);
59
}
60
@@ -XXX,XX +XXX,XX @@ void unallocated_encoding(DisasContext *s)
61
/* Force a TB lookup after an instruction that changes the CPU state. */
62
void gen_lookup_tb(DisasContext *s)
63
{
64
- tcg_gen_movi_i32(cpu_R[15], s->base.pc_next);
65
+ gen_pc_plus_diff(s, cpu_R[15], curr_insn_len(s));
66
s->base.is_jmp = DISAS_EXIT;
67
}
68
69
@@ -XXX,XX +XXX,XX @@ static bool trans_BLX_r(DisasContext *s, arg_BLX_r *a)
70
return false;
71
}
72
tmp = load_reg(s, a->rm);
73
- tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | s->thumb);
74
+ gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | s->thumb);
75
gen_bx(s, tmp);
76
return true;
77
}
78
@@ -XXX,XX +XXX,XX @@ static bool trans_B_cond_thumb(DisasContext *s, arg_ci *a)
79
80
static bool trans_BL(DisasContext *s, arg_i *a)
81
{
82
- tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | s->thumb);
83
+ gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | s->thumb);
84
gen_jmp(s, jmp_diff(s, a->imm));
85
return true;
86
}
87
@@ -XXX,XX +XXX,XX @@ static bool trans_BLX_i(DisasContext *s, arg_BLX_i *a)
88
if (s->thumb && (a->imm & 2)) {
89
return false;
90
}
91
- tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | s->thumb);
92
+ gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | s->thumb);
93
store_cpu_field_constant(!s->thumb, thumb);
94
/* This jump is computed from an aligned PC: subtract off the low bits. */
95
gen_jmp(s, jmp_diff(s, a->imm - (s->pc_curr & 3)));
96
@@ -XXX,XX +XXX,XX @@ static bool trans_BLX_i(DisasContext *s, arg_BLX_i *a)
97
static bool trans_BL_BLX_prefix(DisasContext *s, arg_BL_BLX_prefix *a)
98
{
99
assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2));
100
- tcg_gen_movi_i32(cpu_R[14], read_pc(s) + (a->imm << 12));
101
+ gen_pc_plus_diff(s, cpu_R[14], jmp_diff(s, a->imm << 12));
102
return true;
103
}
104
105
@@ -XXX,XX +XXX,XX @@ static bool trans_BL_suffix(DisasContext *s, arg_BL_suffix *a)
106
107
assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2));
108
tcg_gen_addi_i32(tmp, cpu_R[14], (a->imm << 1) | 1);
109
- tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | 1);
110
+ gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | 1);
111
gen_bx(s, tmp);
112
return true;
113
}
114
@@ -XXX,XX +XXX,XX @@ static bool trans_BLX_suffix(DisasContext *s, arg_BLX_suffix *a)
115
tmp = tcg_temp_new_i32();
116
tcg_gen_addi_i32(tmp, cpu_R[14], a->imm << 1);
117
tcg_gen_andi_i32(tmp, tmp, 0xfffffffc);
118
- tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | 1);
119
+ gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | 1);
120
gen_bx(s, tmp);
121
return true;
122
}
123
@@ -XXX,XX +XXX,XX @@ static bool op_tbranch(DisasContext *s, arg_tbranch *a, bool half)
124
tcg_gen_add_i32(addr, addr, tmp);
125
126
gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), half ? MO_UW : MO_UB);
127
- tcg_temp_free_i32(addr);
128
129
tcg_gen_add_i32(tmp, tmp, tmp);
130
- tcg_gen_addi_i32(tmp, tmp, read_pc(s));
131
+ gen_pc_plus_diff(s, addr, jmp_diff(s, 0));
132
+ tcg_gen_add_i32(tmp, tmp, addr);
133
+ tcg_temp_free_i32(addr);
134
store_reg(s, 15, tmp);
135
return true;
136
}
42
--
137
--
43
2.20.1
138
2.25.1
44
139
45
140
diff view generated by jsdifflib
1
From: Hao Wu <wuhaotsh@google.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
The ADC is part of NPCM7XX Module. Its behavior is controled by the
3
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
4
ADC_CON register. It converts one of the eight analog inputs into a
4
Message-id: 20221020030641.2066807-10-richard.henderson@linaro.org
5
digital input and stores it in the ADC_DATA register when enabled.
6
7
Users can alter input value by using qom-set QMP command.
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>
5
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
---
7
---
17
docs/system/arm/nuvoton.rst | 2 +-
8
target/arm/cpu-param.h | 2 +
18
meson.build | 1 +
9
target/arm/translate.h | 50 +++++++++++++++-
19
hw/adc/trace.h | 1 +
10
target/arm/cpu.c | 23 ++++----
20
include/hw/adc/npcm7xx_adc.h | 69 ++++++
11
target/arm/translate-a64.c | 64 +++++++++++++-------
21
include/hw/arm/npcm7xx.h | 2 +
12
target/arm/translate-m-nocp.c | 2 +-
22
hw/adc/npcm7xx_adc.c | 301 ++++++++++++++++++++++++++
13
target/arm/translate.c | 108 +++++++++++++++++++++++-----------
23
hw/arm/npcm7xx.c | 24 ++-
14
6 files changed, 178 insertions(+), 71 deletions(-)
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
15
35
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
16
diff --git a/target/arm/cpu-param.h b/target/arm/cpu-param.h
36
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
37
--- a/docs/system/arm/nuvoton.rst
18
--- a/target/arm/cpu-param.h
38
+++ b/docs/system/arm/nuvoton.rst
19
+++ b/target/arm/cpu-param.h
39
@@ -XXX,XX +XXX,XX @@ Supported devices
20
@@ -XXX,XX +XXX,XX @@
40
* Random Number Generator (RNG)
21
# define TARGET_PAGE_BITS_VARY
41
* USB host (USBH)
22
# define TARGET_PAGE_BITS_MIN 10
42
* GPIO controller
23
43
+ * Analog to Digital Converter (ADC)
24
+# define TARGET_TB_PCREL 1
44
25
+
45
Missing devices
26
/*
46
---------------
27
* Cache the attrs and shareability fields from the page table entry.
47
@@ -XXX,XX +XXX,XX @@ Missing devices
28
*
48
* USB device (USBD)
29
diff --git a/target/arm/translate.h b/target/arm/translate.h
49
* SMBus controller (SMBF)
50
* Peripheral SPI controller (PSPI)
51
- * Analog to Digital Converter (ADC)
52
* SD/MMC host
53
* PECI interface
54
* Pulse Width Modulation (PWM)
55
diff --git a/meson.build b/meson.build
56
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
57
--- a/meson.build
31
--- a/target/arm/translate.h
58
+++ b/meson.build
32
+++ b/target/arm/translate.h
59
@@ -XXX,XX +XXX,XX @@ if have_system
60
'chardev',
61
'hw/9pfs',
62
'hw/acpi',
63
+ 'hw/adc',
64
'hw/alpha',
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 @@
33
@@ -XXX,XX +XXX,XX @@
34
35
36
/* internal defines */
37
+
80
+/*
38
+/*
81
+ * Nuvoton NPCM7xx ADC Module
39
+ * Save pc_save across a branch, so that we may restore the value from
82
+ *
40
+ * before the branch at the point the label is emitted.
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
+ */
41
+ */
95
+#ifndef NPCM7XX_ADC_H
42
+typedef struct DisasLabel {
96
+#define NPCM7XX_ADC_H
43
+ TCGLabel *label;
44
+ target_ulong pc_save;
45
+} DisasLabel;
97
+
46
+
98
+#include "hw/clock.h"
47
typedef struct DisasContext {
99
+#include "hw/irq.h"
48
DisasContextBase base;
100
+#include "hw/sysbus.h"
49
const ARMISARegisters *isar;
101
+#include "qemu/timer.h"
50
102
+
51
/* The address of the current instruction being translated. */
103
+#define NPCM7XX_ADC_NUM_INPUTS 8
52
target_ulong pc_curr;
104
+/**
53
+ /*
105
+ * This value should not be changed unless write_adc_calibration function in
54
+ * For TARGET_TB_PCREL, the full value of cpu_pc is not known
106
+ * hw/arm/npcm7xx.c is also changed.
55
+ * (although the page offset is known). For convenience, the
56
+ * translation loop uses the full virtual address that triggered
57
+ * the translation, from base.pc_start through pc_curr.
58
+ * For efficiency, we do not update cpu_pc for every instruction.
59
+ * Instead, pc_save has the value of pc_curr at the time of the
60
+ * last update to cpu_pc, which allows us to compute the addend
61
+ * needed to bring cpu_pc current: pc_curr - pc_save.
62
+ * If cpu_pc now contains the destination of an indirect branch,
63
+ * pc_save contains -1 to indicate that relative updates are no
64
+ * longer possible.
65
+ */
66
+ target_ulong pc_save;
67
target_ulong page_start;
68
uint32_t insn;
69
/* Nonzero if this instruction has been conditionally skipped. */
70
int condjmp;
71
/* The label that will be jumped to when the instruction is skipped. */
72
- TCGLabel *condlabel;
73
+ DisasLabel condlabel;
74
/* Thumb-2 conditional execution bits. */
75
int condexec_mask;
76
int condexec_cond;
77
@@ -XXX,XX +XXX,XX @@ typedef struct DisasContext {
78
* after decode (ie after any UNDEF checks)
79
*/
80
bool eci_handled;
81
- /* TCG op to rewind to if this turns out to be an invalid ECI state */
82
- TCGOp *insn_eci_rewind;
83
int sctlr_b;
84
MemOp be_data;
85
#if !defined(CONFIG_USER_ONLY)
86
@@ -XXX,XX +XXX,XX @@ static inline MemOp finalize_memop(DisasContext *s, MemOp opc)
87
*/
88
uint64_t asimd_imm_const(uint32_t imm, int cmode, int op);
89
90
+/*
91
+ * gen_disas_label:
92
+ * Create a label and cache a copy of pc_save.
107
+ */
93
+ */
108
+#define NPCM7XX_ADC_NUM_CALIB 2
94
+static inline DisasLabel gen_disas_label(DisasContext *s)
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
+{
95
+{
225
+ timer_del(&s->conv_timer);
96
+ return (DisasLabel){
226
+ s->con = 0x000c0001;
97
+ .label = gen_new_label(),
227
+ s->data = 0x00000000;
98
+ .pc_save = s->pc_save,
99
+ };
228
+}
100
+}
229
+
101
+
230
+static uint32_t npcm7xx_adc_convert(uint32_t input, uint32_t ref)
102
+/*
103
+ * set_disas_label:
104
+ * Emit a label and restore the cached copy of pc_save.
105
+ */
106
+static inline void set_disas_label(DisasContext *s, DisasLabel l)
231
+{
107
+{
232
+ uint32_t result;
108
+ gen_set_label(l.label);
233
+
109
+ s->pc_save = l.pc_save;
234
+ result = input * (NPCM7XX_ADC_MAX_RESULT + 1) / ref;
235
+ if (result > NPCM7XX_ADC_MAX_RESULT) {
236
+ result = NPCM7XX_ADC_MAX_RESULT;
237
+ }
238
+
239
+ return result;
240
+}
110
+}
241
+
111
+
242
+static uint32_t npcm7xx_adc_prescaler(NPCM7xxADCState *s)
112
/*
243
+{
113
* Helpers for implementing sets of trans_* functions.
244
+ return 2 * (NPCM7XX_ADC_CON_DIV(s->con) + 1);
114
* Defer the implementation of NAME to FUNC, with optional extra arguments.
245
+}
115
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
116
index XXXXXXX..XXXXXXX 100644
117
--- a/target/arm/cpu.c
118
+++ b/target/arm/cpu.c
119
@@ -XXX,XX +XXX,XX @@ static vaddr arm_cpu_get_pc(CPUState *cs)
120
void arm_cpu_synchronize_from_tb(CPUState *cs,
121
const TranslationBlock *tb)
122
{
123
- ARMCPU *cpu = ARM_CPU(cs);
124
- CPUARMState *env = &cpu->env;
125
-
126
- /*
127
- * It's OK to look at env for the current mode here, because it's
128
- * never possible for an AArch64 TB to chain to an AArch32 TB.
129
- */
130
- if (is_a64(env)) {
131
- env->pc = tb_pc(tb);
132
- } else {
133
- env->regs[15] = tb_pc(tb);
134
+ /* The program counter is always up to date with TARGET_TB_PCREL. */
135
+ if (!TARGET_TB_PCREL) {
136
+ CPUARMState *env = cs->env_ptr;
137
+ /*
138
+ * It's OK to look at env for the current mode here, because it's
139
+ * never possible for an AArch64 TB to chain to an AArch32 TB.
140
+ */
141
+ if (is_a64(env)) {
142
+ env->pc = tb_pc(tb);
143
+ } else {
144
+ env->regs[15] = tb_pc(tb);
145
+ }
146
}
147
}
148
#endif /* CONFIG_TCG */
149
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
150
index XXXXXXX..XXXXXXX 100644
151
--- a/target/arm/translate-a64.c
152
+++ b/target/arm/translate-a64.c
153
@@ -XXX,XX +XXX,XX @@ static void reset_btype(DisasContext *s)
154
155
static void gen_pc_plus_diff(DisasContext *s, TCGv_i64 dest, target_long diff)
156
{
157
- tcg_gen_movi_i64(dest, s->pc_curr + diff);
158
+ assert(s->pc_save != -1);
159
+ if (TARGET_TB_PCREL) {
160
+ tcg_gen_addi_i64(dest, cpu_pc, (s->pc_curr - s->pc_save) + diff);
161
+ } else {
162
+ tcg_gen_movi_i64(dest, s->pc_curr + diff);
163
+ }
164
}
165
166
void gen_a64_update_pc(DisasContext *s, target_long diff)
167
{
168
gen_pc_plus_diff(s, cpu_pc, diff);
169
+ s->pc_save = s->pc_curr + diff;
170
}
171
172
/*
173
@@ -XXX,XX +XXX,XX @@ static void gen_a64_set_pc(DisasContext *s, TCGv_i64 src)
174
* then loading an address into the PC will clear out any tag.
175
*/
176
gen_top_byte_ignore(s, cpu_pc, src, s->tbii);
177
+ s->pc_save = -1;
178
}
179
180
/*
181
@@ -XXX,XX +XXX,XX @@ static inline bool use_goto_tb(DisasContext *s, uint64_t dest)
182
183
static void gen_goto_tb(DisasContext *s, int n, int64_t diff)
184
{
185
- uint64_t dest = s->pc_curr + diff;
186
-
187
- if (use_goto_tb(s, dest)) {
188
- tcg_gen_goto_tb(n);
189
- gen_a64_update_pc(s, diff);
190
+ if (use_goto_tb(s, s->pc_curr + diff)) {
191
+ /*
192
+ * For pcrel, the pc must always be up-to-date on entry to
193
+ * the linked TB, so that it can use simple additions for all
194
+ * further adjustments. For !pcrel, the linked TB is compiled
195
+ * to know its full virtual address, so we can delay the
196
+ * update to pc to the unlinked path. A long chain of links
197
+ * can thus avoid many updates to the PC.
198
+ */
199
+ if (TARGET_TB_PCREL) {
200
+ gen_a64_update_pc(s, diff);
201
+ tcg_gen_goto_tb(n);
202
+ } else {
203
+ tcg_gen_goto_tb(n);
204
+ gen_a64_update_pc(s, diff);
205
+ }
206
tcg_gen_exit_tb(s->base.tb, n);
207
s->base.is_jmp = DISAS_NORETURN;
208
} else {
209
@@ -XXX,XX +XXX,XX @@ static void disas_comp_b_imm(DisasContext *s, uint32_t insn)
210
{
211
unsigned int sf, op, rt;
212
int64_t diff;
213
- TCGLabel *label_match;
214
+ DisasLabel match;
215
TCGv_i64 tcg_cmp;
216
217
sf = extract32(insn, 31, 1);
218
@@ -XXX,XX +XXX,XX @@ static void disas_comp_b_imm(DisasContext *s, uint32_t insn)
219
diff = sextract32(insn, 5, 19) * 4;
220
221
tcg_cmp = read_cpu_reg(s, rt, sf);
222
- label_match = gen_new_label();
223
-
224
reset_btype(s);
225
- tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ,
226
- tcg_cmp, 0, label_match);
227
228
+ match = gen_disas_label(s);
229
+ tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ,
230
+ tcg_cmp, 0, match.label);
231
gen_goto_tb(s, 0, 4);
232
- gen_set_label(label_match);
233
+ set_disas_label(s, match);
234
gen_goto_tb(s, 1, diff);
235
}
236
237
@@ -XXX,XX +XXX,XX @@ static void disas_test_b_imm(DisasContext *s, uint32_t insn)
238
{
239
unsigned int bit_pos, op, rt;
240
int64_t diff;
241
- TCGLabel *label_match;
242
+ DisasLabel match;
243
TCGv_i64 tcg_cmp;
244
245
bit_pos = (extract32(insn, 31, 1) << 5) | extract32(insn, 19, 5);
246
@@ -XXX,XX +XXX,XX @@ static void disas_test_b_imm(DisasContext *s, uint32_t insn)
247
248
tcg_cmp = tcg_temp_new_i64();
249
tcg_gen_andi_i64(tcg_cmp, cpu_reg(s, rt), (1ULL << bit_pos));
250
- label_match = gen_new_label();
251
252
reset_btype(s);
246
+
253
+
247
+static void npcm7xx_adc_start_timer(Clock *clk, QEMUTimer *timer,
254
+ match = gen_disas_label(s);
248
+ uint32_t cycles, uint32_t prescaler)
255
tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ,
249
+{
256
- tcg_cmp, 0, label_match);
250
+ int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
257
+ tcg_cmp, 0, match.label);
251
+ int64_t ticks = cycles;
258
tcg_temp_free_i64(tcg_cmp);
252
+ int64_t ns;
259
gen_goto_tb(s, 0, 4);
253
+
260
- gen_set_label(label_match);
254
+ ticks *= prescaler;
261
+ set_disas_label(s, match);
255
+ ns = clock_ticks_to_ns(clk, ticks);
262
gen_goto_tb(s, 1, diff);
256
+ ns += now;
263
}
257
+ timer_mod(timer, ns);
264
258
+}
265
@@ -XXX,XX +XXX,XX @@ static void disas_cond_b_imm(DisasContext *s, uint32_t insn)
259
+
266
reset_btype(s);
260
+static void npcm7xx_adc_start_convert(NPCM7xxADCState *s)
267
if (cond < 0x0e) {
261
+{
268
/* genuinely conditional branches */
262
+ uint32_t prescaler = npcm7xx_adc_prescaler(s);
269
- TCGLabel *label_match = gen_new_label();
263
+
270
- arm_gen_test_cc(cond, label_match);
264
+ npcm7xx_adc_start_timer(s->clock, &s->conv_timer, NPCM7XX_ADC_CONV_CYCLES,
271
+ DisasLabel match = gen_disas_label(s);
265
+ prescaler);
272
+ arm_gen_test_cc(cond, match.label);
266
+}
273
gen_goto_tb(s, 0, 4);
267
+
274
- gen_set_label(label_match);
268
+static void npcm7xx_adc_convert_done(void *opaque)
275
+ set_disas_label(s, match);
269
+{
276
gen_goto_tb(s, 1, diff);
270
+ NPCM7xxADCState *s = opaque;
277
} else {
271
+ uint32_t input = NPCM7XX_ADC_CON_MUX(s->con);
278
/* 0xe and 0xf are both "always" conditions */
272
+ uint32_t ref = (s->con & NPCM7XX_ADC_CON_REFSEL)
279
@@ -XXX,XX +XXX,XX @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
273
+ ? s->iref : s->vref;
280
274
+
281
dc->isar = &arm_cpu->isar;
275
+ if (input >= NPCM7XX_ADC_NUM_INPUTS) {
282
dc->condjmp = 0;
276
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid input: %u\n",
283
-
277
+ __func__, input);
284
+ dc->pc_save = dc->base.pc_first;
278
+ return;
285
dc->aarch64 = true;
286
dc->thumb = false;
287
dc->sctlr_b = 0;
288
@@ -XXX,XX +XXX,XX @@ static void aarch64_tr_tb_start(DisasContextBase *db, CPUState *cpu)
289
static void aarch64_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
290
{
291
DisasContext *dc = container_of(dcbase, DisasContext, base);
292
+ target_ulong pc_arg = dc->base.pc_next;
293
294
- tcg_gen_insn_start(dc->base.pc_next, 0, 0);
295
+ if (TARGET_TB_PCREL) {
296
+ pc_arg &= ~TARGET_PAGE_MASK;
279
+ }
297
+ }
280
+ s->data = npcm7xx_adc_convert(s->adci[input], ref);
298
+ tcg_gen_insn_start(pc_arg, 0, 0);
281
+ if (s->con & NPCM7XX_ADC_CON_INT_EN) {
299
dc->insn_start = tcg_last_op();
282
+ s->con |= NPCM7XX_ADC_CON_INT;
300
}
283
+ qemu_irq_raise(s->irq);
301
302
diff --git a/target/arm/translate-m-nocp.c b/target/arm/translate-m-nocp.c
303
index XXXXXXX..XXXXXXX 100644
304
--- a/target/arm/translate-m-nocp.c
305
+++ b/target/arm/translate-m-nocp.c
306
@@ -XXX,XX +XXX,XX @@ static bool trans_VSCCLRM(DisasContext *s, arg_VSCCLRM *a)
307
tcg_gen_andi_i32(sfpa, sfpa, R_V7M_CONTROL_SFPA_MASK);
308
tcg_gen_or_i32(sfpa, sfpa, aspen);
309
arm_gen_condlabel(s);
310
- tcg_gen_brcondi_i32(TCG_COND_EQ, sfpa, 0, s->condlabel);
311
+ tcg_gen_brcondi_i32(TCG_COND_EQ, sfpa, 0, s->condlabel.label);
312
313
if (s->fp_excp_el != 0) {
314
gen_exception_insn_el(s, 0, EXCP_NOCP,
315
diff --git a/target/arm/translate.c b/target/arm/translate.c
316
index XXXXXXX..XXXXXXX 100644
317
--- a/target/arm/translate.c
318
+++ b/target/arm/translate.c
319
@@ -XXX,XX +XXX,XX @@ uint64_t asimd_imm_const(uint32_t imm, int cmode, int op)
320
void arm_gen_condlabel(DisasContext *s)
321
{
322
if (!s->condjmp) {
323
- s->condlabel = gen_new_label();
324
+ s->condlabel = gen_disas_label(s);
325
s->condjmp = 1;
326
}
327
}
328
@@ -XXX,XX +XXX,XX @@ static target_long jmp_diff(DisasContext *s, target_long diff)
329
330
static void gen_pc_plus_diff(DisasContext *s, TCGv_i32 var, target_long diff)
331
{
332
- tcg_gen_movi_i32(var, s->pc_curr + diff);
333
+ assert(s->pc_save != -1);
334
+ if (TARGET_TB_PCREL) {
335
+ tcg_gen_addi_i32(var, cpu_R[15], (s->pc_curr - s->pc_save) + diff);
336
+ } else {
337
+ tcg_gen_movi_i32(var, s->pc_curr + diff);
284
+ }
338
+ }
285
+ s->con &= ~NPCM7XX_ADC_CON_CONV;
339
}
286
+}
340
287
+
341
/* Set a variable to the value of a CPU register. */
288
+static void npcm7xx_adc_calibrate(NPCM7xxADCState *adc)
342
@@ -XXX,XX +XXX,XX @@ void store_reg(DisasContext *s, int reg, TCGv_i32 var)
289
+{
343
*/
290
+ adc->calibration_r_values[0] = npcm7xx_adc_convert(NPCM7XX_ADC_R0_INPUT,
344
tcg_gen_andi_i32(var, var, s->thumb ? ~1 : ~3);
291
+ adc->iref);
345
s->base.is_jmp = DISAS_JUMP;
292
+ adc->calibration_r_values[1] = npcm7xx_adc_convert(NPCM7XX_ADC_R1_INPUT,
346
+ s->pc_save = -1;
293
+ adc->iref);
347
} else if (reg == 13 && arm_dc_feature(s, ARM_FEATURE_M)) {
294
+}
348
/* For M-profile SP bits [1:0] are always zero */
295
+
349
tcg_gen_andi_i32(var, var, ~3);
296
+static void npcm7xx_adc_write_con(NPCM7xxADCState *s, uint32_t new_con)
350
@@ -XXX,XX +XXX,XX @@ void gen_set_condexec(DisasContext *s)
297
+{
351
298
+ uint32_t old_con = s->con;
352
void gen_update_pc(DisasContext *s, target_long diff)
299
+
353
{
300
+ /* Write ADC_INT to 1 to clear it */
354
- tcg_gen_movi_i32(cpu_R[15], s->pc_curr + diff);
301
+ if (new_con & NPCM7XX_ADC_CON_INT) {
355
+ gen_pc_plus_diff(s, cpu_R[15], diff);
302
+ new_con &= ~NPCM7XX_ADC_CON_INT;
356
+ s->pc_save = s->pc_curr + diff;
303
+ qemu_irq_lower(s->irq);
357
}
304
+ } else if (old_con & NPCM7XX_ADC_CON_INT) {
358
305
+ new_con |= NPCM7XX_ADC_CON_INT;
359
/* Set PC and Thumb state from var. var is marked as dead. */
360
@@ -XXX,XX +XXX,XX @@ static inline void gen_bx(DisasContext *s, TCGv_i32 var)
361
tcg_gen_andi_i32(cpu_R[15], var, ~1);
362
tcg_gen_andi_i32(var, var, 1);
363
store_cpu_field(var, thumb);
364
+ s->pc_save = -1;
365
}
366
367
/*
368
@@ -XXX,XX +XXX,XX @@ static inline void gen_bx_excret(DisasContext *s, TCGv_i32 var)
369
static inline void gen_bx_excret_final_code(DisasContext *s)
370
{
371
/* Generate the code to finish possible exception return and end the TB */
372
- TCGLabel *excret_label = gen_new_label();
373
+ DisasLabel excret_label = gen_disas_label(s);
374
uint32_t min_magic;
375
376
if (arm_dc_feature(s, ARM_FEATURE_M_SECURITY)) {
377
@@ -XXX,XX +XXX,XX @@ static inline void gen_bx_excret_final_code(DisasContext *s)
378
}
379
380
/* Is the new PC value in the magic range indicating exception return? */
381
- tcg_gen_brcondi_i32(TCG_COND_GEU, cpu_R[15], min_magic, excret_label);
382
+ tcg_gen_brcondi_i32(TCG_COND_GEU, cpu_R[15], min_magic, excret_label.label);
383
/* No: end the TB as we would for a DISAS_JMP */
384
if (s->ss_active) {
385
gen_singlestep_exception(s);
386
} else {
387
tcg_gen_exit_tb(NULL, 0);
388
}
389
- gen_set_label(excret_label);
390
+ set_disas_label(s, excret_label);
391
/* Yes: this is an exception return.
392
* At this point in runtime env->regs[15] and env->thumb will hold
393
* the exception-return magic number, which do_v7m_exception_exit()
394
@@ -XXX,XX +XXX,XX @@ static void gen_goto_ptr(void)
395
*/
396
static void gen_goto_tb(DisasContext *s, int n, target_long diff)
397
{
398
- target_ulong dest = s->pc_curr + diff;
399
-
400
- if (translator_use_goto_tb(&s->base, dest)) {
401
- tcg_gen_goto_tb(n);
402
- gen_update_pc(s, diff);
403
+ if (translator_use_goto_tb(&s->base, s->pc_curr + diff)) {
404
+ /*
405
+ * For pcrel, the pc must always be up-to-date on entry to
406
+ * the linked TB, so that it can use simple additions for all
407
+ * further adjustments. For !pcrel, the linked TB is compiled
408
+ * to know its full virtual address, so we can delay the
409
+ * update to pc to the unlinked path. A long chain of links
410
+ * can thus avoid many updates to the PC.
411
+ */
412
+ if (TARGET_TB_PCREL) {
413
+ gen_update_pc(s, diff);
414
+ tcg_gen_goto_tb(n);
415
+ } else {
416
+ tcg_gen_goto_tb(n);
417
+ gen_update_pc(s, diff);
418
+ }
419
tcg_gen_exit_tb(s->base.tb, n);
420
} else {
421
gen_update_pc(s, diff);
422
@@ -XXX,XX +XXX,XX @@ static void gen_srs(DisasContext *s,
423
static void arm_skip_unless(DisasContext *s, uint32_t cond)
424
{
425
arm_gen_condlabel(s);
426
- arm_gen_test_cc(cond ^ 1, s->condlabel);
427
+ arm_gen_test_cc(cond ^ 1, s->condlabel.label);
428
}
429
430
431
@@ -XXX,XX +XXX,XX @@ static bool trans_WLS(DisasContext *s, arg_WLS *a)
432
{
433
/* M-profile low-overhead while-loop start */
434
TCGv_i32 tmp;
435
- TCGLabel *nextlabel;
436
+ DisasLabel nextlabel;
437
438
if (!dc_isar_feature(aa32_lob, s)) {
439
return false;
440
@@ -XXX,XX +XXX,XX @@ static bool trans_WLS(DisasContext *s, arg_WLS *a)
441
}
442
}
443
444
- nextlabel = gen_new_label();
445
- tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_R[a->rn], 0, nextlabel);
446
+ nextlabel = gen_disas_label(s);
447
+ tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_R[a->rn], 0, nextlabel.label);
448
tmp = load_reg(s, a->rn);
449
store_reg(s, 14, tmp);
450
if (a->size != 4) {
451
@@ -XXX,XX +XXX,XX @@ static bool trans_WLS(DisasContext *s, arg_WLS *a)
452
}
453
gen_jmp_tb(s, curr_insn_len(s), 1);
454
455
- gen_set_label(nextlabel);
456
+ set_disas_label(s, nextlabel);
457
gen_jmp(s, jmp_diff(s, a->imm));
458
return true;
459
}
460
@@ -XXX,XX +XXX,XX @@ static bool trans_LE(DisasContext *s, arg_LE *a)
461
* any faster.
462
*/
463
TCGv_i32 tmp;
464
- TCGLabel *loopend;
465
+ DisasLabel loopend;
466
bool fpu_active;
467
468
if (!dc_isar_feature(aa32_lob, s)) {
469
@@ -XXX,XX +XXX,XX @@ static bool trans_LE(DisasContext *s, arg_LE *a)
470
471
if (!a->tp && dc_isar_feature(aa32_mve, s) && fpu_active) {
472
/* Need to do a runtime check for LTPSIZE != 4 */
473
- TCGLabel *skipexc = gen_new_label();
474
+ DisasLabel skipexc = gen_disas_label(s);
475
tmp = load_cpu_field(v7m.ltpsize);
476
- tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 4, skipexc);
477
+ tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 4, skipexc.label);
478
tcg_temp_free_i32(tmp);
479
gen_exception_insn(s, 0, EXCP_INVSTATE, syn_uncategorized());
480
- gen_set_label(skipexc);
481
+ set_disas_label(s, skipexc);
482
}
483
484
if (a->f) {
485
@@ -XXX,XX +XXX,XX @@ static bool trans_LE(DisasContext *s, arg_LE *a)
486
* loop decrement value is 1. For LETP we need to calculate the decrement
487
* value from LTPSIZE.
488
*/
489
- loopend = gen_new_label();
490
+ loopend = gen_disas_label(s);
491
if (!a->tp) {
492
- tcg_gen_brcondi_i32(TCG_COND_LEU, cpu_R[14], 1, loopend);
493
+ tcg_gen_brcondi_i32(TCG_COND_LEU, cpu_R[14], 1, loopend.label);
494
tcg_gen_addi_i32(cpu_R[14], cpu_R[14], -1);
495
} else {
496
/*
497
@@ -XXX,XX +XXX,XX @@ static bool trans_LE(DisasContext *s, arg_LE *a)
498
tcg_gen_shl_i32(decr, tcg_constant_i32(1), decr);
499
tcg_temp_free_i32(ltpsize);
500
501
- tcg_gen_brcond_i32(TCG_COND_LEU, cpu_R[14], decr, loopend);
502
+ tcg_gen_brcond_i32(TCG_COND_LEU, cpu_R[14], decr, loopend.label);
503
504
tcg_gen_sub_i32(cpu_R[14], cpu_R[14], decr);
505
tcg_temp_free_i32(decr);
506
@@ -XXX,XX +XXX,XX @@ static bool trans_LE(DisasContext *s, arg_LE *a)
507
/* Jump back to the loop start */
508
gen_jmp(s, jmp_diff(s, -a->imm));
509
510
- gen_set_label(loopend);
511
+ set_disas_label(s, loopend);
512
if (a->tp) {
513
/* Exits from tail-pred loops must reset LTPSIZE to 4 */
514
store_cpu_field(tcg_constant_i32(4), v7m.ltpsize);
515
@@ -XXX,XX +XXX,XX @@ static bool trans_CBZ(DisasContext *s, arg_CBZ *a)
516
517
arm_gen_condlabel(s);
518
tcg_gen_brcondi_i32(a->nz ? TCG_COND_EQ : TCG_COND_NE,
519
- tmp, 0, s->condlabel);
520
+ tmp, 0, s->condlabel.label);
521
tcg_temp_free_i32(tmp);
522
gen_jmp(s, jmp_diff(s, a->imm));
523
return true;
524
@@ -XXX,XX +XXX,XX @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
525
526
dc->isar = &cpu->isar;
527
dc->condjmp = 0;
528
-
529
+ dc->pc_save = dc->base.pc_first;
530
dc->aarch64 = false;
531
dc->thumb = EX_TBFLAG_AM32(tb_flags, THUMB);
532
dc->be_data = EX_TBFLAG_ANY(tb_flags, BE_DATA) ? MO_BE : MO_LE;
533
@@ -XXX,XX +XXX,XX @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
534
*/
535
dc->eci = dc->condexec_mask = dc->condexec_cond = 0;
536
dc->eci_handled = false;
537
- dc->insn_eci_rewind = NULL;
538
if (condexec & 0xf) {
539
dc->condexec_mask = (condexec & 0xf) << 1;
540
dc->condexec_cond = condexec >> 4;
541
@@ -XXX,XX +XXX,XX @@ static void arm_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
542
* fields here.
543
*/
544
uint32_t condexec_bits;
545
+ target_ulong pc_arg = dc->base.pc_next;
546
547
+ if (TARGET_TB_PCREL) {
548
+ pc_arg &= ~TARGET_PAGE_MASK;
306
+ }
549
+ }
307
+
550
if (dc->eci) {
308
+ s->con = new_con;
551
condexec_bits = dc->eci << 4;
309
+
552
} else {
310
+ if (s->con & NPCM7XX_ADC_CON_RST) {
553
condexec_bits = (dc->condexec_cond << 4) | (dc->condexec_mask >> 1);
311
+ npcm7xx_adc_reset(s);
554
}
312
+ return;
555
- tcg_gen_insn_start(dc->base.pc_next, condexec_bits, 0);
313
+ }
556
+ tcg_gen_insn_start(pc_arg, condexec_bits, 0);
314
+
557
dc->insn_start = tcg_last_op();
315
+ if ((s->con & NPCM7XX_ADC_CON_EN)) {
558
}
316
+ if (s->con & NPCM7XX_ADC_CON_CONV) {
559
317
+ if (!(old_con & NPCM7XX_ADC_CON_CONV)) {
560
@@ -XXX,XX +XXX,XX @@ static bool arm_check_ss_active(DisasContext *dc)
318
+ npcm7xx_adc_start_convert(s);
561
319
+ }
562
static void arm_post_translate_insn(DisasContext *dc)
563
{
564
- if (dc->condjmp && !dc->base.is_jmp) {
565
- gen_set_label(dc->condlabel);
566
+ if (dc->condjmp && dc->base.is_jmp == DISAS_NEXT) {
567
+ if (dc->pc_save != dc->condlabel.pc_save) {
568
+ gen_update_pc(dc, dc->condlabel.pc_save - dc->pc_save);
569
+ }
570
+ gen_set_label(dc->condlabel.label);
571
dc->condjmp = 0;
572
}
573
translator_loop_temp_check(&dc->base);
574
@@ -XXX,XX +XXX,XX @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
575
uint32_t pc = dc->base.pc_next;
576
uint32_t insn;
577
bool is_16bit;
578
+ /* TCG op to rewind to if this turns out to be an invalid ECI state */
579
+ TCGOp *insn_eci_rewind = NULL;
580
+ target_ulong insn_eci_pc_save = -1;
581
582
/* Misaligned thumb PC is architecturally impossible. */
583
assert((dc->base.pc_next & 1) == 0);
584
@@ -XXX,XX +XXX,XX @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
585
* insn" case. We will rewind to the marker (ie throwing away
586
* all the generated code) and instead emit "take exception".
587
*/
588
- dc->insn_eci_rewind = tcg_last_op();
589
+ insn_eci_rewind = tcg_last_op();
590
+ insn_eci_pc_save = dc->pc_save;
591
}
592
593
if (dc->condexec_mask && !thumb_insn_is_unconditional(dc, insn)) {
594
@@ -XXX,XX +XXX,XX @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
595
* Insn wasn't valid for ECI/ICI at all: undo what we
596
* just generated and instead emit an exception
597
*/
598
- tcg_remove_ops_after(dc->insn_eci_rewind);
599
+ tcg_remove_ops_after(insn_eci_rewind);
600
+ dc->pc_save = insn_eci_pc_save;
601
dc->condjmp = 0;
602
gen_exception_insn(dc, 0, EXCP_INVSTATE, syn_uncategorized());
603
}
604
@@ -XXX,XX +XXX,XX @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
605
606
if (dc->condjmp) {
607
/* "Condition failed" instruction codepath for the branch/trap insn */
608
- gen_set_label(dc->condlabel);
609
+ set_disas_label(dc, dc->condlabel);
610
gen_set_condexec(dc);
611
if (unlikely(dc->ss_active)) {
612
gen_update_pc(dc, curr_insn_len(dc));
613
@@ -XXX,XX +XXX,XX @@ void restore_state_to_opc(CPUARMState *env, TranslationBlock *tb,
614
target_ulong *data)
615
{
616
if (is_a64(env)) {
617
- env->pc = data[0];
618
+ if (TARGET_TB_PCREL) {
619
+ env->pc = (env->pc & TARGET_PAGE_MASK) | data[0];
320
+ } else {
620
+ } else {
321
+ timer_del(&s->conv_timer);
621
+ env->pc = data[0];
322
+ }
622
+ }
323
+ }
623
env->condexec_bits = 0;
324
+}
624
env->exception.syndrome = data[2] << ARM_INSN_START_WORD2_SHIFT;
325
+
625
} else {
326
+static uint64_t npcm7xx_adc_read(void *opaque, hwaddr offset, unsigned size)
626
- env->regs[15] = data[0];
327
+{
627
+ if (TARGET_TB_PCREL) {
328
+ uint64_t value = 0;
628
+ env->regs[15] = (env->regs[15] & TARGET_PAGE_MASK) | data[0];
329
+ NPCM7xxADCState *s = opaque;
629
+ } else {
330
+
630
+ env->regs[15] = data[0];
331
+ switch (offset) {
332
+ case A_NPCM7XX_ADC_CON:
333
+ value = s->con;
334
+ break;
335
+
336
+ case A_NPCM7XX_ADC_DATA:
337
+ value = s->data;
338
+ break;
339
+
340
+ default:
341
+ qemu_log_mask(LOG_GUEST_ERROR,
342
+ "%s: invalid offset 0x%04" HWADDR_PRIx "\n",
343
+ __func__, offset);
344
+ break;
345
+ }
346
+
347
+ trace_npcm7xx_adc_read(DEVICE(s)->canonical_path, offset, value);
348
+ return value;
349
+}
350
+
351
+static void npcm7xx_adc_write(void *opaque, hwaddr offset, uint64_t v,
352
+ unsigned size)
353
+{
354
+ NPCM7xxADCState *s = opaque;
355
+
356
+ trace_npcm7xx_adc_write(DEVICE(s)->canonical_path, offset, v);
357
+ switch (offset) {
358
+ case A_NPCM7XX_ADC_CON:
359
+ npcm7xx_adc_write_con(s, v);
360
+ break;
361
+
362
+ case A_NPCM7XX_ADC_DATA:
363
+ qemu_log_mask(LOG_GUEST_ERROR,
364
+ "%s: register @ 0x%04" HWADDR_PRIx " is read-only\n",
365
+ __func__, offset);
366
+ break;
367
+
368
+ default:
369
+ qemu_log_mask(LOG_GUEST_ERROR,
370
+ "%s: invalid offset 0x%04" HWADDR_PRIx "\n",
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
}
509
510
+static void npcm7xx_write_adc_calibration(NPCM7xxState *s)
511
+{
512
+ /* Both ADC and the fuse array must have realized. */
513
+ QEMU_BUILD_BUG_ON(sizeof(s->adc.calibration_r_values) != 4);
514
+ npcm7xx_otp_array_write(&s->fuse_array, s->adc.calibration_r_values,
515
+ NPCM7XX_FUSE_ADC_CALIB, sizeof(s->adc.calibration_r_values));
516
+}
517
+
518
static qemu_irq npcm7xx_irq(NPCM7xxState *s, int n)
519
{
520
return qdev_get_gpio_in(DEVICE(&s->a9mpcore), n);
521
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
522
TYPE_NPCM7XX_FUSE_ARRAY);
523
object_initialize_child(obj, "mc", &s->mc, TYPE_NPCM7XX_MC);
524
object_initialize_child(obj, "rng", &s->rng, TYPE_NPCM7XX_RNG);
525
+ object_initialize_child(obj, "adc", &s->adc, TYPE_NPCM7XX_ADC);
526
527
for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
528
object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER);
529
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
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
+ }
631
+ }
784
+ }
632
env->condexec_bits = data[1];
785
+
633
env->exception.syndrome = data[2] << ARM_INSN_START_WORD2_SHIFT;
786
+ qtest_quit(qts);
634
}
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
--
635
--
969
2.20.1
636
2.25.1
970
971
diff view generated by jsdifflib
1
In commit 1982e1602d15 we added a new qemu-storage-daemon(1) manpage.
1
Currently the microdrive code uses device_legacy_reset() to reset
2
At the moment new manpages have to be listed both in the conf.py for
2
itself, and has its reset method call reset on the IDE bus as the
3
Sphinx and also in docs/meson.build for Meson. We forgot the second
3
last thing it does. Switch to using device_cold_reset().
4
of those -- correct the omission.
4
5
The only concrete microdrive device is the TYPE_DSCM1XXXX; it is not
6
command-line pluggable, so it is used only by the old pxa2xx Arm
7
boards 'akita', 'borzoi', 'spitz', 'terrier' and 'tosa'.
8
9
You might think that this would result in the IDE bus being
10
reset automatically, but it does not, because the IDEBus type
11
does not set the BusClass::reset method. Instead the controller
12
must explicitly call ide_bus_reset(). We therefore leave that
13
call in md_reset().
14
15
Note also that because the PCMCIA card device is a direct subclass of
16
TYPE_DEVICE and we don't model the PCMCIA controller-to-card
17
interface as a qbus, PCMCIA cards are not on any qbus and so they
18
don't get reset when the system is reset. The reset only happens via
19
the dscm1xxxx_attach() and dscm1xxxx_detach() functions during
20
machine creation.
21
22
Because our aim here is merely to try to get rid of calls to the
23
device_legacy_reset() function, we leave these other dubious
24
reset-related issues alone. (They all stem from this code being
25
absolutely ancient.)
5
26
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
27
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
28
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
8
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
29
Message-id: 20221013174042.1602926-1-peter.maydell@linaro.org
9
Message-id: 20210108161416.21129-2-peter.maydell@linaro.org
10
---
30
---
11
docs/meson.build | 1 +
31
hw/ide/microdrive.c | 8 ++++----
12
1 file changed, 1 insertion(+)
32
1 file changed, 4 insertions(+), 4 deletions(-)
13
33
14
diff --git a/docs/meson.build b/docs/meson.build
34
diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c
15
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
16
--- a/docs/meson.build
36
--- a/hw/ide/microdrive.c
17
+++ b/docs/meson.build
37
+++ b/hw/ide/microdrive.c
18
@@ -XXX,XX +XXX,XX @@ if build_docs
38
@@ -XXX,XX +XXX,XX @@ static void md_attr_write(PCMCIACardState *card, uint32_t at, uint8_t value)
19
'qemu-img.1': (have_tools ? 'man1' : ''),
39
case 0x00:    /* Configuration Option Register */
20
'qemu-nbd.8': (have_tools ? 'man8' : ''),
40
s->opt = value & 0xcf;
21
'qemu-pr-helper.8': (have_tools ? 'man8' : ''),
41
if (value & OPT_SRESET) {
22
+ 'qemu-storage-daemon.1': (have_tools ? 'man1' : ''),
42
- device_legacy_reset(DEVICE(s));
23
'qemu-trace-stap.1': (config_host.has_key('CONFIG_TRACE_SYSTEMTAP') ? 'man1' : ''),
43
+ device_cold_reset(DEVICE(s));
24
'virtfs-proxy-helper.1': (have_virtfs_proxy_helper ? 'man1' : ''),
44
}
25
'virtiofsd.1': (have_virtiofsd ? 'man1' : ''),
45
md_interrupt_update(s);
46
break;
47
@@ -XXX,XX +XXX,XX @@ static void md_common_write(PCMCIACardState *card, uint32_t at, uint16_t value)
48
case 0xe:    /* Device Control */
49
s->ctrl = value;
50
if (value & CTRL_SRST) {
51
- device_legacy_reset(DEVICE(s));
52
+ device_cold_reset(DEVICE(s));
53
}
54
md_interrupt_update(s);
55
break;
56
@@ -XXX,XX +XXX,XX @@ static int dscm1xxxx_attach(PCMCIACardState *card)
57
md->attr_base = pcc->cis[0x74] | (pcc->cis[0x76] << 8);
58
md->io_base = 0x0;
59
60
- device_legacy_reset(DEVICE(md));
61
+ device_cold_reset(DEVICE(md));
62
md_interrupt_update(md);
63
64
return 0;
65
@@ -XXX,XX +XXX,XX @@ static int dscm1xxxx_detach(PCMCIACardState *card)
66
{
67
MicroDriveState *md = MICRODRIVE(card);
68
69
- device_legacy_reset(DEVICE(md));
70
+ device_cold_reset(DEVICE(md));
71
return 0;
72
}
73
26
--
74
--
27
2.20.1
75
2.25.1
28
76
29
77
diff view generated by jsdifflib