119 lines
4.1 KiB
Python
119 lines
4.1 KiB
Python
|
|
import xml, xml.etree
|
|
import xml.etree.ElementTree as ET
|
|
import typing, collections.abc
|
|
|
|
from svd import *
|
|
from typing import get_type_hints
|
|
|
|
|
|
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.replace('&', "&").replace('<', "<").replace('>', ">")
|
|
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',
|
|
}
|
|
flattenchildren = {
|
|
SvdEnumeratedValues: {'enumeratedValue'},
|
|
SvdCluster: {'cluster','register'},
|
|
SvdDimArrayIndex: {'enumeratedValue'},
|
|
SvdPeripheral: {'interrupt','addressBlock'},
|
|
}
|
|
|
|
|
|
def gen_generic(f, svdelem, T: type, tag: str, attrs=(), extraattr="", no_outer=False, rec=[]):
|
|
rec=[*rec, tag]
|
|
#print(rec, T, type(svdelem))
|
|
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
|
|
#print('k', k, "typ",typ)
|
|
if typ == typing.Any and k == 'vendorExtensions':
|
|
if type(v) == ET.Element:
|
|
#print("v",v,type(v))
|
|
xstr = ET.tostring(v, method='xml')#, encoding='utf8')
|
|
xstr = xstr.decode()
|
|
#print("xstr",xstr)
|
|
f.write(xstr)
|
|
else:
|
|
# uuuuuh idk fuck
|
|
f.write(repr(v))
|
|
f.write('\n')
|
|
|
|
elif typ == list or ('__origin__' in typ.__dict__ and typ.__origin__ in {collections.abc.Sequence,list}):
|
|
if len(v) > 0:
|
|
flatten = k in flattenchildren.get(T, ())
|
|
if not flatten: f.write("<%s>\n" % k)
|
|
ttt = typ.__args__[0]
|
|
isdyn = ttt == typing.Any or ('__origin__' in ttt.__dict__ and ttt.__origin__ == typing.Union)
|
|
for x in v:
|
|
if isdyn: ttt = type(x)
|
|
#print("ttt",ttt)
|
|
gen_generic(f, x, ttt, type2tag[ttt], type2attr.get(ttt, ()), rec=[*rec, k])
|
|
if not flatten: f.write("</%s>\n" % k)
|
|
else:
|
|
noouter = typ in {SvdDimElement, SvdRegisterProperties}
|
|
gen_generic(f, v, typ, k, type2attr.get(typ, ()), no_outer=noouter, rec=[*rec, k])
|
|
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" """)
|
|
|