Add support for field_reset and cpuif_reset

These two special kind of resets are now recognized by the compiler and
are propagated to all regfiles, registers, and fields.

Furthermore, every object has a set of resets which will be used to
generate a seperate input section for resets in the addrmap.
This commit is contained in:
Dennis Potter 2021-05-24 14:42:24 +02:00
parent 44c87af8cb
commit 2a3cc9505e
Signed by: Dennis
GPG Key ID: 186A8AD440942BAF
5 changed files with 118 additions and 31 deletions

View File

@ -29,15 +29,22 @@ class AddrMap(Component):
template = pkg_resources.read_text(templates, 'addrmap.sv') template = pkg_resources.read_text(templates, 'addrmap.sv')
# Check if global resets are defined
glbl_settings = dict()
(glbl_settings['field_reset'], glbl_settings['cpuif_reset']) = \
self.__process_global_resets()
# 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.rdl_nodes = dict()
# Traverse through children # Traverse through children
for child in obj.children(): for child in obj.children():
if isinstance(child, node.AddrmapNode): 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.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):
@ -49,7 +56,8 @@ class AddrMap(Component):
# additional properties # additional properties
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] = Register(child, config) self.registers[child.inst_name] = \
Register(child, config, glbl_settings)
# Add regfiles and registers to children # Add regfiles and registers to children
self.children = [x for x in self.registers.values()] self.children = [x for x in self.registers.values()]
@ -59,6 +67,13 @@ class AddrMap(Component):
# 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/inout ports")
# Reset ports
reset_ports_rtl = [
AddrMap.templ_dict['reset_port'].format(
name = name)
for name in [x for x in self.get_resets()]
]
# Prefetch dictionaries in local array # Prefetch dictionaries in local array
input_dict_list = [(key, value) for (key, value) in self.get_ports('input').items()] input_dict_list = [(key, value) for (key, value) in self.get_ports('input').items()]
output_dict_list = [(key, value) for (key, value) in self.get_ports('output').items()] output_dict_list = [(key, value) for (key, value) in self.get_ports('output').items()]
@ -110,6 +125,7 @@ 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 = obj.inst_name,
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)))
@ -126,3 +142,43 @@ class AddrMap(Component):
self.path_underscored = self.path.replace('.', '_') self.path_underscored = self.path.replace('.', '_')
self.name = obj.inst_name self.name = obj.inst_name
def __process_global_resets(self):
field_reset_list = \
[x for x in self.obj.signals() if x.get_property('field_reset')]
cpuif_reset_list = \
[x for x in self.obj.signals() if x.get_property('cpuif_reset')]
if field_reset_list:
rst_name = field_reset_list[0].inst_name
self.logger.info("Found field_reset signal '{}'".format(rst_name))
# Save to set to generate input
self.resets.add(rst_name)
# Save position 0 of list
field_reset_item = field_reset_list[0]
else:
field_reset_item = None
if cpuif_reset_list:
rst_name = cpuif_reset_list[0].inst_name
self.logger.info("Found cpuif_reset signal '{}'".format(rst_name))
# Save to set to generate input
self.resets.add(rst_name)
# Save position 0 of list
cpuif_reset_item = cpuif_reset_list[0]
else:
cpuif_reset_item = None
# Method is only called once on a global level. Otherwise, process_reset_signal
# is called several times to calculate the dictionary, although it will always
# return the same result.
field_reset = AddrMap.process_reset_signal(field_reset_item)
cpuif_reset = AddrMap.process_reset_signal(cpuif_reset_item)
return (field_reset, cpuif_reset)

View File

@ -18,6 +18,7 @@ class Component():
self.children = [] self.children = []
self.typedef = dict() self.typedef = dict()
self.ports = dict() self.ports = dict()
self.resets = set()
self.signals = dict() self.signals = dict()
self.ports['input'] = dict() self.ports['input'] = dict()
self.ports['output'] = dict() self.ports['output'] = dict()
@ -31,6 +32,14 @@ class Component():
file_name=config['file_log_location']) file_name=config['file_log_location'])
self.logger.propagate = False self.logger.propagate = False
def get_resets(self):
self.logger.debug("Return reset list")
for x in self.children:
self.resets |= x.get_resets()
return self.resets
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")
@ -169,3 +178,29 @@ class Component():
self.array_dimensions) self.array_dimensions)
except (TypeError, KeyError): except (TypeError, KeyError):
pass pass
@staticmethod
def process_reset_signal(reset_signal):
rst = dict()
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

View File

@ -16,11 +16,11 @@ 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): def __init__(self, obj: FieldNode, array_dimensions: list, config:dict, glbl_settings: dict):
super().__init__() super().__init__()
# Save and/or process important variables # Save and/or process important variables
self.__process_variables(obj, array_dimensions) self.__process_variables(obj, array_dimensions, glbl_settings)
# 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)
@ -136,7 +136,7 @@ class Field(Component):
else: else:
self.field_type = 'logic' self.field_type = 'logic'
def __process_variables(self, obj: FieldNode, array_dimensions: list): def __process_variables(self, obj: FieldNode, array_dimensions: list, glbl_settings: dict):
# Save object # Save object
self.obj = obj self.obj = obj
@ -168,32 +168,22 @@ class Field(Component):
# the reset value, and whether the field actually has a reset # the reset value, and whether the field actually has a reset
self.rst = dict() self.rst = dict()
try: reset_signal = obj.get_property("resetsignal")
rst_signal = obj.get_property("resetsignal")
self.rst['name'] = rst_signal.inst_name if (reset_signal):
self.rst['async'] = rst_signal.get_property("async") self.rst = Field.process_reset_signal(reset_signal)
self.rst['type'] = "asynchronous" if self.rst['async'] else "synchronous" else:
# Only use global reset (if present) if no local reset is set
self.rst = glbl_settings['field_reset']
# Active low or active high? self.resets.add(self.rst['name'])
if rst_signal.get_property("activelow"):
self.rst['edge'] = "negedge"
self.rst['active'] = "active_low"
else:
self.rst['edge'] = "posedge"
self.rst['active'] = "active_high"
# Value of reset? # Value of reset must always be determined on field level
self.rst['value'] = '\'x' if obj.get_property("reset") == None else\ self.rst['value'] = \
obj.get_property('reset') '\'x' if obj.get_property("reset") == None else\
except: obj.get_property('reset')
self.rst['async'] = False
self.rst['name'] = None
self.rst['edge'] = None
self.rst['value'] = "'x"
self.rst['active'] = "-"
self.rst['type'] = "-"
# Define hardware access
self.hw_access = obj.get_property('hw') self.hw_access = obj.get_property('hw')
self.sw_access = obj.get_property('sw') self.sw_access = obj.get_property('sw')
self.precedence = obj.get_property('precedence') self.precedence = obj.get_property('precedence')

View File

@ -1,8 +1,7 @@
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
# Local modules # Local modules
from components.component import Component from components.component import Component
@ -15,7 +14,7 @@ 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): def __init__(self, obj: node.RootNode, config: dict, glbl_settings: dict):
super().__init__() super().__init__()
# Save and/or process important variables # Save and/or process important variables
@ -28,7 +27,7 @@ class Register(Component):
# 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) field_obj = Field(field, self.array_dimensions, config, glbl_settings)
if not config['disable_sanity']: if not config['disable_sanity']:
field_obj.sanity_checks() field_obj.sanity_checks()

View File

@ -1,6 +1,11 @@
--- ---
module_declaration: |- module_declaration: |-
module {name} ( module {name} (
// Clock & Resets
input reg_clk,
input bus_clk,
{resets}
// Bus I/O // Bus I/O
// TODO // TODO
@ -10,6 +15,8 @@ module_declaration: |-
// Outputs // Outputs
{outputs} {outputs}
); );
reset_port: |-
input {name},
input_port: |- input_port: |-
input {signal_type:{signal_width}} {name:{name_width}}{unpacked_dim}, input {signal_type:{signal_width}} {name:{name_width}}{unpacked_dim},
output_port: |- output_port: |-