From ae83dceb7acdf53af9738ff393369b05bf107bca Mon Sep 17 00:00:00 2001 From: Dennis Date: Fri, 26 Nov 2021 16:15:00 -0800 Subject: [PATCH] Closes #13: I/O ports are now grouped and are tied to the register the belong to --- srdl2sv/components/addrmap.py | 115 +++++++----------- srdl2sv/components/component.py | 93 +++++++++++--- srdl2sv/components/field.py | 27 ++-- srdl2sv/components/register.py | 12 +- srdl2sv/components/templates/addrmap.yaml | 16 +-- .../widgets/srdl2sv_amba3ahblite.yaml | 12 ++ 6 files changed, 158 insertions(+), 117 deletions(-) diff --git a/srdl2sv/components/addrmap.py b/srdl2sv/components/addrmap.py index a8c80df..5f75ce4 100644 --- a/srdl2sv/components/addrmap.py +++ b/srdl2sv/components/addrmap.py @@ -153,81 +153,55 @@ class AddrMap(Component): for name in self.get_resets() ] + ports_rtl = [] + # Prefetch dictionaries in local array - input_dict_list = self.get_ports('input').items() - output_dict_list = self.get_ports('output').items() + port_dict_list = self.get_ports().items() - input_signal_width = min( - max([len(value[0]) for (_, value) in input_dict_list]), 40) + for group, ports in port_dict_list: + ports_rtl.append(f"// Ports for '{group}'") - input_name_width = min( - max([len(key) for (key, _) in input_dict_list]), 40) + # Determine widths for this group + signal_width = max( + max([len(value.datatype) for (_, value) in ports.items()]), 12) - output_signal_width = min( - max([len(value[0]) for (_, value) in output_dict_list]), 40) + name_width = max([len(key) for (key, _) in ports.items()]) - output_name_width = min( - max([len(key) for (key, _) in output_dict_list]), 40) + # Generate RTL + for (key, port_type) in ports.items(): + # TODO: Think about a better way to handle datatypes. Simply replacing them + # is not the most efficient way of handling it. + signal_type = port_type.datatype.replace('logic', '').strip() + if config['unpacked_arrays'] and port_type.dim: + unpacked_dim = f"[{']['.join([str(y) for y in port_type.dim])}]" + elif port_type.dim: + unpacked_dim = '' + signal_type = ''.join([ + f"[{':0]['.join([str(y-1) for y in port_type.dim])}:0]", + signal_type + ]) + else: + unpacked_dim = '' - # Input ports - input_ports_rtl = [] - for (key, value) in input_dict_list: - # TODO: Think about a better way to handle datatypes. Simply replacing them - # is not the most efficient way of handling it. - signal_type = value[0].replace('logic', '').strip() - - if config['unpacked_arrays'] and value[1]: - unpacked_dim = f"[{']['.join([str(y) for y in value[1]])}]" - elif value[1]: - unpacked_dim = '' - signal_type = ''.join([ - f"[{':0]['.join([str(y-1) for y in value[1]])}:0]", - signal_type - ]) - else: - unpacked_dim = '' - - input_ports_rtl.append( - AddrMap.templ_dict['input_port']['rtl'].format( - name = key, - signal_type = signal_type, - signal_width = input_signal_width, - name_width = input_name_width, - unpacked_dim = unpacked_dim, + ports_rtl.append( + AddrMap.templ_dict['port']['rtl'].format( + name = key, + direction = port_type.direction, + signal_type = signal_type, + signal_width = signal_width, + name_width = name_width, + unpacked_dim = unpacked_dim, + ) ) - ) - # Output ports - output_ports_rtl = [] - for (key, value) in output_dict_list: - # TODO: Think about a better way to handle datatypes. Simply replacing them - # is not the most efficient way of handling it. - signal_type = value[0].replace('logic', '').strip() - - if config['unpacked_arrays'] and value[1]: - unpacked_dim = f"[{']['.join([str(y) for y in value[1]])}]" - elif value[1]: - unpacked_dim = '' - signal_type = ''.join([ - f"[{':0]['.join([str(y-1) for y in value[1]])}:0]", - signal_type - ]) - else: - unpacked_dim = '' - - output_ports_rtl.append( - AddrMap.templ_dict['output_port']['rtl'].format( - name = key, - signal_type = signal_type, - signal_width = output_signal_width, - name_width = output_name_width, - unpacked_dim = unpacked_dim, - ) - ) + # Append a new line after every port + ports_rtl.append('') + # Remove last newline # Remove comma from last port entry - output_ports_rtl[-1] = output_ports_rtl[-1].rstrip(',') + ports_rtl.pop() + ports_rtl[-1] = ports_rtl[-1].rstrip(',') # Define packages to be included. Always include the # b2w and w2b defines. @@ -268,8 +242,7 @@ class AddrMap(Component): name = self.name, import_package_list = ''.join(import_package_list), resets = '\n'.join(reset_ports_rtl), - inputs = '\n'.join(input_ports_rtl), - outputs = '\n'.join(output_ports_rtl))) + ports = '\n'.join(ports_rtl))) # Add description, if applicable self.rtl_header.append(self.get_description()) @@ -321,8 +294,8 @@ class AddrMap(Component): def __add_signal_instantiation(self): dict_list = list(self.get_signals(True).items()) - signal_width = min(max([len(value[0]) for (_, value) in dict_list]), 40) - name_width = min(max([len(key) for (key, _) in dict_list]), 40) + signal_width = max(max([len(value.datatype) for (_, value) in dict_list]), 12) + name_width = max([len(key) for (key, _) in dict_list]) self.rtl_header = [ *self.rtl_header, @@ -330,13 +303,13 @@ class AddrMap(Component): '// Internal signals', *[AddrMap.templ_dict['signal_declaration'].format( name = key, - type = value[0], + type = value.datatype, signal_width = signal_width, name_width = name_width, unpacked_dim = '[{}]'.format( ']['.join( - [str(y) for y in value[1]])) - if value[1] else '') + [str(y) for y in value.dim])) + if value.dim else '') for (key, value) in dict_list], '' ] diff --git a/srdl2sv/components/component.py b/srdl2sv/components/component.py index fa754dc..8d63bae 100644 --- a/srdl2sv/components/component.py +++ b/srdl2sv/components/component.py @@ -3,6 +3,7 @@ import math import sys from typing import NamedTuple, Optional from dataclasses import dataclass +from enum import Enum from systemrdl import node @@ -27,6 +28,15 @@ class SWMuxEntryDimensioned(): mux_entry: SWMuxEntry dim: str +class SignalType(NamedTuple): + datatype: str + dim: list + +class PortType(NamedTuple): + datatype: str + dim: list + direction: str # String "input" or "output" + class Component(): def __init__( self, @@ -42,8 +52,6 @@ class Component(): self.ports = {} self.resets = set() self.signals = {} - self.ports['input'] = {} - self.ports['output'] = {} self.field_type = '' # Save object @@ -146,13 +154,19 @@ class Component(): return self.resets - def get_ports(self, port_type: str): + def get_ports(self): self.logger.debug("Return port list") for child in self.children.values(): - self.ports[port_type] |= child.get_ports(port_type) + for key, value in child.get_ports().items(): + if key in self.ports: + self.logger.debug("Group '%s' already present in port list") + self.ports[key] |= value + else: + self.logger.debug("Adding group '%s' to port list") + self.ports |= {key: value} - return self.ports[port_type] + return self.ports def get_max_dim_depth(self) -> int: self.logger.debug("Return depth '%s' for dimensions (including parents) '%s'.", @@ -285,8 +299,12 @@ class Component(): name.append('_q') elif isinstance(obj, node.SignalNode): # Must add it to signal list - self.ports['input'][obj.inst_name] =\ - ("logic" if obj.width == 1 else f"logic [{obj.width}:0]", []) + self.ports['Signals'][obj.inst_name] =\ + PortType ( + datatype = "logic" if obj.width == 1 else f"logic [{obj.width}:0]", + dim = [], + direction = "input" + ) else: name.append('_') name.append(obj.name) @@ -325,8 +343,10 @@ class Component(): array_dimensions = self.total_array_dimensions self.signals[signal['name'].format(**values)] =\ - (signal['signal_type'].format(**values), - array_dimensions) + SignalType ( + datatype = signal['signal_type'].format(**values), + dim = array_dimensions, + ) except (TypeError, KeyError): pass @@ -341,9 +361,29 @@ class Component(): except KeyError: array_dimensions = self.total_array_dimensions - self.ports['input'][input_p['name'].format(**values)] =\ - (input_p['signal_type'].format(**values), - array_dimensions) + try: + group = input_p['group'].format(**values) + except KeyError: + group = self.path_underscored_wo_field + + name = input_p['name'].format(**values) + + if group not in self.ports: + self.ports[group] = { + name: + PortType ( + datatype = input_p['signal_type'].format(**values), + dim = array_dimensions, + direction = "input", + ) + } + elif name not in self.ports[group]: + self.ports[group][name] =\ + PortType ( + datatype = input_p['signal_type'].format(**values), + dim = array_dimensions, + direction = "input", + ) except (TypeError, KeyError): pass @@ -358,9 +398,29 @@ class Component(): except KeyError: array_dimensions = self.total_array_dimensions - self.ports['output'][output_p['name'].format(**values)] =\ - (output_p['signal_type'].format(**values), - array_dimensions) + try: + group = output_p['group'].format(**values) + except KeyError: + group = self.path_underscored_wo_field + + name = output_p['name'].format(**values) + + if group not in self.ports: + self.ports[group] = { + name: + PortType ( + datatype = output_p['signal_type'].format(**values), + dim = array_dimensions, + direction = "output", + ) + } + elif name not in self.ports[group]: + self.ports[group][name] =\ + PortType ( + datatype = output_p['signal_type'].format(**values), + dim = array_dimensions, + direction = "output", + ) except (TypeError, KeyError): pass @@ -371,6 +431,9 @@ class Component(): self.owning_addrmap, self.full_path, self.path, self.path_underscored =\ Component.create_underscored_path_static(self.obj) + # By default, this is identical to path_underscored. Fields will override this + self.path_underscored_wo_field = self.path_underscored + @staticmethod def create_underscored_path_static(obj): owning_addrmap = obj.owning_addrmap.inst_name diff --git a/srdl2sv/components/field.py b/srdl2sv/components/field.py index 824f248..f5af72e 100644 --- a/srdl2sv/components/field.py +++ b/srdl2sv/components/field.py @@ -110,10 +110,11 @@ class Field(Component): else: path = self.path - path_wo_field = '__'.join(path.split('.', -1)[0:-1]) + # This is different than self.path_underscored_wo_field + path_underscored_wo_field = '__'.join(path.split('.', -1)[0:-1]) # path_wo_field_vec & path_undrescored_vec only used for external registers - self.path_wo_field_vec.append(path_wo_field) + self.path_wo_field_vec.append(path_underscored_wo_field) self.path_underscored_vec.append(alias_path_underscored if alias else self.path_underscored) # Define software access (if applicable) @@ -121,7 +122,7 @@ class Field(Component): if self.properties['sw_wr']: # Append to list of registers that can write - self.writable_by.add(path_wo_field) + self.writable_by.add(path_underscored_wo_field) # This will need a wire to indicate that a write is taking place self.properties['sw_wr_wire'] = True @@ -133,7 +134,7 @@ class Field(Component): access_rtl['sw_write'][0].append( self._process_yaml( Field.templ_dict['sw_access_field_swwe'], - {'path_wo_field': path_wo_field, + {'path_wo_field': path_underscored_wo_field, 'genvars': self.genvars_str, 'swwe': self.get_signal_name(swwe), 'field_type': self.field_type} @@ -143,7 +144,7 @@ class Field(Component): access_rtl['sw_write'][0].append( self._process_yaml( Field.templ_dict['sw_access_field_swwel'], - {'path_wo_field': path_wo_field, + {'path_wo_field': path_underscored_wo_field, 'genvars': self.genvars_str, 'swwel': self.get_signal_name(swwel), 'field_type': self.field_type} @@ -153,7 +154,7 @@ class Field(Component): access_rtl['sw_write'][0].append( self._process_yaml( Field.templ_dict['sw_access_field'], - {'path_wo_field': path_wo_field, + {'path_wo_field': path_underscored_wo_field, 'genvars': self.genvars_str, 'field_type': self.field_type} ) @@ -211,7 +212,7 @@ class Field(Component): if obj.get_property('sw') in (AccessType.rw, AccessType.r): # Append to list of registers that can read - self.readable_by.add(path_wo_field) + self.readable_by.add(path_underscored_wo_field) self.properties['sw_rd'] = True @@ -224,7 +225,7 @@ class Field(Component): access_rtl['sw_read'][0].append( self._process_yaml( Field.templ_dict['sw_read_access_field'], - {'path_wo_field': path_wo_field, + {'path_wo_field': path_underscored_wo_field, 'genvars': self.genvars_str, 'field_type': self.field_type} ) @@ -711,7 +712,7 @@ class Field(Component): self._process_yaml( Field.templ_dict['swmod_assign'], {'path': self.path_underscored, - 'path_wo_field': self.path_wo_field, + 'path_wo_field': self.path_underscored_wo_field, 'genvars': self.genvars_str, 'rd_wr': 'rd', 'msbyte': self.msbyte, @@ -727,7 +728,7 @@ class Field(Component): self._process_yaml( Field.templ_dict['swmod_assign'], {'path': self.path_underscored, - 'path_wo_field': self.path_wo_field, + 'path_wo_field': self.path_underscored_wo_field, 'genvars': self.genvars_str, 'rd_wr': 'wr', 'msbyte': self.msbyte, @@ -762,7 +763,7 @@ class Field(Component): swacc_props = self._process_yaml( Field.templ_dict['swacc_assign'], {'path': self.path_underscored, - 'path_wo_field': self.path_wo_field, + 'path_wo_field': self.path_underscored_wo_field, 'genvars': self.genvars_str, 'msbyte': self.msbyte, 'lsbyte': self.lsbyte, @@ -1349,7 +1350,7 @@ class Field(Component): self, obj: FieldNode): # Create full name - self.path_wo_field = '__'.join(self.path.split('.', -1)[0:-1]) + self.path_underscored_wo_field = '__'.join(self.path.split('.', -1)[0:-1]) self.register_name = ''.join([self.path_underscored, '_q']) self.path_underscored_vec = [] @@ -1451,7 +1452,7 @@ class Field(Component): external = self.config['external'], lsb = self.obj.lsb, msb = self.obj.msb, - path_wo_field = self.path_wo_field, + path_wo_field = self.path_underscored_wo_field, storage_type = self.storage_type, ) diff --git a/srdl2sv/components/register.py b/srdl2sv/components/register.py index e2caefc..6f21f01 100644 --- a/srdl2sv/components/register.py +++ b/srdl2sv/components/register.py @@ -511,20 +511,18 @@ class Register(Component): def get_signal_instantiations_list(self): dict_list = list(self.get_signals().items()) - - signal_width = min(max([len(value[0]) for (_, value) in dict_list]), 40) - - name_width = min(max([len(key) for (key, _) in dict_list]), 40) + signal_width = max(max([len(value.datatype) for (_, value) in dict_list]), 12) + name_width = max([len(key) for (key, _) in dict_list]) return [Register.templ_dict['signal_declaration'].format( name = key, - type = value[0], + type = value.datatype, signal_width = signal_width, name_width = name_width, unpacked_dim = '[{}]'.format( ']['.join( - [str(y) for y in value[1]])) - if value[1] else '') + [str(y) for y in value.dim])) + if value.dim else '') for (key, value) in dict_list] def add_alias(self, obj: node.RegNode): diff --git a/srdl2sv/components/templates/addrmap.yaml b/srdl2sv/components/templates/addrmap.yaml index adad7fb..efa386e 100644 --- a/srdl2sv/components/templates/addrmap.yaml +++ b/srdl2sv/components/templates/addrmap.yaml @@ -75,14 +75,11 @@ module_declaration: <> ( <> - // Resets + // Reset signals declared for registers {resets} - // Inputs - {inputs} + {ports} - // Outputs - {outputs} <> ); import_package: @@ -91,12 +88,9 @@ import_package: reset_port: rtl: input {name}, -input_port: - rtl: - input {signal_type:{signal_width}} {name:{name_width}}{unpacked_dim}, -output_port: - rtl: - output {signal_type:{signal_width}} {name:{name_width}}{unpacked_dim}, +port: + rtl: |- + {direction:6} {signal_type:{signal_width}} {name:{name_width}}{unpacked_dim}, signal_declaration: |- {type:{signal_width}} {name:{name_width}}{unpacked_dim}; package_declaration: diff --git a/srdl2sv/components/widgets/srdl2sv_amba3ahblite.yaml b/srdl2sv/components/widgets/srdl2sv_amba3ahblite.yaml index 61bc6a7..0f8023e 100644 --- a/srdl2sv/components/widgets/srdl2sv_amba3ahblite.yaml +++ b/srdl2sv/components/widgets/srdl2sv_amba3ahblite.yaml @@ -40,26 +40,38 @@ module_instantiation: input_ports: - name: 'clk' signal_type: '' + group: 'General Clock' - name: 'HRESETn' signal_type: '' + group: 'AHB Protocol' - name: 'HADDR' signal_type: '[31:0]' + group: 'AHB Protocol' - name: 'HWRITE' signal_type: '' + group: 'AHB Protocol' - name: 'HSIZE' signal_type: '[2:0]' + group: 'AHB Protocol' - name: 'HPROT' signal_type: '[3:0]' + group: 'AHB Protocol' - name: 'HTRANS' signal_type: '[1:0]' + group: 'AHB Protocol' - name: 'HWDATA' signal_type: '[{bus_width}-1:0]' + group: 'AHB Protocol' - name: 'HSEL' signal_type: '' + group: 'AHB Protocol' output_ports: - name: 'HREADYOUT' signal_type: '' + group: 'AHB Protocol' - name: 'HRESP' signal_type: '' + group: 'AHB Protocol' - name: 'HRDATA' signal_type: '[{bus_width}-1:0]' + group: 'AHB Protocol'