From 7663529ec87fff8da743d4ffe4ead736af302313 Mon Sep 17 00:00:00 2001 From: Rahix Date: Sat, 12 Sep 2020 20:54:42 +0200 Subject: [PATCH] patch: Switch to upstream svdtools patch tool Instead of using our locally vendored version of svdpatch, switch to the upstream version maintained by the stm32-rs project: https://github.com/stm32-rs/svdtools Signed-off-by: Rahix --- Makefile | 14 +- patch/makedeps.py | 31 -- patch/svdpatch.py | 847 ---------------------------------------------- 3 files changed, 8 insertions(+), 884 deletions(-) delete mode 100644 patch/makedeps.py delete mode 100644 patch/svdpatch.py diff --git a/Makefile b/Makefile index 73bd16b..4909739 100644 --- a/Makefile +++ b/Makefile @@ -15,23 +15,24 @@ vector: macros/src/vector.rs $(foreach chip, $(CHIPS), $(eval $(chip): src/devices/$(chip)/mod.rs)) .SECONDARY: -svd/%.bare.svd: vendor/%.atdf +svd/%.svd: vendor/%.atdf @mkdir -p svd @echo -e "\tATDF2SVD\t$*" @atdf2svd $< $@ 2>/dev/null -$(foreach patch, $(PATCHES), $(eval $(patsubst patch/%.yaml, svd/%.patched.svd, $(patch)): $(patch))) +$(foreach patch, $(PATCHES), $(eval $(patsubst patch/%.yaml, svd/%.svd.patched, $(patch)): $(patch))) -svd/%.patched.svd: svd/%.bare.svd patch/svdpatch.py +svd/%.svd.patched: svd/%.svd .deps/%.d @if [ -f patch/$*.yaml ] ; then \ echo -e "\tPATCH\t\t$*"; \ - python3 patch/svdpatch.py patch/$*.yaml $< $@; \ + svd patch patch/$*.yaml; \ + test -e $@; \ else \ echo -e "\t - No patches found for $*"; \ cp $< $@; \ fi -src/devices/%/mod.full.rs: svd/%.patched.svd +src/devices/%/mod.full.rs: svd/%.svd.patched @mkdir -p $(@D) @echo -e "\tSVD2RUST\t$*" @cd $(@D); svd2rust --generic_mod --target none -i $(realpath $<) @@ -69,9 +70,10 @@ clean: @rm -rf macros/src/vector.rs # Patch dependencies +patch/%.yaml: .deps/%.d .deps/%.d: patch/%.yaml @mkdir -p .deps @echo -e "\tMAKEDEPS\t$*" - @python3 patch/makedeps.py $< >$@ + @svd makedeps $< $@ -include $(DEPS) diff --git a/patch/makedeps.py b/patch/makedeps.py deleted file mode 100644 index 5e88484..0000000 --- a/patch/makedeps.py +++ /dev/null @@ -1,31 +0,0 @@ -""" -makedeps.py -Copyright 2017 Adam Greig -Licensed under the MIT and Apache 2.0 licenses. - -Generate make dependency file for each device. -""" - -import yaml -import os.path -import argparse -import svdpatch - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument("devices", nargs="*") - args = parser.parse_args() - for dpath in args.devices: - with open(dpath) as f: - device = yaml.safe_load(f) - device["_path"] = dpath - deps = svdpatch.yaml_includes(device) - depname = ".deps/{}.d".format( - os.path.splitext(os.path.basename(dpath))[0]) - svdname = "svd/{}.patched.svd".format( - os.path.splitext(os.path.basename(dpath))[0]) - print("{} {} {}: {}".format(dpath, svdname, depname, " ".join(deps))) - -if __name__ == "__main__": - main() diff --git a/patch/svdpatch.py b/patch/svdpatch.py deleted file mode 100644 index 7486081..0000000 --- a/patch/svdpatch.py +++ /dev/null @@ -1,847 +0,0 @@ -""" -svdpatch.py - -Copyright 2017-2019 Adam Greig. -Licensed under the MIT and Apache 2.0 licenses. See LICENSE files for details. - -This script was adapted from stm32-rs (https://github.com/stm32-rs/stm32-rs/blob/master/scripts/svdpatch.py). -To be integrated into the build system, support for an input / output svd argument is added. - -Additional changes: - - Support for _replace_enum to overwrite existing - - Fix field modifications not being able to add new elements - - Add _write_constraint modifier for changing the - - Fix peripheral modifications not being able to add new elements -""" - -import copy -import yaml -import os.path -import argparse -import xml.etree.ElementTree as ET -from fnmatch import fnmatch -from collections import OrderedDict - - -DEVICE_CHILDREN = [ - "vendor", "vendorID", "name", "series", "version", "description", - "licenseText", "headerSystemFilename", "headerDefinitionsPrefix", - "addressUnitBits", "width", "size", "access", "protection", "resetValue", - "resetMask"] - - -# Set up pyyaml to use ordered dicts so we generate the same -# XML output each time -def dict_constructor(loader, node): - return OrderedDict(loader.construct_pairs(node)) - - -_mapping_tag = yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG -yaml.add_constructor(_mapping_tag, dict_constructor, yaml.SafeLoader) - - -def parseargs(): - """Parse our command line arguments, returns a Namespace of results.""" - parser = argparse.ArgumentParser() - parser.add_argument("yaml", help="Path to YAML file to load") - parser.add_argument("svd_in", help="Path to the input SVD file") - parser.add_argument("svd_out", help="Path to write the patched SVD file") - args = parser.parse_args() - return args - - -def matchname(name, spec): - """Check if name matches against a specification.""" - return ( - (not spec.startswith("_")) - and any(fnmatch(name, subspec) for subspec in spec.split(","))) - - -def abspath(frompath, relpath): - """Gets the absolute path of relpath from the point of view of frompath.""" - basepath = os.path.realpath( - os.path.join(os.path.abspath(frompath), os.pardir)) - return os.path.normpath(os.path.join(basepath, relpath)) - - -def update_dict(parent, child): - """ - Recursively merge child.key into parent.key, with parent overriding. - """ - for key in child: - if key == "_path" or key == "_include": - continue - elif key in parent: - if isinstance(parent[key], list): - parent[key] += child[key] - elif isinstance(parent[key], dict): - update_dict(parent[key], child[key]) - else: - parent[key] = child[key] - - -def yaml_includes(parent): - """Recursively loads any included YAML files.""" - included = [] - for relpath in parent.get("_include", []): - path = abspath(parent["_path"], relpath) - if path in included: - continue - with open(path) as f: - child = yaml.safe_load(f) - child["_path"] = path - included.append(path) - # Process any peripheral-level includes in child - for pspec in child: - if not pspec.startswith("_") and "_include" in child[pspec]: - child[pspec]["_path"] = path - included += yaml_includes(child[pspec]) - # Process any top-level includes in child - included += yaml_includes(child) - update_dict(parent, child) - return included - - -def make_write_constraint(wc_range): - """Given a (min, max), returns a writeConstraint Element.""" - wc = ET.Element('writeConstraint') - r = ET.SubElement(wc, 'range') - minimum = ET.SubElement(r, 'minimum') - minimum.text = str(wc_range[0]) - maximum = ET.SubElement(r, 'maximum') - maximum.text = str(wc_range[1]) - wc.tail = "\n " - return wc - - -def make_enumerated_values(name, values, usage="read-write"): - """ - Given a name and a dict of values which maps variant names to (value, - description), returns an enumeratedValues Element. - """ - ev = ET.Element('enumeratedValues') - usagekey = { - "read": "R", - "write": "W", - }.get(usage, "") - ET.SubElement(ev, 'name').text = name + usagekey - ET.SubElement(ev, 'usage').text = usage - if len(set(v[0] for v in values.values())) != len(values): - raise ValueError("enumeratedValue {}: can't have duplicate values" - .format(name)) - if name[0] in "0123456789": - raise ValueError("enumeratedValue {}: can't start with a number" - .format(name)) - for vname in values: - if vname.startswith("_"): - continue - if vname[0] in "0123456789": - raise ValueError("enumeratedValue {}.{}: can't start with a number" - .format(name, vname)) - value, description = values[vname] - if not description: - raise ValueError("enumeratedValue {}: can't have empty description" - " for value {}".format(name, value)) - el = ET.SubElement(ev, 'enumeratedValue') - ET.SubElement(el, 'name').text = vname - ET.SubElement(el, 'description').text = description - ET.SubElement(el, 'value').text = str(value) - ev.tail = "\n " - return ev - - -def make_derived_enumerated_values(name): - """Returns an enumeratedValues Element which is derivedFrom name.""" - evd = ET.Element('enumeratedValues', {"derivedFrom": name}) - evd.tail = "\n " - return evd - - -def iter_peripherals(tree, pspec, check_derived=True): - """Iterates over all peripherals that match pspec.""" - for ptag in tree.iter('peripheral'): - name = ptag.find('name').text - if matchname(name, pspec): - if check_derived and "derivedFrom" in ptag.attrib: - continue - yield ptag - - -def iter_registers(ptag, rspec): - """ - Iterates over all registers that match rspec and live inside ptag. - """ - for rtag in ptag.iter('register'): - name = rtag.find('name').text - if matchname(name, rspec): - yield rtag - - -def iter_fields(rtag, fspec): - """ - Iterates over all fields that match fspec and live inside rtag. - """ - for ftag in rtag.find('fields').iter('field'): - name = ftag.find('name').text - if matchname(name, fspec): - yield ftag - - -def process_device_peripheral_modify(device, pspec, pmod): - """Modify pspec inside device according to pmod.""" - for ptag in iter_peripherals(device, pspec): - for (key, value) in pmod.items(): - ptag.find(key).text = str(value) - - -def process_device_child_modify(device, key, val): - """Modify key inside device and set it to val.""" - for child in device.findall(key): - child.text = str(val) - - -def process_device_cpu_modify(device, mod): - """Modify the `cpu` node inside `device` according to `mod`.""" - cpu = device.find('cpu') - for key, val in mod.items(): - field = cpu.find(key) - if field is not None: - field.text = str(val) - else: - field = ET.SubElement(cpu, key) - field.text = str(val) - - -def process_peripheral_modify(ptag, rspec, rmod): - """Modify rspec inside ptag according to rmod.""" - for rtag in iter_registers(ptag, rspec): - for (key, value) in rmod.items(): - field = rtag.find(key) - if field is not None: - field.text = value - else: - field = ET.SubElement(rtag, key) - field.text = value - - -def process_register_modify(rtag, fspec, fmod): - """Modify fspec inside rtag according to fmod.""" - for ftag in iter_fields(rtag, fspec): - for (key, value) in fmod.items(): - if key == "_write_constraint": - key = "writeConstraint" - - tag = ftag.find(key) - if tag is None: - tag = ET.SubElement(ftag, key) - - if key == "writeConstraint": - # Remove existing constraint contents - for child in list(tag): - tag.remove(child) - if value == "none": - # Completely remove the existing writeConstraint - ftag.remove(tag) - elif value == "enum": - # Only allow enumerated values - enum_tag = ET.SubElement(tag, "useEnumeratedValues") - enum_tag.text = "true" - elif isinstance(value, list): - # Allow a certain range - range_tag = make_write_constraint(value).find("range") - tag.append(range_tag) - else: - raise SvdPatchError('Unknown writeConstraint type {}' - .format(repr(value))) - else: - # For all other tags, just set the value - tag.text = str(value) - - -def process_device_add(device, pname, padd): - """Add pname given by padd to device.""" - parent = device.find('peripherals') - for ptag in parent.iter('peripheral'): - if ptag.find('name').text == pname: - raise SvdPatchError('device already has a peripheral {}' - .format(pname)) - if "derivedFrom" in padd: - derived = padd["derivedFrom"] - pnew = ET.SubElement(parent, 'peripheral', {"derivedFrom": derived}) - else: - pnew = ET.SubElement(parent, 'peripheral') - ET.SubElement(pnew, 'name').text = pname - for (key, value) in padd.items(): - if key == "registers": - ET.SubElement(pnew, 'registers') - for rname in value: - process_peripheral_add_reg(pnew, rname, value[rname]) - elif key == "interrupts": - for iname in value: - process_peripheral_add_int(pnew, iname, value[iname]) - elif key == "addressBlock": - ab = ET.SubElement(pnew, 'addressBlock') - for (ab_key, ab_value) in value.items(): - ET.SubElement(ab, ab_key).text = str(ab_value) - elif key != "derivedFrom": - ET.SubElement(pnew, key).text = str(value) - pnew.tail = "\n " - - -def process_device_derive(device, pname, pderive): - """ - Remove registers from pname and mark it as derivedFrom pderive. - Update all derivedFrom referencing pname. - """ - parent = device.find('peripherals') - ptag = parent.find('./peripheral[name=\'{}\']'.format(pname)) - derived = parent.find('./peripheral[name=\'{}\']'.format(pderive)) - if ptag is None: - raise SvdPatchError('peripheral {} not found'.format(pname)) - if derived is None: - raise SvdPatchError('peripheral {} not found'.format(pderive)) - for (value) in list(ptag): - if value.tag in ('name', 'baseAddress', 'interrupt'): - continue - ptag.remove(value) - for value in ptag: - last = value - last.tail = "\n " - ptag.set('derivedFrom', pderive) - for p in parent.findall('./peripheral[@derivedFrom=\'{}\']'.format(pname)): - p.set('derivedFrom', pderive) - - -def process_device_rebase(device, pnew, pold): - """ - Move registers from pold to pnew. - Update all derivedFrom referencing pold. - """ - parent = device.find('peripherals') - old = parent.find('./peripheral[name=\'{}\']'.format(pold)) - new = parent.find('./peripheral[name=\'{}\']'.format(pnew)) - if old is None: - raise SvdPatchError('peripheral {} not found'.format(pold)) - if new is None: - raise SvdPatchError('peripheral {} not found'.format(pnew)) - for value in new: - last = value - last.tail = "\n " - for (value) in list(old): - if value.tag in ('name', 'baseAddress', 'interrupt'): - continue - old.remove(value) - new.append(value) - for value in old: - last = value - last.tail = "\n " - del new.attrib['derivedFrom'] - old.set('derivedFrom', pnew) - for p in parent.findall('./peripheral[@derivedFrom=\'{}\']'.format(pold)): - p.set('derivedFrom', pnew) - - -def process_peripheral_add_reg(ptag, rname, radd): - """Add rname given by radd to ptag.""" - parent = ptag.find('registers') - for rtag in parent.iter('register'): - if rtag.find('name').text == rname: - raise SvdPatchError('peripheral {} already has a register {}' - .format(ptag.find('name').text, rname)) - rnew = ET.SubElement(parent, 'register') - ET.SubElement(rnew, 'name').text = rname - ET.SubElement(rnew, 'fields') - for (key, value) in radd.items(): - if key == "fields": - for fname in value: - process_register_add(rnew, fname, value[fname]) - else: - ET.SubElement(rnew, key).text = str(value) - rnew.tail = "\n " - - -def process_peripheral_add_int(ptag, iname, iadd): - """Add iname given by iadd to ptag.""" - for itag in ptag.iter('interrupt'): - if itag.find('name').text == iname: - raise SvdPatchError('peripheral {} already has an interrupt {}' - .format(ptag.find('name').text, iname)) - inew = ET.SubElement(ptag, 'interrupt') - ET.SubElement(inew, 'name').text = iname - for key, val in iadd.items(): - ET.SubElement(inew, key).text = str(val) - inew.tail = "\n " - - -def process_register_add(rtag, fname, fadd): - """Add fname given by fadd to rtag.""" - parent = rtag.find('fields') - if parent is None: - parent = ET.SubElement(rtag, 'fields') - else: - for ftag in parent.iter('field'): - if ftag.find('name').text == fname: - raise SvdPatchError('register {} already has a field {}' - .format(rtag.find('name').text, fname)) - fnew = ET.SubElement(parent, 'field') - ET.SubElement(fnew, 'name').text = fname - for (key, value) in fadd.items(): - ET.SubElement(fnew, key).text = str(value) - fnew.tail = "\n " - - -def process_device_delete(device, pspec): - """Delete registers matched by rspec inside ptag.""" - for ptag in list(iter_peripherals(device, pspec, check_derived=False)): - device.find('peripherals').remove(ptag) - - -def process_peripheral_delete(ptag, rspec): - """Delete registers matched by rspec inside ptag.""" - for rtag in list(iter_registers(ptag, rspec)): - ptag.find('registers').remove(rtag) - - -def process_register_delete(rtag, fspec): - """Delete fields matched by fspec inside rtag.""" - for ftag in list(iter_fields(rtag, fspec)): - rtag.find('fields').remove(ftag) - -def process_peripheral_strip(ptag, prefix): - """Delete prefix in register names inside ptag.""" - for rtag in ptag.iter('register'): - nametag = rtag.find('name') - name = nametag.text - if name.startswith(prefix): - nametag.text = name[len(prefix):] - dnametag = rtag.find('displayName') - dname = dnametag.text - if dname.startswith(prefix): - dnametag.text = dname[len(prefix):] - -def spec_ind(spec): - """ - Find left and right indices of enumeration token in specification string. - """ - li1 = spec.find("*") - li2 = spec.find("?") - li3 = spec.find("[") - li = li1 if li1 > -1 else li2 if li2 > -1 else li3 if li3 > -1 else None - ri1 = spec[::-1].find("*") - ri2 = spec[::-1].find("?") - ri3 = spec[::-1].find("]") - ri = ri1 if ri1 > -1 else ri2 if ri2 > -1 else ri3 if ri3 > -1 else None - return li, ri - - -def check_offsets(offsets, dimIncrement): - for o1, o2 in zip(offsets[:-1], offsets[1:]): - if o2-o1 != dimIncrement: - return False - return True - -def get_bitmask(rtag): - """Calculate filling of register""" - mask = 0x0 - for ftag in iter_fields(rtag, "*"): - foffset = int(ftag.findtext("bitOffset"), 0) - fwidth = int(ftag.findtext("bitWidth"), 0) - mask |= (0xffffffff >> (32-fwidth)) << foffset - return mask - -def check_bitmasks(masks, mask): - for m in masks: - if m != mask: - return False - return True - -def process_peripheral_regs_array(ptag, rspec, rmod): - """Collect same registers in peripheral into register array.""" - registers = [] - li, ri = spec_ind(rspec) - for rtag in list(iter_registers(ptag, rspec)): - rname = rtag.findtext('name') - registers.append([rtag, rname[li:len(rname)-ri], - int(rtag.findtext('addressOffset'), 0)]) - dim = len(registers) - if dim == 0: - raise SvdPatchError("{}: registers {} not found" - .format(ptag.findtext('name'), rspec)) - registers = sorted(registers, key=lambda r: r[2]) - - dimIndex = "{0}-{0}".format(registers[0][1]) if dim == 1 else ",".join([r[1] for r in registers]) - offsets = [r[2] for r in registers] - bitmasks = [get_bitmask(r[0]) for r in registers] - dimIncrement = 0 - if dim > 1: - dimIncrement = offsets[1]-offsets[0] - - if not (check_offsets(offsets, dimIncrement) and check_bitmasks(bitmasks, bitmasks[0])): - raise SvdPatchError("{}: registers cannot be collected into {} array" - .format(ptag.findtext('name'), rspec)) - for rtag, _, _ in registers[1:]: - ptag.find('registers').remove(rtag) - rtag = registers[0][0] - if 'name' in rmod: - name = rmod['name'] - else: - name = rspec[:li]+"%s"+rspec[len(rspec)-ri:] - rtag.find('name').text = name - process_peripheral_register(ptag, name, rmod) - ET.SubElement(rtag, 'dim').text = str(dim) - ET.SubElement(rtag, 'dimIndex').text = dimIndex - ET.SubElement(rtag, 'dimIncrement').text = hex(dimIncrement) - - -def process_peripheral_cluster(ptag, cname, cmod): - """Collect registers in peripheral into clusters.""" - rdict = {} - first = True - check = True - rspecs = [r for r in cmod if r != "description"] - for rspec in rspecs: - registers = [] - li, ri = spec_ind(rspec) - for rtag in list(iter_registers(ptag, rspec)): - rname = rtag.findtext('name') - registers.append([rtag, rname[li:len(rname)-ri], - int(rtag.findtext('addressOffset'), 0)]) - registers = sorted(registers, key=lambda r: r[2]) - rdict[rspec] = registers - bitmasks = [get_bitmask(r[0]) for r in registers] - if first: - dim = len(registers) - if dim == 0: - check = False - break - dimIndex = ",".join([r[1] for r in registers]) - offsets = [r[2] for r in registers] - dimIncrement = 0 - if dim > 1: - dimIncrement = offsets[1]-offsets[0] - if not (check_offsets(offsets, dimIncrement) and check_bitmasks(bitmasks, bitmasks[0])): - check = False - break - else: - if ( - (dim != len(registers)) or - (dimIndex != ",".join([r[1] for r in registers])) or - (not check_offsets(offsets, dimIncrement)) or - (not check_bitmasks(bitmasks, bitmasks[0])) - ): - check = False - break - first = False - if not check: - raise SvdPatchError("{}: registers cannot be collected into {} cluster" - .format(ptag.findtext('name'), cname)) - ctag = ET.SubElement(ptag.find('registers'), 'cluster') - addressOffset = min([registers[0][2] for _, registers in rdict.items()]) - ET.SubElement(ctag, 'name').text = cname - if 'description' in cmod: - description = cmod['description'] - else: - description = ("Cluster {}, containing {}" - .format(cname, ", ".join(rspecs))) - ET.SubElement(ctag, 'description').text = description - ET.SubElement(ctag, 'addressOffset').text = hex(addressOffset) - for rspec, registers in rdict.items(): - for rtag, _, _ in registers[1:]: - ptag.find('registers').remove(rtag) - rtag = registers[0][0] - rmod = cmod[rspec] - process_peripheral_register(ptag, rspec, rmod) - new_rtag = copy.deepcopy(rtag) - ptag.find('registers').remove(rtag) - if 'name' in rmod: - name = rmod['name'] - else: - li, ri = spec_ind(rspec) - name = rspec[:li]+rspec[len(rspec)-ri:] - new_rtag.find('name').text = name - offset = new_rtag.find('addressOffset') - offset.text = hex(int(offset.text, 0)-addressOffset) - ctag.append(new_rtag) - ET.SubElement(ctag, 'dim').text = str(dim) - ET.SubElement(ctag, 'dimIndex').text = dimIndex - ET.SubElement(ctag, 'dimIncrement').text = hex(dimIncrement) - - -class SvdPatchError(ValueError): - pass - - -class RegisterMergeError(SvdPatchError): - pass - - -class MissingFieldError(SvdPatchError): - pass - - -class MissingRegisterError(SvdPatchError): - pass - - -class MissingPeripheralError(SvdPatchError): - pass - - -def process_register_merge(rtag, fspec): - """Merge all fspec in rtag.""" - fields = list(iter_fields(rtag, fspec)) - if len(fields) == 0: - rname = rtag.find('name').text - raise RegisterMergeError("Could not find any fields to merge {}.{}" - .format(rname, fspec)) - parent = rtag.find('fields') - name = os.path.commonprefix([f.find('name').text for f in fields]) - desc = fields[0].find('description').text - bitwidth = sum(int(f.find('bitWidth').text) for f in fields) - bitoffset = min(int(f.find('bitOffset').text) for f in fields) - for field in fields: - parent.remove(field) - fnew = ET.SubElement(parent, 'field') - ET.SubElement(fnew, 'name').text = name - ET.SubElement(fnew, 'description').text = desc - ET.SubElement(fnew, 'bitOffset').text = str(bitoffset) - ET.SubElement(fnew, 'bitWidth').text = str(bitwidth) - - -def process_register_split(rtag, fspec): - """split all fspec in rtag.""" - fields = list(iter_fields(rtag, fspec)) - if len(fields) == 0: - rname = rtag.find('name').text - raise RegisterMergeError("Could not find any fields to split {}.{}" - .format(rname, fspec)) - parent = rtag.find('fields') - name = os.path.commonprefix([f.find('name').text for f in fields]) - desc = fields[0].find('description').text - bitwidth = sum(int(f.find('bitWidth').text) for f in fields) - parent.remove(fields[0]) - for i in range(bitwidth): - fnew = ET.SubElement(parent, 'field') - ET.SubElement(fnew, 'name').text = name + str(i) - ET.SubElement(fnew, 'description').text = desc - ET.SubElement(fnew, 'bitOffset').text = str(i) - ET.SubElement(fnew, 'bitWidth').text = str(1) - - -def process_field_enum(pname, rtag, fspec, field, usage="read-write"): - """Add an enumeratedValues given by field to all fspec in rtag.""" - replace_if_exists = False - if "_replace_enum" in field: - field = field["_replace_enum"] - replace_if_exists = True - - derived, enum, enum_name, enum_usage = None, None, None, None - for ftag in iter_fields(rtag, fspec): - name = ftag.find('name').text - - if enum is None: - enum = make_enumerated_values(name, field, usage=usage) - enum_name = enum.find('name').text - enum_usage = enum.find('usage').text - - for ev in ftag.iter('enumeratedValues'): - ev_usage_tag = ev.find('usage') - ev_usage = ev_usage_tag.text if ev_usage_tag is not None else 'read-write' - if ev_usage == enum_usage or ev_usage == "read-write": - if replace_if_exists: - ftag.remove(ev) - else: - print(pname, fspec, field) - raise SvdPatchError( - "{}: field {} already has enumeratedValues for {}. Use '_replace_enum' to overwrite." - .format(pname, name, ev_usage)) - - if derived is None: - ftag.append(enum) - derived = make_derived_enumerated_values(enum_name) - else: - ftag.append(derived) - if derived is None: - rname = rtag.find('name').text - raise MissingFieldError("Could not find {}:{}.{}" - .format(pname, rname, fspec)) - - -def process_field_range(pname, rtag, fspec, field): - """Add a writeConstraint range given by field to all fspec in rtag.""" - set_any = False - for ftag in iter_fields(rtag, fspec): - ftag.append(make_write_constraint(field)) - set_any = True - if not set_any: - rname = rtag.find('name').text - raise MissingFieldError("Could not find {}:{}.{}" - .format(pname, rname, fspec)) - - -def process_register_field(pname, rtag, fspec, field): - """Work through a field, handling either an enum or a range.""" - if isinstance(field, dict): - usages = ("_read", "_write") - - if not any(u in field for u in usages): - process_field_enum(pname, rtag, fspec, field) - - for usage in (u for u in usages if u in field): - process_field_enum(pname, rtag, fspec, field[usage], - usage=usage.replace("_", "")) - - elif isinstance(field, list) and len(field) == 2: - process_field_range(pname, rtag, fspec, field) - - -def process_peripheral_register(ptag, rspec, register, update_fields=True): - """Work through a register, handling all fields.""" - # Find all registers that match the spec - pname = ptag.find('name').text - rcount = 0 - for rtag in iter_registers(ptag, rspec): - rcount += 1 - # Handle deletions - for fspec in register.get("_delete", []): - process_register_delete(rtag, fspec) - # Handle modifications - for fspec in register.get("_modify", []): - fmod = register["_modify"][fspec] - process_register_modify(rtag, fspec, fmod) - # Handle additions - for fname in register.get("_add", []): - fadd = register["_add"][fname] - process_register_add(rtag, fname, fadd) - # Handle merges - for fspec in register.get("_merge", []): - process_register_merge(rtag, fspec) - # Handle splits - for fspec in register.get("_split", []): - process_register_split(rtag, fspec) - # Handle fields - if update_fields: - for fspec in register: - if not fspec.startswith("_"): - field = register[fspec] - process_register_field(pname, rtag, fspec, field) - if rcount == 0: - raise MissingRegisterError("Could not find {}:{}" - .format(pname, rspec)) - - -def process_peripheral(svd, pspec, peripheral, update_fields=True): - """Work through a peripheral, handling all registers.""" - # Find all peripherals that match the spec - pcount = 0 - for ptag in iter_peripherals(svd, pspec): - pcount += 1 - # Handle deletions - for rspec in peripheral.get("_delete", []): - process_peripheral_delete(ptag, rspec) - # Handle modifications - for rspec in peripheral.get("_modify", {}): - rmod = peripheral["_modify"][rspec] - process_peripheral_modify(ptag, rspec, rmod) - # Handle strips - for rspec in peripheral.get("_strip", []): - process_peripheral_strip(ptag, rspec) - # Handle additions - for rname in peripheral.get("_add", {}): - radd = peripheral["_add"][rname] - if rname == "_registers": - for rname in radd: - process_peripheral_add_reg(ptag, rname, radd[rname]) - elif rname == "_interrupts": - for iname in radd: - process_peripheral_add_int(ptag, iname, radd[iname]) - else: - process_peripheral_add_reg(ptag, rname, radd) - # Handle registers - for rspec in peripheral: - if not rspec.startswith("_"): - register = peripheral[rspec] - process_peripheral_register(ptag, rspec, register, - update_fields) - # Handle register arrays - for rspec in peripheral.get("_array", {}): - rmod = peripheral["_array"][rspec] - process_peripheral_regs_array(ptag, rspec, rmod) - # Handle clusters - for cname in peripheral.get("_cluster", {}): - cmod = peripheral["_cluster"][cname] - process_peripheral_cluster(ptag, cname, cmod) - if pcount == 0: - raise MissingPeripheralError("Could not find {}".format(pspec)) - - -def process_device(svd, device, update_fields=True): - """Work through a device, handling all peripherals""" - - # Handle any deletions - for pspec in device.get("_delete", []): - process_device_delete(svd, pspec) - - # Handle any modifications - for key in device.get("_modify", {}): - val = device["_modify"][key] - if key == "cpu": - process_device_cpu_modify(svd, val) - elif key == "_peripherals": - for pspec in val: - pmod = device['_modify']['_peripherals'][pspec] - process_device_peripheral_modify(svd, pspec, pmod) - elif key in DEVICE_CHILDREN: - process_device_child_modify(svd, key, val) - else: - process_device_peripheral_modify(svd, key, val) - - # Handle any new peripherals (!) - for pname in device.get("_add", []): - padd = device["_add"][pname] - process_device_add(svd, pname, padd) - - # Handle any derived peripherals - for pname in device.get("_derive", []): - pderive = device["_derive"][pname] - process_device_derive(svd, pname, pderive) - - # Handle any rebased peripherals - for pname in device.get("_rebase", []): - pold = device["_rebase"][pname] - process_device_rebase(svd, pname, pold) - - # Now process all peripherals - for periphspec in device: - if not periphspec.startswith("_"): - device[periphspec]["_path"] = device["_path"] - process_peripheral(svd, periphspec, device[periphspec], - update_fields) - - -def main(): - # Load the specified YAML root file - args = parseargs() - with open(args.yaml) as f: - root = yaml.safe_load(f) - root["_path"] = args.yaml - - # Load the specified SVD file - svdpath = args.svd_in - if not os.path.exists(svdpath): - raise FileNotFoundError("The input SVD file does not exist") - svdpath_out = args.svd_out - svd = ET.parse(svdpath) - - # Load all included YAML files - yaml_includes(root) - - # Process device - process_device(svd, root) - - # SVD should now be updated, write it out - svd.write(svdpath_out) - - -if __name__ == "__main__": - main() -- 2.49.0