modm_data.svd
1# Copyright 2022, Niklas Hauser 2# SPDX-License-Identifier: MPL-2.0 3 4from .model import Device, PeripheralType, Peripheral, Register, BitField, EnumeratedValue, compare_device_trees 5from .write import format_svd, write_svd 6from .read import read_svd 7 8__all__ = [ 9 "stmicro", 10 "Device", 11 "PeripheralType", 12 "Peripheral", 13 "Register", 14 "BitField", 15 "EnumeratedValue", 16 "compare_device_trees", 17 "format_svd", 18 "write_svd", 19 "read_svd", 20]
8class Device(Node): 9 def __init__(self, name, **kw): 10 if "compatible" not in kw: 11 kw["compatible"] = [name] 12 super().__init__(name, **kw) 13 14 def __hash__(self) -> int: 15 value = 0 16 for peripheral in self.children: 17 value += hash(peripheral) 18 for register in peripheral.children: 19 value += hash(register) 20 for bitfield in register.children: 21 value += hash(bitfield) 22 return value 23 24 def __eq__(self, other) -> bool: 25 if isinstance(other, self.__class__): 26 return compare_device_trees(self, other) 27 else: 28 return NotImplemented
A simple tree node with a name and any kwargs.
Args: name: A name or any other object this node can reference to as identifier.
Keyword Args: parent: Reference to parent node. children: Iterable with child nodes. *: Any other given attribute is just stored as object attribute.
Other than :any:AnyNode this class has at least the name attribute,
to distinguish between different instances.
The parent attribute refers the parent node:
>>> from anytree import Node, RenderTree
>>> root = Node("root")
>>> s0 = Node("sub0", parent=root)
>>> s0b = Node("sub0B", parent=s0, foo=4, bar=109)
>>> s0a = Node("sub0A", parent=s0)
>>> s1 = Node("sub1", parent=root)
>>> s1a = Node("sub1A", parent=s1)
>>> s1b = Node("sub1B", parent=s1, bar=8)
>>> s1c = Node("sub1C", parent=s1)
>>> s1ca = Node("sub1Ca", parent=s1c)
>>> print(RenderTree(root))
Node('/root')
├── Node('/root/sub0')
│ ├── Node('/root/sub0/sub0B', bar=109, foo=4)
│ └── Node('/root/sub0/sub0A')
└── Node('/root/sub1')
├── Node('/root/sub1/sub1A')
├── Node('/root/sub1/sub1B', bar=8)
└── Node('/root/sub1/sub1C')
└── Node('/root/sub1/sub1C/sub1Ca')
The same tree can be constructed by using the children attribute:
>>> root = Node("root", children=[
... Node("sub0", children=[
... Node("sub0B", bar=109, foo=4),
... Node("sub0A", children=None),
... ]),
... Node("sub1", children=[
... Node("sub1A"),
... Node("sub1B", bar=8, children=[]),
... Node("sub1C", children=[
... Node("sub1Ca"),
... ]),
... ]),
... ])
>>> print(RenderTree(root))
Node('/root')
├── Node('/root/sub0')
│ ├── Node('/root/sub0/sub0B', bar=109, foo=4)
│ └── Node('/root/sub0/sub0A')
└── Node('/root/sub1')
├── Node('/root/sub1/sub1A')
├── Node('/root/sub1/sub1B', bar=8)
└── Node('/root/sub1/sub1C')
└── Node('/root/sub1/sub1C/sub1Ca')
Inherited Members
- anytree.node.node.Node
- name
- parent
- anytree.node.nodemixin.NodeMixin
- separator
- children
- path
- iter_path_reverse
- ancestors
- anchestors
- descendants
- root
- siblings
- leaves
- is_leaf
- is_root
- height
- depth
- size
31class PeripheralType(Node): 32 def __init__(self, name, **kw): 33 super().__init__(name, **kw) 34 35 def __hash__(self) -> int: 36 value = hash(self.name) 37 if hasattr(self, "filters") and self.filters: 38 value += hash(str(self.filters)) 39 return value 40 41 def __eq__(self, other) -> bool: 42 if isinstance(other, self.__class__): 43 return self.name == other.name and self.filters == other.filters 44 else: 45 return NotImplemented
A simple tree node with a name and any kwargs.
Args: name: A name or any other object this node can reference to as identifier.
Keyword Args: parent: Reference to parent node. children: Iterable with child nodes. *: Any other given attribute is just stored as object attribute.
Other than :any:AnyNode this class has at least the name attribute,
to distinguish between different instances.
The parent attribute refers the parent node:
>>> from anytree import Node, RenderTree
>>> root = Node("root")
>>> s0 = Node("sub0", parent=root)
>>> s0b = Node("sub0B", parent=s0, foo=4, bar=109)
>>> s0a = Node("sub0A", parent=s0)
>>> s1 = Node("sub1", parent=root)
>>> s1a = Node("sub1A", parent=s1)
>>> s1b = Node("sub1B", parent=s1, bar=8)
>>> s1c = Node("sub1C", parent=s1)
>>> s1ca = Node("sub1Ca", parent=s1c)
>>> print(RenderTree(root))
Node('/root')
├── Node('/root/sub0')
│ ├── Node('/root/sub0/sub0B', bar=109, foo=4)
│ └── Node('/root/sub0/sub0A')
└── Node('/root/sub1')
├── Node('/root/sub1/sub1A')
├── Node('/root/sub1/sub1B', bar=8)
└── Node('/root/sub1/sub1C')
└── Node('/root/sub1/sub1C/sub1Ca')
The same tree can be constructed by using the children attribute:
>>> root = Node("root", children=[
... Node("sub0", children=[
... Node("sub0B", bar=109, foo=4),
... Node("sub0A", children=None),
... ]),
... Node("sub1", children=[
... Node("sub1A"),
... Node("sub1B", bar=8, children=[]),
... Node("sub1C", children=[
... Node("sub1Ca"),
... ]),
... ]),
... ])
>>> print(RenderTree(root))
Node('/root')
├── Node('/root/sub0')
│ ├── Node('/root/sub0/sub0B', bar=109, foo=4)
│ └── Node('/root/sub0/sub0A')
└── Node('/root/sub1')
├── Node('/root/sub1/sub1A')
├── Node('/root/sub1/sub1B', bar=8)
└── Node('/root/sub1/sub1C')
└── Node('/root/sub1/sub1C/sub1Ca')
Inherited Members
- anytree.node.node.Node
- name
- parent
- anytree.node.nodemixin.NodeMixin
- separator
- children
- path
- iter_path_reverse
- ancestors
- anchestors
- descendants
- root
- siblings
- leaves
- is_leaf
- is_root
- height
- depth
- size
48class Peripheral(Node): 49 def __init__(self, name, type, address, **kw): 50 super().__init__(name, type=type, address=address, **kw) 51 52 def __hash__(self) -> int: 53 value = hash(f"{self.name} {self.address} {self.type}") 54 if hasattr(self, "filters") and self.filters: 55 value += hash(str(self.filters)) 56 return value 57 58 def __eq__(self, other) -> bool: 59 if isinstance(other, self.__class__): 60 return self.name == other.name and self.address == other.address 61 else: 62 return NotImplemented
A simple tree node with a name and any kwargs.
Args: name: A name or any other object this node can reference to as identifier.
Keyword Args: parent: Reference to parent node. children: Iterable with child nodes. *: Any other given attribute is just stored as object attribute.
Other than :any:AnyNode this class has at least the name attribute,
to distinguish between different instances.
The parent attribute refers the parent node:
>>> from anytree import Node, RenderTree
>>> root = Node("root")
>>> s0 = Node("sub0", parent=root)
>>> s0b = Node("sub0B", parent=s0, foo=4, bar=109)
>>> s0a = Node("sub0A", parent=s0)
>>> s1 = Node("sub1", parent=root)
>>> s1a = Node("sub1A", parent=s1)
>>> s1b = Node("sub1B", parent=s1, bar=8)
>>> s1c = Node("sub1C", parent=s1)
>>> s1ca = Node("sub1Ca", parent=s1c)
>>> print(RenderTree(root))
Node('/root')
├── Node('/root/sub0')
│ ├── Node('/root/sub0/sub0B', bar=109, foo=4)
│ └── Node('/root/sub0/sub0A')
└── Node('/root/sub1')
├── Node('/root/sub1/sub1A')
├── Node('/root/sub1/sub1B', bar=8)
└── Node('/root/sub1/sub1C')
└── Node('/root/sub1/sub1C/sub1Ca')
The same tree can be constructed by using the children attribute:
>>> root = Node("root", children=[
... Node("sub0", children=[
... Node("sub0B", bar=109, foo=4),
... Node("sub0A", children=None),
... ]),
... Node("sub1", children=[
... Node("sub1A"),
... Node("sub1B", bar=8, children=[]),
... Node("sub1C", children=[
... Node("sub1Ca"),
... ]),
... ]),
... ])
>>> print(RenderTree(root))
Node('/root')
├── Node('/root/sub0')
│ ├── Node('/root/sub0/sub0B', bar=109, foo=4)
│ └── Node('/root/sub0/sub0A')
└── Node('/root/sub1')
├── Node('/root/sub1/sub1A')
├── Node('/root/sub1/sub1B', bar=8)
└── Node('/root/sub1/sub1C')
└── Node('/root/sub1/sub1C/sub1Ca')
Inherited Members
- anytree.node.node.Node
- name
- parent
- anytree.node.nodemixin.NodeMixin
- separator
- children
- path
- iter_path_reverse
- ancestors
- anchestors
- descendants
- root
- siblings
- leaves
- is_leaf
- is_root
- height
- depth
- size
65class Register(Node): 66 def __init__(self, name, offset, width=None, **kw): 67 super().__init__(name, offset=offset, width=width or 4, **kw) 68 69 @property 70 def address(self) -> int: 71 return self.parent.address + self.offset 72 73 @property 74 def addresses(self) -> int: 75 for ii in range(self.width): 76 yield self.parent.address + self.offset + ii 77 78 def __hash__(self) -> int: 79 value = hash(f"{self.name} {self.offset} {self.width}") 80 if hasattr(self, "filters") and self.filters: 81 value += hash(str(self.filters)) 82 return value 83 84 def __eq__(self, other) -> bool: 85 if isinstance(other, self.__class__): 86 return self.name == other.name and self.offset == other.offset 87 else: 88 return NotImplemented
A simple tree node with a name and any kwargs.
Args: name: A name or any other object this node can reference to as identifier.
Keyword Args: parent: Reference to parent node. children: Iterable with child nodes. *: Any other given attribute is just stored as object attribute.
Other than :any:AnyNode this class has at least the name attribute,
to distinguish between different instances.
The parent attribute refers the parent node:
>>> from anytree import Node, RenderTree
>>> root = Node("root")
>>> s0 = Node("sub0", parent=root)
>>> s0b = Node("sub0B", parent=s0, foo=4, bar=109)
>>> s0a = Node("sub0A", parent=s0)
>>> s1 = Node("sub1", parent=root)
>>> s1a = Node("sub1A", parent=s1)
>>> s1b = Node("sub1B", parent=s1, bar=8)
>>> s1c = Node("sub1C", parent=s1)
>>> s1ca = Node("sub1Ca", parent=s1c)
>>> print(RenderTree(root))
Node('/root')
├── Node('/root/sub0')
│ ├── Node('/root/sub0/sub0B', bar=109, foo=4)
│ └── Node('/root/sub0/sub0A')
└── Node('/root/sub1')
├── Node('/root/sub1/sub1A')
├── Node('/root/sub1/sub1B', bar=8)
└── Node('/root/sub1/sub1C')
└── Node('/root/sub1/sub1C/sub1Ca')
The same tree can be constructed by using the children attribute:
>>> root = Node("root", children=[
... Node("sub0", children=[
... Node("sub0B", bar=109, foo=4),
... Node("sub0A", children=None),
... ]),
... Node("sub1", children=[
... Node("sub1A"),
... Node("sub1B", bar=8, children=[]),
... Node("sub1C", children=[
... Node("sub1Ca"),
... ]),
... ]),
... ])
>>> print(RenderTree(root))
Node('/root')
├── Node('/root/sub0')
│ ├── Node('/root/sub0/sub0B', bar=109, foo=4)
│ └── Node('/root/sub0/sub0A')
└── Node('/root/sub1')
├── Node('/root/sub1/sub1A')
├── Node('/root/sub1/sub1B', bar=8)
└── Node('/root/sub1/sub1C')
└── Node('/root/sub1/sub1C/sub1Ca')
Inherited Members
- anytree.node.node.Node
- name
- parent
- anytree.node.nodemixin.NodeMixin
- separator
- children
- path
- iter_path_reverse
- ancestors
- anchestors
- descendants
- root
- siblings
- leaves
- is_leaf
- is_root
- height
- depth
- size
91class BitField(Node): 92 def __init__(self, name, position, width=None, **kw): 93 super().__init__(name, position=position, width=width or 1, **kw) 94 95 @property 96 def bit_address(self) -> int: 97 return self.parent.address * 8 + self.position 98 99 @property 100 def bit_addresses(self) -> int: 101 for ii in range(self.width): 102 yield self.parent.address * 8 + self.position + ii 103 104 def __hash__(self) -> int: 105 return hash(f"{self.name} {self.position} {self.width}") 106 107 def __eq__(self, other) -> bool: 108 if isinstance(other, self.__class__): 109 return self.name == other.name and self.position == other.position 110 else: 111 return NotImplemented
A simple tree node with a name and any kwargs.
Args: name: A name or any other object this node can reference to as identifier.
Keyword Args: parent: Reference to parent node. children: Iterable with child nodes. *: Any other given attribute is just stored as object attribute.
Other than :any:AnyNode this class has at least the name attribute,
to distinguish between different instances.
The parent attribute refers the parent node:
>>> from anytree import Node, RenderTree
>>> root = Node("root")
>>> s0 = Node("sub0", parent=root)
>>> s0b = Node("sub0B", parent=s0, foo=4, bar=109)
>>> s0a = Node("sub0A", parent=s0)
>>> s1 = Node("sub1", parent=root)
>>> s1a = Node("sub1A", parent=s1)
>>> s1b = Node("sub1B", parent=s1, bar=8)
>>> s1c = Node("sub1C", parent=s1)
>>> s1ca = Node("sub1Ca", parent=s1c)
>>> print(RenderTree(root))
Node('/root')
├── Node('/root/sub0')
│ ├── Node('/root/sub0/sub0B', bar=109, foo=4)
│ └── Node('/root/sub0/sub0A')
└── Node('/root/sub1')
├── Node('/root/sub1/sub1A')
├── Node('/root/sub1/sub1B', bar=8)
└── Node('/root/sub1/sub1C')
└── Node('/root/sub1/sub1C/sub1Ca')
The same tree can be constructed by using the children attribute:
>>> root = Node("root", children=[
... Node("sub0", children=[
... Node("sub0B", bar=109, foo=4),
... Node("sub0A", children=None),
... ]),
... Node("sub1", children=[
... Node("sub1A"),
... Node("sub1B", bar=8, children=[]),
... Node("sub1C", children=[
... Node("sub1Ca"),
... ]),
... ]),
... ])
>>> print(RenderTree(root))
Node('/root')
├── Node('/root/sub0')
│ ├── Node('/root/sub0/sub0B', bar=109, foo=4)
│ └── Node('/root/sub0/sub0A')
└── Node('/root/sub1')
├── Node('/root/sub1/sub1A')
├── Node('/root/sub1/sub1B', bar=8)
└── Node('/root/sub1/sub1C')
└── Node('/root/sub1/sub1C/sub1Ca')
Inherited Members
- anytree.node.node.Node
- name
- parent
- anytree.node.nodemixin.NodeMixin
- separator
- children
- path
- iter_path_reverse
- ancestors
- anchestors
- descendants
- root
- siblings
- leaves
- is_leaf
- is_root
- height
- depth
- size
114class EnumeratedValue(Node): 115 def __init__(self, name, value, **kw): 116 super().__init__(name, value=value, **kw) 117 118 def __hash__(self) -> int: 119 return hash(f"{self.name} {self.value}") 120 121 def __eq__(self, other) -> bool: 122 if isinstance(other, self.__class__): 123 return self.name == other.name and self.value == other.value 124 else: 125 return NotImplemented
A simple tree node with a name and any kwargs.
Args: name: A name or any other object this node can reference to as identifier.
Keyword Args: parent: Reference to parent node. children: Iterable with child nodes. *: Any other given attribute is just stored as object attribute.
Other than :any:AnyNode this class has at least the name attribute,
to distinguish between different instances.
The parent attribute refers the parent node:
>>> from anytree import Node, RenderTree
>>> root = Node("root")
>>> s0 = Node("sub0", parent=root)
>>> s0b = Node("sub0B", parent=s0, foo=4, bar=109)
>>> s0a = Node("sub0A", parent=s0)
>>> s1 = Node("sub1", parent=root)
>>> s1a = Node("sub1A", parent=s1)
>>> s1b = Node("sub1B", parent=s1, bar=8)
>>> s1c = Node("sub1C", parent=s1)
>>> s1ca = Node("sub1Ca", parent=s1c)
>>> print(RenderTree(root))
Node('/root')
├── Node('/root/sub0')
│ ├── Node('/root/sub0/sub0B', bar=109, foo=4)
│ └── Node('/root/sub0/sub0A')
└── Node('/root/sub1')
├── Node('/root/sub1/sub1A')
├── Node('/root/sub1/sub1B', bar=8)
└── Node('/root/sub1/sub1C')
└── Node('/root/sub1/sub1C/sub1Ca')
The same tree can be constructed by using the children attribute:
>>> root = Node("root", children=[
... Node("sub0", children=[
... Node("sub0B", bar=109, foo=4),
... Node("sub0A", children=None),
... ]),
... Node("sub1", children=[
... Node("sub1A"),
... Node("sub1B", bar=8, children=[]),
... Node("sub1C", children=[
... Node("sub1Ca"),
... ]),
... ]),
... ])
>>> print(RenderTree(root))
Node('/root')
├── Node('/root/sub0')
│ ├── Node('/root/sub0/sub0B', bar=109, foo=4)
│ └── Node('/root/sub0/sub0A')
└── Node('/root/sub1')
├── Node('/root/sub1/sub1A')
├── Node('/root/sub1/sub1B', bar=8)
└── Node('/root/sub1/sub1C')
└── Node('/root/sub1/sub1C/sub1Ca')
Inherited Members
- anytree.node.node.Node
- name
- parent
- anytree.node.nodemixin.NodeMixin
- separator
- children
- path
- iter_path_reverse
- ancestors
- anchestors
- descendants
- root
- siblings
- leaves
- is_leaf
- is_root
- height
- depth
- size
138def compare_device_trees(left, right): 139 assert isinstance(left, Device) and isinstance(right, Device) 140 if len(left.children) != len(right.children): 141 return False 142 if not left.children: 143 return True 144 return all(_compare_trees(left, right) for left, right in zip(left.children, right.children))
114def format_svd(register_tree): 115 device = etree.Element("device") 116 device.set("schemaVersion", "1.1") 117 # device.set("xmlns:xs", "http://www.w3.org/2001/XMLSchema-instance") 118 # device.set("xs:noNamespaceSchemaLocation", "CMSIS-SVD_Schema_1_1.xsd") 119 120 _format_svd(device, register_tree) 121 122 svd = etree.ElementTree(device) 123 return svd
25def read_svd(path) -> Device: 26 """ 27 Reads the peripherals, registers and bit fields of a CMSIS-SVD file. 28 Derived peripherals are resolved, register arrays are not expanded. 29 30 :param path: path to the SVD file. 31 :return: the SVD device tree. 32 """ 33 root = etree.parse(str(path)).getroot() 34 device = Device(root.findtext("name"), compatible=(root.findtext("description") or "").split(",")) 35 36 registers = {} 37 peripherals = [] 38 for node in root.iter("peripheral"): 39 name = node.findtext("name") 40 registers[name] = node.find("registers") 41 peripherals.append((name, node.get("derivedFrom"), _int(node, "baseAddress"))) 42 43 for name, derived_from, address in peripherals: 44 peripheral = Peripheral(name, derived_from, address, parent=device) 45 if derived_from: 46 peripheral.derived_from = derived_from 47 if (nodes := registers[name]) is None and derived_from: 48 nodes = registers.get(derived_from) 49 if nodes is None: 50 continue 51 for rnode in nodes.iter("register"): 52 size = _int(rnode, "size", 32) // 8 53 register = Register(rnode.findtext("name"), _int(rnode, "addressOffset"), size, parent=peripheral) 54 for fnode in rnode.iter("field"): 55 BitField(fnode.findtext("name"), *_bit_range(fnode), parent=register) 56 57 return device
Reads the peripherals, registers and bit fields of a CMSIS-SVD file. Derived peripherals are resolved, register arrays are not expanded.
Parameters
- path: path to the SVD file.
Returns
the SVD device tree.