mirror of
https://github.com/Silicon1602/srdl2sv.git
synced 2024-11-13 02:53:37 +00:00
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:
parent
44c87af8cb
commit
2a3cc9505e
@ -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)
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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')
|
||||
|
@ -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()
|
||||
|
@ -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: |-
|
||||
|
Loading…
Reference in New Issue
Block a user