mirror of
https://github.com/Silicon1602/srdl2sv.git
synced 2024-11-14 11:03:36 +00:00
Add support for alias registers
This required some fundamental changes. One of them is that YAML fields are now processed in a more systematic way in which all fields are passed via a dictionary. That way, some of the fields are not bound to the original object anymore.
This commit is contained in:
parent
9deb28ce4e
commit
b2c756af41
@ -23,10 +23,6 @@ class AddrMap(Component):
|
|||||||
def __init__(self, obj: node.RootNode, config: dict):
|
def __init__(self, obj: node.RootNode, config: dict):
|
||||||
super().__init__(obj, config)
|
super().__init__(obj, config)
|
||||||
|
|
||||||
# Create logger object
|
|
||||||
self.create_logger(self.path, config)
|
|
||||||
self.logger.debug('Starting to process addrmap')
|
|
||||||
|
|
||||||
# Check if global resets are defined
|
# Check if global resets are defined
|
||||||
glbl_settings = dict()
|
glbl_settings = dict()
|
||||||
|
|
||||||
@ -44,7 +40,7 @@ class AddrMap(Component):
|
|||||||
# We need a dictionary since it might be required to access the objects later
|
# We need a dictionary since it might be required to access the objects later
|
||||||
# by name (for example, in case of aliases)
|
# by name (for example, in case of aliases)
|
||||||
self.registers = dict()
|
self.registers = dict()
|
||||||
self.regfiles = []
|
self.regfiles = dict()
|
||||||
|
|
||||||
# Traverse through children
|
# Traverse through children
|
||||||
for child in obj.children():
|
for child in obj.children():
|
||||||
@ -54,28 +50,27 @@ 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.regfiles.append(RegFile(child, [], [], config, glbl_settings))
|
self.regfiles[child.inst_name] = \
|
||||||
|
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
|
||||||
# new register. Rather, we bury up the old register and add
|
# new register. Rather, we bury up the old register and add
|
||||||
# additional properties
|
# additional properties
|
||||||
self.logger.error('Alias registers are not implemented yet!')
|
self.registers[child.inst.alias_primary_inst.inst_name]\
|
||||||
|
.add_alias(child)
|
||||||
else:
|
else:
|
||||||
self.registers[child.inst_name] = \
|
self.registers[child.inst_name] = \
|
||||||
Register(child, [], [], config, glbl_settings)
|
Register(child, [], [], config, glbl_settings)
|
||||||
|
|
||||||
# Add registers to children. This must be done in a last step
|
# Add registers to children. This must be done in a last step
|
||||||
# to account for all possible alias combinations
|
# to account for all possible alias combinations
|
||||||
self.children = [
|
self.children = {**self.regfiles, **self.registers}
|
||||||
*self.regfiles,
|
|
||||||
*[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")
|
||||||
|
|
||||||
# Add bus widget ports
|
# Add bus widget ports
|
||||||
self.__add_bus_widget_ports()
|
widget_rtl = self.__get_widget_ports_rtl()
|
||||||
|
|
||||||
# Start assembling addrmap module
|
# Start assembling addrmap module
|
||||||
self.logger.info("Starting to assemble input & output ports")
|
self.logger.info("Starting to assemble input & output ports")
|
||||||
@ -159,7 +154,7 @@ class AddrMap(Component):
|
|||||||
self.__add_signal_instantiation()
|
self.__add_signal_instantiation()
|
||||||
|
|
||||||
# Add bus widget RTL
|
# Add bus widget RTL
|
||||||
self.__add_bus_widget_instantiation()
|
self.rtl_header.append(widget_rtl)
|
||||||
|
|
||||||
# Append genvars
|
# Append genvars
|
||||||
self.__append_genvars()
|
self.__append_genvars()
|
||||||
@ -189,16 +184,15 @@ class AddrMap(Component):
|
|||||||
''
|
''
|
||||||
]
|
]
|
||||||
|
|
||||||
def __add_bus_widget_ports(self):
|
def __get_widget_ports_rtl(self):
|
||||||
self.widget_templ_dict = yaml.load(
|
self.widget_templ_dict = yaml.load(
|
||||||
pkg_resources.read_text(widgets, '{}.yaml'.format(self.config['bus'])),
|
pkg_resources.read_text(widgets, '{}.yaml'.format(self.config['bus'])),
|
||||||
Loader=yaml.FullLoader)
|
Loader=yaml.FullLoader)
|
||||||
|
|
||||||
self.yaml_signals_to_list(self.widget_templ_dict['module_instantiation'])
|
return self.process_yaml(
|
||||||
|
self.widget_templ_dict['module_instantiation'],
|
||||||
def __add_bus_widget_instantiation(self):
|
# TODO: Add widths
|
||||||
self.rtl_header.append(
|
)
|
||||||
self.widget_templ_dict['module_instantiation']['rtl'])
|
|
||||||
|
|
||||||
|
|
||||||
def __append_genvars(self):
|
def __append_genvars(self):
|
||||||
|
@ -16,7 +16,7 @@ class Component():
|
|||||||
def __init__(self, obj, config):
|
def __init__(self, obj, config):
|
||||||
self.rtl_header = []
|
self.rtl_header = []
|
||||||
self.rtl_footer = []
|
self.rtl_footer = []
|
||||||
self.children = []
|
self.children = dict()
|
||||||
self.typedefs = dict()
|
self.typedefs = dict()
|
||||||
self.ports = dict()
|
self.ports = dict()
|
||||||
self.resets = set()
|
self.resets = set()
|
||||||
@ -39,7 +39,9 @@ class Component():
|
|||||||
|
|
||||||
# Create logger object
|
# Create logger object
|
||||||
self.create_logger("{}.{}".format(self.owning_addrmap, self.path), config)
|
self.create_logger("{}.{}".format(self.owning_addrmap, self.path), config)
|
||||||
self.logger.debug('Starting to process register "{}"'.format(obj.inst_name))
|
self.logger.debug('Starting to process {} "{}"'.format(
|
||||||
|
self.__class__.__name__,
|
||||||
|
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(
|
||||||
@ -52,7 +54,7 @@ class Component():
|
|||||||
def get_resets(self):
|
def get_resets(self):
|
||||||
self.logger.debug("Return reset list")
|
self.logger.debug("Return reset list")
|
||||||
|
|
||||||
for x in self.children:
|
for x in self.children.values():
|
||||||
self.resets |= x.get_resets()
|
self.resets |= x.get_resets()
|
||||||
|
|
||||||
return self.resets
|
return self.resets
|
||||||
@ -60,7 +62,7 @@ class Component():
|
|||||||
def get_ports(self, port_type: str):
|
def get_ports(self, port_type: str):
|
||||||
self.logger.debug("Return port list")
|
self.logger.debug("Return port list")
|
||||||
|
|
||||||
for x in self.children:
|
for x in self.children.values():
|
||||||
self.ports[port_type] |= x.get_ports(port_type)
|
self.ports[port_type] |= x.get_ports(port_type)
|
||||||
|
|
||||||
return self.ports[port_type]
|
return self.ports[port_type]
|
||||||
@ -71,14 +73,14 @@ class Component():
|
|||||||
self.total_array_dimensions))
|
self.total_array_dimensions))
|
||||||
return max([
|
return max([
|
||||||
self.total_dimensions,
|
self.total_dimensions,
|
||||||
*[x.get_max_dim_depth() for x in self.children]
|
*[x.get_max_dim_depth() for x in self.children.values()]
|
||||||
])
|
])
|
||||||
|
|
||||||
def get_signals(self, no_children = False):
|
def get_signals(self, no_children = False):
|
||||||
self.logger.debug("Return signal list")
|
self.logger.debug("Return signal list")
|
||||||
|
|
||||||
if not no_children:
|
if not no_children:
|
||||||
for x in self.children:
|
for x in self.children.values():
|
||||||
self.signals |= x.get_signals()
|
self.signals |= x.get_signals()
|
||||||
|
|
||||||
return self.signals
|
return self.signals
|
||||||
@ -86,7 +88,7 @@ class Component():
|
|||||||
def get_typedefs(self):
|
def get_typedefs(self):
|
||||||
self.logger.debug("Return typedef list")
|
self.logger.debug("Return typedef list")
|
||||||
|
|
||||||
for x in self.children:
|
for x in self.children.values():
|
||||||
self.typedefs |= x.get_typedefs()
|
self.typedefs |= x.get_typedefs()
|
||||||
|
|
||||||
return self.typedefs
|
return self.typedefs
|
||||||
@ -97,8 +99,16 @@ class Component():
|
|||||||
# Loop through children and append RTL
|
# Loop through children and append RTL
|
||||||
rtl_children = []
|
rtl_children = []
|
||||||
|
|
||||||
for child in self.children:
|
for x in self.children.values():
|
||||||
rtl_children.append(child.get_rtl())
|
# In case of fields, the RTL must first be generated.
|
||||||
|
# Reason is that we only know at the very end whether
|
||||||
|
# all alias registers are processed for fields
|
||||||
|
try:
|
||||||
|
x.create_rtl()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
rtl_children.append(x.get_rtl())
|
||||||
|
|
||||||
# Concatenate header, main, and footer
|
# Concatenate header, main, and footer
|
||||||
rtl = [*self.rtl_header, *rtl_children, *self.rtl_footer]
|
rtl = [*self.rtl_header, *rtl_children, *self.rtl_footer]
|
||||||
@ -204,31 +214,34 @@ class Component():
|
|||||||
|
|
||||||
return ''.join(name)
|
return ''.join(name)
|
||||||
|
|
||||||
def yaml_signals_to_list(self, yaml_obj):
|
def process_yaml(self, yaml_obj, values: dict = {}):
|
||||||
try:
|
try:
|
||||||
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(**values)] =\
|
||||||
(x['signal_type'].format(field_type = self.field_type),
|
(x['signal_type'].format(**values),
|
||||||
self.total_array_dimensions)
|
self.total_array_dimensions)
|
||||||
except (TypeError, KeyError):
|
except (TypeError, KeyError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
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(**values)] =\
|
||||||
(x['signal_type'].format(field_type = self.field_type),
|
(x['signal_type'].format(**values),
|
||||||
self.total_array_dimensions)
|
self.total_array_dimensions)
|
||||||
except (TypeError, KeyError):
|
except (TypeError, KeyError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
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(**values)] =\
|
||||||
(x['signal_type'].format(field_type = self.field_type),
|
(x['signal_type'].format(**values),
|
||||||
self.total_array_dimensions)
|
self.total_array_dimensions)
|
||||||
except (TypeError, KeyError):
|
except (TypeError, KeyError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Return RTL with values
|
||||||
|
return yaml_obj['rtl'].format(**values)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def process_reset_signal(reset_signal):
|
def process_reset_signal(reset_signal):
|
||||||
rst = dict()
|
rst = dict()
|
||||||
@ -256,9 +269,16 @@ class Component():
|
|||||||
return rst
|
return rst
|
||||||
|
|
||||||
def create_underscored_path(self):
|
def create_underscored_path(self):
|
||||||
self.owning_addrmap = self.obj.owning_addrmap.inst_name
|
self.owning_addrmap, self.full_path, self.path, self.path_underscored =\
|
||||||
self.full_path = Component.split_dimensions(self.obj.get_path())[0]
|
Component.create_underscored_path_static(self.obj)
|
||||||
self.path = self.full_path\
|
|
||||||
.replace('{}.'.format(self.owning_addrmap), '')
|
|
||||||
|
|
||||||
self.path_underscored = self.path.replace('.', '__')
|
@staticmethod
|
||||||
|
def create_underscored_path_static(obj):
|
||||||
|
owning_addrmap = obj.owning_addrmap.inst_name
|
||||||
|
full_path = Component.split_dimensions(obj.get_path())[0]
|
||||||
|
path = full_path\
|
||||||
|
.replace('{}.'.format(owning_addrmap), '')
|
||||||
|
|
||||||
|
path_underscored = path.replace('.', '__')
|
||||||
|
|
||||||
|
return (owning_addrmap, full_path, path, path_underscored)
|
||||||
|
@ -39,12 +39,266 @@ class Field(Component):
|
|||||||
# Print a summary
|
# Print a summary
|
||||||
self.rtl_header.append(self.summary())
|
self.rtl_header.append(self.summary())
|
||||||
|
|
||||||
# Generate RTL
|
# HW Access can be handled in __init__ function but SW access
|
||||||
|
# must be handled in a seperate method that can be called
|
||||||
|
# seperately in case of alias registers
|
||||||
self.__add_always_ff()
|
self.__add_always_ff()
|
||||||
self.__add_access_rtl()
|
self.__add_hw_access()
|
||||||
self.__add_combo()
|
self.__add_combo()
|
||||||
self.__add_ports()
|
|
||||||
self.__prepend_signal_declarations()
|
self.add_sw_access(obj)
|
||||||
|
|
||||||
|
def add_sw_access(self, obj, alias = False):
|
||||||
|
access_rtl = dict()
|
||||||
|
|
||||||
|
if alias:
|
||||||
|
owning_addrmap, full_path, path, path_underscored =\
|
||||||
|
Field.create_underscored_path_static(obj)
|
||||||
|
else:
|
||||||
|
owning_addrmap, full_path, path, path_underscored =\
|
||||||
|
self.owning_addrmap, self.full_path, self.path, self.path_underscored
|
||||||
|
|
||||||
|
path_wo_field = '__'.join(path.split('.', -1)[0:-1])
|
||||||
|
|
||||||
|
# Define software access (if applicable)
|
||||||
|
access_rtl['sw_write'] = ([], False)
|
||||||
|
|
||||||
|
if obj.get_property('sw') in (AccessType.rw, AccessType.w):
|
||||||
|
swwe = obj.get_property('swwe')
|
||||||
|
swwel = obj.get_property('swwel')
|
||||||
|
|
||||||
|
if isinstance(swwe, (FieldNode, SignalNode)):
|
||||||
|
access_rtl['sw_write'][0].append(
|
||||||
|
self.process_yaml(
|
||||||
|
Field.templ_dict['sw_access_field_swwe'],
|
||||||
|
{'path_wo_field': path_wo_field,
|
||||||
|
'genvars': self.genvars_str,
|
||||||
|
'swwe': self.get_signal_name(swwe),
|
||||||
|
'field_type': self.field_type}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif isinstance(swwel, (FieldNode, SignalNode)):
|
||||||
|
access_rtl['sw_write'][0].append(
|
||||||
|
self.process_yaml(
|
||||||
|
Field.templ_dict['sw_access_field_swwel'],
|
||||||
|
{'path_wo_field': path_wo_field,
|
||||||
|
'genvars': self.genvars_str,
|
||||||
|
'swwel': self.get_signal_name(swwel),
|
||||||
|
'field_type': self.field_type}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
access_rtl['sw_write'][0].append(
|
||||||
|
self.process_yaml(
|
||||||
|
Field.templ_dict['sw_access_field'],
|
||||||
|
{'path_wo_field': path_wo_field,
|
||||||
|
'genvars': self.genvars_str,
|
||||||
|
'field_type': self.field_type}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check if an onwrite property is set
|
||||||
|
onwrite = obj.get_property('onwrite')
|
||||||
|
|
||||||
|
if onwrite:
|
||||||
|
if onwrite == OnWriteType.wuser:
|
||||||
|
self.logger.warning("The OnReadType.wuser is not yet supported!")
|
||||||
|
elif onwrite in (OnWriteType.wclr, OnWriteType.wset):
|
||||||
|
access_rtl['sw_write'][0].append(
|
||||||
|
self.process_yaml(
|
||||||
|
Field.templ_dict[str(onwrite)],
|
||||||
|
{'path': path_underscored,
|
||||||
|
'genvars': self.genvars_str,
|
||||||
|
'width': obj.width,
|
||||||
|
'path_wo_field': path_wo_field,
|
||||||
|
'field_type': self.field_type}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# If field spans multiple bytes, every byte shall have a seperate enable!
|
||||||
|
for j, i in enumerate(range(self.lsbyte, self.msbyte+1)):
|
||||||
|
access_rtl['sw_write'][0].append(
|
||||||
|
self.process_yaml(
|
||||||
|
Field.templ_dict[str(onwrite)],
|
||||||
|
{'path': path_underscored,
|
||||||
|
'genvars': self.genvars_str,
|
||||||
|
'i': i,
|
||||||
|
'width': obj.width,
|
||||||
|
'msb_bus': str(8*(i+1)-1 if i != self.msbyte else obj.msb),
|
||||||
|
'bus_w': str(8 if i != self.msbyte else obj.width-(8*j)),
|
||||||
|
'msb_field': str(8*(j+1)-1 if i != self.msbyte else obj.width-1),
|
||||||
|
'field_w': str(8 if i != self.msbyte else obj.width-(8*j)),
|
||||||
|
'field_type': self.field_type}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Normal write
|
||||||
|
# If field spans multiple bytes, every byte shall have a seperate enable!
|
||||||
|
for j, i in enumerate(range(self.lsbyte, self.msbyte+1)):
|
||||||
|
access_rtl['sw_write'][0].append(
|
||||||
|
self.process_yaml(
|
||||||
|
Field.templ_dict['sw_access_byte'],
|
||||||
|
{'path': self.path_underscored,
|
||||||
|
'genvars': self.genvars_str,
|
||||||
|
'i': i,
|
||||||
|
'msb_bus': str(8*(i+1)-1 if i != self.msbyte else obj.msb),
|
||||||
|
'bus_w': str(8 if i != self.msbyte else obj.width-(8*j)),
|
||||||
|
'msb_field': str(8*(j+1)-1 if i != self.msbyte else obj.width-1),
|
||||||
|
'field_w': str(8 if i != self.msbyte else obj.width-(8*j)),
|
||||||
|
'field_type': self.field_type}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
access_rtl['sw_write'][0].append("end")
|
||||||
|
|
||||||
|
onread = obj.get_property('onread')
|
||||||
|
|
||||||
|
access_rtl['sw_read'] = ([], False)
|
||||||
|
if obj.get_property('sw') in (AccessType.rw, AccessType.r) and onread:
|
||||||
|
if onread == OnReadType.ruser:
|
||||||
|
self.logger.warning("The OnReadType.ruser is not yet supported!")
|
||||||
|
else:
|
||||||
|
access_rtl['sw_read'][0].append(
|
||||||
|
self.process_yaml(
|
||||||
|
Field.templ_dict[str(onread)],
|
||||||
|
{'width': obj.width,
|
||||||
|
'path': path_underscored,
|
||||||
|
'genvars': self.genvars_str,
|
||||||
|
'path_wo_field': path_wo_field}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add singlepulse property
|
||||||
|
# Property cannot be overwritten by alias
|
||||||
|
if obj.get_property('singlepulse'):
|
||||||
|
self.access_rtl['singlepulse'] = ([
|
||||||
|
self.process_yaml(
|
||||||
|
Field.templ_dict['singlepulse'],
|
||||||
|
{'path': self.path_underscored,
|
||||||
|
'genvars': self.genvars_str}
|
||||||
|
)
|
||||||
|
],
|
||||||
|
True)
|
||||||
|
else:
|
||||||
|
self.access_rtl['singlepulse'] = ([], False)
|
||||||
|
|
||||||
|
# Add to global dictionary
|
||||||
|
try:
|
||||||
|
# Alias, so add 'else'
|
||||||
|
self.access_rtl['sw_read'] = \
|
||||||
|
[*self.access_rtl['sw_read'], access_rtl['sw_read']]
|
||||||
|
self.access_rtl['sw_write'] = \
|
||||||
|
[*self.access_rtl['sw_write'], access_rtl['sw_write']]
|
||||||
|
except KeyError:
|
||||||
|
self.access_rtl['sw_read'] = [access_rtl['sw_read']]
|
||||||
|
self.access_rtl['sw_write'] = [access_rtl['sw_write']]
|
||||||
|
|
||||||
|
def __add_hw_access(self):
|
||||||
|
# Define hardware access (if applicable)
|
||||||
|
if self.obj.get_property('hw') in (AccessType.rw, AccessType.w):
|
||||||
|
write_condition = 'hw_access_we_wel' if self.we_or_wel else 'hw_access_no_we_wel'
|
||||||
|
|
||||||
|
# if-line of hw-access
|
||||||
|
self.access_rtl['hw_write'] = ([
|
||||||
|
self.process_yaml(
|
||||||
|
Field.templ_dict[write_condition],
|
||||||
|
{'negl': '!' if self.obj.get_property('wel') else '',
|
||||||
|
'path': self.path_underscored,
|
||||||
|
'genvars': self.genvars_str,
|
||||||
|
'field_type': self.field_type}
|
||||||
|
)
|
||||||
|
],
|
||||||
|
write_condition == 'hw_access_no_we_wel') # Abort if no condition is set
|
||||||
|
|
||||||
|
# Actual assignment of register
|
||||||
|
self.access_rtl['hw_write'][0].append(
|
||||||
|
self.process_yaml(
|
||||||
|
Field.templ_dict['hw_access_field'],
|
||||||
|
{'path': self.path_underscored,
|
||||||
|
'genvars': self.genvars_str,
|
||||||
|
'field_type': self.field_type}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.access_rtl['hw_write'] = ([], False)
|
||||||
|
|
||||||
|
# Hookup flop to output port in case register is readable by hardware
|
||||||
|
if self.obj.get_property('hw') in (AccessType.rw, AccessType.r):
|
||||||
|
# Connect flops to output port
|
||||||
|
self.rtl_footer.append(
|
||||||
|
self.process_yaml(
|
||||||
|
Field.templ_dict['out_port_assign'],
|
||||||
|
{'genvars': self.genvars_str,
|
||||||
|
'path': self.path_underscored,
|
||||||
|
'field_type': self.field_type}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def create_rtl(self):
|
||||||
|
# Not all access types are required and the order might differ
|
||||||
|
# depending on what types are defined and what precedence is
|
||||||
|
# set. Therefore, first add all RTL into a dictionary and
|
||||||
|
# later place it in the right order.
|
||||||
|
#
|
||||||
|
# Check if hardware has precedence (default `precedence = sw`)
|
||||||
|
if self.obj.get_property('precedence') == PrecedenceType.sw:
|
||||||
|
order_list = [
|
||||||
|
'sw_write',
|
||||||
|
'sw_read',
|
||||||
|
'hw_write',
|
||||||
|
'singlepulse'
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
order_list = [
|
||||||
|
'hw_write',
|
||||||
|
'sw_write',
|
||||||
|
'sw_read',
|
||||||
|
'singlepulse'
|
||||||
|
]
|
||||||
|
|
||||||
|
# Add appropriate else
|
||||||
|
order_list_rtl = []
|
||||||
|
abort_set = False
|
||||||
|
|
||||||
|
for i in order_list:
|
||||||
|
# Still a loop and not a list comprehension since this might
|
||||||
|
# get longer in the future and thus become unreadable
|
||||||
|
|
||||||
|
# First check if we need to break or continue the loop
|
||||||
|
if abort_set:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Check if there is a list that shall be unlooped
|
||||||
|
if isinstance(self.access_rtl[i], tuple):
|
||||||
|
access_rtl = [self.access_rtl[i]]
|
||||||
|
else:
|
||||||
|
access_rtl = self.access_rtl[i]
|
||||||
|
|
||||||
|
for unpacked_access_rtl in access_rtl:
|
||||||
|
if len(unpacked_access_rtl[0]) == 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
order_list_rtl = [*order_list_rtl, *unpacked_access_rtl[0]]
|
||||||
|
order_list_rtl.append("else")
|
||||||
|
|
||||||
|
# If the access_rtl entry has an abortion entry, do not print
|
||||||
|
# any further branches of the conditional block
|
||||||
|
abort_set = unpacked_access_rtl[1]
|
||||||
|
|
||||||
|
# Remove last else
|
||||||
|
order_list_rtl.pop()
|
||||||
|
|
||||||
|
# Chain access RTL to the rest of the RTL
|
||||||
|
self.rtl_header = [*self.rtl_header, *order_list_rtl]
|
||||||
|
|
||||||
|
self.rtl_header.append(
|
||||||
|
self.process_yaml(
|
||||||
|
Field.templ_dict['end_field_ff'],
|
||||||
|
{'path': self.path_underscored}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def __add_combo(self):
|
def __add_combo(self):
|
||||||
operations = []
|
operations = []
|
||||||
@ -56,20 +310,24 @@ class Field(Component):
|
|||||||
operations.append(['^', 'assign_xored_operation'])
|
operations.append(['^', 'assign_xored_operation'])
|
||||||
|
|
||||||
if len(operations) > 0:
|
if len(operations) > 0:
|
||||||
self.rtl_header.append(
|
self.rtl_footer.append(
|
||||||
Field.templ_dict['combo_operation_comment']['rtl'].format(
|
self.process_yaml(
|
||||||
path = self.path_underscored))
|
Field.templ_dict['combo_operation_comment'],
|
||||||
|
{'path': self.path_underscored}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
self.rtl_header = [
|
self.rtl_footer = [
|
||||||
*self.rtl_header,
|
*self.rtl_footer,
|
||||||
*[Field.templ_dict[i[1]]['rtl'].format(
|
*[self.process_yaml(
|
||||||
path = self.path_underscored,
|
Field.templ_dict[i[1]],
|
||||||
genvars = self.genvars_str,
|
{'path': self.path_underscored,
|
||||||
op_verilog = i[0]) for i in operations]
|
'genvars': self.genvars_str,
|
||||||
|
'op_verilog': i[0],
|
||||||
|
'field_type': self.field_type}
|
||||||
|
) for i in operations]
|
||||||
]
|
]
|
||||||
|
|
||||||
[self.yaml_signals_to_list(Field.templ_dict[i[1]]) for i in operations]
|
|
||||||
|
|
||||||
|
|
||||||
def __process_fieldtype(self):
|
def __process_fieldtype(self):
|
||||||
try:
|
try:
|
||||||
@ -174,11 +432,10 @@ class Field(Component):
|
|||||||
'\'x' if not obj.get_property("reset") else\
|
'\'x' if not obj.get_property("reset") else\
|
||||||
obj.get_property('reset')
|
obj.get_property('reset')
|
||||||
|
|
||||||
# Define hardware access
|
# Define dict that holds all RTL
|
||||||
self.hw_access = obj.get_property('hw')
|
self.access_rtl = dict()
|
||||||
self.sw_access = obj.get_property('sw')
|
self.access_rtl['else'] = (["else"], False)
|
||||||
self.precedence = obj.get_property('precedence')
|
self.access_rtl[''] = ([''], False)
|
||||||
|
|
||||||
|
|
||||||
def summary(self):
|
def summary(self):
|
||||||
# Additional flags that are set
|
# Additional flags that are set
|
||||||
@ -189,14 +446,16 @@ class Field(Component):
|
|||||||
misc_flags.discard('hw')
|
misc_flags.discard('hw')
|
||||||
misc_flags.discard('reset')
|
misc_flags.discard('reset')
|
||||||
|
|
||||||
|
precedence = self.obj.get_property('precedence')
|
||||||
|
|
||||||
# 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.name,
|
name = self.name,
|
||||||
hw_access = str(self.hw_access)[11:],
|
hw_access = str(self.obj.get_property('hw'))[11:],
|
||||||
sw_access = str(self.sw_access)[11:],
|
sw_access = str(self.obj.get_property('sw'))[11:],
|
||||||
hw_precedence = '(precedence)' if self.precedence == PrecedenceType.hw else '',
|
hw_precedence = '(precedence)' if precedence == PrecedenceType.hw else '',
|
||||||
sw_precedence = '(precedence)' if self.precedence == PrecedenceType.sw else '',
|
sw_precedence = '(precedence)' if precedence == PrecedenceType.sw else '',
|
||||||
rst_active = self.rst['active'],
|
rst_active = self.rst['active'],
|
||||||
rst_type = self.rst['type'],
|
rst_type = self.rst['type'],
|
||||||
misc_flags = misc_flags if misc_flags else '-',
|
misc_flags = misc_flags if misc_flags else '-',
|
||||||
@ -209,228 +468,38 @@ class Field(Component):
|
|||||||
sense_list = 'sense_list_rst' if self.rst['async'] else 'sense_list_no_rst'
|
sense_list = 'sense_list_rst' if self.rst['async'] else 'sense_list_no_rst'
|
||||||
|
|
||||||
self.rtl_header.append(
|
self.rtl_header.append(
|
||||||
Field.templ_dict[sense_list]['rtl'].format(
|
self.process_yaml(
|
||||||
rst_edge = self.rst['edge'],
|
Field.templ_dict[sense_list],
|
||||||
rst_name = self.rst['name']))
|
{'rst_edge': self.rst['edge'],
|
||||||
|
'rst_name': self.rst['name']}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
# Add actual reset line
|
# Add actual reset line
|
||||||
if self.rst['name']:
|
if self.rst['name']:
|
||||||
self.rtl_header.append(
|
self.rtl_header.append(
|
||||||
Field.templ_dict['rst_field_assign']['rtl'].format(
|
self.process_yaml(
|
||||||
path = self.path_underscored,
|
Field.templ_dict['rst_field_assign'],
|
||||||
rst_name = self.rst['name'],
|
{'path': self.path_underscored,
|
||||||
rst_negl = "!" if self.rst['active'] == "active_low" else "",
|
'rst_name': self.rst['name'],
|
||||||
rst_value = self.rst['value'],
|
'rst_negl': "!" if self.rst['active'] == "active_low" else "",
|
||||||
genvars = self.genvars_str))
|
'rst_value': self.rst['value'],
|
||||||
|
'genvars': self.genvars_str,
|
||||||
self.yaml_signals_to_list(Field.templ_dict['rst_field_assign'])
|
'field_type': self.field_type}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
self.rtl_header.append("begin")
|
self.rtl_header.append("begin")
|
||||||
|
|
||||||
# Add name of actual field to Signal field
|
# Add name of actual field to Signal field
|
||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
def __prepend_signal_declarations(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def __add_access_rtl(self):
|
|
||||||
# Not all access types are required and the order might differ
|
|
||||||
# depending on what types are defined and what precedence is
|
|
||||||
# set. Therefore, first add all RTL into a dictionary and
|
|
||||||
# later place it in the right order.
|
|
||||||
#
|
|
||||||
# The following RTL blocks are defined:
|
|
||||||
# - hw_write --> write access for the hardware interface
|
|
||||||
# - sw_write --> write access for the software interface
|
|
||||||
#
|
|
||||||
access_rtl = dict()
|
|
||||||
|
|
||||||
# Define hardware access (if applicable)
|
|
||||||
if self.hw_access in (AccessType.rw, AccessType.w):
|
|
||||||
write_condition = 'hw_access_we_wel' if self.we_or_wel else 'hw_access_no_we_wel'
|
|
||||||
|
|
||||||
# if-line of hw-access
|
|
||||||
access_rtl['hw_write'] = ([
|
|
||||||
Field.templ_dict[write_condition]['rtl'].format(
|
|
||||||
negl = '!' if self.obj.get_property('wel') else '',
|
|
||||||
path = self.path_underscored,
|
|
||||||
genvars = self.genvars_str)
|
|
||||||
],
|
|
||||||
write_condition == 'hw_access_no_we_wel') # Abort if no condition is set
|
|
||||||
|
|
||||||
# Actual assignment of register
|
|
||||||
access_rtl['hw_write'][0].append(
|
|
||||||
Field.templ_dict['hw_access_field']['rtl'].format(
|
|
||||||
path = self.path_underscored,
|
|
||||||
genvars = self.genvars_str))
|
|
||||||
|
|
||||||
# Get ports/signals from list
|
|
||||||
self.yaml_signals_to_list(Field.templ_dict[write_condition])
|
|
||||||
self.yaml_signals_to_list(Field.templ_dict['hw_access_field'])
|
|
||||||
else:
|
|
||||||
access_rtl['hw_write'] = ([], False)
|
|
||||||
|
|
||||||
# Define software access (if applicable)
|
|
||||||
access_rtl['sw_write'] = ([], False)
|
|
||||||
|
|
||||||
if self.sw_access in (AccessType.rw, AccessType.w):
|
|
||||||
swwe = self.obj.get_property('swwe')
|
|
||||||
swwel = self.obj.get_property('swwel')
|
|
||||||
|
|
||||||
if isinstance(swwe, (FieldNode, SignalNode)):
|
|
||||||
access_rtl['sw_write'][0].append(
|
|
||||||
Field.templ_dict['sw_access_field_swwe']['rtl'].format(
|
|
||||||
path_wo_field = self.path_wo_field,
|
|
||||||
genvars = self.genvars_str,
|
|
||||||
swwe = self.get_signal_name(swwe)))
|
|
||||||
elif isinstance(swwel, (FieldNode, SignalNode)):
|
|
||||||
access_rtl['sw_write'][0].append(
|
|
||||||
Field.templ_dict['sw_access_field_swwel']['rtl'].format(
|
|
||||||
path_wo_field = self.path_wo_field,
|
|
||||||
genvars = self.genvars_str,
|
|
||||||
swwel = self.get_signal_name(swwel)))
|
|
||||||
else:
|
|
||||||
access_rtl['sw_write'][0].append(
|
|
||||||
Field.templ_dict['sw_access_field']['rtl'].format(
|
|
||||||
path_wo_field = self.path_wo_field,
|
|
||||||
genvars = self.genvars_str))
|
|
||||||
|
|
||||||
# Check if an onwrite property is set
|
|
||||||
onwrite = self.obj.get_property('onwrite')
|
|
||||||
|
|
||||||
if onwrite:
|
|
||||||
if onwrite == OnWriteType.wuser:
|
|
||||||
self.logger.warning("The OnReadType.wuser is not yet supported!")
|
|
||||||
elif onwrite in (OnWriteType.wclr, OnWriteType.wset):
|
|
||||||
access_rtl['sw_write'][0].append(
|
|
||||||
Field.templ_dict[str(onwrite)]['rtl'].format(
|
|
||||||
path = self.path_underscored,
|
|
||||||
genvars = self.genvars_str,
|
|
||||||
width = self.obj.width,
|
|
||||||
path_wo_field = self.path_wo_field
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
# If field spans multiple bytes, every byte shall have a seperate enable!
|
|
||||||
for j, i in enumerate(range(self.lsbyte, self.msbyte+1)):
|
|
||||||
access_rtl['sw_write'][0].append(
|
|
||||||
Field.templ_dict[str(onwrite)]['rtl'].format(
|
|
||||||
path = self.path_underscored,
|
|
||||||
genvars = self.genvars_str,
|
|
||||||
i = i,
|
|
||||||
width = self.obj.width,
|
|
||||||
msb_bus = str(8*(i+1)-1 if i != self.msbyte else self.obj.msb),
|
|
||||||
bus_w = str(8 if i != self.msbyte else self.obj.width-(8*j)),
|
|
||||||
msb_field = str(8*(j+1)-1 if i != self.msbyte else self.obj.width-1),
|
|
||||||
field_w = str(8 if i != self.msbyte else self.obj.width-(8*j))))
|
|
||||||
else:
|
|
||||||
# Normal write
|
|
||||||
# If field spans multiple bytes, every byte shall have a seperate enable!
|
|
||||||
for j, i in enumerate(range(self.lsbyte, self.msbyte+1)):
|
|
||||||
access_rtl['sw_write'][0].append(
|
|
||||||
Field.templ_dict['sw_access_byte']['rtl'].format(
|
|
||||||
path = self.path_underscored,
|
|
||||||
genvars = self.genvars_str,
|
|
||||||
i = i,
|
|
||||||
msb_bus = str(8*(i+1)-1 if i != self.msbyte else self.obj.msb),
|
|
||||||
bus_w = str(8 if i != self.msbyte else self.obj.width-(8*j)),
|
|
||||||
msb_field = str(8*(j+1)-1 if i != self.msbyte else self.obj.width-1),
|
|
||||||
field_w = str(8 if i != self.msbyte else self.obj.width-(8*j))))
|
|
||||||
|
|
||||||
access_rtl['sw_write'][0].append("end")
|
|
||||||
|
|
||||||
onread = self.obj.get_property('onread')
|
|
||||||
|
|
||||||
access_rtl['sw_read'] = ([], False)
|
|
||||||
if self.sw_access in (AccessType.rw, AccessType.r) and onread:
|
|
||||||
if onread == OnReadType.ruser:
|
|
||||||
self.logger.warning("The OnReadType.ruser is not yet supported!")
|
|
||||||
else:
|
|
||||||
access_rtl['sw_read'][0].append(
|
|
||||||
Field.templ_dict[str(onread)]['rtl'].format(
|
|
||||||
width = self.obj.width,
|
|
||||||
path = self.path_underscored,
|
|
||||||
genvars = self.genvars_str,
|
|
||||||
path_wo_field = self.path_wo_field
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Add singlepulse property
|
|
||||||
if self.obj.get_property('singlepulse'):
|
|
||||||
access_rtl['singlepulse'] = ([
|
|
||||||
Field.templ_dict['singlepulse']['rtl'].format(
|
|
||||||
path = self.path_underscored,
|
|
||||||
genvars = self.genvars_str)
|
|
||||||
],
|
|
||||||
True)
|
|
||||||
else:
|
|
||||||
access_rtl['singlepulse'] = ([], False)
|
|
||||||
|
|
||||||
# Define else
|
|
||||||
access_rtl['else'] = (["else"], False)
|
|
||||||
|
|
||||||
# Add empty string
|
|
||||||
access_rtl[''] = ([''], False)
|
|
||||||
|
|
||||||
# Check if hardware has precedence (default `precedence = sw`)
|
|
||||||
if self.precedence == PrecedenceType.sw:
|
|
||||||
order_list = [
|
|
||||||
'sw_write',
|
|
||||||
'sw_read',
|
|
||||||
'hw_write',
|
|
||||||
'singlepulse'
|
|
||||||
]
|
|
||||||
else:
|
|
||||||
order_list = [
|
|
||||||
'hw_write',
|
|
||||||
'sw_write',
|
|
||||||
'sw_read',
|
|
||||||
'singlepulse'
|
|
||||||
]
|
|
||||||
|
|
||||||
# Add appropriate else
|
|
||||||
order_list_rtl = []
|
|
||||||
abort_set = False
|
|
||||||
|
|
||||||
for i in order_list:
|
|
||||||
# Still a loop and not a list comprehension since this might
|
|
||||||
# get longer in the future and thus become unreadable
|
|
||||||
if len(access_rtl[i][0]) and not abort_set:
|
|
||||||
order_list_rtl = [*order_list_rtl, *access_rtl[i][0]]
|
|
||||||
order_list_rtl.append("else")
|
|
||||||
|
|
||||||
# If he access_rtl entry has an abortion entry, do not print
|
|
||||||
# any further branches of the conditional block
|
|
||||||
abort_set = access_rtl[i][1]
|
|
||||||
|
|
||||||
# Remove last else
|
|
||||||
order_list_rtl.pop()
|
|
||||||
|
|
||||||
# Chain access RTL to the rest of the RTL
|
|
||||||
self.rtl_header = [*self.rtl_header, *order_list_rtl]
|
|
||||||
|
|
||||||
self.rtl_header.append(
|
|
||||||
Field.templ_dict['end_field_ff']['rtl'].format(
|
|
||||||
path = self.path_underscored))
|
|
||||||
|
|
||||||
|
|
||||||
def __add_ports(self):
|
|
||||||
if self.hw_access in (AccessType.rw, AccessType.r):
|
|
||||||
# Connect flops to output port
|
|
||||||
self.rtl_header.append(
|
|
||||||
Field.templ_dict['out_port_assign']['rtl'].format(
|
|
||||||
genvars = self.genvars_str,
|
|
||||||
path = self.path_underscored))
|
|
||||||
|
|
||||||
self.yaml_signals_to_list(Field.templ_dict['out_port_assign'])
|
|
||||||
|
|
||||||
def sanity_checks(self):
|
def sanity_checks(self):
|
||||||
# If hw=rw/sw=[r]w and hw has no we/wel, sw will never be able to write
|
# If hw=rw/sw=[r]w and hw has no we/wel, sw will never be able to write
|
||||||
if not self.we_or_wel and\
|
if not self.we_or_wel and\
|
||||||
self.precedence == PrecedenceType.hw and \
|
self.obj.get_property('precedence') == PrecedenceType.hw and \
|
||||||
self.hw_access in (AccessType.rw, AccessType.w) and \
|
self.obj.get_property('hw') in (AccessType.rw, AccessType.w) and \
|
||||||
self.sw_access in (AccessType.rw, AccessType.w):
|
self.obj.get_property('sw') in (AccessType.rw, AccessType.w):
|
||||||
|
|
||||||
self.logger.warning("Fields with hw=rw/sw=[r]w, we/wel not set and "\
|
self.logger.warning("Fields with hw=rw/sw=[r]w, we/wel not set and "\
|
||||||
"precedence for hardware will render software's "\
|
"precedence for hardware will render software's "\
|
||||||
|
@ -34,18 +34,23 @@ class RegFile(Component):
|
|||||||
# Create comment and provide user information about register he/she
|
# Create comment and provide user information about register he/she
|
||||||
# is looking at.
|
# is looking at.
|
||||||
self.rtl_header = [
|
self.rtl_header = [
|
||||||
RegFile.templ_dict['regfile_comment']['rtl'].format(
|
self.process_yaml(
|
||||||
name = obj.inst_name,
|
RegFile.templ_dict['regfile_comment'],
|
||||||
dimensions = self.dimensions,
|
{'name': obj.inst_name,
|
||||||
depth = self.depth),
|
'dimensions': self.dimensions,
|
||||||
*self.rtl_header
|
'depth': self.depth}
|
||||||
|
),
|
||||||
|
*self.rtl_header
|
||||||
]
|
]
|
||||||
|
|
||||||
# Create generate block for register and add comment
|
# Create generate block for register and add comment
|
||||||
for i in range(self.dimensions-1, -1, -1):
|
for i in range(self.dimensions-1, -1, -1):
|
||||||
self.rtl_footer.append(
|
self.rtl_footer.append(
|
||||||
RegFile.templ_dict['generate_for_end']['rtl'].format(
|
self.process_yaml(
|
||||||
dimension = chr(97+i)))
|
RegFile.templ_dict['generate_for_end'],
|
||||||
|
{'dimension': chr(97+i)}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
if self.dimensions and not glbl_settings['generate_active']:
|
if self.dimensions and not glbl_settings['generate_active']:
|
||||||
self.rtl_header.append("generate")
|
self.rtl_header.append("generate")
|
||||||
@ -56,15 +61,18 @@ class RegFile(Component):
|
|||||||
|
|
||||||
for i in range(self.dimensions):
|
for i in range(self.dimensions):
|
||||||
self.rtl_header.append(
|
self.rtl_header.append(
|
||||||
RegFile.templ_dict['generate_for_start']['rtl'].format(
|
self.process_yaml(
|
||||||
iterator = chr(97+i+self.parents_depths),
|
RegFile.templ_dict['generate_for_start'],
|
||||||
limit = self.array_dimensions[i]))
|
{'iterator': chr(97+i+self.parents_depths),
|
||||||
|
'limit': self.array_dimensions[i]}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
# Empty dictionary of register objects
|
# Empty dictionary of register objects
|
||||||
# We need a dictionary since it might be required to access the objects later
|
# We need a dictionary since it might be required to access the objects later
|
||||||
# by name (for example, in case of aliases)
|
# by name (for example, in case of aliases)
|
||||||
self.registers = dict()
|
self.registers = dict()
|
||||||
self.regfiles = []
|
self.regfiles = dict()
|
||||||
|
|
||||||
# Set object to 0 for easy addressing
|
# Set object to 0 for easy addressing
|
||||||
self.obj.current_idx = [0]
|
self.obj.current_idx = [0]
|
||||||
@ -79,19 +87,20 @@ class RegFile(Component):
|
|||||||
elif isinstance(child, node.RegfileNode):
|
elif isinstance(child, node.RegfileNode):
|
||||||
self.obj.current_idx = [0]
|
self.obj.current_idx = [0]
|
||||||
|
|
||||||
self.regfiles.append(
|
self.regfiles[child.inst_name] = \
|
||||||
RegFile(
|
RegFile(
|
||||||
child,
|
child,
|
||||||
self.total_array_dimensions,
|
self.total_array_dimensions,
|
||||||
self.total_stride,
|
self.total_stride,
|
||||||
config,
|
config,
|
||||||
glbl_settings))
|
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
|
||||||
# new register. Rather, we bury up the old register and add
|
# new register. Rather, we bury up the old register and add
|
||||||
# additional properties
|
# additional properties
|
||||||
self.logger.error('Alias registers are not implemented yet!')
|
self.registers[child.inst.alias_primary_inst.inst_name]\
|
||||||
|
.add_alias(child)
|
||||||
else:
|
else:
|
||||||
self.obj.current_idx = [0]
|
self.obj.current_idx = [0]
|
||||||
self.registers[child.inst_name] = \
|
self.registers[child.inst_name] = \
|
||||||
@ -104,10 +113,7 @@ class RegFile(Component):
|
|||||||
|
|
||||||
# Add registers to children. This must be done in a last step
|
# Add registers to children. This must be done in a last step
|
||||||
# to account for all possible alias combinations
|
# to account for all possible alias combinations
|
||||||
self.children = [
|
self.children = {**self.regfiles, **self.registers}
|
||||||
*self.regfiles,
|
|
||||||
*[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")
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import importlib.resources as pkg_resources
|
import importlib.resources as pkg_resources
|
||||||
import yaml
|
|
||||||
import math
|
import math
|
||||||
|
import sys
|
||||||
|
import yaml
|
||||||
|
|
||||||
from systemrdl import node
|
from systemrdl import node
|
||||||
|
|
||||||
@ -25,43 +26,59 @@ class Register(Component):
|
|||||||
super().__init__(obj, config)
|
super().__init__(obj, config)
|
||||||
|
|
||||||
# Save and/or process important variables
|
# Save and/or process important variables
|
||||||
self.__process_variables(obj, parents_dimensions, parents_stride)
|
self.__process_variables(obj, parents_dimensions, parents_stride, glbl_settings)
|
||||||
|
|
||||||
# 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.total_array_dimensions, config, glbl_settings)
|
# 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,
|
||||||
|
config,
|
||||||
|
glbl_settings)
|
||||||
|
|
||||||
if not config['disable_sanity']:
|
if not config['disable_sanity']:
|
||||||
field_obj.sanity_checks()
|
self.children[field_range].sanity_checks()
|
||||||
|
|
||||||
self.children.append(field_obj)
|
|
||||||
|
|
||||||
|
def create_rtl(self):
|
||||||
# Create generate block for register and add comment
|
# Create generate block for register and add comment
|
||||||
if self.dimensions and not glbl_settings['generate_active']:
|
if self.dimensions and not self.generate_active:
|
||||||
self.rtl_header.append("generate")
|
self.rtl_header.append("generate")
|
||||||
glbl_settings['generate_active'] = True
|
|
||||||
self.generate_initiated = True
|
|
||||||
else:
|
|
||||||
self.generate_initiated = False
|
|
||||||
|
|
||||||
|
# Add N layers of for-loop starts
|
||||||
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+self.parents_depths),
|
iterator = chr(97+i+self.parents_depths),
|
||||||
limit = self.array_dimensions[i]))
|
limit = self.array_dimensions[i]))
|
||||||
|
|
||||||
|
# Add decoders for all registers & aliases
|
||||||
|
self.__add_address_decoder()
|
||||||
|
|
||||||
# End loops
|
# Fields will be added by get_rtl()
|
||||||
|
|
||||||
|
# Add N layers of for-loop end
|
||||||
for i in range(self.dimensions-1, -1, -1):
|
for i in range(self.dimensions-1, -1, -1):
|
||||||
self.rtl_footer.append(
|
self.rtl_footer.append(
|
||||||
Register.templ_dict['generate_for_end'].format(
|
Register.templ_dict['generate_for_end'].format(
|
||||||
dimension = chr(97+i)))
|
dimension = chr(97+i)))
|
||||||
|
|
||||||
if self.generate_initiated:
|
if self.dimensions and not self.generate_active:
|
||||||
glbl_settings['generate_active'] = False
|
self.rtl_footer.append("endgenerate\n")
|
||||||
self.rtl_footer.append("endgenerate")
|
|
||||||
|
|
||||||
|
# Create comment and provide user information about register he/she is looking at
|
||||||
|
self.rtl_header = [
|
||||||
|
Register.templ_dict['reg_comment'].format(
|
||||||
|
name = obj.inst_name,
|
||||||
|
dimensions = self.dimensions,
|
||||||
|
depth = self.depth),
|
||||||
|
*self.rtl_header
|
||||||
|
]
|
||||||
|
|
||||||
|
def __add_address_decoder(self):
|
||||||
# Assign variables from bus
|
# Assign variables from bus
|
||||||
self.obj.current_idx = [0]
|
self.obj.current_idx = [0]
|
||||||
|
|
||||||
@ -70,15 +87,18 @@ class Register(Component):
|
|||||||
else:
|
else:
|
||||||
rw_wire_assign_field = 'rw_wire_assign_1_dim'
|
rw_wire_assign_field = 'rw_wire_assign_1_dim'
|
||||||
|
|
||||||
self.rtl_header.append(
|
[self.rtl_header.append(
|
||||||
Register.templ_dict[rw_wire_assign_field]['rtl'].format(
|
self.process_yaml(
|
||||||
path = self.path_underscored,
|
Register.templ_dict[rw_wire_assign_field],
|
||||||
addr = self.obj.absolute_address,
|
{'path': x[0],
|
||||||
genvars = self.genvars_str,
|
'addr': x[1],
|
||||||
genvars_sum =self.genvars_sum_str,
|
'alias': '(alias)' if i > 0 else '',
|
||||||
depth = self.depth))
|
'genvars': self.genvars_str,
|
||||||
|
'genvars_sum': self.genvars_sum_str,
|
||||||
self.yaml_signals_to_list(Register.templ_dict[rw_wire_assign_field])
|
'depth': self.depth,
|
||||||
|
'field_type': self.field_type}
|
||||||
|
)
|
||||||
|
) for i, x in enumerate(self.alias_names)]
|
||||||
|
|
||||||
# Add wire/register instantiations
|
# Add wire/register instantiations
|
||||||
dict_list = [(key, value) for (key, value) in self.get_signals().items()]
|
dict_list = [(key, value) for (key, value) in self.get_signals().items()]
|
||||||
@ -103,31 +123,48 @@ class Register(Component):
|
|||||||
*self.rtl_header,
|
*self.rtl_header,
|
||||||
]
|
]
|
||||||
|
|
||||||
# Create comment and provide user information about register he/she
|
def add_alias(self, obj: node.RegNode):
|
||||||
# is looking at.
|
for field in obj.fields():
|
||||||
self.rtl_header = [
|
# Use range to save field in an array. Reason is, names are allowed to
|
||||||
Register.templ_dict['reg_comment'].format(
|
# change when using an alias
|
||||||
name = obj.inst_name,
|
field_range = ':'.join(map(str, [field.msb, field.lsb]))
|
||||||
dimensions = self.dimensions,
|
|
||||||
depth = self.depth),
|
|
||||||
*self.rtl_header
|
|
||||||
]
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.children[field_range].add_sw_access(field, alias=True)
|
||||||
|
except KeyError:
|
||||||
|
self.logger.fatal("Range of field '{}' in alias register '{}' does "
|
||||||
|
"not correspond to range of field in original "
|
||||||
|
"register '{}'. This is illegal according to 10.5.1 b)"
|
||||||
|
"of the SystemRDL 2.0 LRM.". format(
|
||||||
|
field.inst_name,
|
||||||
|
obj.inst_name,
|
||||||
|
self.name))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Add name to list
|
||||||
|
self.obj.current_idx = [0]
|
||||||
|
self.alias_names.append((self.create_underscored_path_static(obj)[3], obj.absolute_address))
|
||||||
|
|
||||||
def __process_variables(
|
def __process_variables(
|
||||||
self,
|
self,
|
||||||
obj: node.RegNode,
|
obj: node.RegNode,
|
||||||
parents_dimensions: list,
|
parents_dimensions: list,
|
||||||
parents_stride: list):
|
parents_stride: list,
|
||||||
|
glbl_settings: dict):
|
||||||
# Save object
|
# Save object
|
||||||
self.obj = obj
|
self.obj = obj
|
||||||
|
|
||||||
# Save name
|
# Save name
|
||||||
|
self.obj.current_idx = [0]
|
||||||
self.name = obj.inst_name
|
self.name = obj.inst_name
|
||||||
|
self.alias_names = [(self.create_underscored_path_static(obj)[3], obj.absolute_address)]
|
||||||
|
|
||||||
# Create full name
|
# Create full name
|
||||||
self.create_underscored_path()
|
self.create_underscored_path()
|
||||||
|
|
||||||
|
# Gnerate already started?
|
||||||
|
self.generate_active = glbl_settings['generate_active']
|
||||||
|
|
||||||
# Determine dimensions of register
|
# Determine dimensions of register
|
||||||
if obj.is_array:
|
if obj.is_array:
|
||||||
self.sel_arr = 'array'
|
self.sel_arr = 'array'
|
||||||
|
@ -33,7 +33,9 @@ sw_access_byte:
|
|||||||
begin
|
begin
|
||||||
{path}_q{genvars}[{msb_field}-:{field_w}] <= sw_wr_bus[{msb_bus}-:{bus_w}];
|
{path}_q{genvars}[{msb_field}-:{field_w}] <= sw_wr_bus[{msb_bus}-:{bus_w}];
|
||||||
end
|
end
|
||||||
|
signals:
|
||||||
|
- name: '{path}_q'
|
||||||
|
signal_type: '{field_type}'
|
||||||
hw_access_we_wel:
|
hw_access_we_wel:
|
||||||
rtl: |-
|
rtl: |-
|
||||||
if ({negl}{path}_hw_wr{genvars})
|
if ({negl}{path}_hw_wr{genvars})
|
||||||
|
@ -1,34 +1,31 @@
|
|||||||
---
|
---
|
||||||
rw_wire_assign_1_dim:
|
rw_wire_assign_1_dim:
|
||||||
rtl: |
|
rtl: |
|
||||||
// Assign register-activation signals
|
// Register-activation for '{path}' {alias}
|
||||||
assign {path}_reg_active{genvars} = addr == {addr};
|
assign {path}_accss = addr == {addr};
|
||||||
|
assign {path}_sw_wr = {path}_accss && r_vld;
|
||||||
assign {path}_sw_wr = {path}_reg_active && r_vld;
|
assign {path}_sw_rd = {path}_accss && w_vld;
|
||||||
assign {path}_sw_rd = {path}_reg_active && w_vld;
|
|
||||||
signals:
|
signals:
|
||||||
- name: '{path}_sw_wr'
|
- name: '{path}_sw_wr'
|
||||||
signal_type: 'logic'
|
signal_type: 'logic'
|
||||||
- name: '{path}_sw_rd'
|
- name: '{path}_sw_rd'
|
||||||
signal_type: 'logic'
|
signal_type: 'logic'
|
||||||
- name: '{path}_reg_active'
|
- name: '{path}_accss'
|
||||||
signal_type: 'logic'
|
signal_type: 'logic'
|
||||||
input_ports:
|
input_ports:
|
||||||
output_ports:
|
output_ports:
|
||||||
rw_wire_assign_multi_dim:
|
rw_wire_assign_multi_dim:
|
||||||
rtl: |
|
rtl: |
|
||||||
|
// Register-activation for '{path}' {alias}
|
||||||
// Assign register-activation signals
|
assign {path}_accss{genvars} = addr == {addr}+({genvars_sum});
|
||||||
assign {path}_reg_active{genvars} = addr == {addr}+({genvars_sum});
|
assign {path}_sw_wr{genvars} = {path}_accss{genvars} && r_vld;
|
||||||
|
assign {path}_sw_rd{genvars} = {path}_accss{genvars} && w_vld;
|
||||||
assign {path}_sw_wr{genvars} = {path}_reg_active{genvars} && r_vld;
|
|
||||||
assign {path}_sw_rd{genvars} = {path}_reg_active{genvars} && w_vld;
|
|
||||||
signals:
|
signals:
|
||||||
- name: '{path}_sw_wr'
|
- name: '{path}_sw_wr'
|
||||||
signal_type: 'logic'
|
signal_type: 'logic'
|
||||||
- name: '{path}_sw_rd'
|
- name: '{path}_sw_rd'
|
||||||
signal_type: 'logic'
|
signal_type: 'logic'
|
||||||
- name: '{path}_reg_active'
|
- name: '{path}_accss'
|
||||||
signal_type: 'logic'
|
signal_type: 'logic'
|
||||||
input_ports:
|
input_ports:
|
||||||
output_ports:
|
output_ports:
|
||||||
|
Loading…
Reference in New Issue
Block a user