diff --git a/src/peakrdl_regblock/utils.py b/src/peakrdl_regblock/utils.py index d3a9cb0..014586e 100644 --- a/src/peakrdl_regblock/utils.py +++ b/src/peakrdl_regblock/utils.py @@ -1,14 +1,16 @@ import re -from typing import TYPE_CHECKING, Match +from typing import TYPE_CHECKING, Match, Union + +from systemrdl.rdltypes.references import PropertyReference +from systemrdl.node import Node, SignalNode, AddrmapNode from .identifier_filter import kw_filter as kwf if TYPE_CHECKING: - from systemrdl.node import Node, SignalNode from typing import Optional from .dereferencer import Dereferencer -def get_indexed_path(top_node: 'Node', target_node: 'Node') -> str: +def get_indexed_path(top_node: Node, target_node: Node) -> str: """ TODO: Add words about indexing and why i'm doing this. Copy from logbook """ @@ -49,3 +51,30 @@ def is_pow2(x: int) -> bool: def roundup_pow2(x: int) -> int: return 1<<(x-1).bit_length() + +def ref_is_internal(top_node: AddrmapNode, ref: Union[Node, PropertyReference]) -> bool: + """ + Determine whether the reference is internal to the top node. + + For the sake of this exporter, root signals are treated as internal. + """ + if isinstance(ref, Node): + current_node = ref + elif isinstance(ref, PropertyReference): + current_node = ref.node + + while current_node is not None: + if current_node == top_node: + # reached top node without finding any external components + # is internal! + return True + + if current_node.external: + # not internal! + return False + + current_node = current_node.parent + + # A root signal was referenced, which dodged the top addrmap + # This is considerd internal for this exporter + return True diff --git a/src/peakrdl_regblock/validate_design.py b/src/peakrdl_regblock/validate_design.py index 6c6a0ce..2e3ac50 100644 --- a/src/peakrdl_regblock/validate_design.py +++ b/src/peakrdl_regblock/validate_design.py @@ -4,6 +4,8 @@ from systemrdl.walker import RDLListener, RDLWalker, WalkerAction from systemrdl.rdltypes import PropertyReference from systemrdl.node import Node +from .utils import ref_is_internal + if TYPE_CHECKING: from systemrdl.node import RegNode, FieldNode, SignalNode, AddressableNode from .exporter import RegblockExporter @@ -36,15 +38,12 @@ class DesignValidator(RDLListener): # Check if any property references reach across the internal/external boundary for prop_name in node.list_properties(): value = node.get_property(prop_name) - if isinstance(value, PropertyReference): - if not self._is_internal(value.node): - self.msg.error( - "Property is assigned a reference that points to a component not internal to the regblock being exported.", - value.src_ref - ) - elif isinstance(value, Node): - if not self._is_internal(value): - src_ref = node.inst.property_src_ref.get(prop_name, node.inst.inst_src_ref) + if isinstance(value, (PropertyReference, Node)): + if not ref_is_internal(self.exp.top_node, value): + if isinstance(value, PropertyReference): + src_ref = value.src_ref + else: + src_ref = node.inst.property_src_ref.get(prop_name, node.inst.inst_src_ref) self.msg.error( "Property is assigned a reference that points to a component not internal to the regblock being exported.", src_ref @@ -127,26 +126,3 @@ class DesignValidator(RDLListener): "For more details, see: https://peakrdl-regblock.readthedocs.io/en/latest/udps/read_buffering.html", node.inst.inst_src_ref ) - - def _is_internal(self, node: Node) -> bool: - """ - Recurse parents to see if at any point, the referenced component is - enclosed in an external component. - """ - current_node = node - - while current_node is not None: - if current_node == self.exp.top_node: - # reached top node without finding any external components - # is internal! - return True - - if current_node.external: - # not internal! - return False - - current_node = current_node.parent - - # A root signal was referenced, which dodged the top addrmap - # This is considerd internal for this exporter - return True