modm_data.svd.model

  1# Copyright 2022, Niklas Hauser
  2# SPDX-License-Identifier: MPL-2.0
  3
  4from anytree import Node
  5
  6
  7class Device(Node):
  8    def __init__(self, name, **kw):
  9        if "compatible" not in kw:
 10            kw["compatible"] = [name]
 11        super().__init__(name, **kw)
 12
 13    def __hash__(self) -> int:
 14        value = 0
 15        for peripheral in self.children:
 16            value += hash(peripheral)
 17            for register in peripheral.children:
 18                value += hash(register)
 19                for bitfield in register.children:
 20                    value += hash(bitfield)
 21        return value
 22
 23    def __eq__(self, other) -> bool:
 24        if isinstance(other, self.__class__):
 25            return compare_device_trees(self, other)
 26        else:
 27            return NotImplemented
 28
 29
 30class PeripheralType(Node):
 31    def __init__(self, name, **kw):
 32        super().__init__(name, **kw)
 33
 34    def __hash__(self) -> int:
 35        value = hash(self.name)
 36        if hasattr(self, "filters") and self.filters:
 37            value += hash(str(self.filters))
 38        return value
 39
 40    def __eq__(self, other) -> bool:
 41        if isinstance(other, self.__class__):
 42            return self.name == other.name and self.filters == other.filters
 43        else:
 44            return NotImplemented
 45
 46
 47class Peripheral(Node):
 48    def __init__(self, name, type, address, **kw):
 49        super().__init__(name, type=type, address=address, **kw)
 50
 51    def __hash__(self) -> int:
 52        value = hash(f"{self.name} {self.address} {self.type}")
 53        if hasattr(self, "filters") and self.filters:
 54            value += hash(str(self.filters))
 55        return value
 56
 57    def __eq__(self, other) -> bool:
 58        if isinstance(other, self.__class__):
 59            return self.name == other.name and self.address == other.address
 60        else:
 61            return NotImplemented
 62
 63
 64class Register(Node):
 65    def __init__(self, name, offset, width=None, **kw):
 66        super().__init__(name, offset=offset, width=width or 4, **kw)
 67
 68    @property
 69    def address(self) -> int:
 70        return self.parent.address + self.offset
 71
 72    @property
 73    def addresses(self) -> int:
 74        for ii in range(self.width):
 75            yield self.parent.address + self.offset + ii
 76
 77    def __hash__(self) -> int:
 78        value = hash(f"{self.name} {self.offset} {self.width}")
 79        if hasattr(self, "filters") and self.filters:
 80            value += hash(str(self.filters))
 81        return value
 82
 83    def __eq__(self, other) -> bool:
 84        if isinstance(other, self.__class__):
 85            return self.name == other.name and self.offset == other.offset
 86        else:
 87            return NotImplemented
 88
 89
 90class BitField(Node):
 91    def __init__(self, name, position, width=None, **kw):
 92        super().__init__(name, position=position, width=width or 1, **kw)
 93
 94    @property
 95    def bit_address(self) -> int:
 96        return self.parent.address * 8 + self.position
 97
 98    @property
 99    def bit_addresses(self) -> int:
100        for ii in range(self.width):
101            yield self.parent.address * 8 + self.position + ii
102
103    def __hash__(self) -> int:
104        return hash(f"{self.name} {self.position} {self.width}")
105
106    def __eq__(self, other) -> bool:
107        if isinstance(other, self.__class__):
108            return self.name == other.name and self.position == other.position
109        else:
110            return NotImplemented
111
112
113# class EnumeratedValue(Node):
114#     def __init__(self, name, value):
115#         super().__init__(name, value=value)
116
117
118def _compare_trees(left, right):
119    if left != right:
120        return False
121    if len(left.children) != len(right.children):
122        return False
123    if not left.children:
124        return True
125    return all(_compare_trees(l, r) for l,r in zip(left.children, right.children))
126
127
128def compare_device_trees(left, right):
129    assert isinstance(left, Device) and isinstance(right, Device)
130    if len(left.children) != len(right.children): return False
131    if not left.children: return True
132    return all(_compare_trees(l, r) for l,r in zip(left.children, right.children))
class Device(anytree.node.node.Node):
 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')
Device(name, **kw)
 9    def __init__(self, name, **kw):
10        if "compatible" not in kw:
11            kw["compatible"] = [name]
12        super().__init__(name, **kw)
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
class PeripheralType(anytree.node.node.Node):
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')
PeripheralType(name, **kw)
32    def __init__(self, name, **kw):
33        super().__init__(name, **kw)
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
class Peripheral(anytree.node.node.Node):
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')
Peripheral(name, type, address, **kw)
49    def __init__(self, name, type, address, **kw):
50        super().__init__(name, type=type, address=address, **kw)
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
class Register(anytree.node.node.Node):
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')
Register(name, offset, width=None, **kw)
66    def __init__(self, name, offset, width=None, **kw):
67        super().__init__(name, offset=offset, width=width or 4, **kw)
address: int
69    @property
70    def address(self) -> int:
71        return self.parent.address + self.offset
addresses: int
73    @property
74    def addresses(self) -> int:
75        for ii in range(self.width):
76            yield self.parent.address + self.offset + ii
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
class BitField(anytree.node.node.Node):
 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')
BitField(name, position, width=None, **kw)
92    def __init__(self, name, position, width=None, **kw):
93        super().__init__(name, position=position, width=width or 1, **kw)
bit_address: int
95    @property
96    def bit_address(self) -> int:
97        return self.parent.address * 8 + self.position
bit_addresses: int
 99    @property
100    def bit_addresses(self) -> int:
101        for ii in range(self.width):
102            yield self.parent.address * 8 + self.position + ii
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
def compare_device_trees(left, right):
129def compare_device_trees(left, right):
130    assert isinstance(left, Device) and isinstance(right, Device)
131    if len(left.children) != len(right.children): return False
132    if not left.children: return True
133    return all(_compare_trees(l, r) for l,r in zip(left.children, right.children))