Skip to content

Commit 1fc66b0

Browse files
update core register management
- register alignment to gdb feature names - correct cache handling for banked SP registers - support for secure/non-secure CONTROL, FAULTMASK, BASEPRI, and PRIMASK
1 parent 7e600ef commit 1fc66b0

File tree

7 files changed

+226
-205
lines changed

7 files changed

+226
-205
lines changed

pyocd/cache/register.py

Lines changed: 64 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# pyOCD debugger
2-
# Copyright (c) 2016-2020 Arm Limited
2+
# Copyright (c) 2016-2020,2025 Arm Limited
33
# SPDX-License-Identifier: Apache-2.0
44
#
55
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -35,26 +35,27 @@ class RegisterCache(object):
3535
Same logic applies for XPSR submasks.
3636
"""
3737

38-
CFBP_INDEX = index_for_reg('cfbp')
38+
CFBP_INDEX_LIST = [
39+
index_for_reg('cfbp'),
40+
index_for_reg('cfbp_s'),
41+
index_for_reg('cfbp_ns')
42+
]
43+
44+
CFBP_REGS_LIST = [
45+
[index_for_reg(name) for name in ['control', 'faultmask', 'basepri', 'primask' ]],
46+
[index_for_reg(name) for name in ['control_s', 'faultmask_s', 'basepri_s', 'primask_s' ]],
47+
[index_for_reg(name) for name in ['control_ns', 'faultmask_ns', 'basepri_ns', 'primask_ns']]
48+
]
49+
3950
XPSR_INDEX = index_for_reg('xpsr')
4051

41-
CFBP_REGS = [index_for_reg(name) for name in [
42-
'cfbp',
43-
'control',
44-
'faultmask',
45-
'basepri',
46-
'primask',
47-
]]
48-
49-
XPSR_REGS = [index_for_reg(name) for name in [
50-
'xpsr',
51-
'apsr',
52-
'iapsr',
53-
'eapsr',
54-
'ipsr',
55-
'epsr',
56-
'iepsr',
57-
]]
52+
XPSR_REGS = [
53+
index_for_reg(name) for name in ['apsr', 'iapsr', 'eapsr', 'ipsr', 'epsr', 'iepsr']
54+
]
55+
56+
SP_REGS = [
57+
index_for_reg(name) for name in ['sp', 'msp', 'psp', 'msp_s', 'psp_s', 'msp_ns', 'psp_ns']
58+
]
5859

5960
def __init__(self, context, core):
6061
self._context = context
@@ -103,18 +104,20 @@ def read_core_registers_raw(self, reg_list):
103104
cached_set = set(r for r in reg_list if r in self._cache)
104105
self._metrics.hits += len(cached_set)
105106

106-
# Read uncached registers from the target.
107+
# Create list of uncached registers.
107108
read_list = list(reg_set.difference(cached_set))
108-
reading_cfbp = any(r for r in read_list if r in self.CFBP_REGS)
109-
reading_xpsr = any(r for r in read_list if r in self.XPSR_REGS)
110-
if reading_cfbp:
111-
if not self.CFBP_INDEX in read_list:
112-
read_list.append(self.CFBP_INDEX)
113-
cfbp_index = read_list.index(self.CFBP_INDEX)
114-
if reading_xpsr:
115-
if not self.XPSR_INDEX in read_list:
116-
read_list.append(self.XPSR_INDEX)
117-
xpsr_index = read_list.index(self.XPSR_INDEX)
109+
110+
read_cfbp_flags = []
111+
for index, regs in zip(self.CFBP_INDEX_LIST, self.CFBP_REGS_LIST):
112+
read_cfpb = any(r for r in read_list if r in regs or r == index)
113+
read_cfbp_flags.append(read_cfpb)
114+
if read_cfpb and index not in read_list:
115+
read_list.append(index)
116+
117+
read_xpsr = any(r for r in read_list if r in self.XPSR_REGS or r == self.XPSR_INDEX)
118+
if read_xpsr and self.XPSR_INDEX not in read_list:
119+
read_list.append(self.XPSR_INDEX)
120+
118121
self._metrics.misses += len(read_list)
119122

120123
# Read registers not in the cache from the target.
@@ -129,21 +132,20 @@ def read_core_registers_raw(self, reg_list):
129132
values = []
130133

131134
# Update all CFBP based registers.
132-
if reading_cfbp:
133-
v = values[cfbp_index]
134-
self._cache[self.CFBP_INDEX] = v
135-
for r in self.CFBP_REGS:
136-
if r == self.CFBP_INDEX:
137-
continue
138-
self._cache[r] = (v >> ((-r - 1) * 8)) & 0xff
135+
for read_cfbp, index, regs in zip(read_cfbp_flags, self.CFBP_INDEX_LIST, self.CFBP_REGS_LIST):
136+
if read_cfbp:
137+
i = read_list.index(index)
138+
v = values[i]
139+
self._cache[index] = v
140+
for r in regs:
141+
self._cache[r] = (v >> ((r & 3) * 8)) & 0xff
139142

140143
# Update all XPSR based registers.
141-
if reading_xpsr:
142-
v = values[xpsr_index]
144+
if read_xpsr:
145+
i = read_list.index(self.XPSR_INDEX)
146+
v = values[i]
143147
self._cache[self.XPSR_INDEX] = v
144148
for r in self.XPSR_REGS:
145-
if r == self.XPSR_INDEX:
146-
continue
147149
self._cache[r] = v & CortexMCoreRegisterInfo.get(r).psr_mask
148150

149151
# Build the results list in the same order as requested registers.
@@ -170,21 +172,34 @@ def write_core_registers_raw(self, reg_list, data_list):
170172
reg_list = self._convert_and_check_registers(reg_list)
171173
self._metrics.writes += len(reg_list)
172174

173-
writing_cfbp = any(r for r in reg_list if r in self.CFBP_REGS)
174-
writing_xpsr = any(r for r in reg_list if r in self.XPSR_REGS)
175-
176175
# Update cached register values.
177176
for i, r in enumerate(reg_list):
178177
v = data_list[i]
179178
self._cache[r] = v
180179

181-
# Just remove all cached CFBP and XPSR based register values.
182-
if writing_cfbp:
183-
for r in self.CFBP_REGS:
180+
# Remove cached CFBP based register values when writing to them.
181+
if any(r for r in reg_list if r in self.CFBP_INDEX_LIST):
182+
# If writing to any variant of CFBP register, remove all CFBP based registers from the cache.
183+
for index, regs in zip(self.CFBP_INDEX_LIST, self.CFBP_REGS_LIST):
184+
for r in regs + [index]:
185+
self._cache.pop(r, None)
186+
else:
187+
# If writing to any variant of CFBP sub-register (CONTROL, FAULTMASK, BASEPRI, PRIMASK),
188+
# remove only variants of that sub-register from the cache.
189+
for pos in range(len(self.CFBP_REGS_LIST[0])):
190+
sub_regs = [regs[pos] for regs in self.CFBP_REGS_LIST]
191+
if any(r in sub_regs for r in reg_list):
192+
for r in sub_regs:
193+
self._cache.pop(r, None)
194+
195+
# Remove all cached XPSR based register values when writing any of them.
196+
if any(r for r in reg_list if r in self.XPSR_REGS or r == self.XPSR_INDEX):
197+
for r in self.XPSR_REGS + [self.XPSR_INDEX]:
184198
self._cache.pop(r, None)
185199

186-
if writing_xpsr:
187-
for r in self.XPSR_REGS:
200+
# Remove all cached SP register values when writing any of them.
201+
if any(r for r in reg_list if r in self.SP_REGS):
202+
for r in self.SP_REGS:
188203
self._cache.pop(r, None)
189204

190205
# Write new register values to target.
@@ -197,4 +212,3 @@ def write_core_registers_raw(self, reg_list, data_list):
197212

198213
def invalidate(self):
199214
self._reset_cache()
200-

pyocd/coresight/cortex_m.py

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,7 +1326,7 @@ def _base_read_core_registers_raw(self, reg_list: List[int]) -> List[int]:
13261326
reg_cb_list = []
13271327
for reg in reg_list:
13281328
if CortexMCoreRegisterInfo.get(reg).is_cfbp_subregister:
1329-
reg = CortexMCoreRegisterInfo.get('cfbp').index
1329+
reg = reg >> 8
13301330
elif CortexMCoreRegisterInfo.get(reg).is_psr_subregister:
13311331
reg = CortexMCoreRegisterInfo.get('xpsr').index
13321332

@@ -1353,7 +1353,7 @@ def _base_read_core_registers_raw(self, reg_list: List[int]) -> List[int]:
13531353

13541354
# Special handling for registers that are combined into a single DCRSR number.
13551355
if CortexMCoreRegisterInfo.get(reg).is_cfbp_subregister:
1356-
val = (val >> ((-reg - 1) * 8)) & 0xff
1356+
val = (val >> ((reg & 3) * 8)) & 0xff
13571357
elif CortexMCoreRegisterInfo.get(reg).is_psr_subregister:
13581358
val &= CortexMCoreRegisterInfo.get(reg).psr_mask
13591359

@@ -1455,44 +1455,53 @@ def _base_write_core_registers_raw(self, reg_list: Sequence[int], data_list: Seq
14551455

14561456
# Read special register if it is present in the list and
14571457
# convert doubles to single float register writes.
1458-
cfbpValue = None
14591458
xpsrValue = None
14601459
reg_data_list = []
1460+
reg_data_list_extra = []
14611461
for reg, data in zip(reg_list, data_list):
14621462
if CortexMCoreRegisterInfo.get(reg).is_double_float_register:
14631463
# Replace double with two single float register writes. For instance,
14641464
# a write of D2 gets converted to writes to S4 and S5.
14651465
singleLow = data & 0xffffffff
14661466
singleHigh = (data >> 32) & 0xffffffff
14671467
reg_data_list += [(-reg, singleLow), (-reg + 1, singleHigh)]
1468-
elif CortexMCoreRegisterInfo.get(reg).is_cfbp_subregister and cfbpValue is None:
1469-
cfbpValue = self._base_read_core_registers_raw([CortexMCoreRegisterInfo.get('cfbp').index])[0]
1470-
reg_data_list.append((reg, data))
1471-
elif CortexMCoreRegisterInfo.get(reg).is_psr_subregister and xpsrValue is None:
1472-
xpsrValue = self._base_read_core_registers_raw([CortexMCoreRegisterInfo.get('xpsr').index])[0]
1473-
reg_data_list.append((reg, data))
1468+
elif CortexMCoreRegisterInfo.get(reg).is_cfbp_subregister:
1469+
read_reg32 = True
1470+
shift = (reg & 3) * 8
1471+
mask = 0xffffffff ^ (0xff << shift)
1472+
for i, (reg32, data32) in enumerate(reg_data_list_extra):
1473+
if reg32 == (reg >> 8):
1474+
# Already have a write for this register, just update the byte.
1475+
data32 = (data32 & mask) | ((data & 0xff) << shift)
1476+
reg_data_list_extra[i] = (reg32, data32)
1477+
read_reg32 = False
1478+
break
1479+
if read_reg32:
1480+
reg32 = reg >> 8
1481+
data32 = self._base_read_core_registers_raw([CortexMCoreRegisterInfo.get(reg32).index])[0]
1482+
data32 = (data32 & mask) | ((data & 0xff) << shift)
1483+
reg_data_list_extra.append((reg32, data32))
1484+
1485+
elif CortexMCoreRegisterInfo.get(reg).is_psr_subregister:
1486+
if xpsrValue is None:
1487+
# Read initial XPSR value.
1488+
xpsrValue = self._base_read_core_registers_raw([CortexMCoreRegisterInfo.get('xpsr').index])[0]
1489+
mask = CortexMCoreRegisterInfo.get(reg).psr_mask
1490+
data = (xpsrValue & (0xffffffff ^ mask)) | (data & mask)
1491+
xpsrValue = data
14741492
else:
14751493
# Other register, just copy directly.
14761494
reg_data_list.append((reg, data))
14771495

1496+
if xpsrValue is not None:
1497+
reg = CortexMCoreRegisterInfo.get('xpsr').index
1498+
data = xpsrValue
1499+
reg_data_list.append((reg, data))
1500+
reg_data_list.extend(reg_data_list_extra)
1501+
14781502
# Write out registers
14791503
dhcsr_cb_list = []
14801504
for reg, data in reg_data_list:
1481-
if CortexMCoreRegisterInfo.get(reg).is_cfbp_subregister:
1482-
# Mask in the new special register value so we don't modify the other register
1483-
# values that share the same DCRSR number.
1484-
shift = (-reg - 1) * 8
1485-
mask = 0xffffffff ^ (0xff << shift)
1486-
data = (cfbpValue & mask) | ((data & 0xff) << shift)
1487-
cfbpValue = data # update special register for other writes that might be in the list
1488-
reg = CortexMCoreRegisterInfo.get('cfbp').index
1489-
elif CortexMCoreRegisterInfo.get(reg).is_psr_subregister:
1490-
mask = CortexMCoreRegisterInfo.get(reg).psr_mask
1491-
assert xpsrValue is not None
1492-
data = (xpsrValue & (0xffffffff ^ mask)) | (data & mask)
1493-
xpsrValue = data
1494-
reg = CortexMCoreRegisterInfo.get('xpsr').index
1495-
14961505
# write DCRDR
14971506
self.write_memory(CortexM.DCRDR, data)
14981507

0 commit comments

Comments
 (0)