mirror of
https://github.com/Silicon1602/srdl2sv.git
synced 2024-11-13 02:53:37 +00:00
Add initial version of widget-code and fix remaining SV compiler errors
This adds initial support for a dynamic bus-protocol to internal register logic SHIM. The chosen default protocol at this point is AMBA 3 AHB Lite and the logic is still empty. -> TODO: Adding the widget instantiation showed that it is required to have a better interface to parametrize ports & signals in the YAML. At this point, only a limited set of variables are supported. Furthermore, all remaining Verilator compilation issues in the field are resolved. Those were mostly related to non-declared wires and wrongly named wires.
This commit is contained in:
parent
21abdefac0
commit
9deb28ce4e
@ -19,6 +19,14 @@ class CliArguments():
|
||||
self.parser = argparse.ArgumentParser(
|
||||
description="SystemRDL 2 SystemVerilog compiler")
|
||||
|
||||
self.parser.add_argument(
|
||||
"-b",
|
||||
"--bus",
|
||||
choices=['amba3ahblite'],
|
||||
default='amba3ahblite',
|
||||
help="Set the bus protocol that shall be used by software to ',\
|
||||
communicate with the registers. (default: %(default)s)")
|
||||
|
||||
self.parser.add_argument(
|
||||
"-o",
|
||||
"--out_dir",
|
||||
@ -129,4 +137,7 @@ class CliArguments():
|
||||
# Set enums
|
||||
config['enums'] = not args.disable_enums
|
||||
|
||||
# Set bus
|
||||
config['bus'] = args.bus
|
||||
|
||||
return config
|
||||
|
@ -11,6 +11,7 @@ from components.component import Component
|
||||
from components.regfile import RegFile
|
||||
from components.register import Register
|
||||
from . import templates
|
||||
from . import widgets
|
||||
|
||||
|
||||
class AddrMap(Component):
|
||||
@ -32,6 +33,10 @@ class AddrMap(Component):
|
||||
(glbl_settings['field_reset'], glbl_settings['cpuif_reset']) = \
|
||||
self.__process_global_resets()
|
||||
|
||||
# Set defaults so that some of the common component methods work
|
||||
self.total_dimensions = 0
|
||||
self.total_array_dimensions = []
|
||||
|
||||
# Use global settings to define whether a component is already in a generate block
|
||||
glbl_settings['generate_active'] = False
|
||||
|
||||
@ -69,6 +74,9 @@ class AddrMap(Component):
|
||||
|
||||
self.logger.info("Done generating all child-regfiles/registers")
|
||||
|
||||
# Add bus widget ports
|
||||
self.__add_bus_widget_ports()
|
||||
|
||||
# Start assembling addrmap module
|
||||
self.logger.info("Starting to assemble input & output ports")
|
||||
|
||||
@ -147,18 +155,61 @@ class AddrMap(Component):
|
||||
inputs = '\n'.join(input_ports_rtl),
|
||||
outputs = '\n'.join(output_ports_rtl)))
|
||||
|
||||
# Add wire/register instantiations
|
||||
self.__add_signal_instantiation()
|
||||
|
||||
# Add bus widget RTL
|
||||
self.__add_bus_widget_instantiation()
|
||||
|
||||
# Append genvars
|
||||
self.__append_genvars()
|
||||
|
||||
# Add endmodule keyword
|
||||
self.rtl_footer.append('endmodule')
|
||||
|
||||
def __add_signal_instantiation(self):
|
||||
dict_list = [(key, value) for (key, value) in self.get_signals(True).items()]
|
||||
signal_width = min(max([len(value[0]) for (_, value) in dict_list]), 40)
|
||||
name_width = min(max([len(key) for (key, _) in dict_list]), 40)
|
||||
|
||||
self.rtl_header = [
|
||||
*self.rtl_header,
|
||||
'',
|
||||
'// Internal signals',
|
||||
*[AddrMap.templ_dict['signal_declaration'].format(
|
||||
name = key,
|
||||
type = value[0],
|
||||
signal_width = signal_width,
|
||||
name_width = name_width,
|
||||
unpacked_dim = '[{}]'.format(
|
||||
']['.join(
|
||||
[str(y) for y in value[1]]))
|
||||
if value[1] else '')
|
||||
for (key, value) in dict_list],
|
||||
''
|
||||
]
|
||||
|
||||
def __add_bus_widget_ports(self):
|
||||
self.widget_templ_dict = yaml.load(
|
||||
pkg_resources.read_text(widgets, '{}.yaml'.format(self.config['bus'])),
|
||||
Loader=yaml.FullLoader)
|
||||
|
||||
self.yaml_signals_to_list(self.widget_templ_dict['module_instantiation'])
|
||||
|
||||
def __add_bus_widget_instantiation(self):
|
||||
self.rtl_header.append(
|
||||
self.widget_templ_dict['module_instantiation']['rtl'])
|
||||
|
||||
|
||||
def __append_genvars(self):
|
||||
genvars = ''.join([
|
||||
'\ngenvar ',
|
||||
','.join([chr(97+i) for i in range(self.get_max_dim_depth())]),
|
||||
', '.join([chr(97+i) for i in range(self.get_max_dim_depth())]),
|
||||
';\n'
|
||||
])
|
||||
|
||||
self.rtl_header.append(genvars)
|
||||
|
||||
# Add endmodule keyword
|
||||
self.rtl_footer.append('endmodule')
|
||||
|
||||
def __process_global_resets(self):
|
||||
field_reset_list = \
|
||||
[x for x in self.obj.signals() if x.get_property('field_reset')]
|
||||
|
@ -66,25 +66,20 @@ class Component():
|
||||
return self.ports[port_type]
|
||||
|
||||
def get_max_dim_depth(self) -> int:
|
||||
try:
|
||||
total_dimensions = self.total_dimensions
|
||||
total_array_dimensions = self.total_array_dimensions
|
||||
except AttributeError:
|
||||
total_dimensions = 0
|
||||
total_array_dimensions = []
|
||||
|
||||
self.logger.debug("Return depth '{}' for dimensions (including "\
|
||||
"parents) '{}'".format(total_dimensions, total_array_dimensions))
|
||||
"parents) '{}'".format(self.total_dimensions,
|
||||
self.total_array_dimensions))
|
||||
return max([
|
||||
total_dimensions,
|
||||
self.total_dimensions,
|
||||
*[x.get_max_dim_depth() for x in self.children]
|
||||
])
|
||||
|
||||
def get_signals(self):
|
||||
def get_signals(self, no_children = False):
|
||||
self.logger.debug("Return signal list")
|
||||
|
||||
for x in self.children:
|
||||
self.signals |= x.get_signals()
|
||||
if not no_children:
|
||||
for x in self.children:
|
||||
self.signals |= x.get_signals()
|
||||
|
||||
return self.signals
|
||||
|
||||
@ -171,7 +166,7 @@ class Component():
|
||||
return path\
|
||||
.replace('[]', '')\
|
||||
.replace('{}.'.format(owning_addrmap), '')\
|
||||
.replace('.', '_')
|
||||
.replace('.', '__')
|
||||
|
||||
@staticmethod
|
||||
def split_dimensions(path: str):
|
||||
@ -179,8 +174,7 @@ class Component():
|
||||
new_path = re_dimensions.sub('', path)
|
||||
return (new_path, ''.join(re_dimensions.findall(path)))
|
||||
|
||||
@staticmethod
|
||||
def get_signal_name(obj):
|
||||
def get_signal_name(self, obj):
|
||||
name = []
|
||||
|
||||
try:
|
||||
@ -199,9 +193,11 @@ class Component():
|
||||
if isinstance(obj, node.FieldNode):
|
||||
name.append('_q')
|
||||
elif isinstance(obj, node.SignalNode):
|
||||
pass
|
||||
# Must add it to signal list
|
||||
self.ports['input'][obj.inst_name] =\
|
||||
("logic" if obj.width == 1 else 'logic [{}:0]'.format(obj.width), [])
|
||||
else:
|
||||
name.append('_')
|
||||
name.append('__')
|
||||
name.append(obj.name)
|
||||
|
||||
name.append(split_name[1])
|
||||
|
@ -133,10 +133,7 @@ class Field(Component):
|
||||
except AttributeError:
|
||||
# In case of an AttributeError, the encode property is None. Hence,
|
||||
# the field has a simple width
|
||||
if self.obj.width > 1:
|
||||
self.field_type = 'logic [{}:0]'.format(self.obj.width-1)
|
||||
else:
|
||||
self.field_type = 'logic'
|
||||
self.field_type = 'logic [{}:0]'.format(self.obj.width-1)
|
||||
|
||||
def __process_variables(self, obj: FieldNode, array_dimensions: list, glbl_settings: dict):
|
||||
# Create full name
|
||||
@ -213,7 +210,6 @@ class Field(Component):
|
||||
|
||||
self.rtl_header.append(
|
||||
Field.templ_dict[sense_list]['rtl'].format(
|
||||
clk_name = "clk",
|
||||
rst_edge = self.rst['edge'],
|
||||
rst_name = self.rst['name']))
|
||||
|
||||
@ -252,25 +248,25 @@ class Field(Component):
|
||||
|
||||
# Define hardware access (if applicable)
|
||||
if self.hw_access in (AccessType.rw, AccessType.w):
|
||||
if self.we_or_wel:
|
||||
access_rtl['hw_write'] = ([
|
||||
Field.templ_dict['hw_access_we_wel']['rtl'].format(
|
||||
negl = '!' if self.obj.get_property('wel') else '',
|
||||
path = self.path_underscored,
|
||||
genvars = self.genvars_str)
|
||||
],
|
||||
False)
|
||||
else:
|
||||
access_rtl['hw_write'] = ([
|
||||
Field.templ_dict['hw_access_no_we_wel']['rtl']
|
||||
],
|
||||
True)
|
||||
write_condition = 'hw_access_we_wel' if self.we_or_wel else 'hw_access_no_we_wel'
|
||||
|
||||
# if-line of hw-access
|
||||
access_rtl['hw_write'] = ([
|
||||
Field.templ_dict[write_condition]['rtl'].format(
|
||||
negl = '!' if self.obj.get_property('wel') else '',
|
||||
path = self.path_underscored,
|
||||
genvars = self.genvars_str)
|
||||
],
|
||||
write_condition == 'hw_access_no_we_wel') # Abort if no condition is set
|
||||
|
||||
# Actual assignment of register
|
||||
access_rtl['hw_write'][0].append(
|
||||
Field.templ_dict['hw_access_field']['rtl'].format(
|
||||
path = self.path_underscored,
|
||||
genvars = self.genvars_str))
|
||||
|
||||
# Get ports/signals from list
|
||||
self.yaml_signals_to_list(Field.templ_dict[write_condition])
|
||||
self.yaml_signals_to_list(Field.templ_dict['hw_access_field'])
|
||||
else:
|
||||
access_rtl['hw_write'] = ([], False)
|
||||
@ -287,13 +283,13 @@ class Field(Component):
|
||||
Field.templ_dict['sw_access_field_swwe']['rtl'].format(
|
||||
path_wo_field = self.path_wo_field,
|
||||
genvars = self.genvars_str,
|
||||
swwe = Component.get_signal_name(swwe)))
|
||||
swwe = self.get_signal_name(swwe)))
|
||||
elif isinstance(swwel, (FieldNode, SignalNode)):
|
||||
access_rtl['sw_write'][0].append(
|
||||
Field.templ_dict['sw_access_field_swwel']['rtl'].format(
|
||||
path_wo_field = self.path_wo_field,
|
||||
genvars = self.genvars_str,
|
||||
swwel = Component.get_signal_name(swwel)))
|
||||
swwel = self.get_signal_name(swwel)))
|
||||
else:
|
||||
access_rtl['sw_write'][0].append(
|
||||
Field.templ_dict['sw_access_field']['rtl'].format(
|
||||
|
@ -7,6 +7,7 @@ module_declaration:
|
||||
// Clock & Resets
|
||||
input reg_clk,
|
||||
input bus_clk,
|
||||
input bus_rst_n,
|
||||
{resets}
|
||||
|
||||
// Bus I/O
|
||||
@ -30,6 +31,8 @@ input_port:
|
||||
output_port:
|
||||
rtl:
|
||||
output {signal_type:{signal_width}} {name:{name_width}}{unpacked_dim},
|
||||
signal_declaration: |-
|
||||
{type:{signal_width}} {name:{name_width}}{unpacked_dim};
|
||||
package_declaration:
|
||||
rtl: |-
|
||||
package {name}_pkg;
|
||||
|
@ -1,10 +1,10 @@
|
||||
---
|
||||
sense_list_rst:
|
||||
rtl: |-
|
||||
always_ff @(posedge {clk_name} or {rst_edge} {rst_name})
|
||||
always_ff @(posedge reg_clk or {rst_edge} {rst_name})
|
||||
sense_list_no_rst:
|
||||
rtl: |-
|
||||
always_ff @(posedge {clk_name})
|
||||
always_ff @(posedge reg_clk)
|
||||
rst_field_assign:
|
||||
rtl: |-
|
||||
if ({rst_negl}{rst_name})
|
||||
@ -37,6 +37,9 @@ sw_access_byte:
|
||||
hw_access_we_wel:
|
||||
rtl: |-
|
||||
if ({negl}{path}_hw_wr{genvars})
|
||||
input_ports:
|
||||
- name: '{path}_hw_wr'
|
||||
signal_type: '{field_type}'
|
||||
hw_access_no_we_wel:
|
||||
rtl: |-
|
||||
// we or wel property not set
|
||||
|
0
srdl2sv/components/widgets/__init__.py
Normal file
0
srdl2sv/components/widgets/__init__.py
Normal file
31
srdl2sv/components/widgets/amba3ahblite.sv
Normal file
31
srdl2sv/components/widgets/amba3ahblite.sv
Normal file
@ -0,0 +1,31 @@
|
||||
module amba3ahblite_widget
|
||||
(
|
||||
// Register clock
|
||||
input reg_clk,
|
||||
|
||||
// Outputs to internal logic
|
||||
output [31:0] addr,
|
||||
output w_vld,
|
||||
output r_vld,
|
||||
output [ 3:0] byte_enable,
|
||||
output [31:0] sw_wr_bus,
|
||||
|
||||
// Bus protocol
|
||||
input HRESETn,
|
||||
input HCLK,
|
||||
input [31:0] HADDR,
|
||||
input HWRITE,
|
||||
input [ 2:0] HSIZE,
|
||||
input [ 2:0] HBURST,
|
||||
input [ 3:0] HPROT,
|
||||
input [ 1:0] HTRANS,
|
||||
input HMASTLOCK,
|
||||
input HREADY,
|
||||
|
||||
output HREADYOUT,
|
||||
output HRESP,
|
||||
output [31:0] HRDATA
|
||||
);
|
||||
|
||||
|
||||
endmodule
|
72
srdl2sv/components/widgets/amba3ahblite.yaml
Normal file
72
srdl2sv/components/widgets/amba3ahblite.yaml
Normal file
@ -0,0 +1,72 @@
|
||||
# This file only contains the instantiation of the module
|
||||
module_instantiation:
|
||||
rtl: |-
|
||||
/****************************
|
||||
* AMBA 3 AHB Lite Widget
|
||||
****************************/
|
||||
amba3ahblite_widget
|
||||
amba3ahblite_widget_inst
|
||||
(// Register clock
|
||||
.reg_clk,
|
||||
|
||||
// Outputs to internal logic
|
||||
.addr,
|
||||
.w_vld,
|
||||
.r_vld,
|
||||
.byte_enable,
|
||||
.sw_wr_bus,
|
||||
|
||||
// Bus protocol
|
||||
.HRESETn,
|
||||
.HCLK,
|
||||
.HADDR,
|
||||
.HWRITE,
|
||||
.HSIZE,
|
||||
.HBURST,
|
||||
.HPROT,
|
||||
.HTRANS,
|
||||
.HMASTLOCK,
|
||||
.HREADY,
|
||||
|
||||
.HREADYOUT,
|
||||
.HRESP,
|
||||
.HRDATA);
|
||||
signals:
|
||||
- name: 'addr'
|
||||
signal_type: 'logic [31:0]'
|
||||
- name: 'w_vld'
|
||||
signal_type: 'logic'
|
||||
- name: 'r_vld'
|
||||
signal_type: 'logic'
|
||||
- name: 'byte_enable'
|
||||
signal_type: 'logic [ 3:0]'
|
||||
- name: 'sw_wr_bus'
|
||||
signal_type: 'logic [31:0]'
|
||||
input_ports:
|
||||
- name: 'HRESETn'
|
||||
signal_type: ''
|
||||
- name: 'HCLK'
|
||||
signal_type: ''
|
||||
- name: 'HADDR'
|
||||
signal_type: '[31:0]'
|
||||
- name: 'HWRITE'
|
||||
signal_type: ''
|
||||
- name: 'HSIZE'
|
||||
signal_type: '[2:0]'
|
||||
- name: 'HBURST'
|
||||
signal_type: '[2:0]'
|
||||
- name: 'HPROT'
|
||||
signal_type: '[3:0]'
|
||||
- name: 'HTRANS'
|
||||
signal_type: '[1:0]'
|
||||
- name: 'HMASTLOCK'
|
||||
signal_type: ''
|
||||
- name: 'HREADY'
|
||||
signal_type: ''
|
||||
output_ports:
|
||||
- name: 'HREADYOUT'
|
||||
signal_type: ''
|
||||
- name: 'HRESP'
|
||||
signal_type: ''
|
||||
- name: 'HRDATA'
|
||||
signal_type: '[31:0]'
|
@ -4,6 +4,7 @@
|
||||
import sys
|
||||
import time
|
||||
import os
|
||||
import importlib.resources as pkg_resources
|
||||
|
||||
# Imported modules
|
||||
from systemrdl import RDLCompiler, RDLCompileError
|
||||
@ -12,6 +13,7 @@ from systemrdl import RDLCompiler, RDLCompileError
|
||||
from components.addrmap import AddrMap
|
||||
from cli.cli import CliArguments
|
||||
from log.log import create_logger
|
||||
from components import widgets
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Take start timestamp
|
||||
@ -74,4 +76,12 @@ if __name__ == "__main__":
|
||||
with open('{}/{}_pkg.sv'.format(config['output_dir'], key), 'w') as file:
|
||||
file.write(value)
|
||||
|
||||
# Copy over widget RTL from widget directory
|
||||
widget_rtl = pkg_resources.read_text(widgets, '{}.sv'.format(config['bus']))
|
||||
|
||||
out_widget_file = "{}/{}.sv".format(config['output_dir'], config['bus'])
|
||||
|
||||
with open(out_widget_file, 'w') as file:
|
||||
file.write(widget_rtl)
|
||||
|
||||
logger.info("Elapsed time: %f seconds", time.time() - start)
|
||||
|
Loading…
Reference in New Issue
Block a user