mirror of
https://github.com/Silicon1602/srdl2sv.git
synced 2024-12-22 15:08:39 +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')
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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')
|
||||||
|
@ -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()
|
||||||
|
@ -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: |-
|
||||||
|
Loading…
Reference in New Issue
Block a user