mirror of
https://github.com/Silicon1602/srdl2sv.git
synced 2024-11-14 03:03:35 +00:00
Fundamental changes to the architecture of component classes
All components (e.g., fields, registers, addrmaps) are now children of a common class Component. This common class has certain common methods such as get_ports(), get_rtl(), or create_logger(). The AddrMap is now prepared to support alias registers by saving the registers in a dictionary. That way, registers can easily be accessed once an alias to a register is found. Furthermore, the addrmap template is now also loaded from a YAML file. Lastly, the first preparements to insert ports into the addrmap module are made. For templates, the indents do not need to be added anymore to the template. Now, a seperate method will automatically indent the RTL based on simple rules (e.g., increment indent if `begin` is found). The CLI also supports settings for the tabs (i.e., real tabs or spaces and the tab width). A lot of functionality from the __init__() method of the field class got reorganized. More logic will be reorganized in the future.
This commit is contained in:
parent
59b91536ed
commit
cecb73f07a
@ -19,20 +19,6 @@ class CliArguments():
|
|||||||
self.parser = argparse.ArgumentParser(
|
self.parser = argparse.ArgumentParser(
|
||||||
description="SystemRDL 2 SystemVerilog compiler")
|
description="SystemRDL 2 SystemVerilog compiler")
|
||||||
|
|
||||||
self.parser.add_argument(
|
|
||||||
"--stream_log_level",
|
|
||||||
choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL', 'NONE'],
|
|
||||||
default='WARNING',
|
|
||||||
help="Set verbosity level of output to shell. When set to 'NONE',\
|
|
||||||
nothing will be printed to the shell. (default: %(default)s)")
|
|
||||||
|
|
||||||
self.parser.add_argument(
|
|
||||||
"--file_log_level",
|
|
||||||
choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL', 'NONE'],
|
|
||||||
default='INFO',
|
|
||||||
help="Set verbosity level of output to log-file. When set to 'NONE',\
|
|
||||||
nothing will be printed to the shell. (default: %(default)s)")
|
|
||||||
|
|
||||||
self.parser.add_argument(
|
self.parser.add_argument(
|
||||||
"-o",
|
"-o",
|
||||||
"--out_dir",
|
"--out_dir",
|
||||||
@ -55,7 +41,41 @@ class CliArguments():
|
|||||||
"--recursive_search",
|
"--recursive_search",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="If set, the dependency directories will be\
|
help="If set, the dependency directories will be\
|
||||||
searched recursively.");
|
searched recursively.")
|
||||||
|
|
||||||
|
self.parser.add_argument(
|
||||||
|
"-x",
|
||||||
|
"--disable_sanity",
|
||||||
|
action="store_true",
|
||||||
|
help="Disable sanity checks or components. This might speed\
|
||||||
|
up the compiler but is generally not recommended!")
|
||||||
|
|
||||||
|
self.parser.add_argument(
|
||||||
|
"--stream_log_level",
|
||||||
|
choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL', 'NONE'],
|
||||||
|
default='WARNING',
|
||||||
|
help="Set verbosity level of output to shell. When set to 'NONE',\
|
||||||
|
nothing will be printed to the shell. (default: %(default)s)")
|
||||||
|
|
||||||
|
self.parser.add_argument(
|
||||||
|
"--file_log_level",
|
||||||
|
choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL', 'NONE'],
|
||||||
|
default='INFO',
|
||||||
|
help="Set verbosity level of output to log-file. When set to 'NONE',\
|
||||||
|
nothing will be printed to the shell. (default: %(default)s)")
|
||||||
|
|
||||||
|
self.parser.add_argument(
|
||||||
|
"--real_tabs",
|
||||||
|
action="store_true",
|
||||||
|
help="Use tabs, rather than spaces, for tabs")
|
||||||
|
|
||||||
|
self.parser.add_argument(
|
||||||
|
"--tab_width",
|
||||||
|
type=int,
|
||||||
|
default=4,
|
||||||
|
help="Define how many tabs or spaces will be contained\
|
||||||
|
in one level of indentation. (default: %(default)s)")
|
||||||
|
|
||||||
|
|
||||||
self.parser.add_argument(
|
self.parser.add_argument(
|
||||||
"IN_RDL",
|
"IN_RDL",
|
||||||
@ -91,4 +111,11 @@ class CliArguments():
|
|||||||
ts = time.strftime('%Y%m%d_%H%M%S', config['ts'])
|
ts = time.strftime('%Y%m%d_%H%M%S', config['ts'])
|
||||||
config['file_log_location'] = "srdl2sv_{}.log".format(ts)
|
config['file_log_location'] = "srdl2sv_{}.log".format(ts)
|
||||||
|
|
||||||
|
# Tab style
|
||||||
|
config['real_tabs'] = args.real_tabs
|
||||||
|
config['tab_width'] = args.tab_width
|
||||||
|
|
||||||
|
# Sanity check related
|
||||||
|
config['disable_sanity'] = args.disable_sanity
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
@ -1,56 +1,101 @@
|
|||||||
import yaml
|
|
||||||
import re
|
import re
|
||||||
|
import importlib.resources as pkg_resources
|
||||||
|
import yaml
|
||||||
|
|
||||||
from systemrdl import RDLCompiler, RDLCompileError, RDLWalker, RDLListener, node
|
from systemrdl import RDLCompiler, RDLCompileError, RDLWalker, RDLListener, node
|
||||||
from systemrdl.node import FieldNode
|
from systemrdl.node import FieldNode
|
||||||
|
|
||||||
# Local packages
|
# Local packages
|
||||||
|
from components.component import Component
|
||||||
from components.register import Register
|
from components.register import Register
|
||||||
from log.log import create_logger
|
from log.log import create_logger
|
||||||
from . import templates
|
from . import templates
|
||||||
|
|
||||||
# Import templates
|
|
||||||
try:
|
|
||||||
import importlib.resources as pkg_resources
|
|
||||||
except ImportError:
|
|
||||||
# Try backported to PY<37 `importlib_resources`.
|
|
||||||
import importlib_resources as pkg_resources
|
|
||||||
|
|
||||||
class AddrMap:
|
class AddrMap(Component):
|
||||||
def __init__(self, rdlc: RDLCompiler, obj: node.RootNode, config: dict):
|
# Save YAML template as class variable
|
||||||
|
templ_dict = yaml.load(
|
||||||
|
pkg_resources.read_text(templates, 'addrmap.yaml'),
|
||||||
|
Loader=yaml.FullLoader)
|
||||||
|
|
||||||
self.rdlc = rdlc
|
def __init__(self, obj: node.RootNode, config: dict):
|
||||||
self.name = obj.inst_name
|
super().__init__()
|
||||||
|
|
||||||
|
# Save and/or process important variables
|
||||||
|
self.__process_variables(obj)
|
||||||
|
|
||||||
# Create logger object
|
# Create logger object
|
||||||
self.logger = create_logger(
|
self.create_logger(self.path, config)
|
||||||
"{}.{}".format(__name__, obj.inst_name),
|
self.logger.debug('Starting to process addrmap')
|
||||||
stream_log_level=config['stream_log_level'],
|
|
||||||
file_log_level=config['file_log_level'],
|
|
||||||
file_name=config['file_log_location'])
|
|
||||||
|
|
||||||
self.logger.debug('Starting to process addrmap "{}"'.format(obj.inst_name))
|
|
||||||
|
|
||||||
template = pkg_resources.read_text(templates, 'addrmap.sv')
|
template = pkg_resources.read_text(templates, 'addrmap.sv')
|
||||||
|
|
||||||
# Read template for SystemVerilog module
|
# Empty dictionary of register objects
|
||||||
tmpl_addrmap = re.compile("{addrmap_name}")
|
# We need a dictionary since it might be required to access the objects later
|
||||||
self.rtl = tmpl_addrmap.sub(obj.inst_name, template)
|
# by name (for example, in case of aliases)
|
||||||
|
self.registers = dict()
|
||||||
# Empty list of register logic
|
|
||||||
self.registers = set()
|
|
||||||
|
|
||||||
# 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):
|
||||||
pass
|
self.logger.info('Found hierarchical addrmap. Entering it...')
|
||||||
|
self.logger.error('Child addrmaps are not implemented yet!')
|
||||||
elif isinstance(child, node.RegfileNode):
|
elif isinstance(child, node.RegfileNode):
|
||||||
pass
|
self.logger.error('Regfiles are not implemented yet!')
|
||||||
elif isinstance(child, node.RegNode):
|
elif isinstance(child, node.RegNode):
|
||||||
self.registers.add(Register(child, config))
|
if child.inst.is_alias:
|
||||||
|
# If the node we found is an alias, we shall not create a
|
||||||
|
# new register. Rather, we bury up the old register and add
|
||||||
|
# additional properties
|
||||||
|
self.logger.error('Alias registers are not implemented yet!')
|
||||||
|
else:
|
||||||
|
self.registers[child.inst_name] = Register(child, config)
|
||||||
|
|
||||||
# TODO: Temporarily override RTL
|
# Add regfiles and registers to children
|
||||||
self.rtl = [x.get_rtl() for x in self.registers]
|
self.children = [x for x in self.registers.values()]
|
||||||
|
|
||||||
def get_rtl(self) -> str:
|
self.logger.info("Done generating all child-regfiles/registers")
|
||||||
return '\n'.join(self.rtl)
|
|
||||||
|
# Start assembling addrmap module
|
||||||
|
self.logger.info("Starting to assemble input/output/inout ports")
|
||||||
|
|
||||||
|
# Inout port
|
||||||
|
inout_ports_rtl = [
|
||||||
|
AddrMap.templ_dict['inout_port'].format(
|
||||||
|
name = x) for x in self.get_ports('inout')]
|
||||||
|
# Input ports
|
||||||
|
input_ports_rtl = [
|
||||||
|
AddrMap.templ_dict['input_port'].format(
|
||||||
|
name = x) for x in self.get_ports('input')]
|
||||||
|
# Output ports
|
||||||
|
output_ports_rtl = [
|
||||||
|
AddrMap.templ_dict['output_port'].format(
|
||||||
|
name = x) for x in self.get_ports('output')]
|
||||||
|
|
||||||
|
# Remove comma from last port entry
|
||||||
|
output_ports_rtl[-1] = output_ports_rtl[-1].rstrip(',')
|
||||||
|
|
||||||
|
self.rtl_header.append(
|
||||||
|
AddrMap.templ_dict['module_declaration'].format(
|
||||||
|
name = obj.inst_name,
|
||||||
|
inouts = '\n'.join(inout_ports_rtl),
|
||||||
|
inputs = '\n'.join(input_ports_rtl),
|
||||||
|
outputs = '\n'.join(output_ports_rtl)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def __process_variables(self, obj: node.RootNode):
|
||||||
|
# Save object
|
||||||
|
self.obj = obj
|
||||||
|
|
||||||
|
# Create full name
|
||||||
|
self.owning_addrmap = obj.owning_addrmap.inst_name
|
||||||
|
self.path = obj.get_path()\
|
||||||
|
.replace('[]', '')\
|
||||||
|
.replace('{}.'.format(self.owning_addrmap), '')
|
||||||
|
|
||||||
|
self.path_underscored = self.path.replace('.', '_')
|
||||||
|
|
||||||
|
self.name = obj.inst_name
|
||||||
|
85
srdl2sv/components/component.py
Normal file
85
srdl2sv/components/component.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import re
|
||||||
|
from itertools import chain
|
||||||
|
|
||||||
|
# Local modules
|
||||||
|
from log.log import create_logger
|
||||||
|
|
||||||
|
class Component():
|
||||||
|
def __init__(self):
|
||||||
|
self.rtl_header = []
|
||||||
|
self.rtl_footer = []
|
||||||
|
self.children = []
|
||||||
|
self.ports = dict()
|
||||||
|
self.ports['input'] = []
|
||||||
|
self.ports['output'] = []
|
||||||
|
self.ports['inout'] = []
|
||||||
|
|
||||||
|
def create_logger(self, name: str, config: dict):
|
||||||
|
self.logger = create_logger(
|
||||||
|
"{}".format(name),
|
||||||
|
stream_log_level=config['stream_log_level'],
|
||||||
|
file_log_level=config['file_log_level'],
|
||||||
|
file_name=config['file_log_location'])
|
||||||
|
|
||||||
|
def get_ports(self, port_type: str):
|
||||||
|
self.logger.debug("Return port list")
|
||||||
|
return [
|
||||||
|
*self.ports[port_type],
|
||||||
|
*list(chain(*[x.get_ports(port_type) for x in self.children]))
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_rtl(self, tab_width: int = 0, real_tabs: bool = False) -> str:
|
||||||
|
self.logger.debug("Return RTL")
|
||||||
|
|
||||||
|
# Loop through children and append RTL
|
||||||
|
rtl_children = []
|
||||||
|
|
||||||
|
for child in self.children:
|
||||||
|
rtl_children.append(child.get_rtl())
|
||||||
|
|
||||||
|
# Concatenate header, main, and footer
|
||||||
|
rtl = [*self.rtl_header, *rtl_children, *self.rtl_footer]
|
||||||
|
|
||||||
|
# Join lists and return string
|
||||||
|
if tab_width > 0:
|
||||||
|
return Component.__add_tabs(
|
||||||
|
'\n'.join(rtl),
|
||||||
|
tab_width,
|
||||||
|
real_tabs)
|
||||||
|
|
||||||
|
return '\n'.join(rtl)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __add_tabs(rtl: str, tab_width: int = 4, real_tabs = False) -> str:
|
||||||
|
indent_lvl = 0
|
||||||
|
|
||||||
|
# Define tab style
|
||||||
|
tab = "\t" if real_tabs else " "
|
||||||
|
tab = tab_width * tab
|
||||||
|
|
||||||
|
# Define triggers for which the indentation level will increment or
|
||||||
|
# decrement on the next line
|
||||||
|
incr_trigger = re.compile('\\bbegin\\b')
|
||||||
|
decr_trigger = re.compile('\\bend\\b')
|
||||||
|
|
||||||
|
rtl_indented = []
|
||||||
|
|
||||||
|
# Go through RTL, line by line
|
||||||
|
for line in rtl.split('\n', -1):
|
||||||
|
skip_incr_check = False
|
||||||
|
|
||||||
|
# Check if indentation must be decremented
|
||||||
|
if decr_trigger.search(line):
|
||||||
|
indent_lvl -= 1
|
||||||
|
skip_incr_check = True
|
||||||
|
|
||||||
|
# Add tabs
|
||||||
|
rtl_indented.append("{}{}".format(tab*indent_lvl, line))
|
||||||
|
|
||||||
|
# Check if tab level must be incremented
|
||||||
|
if skip_incr_check:
|
||||||
|
continue
|
||||||
|
elif incr_trigger.search(line):
|
||||||
|
indent_lvl += 1
|
||||||
|
|
||||||
|
return '\n'.join(rtl_indented)
|
@ -1,123 +1,61 @@
|
|||||||
import math
|
import math
|
||||||
|
import importlib.resources as pkg_resources
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from systemrdl import RDLCompiler, RDLCompileError, RDLWalker, RDLListener, node
|
from systemrdl import RDLCompiler, RDLCompileError, RDLWalker, RDLListener, node
|
||||||
from systemrdl.node import FieldNode
|
from systemrdl.node import FieldNode
|
||||||
from systemrdl.rdltypes import PrecedenceType, AccessType
|
from systemrdl.rdltypes import PrecedenceType, AccessType
|
||||||
from itertools import chain
|
|
||||||
|
|
||||||
# Local modules
|
# Local modules
|
||||||
from log.log import create_logger
|
from log.log import create_logger
|
||||||
|
from components.component import Component
|
||||||
|
from . import templates
|
||||||
|
|
||||||
TAB = " "
|
class Field(Component):
|
||||||
|
|
||||||
class Field:
|
|
||||||
# Save YAML template as class variable
|
# Save YAML template as class variable
|
||||||
with open('srdl2sv/components/templates/fields.yaml', 'r') as file:
|
templ_dict = yaml.load(
|
||||||
templ_dict = yaml.load(file, Loader=yaml.FullLoader)
|
pkg_resources.read_text(templates, 'fields.yaml'),
|
||||||
|
Loader=yaml.FullLoader)
|
||||||
|
|
||||||
def __init__(self, obj: node.RootNode, indent_lvl: int, dimensions: int, config:dict):
|
def __init__(self, obj: node.RootNode, dimensions: int, config:dict):
|
||||||
self.obj = obj
|
super().__init__()
|
||||||
self.rtl = []
|
|
||||||
self.bytes = math.ceil(obj.width / 8)
|
# Save and/or process important variables
|
||||||
|
self.__process_variables(obj, dimensions)
|
||||||
|
|
||||||
# Create logger object
|
# Create logger object
|
||||||
self.logger = create_logger(
|
self.create_logger("{}.{}".format(self.owning_addrmap, self.path), config)
|
||||||
"{}.{}".format(__name__, obj.inst_name),
|
|
||||||
stream_log_level=config['stream_log_level'],
|
|
||||||
file_log_level=config['file_log_level'],
|
|
||||||
file_name=config['file_log_location'])
|
|
||||||
|
|
||||||
self.logger.debug('Starting to process field "{}"'.format(obj.inst_name))
|
self.logger.debug('Starting to process field "{}"'.format(obj.inst_name))
|
||||||
|
|
||||||
# Make a list of I/O that shall be added to the addrmap
|
|
||||||
self.input_ports = []
|
|
||||||
self.output_ports = []
|
|
||||||
|
|
||||||
##################################################################################
|
##################################################################################
|
||||||
# LIMITATION:
|
# LIMITATION:
|
||||||
# v1.x of the systemrdl-compiler does not support non-homogeneous arrays.
|
# v1.x of the systemrdl-compiler does not support non-homogeneous arrays.
|
||||||
# It is planned, however, for v2.0.0 of the compiler. More information
|
# It is planned, however, for v2.0.0 of the compiler. More information
|
||||||
# can be found here: https://github.com/SystemRDL/systemrdl-compiler/issues/51
|
# can be found here: https://github.com/SystemRDL/systemrdl-compiler/issues/51
|
||||||
##################################################################################
|
##################################################################################
|
||||||
|
# Print a summary
|
||||||
# Determine resets. This includes checking for async/sync resets,
|
self.summary()
|
||||||
# the reset value, and whether the field actually has a reset
|
|
||||||
try:
|
|
||||||
rst_signal = obj.get_property("resetsignal")
|
|
||||||
rst_name = rst_signal.inst_name
|
|
||||||
rst_async = rst_signal.get_property("async")
|
|
||||||
rst_type = "asynchronous" if rst_async else "synchronous"
|
|
||||||
|
|
||||||
# Active low or active high?
|
|
||||||
if rst_signal.get_property("activelow"):
|
|
||||||
rst_edge = "negedge"
|
|
||||||
rst_negl = "!"
|
|
||||||
rst_active = "active_low"
|
|
||||||
else:
|
|
||||||
rst_edge = "posedge"
|
|
||||||
rst_negl = ""
|
|
||||||
rst_active = "active_high"
|
|
||||||
|
|
||||||
# Value of reset?
|
|
||||||
rst_value = '\'x' if obj.get_property("reset") == None else obj.get_property('reset')
|
|
||||||
except:
|
|
||||||
rst_async = False
|
|
||||||
rst_name = None
|
|
||||||
rst_negl = None
|
|
||||||
rst_edge = None
|
|
||||||
rst_value = "'x"
|
|
||||||
rst_active = "-"
|
|
||||||
rst_type = "-"
|
|
||||||
|
|
||||||
# Get certain properties
|
|
||||||
hw_access = obj.get_property('hw')
|
|
||||||
sw_access = obj.get_property('sw')
|
|
||||||
precedence = obj.get_property('precedence')
|
|
||||||
|
|
||||||
# Add comment with summary on field's properties
|
|
||||||
self.rtl.append(
|
|
||||||
Field.templ_dict['field_comment'].format(
|
|
||||||
name = obj.inst_name,
|
|
||||||
hw_access = str(hw_access)[11:],
|
|
||||||
sw_access = str(sw_access)[11:],
|
|
||||||
hw_precedence = '(precedence)' if precedence == PrecedenceType.hw else '',
|
|
||||||
sw_precedence = '(precedence)' if precedence == PrecedenceType.sw else '',
|
|
||||||
rst_active = rst_active,
|
|
||||||
rst_type = rst_type,
|
|
||||||
indent = self.indent(indent_lvl)))
|
|
||||||
|
|
||||||
# Handle always_ff
|
# Handle always_ff
|
||||||
sense_list = 'sense_list_rst' if rst_async else 'sense_list_no_rst'
|
sense_list = 'sense_list_rst' if self.rst['async'] else 'sense_list_no_rst'
|
||||||
|
|
||||||
self.rtl.append(
|
self.rtl_header.append(
|
||||||
Field.templ_dict[sense_list].format(
|
Field.templ_dict[sense_list].format(
|
||||||
clk_name = "clk",
|
clk_name = "clk",
|
||||||
rst_edge = rst_edge,
|
rst_edge = self.rst['edge'],
|
||||||
rst_name = rst_name,
|
rst_name = self.rst['name']))
|
||||||
indent = self.indent(indent_lvl)))
|
|
||||||
|
|
||||||
|
|
||||||
# Calculate how many genvars shall be added
|
|
||||||
genvars = ['[{}]'.format(chr(97+i)) for i in range(dimensions)]
|
|
||||||
genvars_str = ''.join(genvars)
|
|
||||||
|
|
||||||
# Add actual reset line
|
# Add actual reset line
|
||||||
if rst_name:
|
if self.rst['name']:
|
||||||
indent_lvl += 1
|
self.rtl_header.append(
|
||||||
|
|
||||||
self.rtl.append(
|
|
||||||
Field.templ_dict['rst_field_assign'].format(
|
Field.templ_dict['rst_field_assign'].format(
|
||||||
field_name = obj.inst_name,
|
path = self.path_underscored,
|
||||||
rst_name = rst_name,
|
rst_name = self.rst['name'],
|
||||||
rst_negl = rst_negl,
|
rst_negl = "!" if self.rst['active'] == "active_high" else "",
|
||||||
rst_value = rst_value,
|
rst_value = self.rst['value'],
|
||||||
genvars = genvars_str,
|
genvars = self.genvars_str))
|
||||||
indent = self.indent(indent_lvl)))
|
|
||||||
|
|
||||||
self.rtl.append("{}begin".format(self.indent(indent_lvl)))
|
self.rtl_header.append("begin")
|
||||||
|
|
||||||
indent_lvl += 1
|
|
||||||
|
|
||||||
# Not all access types are required and the order might differ
|
# Not all access types are required and the order might differ
|
||||||
# depending on what types are defined and what precedence is
|
# depending on what types are defined and what precedence is
|
||||||
@ -133,67 +71,67 @@ class Field:
|
|||||||
# Define hardware access (if applicable)
|
# Define hardware access (if applicable)
|
||||||
access_rtl['hw_write'] = []
|
access_rtl['hw_write'] = []
|
||||||
|
|
||||||
if hw_access in (AccessType.rw, AccessType.w):
|
if self.hw_access in (AccessType.rw, AccessType.w):
|
||||||
if obj.get_property('we') or obj.get_property('wel'):
|
if self.we_or_wel:
|
||||||
access_rtl['hw_write'].append(
|
access_rtl['hw_write'].append(
|
||||||
Field.templ_dict['hw_access_we_wel'].format(
|
Field.templ_dict['hw_access_we_wel'].format(
|
||||||
negl = '!' if obj.get_property('wel') else '',
|
negl = '!' if obj.get_property('wel') else '',
|
||||||
reg_name = obj.parent.inst_name,
|
path = self.path_underscored,
|
||||||
field_name = obj.inst_name,
|
genvars = self.genvars_str))
|
||||||
genvars = genvars_str,
|
|
||||||
indent = self.indent(indent_lvl)))
|
|
||||||
else:
|
else:
|
||||||
access_rtl['hw_write'].append(
|
access_rtl['hw_write'].append(
|
||||||
Field.templ_dict['hw_access_no_we_wel'].format(
|
Field.templ_dict['hw_access_no_we_wel'])
|
||||||
indent = self.indent(indent_lvl)))
|
|
||||||
|
|
||||||
access_rtl['hw_write'].append(
|
access_rtl['hw_write'].append(
|
||||||
Field.templ_dict['hw_access_field'].format(
|
Field.templ_dict['hw_access_field'].format(
|
||||||
reg_name = obj.parent.inst_name,
|
path = self.path_underscored,
|
||||||
field_name = obj.inst_name,
|
genvars = self.genvars_str))
|
||||||
genvars = genvars_str,
|
|
||||||
indent = self.indent(indent_lvl)))
|
|
||||||
|
|
||||||
# Define software access (if applicable)
|
# Define software access (if applicable)
|
||||||
access_rtl['sw_write'] = []
|
access_rtl['sw_write'] = []
|
||||||
|
|
||||||
if sw_access in (AccessType.rw, AccessType.w):
|
if self.sw_access in (AccessType.rw, AccessType.w):
|
||||||
access_rtl['sw_write'].append(
|
access_rtl['sw_write'].append(
|
||||||
Field.templ_dict['sw_access_field'].format(
|
Field.templ_dict['sw_access_field'].format(
|
||||||
reg_name = obj.parent.inst_name,
|
path = self.path_underscored,
|
||||||
field_name = obj.inst_name,
|
genvars = self.genvars_str))
|
||||||
genvars = genvars_str,
|
|
||||||
indent = self.indent(indent_lvl)))
|
|
||||||
|
|
||||||
indent_lvl += 1
|
|
||||||
|
|
||||||
# If field spans multiple bytes, every byte shall have a seperate enable!
|
# If field spans multiple bytes, every byte shall have a seperate enable!
|
||||||
for i in range(self.bytes):
|
for j, i in enumerate(range(self.lsbyte, self.msbyte+1)):
|
||||||
access_rtl['sw_write'].append(
|
access_rtl['sw_write'].append(
|
||||||
Field.templ_dict['sw_access_byte'].format(
|
Field.templ_dict['sw_access_byte'].format(
|
||||||
reg_name = obj.parent.inst_name,
|
path = self.path_underscored,
|
||||||
field_name = obj.inst_name,
|
genvars = self.genvars_str,
|
||||||
genvars = genvars_str,
|
|
||||||
i = i,
|
i = i,
|
||||||
indent = self.indent(indent_lvl)))
|
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))))
|
||||||
|
|
||||||
indent_lvl -= 1
|
access_rtl['sw_write'].append("end")
|
||||||
|
|
||||||
access_rtl['sw_write'].append("{}end".format(self.indent(indent_lvl)))
|
# Add singlepulse property
|
||||||
|
access_rtl['singlepulse'] = [
|
||||||
|
Field.templ_dict['singlepulse'].format(
|
||||||
|
path = self.path_underscored,
|
||||||
|
genvars = self.genvars_str)
|
||||||
|
]
|
||||||
|
|
||||||
# Define else with correct indentation and add to dictionary
|
# Define else
|
||||||
access_rtl['else'] = ["{}else".format(self.indent(indent_lvl))]
|
access_rtl['else'] = ["else"]
|
||||||
|
|
||||||
# Add empty string
|
# Add empty string
|
||||||
access_rtl[''] = ['']
|
access_rtl[''] = ['']
|
||||||
|
|
||||||
# Check if hardware has precedence (default `precedence = sw`)
|
# Check if hardware has precedence (default `precedence = sw`)
|
||||||
if precedence == 'PrecedenceType.sw':
|
if self.precedence == 'PrecedenceType.sw':
|
||||||
order_list = ['sw_write',
|
order_list = ['sw_write',
|
||||||
'hw_write']
|
'hw_write',
|
||||||
|
'singlepulse']
|
||||||
else:
|
else:
|
||||||
order_list = ['hw_write',
|
order_list = ['hw_write',
|
||||||
'sw_write']
|
'sw_write',
|
||||||
|
'singlepulse']
|
||||||
|
|
||||||
# Add appropriate else
|
# Add appropriate else
|
||||||
order_list_rtl = []
|
order_list_rtl = []
|
||||||
@ -203,57 +141,149 @@ class Field:
|
|||||||
# get longer in the future and thus become unreadable
|
# get longer in the future and thus become unreadable
|
||||||
if len(access_rtl[i]) > 0:
|
if len(access_rtl[i]) > 0:
|
||||||
order_list_rtl = [*order_list_rtl, *access_rtl[i]]
|
order_list_rtl = [*order_list_rtl, *access_rtl[i]]
|
||||||
order_list_rtl.append("{}else".format(self.indent(indent_lvl)))
|
order_list_rtl.append("else")
|
||||||
|
|
||||||
# Remove last pop
|
# Remove last pop
|
||||||
order_list_rtl.pop()
|
order_list_rtl.pop()
|
||||||
|
|
||||||
# Chain access RTL to the rest of the RTL
|
# Chain access RTL to the rest of the RTL
|
||||||
self.rtl = [*self.rtl, *order_list_rtl]
|
self.rtl_header = [*self.rtl_header, *order_list_rtl]
|
||||||
|
|
||||||
indent_lvl -= 1
|
self.rtl_header.append(
|
||||||
|
|
||||||
self.rtl.append(
|
|
||||||
Field.templ_dict['end_field_ff'].format(
|
Field.templ_dict['end_field_ff'].format(
|
||||||
reg_name = obj.parent.inst_name,
|
path = self.path_underscored))
|
||||||
field_name = obj.inst_name,
|
|
||||||
indent = self.indent(indent_lvl)))
|
|
||||||
|
|
||||||
#####################
|
|
||||||
# Add combo logic
|
self.__add_combo()
|
||||||
#####################
|
self.__add_ports()
|
||||||
|
|
||||||
|
def __add_combo(self):
|
||||||
operations = []
|
operations = []
|
||||||
if obj.get_property('anded'):
|
if self.obj.get_property('anded'):
|
||||||
operations.append(['anded', '&'])
|
operations.append(['anded', '&'])
|
||||||
if obj.get_property('ored'):
|
if self.obj.get_property('ored'):
|
||||||
operations.append(['ored', '|'])
|
operations.append(['ored', '|'])
|
||||||
if obj.get_property('xored'):
|
if self.obj.get_property('xored'):
|
||||||
operations.append(['xored', '^'])
|
operations.append(['xored', '^'])
|
||||||
|
|
||||||
if len(operations) > 0:
|
if len(operations) > 0:
|
||||||
self.rtl.append(
|
self.rtl_header.append(
|
||||||
Field.templ_dict['combo_operation_comment'].format(
|
Field.templ_dict['combo_operation_comment'].format(
|
||||||
reg_name = obj.parent.inst_name,
|
path = self.path_underscored))
|
||||||
field_name = obj.inst_name,
|
|
||||||
indent = self.indent(indent_lvl)))
|
|
||||||
|
|
||||||
self.rtl = [
|
self.rtl_header = [
|
||||||
*self.rtl,
|
*self.rtl_header,
|
||||||
*[Field.templ_dict['assign_combo_operation'].format(
|
*[Field.templ_dict['assign_combo_operation'].format(
|
||||||
field_name = obj.inst_name,
|
path = self.path_underscored,
|
||||||
reg_name = obj.parent.inst_name,
|
genvars = self.genvars_str,
|
||||||
genvars = genvars_str,
|
|
||||||
op_name = i[0],
|
op_name = i[0],
|
||||||
op_verilog = i[1],
|
op_verilog = i[1]) for i in operations]
|
||||||
indent = self.indent(indent_lvl)) for i in operations]]
|
]
|
||||||
|
|
||||||
# TODO: Set sanity checks. For example, having no we but precedence = hw
|
|
||||||
# will cause weird behavior.
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
def __process_variables(self, obj: node.RootNode, dimensions: int):
|
||||||
def indent(level):
|
# Save object
|
||||||
return TAB*level
|
self.obj = obj
|
||||||
|
|
||||||
def get_rtl(self) -> str:
|
# Create full name
|
||||||
return '\n'.join(self.rtl)
|
self.owning_addrmap = obj.owning_addrmap.inst_name
|
||||||
|
self.path = obj.get_path()\
|
||||||
|
.replace('[]', '')\
|
||||||
|
.replace('{}.'.format(self.owning_addrmap), '')
|
||||||
|
|
||||||
|
self.path_underscored = self.path.replace('.', '_')
|
||||||
|
self.path_wo_field = '.'.join(self.path.split('.', -1)[0:-1])
|
||||||
|
|
||||||
|
# Calculate how many genvars shall be added
|
||||||
|
genvars = ['[{}]'.format(chr(97+i)) for i in range(dimensions)]
|
||||||
|
self.genvars_str = ''.join(genvars)
|
||||||
|
|
||||||
|
# Write enable
|
||||||
|
self.we_or_wel = self.obj.get_property('we') or self.obj.get_property('wel')
|
||||||
|
|
||||||
|
# Save byte boundaries
|
||||||
|
self.lsbyte = math.floor(obj.inst.lsb / 8)
|
||||||
|
self.msbyte = math.floor(obj.inst.msb / 8)
|
||||||
|
|
||||||
|
# Determine resets. This includes checking for async/sync resets,
|
||||||
|
# the reset value, and whether the field actually has a reset
|
||||||
|
self.rst = dict()
|
||||||
|
|
||||||
|
try:
|
||||||
|
rst_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 rst['async'] else "synchronous"
|
||||||
|
|
||||||
|
# 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"
|
||||||
|
|
||||||
|
# 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'] = "-"
|
||||||
|
|
||||||
|
self.hw_access = obj.get_property('hw')
|
||||||
|
self.sw_access = obj.get_property('sw')
|
||||||
|
self.precedence = obj.get_property('precedence')
|
||||||
|
|
||||||
|
|
||||||
|
def summary(self):
|
||||||
|
# Additional flags that are set
|
||||||
|
misc_flags = set(self.obj.list_properties())
|
||||||
|
|
||||||
|
# Remove some flags that are not interesting
|
||||||
|
# or that are listed elsewhere
|
||||||
|
misc_flags.discard('hw')
|
||||||
|
misc_flags.discard('reset')
|
||||||
|
|
||||||
|
# Add comment with summary on field's properties
|
||||||
|
self.rtl_header.append(
|
||||||
|
Field.templ_dict['field_comment'].format(
|
||||||
|
name = self.obj.inst_name,
|
||||||
|
hw_access = str(self.hw_access)[11:],
|
||||||
|
sw_access = str(self.sw_access)[11:],
|
||||||
|
hw_precedence = '(precedence)' if self.precedence == PrecedenceType.hw else '',
|
||||||
|
sw_precedence = '(precedence)' if self.precedence == PrecedenceType.sw else '',
|
||||||
|
rst_active = self.rst['active'],
|
||||||
|
rst_type = self.rst['type'],
|
||||||
|
misc_flags = misc_flags if misc_flags else '-',
|
||||||
|
lsb = self.obj.lsb,
|
||||||
|
msb = self.obj.msb,
|
||||||
|
path_wo_field = self.path_wo_field))
|
||||||
|
|
||||||
|
def __add_ports(self):
|
||||||
|
# Port is writable by hardware --> Input port from hardware
|
||||||
|
if self.hw_access in (AccessType.rw, AccessType.w):
|
||||||
|
self.ports['input'].append("{}_in".format(self.path_underscored))
|
||||||
|
|
||||||
|
# Port has enable signal --> create such an enable
|
||||||
|
if self.we_or_wel:
|
||||||
|
self.ports['input'].append("{}_hw_wr".format(self.path_underscored))
|
||||||
|
|
||||||
|
if self.hw_access in (AccessType.rw, AccessType.r):
|
||||||
|
self.ports['output'].append("{}_r".format(self.path_underscored))
|
||||||
|
|
||||||
|
def sanity_checks(self):
|
||||||
|
# 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\
|
||||||
|
self.precedence == PrecedenceType.hw and \
|
||||||
|
self.hw_access in (AccessType.rw, AccessType.w) and \
|
||||||
|
self.sw_access in (AccessType.rw, AccessType.w):
|
||||||
|
|
||||||
|
self.logger.warning("Fields with hw=rw/sw=[r]w, we/wel not set and "\
|
||||||
|
"precedence for hardware will render software's "\
|
||||||
|
"write property useless since hardware will "\
|
||||||
|
"write every cycle.")
|
||||||
|
@ -1,32 +1,29 @@
|
|||||||
|
import importlib.resources as pkg_resources
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from systemrdl import RDLCompiler, RDLCompileError, RDLWalker, RDLListener, node
|
from systemrdl import RDLCompiler, RDLCompileError, RDLWalker, RDLListener, node
|
||||||
from systemrdl.node import FieldNode
|
from systemrdl.node import FieldNode
|
||||||
|
|
||||||
from components.field import Field
|
|
||||||
|
|
||||||
# Local modules
|
# Local modules
|
||||||
from log.log import create_logger
|
from log.log import create_logger
|
||||||
|
from components.component import Component
|
||||||
|
from components.field import Field
|
||||||
|
from . import templates
|
||||||
|
|
||||||
TAB = " "
|
class Register(Component):
|
||||||
|
|
||||||
class Register:
|
|
||||||
# Save YAML template as class variable
|
# Save YAML template as class variable
|
||||||
with open('srdl2sv/components/templates/regs.yaml', 'r') as file:
|
templ_dict = yaml.load(
|
||||||
templ_dict = yaml.load(file, Loader=yaml.FullLoader)
|
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):
|
||||||
self.obj = obj
|
super().__init__()
|
||||||
self.name = obj.inst_name
|
|
||||||
self.rtl = []
|
# Save and/or process important variables
|
||||||
|
self.__process_variables(obj)
|
||||||
|
|
||||||
# Create logger object
|
# Create logger object
|
||||||
self.logger = create_logger(
|
self.create_logger("{}.{}".format(self.owning_addrmap, self.path), config)
|
||||||
"{}.{}".format(__name__, obj.inst_name),
|
|
||||||
stream_log_level=config['stream_log_level'],
|
|
||||||
file_log_level=config['file_log_level'],
|
|
||||||
file_name=config['file_log_location'])
|
|
||||||
|
|
||||||
self.logger.debug('Starting to process register "{}"'.format(obj.inst_name))
|
self.logger.debug('Starting to process register "{}"'.format(obj.inst_name))
|
||||||
|
|
||||||
if obj.is_array:
|
if obj.is_array:
|
||||||
@ -38,56 +35,55 @@ class Register:
|
|||||||
|
|
||||||
depth = '[{}]'.format(']['.join(f"{i}" for i in array_dimensions))
|
depth = '[{}]'.format(']['.join(f"{i}" for i in array_dimensions))
|
||||||
dimensions = len(array_dimensions)
|
dimensions = len(array_dimensions)
|
||||||
indent_lvl = 0
|
|
||||||
|
|
||||||
# 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.append(
|
self.rtl_header.append(
|
||||||
Register.templ_dict['reg_comment'].format(
|
Register.templ_dict['reg_comment'].format(
|
||||||
name = obj.inst_name,
|
name = obj.inst_name,
|
||||||
dimensions = dimensions,
|
dimensions = dimensions,
|
||||||
depth = depth))
|
depth = depth))
|
||||||
|
|
||||||
# Create wires every register
|
# Create wires every register
|
||||||
self.rtl.append(
|
self.rtl_header.append(
|
||||||
Register.templ_dict['rw_wire_declare'].format(
|
Register.templ_dict['rw_wire_declare'].format(
|
||||||
name = obj.inst_name,
|
name = obj.inst_name,
|
||||||
depth = depth))
|
depth = depth))
|
||||||
|
|
||||||
# Create generate block for register and add comment
|
# Create generate block for register and add comment
|
||||||
self.rtl.append("generate")
|
self.rtl_header.append("generate")
|
||||||
for i in range(dimensions):
|
for i in range(dimensions):
|
||||||
self.rtl.append(
|
self.rtl_header.append(
|
||||||
Register.templ_dict['generate_for_start'].format(
|
Register.templ_dict['generate_for_start'].format(
|
||||||
iterator = chr(97+i),
|
iterator = chr(97+i),
|
||||||
limit = array_dimensions[i],
|
limit = array_dimensions[i]))
|
||||||
indent = self.indent(i)))
|
|
||||||
|
|
||||||
indent_lvl = i
|
|
||||||
|
|
||||||
indent_lvl += 1
|
|
||||||
|
|
||||||
# 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
|
||||||
self.fields = []
|
|
||||||
|
|
||||||
for field in obj.fields():
|
for field in obj.fields():
|
||||||
field_obj = Field(field, indent_lvl, dimensions, config)
|
field_obj = Field(field, dimensions, config)
|
||||||
self.fields.append(field_obj)
|
|
||||||
|
|
||||||
self.rtl += field_obj.rtl
|
if not config['disable_sanity']:
|
||||||
|
field_obj.sanity_checks()
|
||||||
|
|
||||||
|
self.children.append(field_obj)
|
||||||
|
|
||||||
# End loops
|
# End loops
|
||||||
for i in range(dimensions-1, -1, -1):
|
for i in range(dimensions-1, -1, -1):
|
||||||
self.rtl.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)))
|
||||||
indent = self.indent(i)))
|
|
||||||
|
|
||||||
|
def __process_variables(self, obj: node.RootNode):
|
||||||
|
# Save object
|
||||||
|
self.obj = obj
|
||||||
|
|
||||||
@staticmethod
|
# Create full name
|
||||||
def indent(level):
|
self.owning_addrmap = obj.owning_addrmap.inst_name
|
||||||
return TAB*level
|
self.path = obj.get_path()\
|
||||||
|
.replace('[]', '')\
|
||||||
|
.replace('{}.'.format(self.owning_addrmap), '')
|
||||||
|
|
||||||
def get_rtl(self) -> str:
|
self.path_underscored = self.path.replace('.', '_')
|
||||||
return '\n'.join(self.rtl)
|
|
||||||
|
self.name = obj.inst_name
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
module {addrmap_name} (
|
|
||||||
{bus_io}
|
|
||||||
{io_list}
|
|
||||||
);
|
|
||||||
|
|
||||||
{bus_widget}
|
|
||||||
|
|
||||||
{registers}
|
|
||||||
endmodule
|
|
21
srdl2sv/components/templates/addrmap.yaml
Normal file
21
srdl2sv/components/templates/addrmap.yaml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
module_declaration: |-
|
||||||
|
module {name} (
|
||||||
|
// Bus I/O
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
// InOuts
|
||||||
|
{inouts}
|
||||||
|
|
||||||
|
// Inputs
|
||||||
|
{inputs}
|
||||||
|
|
||||||
|
// Outputs
|
||||||
|
{outputs}
|
||||||
|
);
|
||||||
|
input_port: |-
|
||||||
|
input {name},
|
||||||
|
output_port: |-
|
||||||
|
output {name},
|
||||||
|
inout_port: |-
|
||||||
|
inout {name},
|
@ -1,40 +1,49 @@
|
|||||||
---
|
---
|
||||||
sense_list_rst: |-
|
sense_list_rst: |-
|
||||||
{indent}always_ff @(posedge {clk_name} or {rst_edge} {rst_name})
|
always_ff @(posedge {clk_name} or {rst_edge} {rst_name})
|
||||||
sense_list_no_rst: |-
|
sense_list_no_rst: |-
|
||||||
{indent}always_ff @(posedge {clk_name})
|
always_ff @(posedge {clk_name})
|
||||||
rst_field_assign: |-
|
rst_field_assign: |-
|
||||||
{indent}if ({rst_negl}{rst_name})
|
if ({rst_negl}{rst_name})
|
||||||
{indent} {field_name}_q{genvars} <= {rst_value};
|
begin
|
||||||
{indent}else
|
{path}_q{genvars} <= {rst_value};
|
||||||
|
end
|
||||||
|
else
|
||||||
sw_access_field: |-
|
sw_access_field: |-
|
||||||
{indent}if ({reg_name}_{field_name}_sw_wr{genvars})
|
if ({path}_sw_wr{genvars})
|
||||||
{indent}begin
|
begin
|
||||||
sw_access_byte: |-
|
sw_access_byte: |-
|
||||||
{indent}if (byte_enable[{i}])
|
if (byte_enable[{i}])
|
||||||
{indent} {reg_name}_{field_name}_q{genvars}[8*({i}+1)-1 -: 8] <= sw_wr_bus[8*({i}+1)-1 -: 8];
|
begin
|
||||||
|
{path}_q{genvars}[{msb_field}-:{field_w}] <= sw_wr_bus[{msb_bus}-:{bus_w}];
|
||||||
|
end
|
||||||
|
|
||||||
hw_access_we_wel: |-
|
hw_access_we_wel: |-
|
||||||
{indent}if ({negl}{reg_name}_{field_name}_hw_wr{genvars})
|
if ({negl}{path}_hw_wr{genvars})
|
||||||
hw_access_no_we_wel: |-
|
hw_access_no_we_wel: |-
|
||||||
{indent}if (1) // we or wel property not set
|
if (1) // we or wel property not set
|
||||||
hw_access_field: |-
|
hw_access_field: |-
|
||||||
{indent}begin
|
begin
|
||||||
{indent} {reg_name}_{field_name}_q{genvars} <= {reg_name}_{field_name}_in{genvars};
|
{path}_q{genvars} <= {path}_in{genvars};
|
||||||
{indent}end
|
end
|
||||||
end_field_ff: |-
|
end_field_ff: |-
|
||||||
{indent}end // of {reg_name}_{field_name}'s always_ff
|
end // of {path}'s always_ff
|
||||||
field_comment: |-
|
field_comment: |-
|
||||||
|
|
||||||
{indent}//-----------------FIELD SUMMARY-----------------
|
//-----------------FIELD SUMMARY-----------------
|
||||||
{indent}// name : {name}
|
// name : {name} ({path_wo_field}[{msb}:{lsb}])
|
||||||
{indent}// access : hw = {hw_access} {hw_precedence}
|
// access : hw = {hw_access} {hw_precedence}
|
||||||
{indent}// sw = {sw_access} {sw_precedence}
|
// sw = {sw_access} {sw_precedence}
|
||||||
{indent}// reset : {rst_active} / {rst_type}
|
// reset : {rst_active} / {rst_type}
|
||||||
{indent}//-----------------------------------------------
|
// flags : {misc_flags}
|
||||||
|
//-----------------------------------------------
|
||||||
combo_operation_comment: |-
|
combo_operation_comment: |-
|
||||||
|
|
||||||
{indent}// Combinational logic for {reg_name}_{field_name}
|
// Combinational logic for {path}
|
||||||
assign_combo_operation: |-
|
assign_combo_operation: |-
|
||||||
{indent}assign {reg_name}_{field_name}_{op_name}{genvars} = {op_verilog}{reg_name}_{field_name}_q{genvars}
|
assign {path}_{op_name}{genvars} = {op_verilog}{path}_q{genvars}
|
||||||
|
singlepulse: |-
|
||||||
|
begin
|
||||||
|
{path}{genvars} <= 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ reg_comment: |-
|
|||||||
*******************************************************************
|
*******************************************************************
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
generate_for_start: |-
|
generate_for_start: |-
|
||||||
{indent}for ({iterator} = 0; {iterator} < {limit}; {iterator}++)
|
for ({iterator} = 0; {iterator} < {limit}; {iterator}++)
|
||||||
{indent}begin
|
begin
|
||||||
generate_for_end: |-
|
generate_for_end: |-
|
||||||
{indent}end // of for loop with iterator {dimension}
|
end // of for loop with iterator {dimension}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
# TODO: In general, it would be more useful if the hierarchy of the objects pop up
|
||||||
|
# in the logs, not the Python objectname and than the name of the SRDL object.
|
||||||
class CustomFormatter(logging.Formatter):
|
class CustomFormatter(logging.Formatter):
|
||||||
"""Logging Formatter to add colors and count warning / errors"""
|
"""Logging Formatter to add colors and count warning / errors"""
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ if __name__ == "__main__":
|
|||||||
except RDLCompileError:
|
except RDLCompileError:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
addrmap = AddrMap(rdlc, root.top, config)
|
addrmap = AddrMap(root.top, config)
|
||||||
|
|
||||||
# Create output directory
|
# Create output directory
|
||||||
try:
|
try:
|
||||||
@ -55,7 +55,12 @@ if __name__ == "__main__":
|
|||||||
out_file_name = "{}/{}.sv".format(config['output_dir'], addrmap.name)
|
out_file_name = "{}/{}.sv".format(config['output_dir'], addrmap.name)
|
||||||
|
|
||||||
with open(out_file_name, 'w') as file:
|
with open(out_file_name, 'w') as file:
|
||||||
file.write(addrmap.get_rtl())
|
file.write(
|
||||||
|
addrmap.get_rtl(
|
||||||
|
tab_width=config['tab_width'],
|
||||||
|
real_tabs=config['real_tabs']
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
logger.info('Succesfully created "{}"'.format(out_file_name))
|
logger.info('Succesfully created "{}"'.format(out_file_name))
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user