modm_data.html2svd.stmicro.reference
1# Copyright 2022, Niklas Hauser 2# SPDX-License-Identifier: MPL-2.0 3 4import re 5from functools import cached_property 6from collections import defaultdict 7from anytree import RenderTree 8 9from ...html.stmicro.helper import split_device_filter 10from ...svd import * 11from ...header2svd.stmicro.tree import _normalize_order 12from ...cubemx import cubemx_device_list 13from ...html import replace as html_replace 14 15 16def _deduplicate_bit_fields(bit_fields): 17 named_fields = defaultdict(set) 18 for field in sorted(bit_fields, key=lambda f: f.position): 19 named_fields[field.name].add(field.position) 20 21 new_fields = [] 22 for name, positions in named_fields.items(): 23 position = min(positions) 24 width = max(positions) + 1 - position 25 new_fields.append(BitField(name, position, width)) 26 27 return new_fields 28 29 30def _peripheral_map_to_tree(chapter, peripheral_maps): 31 cap_replace = {"STM32F415/417xx": "STM32F415/417"} 32 33 peripheral_trees = [] 34 for caption, (heading, register_map) in peripheral_maps.items(): 35 print(caption) 36 if match := re.search(f"OTG_[FH]S", caption): 37 replace_name = peripheral_name = "OTG" 38 elif match := re.search(f"JPEG", caption): 39 replace_name = peripheral_name = "JPEG" 40 elif match := re.search(f"CCU ", caption): 41 peripheral_name = "CANCCU" 42 replace_name = "FDCAN_CCU" 43 else: 44 peripheral_names = {n.split("_")[0] for n in register_map.keys()} 45 replace_name = peripheral_name = list(sorted(peripheral_names))[-1] 46 if all(p.startswith("COMP") for p in peripheral_names): 47 peripheral_name = "COMP" 48 replace_name = "" 49 if all(p.startswith("OPAMP") for p in peripheral_names): 50 peripheral_name = "OPAMP" 51 replace_name = "" 52 elif len(peripheral_names) > 1: 53 print(f"Multiple peripheral names detected: {peripheral_names}") 54 55 if peripheral_name == "M7": continue 56 # Some chapters have multiple tables for multiple instances 57 filters = defaultdict(set) 58 instances = set() 59 if peripheral_name.startswith("LPTIM"): 60 replace_name = peripheral_name = "LPTIM" 61 elif peripheral_name.startswith("DLYB"): 62 instances.add("DLYB") 63 elif peripheral_name.startswith("TIM"): 64 peripheral_name = "TIM" 65 if match := re.search(r"TIM(\d+) +to +TIM(\d+)", caption): 66 irange = list(sorted([int(match.group(1)), int(match.group(2))])) 67 irange = range(irange[0], irange[1] + 1) 68 instances.add(f"TIM({'|'.join(map(str, irange))})") 69 for pfilter in re.findall(r"TIM\d+(?:/\d+)*", caption): 70 if "/" in pfilter: 71 pfilter = f"TIM({pfilter[3:].replace('/', '|')})" 72 instances.add(f"^{pfilter}$") 73 elif "GPIOx" in peripheral_name: 74 peripheral_name = "GPIO" 75 for pfilter in re.findall(r"GPIO[A-Z](?:[/A-Z]+]+)?", caption): 76 if "/" in pfilter: 77 pfilter = f"GPIO({pfilter[4:].replace('/', '|')})" 78 instances.add(pfilter) 79 if instances: 80 filters["instances"].update(instances) 81 82 devices = set() 83 for pfilter in re.findall(r"STM32[\w/]+", html_replace(caption, **cap_replace)): 84 devices.update(split_device_filter(pfilter) if "/" in pfilter else [pfilter]) 85 if devices: 86 filters["devices"].update(d.replace("x", ".") for d in devices) 87 88 if "connectivity line" in chapter.name: 89 filters["devices"].add("STM32F10[57]") 90 elif "low medium high and xl density" in chapter.name: 91 filters["devices"].add("STM32F10[123]") 92 93 peripheral_type = PeripheralType(peripheral_name, _chapter=chapter, 94 filters=dict(filters), section=heading) 95 for rname, (offset, bitfields) in register_map.items(): 96 filters = {} 97 if replace_name: 98 if replace_name == "OTG" and (match := re.match("^OTG_[FH]S", rname)): 99 filters["instances"] = {match.group(0)} 100 nrname = rname.replace(match.group(0) + "_", "") 101 else: 102 nrname = rname.replace(replace_name + "_", "") 103 if len(rname) == len(nrname) and "_" in rname: 104 instance = rname.split("_")[0] 105 filters["instances"] = {instance+"$"} 106 nrname = rname.replace(instance + "_", "") 107 print(instance, nrname) 108 rname = nrname 109 if match := re.match("(.*?)connectivitylinedevices", rname): 110 rname = match.group(1) 111 filters["devices"] = {r"STM32F10[57]"} 112 elif match := re.match("(.*?)low,medium,highandXLdensitydevices", rname): 113 rname = match.group(1) 114 filters["devices"] = {r"STM32F10[123]"} 115 try: offset = int(offset, 16) 116 except: pass 117 register_type = Register(rname, offset, filters=filters, parent=peripheral_type) 118 fields = [BitField(field, bit) for bit, field in bitfields.items()] 119 register_type.children = _deduplicate_bit_fields(fields) 120 121 peripheral_trees.append(peripheral_type) 122 123 return peripheral_trees 124 125 126def _expand_register_offsets(peripheral_trees): 127 for peripheral in peripheral_trees: 128 unexpanded = defaultdict(list) 129 for register in peripheral.children: 130 if (isinstance(register.offset, str) or 131 ("CAN" in peripheral.name and "F1R2" in register.name) or 132 ("GFXMMU" in peripheral.name and "LUT0L" in register.name) or 133 ("GFXMMU" in peripheral.name and "LUT0H" in register.name) or 134 ("HSEM" in peripheral.name and "R1" in register.name)): 135 unexpanded[str(register.offset)].append(register) 136 for offsets, registers in unexpanded.items(): 137 print(offsets, registers) 138 139 conv = lambda i: int(i, 16) 140 # if match := re.search(r"x=([\d,]+)", registers[0].name): 141 # offsets = [offsets] * len(match.group(1).split(",")) 142 if any(pat in offsets for pat in ["x=", "channelnumber"]): 143 if matches := re.findall(r"(0x[\dA-Fa-f]+)\(x=\w+\)", offsets): 144 orange = enumerate(map(conv, matches)) 145 formula = "x" 146 elif "channelnumber" in offsets: 147 orange = enumerate(range(0, 16)) 148 formula = offsets.replace("channelnumber", "x") 149 elif "moni-ringunitnumber" in offsets: 150 orange = [(i, i) for i in range(1, 6)] 151 formula = offsets.split("(x=")[0] 152 else: 153 match = re.search(r"\(x=(\d+)(?:-\.?|\.\.)(\d+)", offsets) 154 orange = [(i, i) for i in range(int(match.group(1)), int(match.group(2)) + 1)] 155 formula = re.split(r"\(x=|,", offsets)[0] 156 offsets = [(ii, eval(formula, None, {"x": x})) for ii, x in orange] 157 print(formula, offsets, orange) 158 elif "-" in offsets: 159 omin, omax = list(map(conv, offsets.split("-"))) 160 offsets = enumerate(range(omin, omax+1, 4)) 161 elif "or" in offsets: 162 offsets = enumerate(list(map(conv, offsets.split("or")))) 163 elif "F1R2" in registers[0].name: 164 offsets = enumerate(range(int(offsets), int(offsets)+4*25*2+1, 4)) 165 elif "LUT0" in registers[0].name: 166 offsets = enumerate(range(int(offsets), int(offsets)+4*2044+1, 8)) 167 elif "HSEM" in peripheral.name: 168 print(offsets) 169 offsets = enumerate(range(int(offsets), int(offsets)+4*29+1, 4)) 170 else: 171 print(f"Unknown expansion format for {offsets}!") 172 return False 173 174 fields = registers[0].children 175 if all(re.match(r"BKP\d+R", r.name) for r in registers): 176 name_template = lambda i: f"BKP{i}R" 177 elif "SAI" in peripheral.name: 178 name_template = lambda i: f"{registers[0].name[1:]}{chr(i+ord('A'))}" 179 elif "HRTIM" in peripheral.name: 180 name_template = lambda i: registers[0].name.replace("x", chr(i+ord('A'))) 181 elif "CAN" in peripheral.name: 182 name_template = lambda i: f"F{(i+3)//2}R{(i+1)%2+1}" 183 elif "GFXMMU" in peripheral.name: 184 name_template = lambda i: f"LUT{i}{registers[0].name[-1]}" 185 elif "HSEM" in peripheral.name: 186 name_template = lambda i: f"{registers[0].name[:-1]}{i+1}" 187 elif len(registers) == 1: 188 # if "x=" in registers[0].name: 189 # name_template = lambda i: f"{registers[0].name.split('x=')[0]}.{i}" 190 if "x" in registers[0].name: 191 name_template = lambda i: registers[0].name.replace("x", str(i)) 192 else: 193 name_template = lambda i: f"{registers[0].name}.{i}" 194 else: 195 print(f"Unknown expansion pattern for {registers}!") 196 return False 197 198 for ii, offset in offsets: 199 nreg = Register(name_template(ii), offset, filters=registers[0].filters, parent=peripheral) 200 nreg.children = [BitField(f.name, f.position, f.width) for f in fields] 201 for register in registers: 202 register.parent = None 203 204 return True 205 206 207def _link_instance_to_type(rm, peripheral_types, instance_offsets): 208 cap_replace = {} 209 peripherals = set() 210 for caption, locations in rm.peripherals.items(): 211 filters = defaultdict(set) 212 devices = set() 213 for pfilter in re.findall(r"STM32[\w/]+", html_replace(caption, **cap_replace)): 214 devices.update(split_device_filter(pfilter) if "/" in pfilter else [pfilter]) 215 if "Low and medium-density device" in caption: 216 devices.add("STM32F10..[468B]") 217 elif "High-density device" in caption: 218 devices.add("STM32F10..[CDE]") 219 if devices: 220 filters["devices"].update(d.replace("x", ".") for d in devices) 221 222 for (names, amin, amax, bus, sections) in locations: 223 for name in names: 224 ptypes = [t for tname, types in peripheral_types.items() for t in types if tname == name] 225 if not ptypes: 226 ptypes = [t for tname, types in peripheral_types.items() for t in types if tname in name] 227 if not ptypes: 228 ptypes = [t for tname, types in peripheral_types.items() 229 for t in types if t.section in sections] 230 if not ptypes and name.startswith("UART"): 231 ptypes = [t for tname, types in peripheral_types.items() for t in types if tname == "USART"] 232 if not ptypes and "BKP" == name: 233 ptypes = [t for tname, types in peripheral_types.items() for t in types if tname == "RTC"] 234 if not ptypes: 235 print(f"Cannot find peripheral type for instance {name} in section {sections}!") 236 nsections = list(sorted({t.section for types in peripheral_types.values() for t in types})) 237 print(f"Available sections are {nsections}.") 238 exit(1) 239 offsets = [v for k, v in instance_offsets.items() if re.search(k, name)] 240 if offsets: amin += offsets[0] 241 p = Peripheral(name, ptypes, amin, filters=dict(filters), sections=sections) 242 peripherals.add(p) 243 return peripherals 244 245 246def _resolve_filters(filters, **kw): 247 keys = [] 248 for key, value in kw.items(): 249 if values := filters.get(key): 250 keys.append(key) 251 if any(re.search(pat, value, flags=re.IGNORECASE) for pat in values): 252 return True 253 return not keys 254 255 256def _normalize_instances(memtree, peripherals, device): 257 for peripheral in peripherals: 258 if not _resolve_filters(peripheral.filters, devices=device.string): 259 continue 260 ptypes = peripheral.type 261 if len(ptypes) > 1: 262 ptypes = [ptype for ptype in sorted(peripheral.type, key=lambda p: -len(p.filters)) 263 if _resolve_filters(ptype.filters, instances=peripheral.name, devices=device.string)] 264 if len(ptypes) > 1 and any(p.filters for p in ptypes): 265 ptypes = [p for p in ptypes if p.filters] 266 if len(ptypes) > 1: 267 nptypes = [p for p in ptypes if any(p.section.startswith(per) or per.startswith(p.section) 268 for per in peripheral.sections)] 269 if nptypes: ptypes = nptypes 270 for pname in ["DMAMUX", "BDMA", "OCTOSPI"]: 271 if len(ptypes) > 1 and pname in peripheral.name: 272 ptypes = [p for p in ptypes if pname in p.name] 273 274 if len(ptypes) != 1: 275 print(f"Unknown peripheral type {device} {peripheral} {ptypes}!") 276 continue 277 ptype = ptypes[0] 278 279 nper = Peripheral(peripheral.name, ptype, peripheral.address, 280 filters=peripheral.filters, parent=memtree) 281 rmap = defaultdict(list) 282 for treg in ptype.children: 283 rmap[treg.name].append(treg) 284 285 for name, tregs in rmap.items(): 286 regs = [reg for reg in sorted(tregs, key=lambda p: -len(p.filters)) 287 if _resolve_filters(reg.filters, instances=peripheral.name, devices=device.string)] 288 if len(regs) > 1 and any(r.filters for r in regs): 289 regs = [r for r in regs if r.filters] 290 if len(regs) != 1: 291 if len(regs) > 1: 292 print(f"Unsuccessful register filtering {peripheral.name} {device}: {tregs}!") 293 continue 294 treg = regs[0] 295 if _resolve_filters(treg.filters, devices=device.string, instances=nper.name): 296 preg = Register(treg.name, offset=treg.offset, width=treg.width, 297 filters=treg.filters, parent=nper) 298 for tbit in treg.children: 299 BitField(tbit.name, tbit.position, tbit.width, parent=preg) 300 301 302def _build_device_trees(rm, peripheral_types, instance_offsets): 303 devices = rm.filter_devices(modm_device_list()) 304 memtrees = [] 305 306 for device in devices: 307 memtree = Device(device) 308 peripherals = _link_instance_to_type(rm, peripheral_types, instance_offsets) 309 _normalize_instances(memtree, peripherals, device) 310 memtrees.append(memtree) 311 return memtrees 312 313 314def _compactify_device_trees(memtrees): 315 memtree_hashes = defaultdict(list) 316 for memtree in memtrees: 317 memtree_hashes[hash(memtree)].append(memtree) 318 319 new_memtrees = [] 320 for memtrees in memtree_hashes.values(): 321 memtree = memtrees[0] 322 for mtree in memtrees[1:]: 323 memtree.compatible.extend(mtree.compatible) 324 memtree.compatible.sort(key=lambda d: d.string) 325 memtree.name = memtree.compatible[0] 326 new_memtrees.append(memtree) 327 328 return new_memtrees 329 330 331def memory_map_from_reference_manual(rm): 332 if "RM0438" in rm.name or "RM0456" in rm.name: 333 print("RM0438, RM0456 are ARMv8-M with two memory maps!") 334 return [] 335 336 all_chapters = rm.chapters() 337 type_chapters = {rm.chapter(f"chapter {s.split('.')[0]} ") for pers in rm.peripherals.values() 338 for locs in pers for s in locs[4]} 339 peripheral_types = defaultdict(set) 340 instance_offsets = {} 341 for chapter in all_chapters: 342 print() 343 peripheral_maps, peripheral_offsets = rm.peripheral_maps(chapter, assert_table=chapter in type_chapters) 344 instance_offsets.update(peripheral_offsets) 345 peripheral_maps = _peripheral_map_to_tree(chapter, peripheral_maps) 346 if not _expand_register_offsets(peripheral_maps): 347 exit(1) 348 for pmap in peripheral_maps: 349 print(pmap) 350 # print(RenderTree(pmap, maxlevel=2)) 351 peripheral_types[pmap.name].add(pmap) 352 353 for name, pmaps in peripheral_types.items(): 354 print(name) 355 for pmap in pmaps: 356 print(pmap.section, pmap._chapter._relpath) 357 print(RenderTree(pmap, maxlevel=2)) 358 359 360 memtrees = _build_device_trees(rm, peripheral_types, instance_offsets) 361 # for tree in memtrees: 362 # print(RenderTree(tree, maxlevel=2)) 363 # exit(1) 364 memtrees = _compactify_device_trees(memtrees) 365 memtrees = [_normalize_order(memtree) for memtree in memtrees] 366 return memtrees
def
memory_map_from_reference_manual(rm):
332def memory_map_from_reference_manual(rm): 333 if "RM0438" in rm.name or "RM0456" in rm.name: 334 print("RM0438, RM0456 are ARMv8-M with two memory maps!") 335 return [] 336 337 all_chapters = rm.chapters() 338 type_chapters = {rm.chapter(f"chapter {s.split('.')[0]} ") for pers in rm.peripherals.values() 339 for locs in pers for s in locs[4]} 340 peripheral_types = defaultdict(set) 341 instance_offsets = {} 342 for chapter in all_chapters: 343 print() 344 peripheral_maps, peripheral_offsets = rm.peripheral_maps(chapter, assert_table=chapter in type_chapters) 345 instance_offsets.update(peripheral_offsets) 346 peripheral_maps = _peripheral_map_to_tree(chapter, peripheral_maps) 347 if not _expand_register_offsets(peripheral_maps): 348 exit(1) 349 for pmap in peripheral_maps: 350 print(pmap) 351 # print(RenderTree(pmap, maxlevel=2)) 352 peripheral_types[pmap.name].add(pmap) 353 354 for name, pmaps in peripheral_types.items(): 355 print(name) 356 for pmap in pmaps: 357 print(pmap.section, pmap._chapter._relpath) 358 print(RenderTree(pmap, maxlevel=2)) 359 360 361 memtrees = _build_device_trees(rm, peripheral_types, instance_offsets) 362 # for tree in memtrees: 363 # print(RenderTree(tree, maxlevel=2)) 364 # exit(1) 365 memtrees = _compactify_device_trees(memtrees) 366 memtrees = [_normalize_order(memtree) for memtree in memtrees] 367 return memtrees