Skip to content

Commit bbe69bc

Browse files
committed
[st] Add register map query
1 parent 26bb0c9 commit bbe69bc

File tree

3 files changed

+77
-41
lines changed

3 files changed

+77
-41
lines changed

ext/st/cmsis.lb

Lines changed: 64 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import re
1515
from pathlib import Path
1616
from collections import defaultdict
17+
import subprocess
18+
1719

1820
def getDefineForDevice(device_id, familyDefines):
1921
"""
@@ -61,45 +63,68 @@ def getDefineForDevice(device_id, familyDefines):
6163

6264
return None
6365

66+
67+
class RegisterMap:
68+
def __init__(self, defines, logger):
69+
self._defs = defines
70+
self._log = logger
71+
self.result = None
72+
# print(self._defs)
73+
74+
def _result(self, query, value, ll):
75+
self.result = value
76+
self._log(f"{query} -{ll}-> {self.result}")
77+
return self.result
78+
79+
def findall(self, query, default=None):
80+
if matches := re.findall(f"#define (?:{query}) ", self._defs):
81+
return self._result(query, matches, "fn")
82+
return self._result(query, default or [], "fd")
83+
84+
def search(self, query, default=None):
85+
if (match := re.search(f"#define (?:{query}) ", self._defs)) is not None:
86+
if not (groups := match.groups()):
87+
return self._result(query, match.group(0)[7:-1], "s0")
88+
if len(groups) == 1:
89+
return self._result(query, groups[0], "s1")
90+
return self._result(query, groups, "sn")
91+
return self._result(query, default, "sd")
92+
93+
def _ops(self, re_pers, re_regs, re_bits, bit_fmt):
94+
reg_bits = defaultdict(list)
95+
matches = re.findall(f"#define (({re_pers})_({re_regs})_(?:{re_bits})) ", self._defs)
96+
for whole, per, reg in matches:
97+
reg_bits[f"{per}->{reg}"].append(whole)
98+
statements = [f"{reg}{bit_fmt(' | '.join(bits))};" for reg, bits in reg_bits.items()]
99+
return self._result((re_pers, re_regs, re_bits), "\n".join(statements), "r")
100+
101+
def set(self, pers, regs, bits):
102+
return self._ops(pers, regs, bits, lambda bits: f" |= {bits}")
103+
104+
def clear(self, pers, regs, bits):
105+
return self._ops(pers, regs, bits, lambda bits: f" &= ~({bits})")
106+
107+
64108
bprops = {}
65-
def common_rcc_map(env):
109+
def common_register_map(env):
66110
"""
67-
Finds all CMSIS bit fields related to enabling and resetting peripherals
68-
in the RCC of the format `RCC_(REGISTER)_(PERIPHERAL)_(TYPE)` where:
111+
Finds all register and bit names in the CMSIS header file.
69112
70-
- REGISTER: a variation of `(BUS)(ID?)(ENR|RSTR)`, e.g. `AHB1ENR`
71-
- PERIPHERAL: typical peripheral name, e.g. `GPIOA`
72-
- TYPE: either `EN` or `RST`.
73-
74-
:returns: a 2D-dictionary: `map[PERIPHERAL][TYPE] = REGISTER`
113+
:returns: a RegisterMap object that allows regex-ing for register names.
75114
"""
76-
headers = env.query("headers")
77-
core_header = repopath("ext/arm/cmsis/CMSIS/Core/Include", headers["core_header"])
78-
79-
content = ""
80-
for header_path in [core_header, localpath(bprops["folder"], headers["device_header"])]:
81-
content += Path(header_path).read_text(encoding="utf-8", errors="replace")
82-
83-
# find mpu and fpu features
84-
features = re.findall(r"#define +__([MF]PU)_PRESENT +([01])", content)
85-
core_features = {f[0]:bool(int(f[1])) for f in features}
86-
# find all peripherals
87-
mperipherals = re.findall(r"#define +(.*?) +\(\((.*?_Type(?:Def)?)", content)
88-
# We only care about the absolute peripheral addresses
89-
peripherals = [(p[0],p[1]) for p in mperipherals]
90-
# filter out MPU and/or FPU if required
91-
peripherals = filter(lambda p: p[0] not in core_features or core_features[p[0]], peripherals)
92-
peripherals = sorted(peripherals, key=lambda p: p[0])
93-
# print("\n".join([s+" -> "+hex(a) for (s,k,a) in peripherals]))
94-
95-
# Find all RCC enable and reset definitions
96-
match = re.findall(r"RCC_([A-Z0-9]*?)_([A-Z0-9]+?)(EN|RST) ", content)
97-
rcc_map = defaultdict(dict)
98-
for (reg, per, typ) in match:
99-
rcc_map[per][typ] = reg
100-
101-
bprops["peripherals"] = peripherals
102-
return rcc_map
115+
cmsis = env.query(":cmsis:device:headers")
116+
include_paths = [repopath("ext/arm/cmsis/CMSIS/Core/Include"), localpath(bprops["folder"])]
117+
headers = [Path(localpath(bprops["folder"], cmsis["device_header"]))]
118+
headers += env.query(":cmsis:ll:__headers", [])
119+
120+
cmd = "arm-none-eabi-gcc"
121+
cmd += " -dM -E -mcpu=" + cmsis["core_header"][:-2].replace("core_c", "cortex-")
122+
cmd += " -D " + cmsis["define"]
123+
for p in include_paths: cmd += f" -I {p}"
124+
for h in headers: cmd += f" {h}"
125+
output = subprocess.run(cmd, shell=True, capture_output=True)
126+
127+
return RegisterMap(output.stdout.decode("utf-8"), env.log.debug)
103128

104129

105130
def common_header_file(env):
@@ -127,7 +152,7 @@ def common_header_file(env):
127152
define = None
128153

129154
content = Path(localpath(folder, family_header)).read_text(encoding="utf-8", errors="replace")
130-
match = re.findall(r"if defined\((?P<define>STM32[CFGHLU][\w\d]+)\)", content)
155+
match = re.findall(r"if defined\((STM32[A-Z][\w\d]+)\)", content)
131156
define = getDefineForDevice(device.identifier, match)
132157
if define is None or match is None:
133158
raise ValidateException("No device define found for '{}'!".format(device.partname))
@@ -198,17 +223,17 @@ def prepare(module, options):
198223
return False
199224

200225
module.add_query(
201-
EnvironmentQuery(name="rcc-map", factory=common_rcc_map))
226+
EnvironmentQuery(name="headers", factory=common_header_file))
202227
module.add_query(
203228
EnvironmentQuery(name="peripherals", factory=common_peripherals))
204229
module.add_query(
205-
EnvironmentQuery(name="headers", factory=common_header_file))
230+
EnvironmentQuery(name="registers", factory=common_register_map))
206231

207232
module.depends(":cmsis:core")
208233
return True
209234

210235
def validate(env):
211-
env.query("rcc-map")
236+
env.query("headers")
212237
env.query("peripherals")
213238

214239
def build(env):

ext/st/ll.lb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,15 @@ def prepare(module, options):
4242
return False
4343

4444
folder = f"stm32{target.family}xx"
45+
headers = []
4546
for header in Path(localpath(f"cube-hal/{folder}/Inc")).glob("*_ll_*.h"):
46-
module.add_submodule(Header(header))
47+
module.add_submodule(header := Header(header))
48+
headers.append(header)
49+
50+
module.add_query(
51+
EnvironmentQuery(name="__headers", factory=lambda env:
52+
[header.header for header in headers
53+
if env.has_module(f":cmsis:ll:{header.name}")]))
4754

4855
module.depends(":cmsis:device")
4956
return True

src/modm/platform/clock/stm32/module.lb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
1313
# -----------------------------------------------------------------------------
1414

15+
from collections import defaultdict
1516

1617
def init(module):
1718
module.name = ":platform:rcc"
@@ -29,6 +30,7 @@ def prepare(module, options):
2930
def build(env):
3031
device = env[":target"]
3132
driver = device.get_driver("rcc")
33+
regs = env.query(":cmsis:device:registers")
3234

3335
properties = {}
3436
properties["target"] = target = device.identifier
@@ -142,7 +144,9 @@ def build(env):
142144
env.template("rcc.hpp.in")
143145

144146
all_peripherals = env.query(":cmsis:device:peripherals")
145-
rcc_map = env.query(":cmsis:device:rcc-map")
147+
rcc_map = defaultdict(dict)
148+
for (reg, per, typ) in regs.findall(r"RCC_([A-Z0-9]*?)_([A-Z0-9]+?)(EN|RST)"):
149+
rcc_map[per][typ] = reg
146150
rcc_enable = {}
147151
rcc_reset = {}
148152

0 commit comments

Comments
 (0)