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
This commit is contained in:
Dennis Potter 2021-10-24 00:07:59 -07:00
parent 20cec0c2a3
commit ec02290bbe
Signed by: Dennis
GPG Key ID: 186A8AD440942BAF
6 changed files with 345 additions and 366 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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')