149 lines
3.4 KiB
Python
149 lines
3.4 KiB
Python
from dataclasses import dataclass
|
|
from fnmatch import fnmatch
|
|
from sys import argv
|
|
|
|
from lxml.etree import XML
|
|
|
|
# List of <peri>.<register> patterns to mark as unsafe.
|
|
UNSAFE: list[str] = [
|
|
"SIO.SPINLOCK[0-9]*",
|
|
"ADC.FIFO",
|
|
"SSI.*CR",
|
|
"SIO.DIV_QUOTIENT",
|
|
"SIO.DIV_REMAINDER",
|
|
"SIO.FIFO_RD",
|
|
"M0PLUS.SYST_CSR",
|
|
"I2C*.IC_CLR*",
|
|
"TIMER.TIME[HL]R",
|
|
"PIO*.RXF*",
|
|
"PPB.*",
|
|
"XIP.*",
|
|
]
|
|
|
|
|
|
def is_unsafe(peri: str, reg: str) -> bool:
|
|
for pattern in UNSAFE:
|
|
if fnmatch(f"{peri}.{reg}", pattern):
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
with open(argv[1], "rb") as fp:
|
|
xml = XML(fp.read())
|
|
|
|
|
|
@dataclass
|
|
class Register:
|
|
name: str
|
|
offset: int
|
|
reset: int
|
|
read: bool
|
|
write: bool
|
|
|
|
|
|
@dataclass
|
|
class Peripheral:
|
|
name: str
|
|
base: int
|
|
regs: list[Register]
|
|
|
|
|
|
peripherals: dict[str, Peripheral] = {}
|
|
|
|
for peri in xml.cssselect("peripheral"):
|
|
if "derivedFrom" in peri.attrib:
|
|
orig = peripherals[peri.attrib["derivedFrom"]]
|
|
names = peri.cssselect("peripheral > name")
|
|
assert len(names) == 1
|
|
|
|
peripheral = Peripheral(name=names[0].text, base=orig.base, regs=orig.regs)
|
|
continue
|
|
|
|
names = peri.cssselect("peripheral > name")
|
|
assert len(names) == 1
|
|
|
|
bases = peri.cssselect("peripheral > baseAddress")
|
|
assert len(bases) == 1
|
|
|
|
base = int(bases[0].text, 16)
|
|
peripheral = Peripheral(name=names[0].text, base=base, regs=[])
|
|
|
|
for reg in peri.cssselect("peripheral > registers > register"):
|
|
names = reg.cssselect("register > name")
|
|
assert len(names) == 1
|
|
|
|
offsets = reg.cssselect("register > addressOffset")
|
|
assert len(offsets) == 1
|
|
|
|
resets = reg.cssselect("register > resetValue")
|
|
assert len(resets) == 1
|
|
|
|
accesses = reg.cssselect("access")
|
|
assert len(accesses) > 0
|
|
|
|
write = read = False
|
|
|
|
for access in accesses:
|
|
match access.text:
|
|
case "read-only":
|
|
read = True
|
|
|
|
case "read-write":
|
|
write = read = True
|
|
|
|
case "write-only":
|
|
write = True
|
|
|
|
case mode:
|
|
assert False, f"unknown access mode {mode!r}"
|
|
|
|
offset = int(offsets[0].text, 16)
|
|
reset = int(resets[0].text, 16)
|
|
register = Register(
|
|
name=names[0].text,
|
|
offset=offset,
|
|
reset=reset,
|
|
write=write,
|
|
read=read,
|
|
)
|
|
peripheral.regs.append(register)
|
|
|
|
peripherals[peripheral.name] = peripheral
|
|
|
|
print(
|
|
"""
|
|
#include "regmap.h"
|
|
|
|
struct reg_info regmap[] = {
|
|
""".strip()
|
|
)
|
|
|
|
for peripheral in peripherals.values():
|
|
for register in peripheral.regs:
|
|
print("{ ", end="")
|
|
print(f"{hex(peripheral.base + register.offset)}, ", end="")
|
|
print(f"{hex(register.reset)}, ", end="")
|
|
print(f"{hex(register.reset)}, ", end="")
|
|
print(f'"{peripheral.name}", ', end="")
|
|
print(f'"{register.name}", ', end="")
|
|
|
|
if register.read:
|
|
print("1, ", end="")
|
|
else:
|
|
print("0, ", end="")
|
|
|
|
if register.write:
|
|
print("1, ", end="")
|
|
else:
|
|
print("0, ", end="")
|
|
|
|
if is_unsafe(peripheral.name, register.name):
|
|
print("1", end="")
|
|
else:
|
|
print("0", end="")
|
|
|
|
print(" },")
|
|
|
|
print("{ 0, 0, 0, NULL, NULL, 0, 0, 0 },")
|
|
print("};")
|