From 384bc416c305cd5c6115c6b26ed1b4c4530e177b Mon Sep 17 00:00:00 2001 From: Alex Mykyta Date: Wed, 30 Aug 2023 21:33:34 -0700 Subject: [PATCH] Uniquify fields with name collisions on import --- docs/importer.rst | 3 +++ src/peakrdl_ipxact/__about__.py | 2 +- src/peakrdl_ipxact/importer.py | 40 ++++++++++++++++++++++++++++----- 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/docs/importer.rst b/docs/importer.rst index 2fbcd02..fde5b03 100644 --- a/docs/importer.rst +++ b/docs/importer.rst @@ -112,6 +112,9 @@ may be performed: * IP-XACT allows registers to be any arbitrary bit width, but SystemRDL requires the ``regwidth`` property to be at least 8, and a power of 2. The imported ``regwidth`` may be padded up as necessary. +* IP-XACT allows a register to contain multiple fields with the same name. If + this is detected, the importer will uniquify the instance names based on the + fields' bit ranges. diff --git a/src/peakrdl_ipxact/__about__.py b/src/peakrdl_ipxact/__about__.py index 46aa803..567bfde 100644 --- a/src/peakrdl_ipxact/__about__.py +++ b/src/peakrdl_ipxact/__about__.py @@ -1 +1 @@ -__version__ = "3.4.2" +__version__ = "3.4.3" diff --git a/src/peakrdl_ipxact/importer.py b/src/peakrdl_ipxact/importer.py index 943c039..1d01c47 100644 --- a/src/peakrdl_ipxact/importer.py +++ b/src/peakrdl_ipxact/importer.py @@ -502,13 +502,20 @@ def parse_register(self, register: ElementTree.Element) -> Optional[comp.Reg]: reg_reset_value = d.get('reset.value', None) reg_reset_mask = d.get('reset.mask', None) - # collect children + # Collect field elements and scan for name collisions + field_tuples = [] + field_names = set() + field_name_collisions = set() for child_el in d['child_els']: local_name = get_local_name(child_el) if local_name == "field": - field = self.parse_field(child_el, reg_access, reg_reset_value, reg_reset_mask) - if field is not None: - self.add_child(C, field) + # This XML element is a field + field_name = self.get_sanitized_element_name(child_el) + field_tuples.append((field_name, child_el)) + if field_name in field_names: + field_name_collisions.add(field_name) + else: + field_names.add(field_name) else: self.msg.error( "Invalid child element <%s> found in <%s:register>" @@ -516,6 +523,20 @@ def parse_register(self, register: ElementTree.Element) -> Optional[comp.Reg]: self.src_ref ) + # Process fields + for field_name, field_el in field_tuples: + # Uniquify field name if necessary + uniquify_field_name = field_name in field_name_collisions + + field = self.parse_field( + field_name, field_el, + reg_access, reg_reset_value, reg_reset_mask, + uniquify_field_name + ) + if field is not None: + self.add_child(C, field) + + if 'vendorExtensions' in d: C = self.register_vendorExtensions(d['vendorExtensions'], C) @@ -531,7 +552,12 @@ def parse_register(self, register: ElementTree.Element) -> Optional[comp.Reg]: return C - def parse_field(self, field: ElementTree.Element, reg_access: rdltypes.AccessType, reg_reset_value: Optional[int], reg_reset_mask: Optional[int]) -> Optional[comp.Field]: + def parse_field( + self, + name: str, field: ElementTree.Element, + reg_access: rdltypes.AccessType, reg_reset_value: Optional[int], reg_reset_mask: Optional[int], + uniquify_field_name: bool, + ) -> Optional[comp.Field]: """ Parses an field and returns an instantiated field component """ @@ -565,7 +591,6 @@ def parse_field(self, field: ElementTree.Element, reg_access: rdltypes.AccessTyp # vendorExtensions d = self.flatten_element_values(field) - name = self.get_sanitized_element_name(field) # Check for required values required = {'bitOffset', 'bitWidth'} @@ -579,6 +604,9 @@ def parse_field(self, field: ElementTree.Element, reg_access: rdltypes.AccessTyp if d.get('reserved', False): return None + if uniquify_field_name: + name += "_%d_%d" % (d['bitOffset'] + d['bitWidth'] - 1, d['bitOffset']) + # Create component instance C = self.instantiate_field( self.create_field_definition(),