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')
# 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
# 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()
self.rdl_nodes = dict()
# Traverse through children
for child in 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):
@ -49,7 +56,8 @@ class AddrMap(Component):
# additional properties
self.logger.error('Alias registers are not implemented yet!')
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
self.children = [x for x in self.registers.values()]
@ -59,6 +67,13 @@ class AddrMap(Component):
# Start assembling addrmap module
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
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()]
@ -110,6 +125,7 @@ class AddrMap(Component):
self.rtl_header.append(
AddrMap.templ_dict['module_declaration'].format(
name = obj.inst_name,
resets = '\n'.join(reset_ports_rtl),
inputs = '\n'.join(input_ports_rtl),
outputs = '\n'.join(output_ports_rtl)))
@ -126,3 +142,43 @@ class AddrMap(Component):
self.path_underscored = self.path.replace('.', '_')
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.typedef = dict()
self.ports = dict()
self.resets = set()
self.signals = dict()
self.ports['input'] = dict()
self.ports['output'] = dict()
@ -31,6 +32,14 @@ class Component():
file_name=config['file_log_location'])
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):
self.logger.debug("Return port list")
@ -169,3 +178,29 @@ class Component():
self.array_dimensions)
except (TypeError, KeyError):
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'),
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__()
# Save and/or process important variables
self.__process_variables(obj, array_dimensions)
self.__process_variables(obj, array_dimensions, glbl_settings)
# Create logger object
self.create_logger("{}.{}".format(self.owning_addrmap, self.path), config)
@ -136,7 +136,7 @@ class Field(Component):
else:
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
self.obj = obj
@ -168,32 +168,22 @@ class Field(Component):
# the reset value, and whether the field actually has a reset
self.rst = dict()
try:
rst_signal = obj.get_property("resetsignal")
reset_signal = obj.get_property("resetsignal")
self.rst['name'] = rst_signal.inst_name
self.rst['async'] = rst_signal.get_property("async")
self.rst['type'] = "asynchronous" if self.rst['async'] else "synchronous"
if (reset_signal):
self.rst = Field.process_reset_signal(reset_signal)
else:
# Only use global reset (if present) if no local reset is set
self.rst = glbl_settings['field_reset']
# Active low or active high?
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"
self.resets.add(self.rst['name'])
# Value of reset?
self.rst['value'] = '\'x' if obj.get_property("reset") == None else\
obj.get_property('reset')
except:
self.rst['async'] = False
self.rst['name'] = None
self.rst['edge'] = None
self.rst['value'] = "'x"
self.rst['active'] = "-"
self.rst['type'] = "-"
# Value of reset must always be determined on field level
self.rst['value'] = \
'\'x' if obj.get_property("reset") == None else\
obj.get_property('reset')
# Define hardware access
self.hw_access = obj.get_property('hw')
self.sw_access = obj.get_property('sw')
self.precedence = obj.get_property('precedence')

View File

@ -1,8 +1,7 @@
import importlib.resources as pkg_resources
import yaml
from systemrdl import RDLCompiler, RDLCompileError, RDLWalker, RDLListener, node
from systemrdl.node import FieldNode
from systemrdl import node
# Local modules
from components.component import Component
@ -15,7 +14,7 @@ class Register(Component):
pkg_resources.read_text(templates, 'regs.yaml'),
Loader=yaml.FullLoader)
def __init__(self, obj: node.RootNode, config: dict):
def __init__(self, obj: node.RootNode, config: dict, glbl_settings: dict):
super().__init__()
# Save and/or process important variables
@ -28,7 +27,7 @@ class Register(Component):
# Create RTL for fields
# Fields should be in order in RTL,therefore, use list
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']:
field_obj.sanity_checks()

View File

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