Skip to content

Commit 875adf8

Browse files
authored
Merge pull request #296 from krcb197/release/3.1.0
Release 3.1.0
2 parents 470d01d + a307c53 commit 875adf8

11 files changed

Lines changed: 259 additions & 45 deletions

File tree

.github/workflows/action.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,8 @@ jobs:
161161
sleep 10
162162
python -m generate_and_test --RDL_source_file tests/testcases/user_defined_properties.rdl --root_node user_defined_properties --udp bool_property_to_include enum_property_to_include int_property_to_include str_property_to_include struct_property_to_include double_layer_struct_property_to_include
163163
sleep 10
164-
164+
python -m generate_and_test --RDL_source_file tests/testcases/user_defined_properties.rdl --root_node user_defined_properties --udp bool_property_to_include enum_property_to_include int_property_to_include str_property_to_include struct_property_to_include double_layer_struct_property_to_include int_array_property_to_include str_array_property_to_include enum_array_property_to_include
165+
sleep 10
165166
python -m generate_and_test --RDL_source_file tests/testcases/user_defined_properties.rdl --root_node user_defined_properties --udp_regex "bool_property_to_include|enum_property_to_include|int_property_to_include|str_property_to_include|struct_property_to_include|double_layer_struct_property_to_include"
166167
sleep 10
167168

generate_and_test.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ def build_logging_cong(logfilepath:str):
222222
skip_library_copy=not CommandLineArgs.copy_libraries,
223223
legacy_block_access=CommandLineArgs.legacy_block_access,
224224
user_defined_properties_to_include=CommandLineArgs.udp,
225+
user_defined_properties_to_include_regex=CommandLineArgs.udp_regex,
225226
hidden_inst_name_regex=CommandLineArgs.hide_regex,
226227
legacy_enum_type=CommandLineArgs.legacy_enum_type,
227228
skip_systemrdl_name_and_desc_properties=

src/peakrdl_python/__about__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@
1717
1818
Variables that describes the peakrdl-python Package
1919
"""
20-
__version__ = "3.0.0"
20+
__version__ = "3.1.0"

src/peakrdl_python/exporter.py

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ def visible_nonsignal_node(node: Node) -> int:
243243
'asyncoutput': asyncoutput,
244244
'isinstance': isinstance,
245245
'str': str,
246+
'list': list,
246247
'uses_enum': uses_enum(top_block),
247248
'get_fully_qualified_type_name': partial(
248249
unique_component_walker.python_class_name,
@@ -414,14 +415,18 @@ def init_line_entry(module_name: str,
414415

415416
context = {
416417
'top_node': top_block,
417-
'systemrdlRegNode': RegNode,
418418
'systemrdlFieldNode': FieldNode,
419+
'systemrdlRegNode': RegNode,
420+
'systemrdlRegfileNode': RegfileNode,
421+
'systemrdlAddrmapNode': AddrmapNode,
422+
'systemrdlMemNode': MemNode,
419423
'systemrdlSignalNode': SignalNode,
420424
'systemrdlUserStruct': UserStruct,
421425
'systemrdlUserEnum': UserEnum,
422426
'isinstance': isinstance,
423427
'type': type,
424428
'str': str,
429+
'list': list,
425430
'asyncoutput': asyncoutput,
426431
'unique_registers': unique_register_subset,
427432
'unique_property_enums':
@@ -511,14 +516,18 @@ def init_line_entry(module_name:str,
511516

512517
context = {
513518
'top_node': top_block,
514-
'systemrdlMemNode': MemNode,
515519
'systemrdlFieldNode': FieldNode,
520+
'systemrdlRegNode': RegNode,
521+
'systemrdlRegfileNode': RegfileNode,
522+
'systemrdlAddrmapNode': AddrmapNode,
523+
'systemrdlMemNode': MemNode,
516524
'systemrdlSignalNode': SignalNode,
517525
'systemrdlUserStruct': UserStruct,
518526
'systemrdlUserEnum': UserEnum,
519527
'isinstance': isinstance,
520528
'type': type,
521529
'str': str,
530+
'list' : list,
522531
'asyncoutput': asyncoutput,
523532
'unique_memories': unique_memory_subset,
524533
'unique_property_enums':
@@ -584,11 +593,16 @@ def __export_reg_model_fields(self, *,
584593
context = {
585594
'top_node': top_block,
586595
'systemrdlFieldNode': FieldNode,
596+
'systemrdlRegNode': RegNode,
597+
'systemrdlRegfileNode': RegfileNode,
598+
'systemrdlAddrmapNode': AddrmapNode,
599+
'systemrdlMemNode': MemNode,
587600
'systemrdlUserStruct': UserStruct,
588601
'systemrdlUserEnum': UserEnum,
589602
'isinstance': isinstance,
590603
'type': type,
591604
'str': str,
605+
'list': list,
592606
'asyncoutput': asyncoutput,
593607
'unique_fields': unique_fields_subset,
594608
'unique_property_enums':
@@ -845,6 +859,7 @@ def is_reg_node(node: Node) -> TypeGuard[RegNode]:
845859
'isinstance': isinstance,
846860
'type': type,
847861
'str': str,
862+
'list': list,
848863
'full_slice_accessor': full_slice_accessor,
849864
'get_python_path_segments': get_python_path_segments,
850865
'safe_node_name': safe_node_name,
@@ -1167,7 +1182,7 @@ def _get_dependent_property_enum( unique_components: UniqueComponents) -> \
11671182
"""
11681183
enum_needed: list[UserEnumMeta] = []
11691184

1170-
def walk_property_struct_node(value: Any) -> None:
1185+
def walk_property_subnode(value: Any) -> None:
11711186
if isinstance(value, UserEnum) and type(value) not in enum_needed:
11721187
enum_type = type(value)
11731188
if not isinstance(enum_type, UserEnumMeta):
@@ -1176,19 +1191,15 @@ def walk_property_struct_node(value: Any) -> None:
11761191

11771192
if isinstance(value, UserStruct):
11781193
for sub_value in value.members.values():
1179-
walk_property_struct_node(sub_value)
1194+
walk_property_subnode(sub_value)
1195+
1196+
if isinstance(value, list):
1197+
for sub_value in value:
1198+
walk_property_subnode(sub_value)
11801199

11811200
for node in unique_components.nodes.values():
11821201
for node_property_name in node.properties_to_include:
11831202
node_property = node.instance.get_property(node_property_name)
1184-
if isinstance(node_property, UserEnum) and type(node_property) not in enum_needed:
1185-
enum_type = type(node_property)
1186-
if not isinstance(enum_type, UserEnumMeta):
1187-
raise TypeError(f'enum type should be UserEnumMeta, got {type(enum_type)}')
1188-
enum_needed.append(enum_type)
1189-
1190-
if isinstance(node_property, UserStruct):
1191-
for sub_value in node_property.members.values():
1192-
walk_property_struct_node(sub_value)
1203+
walk_property_subnode(node_property)
11931204

11941205
return enum_needed

src/peakrdl_python/lib/base.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,15 @@
2626
from itertools import product
2727
from enum import IntEnum, Enum, auto
2828
import math
29+
import re
2930

3031
from .callbacks import CallbackSet, CallbackSetLegacy
3132

3233
UDPStruct = dict[str, 'UDPType']
3334
UDPType = Union[str, int, bool, IntEnum, UDPStruct]
3435

36+
array_instance_re = re.compile(r'(?P<root_name>[A-Za-z_0-9]*)\[(?P<index>\d+)\]')
37+
3538
class Base(ABC):
3639
"""
3740
base class of for all types
@@ -97,6 +100,35 @@ def udp(self) -> UDPStruct:
97100
"""
98101
return {}
99102

103+
def _traverse_from_fully_qualified_name(self, fully_qualified_name: list[str]) -> 'Base':
104+
"""
105+
This method allows another node in the structure to located based on a list of string
106+
which represented the systemRDL path.
107+
108+
This function is intended for use with UDPs which reference other UDPs
109+
"""
110+
111+
# 1) location the root node by walking backwards up the tree until the parent is
112+
# found
113+
def locate_root(node: 'Base') -> 'Base':
114+
if node.parent is None:
115+
return node
116+
return locate_root(node.parent)
117+
root_node = locate_root(self)
118+
# 2) check the 1st entry in the list matches the name of the root
119+
if root_node.inst_name != fully_qualified_name[0]:
120+
raise RuntimeError('root node name mismatch')
121+
# 3) start walking down the tree matching the nodes
122+
walking_node = root_node
123+
for node_name in fully_qualified_name[1:]:
124+
if not isinstance(walking_node, Node):
125+
# the current node being traversed must be a Node type i.e. not a field
126+
raise RuntimeError('node traversal has failed as type:{type(walking_node)} was'
127+
' unexpectedly encountered')
128+
walking_node = walking_node.get_child_by_system_rdl_name(node_name)
129+
130+
return walking_node
131+
100132
@property
101133
def rdl_name(self) -> Optional[str]:
102134
"""
@@ -200,6 +232,18 @@ def get_child_by_system_rdl_name(self, name: Any) -> Any:
200232
"""
201233
if not isinstance(name, str):
202234
raise TypeError(f'name must be a string got {type(name)}')
235+
236+
# check if an array style child pointer
237+
array_name_match = array_instance_re.match(name)
238+
if array_name_match:
239+
root_name = array_name_match.group("root_name")
240+
index = int(array_name_match.group("index"))
241+
child_array = getattr(self, self.systemrdl_python_child_name_map[root_name])
242+
if not isinstance(child_array, NodeArray):
243+
raise ValueError('attempting to use array indexing into a non-array '
244+
f'node: {root_name} of type:{type(child_array)}')
245+
return child_array[index]
246+
203247
return getattr(self, self.systemrdl_python_child_name_map[name])
204248

205249
@property

src/peakrdl_python/systemrdl_node_hashes.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ def __node_hash_components(node: Node,
143143
udp_include_func: ShowUDPCallback,
144144
include_name_and_desc: bool = True) -> list[Any]:
145145

146-
value_to_hash = []
146+
value_to_hash:list[Any] = []
147147

148148
if isinstance(node, FieldNode):
149149
value_to_hash.append('Field')
@@ -167,8 +167,18 @@ def __node_hash_components(node: Node,
167167
if desc is not None:
168168
value_to_hash.append(desc)
169169

170+
def udp_replace_for_hashing(item: Any) -> None:
171+
if isinstance(item, list):
172+
for child_udp_value in item:
173+
udp_replace_for_hashing(child_udp_value)
174+
elif isinstance(item, Node):
175+
value_to_hash.append('.'.join(item.get_path_segments()))
176+
else:
177+
value_to_hash.append(item)
178+
170179
for udp in get_properties_to_include(node, udp_include_func):
171-
value_to_hash.append(node.get_property(udp))
180+
udp_value = node.get_property(udp)
181+
udp_replace_for_hashing(udp_value)
172182

173183
return value_to_hash
174184

src/peakrdl_python/templates/addrmap_tb.py.jinja

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ from ._{{top_node.inst_name}}_test_base import __name__ as base_name
7979
from ._{{top_node.inst_name}}_test_base import random_enum_reg_value
8080

8181
{% from 'addrmap_udp_property.py.jinja' import udp_property_dict_entry with context %}
82+
{% from 'addrmap_udp_property.py.jinja' import udp_property_entry with context %}
8283

8384
class {{fq_block_name}}_single_access({{top_node.inst_name}}_TestCase): # type: ignore[valid-type,misc]
8485

@@ -96,16 +97,10 @@ class {{fq_block_name}}_single_access({{top_node.inst_name}}_TestCase): # type:
9697
{% else %}
9798
{% for property_name in property_list %}
9899
{% set property_value = node.get_property(property_name) %}
99-
{% if isinstance(property_value, systemrdlUserStruct) %}
100-
self.assertDictEqual(self.dut.{{'.'.join(get_python_path_segments(node))}}.udp['{{property_name}}'], { # type: ignore[arg-type]
101-
{% for sub_name, sub_value in property_value.members.items() %} {{udp_property_dict_entry(sub_name, sub_value)}} {% endfor %}
102-
} )
103-
{% elif isinstance(property_value, systemrdlUserEnum) %}
104-
self.assertEqual(self.dut.{{'.'.join(get_python_path_segments(node))}}.udp['{{property_name}}'], {{ type(property_value).type_name }}_property_enumcls.{{ property_value.name.upper() }} )
105-
{% elif isinstance(property_value, str) %}
106-
self.assertEqual(self.dut.{{'.'.join(get_python_path_segments(node))}}.udp['{{property_name}}'], "{{ property_value }}" )
100+
{% if isinstance(property_value, list) %}
101+
self.assertEqual(self.dut.{{'.'.join(get_python_path_segments(node))}}.udp['{{property_name}}'], [{% for sub_property_value in property_value %}{{ udp_property_entry(sub_property_value, true) }},{% endfor %}] )
107102
{% else %}
108-
self.assertEqual(self.dut.{{'.'.join(get_python_path_segments(node))}}.udp['{{property_name}}'], {{ property_value }} )
103+
self.assertEqual(self.dut.{{'.'.join(get_python_path_segments(node))}}.udp['{{property_name}}'], {{ udp_property_entry(property_value, true) }} )
109104
{% endif %}
110105
{% endfor %}
111106
{% endif %}

src/peakrdl_python/templates/addrmap_udp_property.py.jinja

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,34 @@ You should have received a copy of the GNU Lesser General Public License
1616
along with this program. If not, see <https://www.gnu.org/licenses/>.
1717
#}
1818

19-
{%- macro udp_property_dict_entry(name, value) %}
20-
{% if isinstance(value, systemrdlUserStruct) %}
21-
'{{name}}' : {
22-
{% for sub_name, sub_value in value.members.items() %}
23-
{{udp_property_dict_entry(sub_name, sub_value)|indent(4)}}
24-
{% endfor %}
25-
},
26-
{% elif isinstance(value, systemrdlUserEnum) %}
27-
'{{name}}' : {{ type(value).type_name + '_property_enumcls.' + value.name.upper() }} ,
28-
{% elif isinstance(value, str) %}
29-
'{{name}}' : "{{ value }}" ,
30-
{% else %}
31-
'{{name}}' : {{ value }} ,
32-
{% endif %}
19+
{%- macro udp_property_entry(value, full_qual_resolution) %}
20+
{%- if isinstance(value, systemrdlUserStruct) -%}
21+
{
22+
{%- for sub_name, sub_value in value.members.items() %}
23+
{{udp_property_dict_entry(sub_name, sub_value, full_qual_resolution)|indent(4)}}
24+
{%- endfor %}
25+
}
26+
{%- elif isinstance(value, systemrdlUserEnum) -%}
27+
{{ type(value).type_name + '_property_enumcls.' + value.name.upper() }}
28+
{%- elif isinstance(value, str) -%}
29+
"{{ value }}"
30+
{%- elif isinstance(value, (systemrdlFieldNode, systemrdlRegNode, systemrdlRegfileNode, systemrdlAddrmapNode, systemrdlMemNode)) -%}
31+
{%- if full_qual_resolution -%}
32+
self.dut.{{'.'.join(get_python_path_segments(value))}}
33+
{%- else -%}
34+
self._traverse_from_fully_qualified_name({{ value.get_path_segments() }})
35+
{%- endif -%}
36+
{%- else -%}
37+
{{ value }}
38+
{%- endif -%}
39+
{%- endmacro %}
40+
41+
{%- macro udp_property_dict_entry(name, value, full_qual_resolution) %}
42+
{%- if isinstance(value, list) -%}
43+
'{{name}}' : [ {% for sub_value in value %}{{udp_property_entry(sub_value, full_qual_resolution)}}, {% endfor %}],
44+
{%- else -%}
45+
'{{name}}' : {{ udp_property_entry(value, full_qual_resolution) }},
46+
{%- endif %}
3347
{% endmacro %}
3448

3549
{%- macro udp_property(node) %}
@@ -39,9 +53,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
3953
@property
4054
def udp(self) -> UDPStruct:
4155
return {
42-
{% for property_name in property_list %}
43-
{{udp_property_dict_entry(property_name, node.instance.get_property(property_name))}}
44-
{% endfor %}
56+
{% for property_name in property_list -%}
57+
{{udp_property_dict_entry(property_name, node.instance.get_property(property_name), false)|indent(4)}}
58+
{%- endfor %}
4559
}
4660

4761
{% endif %}

0 commit comments

Comments
 (0)