From ec02290bbe10f2b39b17faff95920b2cb613096f Mon Sep 17 00:00:00 2001 From: Dennis Date: Sun, 24 Oct 2021 00:07:59 -0700 Subject: [PATCH] Move several methods to common Components ancestor For example, most methods relating to dimensions or genvars were moved to the Components class. Furthermore, some more care was taken of _ or __ prefixes for methods: - No method-prefix: Public variable that is will be called by non-related functions and methods. - _ method-prefix: Method will be called by class or class that inerhits class - __ method-prefix: Method will be called by class itself only --- srdl2sv/components/addrmap.py | 51 +++++---- srdl2sv/components/component.py | 139 +++++++++++++++--------- srdl2sv/components/field.py | 180 ++++++++++++++++++-------------- srdl2sv/components/memory.py | 61 +++++------ srdl2sv/components/regfile.py | 132 ++++++++--------------- srdl2sv/components/register.py | 148 +++++++++----------------- 6 files changed, 345 insertions(+), 366 deletions(-) diff --git a/srdl2sv/components/addrmap.py b/srdl2sv/components/addrmap.py index 0ff0414..0e3c3f9 100644 --- a/srdl2sv/components/addrmap.py +++ b/srdl2sv/components/addrmap.py @@ -24,22 +24,22 @@ class AddrMap(Component): Loader=yaml.FullLoader) def __init__(self, obj: node.RootNode, config: dict): - super().__init__(obj, config) + super().__init__( + obj=obj, + config=config, + parents_strides=None, + parents_dimensions=None) # Check if global resets are defined glbl_settings = {} - # Set defaults so that some of the common component methods work - self.total_dimensions = 0 - self.total_array_dimensions = [] - # Use global settings to define whether a component is already in a generate block glbl_settings['generate_active'] = False # Save whether 0, 1, or x must be set for reserved bits - if obj.get_property('rsvdset'): + if self.obj.get_property('rsvdset'): glbl_settings['rsvd_val'] = "1" - elif obj.get_property('rsvdsetX'): + elif self.obj.get_property('rsvdsetX'): glbl_settings['rsvd_val'] = "x" else: glbl_settings['rsvd_val'] = "0" @@ -53,17 +53,28 @@ class AddrMap(Component): self.regwidth = 0 # Traverse through children - for child in obj.children(): + for child in self.obj.children(): if isinstance(child, node.AddrmapNode): # This addressmap opens a completely new scope. For example, # a field_reset does not propagate through to this scope. self.logger.info('Found hierarchical addrmap. Entering it...') self.logger.error('Child addrmaps are not implemented yet!') elif isinstance(child, node.RegfileNode): - new_child = RegFile(child, [], [], config, glbl_settings) + new_child = RegFile( + obj=child, + parents_dimensions=None, + parents_strides=None, + config=config, + glbl_settings=glbl_settings) self.regfiles[child.inst_name] = new_child elif isinstance(child, node.MemNode): - new_child = Memory(child, [], [], config, glbl_settings) + new_child = Memory( + obj=child, + parents_dimensions=None, + parents_strides=None, + config=config, + glbl_settings=glbl_settings) + new_child.sanity_checks() self.mems[child.inst_name] = new_child elif isinstance(child, node.RegNode): if child.inst.is_alias: @@ -73,7 +84,12 @@ class AddrMap(Component): self.registers[child.inst.alias_primary_inst.inst_name]\ .add_alias(child) else: - new_child = Register(child, [], [], config, glbl_settings) + new_child = Register( + obj=child, + parents_dimensions=None, + parents_strides=None, + config=config, + glbl_settings=glbl_settings) self.registers[child.inst_name] = new_child try: @@ -168,9 +184,9 @@ class AddrMap(Component): ] try: - for x in self.get_package_names(): + for pkg_name in self.__get_package_names(): import_package_list.append( - AddrMap.templ_dict['import_package']['rtl'].format(name = x) + AddrMap.templ_dict['import_package']['rtl'].format(name = pkg_name) ) import_package_list.append('\n') @@ -243,7 +259,7 @@ class AddrMap(Component): list_of_cases.append(AddrMap.templ_dict['default_mux_case']['rtl']) self.rtl_footer.append( - self.process_yaml( + self._process_yaml( AddrMap.templ_dict['read_mux'], {'list_of_cases': '\n'.join(list_of_cases)} ) @@ -276,7 +292,7 @@ class AddrMap(Component): pkg_resources.read_text(widgets, f"srdl2sv_{self.config['bus']}.yaml"), Loader=yaml.FullLoader) - return self.process_yaml( + return self._process_yaml( self.widget_templ_dict['module_instantiation'], {'bus_width': self.regwidth, 'no_byte_enable': 1 if self.config['no_byte_enable'] else 0, @@ -297,7 +313,7 @@ class AddrMap(Component): self.rtl_header.append(genvars_instantiation) - def get_package_names(self) -> set(): + def __get_package_names(self) -> set(): names = set() for register in self.registers.values(): @@ -387,6 +403,3 @@ class AddrMap(Component): real_tabs) return rtl_return - - def get_regwidth(self) -> int: - return self.regwidth diff --git a/srdl2sv/components/component.py b/srdl2sv/components/component.py index 3e4aae4..23d040e 100644 --- a/srdl2sv/components/component.py +++ b/srdl2sv/components/component.py @@ -1,6 +1,7 @@ import re +import math import sys -from typing import NamedTuple +from typing import NamedTuple, Optional from dataclasses import dataclass from systemrdl import node @@ -27,7 +28,13 @@ class SWMuxEntryDimensioned(): dim: str class Component(): - def __init__(self, obj, config): + def __init__( + self, + obj, + config, + parents_dimensions: Optional[list] = None, + parents_strides: Optional[list] = None): + self.rtl_header = [] self.rtl_footer = [] self.children = {} @@ -52,6 +59,18 @@ class Component(): # Save config self.config = config.copy() + # Generate all variables that have anything to do with dimensions or strides + self.__init_dimensions(parents_dimensions) + self.__init_strides(parents_strides) + + # Save and/or process important variables + self.__init_variables() + + # Create logger object + self.__create_logger(self.full_path, config) + self.logger.debug(f"Starting to process {self.__class__.__name__} '{obj.inst_name}'") + + def __init_variables(self): # By default, registers and fields are not interrupt registers self.properties = { 'intr': False, @@ -64,11 +83,10 @@ class Component(): 'sw_wr_wire': False, } - # Create logger object - self.create_logger(self.full_path, config) - self.logger.debug(f"Starting to process {self.__class__.__name__} '{obj.inst_name}'") + self.genvars_str = '' - def create_logger(self, name: str, config: dict): + + def __create_logger(self, name: str, config: dict): self.logger = create_logger( name, stream_log_level=config['stream_log_level'], @@ -76,6 +94,51 @@ class Component(): file_name=config['file_log_location']) self.logger.propagate = False + def __init_dimensions(self, parents_dimensions): + # Determine dimensions of register + self.sel_arr = 'single' + self.total_array_dimensions = parents_dimensions if parents_dimensions else [] + self.own_array_dimensions = [] + + try: + if self.obj.is_array: + self.sel_arr = 'array' + self.total_array_dimensions = [*self.total_array_dimensions, + *self.obj.array_dimensions] + self.own_array_dimensions = self.obj.array_dimensions + except AttributeError: + pass + + # How many dimensions were already part of some higher up hierarchy? + self.parents_depths = len(parents_dimensions) if parents_dimensions else 0 + + # Calculate depth and number of dimensions + self.own_depth = '[{}]'.format(']['.join(f"{i}" for i in self.own_array_dimensions)) + self.own_dimensions = len(self.own_array_dimensions) + self.total_dimensions = len(self.total_array_dimensions) + + def __init_strides(self, parents_strides): + self.total_stride = parents_strides if parents_strides else [] + + try: + if self.obj.is_array: + # Merge parent's stride with stride of this regfile. Before doing so, the + # respective stride of the different dimensions shall be calculated + self.total_stride = [ + *self.total_stride, + *[math.prod(self.own_array_dimensions[i+1:]) + *self.obj.array_stride + for i, _ in enumerate(self.own_array_dimensions)] + ] + except AttributeError: + # Not all Nodes can be an array. In that case, just take the parent's stride + pass + + def _init_genvars(self): + # Calculate how many genvars shall be added + genvars = [f"[gv_{chr(97+i)}]" for i in range(self.total_dimensions)] + self.genvars_str = ''.join(genvars) + def get_resets(self): self.logger.debug("Return reset list") @@ -145,7 +208,7 @@ class Component(): indent_lvl_next = 0 # Define tab style - tab = "\t" if real_tabs else " " + tab = "\t" if real_tabs else " " tab = tab_width * tab # Define triggers for which the indentation level will increment or @@ -190,14 +253,14 @@ class Component(): return '\n'.join(rtl_indented) @staticmethod - def get_underscored_path(path: str, owning_addrmap: str): + def __get_underscored_path(path: str, owning_addrmap: str): return path\ .replace('[]', '')\ .replace(f"{owning_addrmap}.", '')\ .replace('.', '__') @staticmethod - def split_dimensions(path: str): + def __split_dimensions(path: str): re_dimensions = re.compile(r'(\[[^]]*\])') new_path = re_dimensions.sub('', path) return (new_path, ''.join(re_dimensions.findall(path))) @@ -210,8 +273,8 @@ class Component(): except AttributeError: child_obj = obj - split_name = Component.split_dimensions( - Component.get_underscored_path( + split_name = self.__split_dimensions( + self.__get_underscored_path( child_obj.get_path(), child_obj.owning_addrmap.inst_name) ) @@ -243,7 +306,7 @@ class Component(): return ''.join(name) - def process_yaml(self, + def _process_yaml(self, yaml_obj, values: dict = {}, skip_signals: bool = False, @@ -255,7 +318,8 @@ class Component(): for signal in yaml_obj['signals']: try: - array_dimensions = [] if signal['no_unpacked'] else self.total_array_dimensions + array_dimensions = [] if signal['no_unpacked'] \ + else self.total_array_dimensions except KeyError: array_dimensions = self.total_array_dimensions @@ -269,14 +333,15 @@ class Component(): if skip_inputs: raise KeyError - for input in yaml_obj['input_ports']: + for input_p in yaml_obj['input_ports']: try: - array_dimensions = [] if input['no_unpacked'] else self.total_array_dimensions + array_dimensions = [] if input_p['no_unpacked'] \ + else self.total_array_dimensions except KeyError: array_dimensions = self.total_array_dimensions - self.ports['input'][input['name'].format(**values)] =\ - (input['signal_type'].format(**values), + self.ports['input'][input_p['name'].format(**values)] =\ + (input_p['signal_type'].format(**values), array_dimensions) except (TypeError, KeyError): pass @@ -285,14 +350,15 @@ class Component(): if skip_outputs: raise KeyError - for output in yaml_obj['output_ports']: + for output_p in yaml_obj['output_ports']: try: - array_dimensions = [] if output['no_unpacked'] else self.total_array_dimensions + array_dimensions = [] if output_p['no_unpacked'] \ + else self.total_array_dimensions except KeyError: array_dimensions = self.total_array_dimensions - self.ports['output'][output['name'].format(**values)] =\ - (output['signal_type'].format(**values), + self.ports['output'][output_p['name'].format(**values)] =\ + (output_p['signal_type'].format(**values), array_dimensions) except (TypeError, KeyError): pass @@ -300,32 +366,6 @@ class Component(): # Return RTL with values return yaml_obj['rtl'].format(**values) - @staticmethod - def process_reset_signal(reset_signal): - rst = {} - - try: - rst['name'] = reset_signal.inst_name - rst['async'] = reset_signal.get_property("async") - rst['type'] = "asynchronous" if rst['async'] else "synchronous" - - # Active low or active high? - if reset_signal.get_property("activelow"): - rst['edge'] = "negedge" - rst['active'] = "active_low" - else: - rst['edge'] = "posedge" - rst['active'] = "active_high" - except: - rst['async'] = False - rst['name'] = None - rst['edge'] = None - rst['value'] = "'x" - rst['active'] = "-" - rst['type'] = "-" - - return rst - def create_underscored_path(self): self.owning_addrmap, self.full_path, self.path, self.path_underscored =\ Component.create_underscored_path_static(self.obj) @@ -333,7 +373,7 @@ class Component(): @staticmethod def create_underscored_path_static(obj): owning_addrmap = obj.owning_addrmap.inst_name - full_path = Component.split_dimensions(obj.get_path())[0] + full_path = Component.__split_dimensions(obj.get_path())[0] path = full_path.replace(f"{owning_addrmap}.", '') path_underscored = path.replace('.', '__') @@ -349,3 +389,6 @@ class Component(): ) return '' + + def get_regwidth(self) -> int: + return self.regwidth diff --git a/srdl2sv/components/field.py b/srdl2sv/components/field.py index bf94e4b..2475321 100644 --- a/srdl2sv/components/field.py +++ b/srdl2sv/components/field.py @@ -2,6 +2,7 @@ import math import importlib.resources as pkg_resources import sys +from typing import Optional import yaml from systemrdl.node import FieldNode, SignalNode @@ -21,16 +22,22 @@ class Field(Component): def __init__( self, obj: FieldNode, - array_dimensions: list, - config:dict, - glbl_settings: dict): - super().__init__(obj, config) + parents_dimensions: Optional[list], + config: dict): + super().__init__( + obj=obj, + config=config, + parents_strides=None, + parents_dimensions=parents_dimensions) + + # Generate all variables that have anything to do with dimensions or strides + self._init_genvars() # Save and/or process important variables - self.__process_variables(obj, array_dimensions, glbl_settings) + self.__init_variables(obj) # Determine field types - self.__process_fieldtype() + self.__init_fieldtype() ################################################################################## # LIMITATION: @@ -39,7 +46,7 @@ class Field(Component): # can be found here: https://github.com/SystemRDL/systemrdl-compiler/issues/51 ################################################################################## # Print a summary - self.rtl_header.append(self.summary()) + self.rtl_header.append(self.__summary()) # Add description self.rtl_header.append(self.get_description()) @@ -87,7 +94,7 @@ class Field(Component): if isinstance(swwe, (FieldNode, SignalNode)): access_rtl['sw_write'][0].append( - self.process_yaml( + self._process_yaml( Field.templ_dict['sw_access_field_swwe'], {'path_wo_field': path_wo_field, 'genvars': self.genvars_str, @@ -97,7 +104,7 @@ class Field(Component): ) elif isinstance(swwel, (FieldNode, SignalNode)): access_rtl['sw_write'][0].append( - self.process_yaml( + self._process_yaml( Field.templ_dict['sw_access_field_swwel'], {'path_wo_field': path_wo_field, 'genvars': self.genvars_str, @@ -107,7 +114,7 @@ class Field(Component): ) else: access_rtl['sw_write'][0].append( - self.process_yaml( + self._process_yaml( Field.templ_dict['sw_access_field'], {'path_wo_field': path_wo_field, 'genvars': self.genvars_str, @@ -123,7 +130,7 @@ class Field(Component): self.logger.warning("The OnWriteType.wuser is not yet supported!") elif onwrite in (OnWriteType.wclr, OnWriteType.wset): access_rtl['sw_write'][0].append( - self.process_yaml( + self._process_yaml( Field.templ_dict[str(onwrite)], {'path': path_underscored, 'genvars': self.genvars_str, @@ -139,7 +146,7 @@ class Field(Component): lsb_bus = 8*i if i != self.lsbyte else obj.inst.lsb access_rtl['sw_write'][0].append( - self.process_yaml( + self._process_yaml( Field.templ_dict[str(onwrite)], {'path': path_underscored, 'genvars': self.genvars_str, @@ -161,7 +168,7 @@ class Field(Component): lsb_bus = 8*i if i != self.lsbyte else obj.inst.lsb access_rtl['sw_write'][0].append( - self.process_yaml( + self._process_yaml( Field.templ_dict['sw_access_byte'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -192,7 +199,7 @@ class Field(Component): self.properties['sw_rd_wire'] = True access_rtl['sw_read'][0].append( - self.process_yaml( + self._process_yaml( Field.templ_dict[str(onread)], {'width': obj.width, 'path': path_underscored, @@ -205,7 +212,7 @@ class Field(Component): # Property cannot be overwritten by alias if obj.get_property('singlepulse'): self.access_rtl['singlepulse'] = ([ - self.process_yaml( + self._process_yaml( Field.templ_dict['singlepulse'], {'path': self.path_underscored, 'genvars': self.genvars_str} @@ -297,7 +304,7 @@ class Field(Component): incr_width_input = True # Doesn't return RTL, only adds input port - self.process_yaml( + self._process_yaml( Field.templ_dict['counter_incr_val_input'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -339,7 +346,7 @@ class Field(Component): # an internal signal. It is possible that this is tied to 0. if not incr_width_input: self.rtl_footer.append( - self.process_yaml( + self._process_yaml( Field.templ_dict['counter_internal_incr_val_signal'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -365,7 +372,7 @@ class Field(Component): decr_width_input = True # Doesn't return RTL, only adds input port - self.process_yaml( + self._process_yaml( Field.templ_dict['counter_decr_val_input'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -407,7 +414,7 @@ class Field(Component): # an internal signal. It is possible that this is tied to 0. if not decr_width_input: self.rtl_footer.append( - self.process_yaml( + self._process_yaml( Field.templ_dict['counter_internal_decr_val_signal'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -432,13 +439,13 @@ class Field(Component): if not incr: # Will only add input port but not return any RTL - self.process_yaml( + self._process_yaml( Field.templ_dict['counter_incr_input'], {'path': self.path_underscored} ) else: self.rtl_footer.append( - self.process_yaml( + self._process_yaml( Field.templ_dict['counter_internal_incr_signal'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -459,7 +466,7 @@ class Field(Component): else: # Tie signal to 0 self.rtl_footer.append( - self.process_yaml( + self._process_yaml( Field.templ_dict['counter_internal_incr_signal'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -473,13 +480,13 @@ class Field(Component): if not self.obj.get_property('decr'): # Will only add input port but not return any RTL - self.process_yaml( + self._process_yaml( Field.templ_dict['counter_decr_input'], {'path': self.path_underscored} ) else: self.rtl_footer.append( - self.process_yaml( + self._process_yaml( Field.templ_dict['counter_internal_decr_signal'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -500,7 +507,7 @@ class Field(Component): else: # Tie signal to 0 self.rtl_footer.append( - self.process_yaml( + self._process_yaml( Field.templ_dict['counter_internal_decr_signal'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -512,7 +519,7 @@ class Field(Component): # Handle saturation signals if not incr_sat_value: self.rtl_footer.append( - self.process_yaml( + self._process_yaml( Field.templ_dict['counter_incr_sat_tied'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -521,7 +528,7 @@ class Field(Component): ) else: self.rtl_footer.append( - self.process_yaml( + self._process_yaml( Field.templ_dict['counter_incr_sat'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -534,7 +541,7 @@ class Field(Component): if not decr_sat_value: self.rtl_footer.append( - self.process_yaml( + self._process_yaml( Field.templ_dict['counter_decr_sat_tied'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -543,7 +550,7 @@ class Field(Component): ) else: self.rtl_footer.append( - self.process_yaml( + self._process_yaml( Field.templ_dict['counter_decr_sat'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -560,7 +567,7 @@ class Field(Component): if incr_thr_value: self.rtl_footer.append( - self.process_yaml( + self._process_yaml( Field.templ_dict['counter_incr_thr'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -573,7 +580,7 @@ class Field(Component): if decr_thr_value: self.rtl_footer.append( - self.process_yaml( + self._process_yaml( Field.templ_dict['counter_decr_thr'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -587,7 +594,7 @@ class Field(Component): # Handle overflow & underflow signals if self.obj.get_property('overflow'): self.rtl_footer.append( - self.process_yaml( + self._process_yaml( Field.templ_dict['counter_overflow'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -600,7 +607,7 @@ class Field(Component): if self.obj.get_property('underflow'): self.rtl_footer.append( - self.process_yaml( + self._process_yaml( Field.templ_dict['counter_underflow'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -613,7 +620,7 @@ class Field(Component): # Implement actual counter logic self.rtl_footer.append( - self.process_yaml( + self._process_yaml( Field.templ_dict['counter'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -621,8 +628,6 @@ class Field(Component): ) ) - - def __add_swmod_swacc(self): if self.obj.get_property('swmod'): self.logger.debug("Field has swmod property") @@ -632,7 +637,7 @@ class Field(Component): # Check if read side-effects are defined. if self.obj.get_property('onread'): swmod_assigns.append( - self.process_yaml( + self._process_yaml( Field.templ_dict['swmod_assign'], {'path': self.path_underscored, 'path_wo_field': self.path_wo_field, @@ -648,7 +653,7 @@ class Field(Component): # Check if SW has write access to the field if self.properties['sw_wr']: swmod_assigns.append( - self.process_yaml( + self._process_yaml( Field.templ_dict['swmod_assign'], {'path': self.path_underscored, 'path_wo_field': self.path_wo_field, @@ -661,7 +666,7 @@ class Field(Component): ) ) - swmod_props = self.process_yaml( + swmod_props = self._process_yaml( Field.templ_dict['swmod_always_comb'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -683,7 +688,7 @@ class Field(Component): self.properties['sw_wr_wire'] = True self.properties['sw_rd_wire'] = True - swacc_props = self.process_yaml( + swacc_props = self._process_yaml( Field.templ_dict['swacc_assign'], {'path': self.path_underscored, 'path_wo_field': self.path_wo_field, @@ -719,7 +724,7 @@ class Field(Component): trigger_signal = self.get_signal_name(next_val) else: trigger_signal =\ - self.process_yaml( + self._process_yaml( Field.templ_dict['trigger_input'], {'path': self.path_underscored, 'field_type': self.field_type, @@ -728,7 +733,7 @@ class Field(Component): if bit_type: self.access_rtl['hw_write'] = ([ - self.process_yaml( + self._process_yaml( Field.templ_dict[bit_type], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -741,7 +746,7 @@ class Field(Component): False) self.rtl_footer.append( - self.process_yaml( + self._process_yaml( Field.templ_dict[str(latch_signal)], {'trigger_signal': trigger_signal, 'path': self.path_underscored, @@ -753,7 +758,6 @@ class Field(Component): return (bit_type, trigger_signal) - def __add_interrupt(self): if self.obj.get_property('intr'): @@ -789,7 +793,7 @@ class Field(Component): if intr_type != InterruptType.level: if self.rst['name']: reset_intr_header = \ - self.process_yaml( + self._process_yaml( Field.templ_dict['rst_intr_header'], {'trigger_signal': trigger_signal, 'rst_name': self.rst['name'], @@ -802,7 +806,7 @@ class Field(Component): reset_intr_header = "" self.rtl_footer.append( - self.process_yaml( + self._process_yaml( Field.templ_dict['always_ff_block_intr'], {'trigger_signal': trigger_signal, 'always_ff_header': self.always_ff_header, @@ -816,7 +820,7 @@ class Field(Component): else: self.access_rtl['hw_write'] = ([ - self.process_yaml( + self._process_yaml( Field.templ_dict['nonsticky_intr'], {'path': self.path_underscored, 'assignment': trigger_signal, @@ -878,7 +882,7 @@ class Field(Component): if enable_mask: enable_mask_start_rtl = \ - self.process_yaml( + self._process_yaml( Field.templ_dict['hw_enable_mask_start'], {'signal': self.get_signal_name(enable_mask), 'width': self.obj.width, @@ -886,7 +890,7 @@ class Field(Component): ) enable_mask_end_rtl = \ - self.process_yaml( + self._process_yaml( Field.templ_dict['hw_enable_mask_end'], {'width': self.obj.width} ) @@ -904,7 +908,7 @@ class Field(Component): self.logger.info(f"Found {sticky} property.") elif self.obj.get_property('counter'): self.access_rtl['hw_write'] = ([ - self.process_yaml( + self._process_yaml( Field.templ_dict['hw_access_counter'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -920,7 +924,7 @@ class Field(Component): # if-line of hw-access self.access_rtl['hw_write'] = ([ - self.process_yaml( + self._process_yaml( Field.templ_dict[write_condition], {'negl': '!' if self.obj.get_property('wel') else '', 'path': self.path_underscored, @@ -948,7 +952,7 @@ class Field(Component): # No special property. Assign input to register assignment = \ - self.process_yaml( + self._process_yaml( Field.templ_dict['hw_access_field__assignment__input'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -957,7 +961,7 @@ class Field(Component): ) self.access_rtl['hw_write'][0].append( - self.process_yaml( + self._process_yaml( Field.templ_dict['hw_access_field'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -975,7 +979,7 @@ class Field(Component): # Check if the hwset or hwclr option is set if self.obj.get_property('hwset'): self.access_rtl['hw_setclr'] = ([ - self.process_yaml( + self._process_yaml( Field.templ_dict['hw_access_hwset'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -990,7 +994,7 @@ class Field(Component): False) elif self.obj.get_property('hwclr'): self.access_rtl['hw_setclr'] = ([ - self.process_yaml( + self._process_yaml( Field.templ_dict['hw_access_hwclr'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -1010,7 +1014,7 @@ class Field(Component): if self.obj.get_property('hw') in (AccessType.rw, AccessType.r): # Connect flops to output port self.rtl_footer.append( - self.process_yaml( + self._process_yaml( Field.templ_dict['out_port_assign'], {'genvars': self.genvars_str, 'path': self.path_underscored, @@ -1038,7 +1042,7 @@ class Field(Component): width = width) ) - self.rtl_footer.append(self.process_yaml( + self.rtl_footer.append(self._process_yaml( Field.templ_dict['external_wr_assignments'], {'path': alias, 'path_wo_field': self.path_wo_field_vec[i], @@ -1053,7 +1057,7 @@ class Field(Component): if self.properties['sw_rd']: for i, alias in enumerate(self.path_underscored_vec): - self.rtl_footer.append(self.process_yaml( + self.rtl_footer.append(self._process_yaml( Field.templ_dict['external_rd_assignments'], {'path': alias, 'path_wo_field': self.path_wo_field_vec[i], @@ -1126,13 +1130,12 @@ class Field(Component): self.rtl_header = [*self.rtl_header, *order_list_rtl] self.rtl_header.append( - self.process_yaml( + self._process_yaml( Field.templ_dict['end_field_ff'], {'path': self.path_underscored} ) ) - def __add_combo(self): operations = [] if self.obj.get_property('anded'): @@ -1144,7 +1147,7 @@ class Field(Component): if len(operations) > 0: self.rtl_footer.append( - self.process_yaml( + self._process_yaml( Field.templ_dict['combo_operation_comment'], {'path': self.path_underscored} ) @@ -1152,7 +1155,7 @@ class Field(Component): self.rtl_footer = [ *self.rtl_footer, - *[self.process_yaml( + *[self._process_yaml( Field.templ_dict[i[1]], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -1161,8 +1164,7 @@ class Field(Component): ) for i in operations] ] - - def __process_fieldtype(self): + def __init_fieldtype(self): try: if not self.config['enums']: raise AttributeError @@ -1226,7 +1228,9 @@ class Field(Component): # the field has a simple width self.field_type = f"logic [{self.obj.width-1}:0]" - def __process_variables(self, obj: FieldNode, array_dimensions: list, glbl_settings: dict): + def __init_variables( + self, + obj: FieldNode): # Create full name self.path_wo_field = '__'.join(self.path.split('.', -1)[0:-1]) self.register_name = ''.join([self.path_underscored, '_q']) @@ -1242,15 +1246,6 @@ class Field(Component): # is always required self.properties['sw_rd_wire'] = self.config['external'] and self.properties['sw_rd'] - # Save dimensions of unpacked dimension - self.array_dimensions = array_dimensions - self.total_array_dimensions = array_dimensions - self.total_dimensions = len(self.total_array_dimensions) - - # Calculate how many genvars shall be added - genvars = [f"[gv_{chr(97+i)}]" for i in range(len(array_dimensions))] - self.genvars_str = ''.join(genvars) - # Write enable self.we_or_wel = self.obj.get_property('we') or self.obj.get_property('wel') @@ -1266,8 +1261,7 @@ class Field(Component): # Determine resets. This includes checking for async/sync resets, # the reset value, and whether the field actually has a reset - self.rst = Field.process_reset_signal( - obj.get_property("resetsignal")) + self.rst = Field.__process_reset_signal(obj.get_property("resetsignal")) if self.rst['name']: self.resets.add(self.rst['name']) @@ -1289,7 +1283,7 @@ class Field(Component): self.access_rtl['else'] = (["else"], False) self.access_rtl[''] = ([''], False) - def summary(self): + def __summary(self): # Additional flags that are set # Use list, rather than set, to ensure the order stays the same # when compiled multiple times @@ -1326,7 +1320,7 @@ class Field(Component): sense_list = 'sense_list_rst' if self.rst['async'] else 'sense_list_no_rst' self.always_ff_header = \ - self.process_yaml( + self._process_yaml( Field.templ_dict[sense_list], {'rst_edge': self.rst['edge'], 'rst_name': self.rst['name']} @@ -1337,7 +1331,7 @@ class Field(Component): # Add actual reset line if self.rst['name']: self.rtl_header.append( - self.process_yaml( + self._process_yaml( Field.templ_dict['rst_field_assign'], {'path': self.path_underscored, 'rst_name': self.rst['name'], @@ -1377,3 +1371,31 @@ class Field(Component): self.logger.error("It's not possible to combine the sticky(bit) "\ "property with the counter property. The counter property "\ "will be ignored.") + + @staticmethod + def __process_reset_signal(reset_signal): + rst = {} + + try: + rst['name'] = reset_signal.inst_name + rst['async'] = reset_signal.get_property("async") + rst['type'] = "asynchronous" if rst['async'] else "synchronous" + + # Active low or active high? + if reset_signal.get_property("activelow"): + rst['edge'] = "negedge" + rst['active'] = "active_low" + else: + rst['edge'] = "posedge" + rst['active'] = "active_high" + except AttributeError: + # Catch if reset_signal does not exist + rst['async'] = False + rst['name'] = None + rst['edge'] = None + rst['value'] = "'x" + rst['active'] = "-" + rst['type'] = "-" + + return rst + diff --git a/srdl2sv/components/memory.py b/srdl2sv/components/memory.py index eef4ce3..242441c 100644 --- a/srdl2sv/components/memory.py +++ b/srdl2sv/components/memory.py @@ -21,13 +21,16 @@ class Memory(Component): self, obj: node.RegfileNode, parents_dimensions: list, - parents_stride: list, - config: dict, - glbl_settings: dict): - super().__init__(obj, config) + parents_strides: list, + config: dict): + super().__init__( + obj=obj, + config=config, + parents_strides=parents_strides, + parents_dimensions=parents_dimensions) # Save and/or process important variables - self.__process_variables(obj, parents_dimensions, parents_stride, glbl_settings) + self._init_variables() # Set object to 0 for easy addressing self.obj.current_idx = [0] @@ -37,7 +40,7 @@ class Memory(Component): # fixed memory block self.rtl_header.append( - self.process_yaml( + self._process_yaml( Memory.templ_dict['memory_adr_assignments'], {'path': self.path_underscored, 'bytes_w': int(self.get_regwidth() / 8), @@ -50,7 +53,7 @@ class Memory(Component): if obj.get_property('sw') in (AccessType.rw, AccessType.r): self.rtl_header.append( - self.process_yaml( + self._process_yaml( Memory.templ_dict['memory_rd_assignments'], {'path': self.path_underscored, 'data_w': self.get_regwidth() - 1, @@ -60,7 +63,7 @@ class Memory(Component): if obj.get_property('sw') in (AccessType.rw, AccessType.w): self.rtl_header.append( - self.process_yaml( + self._process_yaml( Memory.templ_dict['memory_wr_assignments'], {'path': self.path_underscored, 'data_w': self.get_regwidth() - 1, @@ -78,7 +81,7 @@ class Memory(Component): # Create comment and provide user information about register he/she # is looking at. Also add a description, if applicable self.rtl_header = [ - self.process_yaml( + self._process_yaml( self.templ_dict['mem_comment'], {'inst_name': obj.inst_name, 'type_name': obj.type_name, @@ -91,26 +94,20 @@ class Memory(Component): *self.rtl_header ] - def __process_variables(self, - obj: node.RegfileNode, - parents_dimensions: list, - parents_stride: list, - glbl_settings: dict): - - self.mementries = obj.get_property('mementries') - self.memwidth = obj.get_property('memwidth') + def _init_variables(self): + self.mementries = self.obj.get_property('mementries') + self.memwidth = self.obj.get_property('memwidth') self.addr_w = self.mementries.bit_length() + + def sanity_checks(self): if not math.log2(self.memwidth).is_integer(): self.logger.fatal( "The defined memory width must be a power of 2. "\ f"it is now defined as '{self.memwidth}'") sys.exit(1) # Determine dimensions of register - if obj.is_array: - self.total_array_dimensions = [*parents_dimensions, *self.obj.array_dimensions] - self.array_dimensions = self.obj.array_dimensions - + if self.obj.is_array: self.logger.warning("The memory is defined as array. The compiler not not "\ "provide any hooks to help here and expects that the user "\ "handles this outside of the memory block.") @@ -122,29 +119,21 @@ class Memory(Component): f"{int(self.mementries * self.memwidth / 8)}). This must be "\ "kept in mind when hooking up the memory interface to an "\ "external memory block.") - else: - self.total_array_dimensions = parents_dimensions - self.array_dimensions = [] - self.total_stride = parents_stride - - self.total_dimensions = len(self.total_array_dimensions) - self.depth = '[{}]'.format(']['.join(f"{i}" for i in self.array_dimensions)) - self.dimensions = len(self.array_dimensions) def __add_sw_mux_assignments(self): # Create list of mux-inputs to later be picked up by carrying addrmap self.sw_mux_assignment_var_name = \ SWMuxEntry ( - data_wire = self.process_yaml( + data_wire = self._process_yaml( Memory.templ_dict['sw_data_assignment_var_name'], {'path': self.path_underscored, 'accesswidth': self.memwidth - 1} ), - rdy_wire = self.process_yaml( + rdy_wire = self._process_yaml( Memory.templ_dict['sw_rdy_assignment_var_name'], {'path': self.path_underscored} ), - err_wire = self.process_yaml( + err_wire = self._process_yaml( Memory.templ_dict['sw_err_assignment_var_name'], {'path': self.path_underscored} ), @@ -159,7 +148,7 @@ class Memory(Component): access_type = 'sw_data_assignment_wo' self.rtl_footer = [ - self.process_yaml( + self._process_yaml( self.templ_dict[access_type], {'path': self.path_underscored, 'sw_data_assignment_var_name': self.sw_mux_assignment_var_name.data_wire, @@ -178,9 +167,6 @@ class Memory(Component): ) ) - def get_regwidth(self) -> int: - return self.memwidth - def __add_signal_instantiations(self): # Add wire/register instantiations self.rtl_header = [ @@ -204,3 +190,6 @@ class Memory(Component): [str(y) for y in value[1]])) if value[1] else '') for (key, value) in dict_list] + + def get_regwidth(self) -> int: + return self.memwidth diff --git a/srdl2sv/components/regfile.py b/srdl2sv/components/regfile.py index 4be7578..2202fb3 100644 --- a/srdl2sv/components/regfile.py +++ b/srdl2sv/components/regfile.py @@ -3,6 +3,8 @@ import sys import math import yaml +from typing import Optional + from systemrdl import node from systemrdl.node import FieldNode @@ -21,15 +23,15 @@ class RegFile(Component): def __init__( self, obj: node.RegfileNode, - parents_dimensions: list, - parents_stride: list, - config: dict, + config: dict, + parents_dimensions: Optional[list], + parents_strides: Optional[list], glbl_settings: dict): - super().__init__(obj, config) - - # Save and/or process important variables - self.__process_variables(obj, parents_dimensions, parents_stride) - + super().__init__( + obj=obj, + config=config, + parents_strides=parents_strides, + parents_dimensions=parents_dimensions) # Empty dictionary of register objects # We need a dictionary since it might be required to access the objects later @@ -41,7 +43,7 @@ class RegFile(Component): self.obj.current_idx = [0] # Determine whether this regfile must add a generate block and for-loop - if self.dimensions and not glbl_settings['generate_active']: + if self.own_dimensions and not glbl_settings['generate_active']: self.generate_initiated = True glbl_settings['generate_active'] = True else: @@ -60,11 +62,11 @@ class RegFile(Component): self.obj.current_idx = [0] new_child = RegFile( - child, - self.total_array_dimensions, - self.total_stride, - config, - glbl_settings) + obj=child, + parents_dimensions=self.total_array_dimensions, + parents_strides=self.total_stride, + config=config, + glbl_settings=glbl_settings) self.regfiles[child.inst_name] = new_child elif isinstance(child, node.RegNode): if child.inst.is_alias: @@ -76,11 +78,11 @@ class RegFile(Component): else: self.obj.current_idx = [0] new_child = Register( - child, - self.total_array_dimensions, - self.total_stride, - config, - glbl_settings) + obj=child, + parents_dimensions=self.total_array_dimensions, + parents_strides=self.total_stride, + config=config, + glbl_settings=glbl_settings) self.registers[child.inst_name] = new_child try: @@ -115,30 +117,30 @@ class RegFile(Component): # Create comment and provide user information about register he/she # is looking at. self.rtl_header = [ - self.process_yaml( + self._process_yaml( RegFile.templ_dict['regfile_comment'], {'name': obj.inst_name, - 'dimensions': self.dimensions, - 'depth': self.depth} + 'dimensions': self.own_dimensions, + 'depth': self.own_depth} ), *self.rtl_header ] # Create generate block for register and add comment - for i in range(self.dimensions-1, -1, -1): + for i in range(self.own_dimensions-1, -1, -1): self.rtl_footer.append( - self.process_yaml( + self._process_yaml( RegFile.templ_dict['generate_for_end'], {'dimension': ''.join(['gv_', chr(97+i)])} ) ) - for i in range(self.dimensions): + for i in range(self.own_dimensions): self.rtl_header.append( - self.process_yaml( + self._process_yaml( RegFile.templ_dict['generate_for_start'], {'iterator': ''.join(['gv_', chr(97+i+self.parents_depths)]), - 'limit': self.array_dimensions[i]} + 'limit': self.own_array_dimensions[i]} ) ) @@ -148,82 +150,42 @@ class RegFile(Component): self.rtl_footer.append("endgenerate") self.rtl_footer.append("") - def __process_variables(self, - obj: node.RegfileNode, - parents_dimensions: list, - parents_stride: list): - - # Determine dimensions of register - if obj.is_array: - self.sel_arr = 'array' - self.total_array_dimensions = [*parents_dimensions, *self.obj.array_dimensions] - self.array_dimensions = self.obj.array_dimensions - - # Merge parent's stride with stride of this regfile. Before doing so, the - # respective stride of the different dimensions shall be calculated - self.total_stride = [ - *parents_stride, - *[math.prod(self.array_dimensions[i+1:]) - *self.obj.array_stride - for i, _ in enumerate(self.array_dimensions)] - ] - else: - self.sel_arr = 'single' - self.total_array_dimensions = parents_dimensions - self.array_dimensions = [] - self.total_stride = parents_stride - - # How many dimensions were already part of some higher up hierarchy? - self.parents_depths = len(parents_dimensions) - - self.total_depth = '[{}]'.format(']['.join(f"{i}" for i in self.total_array_dimensions)) - self.total_dimensions = len(self.total_array_dimensions) - - self.depth = '[{}]'.format(']['.join(f"{i}" for i in self.array_dimensions)) - self.dimensions = len(self.array_dimensions) - - # Calculate how many genvars shall be added - genvars = ['[gv_{}]'.format(chr(97+i)) for i in range(self.dimensions)] - self.genvars_str = ''.join(genvars) - def create_mux_string(self): for i in self.children.values(): yield from i.create_mux_string() def get_signal_instantiations_list(self) -> set(): - instantiations = list() + instantiations = [] - for i in self.children.values(): - if isinstance(i, Register): - instantiations.append("\n// Variables of register '{}'".format(i.name)) - instantiations = [*instantiations, *i.get_signal_instantiations_list()] + for child in self.children.values(): + if isinstance(child, Register): + instantiations.append(f"\n// Variables of register '{child.name}'") + instantiations = [*instantiations, *child.get_signal_instantiations_list()] return instantiations def get_package_names(self) -> set(): names = set() - for i in self.registers.values(): - for key, value in i.get_typedefs().items(): - names.add(value.scope) + for register in self.registers.values(): + for typedef in register.get_typedefs().values(): + names.add(typedef.scope) return names - def get_package_rtl(self) -> dict(): + def get_package_rtl(self) -> {}: if not self.config['enums']: return None # First go through all registers in this scope to generate a package - package_rtl = [] enum_rtl = {} - rtl_return = [] # Need to keep track of enum names since they shall be unique # per scope enum_members = {} - for i in self.registers.values(): - for key, value in i.get_typedefs().items(): + for register in self.registers.values(): + for key, value in register.get_typedefs().items(): if value.scope not in enum_rtl: enum_rtl[value.scope] = [] @@ -237,18 +199,15 @@ class RegFile(Component): enum_members[var[0]] = "::".join([self.name, key]) else: self.logger.fatal( - "Enum member '{}' was found at multiple locations in the same "\ + f"Enum member '{var[0]}' was found at multiple locations in the same "\ "main scope: \n"\ - " -- 1st occurance: '{}'\n"\ - " -- 2nd occurance: '{}'\n\n"\ + f" -- 1st occurance: '{enum_members[var[0]]}'\n"\ + f" -- 2nd occurance: '{'::'.join([self.name, key])}'\n\n"\ "This is not legal because all these enums will be defined "\ "in the same SystemVerilog scope. To share the same enum among "\ "different registers, define them on a higher level in the "\ "hierarchy.\n\n"\ - "Exiting...".format( - var[0], - enum_members[var[0]], - "::".join([value.scope, key]))) + "Exiting...") sys.exit(1) @@ -266,6 +225,3 @@ class RegFile(Component): enum_var_list = ',\n'.join(variable_list))) return enum_rtl - - def get_regwidth(self) -> int: - return self.regwidth diff --git a/srdl2sv/components/register.py b/srdl2sv/components/register.py index 33c4040..ee5ea0c 100644 --- a/srdl2sv/components/register.py +++ b/srdl2sv/components/register.py @@ -1,6 +1,6 @@ import importlib.resources as pkg_resources -import math import sys +from typing import Optional import yaml from systemrdl import node @@ -19,27 +19,31 @@ class Register(Component): def __init__( self, obj: node.RegNode, - parents_dimensions: list, - parents_stride: list, config: dict, + parents_dimensions: Optional[list], + parents_strides: Optional[list], glbl_settings: dict): - super().__init__(obj, config) + super().__init__( + obj=obj, + config=config, + parents_strides=parents_strides, + parents_dimensions=parents_dimensions) - # Save and/or process important variables - self.__process_variables(obj, parents_dimensions, parents_stride, glbl_settings) + # Generate all variables that have anything to do with dimensions or strides + self.__init_genvars() - self.config['external'] = obj.external + # Initialize all other variables + self.__init_variables(glbl_settings) # Create RTL for fields of initial, non-alias register - for field in obj.fields(): + for field in self.obj.fields(): # Use range to save field in an array. Reason is, names are allowed to # change when using an alias field_range = ':'.join(map(str, [field.msb, field.lsb])) self.children[field_range] = Field(field, self.total_array_dimensions, - self.config, - glbl_settings) + self.config) # Get properties from field that apply to whole register for key in self.properties: @@ -58,15 +62,15 @@ class Register(Component): child.create_internal_rtl() # Create generate block for register and add comment - if self.dimensions and not self.generate_active: + if self.own_dimensions and not self.generate_active: self.rtl_header.append("generate") # Add N layers of for-loop starts - for i in range(self.dimensions): + for i in range(self.own_dimensions): self.rtl_header.append( Register.templ_dict['generate_for_start'].format( iterator = ''.join(['gv_', chr(97+i+self.parents_depths)]), - limit = self.array_dimensions[i])) + limit = self.own_array_dimensions[i])) # Add decoders for all registers & aliases self.__add_address_decoder() @@ -80,12 +84,12 @@ class Register(Component): self.__add_sw_mux_assignments() # Add N layers of for-loop end - for i in range(self.dimensions-1, -1, -1): + for i in range(self.own_dimensions-1, -1, -1): self.rtl_footer.append( Register.templ_dict['generate_for_end'].format( dimension = ''.join(['gv_', chr(97+i)]))) - if self.dimensions and not self.generate_active: + if self.own_dimensions and not self.generate_active: self.rtl_footer.append("\nendgenerate\n") # Add wire instantiation @@ -104,8 +108,8 @@ class Register(Component): self.rtl_header = [ Register.templ_dict['reg_comment'].format( name = self.obj.inst_name, - dimensions = self.dimensions, - depth = self.depth), + dimensions = self.own_dimensions, + depth = self.own_depth), *self.rtl_header ] @@ -121,7 +125,7 @@ class Register(Component): self.rtl_footer.append(Register.templ_dict['interrupt_comment']['rtl']) self.rtl_footer.append( - self.process_yaml( + self._process_yaml( Register.templ_dict['interrupt_intr'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -133,7 +137,7 @@ class Register(Component): if self.properties['halt']: self.rtl_footer.append( - self.process_yaml( + self._process_yaml( Register.templ_dict['interrupt_halt'], {'path': self.path_underscored, 'genvars': self.genvars_str, @@ -189,16 +193,16 @@ class Register(Component): # Create list of mux-inputs to later be picked up by carrying addrmap self.sw_mux_assignment_var_name.append( SWMuxEntry( - data_wire = self.process_yaml( + data_wire = self._process_yaml( Register.templ_dict['sw_data_assignment_var_name'], {'path': na_map[0], 'accesswidth': accesswidth} ), - rdy_wire = self.process_yaml( + rdy_wire = self._process_yaml( Register.templ_dict['sw_rdy_assignment_var_name'], {'path': na_map[0]} ), - err_wire = self.process_yaml( + err_wire = self._process_yaml( Register.templ_dict['sw_err_assignment_var_name'], {'path': na_map[0]} ), @@ -216,7 +220,7 @@ class Register(Component): sw_err_condition_vec = [] - sw_err_condition_vec.append(self.process_yaml( + sw_err_condition_vec.append(self._process_yaml( Register.templ_dict['sw_err_condition'], {'rd_byte_list_ored': ' || '.join(bytes_read_format) if bytes_read else "1'b0", @@ -228,7 +232,7 @@ class Register(Component): if self.config['external']: if bytes_read: for field in self.children.values(): - sw_err_condition_vec.append(self.process_yaml( + sw_err_condition_vec.append(self._process_yaml( Register.templ_dict['external_err_condition'], {'path': '__'.join([na_map[0], field.name]), 'genvars': self.genvars_str, @@ -238,7 +242,7 @@ class Register(Component): if bytes_written: for field in self.children.values(): - sw_err_condition_vec.append(self.process_yaml( + sw_err_condition_vec.append(self._process_yaml( Register.templ_dict['external_err_condition'], {'path': '__'.join([na_map[0], field.name]), 'genvars': self.genvars_str, @@ -255,7 +259,7 @@ class Register(Component): sw_rdy_condition_vec = ['('] for field in self.children.values(): - sw_rdy_condition_vec.append(self.process_yaml( + sw_rdy_condition_vec.append(self._process_yaml( Register.templ_dict['external_rdy_condition'], {'path': '__'.join([na_map[0], field.name]), 'genvars': self.genvars_str, @@ -275,7 +279,7 @@ class Register(Component): sw_rdy_condition_vec.append('(') for field in self.children.values(): - sw_rdy_condition_vec.append(self.process_yaml( + sw_rdy_condition_vec.append(self._process_yaml( Register.templ_dict['external_rdy_condition'], {'path': '__'.join([na_map[0], field.name]), 'genvars': self.genvars_str, @@ -294,7 +298,7 @@ class Register(Component): # Assign all values self.rtl_footer.append( - self.process_yaml( + self._process_yaml( Register.templ_dict['sw_data_assignment'], {'sw_data_assignment_var_name': self.sw_mux_assignment_var_name[-1].data_wire, 'sw_rdy_assignment_var_name': self.sw_mux_assignment_var_name[-1].rdy_wire, @@ -313,7 +317,7 @@ class Register(Component): if self.total_array_dimensions: vec = [0]*len(self.total_array_dimensions) - for dimension in Register.eval_genvars(vec, 0, self.total_array_dimensions): + for dimension in Register.__eval_genvars(vec, 0, self.total_array_dimensions): yield ( SWMuxEntryDimensioned( mux_entry = mux_entry, @@ -329,21 +333,18 @@ class Register(Component): ) @staticmethod - def eval_genvars(vec, depth, dimensions): + def __eval_genvars(vec, depth, dimensions): for i in range(dimensions[depth]): vec[depth] = i if depth == len(dimensions) - 1: yield f"[{']['.join(map(str, vec))}]" else: - yield from Register.eval_genvars(vec, depth+1, dimensions) + yield from Register.__eval_genvars(vec, depth+1, dimensions) vec[depth] = 0 def __add_address_decoder(self): - # Assign variables from bus - self.obj.current_idx = [0] - if self.total_dimensions: access_wire_assign_field = 'access_wire_assign_multi_dim' else: @@ -351,7 +352,7 @@ class Register(Component): for i, name_addr_map in enumerate(self.name_addr_mappings): self.rtl_header.append( - self.process_yaml( + self._process_yaml( Register.templ_dict['access_wire_comment'], {'path': name_addr_map[0], 'alias': '(alias)' if i > 0 else '', @@ -360,13 +361,13 @@ class Register(Component): ) self.rtl_header.append( - self.process_yaml( + self._process_yaml( Register.templ_dict[access_wire_assign_field], {'path': name_addr_map[0], 'addr': name_addr_map[1], 'genvars': self.genvars_str, 'genvars_sum': self.genvars_sum_str, - 'depth': self.depth, + 'depth': self.own_depth, } ) ) @@ -377,19 +378,19 @@ class Register(Component): # that is tied to 1'b0 if self.properties['sw_rd']: self.rtl_header.append( - self.process_yaml( + self._process_yaml( Register.templ_dict['read_wire_assign'], {'path': name_addr_map[0], 'addr': name_addr_map[1], 'genvars': self.genvars_str, 'genvars_sum': self.genvars_sum_str, - 'depth': self.depth, + 'depth': self.own_depth, } ) ) else: self.rtl_header.append( - self.process_yaml( + self._process_yaml( Register.templ_dict['read_wire_assign_0'], {'path': name_addr_map[0], 'genvars': self.genvars_str, @@ -403,19 +404,19 @@ class Register(Component): # that is tied to 1'b0 if self.properties['sw_wr']: self.rtl_header.append( - self.process_yaml( + self._process_yaml( Register.templ_dict['write_wire_assign'], {'path': name_addr_map[0], 'addr': name_addr_map[1], 'genvars': self.genvars_str, 'genvars_sum': self.genvars_sum_str, - 'depth': self.depth, + 'depth': self.own_depth, } ) ) else: self.rtl_header.append( - self.process_yaml( + self._process_yaml( Register.templ_dict['write_wire_assign_0'], {'path': name_addr_map[0], 'genvars': self.genvars_str, @@ -426,7 +427,7 @@ class Register(Component): # Add combined signal to be used for general access of the register if self.properties['swacc']: self.rtl_header.append( - self.process_yaml( + self._process_yaml( Register.templ_dict['rw_wire_assign_any_alias'], {'path': self.name_addr_mappings[0][0], 'genvars': self.genvars_str, @@ -484,27 +485,21 @@ class Register(Component): sys.exit(1) # Add name to list - self.obj.current_idx = [0] self.name_addr_mappings.append( (self.create_underscored_path_static(obj)[3], obj.absolute_address)) - def __process_variables( - self, - obj: node.RegNode, - parents_dimensions: list, - parents_stride: list, - glbl_settings: dict): - - # Save name + def __init_variables(self, glbl_settings: dict): self.obj.current_idx = [0] - self.name = obj.inst_name # Save global settings self.glbl_settings = glbl_settings + # Is this an external register? + self.config['external'] = self.obj.external + # Create mapping between (alias-) name and address self.name_addr_mappings = [ - (self.create_underscored_path_static(obj)[3], obj.absolute_address) + (self.create_underscored_path_static(self.obj)[3], self.obj.absolute_address) ] # Geneate already started? @@ -513,42 +508,11 @@ class Register(Component): # Empty array for mux-input signals self.sw_mux_assignment_var_name = [] - # Determine dimensions of register - if obj.is_array: - self.sel_arr = 'array' - self.total_array_dimensions = [*parents_dimensions, *self.obj.array_dimensions] - self.array_dimensions = self.obj.array_dimensions - - # Merge parent's stride with stride of this regfile. Before doing so, the - # respective stride of the different dimensions shall be calculated - self.total_stride = [ - *parents_stride, - *[math.prod(self.array_dimensions[i+1:]) - *self.obj.array_stride - for i, _ in enumerate(self.array_dimensions)] - ] - else: - self.sel_arr = 'single' - self.total_array_dimensions = parents_dimensions - self.array_dimensions = [] - self.total_stride = parents_stride - - # How many dimensions were already part of some higher up hierarchy? - self.parents_depths = len(parents_dimensions) - - self.total_depth = '[{}]'.format(']['.join(f"{i}" for i in self.total_array_dimensions)) - self.total_dimensions = len(self.total_array_dimensions) - - self.depth = '[{}]'.format(']['.join(f"{i}" for i in self.array_dimensions)) - self.dimensions = len(self.array_dimensions) - - # Calculate how many genvars shall be added - genvars = [f"[gv_{chr(97+i)}]" for i in range(self.total_dimensions)] - self.genvars_str = ''.join(genvars) + def __init_genvars(self): + super()._init_genvars() # Determine value to compare address with genvars_sum = [] - genvars_sum_vectorized = [] try: for i, stride in enumerate(self.total_stride): genvars_sum.append(''.join(['gv_', chr(97+i)])) @@ -556,14 +520,7 @@ class Register(Component): genvars_sum.append(str(stride)) genvars_sum.append("+") - genvars_sum_vectorized.append('vec[') - genvars_sum_vectorized.append(str(i)) - genvars_sum_vectorized.append(']*') - genvars_sum_vectorized.append(str(stride)) - genvars_sum_vectorized.append("+") - genvars_sum.pop() - genvars_sum_vectorized.pop() self.logger.debug( f"Multidimensional with dimensions '{self.total_array_dimensions}' " @@ -577,7 +534,6 @@ class Register(Component): "Caugt expected IndexError because genvars_sum is empty") self.genvars_sum_str = ''.join(genvars_sum) - self.genvars_sum_str_vectorized = ''.join(genvars_sum_vectorized) def get_regwidth(self) -> int: return self.obj.get_property('regwidth')