mirror of
https://github.com/Silicon1602/srdl2sv.git
synced 2024-12-22 15:08:39 +00:00
Add regfile capabilities
Apart from adding regfiles in general (which is mostly a combination of addrmap and register code), the stride/array_dimension code had to be revisted to be correct for multi dimensional arrays with multi dimensional registers. Lastly, the logger instantiation has been moved to the __init__() method of `Component`.
This commit is contained in:
parent
2a3cc9505e
commit
8a82d37737
@ -2,11 +2,12 @@ import re
|
|||||||
import importlib.resources as pkg_resources
|
import importlib.resources as pkg_resources
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from systemrdl import RDLCompiler, RDLCompileError, RDLWalker, RDLListener, node
|
from systemrdl import node
|
||||||
from systemrdl.node import FieldNode
|
from systemrdl.node import FieldNode
|
||||||
|
|
||||||
# Local packages
|
# Local packages
|
||||||
from components.component import Component
|
from components.component import Component
|
||||||
|
from components.regfile import RegFile
|
||||||
from components.register import Register
|
from components.register import Register
|
||||||
from . import templates
|
from . import templates
|
||||||
|
|
||||||
@ -18,17 +19,12 @@ class AddrMap(Component):
|
|||||||
Loader=yaml.FullLoader)
|
Loader=yaml.FullLoader)
|
||||||
|
|
||||||
def __init__(self, obj: node.RootNode, config: dict):
|
def __init__(self, obj: node.RootNode, config: dict):
|
||||||
super().__init__()
|
super().__init__(obj, config)
|
||||||
|
|
||||||
# Save and/or process important variables
|
|
||||||
self.__process_variables(obj)
|
|
||||||
|
|
||||||
# Create logger object
|
# Create logger object
|
||||||
self.create_logger(self.path, config)
|
self.create_logger(self.path, config)
|
||||||
self.logger.debug('Starting to process addrmap')
|
self.logger.debug('Starting to process addrmap')
|
||||||
|
|
||||||
template = pkg_resources.read_text(templates, 'addrmap.sv')
|
|
||||||
|
|
||||||
# Check if global resets are defined
|
# Check if global resets are defined
|
||||||
glbl_settings = dict()
|
glbl_settings = dict()
|
||||||
|
|
||||||
@ -48,7 +44,7 @@ class AddrMap(Component):
|
|||||||
self.logger.info('Found hierarchical addrmap. Entering it...')
|
self.logger.info('Found hierarchical addrmap. Entering it...')
|
||||||
self.logger.error('Child addrmaps are not implemented yet!')
|
self.logger.error('Child addrmaps are not implemented yet!')
|
||||||
elif isinstance(child, node.RegfileNode):
|
elif isinstance(child, node.RegfileNode):
|
||||||
self.logger.error('Regfiles are not implemented yet!')
|
self.children.append(RegFile(child, [], [], config, glbl_settings))
|
||||||
elif isinstance(child, node.RegNode):
|
elif isinstance(child, node.RegNode):
|
||||||
if child.inst.is_alias:
|
if child.inst.is_alias:
|
||||||
# If the node we found is an alias, we shall not create a
|
# If the node we found is an alias, we shall not create a
|
||||||
@ -57,15 +53,19 @@ class AddrMap(Component):
|
|||||||
self.logger.error('Alias registers are not implemented yet!')
|
self.logger.error('Alias registers are not implemented yet!')
|
||||||
else:
|
else:
|
||||||
self.registers[child.inst_name] = \
|
self.registers[child.inst_name] = \
|
||||||
Register(child, config, glbl_settings)
|
Register(child, [], [], config, glbl_settings)
|
||||||
|
|
||||||
# Add regfiles and registers to children
|
# Add registers to children. This must be done in a last step
|
||||||
self.children = [x for x in self.registers.values()]
|
# to account for all possible alias combinations
|
||||||
|
self.children = [
|
||||||
|
*self.children,
|
||||||
|
*[x for x in self.registers.values()]
|
||||||
|
]
|
||||||
|
|
||||||
self.logger.info("Done generating all child-regfiles/registers")
|
self.logger.info("Done generating all child-regfiles/registers")
|
||||||
|
|
||||||
# Start assembling addrmap module
|
# Start assembling addrmap module
|
||||||
self.logger.info("Starting to assemble input/output/inout ports")
|
self.logger.info("Starting to assemble input & output ports")
|
||||||
|
|
||||||
# Reset ports
|
# Reset ports
|
||||||
reset_ports_rtl = [
|
reset_ports_rtl = [
|
||||||
@ -124,25 +124,11 @@ class AddrMap(Component):
|
|||||||
|
|
||||||
self.rtl_header.append(
|
self.rtl_header.append(
|
||||||
AddrMap.templ_dict['module_declaration'].format(
|
AddrMap.templ_dict['module_declaration'].format(
|
||||||
name = obj.inst_name,
|
name = self.name,
|
||||||
resets = '\n'.join(reset_ports_rtl),
|
resets = '\n'.join(reset_ports_rtl),
|
||||||
inputs = '\n'.join(input_ports_rtl),
|
inputs = '\n'.join(input_ports_rtl),
|
||||||
outputs = '\n'.join(output_ports_rtl)))
|
outputs = '\n'.join(output_ports_rtl)))
|
||||||
|
|
||||||
def __process_variables(self, obj: node.RootNode):
|
|
||||||
# Save object
|
|
||||||
self.obj = obj
|
|
||||||
|
|
||||||
# Create full name
|
|
||||||
self.owning_addrmap = obj.owning_addrmap.inst_name
|
|
||||||
self.path = obj.get_path()\
|
|
||||||
.replace('[]', '')\
|
|
||||||
.replace('{}.'.format(self.owning_addrmap), '')
|
|
||||||
|
|
||||||
self.path_underscored = self.path.replace('.', '_')
|
|
||||||
|
|
||||||
self.name = obj.inst_name
|
|
||||||
|
|
||||||
def __process_global_resets(self):
|
def __process_global_resets(self):
|
||||||
field_reset_list = \
|
field_reset_list = \
|
||||||
[x for x in self.obj.signals() if x.get_property('field_reset')]
|
[x for x in self.obj.signals() if x.get_property('field_reset')]
|
||||||
|
@ -12,7 +12,7 @@ class TypeDef(NamedTuple):
|
|||||||
members: tuple
|
members: tuple
|
||||||
|
|
||||||
class Component():
|
class Component():
|
||||||
def __init__(self):
|
def __init__(self, obj, config):
|
||||||
self.rtl_header = []
|
self.rtl_header = []
|
||||||
self.rtl_footer = []
|
self.rtl_footer = []
|
||||||
self.children = []
|
self.children = []
|
||||||
@ -24,6 +24,19 @@ class Component():
|
|||||||
self.ports['output'] = dict()
|
self.ports['output'] = dict()
|
||||||
self.field_type = ''
|
self.field_type = ''
|
||||||
|
|
||||||
|
# Save object
|
||||||
|
self.obj = obj
|
||||||
|
|
||||||
|
# Save name
|
||||||
|
self.name = obj.inst_name
|
||||||
|
|
||||||
|
# Create path
|
||||||
|
self.create_underscored_path()
|
||||||
|
|
||||||
|
# Create logger object
|
||||||
|
self.create_logger("{}.{}".format(self.owning_addrmap, self.path), config)
|
||||||
|
self.logger.debug('Starting to process register "{}"'.format(obj.inst_name))
|
||||||
|
|
||||||
def create_logger(self, name: str, config: dict):
|
def create_logger(self, name: str, config: dict):
|
||||||
self.logger = create_logger(
|
self.logger = create_logger(
|
||||||
"{}".format(name),
|
"{}".format(name),
|
||||||
@ -121,7 +134,7 @@ class Component():
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def split_dimensions(path: str):
|
def split_dimensions(path: str):
|
||||||
re_dimensions = re.compile('(\[[^]]\])')
|
re_dimensions = re.compile('(\[[^]]*\])')
|
||||||
new_path = re_dimensions.sub('', path)
|
new_path = re_dimensions.sub('', path)
|
||||||
return (new_path, ''.join(re_dimensions.findall(path)))
|
return (new_path, ''.join(re_dimensions.findall(path)))
|
||||||
|
|
||||||
@ -159,7 +172,7 @@ class Component():
|
|||||||
for x in yaml_obj['signals']:
|
for x in yaml_obj['signals']:
|
||||||
self.signals[x['name'].format(path = self.path_underscored)] =\
|
self.signals[x['name'].format(path = self.path_underscored)] =\
|
||||||
(x['signal_type'].format(field_type = self.field_type),
|
(x['signal_type'].format(field_type = self.field_type),
|
||||||
self.array_dimensions)
|
self.total_array_dimensions)
|
||||||
except (TypeError, KeyError):
|
except (TypeError, KeyError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -167,7 +180,7 @@ class Component():
|
|||||||
for x in yaml_obj['input_ports']:
|
for x in yaml_obj['input_ports']:
|
||||||
self.ports['input'][x['name'].format(path = self.path_underscored)] =\
|
self.ports['input'][x['name'].format(path = self.path_underscored)] =\
|
||||||
(x['signal_type'].format(field_type = self.field_type),
|
(x['signal_type'].format(field_type = self.field_type),
|
||||||
self.array_dimensions)
|
self.total_array_dimensions)
|
||||||
except (TypeError, KeyError):
|
except (TypeError, KeyError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -175,7 +188,7 @@ class Component():
|
|||||||
for x in yaml_obj['output_ports']:
|
for x in yaml_obj['output_ports']:
|
||||||
self.ports['output'][x['name'].format(path = self.path_underscored)] =\
|
self.ports['output'][x['name'].format(path = self.path_underscored)] =\
|
||||||
(x['signal_type'].format(field_type = self.field_type),
|
(x['signal_type'].format(field_type = self.field_type),
|
||||||
self.array_dimensions)
|
self.total_array_dimensions)
|
||||||
except (TypeError, KeyError):
|
except (TypeError, KeyError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -204,3 +217,11 @@ class Component():
|
|||||||
rst['type'] = "-"
|
rst['type'] = "-"
|
||||||
|
|
||||||
return rst
|
return rst
|
||||||
|
|
||||||
|
def create_underscored_path(self):
|
||||||
|
self.owning_addrmap = self.obj.owning_addrmap.inst_name
|
||||||
|
self.full_path = Component.split_dimensions(self.obj.get_path())[0]
|
||||||
|
self.path = self.full_path\
|
||||||
|
.replace('{}.'.format(self.owning_addrmap), '')
|
||||||
|
|
||||||
|
self.path_underscored = self.path.replace('.', '__')
|
||||||
|
@ -16,16 +16,17 @@ class Field(Component):
|
|||||||
pkg_resources.read_text(templates, 'fields.yaml'),
|
pkg_resources.read_text(templates, 'fields.yaml'),
|
||||||
Loader=yaml.FullLoader)
|
Loader=yaml.FullLoader)
|
||||||
|
|
||||||
def __init__(self, obj: FieldNode, array_dimensions: list, config:dict, glbl_settings: dict):
|
def __init__(
|
||||||
super().__init__()
|
self,
|
||||||
|
obj: FieldNode,
|
||||||
|
array_dimensions: list,
|
||||||
|
config:dict,
|
||||||
|
glbl_settings: dict):
|
||||||
|
super().__init__(obj, config)
|
||||||
|
|
||||||
# Save and/or process important variables
|
# Save and/or process important variables
|
||||||
self.__process_variables(obj, array_dimensions, glbl_settings)
|
self.__process_variables(obj, array_dimensions, glbl_settings)
|
||||||
|
|
||||||
# Create logger object
|
|
||||||
self.create_logger("{}.{}".format(self.owning_addrmap, self.path), config)
|
|
||||||
self.logger.debug('Starting to process field "{}"'.format(obj.inst_name))
|
|
||||||
|
|
||||||
# Determine field types
|
# Determine field types
|
||||||
self.__process_fieldtype()
|
self.__process_fieldtype()
|
||||||
|
|
||||||
@ -137,21 +138,12 @@ class Field(Component):
|
|||||||
self.field_type = 'logic'
|
self.field_type = 'logic'
|
||||||
|
|
||||||
def __process_variables(self, obj: FieldNode, array_dimensions: list, glbl_settings: dict):
|
def __process_variables(self, obj: FieldNode, array_dimensions: list, glbl_settings: dict):
|
||||||
# Save object
|
|
||||||
self.obj = obj
|
|
||||||
|
|
||||||
# Create full name
|
# Create full name
|
||||||
self.owning_addrmap = obj.owning_addrmap.inst_name
|
|
||||||
self.full_path = obj.get_path().replace('[]', '')
|
|
||||||
self.path = self.full_path\
|
|
||||||
.replace('[]', '')\
|
|
||||||
.replace('{}.'.format(self.owning_addrmap), '')
|
|
||||||
|
|
||||||
self.path_underscored = self.path.replace('.', '_')
|
|
||||||
self.path_wo_field = '.'.join(self.path.split('.', -1)[0:-1])
|
self.path_wo_field = '.'.join(self.path.split('.', -1)[0:-1])
|
||||||
|
|
||||||
# Save dimensions of unpacked dimension
|
# Save dimensions of unpacked dimension
|
||||||
self.array_dimensions = array_dimensions
|
self.array_dimensions = array_dimensions
|
||||||
|
self.total_array_dimensions = array_dimensions
|
||||||
|
|
||||||
# Calculate how many genvars shall be added
|
# Calculate how many genvars shall be added
|
||||||
genvars = ['[{}]'.format(chr(97+i)) for i in range(len(array_dimensions))]
|
genvars = ['[{}]'.format(chr(97+i)) for i in range(len(array_dimensions))]
|
||||||
@ -170,7 +162,7 @@ class Field(Component):
|
|||||||
|
|
||||||
reset_signal = obj.get_property("resetsignal")
|
reset_signal = obj.get_property("resetsignal")
|
||||||
|
|
||||||
if (reset_signal):
|
if reset_signal:
|
||||||
self.rst = Field.process_reset_signal(reset_signal)
|
self.rst = Field.process_reset_signal(reset_signal)
|
||||||
else:
|
else:
|
||||||
# Only use global reset (if present) if no local reset is set
|
# Only use global reset (if present) if no local reset is set
|
||||||
@ -180,7 +172,7 @@ class Field(Component):
|
|||||||
|
|
||||||
# Value of reset must always be determined on field level
|
# Value of reset must always be determined on field level
|
||||||
self.rst['value'] = \
|
self.rst['value'] = \
|
||||||
'\'x' if obj.get_property("reset") == None else\
|
'\'x' if not obj.get_property("reset") else\
|
||||||
obj.get_property('reset')
|
obj.get_property('reset')
|
||||||
|
|
||||||
# Define hardware access
|
# Define hardware access
|
||||||
@ -201,7 +193,7 @@ class Field(Component):
|
|||||||
# Add comment with summary on field's properties
|
# Add comment with summary on field's properties
|
||||||
return \
|
return \
|
||||||
Field.templ_dict['field_comment']['rtl'].format(
|
Field.templ_dict['field_comment']['rtl'].format(
|
||||||
name = self.obj.inst_name,
|
name = self.name,
|
||||||
hw_access = str(self.hw_access)[11:],
|
hw_access = str(self.hw_access)[11:],
|
||||||
sw_access = str(self.sw_access)[11:],
|
sw_access = str(self.sw_access)[11:],
|
||||||
hw_precedence = '(precedence)' if self.precedence == PrecedenceType.hw else '',
|
hw_precedence = '(precedence)' if self.precedence == PrecedenceType.hw else '',
|
||||||
|
142
srdl2sv/components/regfile.py
Normal file
142
srdl2sv/components/regfile.py
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
import re
|
||||||
|
import importlib.resources as pkg_resources
|
||||||
|
import sys
|
||||||
|
import math
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from systemrdl import node
|
||||||
|
from systemrdl.node import FieldNode
|
||||||
|
|
||||||
|
# Local packages
|
||||||
|
from components.component import Component
|
||||||
|
from components.register import Register
|
||||||
|
from . import templates
|
||||||
|
|
||||||
|
|
||||||
|
class RegFile(Component):
|
||||||
|
# Save YAML template as class variable
|
||||||
|
templ_dict = yaml.load(
|
||||||
|
pkg_resources.read_text(templates, 'regfile.yaml'),
|
||||||
|
Loader=yaml.FullLoader)
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
obj: node.RegfileNode,
|
||||||
|
parents_dimensions: list,
|
||||||
|
parents_stride: list,
|
||||||
|
config: dict,
|
||||||
|
glbl_settings: dict):
|
||||||
|
super().__init__(obj, config)
|
||||||
|
|
||||||
|
# Save and/or process important variables
|
||||||
|
self.__process_variables(obj, parents_dimensions, parents_stride)
|
||||||
|
|
||||||
|
# Create comment and provide user information about register he/she
|
||||||
|
# is looking at.
|
||||||
|
self.rtl_header = [
|
||||||
|
RegFile.templ_dict['regfile_comment']['rtl'].format(
|
||||||
|
name = obj.inst_name,
|
||||||
|
dimensions = self.dimensions,
|
||||||
|
depth = self.depth),
|
||||||
|
*self.rtl_header
|
||||||
|
]
|
||||||
|
|
||||||
|
# Create generate block for register and add comment
|
||||||
|
if self.dimensions:
|
||||||
|
self.rtl_header.append("generate")
|
||||||
|
|
||||||
|
for i in range(self.dimensions):
|
||||||
|
self.rtl_header.append(
|
||||||
|
RegFile.templ_dict['generate_for_start']['rtl'].format(
|
||||||
|
iterator = chr(97+i+self.parents_depths),
|
||||||
|
limit = self.array_dimensions[i]))
|
||||||
|
|
||||||
|
# Empty dictionary of register objects
|
||||||
|
# We need a dictionary since it might be required to access the objects later
|
||||||
|
# by name (for example, in case of aliases)
|
||||||
|
self.registers = dict()
|
||||||
|
|
||||||
|
# Set object to 0 for easy addressing
|
||||||
|
self.obj.current_idx = [0]
|
||||||
|
|
||||||
|
# Traverse through children
|
||||||
|
for child in obj.children():
|
||||||
|
if isinstance(child, node.AddrmapNode):
|
||||||
|
self.logger.fatal('Instantiating addrmaps within regfiles is not '\
|
||||||
|
'supported. Addrmaps shall be instantiated at the '\
|
||||||
|
'top-level of other addrmaps')
|
||||||
|
sys.exit(1)
|
||||||
|
elif isinstance(child, node.RegfileNode):
|
||||||
|
self.obj.current_idx = [0]
|
||||||
|
|
||||||
|
self.children.append(
|
||||||
|
RegFile(
|
||||||
|
child,
|
||||||
|
self.total_array_dimensions,
|
||||||
|
self.total_stride,
|
||||||
|
config,
|
||||||
|
glbl_settings))
|
||||||
|
elif isinstance(child, node.RegNode):
|
||||||
|
if child.inst.is_alias:
|
||||||
|
# If the node we found is an alias, we shall not create a
|
||||||
|
# new register. Rather, we bury up the old register and add
|
||||||
|
# additional properties
|
||||||
|
self.logger.error('Alias registers are not implemented yet!')
|
||||||
|
else:
|
||||||
|
self.obj.current_idx = [0]
|
||||||
|
self.registers[child.inst_name] = \
|
||||||
|
Register(
|
||||||
|
child,
|
||||||
|
self.total_array_dimensions,
|
||||||
|
self.total_stride,
|
||||||
|
config,
|
||||||
|
glbl_settings)
|
||||||
|
|
||||||
|
# Add registers to children. This must be done in a last step
|
||||||
|
# to account for all possible alias combinations
|
||||||
|
self.children = [
|
||||||
|
*self.children,
|
||||||
|
*[x for x in self.registers.values()]
|
||||||
|
]
|
||||||
|
|
||||||
|
self.logger.info("Done generating all child-regfiles/registers")
|
||||||
|
|
||||||
|
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 = ['[{}]'.format(chr(97+i)) for i in range(self.dimensions)]
|
||||||
|
self.genvars_str = ''.join(genvars)
|
||||||
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
|||||||
import importlib.resources as pkg_resources
|
import importlib.resources as pkg_resources
|
||||||
import yaml
|
import yaml
|
||||||
|
import math
|
||||||
|
|
||||||
from systemrdl import node
|
from systemrdl import node
|
||||||
|
|
||||||
@ -14,20 +15,22 @@ class Register(Component):
|
|||||||
pkg_resources.read_text(templates, 'regs.yaml'),
|
pkg_resources.read_text(templates, 'regs.yaml'),
|
||||||
Loader=yaml.FullLoader)
|
Loader=yaml.FullLoader)
|
||||||
|
|
||||||
def __init__(self, obj: node.RootNode, config: dict, glbl_settings: dict):
|
def __init__(
|
||||||
super().__init__()
|
self,
|
||||||
|
obj: node.RegNode,
|
||||||
|
parents_dimensions: list,
|
||||||
|
parents_stride: list,
|
||||||
|
config: dict,
|
||||||
|
glbl_settings: dict):
|
||||||
|
super().__init__(obj, config)
|
||||||
|
|
||||||
# Save and/or process important variables
|
# Save and/or process important variables
|
||||||
self.__process_variables(obj)
|
self.__process_variables(obj, parents_dimensions, parents_stride)
|
||||||
|
|
||||||
# Create logger object
|
|
||||||
self.create_logger("{}.{}".format(self.owning_addrmap, self.path), config)
|
|
||||||
self.logger.debug('Starting to process register "{}"'.format(obj.inst_name))
|
|
||||||
|
|
||||||
# Create RTL for fields
|
# Create RTL for fields
|
||||||
# Fields should be in order in RTL,therefore, use list
|
# Fields should be in order in RTL,therefore, use list
|
||||||
for field in obj.fields():
|
for field in obj.fields():
|
||||||
field_obj = Field(field, self.array_dimensions, config, glbl_settings)
|
field_obj = Field(field, self.total_array_dimensions, config, glbl_settings)
|
||||||
|
|
||||||
if not config['disable_sanity']:
|
if not config['disable_sanity']:
|
||||||
field_obj.sanity_checks()
|
field_obj.sanity_checks()
|
||||||
@ -35,11 +38,13 @@ class Register(Component):
|
|||||||
self.children.append(field_obj)
|
self.children.append(field_obj)
|
||||||
|
|
||||||
# Create generate block for register and add comment
|
# Create generate block for register and add comment
|
||||||
|
if self.dimensions:
|
||||||
self.rtl_header.append("generate")
|
self.rtl_header.append("generate")
|
||||||
|
|
||||||
for i in range(self.dimensions):
|
for i in range(self.dimensions):
|
||||||
self.rtl_header.append(
|
self.rtl_header.append(
|
||||||
Register.templ_dict['generate_for_start'].format(
|
Register.templ_dict['generate_for_start'].format(
|
||||||
iterator = chr(97+i),
|
iterator = chr(97+i+self.parents_depths),
|
||||||
limit = self.array_dimensions[i]))
|
limit = self.array_dimensions[i]))
|
||||||
|
|
||||||
|
|
||||||
@ -49,6 +54,9 @@ class Register(Component):
|
|||||||
Register.templ_dict['generate_for_end'].format(
|
Register.templ_dict['generate_for_end'].format(
|
||||||
dimension = chr(97+i)))
|
dimension = chr(97+i)))
|
||||||
|
|
||||||
|
if self.dimensions:
|
||||||
|
self.rtl_footer.append("endgenerate")
|
||||||
|
|
||||||
# Assign variables from bus
|
# Assign variables from bus
|
||||||
self.obj.current_idx = [0]
|
self.obj.current_idx = [0]
|
||||||
|
|
||||||
@ -59,11 +67,10 @@ class Register(Component):
|
|||||||
|
|
||||||
self.rtl_header.append(
|
self.rtl_header.append(
|
||||||
Register.templ_dict[rw_wire_assign_field]['rtl'].format(
|
Register.templ_dict[rw_wire_assign_field]['rtl'].format(
|
||||||
path = self.path,
|
path = self.path_underscored,
|
||||||
addr = self.obj.absolute_address,
|
addr = self.obj.absolute_address,
|
||||||
genvars = self.genvars_str,
|
genvars = self.genvars_str,
|
||||||
genvars_sum =self.genvars_sum_str,
|
genvars_sum =self.genvars_sum_str,
|
||||||
stride = self.obj.array_stride,
|
|
||||||
depth = self.depth))
|
depth = self.depth))
|
||||||
|
|
||||||
self.yaml_signals_to_list(Register.templ_dict[rw_wire_assign_field])
|
self.yaml_signals_to_list(Register.templ_dict[rw_wire_assign_field])
|
||||||
@ -102,7 +109,11 @@ class Register(Component):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def __process_variables(self, obj: node.RootNode):
|
def __process_variables(
|
||||||
|
self,
|
||||||
|
obj: node.RegNode,
|
||||||
|
parents_dimensions: list,
|
||||||
|
parents_stride: list):
|
||||||
# Save object
|
# Save object
|
||||||
self.obj = obj
|
self.obj = obj
|
||||||
|
|
||||||
@ -110,37 +121,62 @@ class Register(Component):
|
|||||||
self.name = obj.inst_name
|
self.name = obj.inst_name
|
||||||
|
|
||||||
# Create full name
|
# Create full name
|
||||||
self.owning_addrmap = obj.owning_addrmap.inst_name
|
self.create_underscored_path()
|
||||||
self.path = obj.get_path()\
|
|
||||||
.replace('[]', '')\
|
|
||||||
.replace('{}.'.format(self.owning_addrmap), '')
|
|
||||||
|
|
||||||
self.path_underscored = self.path.replace('.', '_')
|
|
||||||
|
|
||||||
# Determine dimensions of register
|
# Determine dimensions of register
|
||||||
if obj.is_array:
|
if obj.is_array:
|
||||||
self.sel_arr = 'array'
|
self.sel_arr = 'array'
|
||||||
|
self.total_array_dimensions = [*parents_dimensions, *self.obj.array_dimensions]
|
||||||
self.array_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:
|
else:
|
||||||
self.sel_arr = 'single'
|
self.sel_arr = 'single'
|
||||||
|
self.total_array_dimensions = parents_dimensions
|
||||||
self.array_dimensions = []
|
self.array_dimensions = []
|
||||||
|
self.total_stride = self.obj.array_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.depth = '[{}]'.format(']['.join(f"{i}" for i in self.array_dimensions))
|
||||||
self.dimensions = len(self.array_dimensions)
|
self.dimensions = len(self.array_dimensions)
|
||||||
|
|
||||||
# Calculate how many genvars shall be added
|
# Calculate how many genvars shall be added
|
||||||
genvars = ['[{}]'.format(chr(97+i)) for i in range(self.dimensions)]
|
genvars = ['[{}]'.format(chr(97+i)) for i in range(self.total_dimensions)]
|
||||||
self.genvars_str = ''.join(genvars)
|
self.genvars_str = ''.join(genvars)
|
||||||
|
|
||||||
# Determine value to compare address with
|
# Determine value to compare address with
|
||||||
genvars_sum = []
|
genvars_sum = []
|
||||||
for i in range(self.dimensions):
|
try:
|
||||||
if i != 0:
|
for i, stride in enumerate(self.total_stride):
|
||||||
genvars_sum.append("+")
|
genvars_sum.append(chr(97+i))
|
||||||
genvars_sum.append("*".join(map(str,self.array_dimensions[self.dimensions-i:])))
|
|
||||||
genvars_sum.append("*")
|
genvars_sum.append("*")
|
||||||
|
genvars_sum.append(str(stride))
|
||||||
|
genvars_sum.append("+")
|
||||||
|
|
||||||
genvars_sum.append(chr(97+self.dimensions-1-i))
|
genvars_sum.pop()
|
||||||
|
|
||||||
|
self.logger.debug(
|
||||||
|
"Multidimensional with dimensions '{}' and stride '{}'".format(
|
||||||
|
self.total_array_dimensions,
|
||||||
|
self.total_stride))
|
||||||
|
except TypeError:
|
||||||
|
self.logger.debug(
|
||||||
|
"Caught expected TypeError because self.total_stride is empty")
|
||||||
|
except IndexError:
|
||||||
|
self.logger.debug(
|
||||||
|
"Caugt expected IndexError because genvars_sum is empty")
|
||||||
|
|
||||||
self.genvars_sum_str = ''.join(genvars_sum)
|
self.genvars_sum_str = ''.join(genvars_sum)
|
||||||
|
|
||||||
|
@ -142,6 +142,7 @@ singlepulse:
|
|||||||
end
|
end
|
||||||
out_port_assign:
|
out_port_assign:
|
||||||
rtl: |-
|
rtl: |-
|
||||||
|
|
||||||
// Connect register to hardware output port
|
// Connect register to hardware output port
|
||||||
assign {path}_r{genvars} = {path}_q{genvars};
|
assign {path}_r{genvars} = {path}_q{genvars};
|
||||||
output_ports:
|
output_ports:
|
||||||
|
17
srdl2sv/components/templates/regfile.yaml
Normal file
17
srdl2sv/components/templates/regfile.yaml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
regfile_comment:
|
||||||
|
rtl: |-
|
||||||
|
/*******************************************************************
|
||||||
|
*******************************************************************
|
||||||
|
* REGFILE : {name}
|
||||||
|
* DIMENSION : {dimensions}
|
||||||
|
* DEPTHS (per dimension): {depth}
|
||||||
|
*******************************************************************
|
||||||
|
*******************************************************************/
|
||||||
|
generate_for_start:
|
||||||
|
rtl: |-
|
||||||
|
for ({iterator} = 0; {iterator} < {limit}; {iterator}++)
|
||||||
|
begin
|
||||||
|
generate_for_end:
|
||||||
|
rtl: |-
|
||||||
|
end // of for loop with iterator {dimension}
|
@ -19,7 +19,7 @@ rw_wire_assign_multi_dim:
|
|||||||
rtl: |
|
rtl: |
|
||||||
|
|
||||||
// Assign register-activation signals
|
// Assign register-activation signals
|
||||||
assign {path}_reg_active{genvars} = addr == ({addr}+({genvars_sum})*{stride});
|
assign {path}_reg_active{genvars} = addr == {addr}+({genvars_sum});
|
||||||
|
|
||||||
assign {path}_sw_wr{genvars} = {path}_reg_active{genvars} && r_vld;
|
assign {path}_sw_wr{genvars} = {path}_reg_active{genvars} && r_vld;
|
||||||
assign {path}_sw_rd{genvars} = {path}_reg_active{genvars} && w_vld;
|
assign {path}_sw_rd{genvars} = {path}_reg_active{genvars} && w_vld;
|
||||||
|
Loading…
Reference in New Issue
Block a user