diff --git a/srdl2sv/components/addrmap.py b/srdl2sv/components/addrmap.py index 40503e5..62b33a7 100644 --- a/srdl2sv/components/addrmap.py +++ b/srdl2sv/components/addrmap.py @@ -59,28 +59,49 @@ class AddrMap(Component): # Start assembling addrmap module self.logger.info("Starting to assemble input/output/inout ports") + # Prefetch dictionaries in local array + input_dict_list = [(key, value) for (key, value) in self.get_ports('input').items()] + output_dict_list = [(key, value) for (key, value) in self.get_ports('output').items()] + + input_signal_width = min( + max([len(value[0]) for (_, value) in input_dict_list]), 40) + + input_name_width = min( + max([len(key) for (key, _) in input_dict_list]), 40) + + output_signal_width = min( + max([len(value[0]) for (_, value) in output_dict_list]), 40) + + output_name_width = min( + max([len(key) for (key, _) in output_dict_list]), 40) + + # Input ports input_ports_rtl = [ AddrMap.templ_dict['input_port'].format( name = key, signal_type = value[0], + signal_width = input_signal_width, + name_width = input_name_width, unpacked_dim = '[{}]'.format( ']['.join( [str(y) for y in value[1]])) if value[1] else '') - for (key, value) in self.get_ports('input').items() + for (key, value) in input_dict_list ] # Output ports output_ports_rtl = [ AddrMap.templ_dict['output_port'].format( name = key, + signal_width = output_signal_width, + name_width = output_name_width, signal_type = value[0], unpacked_dim = '[{}]'.format( ']['.join( [str(y) for y in value[1]])) if value[1] else '') - for (key, value) in self.get_ports('output').items() + for (key, value) in output_dict_list ] # Remove comma from last port entry diff --git a/srdl2sv/components/component.py b/srdl2sv/components/component.py index f44eb03..6f245e1 100644 --- a/srdl2sv/components/component.py +++ b/srdl2sv/components/component.py @@ -7,19 +7,16 @@ from systemrdl import node from log.log import create_logger # Define NamedTuple -class TypeDefMembers(NamedTuple): - name: str - member_type: str - class TypeDef(NamedTuple): - name: str - members: list[TypeDefMembers] + scope: str + members: tuple class Component(): def __init__(self): self.rtl_header = [] self.rtl_footer = [] self.children = [] + self.typedef = dict() self.ports = dict() self.signals = dict() self.ports['input'] = dict() diff --git a/srdl2sv/components/field.py b/srdl2sv/components/field.py index 314646c..e716844 100644 --- a/srdl2sv/components/field.py +++ b/srdl2sv/components/field.py @@ -2,12 +2,12 @@ import math import importlib.resources as pkg_resources import yaml -from systemrdl import RDLCompiler, RDLCompileError, RDLWalker, RDLListener, node -from systemrdl.node import FieldNode +from systemrdl.node import FieldNode, SignalNode +from systemrdl.component import Reg, Regfile, Addrmap, Root from systemrdl.rdltypes import PrecedenceType, AccessType, OnReadType, OnWriteType # Local modules -from components.component import Component +from components.component import Component, TypeDef from . import templates class Field(Component): @@ -16,7 +16,7 @@ class Field(Component): pkg_resources.read_text(templates, 'fields.yaml'), Loader=yaml.FullLoader) - def __init__(self, obj: node.FieldNode, array_dimensions: list, config:dict): + def __init__(self, obj: FieldNode, array_dimensions: list, config:dict): super().__init__() # Save and/or process important variables @@ -26,6 +26,9 @@ class Field(Component): self.create_logger("{}.{}".format(self.owning_addrmap, self.path), config) self.logger.debug('Starting to process field "{}"'.format(obj.inst_name)) + # Determine field types + self.__process_fieldtype() + ################################################################################## # LIMITATION: # v1.x of the systemrdl-compiler does not support non-homogeneous arrays. @@ -67,7 +70,73 @@ class Field(Component): [self.yaml_signals_to_list(Field.templ_dict[i[1]]) for i in operations] - def __process_variables(self, obj: node.RootNode, array_dimensions: list): + def __process_fieldtype(self): + try: + enum = self.obj.get_property('encode') + + # Rules for scope: + # - Regfiles or addrmaps have packages + # - An enum that is not defined within a register will go into the package + # of the first addrmap or regfile that is found when iterating through + # the parents + # - Regfiles don't need to be unique in a design. Therefore, the packages of + # regfiles shall be prepended by the addrmap name. + # - When the enum is defined in a register, that register will be prepended + # to the name of that enum. + # + # This procedure is expensive, but None.parent() will not work and therefore + # kill the try block in most cases + parent_scope = enum.get_parent_scope() + + self.logger.debug("Starting to parse '{}'".format(enum)) + + if isinstance(parent_scope, Reg): + enum_name = '__'.join([enum.get_scope_path().split('::')[-1], enum.__name__]) + parent_scope = parent_scope.parent_scope + else: + enum_name = enum.__name__ + + path = [] + + # Open up all parent scopes and append it to scope list + while 1: + if isinstance(parent_scope, Regfile): + if parent_scope.is_instance: + path.append(parent_scope.inst_name) + else: + path.append(parent_scope.type_name) + + # That's a lot of parent_scope's... + parent_scope = parent_scope.parent_scope + else: + path.append(self.owning_addrmap) + + break + + # Create string. Reverse list so that order starts at addrmap + scope = '__'.join(reversed(path)) + + # Create internal NamedTuple with information on Enum + self.typedef[enum_name] = TypeDef ( + scope=scope, + members= [(x.name, x.value) for x in self.obj.get_property('encode')] + ) + + # Save name of object + self.field_type =\ + '::'.join([scope, enum_name]) + + self.logger.info("Parsed enum '{}'".format(enum_name)) + + except AttributeError: + # In case of an AttributeError, the encode property is None. Hence, + # the field has a simple width + if self.obj.width > 1: + self.field_type = 'logic [{}:0]'.format(self.obj.width-1) + else: + self.field_type = 'logic' + + def __process_variables(self, obj: FieldNode, array_dimensions: list): # Save object self.obj = obj @@ -81,9 +150,6 @@ class Field(Component): self.path_underscored = self.path.replace('.', '_') self.path_wo_field = '.'.join(self.path.split('.', -1)[0:-1]) - # Field type - self.field_type = 'logic' - # Save dimensions of unpacked dimension self.array_dimensions = array_dimensions @@ -228,13 +294,13 @@ class Field(Component): swwe = self.obj.get_property('swwe') swwel = self.obj.get_property('swwel') - if isinstance(swwe, (node.FieldNode, node.SignalNode)): + if isinstance(swwe, (FieldNode, SignalNode)): access_rtl['sw_write'].append( Field.templ_dict['sw_access_field_swwe']['rtl'].format( path_wo_field = self.path_wo_field, genvars = self.genvars_str, swwe = Component.get_signal_name(swwe))) - elif isinstance(swwel, (node.FieldNode, node.SignalNode)): + elif isinstance(swwel, (FieldNode, SignalNode)): access_rtl['sw_write'].append( Field.templ_dict['sw_access_field_swwel']['rtl'].format( path_wo_field = self.path_wo_field, diff --git a/srdl2sv/components/register.py b/srdl2sv/components/register.py index 7805edf..98af9a5 100644 --- a/srdl2sv/components/register.py +++ b/srdl2sv/components/register.py @@ -70,16 +70,24 @@ class Register(Component): self.yaml_signals_to_list(Register.templ_dict[rw_wire_assign_field]) # Add wire/register instantiations + dict_list = [(key, value) for (key, value) in 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) + self.rtl_header = [ *[ Register.templ_dict['signal_declaration'].format( name = key, type = value[0], + signal_width = signal_width, + name_width = name_width, unpacked_dim = '[{}]'.format( ']['.join( [str(y) for y in value[1]])) if value[1] else '') - for (key, value) in self.get_signals().items()], + for (key, value) in dict_list], '', *self.rtl_header, ] diff --git a/srdl2sv/components/templates/addrmap.yaml b/srdl2sv/components/templates/addrmap.yaml index a9a8610..e0d2391 100644 --- a/srdl2sv/components/templates/addrmap.yaml +++ b/srdl2sv/components/templates/addrmap.yaml @@ -11,6 +11,6 @@ module_declaration: |- {outputs} ); input_port: |- - input {signal_type:15s}{name:25s} {unpacked_dim}, + input {signal_type:{signal_width}} {name:{name_width}}{unpacked_dim}, output_port: |- - output {signal_type:15s}{name:25s} {unpacked_dim}, + output {signal_type:{signal_width}} {name:{name_width}}{unpacked_dim}, diff --git a/srdl2sv/components/templates/regs.yaml b/srdl2sv/components/templates/regs.yaml index 7650b6b..4c4b4dd 100644 --- a/srdl2sv/components/templates/regs.yaml +++ b/srdl2sv/components/templates/regs.yaml @@ -47,4 +47,4 @@ generate_for_start: |- generate_for_end: |- end // of for loop with iterator {dimension} signal_declaration: |- - {type:10s}{name:20s} {unpacked_dim}; + {type:{signal_width}} {name:{name_width}}{unpacked_dim};