Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions generate_and_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ def build_logging_cong(logfilepath:str):
skip_library_copy=not CommandLineArgs.copy_libraries,
legacy_block_access=CommandLineArgs.legacy_block_access,
user_defined_properties_to_include=CommandLineArgs.udp,
user_defined_properties_to_include_regex=CommandLineArgs.udp_regex,
hidden_inst_name_regex=CommandLineArgs.hide_regex,
legacy_enum_type=CommandLineArgs.legacy_enum_type,
skip_systemrdl_name_and_desc_properties=
Expand Down
2 changes: 1 addition & 1 deletion src/peakrdl_python/__about__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@

Variables that describes the peakrdl-python Package
"""
__version__ = "3.1.0"
__version__ = "3.1.0rc3"
14 changes: 12 additions & 2 deletions src/peakrdl_python/exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,8 +415,11 @@ def init_line_entry(module_name: str,

context = {
'top_node': top_block,
'systemrdlRegNode': RegNode,
'systemrdlFieldNode': FieldNode,
'systemrdlRegNode': RegNode,
'systemrdlRegfileNode': RegfileNode,
'systemrdlAddrmapNode': AddrmapNode,
'systemrdlMemNode': MemNode,
'systemrdlSignalNode': SignalNode,
'systemrdlUserStruct': UserStruct,
'systemrdlUserEnum': UserEnum,
Expand Down Expand Up @@ -513,8 +516,11 @@ def init_line_entry(module_name:str,

context = {
'top_node': top_block,
'systemrdlMemNode': MemNode,
'systemrdlFieldNode': FieldNode,
'systemrdlRegNode': RegNode,
'systemrdlRegfileNode': RegfileNode,
'systemrdlAddrmapNode': AddrmapNode,
'systemrdlMemNode': MemNode,
'systemrdlSignalNode': SignalNode,
'systemrdlUserStruct': UserStruct,
'systemrdlUserEnum': UserEnum,
Expand Down Expand Up @@ -587,6 +593,10 @@ def __export_reg_model_fields(self, *,
context = {
'top_node': top_block,
'systemrdlFieldNode': FieldNode,
'systemrdlRegNode': RegNode,
'systemrdlRegfileNode': RegfileNode,
'systemrdlAddrmapNode': AddrmapNode,
'systemrdlMemNode': MemNode,
'systemrdlUserStruct': UserStruct,
'systemrdlUserEnum': UserEnum,
'isinstance': isinstance,
Expand Down
44 changes: 44 additions & 0 deletions src/peakrdl_python/lib/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,15 @@
from itertools import product
from enum import IntEnum, Enum, auto
import math
import re

from .callbacks import CallbackSet, CallbackSetLegacy

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

array_instance_re = re.compile(r'(?P<root_name>[A-Za-z_0-9]*)\[(?P<index>\d+)\]')

class Base(ABC):
"""
base class of for all types
Expand Down Expand Up @@ -97,6 +100,35 @@ def udp(self) -> UDPStruct:
"""
return {}

def _traverse_from_fully_qualified_name(self, fully_qualified_name: list[str]) -> 'Base':
"""
This method allows another node in the structure to located based on a list of string
which represented the systemRDL path.

This function is intended for use with UDPs which reference other UDPs
"""

# 1) location the root node by walking backwards up the tree until the parent is
# found
def locate_root(node: 'Base') -> 'Base':
if node.parent is None:
return node
return locate_root(node.parent)
root_node = locate_root(self)
# 2) check the 1st entry in the list matches the name of the root
if root_node.inst_name != fully_qualified_name[0]:
raise RuntimeError('root node name mismatch')
# 3) start walking down the tree matching the nodes
walking_node = root_node
for node_name in fully_qualified_name[1:]:
if not isinstance(walking_node, Node):
# the current node being traversed must be a Node type i.e. not a field
raise RuntimeError('node traversal has failed as type:{type(walking_node)} was'
' unexpectedly encountered')
walking_node = walking_node.get_child_by_system_rdl_name(node_name)

return walking_node

@property
def rdl_name(self) -> Optional[str]:
"""
Expand Down Expand Up @@ -200,6 +232,18 @@ def get_child_by_system_rdl_name(self, name: Any) -> Any:
"""
if not isinstance(name, str):
raise TypeError(f'name must be a string got {type(name)}')

# check if an array style child pointer
array_name_match = array_instance_re.match(name)
if array_name_match:
root_name = array_name_match.group("root_name")
index = int(array_name_match.group("index"))
child_array = getattr(self, self.systemrdl_python_child_name_map[root_name])
if not isinstance(child_array, NodeArray):
raise ValueError('attempting to use array indexing into a non-array '
f'node: {root_name} of type:{type(child_array)}')
return child_array[index]

return getattr(self, self.systemrdl_python_child_name_map[name])

@property
Expand Down
14 changes: 10 additions & 4 deletions src/peakrdl_python/systemrdl_node_hashes.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,12 +167,18 @@ def __node_hash_components(node: Node,
if desc is not None:
value_to_hash.append(desc)

def udp_replace_for_hashing(item: Any) -> None:
if isinstance(item, list):
for child_udp_value in item:
udp_replace_for_hashing(child_udp_value)
elif isinstance(item, Node):
value_to_hash.append('.'.join(item.get_path_segments()))
else:
value_to_hash.append(item)

for udp in get_properties_to_include(node, udp_include_func):
udp_value = node.get_property(udp)
if isinstance(udp_value, list):
value_to_hash.append(tuple(udp_value))
else:
value_to_hash.append(udp_value)
udp_replace_for_hashing(udp_value)

return value_to_hash

Expand Down
4 changes: 2 additions & 2 deletions src/peakrdl_python/templates/addrmap_tb.py.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,9 @@ class {{fq_block_name}}_single_access({{top_node.inst_name}}_TestCase): # type:
{% for property_name in property_list %}
{% set property_value = node.get_property(property_name) %}
{% if isinstance(property_value, list) %}
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) }},{% endfor %}] )
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 %}] )
{% else %}
self.assertEqual(self.dut.{{'.'.join(get_python_path_segments(node))}}.udp['{{property_name}}'], {{ udp_property_entry(property_value) }} )
self.assertEqual(self.dut.{{'.'.join(get_python_path_segments(node))}}.udp['{{property_name}}'], {{ udp_property_entry(property_value, true) }} )
{% endif %}
{% endfor %}
{% endif %}
Expand Down
22 changes: 14 additions & 8 deletions src/peakrdl_python/templates/addrmap_udp_property.py.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,33 @@ You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
#}

{%- macro udp_property_entry(value) %}
{%- macro udp_property_entry(value, full_qual_resolution) %}
{%- if isinstance(value, systemrdlUserStruct) -%}
{
{%- for sub_name, sub_value in value.members.items() %}
{{udp_property_dict_entry(sub_name, sub_value)|indent(4)}}
{{udp_property_dict_entry(sub_name, sub_value, full_qual_resolution)|indent(4)}}
{%- endfor %}
}
{%- elif isinstance(value, systemrdlUserEnum) -%}
{{ type(value).type_name + '_property_enumcls.' + value.name.upper() }}
{%- elif isinstance(value, str) -%}
"{{ value }}"
{%- elif isinstance(value, (systemrdlFieldNode, systemrdlRegNode, systemrdlRegfileNode, systemrdlAddrmapNode, systemrdlMemNode)) -%}
{%- if full_qual_resolution -%}
self.dut.{{'.'.join(get_python_path_segments(value))}}
{%- else -%}
self._traverse_from_fully_qualified_name({{ value.get_path_segments() }})
{%- endif -%}
{%- else -%}
{{ value }}
{%- endif -%}
{%- endmacro %}

{%- macro udp_property_dict_entry(name, value) %}
{%- macro udp_property_dict_entry(name, value, full_qual_resolution) %}
{%- if isinstance(value, list) -%}
'{{name}}' : [ {% for sub_value in value %}{{udp_property_entry(sub_value)|indent(4)}}, {% endfor %}],
'{{name}}' : [ {% for sub_value in value %}{{udp_property_entry(sub_value, full_qual_resolution)}}, {% endfor %}],
{%- else -%}
'{{name}}' : {{ udp_property_entry(value) }},
'{{name}}' : {{ udp_property_entry(value, full_qual_resolution) }},
{%- endif %}
{% endmacro %}

Expand All @@ -47,9 +53,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
@property
def udp(self) -> UDPStruct:
return {
{% for property_name in property_list %}
{{udp_property_dict_entry(property_name, node.instance.get_property(property_name))}}
{% endfor %}
{% for property_name in property_list -%}
{{udp_property_dict_entry(property_name, node.instance.get_property(property_name), false)|indent(4)}}
{%- endfor %}
}

{% endif %}
Expand Down
114 changes: 114 additions & 0 deletions tests/testcases/udp_with_referencing.rdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
Testcase the #292 bug
with a UDP that cross-references another
*/
property field_pointer {
type = field;
component = field;
};

property register_pointer {
type = reg;
component = reg;
};

property register_file_pointer {
type = regfile;
component = regfile;
};

property field_parent_pointer {
type = reg;
component = field;
};

property register_child_pointer {
type = field[];
component = reg;
};

struct addrmap_child {
regfile regfile_children[];
reg reg_children[];
mem mem_children[];
addrmap addrmap_children[];
};

property addrmap_child_pointer {
type = addrmap_child;
component = addrmap;
};

struct regfile_child {
regfile regfile_children[];
reg reg_children[];
};

property regfile_child_pointer {
type = regfile_child;
component = regfile;
};

property mem_child_pointer {
type = reg[];
component = mem;
};

addrmap udp_with_referencing {

reg reg_def {
field { fieldwidth=4; } field_a;
field { fieldwidth=4; } field_b;
field { fieldwidth=4; } field_c;
field { fieldwidth=4; } field_d;
register_child_pointer = '{ field_a, field_b, field_c, field_d } ;
};

regfile regfile_def {
regfile inner_regfile_def {
reg_def reg_value;
regfile_child_pointer = regfile_child'{ reg_children:'{ reg_value } };
};
reg_def reg_value;
inner_regfile_def inner_regfile_value;
regfile_child_pointer = regfile_child'{ reg_children:'{ reg_value }, regfile_children:'{ inner_regfile_value } };
};

mem mem_def {
mementries = 32;
memwidth = 32;

reg_def reg_value;
mem_child_pointer = '{ reg_value } ;
};

addrmap addrmap_def {
addrmap inner_addrmap_def {
reg_def reg_value;
regfile_def regfile_value;
addrmap_child_pointer = addrmap_child'{ reg_children:'{ reg_value }, regfile_children:'{ regfile_value } };
};
reg_def reg_value;
regfile_def addrmap_regfile_value;
external mem_def mem_value;
inner_addrmap_def addrmap_value;
addrmap_child_pointer = addrmap_child'{ reg_children:'{ reg_value }, regfile_children:'{ addrmap_regfile_value }, addrmap_children:'{ addrmap_value }, mem_children:'{ mem_value } };
};

addrmap_def main;
addrmap_def view;

view.reg_value.field_a->field_pointer = main.reg_value.field_a;
view.reg_value.field_a->field_parent_pointer = main.reg_value;

view.reg_value->register_pointer = main.reg_value;

reg basic_reg_def {
// a register def without any UDPs
field { fieldwidth=4; } field_a;
};

basic_reg_def basic_reg_array[3];
main.addrmap_value.reg_value -> register_pointer = basic_reg_array[0];
main.addrmap_value.regfile_value.reg_value -> register_pointer = basic_reg_array[1];
};
Loading