Skip to content

Commit a1f4c6b

Browse files
authored
Merge pull request #96 from krcb197/73-split-the-auto-generated-test-file-into-one-file-per-addr
73 split the auto generated test file into one file per addr
2 parents 118ea1c + 39d5ae4 commit a1f4c6b

7 files changed

Lines changed: 406 additions & 250 deletions

File tree

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
]
2929
},
3030
install_requires=[
31-
"systemrdl-compiler>=1.21.0",
31+
"systemrdl-compiler>=1.24.0",
3232
"autopep8",
3333
"pylint",
3434
"coverage",

src/peakrdl_python/__about__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
"""
22
Variables that describes the PeakRDL Python Package
33
"""
4-
__version__ = "0.5.0"
4+
__version__ = "0.6.0"
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
"""
2+
Node walkers to be used in the generated of the output code
3+
"""
4+
from typing import Optional, List, Union, Iterator
5+
6+
from systemrdl import RDLListener, WalkerAction # type: ignore
7+
from systemrdl.node import RegNode, MemNode, FieldNode, AddrmapNode, RegfileNode # type: ignore
8+
9+
10+
class AddressMaps(RDLListener):
11+
"""
12+
class intended to be used as part of the walker/listener protocol to find all the desendent
13+
address maps
14+
"""
15+
def __init__(self) -> None:
16+
super().__init__()
17+
self.__address_maps: List[AddrmapNode] = []
18+
19+
def enter_Addrmap(self, node: AddrmapNode) -> Optional[WalkerAction]:
20+
self.__address_maps.append(node)
21+
return WalkerAction.Continue
22+
23+
def __iter__(self) -> Iterator[AddrmapNode]:
24+
return self.__address_maps.__iter__()
25+
26+
27+
class OwnedbyAddressMap(RDLListener):
28+
"""
29+
class intended to be used as part of the walker/listener protocol to find all the items owned
30+
by an address map but not the descendents of any address map
31+
"""
32+
def __init__(self) -> None:
33+
super().__init__()
34+
35+
self.registers: List[RegNode] = []
36+
self.fields: List[RegNode] = []
37+
self.memories: List[RegNode] = []
38+
self.addr_maps: List[AddrmapNode] = []
39+
self.reg_files: List[RegfileNode] = []
40+
41+
def enter_Reg(self, node: RegNode) -> Optional[WalkerAction]:
42+
self.registers.append(node)
43+
return WalkerAction.Continue
44+
45+
def enter_Mem(self, node: MemNode) -> Optional[WalkerAction]:
46+
self.memories.append(node)
47+
return WalkerAction.Continue
48+
49+
def enter_Field(self, node: FieldNode) -> Optional[WalkerAction]:
50+
self.fields.append(node)
51+
return WalkerAction.Continue
52+
53+
def enter_Addrmap(self, node: AddrmapNode) -> Optional[WalkerAction]:
54+
self.addr_maps.append(node)
55+
return WalkerAction.SkipDescendants
56+
57+
def enter_Regfile(self, node: RegfileNode) -> Optional[WalkerAction]:
58+
self.reg_files.append(node)
59+
return WalkerAction.Continue
60+
61+
@property
62+
def nodes(self) -> List[Union[RegNode, MemNode, FieldNode, AddrmapNode, RegfileNode]]:
63+
"""
64+
All the nodes owned by the address map, including:
65+
- address maps
66+
- register files
67+
- registers
68+
- memories
69+
- fields
70+
71+
Returns: list of nodes
72+
73+
"""
74+
return self.addr_maps + self.reg_files + self.memories + self.registers + self.fields

src/peakrdl_python/exporter.py

Lines changed: 125 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import autopep8 # type: ignore
1111
import jinja2 as jj
12+
from systemrdl import RDLWalker # type: ignore
1213

1314
from systemrdl.node import RootNode, Node, RegNode, AddrmapNode, RegfileNode # type: ignore
1415
from systemrdl.node import FieldNode, MemNode, AddressableNode # type: ignore
@@ -28,6 +29,8 @@
2829

2930
from .safe_name_utility import get_python_path_segments, safe_node_name
3031

32+
from ._node_walkers import AddressMaps, OwnedbyAddressMap
33+
3134
from .__about__ import __version__
3235

3336
file_path = os.path.dirname(__file__)
@@ -115,78 +118,145 @@ def export(self, node: Node, path: str,
115118

116119
# If it is the root node, skip to top addrmap
117120
if isinstance(node, RootNode):
118-
node = node.top
121+
top_block = node.top
122+
else:
123+
top_block = node
119124

120125
package_path = os.path.join(path, node.inst_name)
121126
self._create_empty_package(package_path=package_path,
122127
skip_test_case_generation=skip_test_case_generation)
123128

124-
modules = [node]
129+
self._build_node_type_table(top_block)
130+
131+
context = {
132+
'print': print,
133+
'type': type,
134+
'top_node': top_block,
135+
'systemrdlFieldNode': FieldNode,
136+
'systemrdlRegNode': RegNode,
137+
'systemrdlRegfileNode': RegfileNode,
138+
'systemrdlAddrmapNode': AddrmapNode,
139+
'systemrdlMemNode': MemNode,
140+
'systemrdlAddressableNode': AddressableNode,
141+
'systemrdlSignalNode': SignalNode,
142+
'asyncoutput': asyncoutput,
143+
'OnWriteType': OnWriteType,
144+
'OnReadType': OnReadType,
145+
'PropertyReference': PropertyReference,
146+
'isinstance': isinstance,
147+
'uses_enum' : uses_enum(top_block),
148+
'uses_memory' : uses_memory(top_block),
149+
'get_fully_qualified_type_name': self._lookup_type_name,
150+
'get_array_dim': get_array_dim,
151+
'get_dependent_component': get_dependent_component,
152+
'get_dependent_enum': self._get_dependent_enum,
153+
'get_enum_values': get_enum_values,
154+
'get_fully_qualified_enum_type': self._fully_qualified_enum_type,
155+
'get_field_bitmask_hex_string': get_field_bitmask_hex_string,
156+
'get_field_inv_bitmask_hex_string': get_field_inv_bitmask_hex_string,
157+
'get_field_max_value_hex_string': get_field_max_value_hex_string,
158+
'get_reg_max_value_hex_string': get_reg_max_value_hex_string,
159+
'get_table_block': get_table_block,
160+
'get_reg_writable_fields': get_reg_writable_fields,
161+
'get_reg_readable_fields': get_reg_readable_fields,
162+
'get_memory_max_entry_value_hex_string': get_memory_max_entry_value_hex_string,
163+
'get_array_typecode': get_array_typecode,
164+
'get_memory_width_bytes': get_memory_width_bytes,
165+
'get_field_default_value': get_field_default_value,
166+
'raise_template_error' : self._raise_template_error,
167+
'get_python_path_segments' : get_python_path_segments,
168+
'safe_node_name' : safe_node_name,
169+
'version' : __version__
170+
}
171+
172+
context.update(self.user_template_context)
173+
174+
template = self.jj_env.get_template("addrmap.py.jinja")
175+
module_fqfn = os.path.join(package_path,
176+
'reg_model',
177+
top_block.inst_name + '.py')
178+
if autoformatoutputs is True:
179+
module_code_str = autopep8.fix_code(template.render(context))
180+
with open(module_fqfn, "w", encoding='utf-8') as fid:
181+
fid.write(module_code_str)
182+
else:
183+
stream = template.stream(context)
184+
stream.dump(module_fqfn, encoding='utf-8')
125185

126-
for block in modules:
186+
if not skip_test_case_generation:
127187

128-
self._build_node_type_table(block)
188+
# make the top level base class for all the other test, this is what instantes
189+
# the register model
190+
template = self.jj_env.get_template("baseclass_tb.py.jinja")
191+
module_tb_fqfn = os.path.join(package_path,
192+
'tests',
193+
'_' + top_block.inst_name + '_test_base.py')
129194

130195
context = {
131-
'print': print,
132-
'type': type,
133-
'top_node': block,
134-
'systemrdlFieldNode': FieldNode,
135-
'systemrdlRegNode': RegNode,
136-
'systemrdlRegfileNode': RegfileNode,
137-
'systemrdlAddrmapNode': AddrmapNode,
138-
'systemrdlMemNode': MemNode,
139-
'systemrdlAddressableNode': AddressableNode,
140-
'systemrdlSignalNode': SignalNode,
196+
'top_node': top_block,
141197
'asyncoutput': asyncoutput,
142-
'OnWriteType': OnWriteType,
143-
'OnReadType': OnReadType,
144-
'PropertyReference': PropertyReference,
145-
'isinstance': isinstance,
146-
'uses_enum' : uses_enum(block),
147-
'uses_memory' : uses_memory(block),
148-
'get_fully_qualified_type_name': self._lookup_type_name,
149-
'get_array_dim': get_array_dim,
150-
'get_dependent_component': get_dependent_component,
151-
'get_dependent_enum': self._get_dependent_enum,
152-
'get_enum_values': get_enum_values,
153-
'get_fully_qualified_enum_type': self._fully_qualified_enum_type,
154-
'get_field_bitmask_hex_string': get_field_bitmask_hex_string,
155-
'get_field_inv_bitmask_hex_string': get_field_inv_bitmask_hex_string,
156-
'get_field_max_value_hex_string': get_field_max_value_hex_string,
157-
'get_reg_max_value_hex_string': get_reg_max_value_hex_string,
158-
'get_table_block': get_table_block,
159-
'get_reg_writable_fields': get_reg_writable_fields,
160-
'get_reg_readable_fields': get_reg_readable_fields,
161-
'get_memory_max_entry_value_hex_string': get_memory_max_entry_value_hex_string,
162-
'get_array_typecode': get_array_typecode,
163-
'get_memory_width_bytes': get_memory_width_bytes,
164-
'get_field_default_value': get_field_default_value,
165-
'raise_template_error' : self._raise_template_error,
166-
'get_python_path_segments' : get_python_path_segments,
167-
'safe_node_name' : safe_node_name,
168-
'version' : __version__
198+
'version': __version__
169199
}
170200

171-
context.update(self.user_template_context)
172-
173-
template = self.jj_env.get_template("addrmap.py.jinja")
174-
module_fqfn = os.path.join(package_path,
175-
'reg_model',
176-
block.inst_name + '.py')
177201
if autoformatoutputs is True:
178-
module_code_str = autopep8.fix_code(template.render(context))
179-
with open(module_fqfn, "w", encoding='utf-8') as fid:
180-
fid.write(module_code_str)
202+
module_tb_code_str = autopep8.fix_code(template.render(context))
203+
with open(module_tb_fqfn, "w", encoding='utf-8') as fid:
204+
fid.write(module_tb_code_str)
181205
else:
182206
stream = template.stream(context)
183-
stream.dump(module_fqfn, encoding='utf-8')
207+
stream.dump(module_tb_fqfn, encoding='utf-8')
208+
209+
# make the tests themselves
210+
template = self.jj_env.get_template("addrmap_tb.py.jinja")
211+
212+
blocks = AddressMaps()
213+
# running the walker populated the blocks with all the address maps in within the
214+
# top block, including the top_block itself
215+
RDLWalker(unroll=True).walk(top_block, blocks, skip_top=False)
216+
217+
for block in blocks:
218+
owned_elements = OwnedbyAddressMap()
219+
# running the walker populated the blocks with all the address maps in within the
220+
# top block, including the top_block itself
221+
RDLWalker(unroll=True).walk(block, owned_elements, skip_top=True)
222+
223+
fq_block_name = '_'.join(block.get_path_segments(array_suffix = '_{index:d}_'))
184224

185-
if not skip_test_case_generation:
186-
template = self.jj_env.get_template("addrmap_tb.py.jinja")
187225
module_tb_fqfn = os.path.join(package_path,
188226
'tests',
189-
'test_' + block.inst_name + '.py')
227+
'test_' + fq_block_name + '.py')
228+
229+
context = {
230+
'top_node': top_block,
231+
'block' : block,
232+
'fq_block_name' : fq_block_name,
233+
'owned_elements': owned_elements,
234+
'systemrdlFieldNode': FieldNode,
235+
'systemrdlSignalNode': SignalNode,
236+
'systemrdlRegNode': RegNode,
237+
'systemrdlMemNode': MemNode,
238+
'systemrdlRegfileNode': RegfileNode,
239+
'systemrdlAddrmapNode': AddrmapNode,
240+
'isinstance': isinstance,
241+
'get_python_path_segments': get_python_path_segments,
242+
'safe_node_name': safe_node_name,
243+
'uses_memory': (len(owned_elements.memories) > 0),
244+
'get_field_bitmask_hex_string': get_field_bitmask_hex_string,
245+
'get_field_inv_bitmask_hex_string': get_field_inv_bitmask_hex_string,
246+
'get_field_max_value_hex_string': get_field_max_value_hex_string,
247+
'get_field_default_value': get_field_default_value,
248+
'get_reg_max_value_hex_string': get_reg_max_value_hex_string,
249+
'get_reg_writable_fields': get_reg_writable_fields,
250+
'get_reg_readable_fields': get_reg_readable_fields,
251+
'get_memory_max_entry_value_hex_string': get_memory_max_entry_value_hex_string,
252+
'get_enum_values': get_enum_values,
253+
'get_array_typecode': get_array_typecode,
254+
'get_memory_width_bytes': get_memory_width_bytes,
255+
'asyncoutput': asyncoutput,
256+
'uses_enum': uses_enum(block),
257+
'version': __version__
258+
}
259+
190260
if autoformatoutputs is True:
191261
module_tb_code_str = autopep8.fix_code(template.render(context))
192262
with open(module_tb_fqfn, "w", encoding='utf-8') as fid:
@@ -195,7 +265,7 @@ def export(self, node: Node, path: str,
195265
stream = template.stream(context)
196266
stream.dump(module_tb_fqfn, encoding='utf-8')
197267

198-
return [m.inst_name for m in modules]
268+
return top_block.inst_name
199269

200270
def _lookup_type_name(self, node: Node) -> str:
201271
"""

0 commit comments

Comments
 (0)