Skip to content

Commit de5f0db

Browse files
committed
[st] Add register map query
1 parent ab7c1ca commit de5f0db

File tree

2 files changed

+67
-40
lines changed

2 files changed

+67
-40
lines changed

ext/st/module.lb

Lines changed: 62 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import re
1515
from pathlib import Path
1616
from collections import defaultdict
1717

18+
1819
def getDefineForDevice(device_id, familyDefines):
1920
"""
2021
Returns the STM32 specific define from an identifier
@@ -61,45 +62,67 @@ def getDefineForDevice(device_id, familyDefines):
6162

6263
return None
6364

65+
66+
class RegisterMap:
67+
def __init__(self, registers, logger):
68+
self._registers = registers
69+
self._register_string = "\n".join(registers)
70+
self.result = None
71+
self._log = logger
72+
# print(self._register_string)
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 query in self._registers:
81+
return self._result(query, [query], "fi")
82+
if matches := re.findall(f"(?:{query})\n", self._register_string):
83+
return self._result(query, matches, "fn")
84+
return self._result(query, default or [], "fd")
85+
86+
def search(self, query, default=None):
87+
if query in self._registers:
88+
return self._result(query, query, "si")
89+
if (match := re.search(f"(?:{query})\n", self._register_string)) is not None:
90+
if not (groups := match.groups()):
91+
return self._result(query, match.group(0)[:-1], "s0")
92+
if len(groups) == 1:
93+
return self._result(query, groups[0], "s1")
94+
return self._result(query, groups, "sn")
95+
return self._result(query, default, "sd")
96+
97+
def _ops(self, re_pers, re_regs, re_bits, bit_fmt):
98+
reg_bits = defaultdict(list)
99+
matches = re.findall(f"(({re_pers})_({re_regs})_(?:{re_bits}))\n", self._register_string)
100+
for whole, per, reg in matches:
101+
reg_bits[f"{per}->{reg}"].append(whole)
102+
statements = [f"{reg}{bit_fmt(' | '.join(bits))};" for reg, bits in reg_bits.items()]
103+
return "\n".join(statements)
104+
105+
def set(self, pers, regs, bits):
106+
return self._ops(pers, regs, bits, lambda bits: f" |= {bits}")
107+
108+
def clear(self, pers, regs, bits):
109+
return self._ops(pers, regs, bits, lambda bits: f" &= ~({bits})")
110+
111+
64112
bprops = {}
65-
def common_rcc_map(env):
113+
def common_register_map(env):
66114
"""
67-
Finds all CMSIS bit fields related to enabling and resetting peripherals
68-
in the RCC of the format `RCC_(REGISTER)_(PERIPHERAL)_(TYPE)` where:
115+
Finds all register and bit names in the CMSIS header file.
69116
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`
117+
:returns: a RegisterMap object that allows regex-ing for register names.
75118
"""
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
119+
headers = env.query(":cmsis:device:headers")
120+
core_header = Path(repopath("ext/arm/cmsis/CMSIS/Core/Include", headers["core_header"]))
121+
device_header = Path(localpath(bprops["folder"], headers["device_header"]))
122+
content = "\n".join(header.read_text(encoding="utf-8", errors="replace")
123+
for header in [core_header, device_header])
124+
registers = re.findall(r"#define\s+([^\s\(\)]*?)(?:_Msk\s+\(|\s+\(.*?_Pos\)|\s+\(?0x)", content)
125+
return RegisterMap(registers, print)
103126

104127

105128
def common_header_file(env):
@@ -127,7 +150,7 @@ def common_header_file(env):
127150
define = None
128151

129152
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)
153+
match = re.findall(r"if defined\((STM32[A-Z][\w\d]+)\)", content)
131154
define = getDefineForDevice(device.identifier, match)
132155
if define is None or match is None:
133156
raise ValidateException("No device define found for '{}'!".format(device.partname))
@@ -198,17 +221,17 @@ def prepare(module, options):
198221
return False
199222

200223
module.add_query(
201-
EnvironmentQuery(name="rcc-map", factory=common_rcc_map))
224+
EnvironmentQuery(name="headers", factory=common_header_file))
202225
module.add_query(
203226
EnvironmentQuery(name="peripherals", factory=common_peripherals))
204227
module.add_query(
205-
EnvironmentQuery(name="headers", factory=common_header_file))
228+
EnvironmentQuery(name="registers", factory=common_register_map))
206229

207230
module.depends(":cmsis:core")
208231
return True
209232

210233
def validate(env):
211-
env.query("rcc-map")
234+
env.query("headers")
212235
env.query("peripherals")
213236

214237
def build(env):

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)