svd generator (+ fix parser, works now)

This commit is contained in:
Triss 2022-05-31 05:04:23 +02:00
parent 303da594c4
commit 4a9db32d33
3 changed files with 150 additions and 32 deletions

View File

@ -23,16 +23,16 @@ SvdAccess = Literal["read-only", "write-only", "read-write", "writeOnce", "read-
class SvdSauRegion(NamedTuple):
enabled: bool
name: str
enabled: bool # attribute
name: str # attribute
base: int
limit: int
access: SvdSauAccess
class SvdSauRegionsConfig(NamedTuple):
enabled: bool
protectionWhenDisabled: SvdSauAccess
enabled: bool # attribute
protectionWhenDisabled: SvdSauAccess # attribute
regions: Sequence[SvdSauRegion]
@ -72,7 +72,7 @@ class SvdEnumeratedValue(NamedTuple):
class SvdEnumeratedValues(NamedTuple):
derivedFrom: str
derivedFrom: str # attribute
name: str
usage: SvdUsage
enumeratedValue: Sequence[SvdEnumeratedValue]
@ -86,7 +86,7 @@ class SvdDimArrayIndex(NamedTuple):
class SvdDimElement(NamedTuple):
dim: int
dimIncrement: int
dimIndex: int
dimIndex: str
dimName: str
dimArrayIndex: SvdDimArrayIndex
@ -105,7 +105,7 @@ class SvdInterrupt(NamedTuple):
class SvdCluster(NamedTuple):
derivedFrom: str
derivedFrom: str # attribute
dimElement: SvdDimElement
name: str
description: str
@ -118,8 +118,8 @@ class SvdCluster(NamedTuple):
class SvdWriteConstraintRange(NamedTuple):
min: int
max: int
minimum: int
maximum: int
class SvdWriteConstraint(NamedTuple):
writeAsRead: bool
@ -127,23 +127,16 @@ class SvdWriteConstraint(NamedTuple):
range: SvdWriteConstraintRange
class SvdBitRangeLsbMsb(NamedTuple):
lsb: int
msb: int
class SvdBitRangeOffsetWidth(NamedTuple):
bitOffset: int
bitWidth: int
SvdBitRangePattern = str
class SvdField(NamedTuple):
derivedFrom: str
derivedFrom: str # attribute
dimElement: SvdDimElement
name: str
description: str
bitRange: Union[SvdBitRangeLsbMsb, SvdBitRangeOffsetWidth, SvdBitRangePattern]
bitOffset: int
bitWidth: int
lsb: int
msb: int
bitRange: str
access: SvdAccess
modifiedWriteValues: SvdModifiedWriteValues
writeConstraint: SvdWriteConstraint
@ -152,7 +145,7 @@ class SvdField(NamedTuple):
class SvdRegister(NamedTuple):
derivedFrom: str
derivedFrom: str # attribute
dimElement: SvdDimElement
name: str
displayName: str
@ -166,10 +159,12 @@ class SvdRegister(NamedTuple):
writeConstraint: SvdWriteConstraint
readAction: SvdReadAction
fields: Sequence[SvdField]
# ignoring for now because this SVD is VERY broken
#enumeratedValues: SvdEnumeratedValues # HACK: SiFive e310x, Kendryte k210
class SvdPeripheral(NamedTuple):
derivedFrom: str
derivedFrom: str # attribute
name: str
version: str
description: str
@ -203,5 +198,5 @@ class SvdDevice(NamedTuple):
peripherals: Sequence[SvdPeripheral]
vendorExtensions: Any
# TODO: functions for expanding registerproperties, dimelements and derivedfrom?
# TODO: functions for expanding/flattening registerProperties, dimElements and derivedFrom?

View File

@ -0,0 +1,96 @@
import typing, collections.abc
from svd import *
from typing import get_type_hints
# FIXME:
# * peripheral registers not emitting
def ser_one(v) -> str:
assert v is not None
if isinstance(v, bool): return "true" if v else "false"
elif isinstance(v, int): return hex(v)
elif isinstance(v, str): return v
elif type(v) == tuple:
return "r%dp%d" % (v[0], v[1])
else: return None
type2attr = {
SvdSauRegion: {'enabled','name'},
SvdSauRegionsConfig: {'enabled','protectionWhenDisabled'},
SvdEnumeratedValues: {'derivedFrom'},
SvdCluster: {'derivedFrom'},
SvdField: {'derivedFrom'},
SvdRegister: {'derivedFrom'},
SvdPeripheral: {'derivedFrom'},
}
type2tag = {
SvdSauRegion: 'region',
SvdSauRegionsConfig: 'sauRegionsConfig',
SvdCpu: 'cpu',
SvdRegisterProperties: 'registerProperties',
SvdEnumeratedValue: 'enumeratedValue',
SvdEnumeratedValues: 'enumeratedValues',
SvdDimArrayIndex: 'dimArrayIndex',
SvdDimElement: 'dimElement',
SvdAddressBlock: 'addressBlock',
SvdInterrupt: 'interrupt',
SvdCluster: 'cluster',
SvdWriteConstraintRange: 'range',
SvdWriteConstraint: 'writeConstraint',
SvdField: 'field',
SvdRegister: 'register',
SvdPeripheral: 'peripheral',
SvdDevice: 'device',
}
def gen_generic(f, svdelem, T, tag, attrs=(), extraattr="", no_outer=False):
atdict={}
childdict={}
d = dict((n, svdelem.__getattribute__(n)) for n in T._fields)
for k, v in d.items():
if v is None: continue
if k in attrs:
atdict[k] = v
else:
childdict[k] = v
atstr = ' '.join('%s="%s"' % (k, ser_one(v)) for k, v in atdict.items())
if not no_outer: f.write("<%s%s%s%s>\n" % (tag, (' ' if len(atstr)+len(extraattr)>0 else ''), atstr, extraattr))
types = get_type_hints(T)
for k, v in childdict.items():
if v is None: continue
typ = types[k]
x = ser_one(v)
if x is None: # TODO: optimize
if '__origin__' in typ.__dict__ and typ.__origin__ == collections.abc.Sequence:
if len(v) > 0:
f.write("<%s>\n" % k)
ttt = typ.__args__[0]
isunion = '__origin__' in ttt.__dict__ and ttt.__origin__ == typing.Union
for x in v:
if isunion: ttt = type(x)
gen_generic(f, x, ttt, type2tag[ttt], type2attr.get(ttt, ()))
f.write("</%s>\n" % k)
else:
noouter = typ in {SvdDimElement, SvdRegisterProperties}
gen_generic(f, v, typ, k, type2attr.get(typ, ()), no_outer=noouter)
else:
f.write("<%s>%s</%s>\n"%(k, x, k))
if not no_outer: f.write("</%s>\n" % tag)
def generate(f, dev: SvdDevice):
f.write("""<?xml version="1.0" encoding="utf-8"?>\n""")
gen_generic(f, dev, SvdDevice, 'device',
extraattr=""" schemaVersion="1.1" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="CMSIS-SVD.xsd" """)

View File

@ -7,6 +7,18 @@ from svd import *
from typing import get_type_hints
def parse_int(s):
if len(s) == 0: raise ValueError()
if s.startswith('0b') or s[0] == '#':
if 'x' in s: return s # eh
elif s.startswith('0b'): return int(s[2:], 2)
else: return int(s[1:], 2)
elif s[0] == '0' and len(s) > 1 and not all(x == '0' for x in s):
# HACK: STMicro STM32F411
return int(s, 16)
else: return int(s, 0)
def parse_one(ch, t):
k, v = None, None
if isinstance(ch, ET.Element):
@ -15,7 +27,6 @@ def parse_one(ch, t):
k, v = ch
field = get_type_hints(t)[k]
#print("%s -> %s [%s]" %(k, v, repr(field)))
known_types = {
SvdDevice: parse_device,
@ -36,20 +47,25 @@ def parse_one(ch, t):
vv = known_types.get(field)
if vv:
#print("%s -> %s [%s]" %(k, v, repr(field)))
return vv(v)
elif isinstance(ch, ET.Element):
v = ch.text
#print("%s -> %s [%s]" %(k, v, repr(field)))
if field == int:
return int(v, 0)
return parse_int(v)
elif field == bool:
assert v in {'true','false','1','0'}, ("invalid boolean value %s"%v)
return v in {'true','1'}
elif field == str or field.__origin__ == typing.Literal:
return v
elif field.__origin__ == tuple:
if k == 'revision':
return tuple(int(x) for x in v[1:].split('p'))
if k == 'revision': # good enough
if len(v) > 0 and v[0] != 'r': # HACK: ESP32
return v
else:
return tuple(int(x) for x in v[1:].split('p'))
else:
assert False, ("unknown Tuple type %s for field %s" % (field, k))
elif field.__origin__ == typing.Union:
@ -127,8 +143,7 @@ def parse_addressBlock(xd): return parse_generic(xd, SvdAddressBlock, 'addressBl
def parse_interrupt(xd): return parse_generic(xd, SvdInterrupt, 'interrupt')
def parse_writeConstraintRange(xd): return parse_generic(xd, SvdWriteConstraintRange, 'range')
def parse_enumeratedValue(xd): return parse_generic(xd, SvdEnumeratedValue, 'enumeratedValue')
def parse_writeConstraint(xd):
return parse_writeConstraint(xd, SvdWriteConstraint, 'writeConstraint')
def parse_writeConstraint(xd): return parse_generic(xd, SvdWriteConstraint, 'writeConstraint')
def parse_dimArrayIndex(xd): return parse_generic(xd, SvdDimArrayIndex, 'dimArrayIndex')
@ -171,6 +186,7 @@ def parse_registers(xd) -> Sequence[Union[SvdCluster, SvdRegister]]:
rr.append(parse_register(ch))
else:
assert False, ("expected cluster or register, got %s"%ch)
return rr
def parse_peripheral(xd) -> SvdPeripheral:
@ -188,7 +204,18 @@ def parse_device(xd) -> SvdDevice:
def parse(path) -> SvdDevice:
import datetime
#a = datetime.datetime.now()
xmlroot = ET.parse(path).getroot()
#b = datetime.datetime.now()
r = parse_device(xmlroot)
#c = datetime.datetime.now()
return parse_device(xmlroot)
#print("a->b:", b - a)
#print("b->c:", c - b)
# for NXP/MIMXRT1062: XML parsing 2s, deserialization 8s, welp
# oh well
return r