mirror of
https://github.com/Silicon1602/srdl2sv.git
synced 2024-11-14 11:03:36 +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(
|
self.parser = argparse.ArgumentParser(
|
||||||
description="SystemRDL 2 SystemVerilog compiler")
|
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(
|
self.parser.add_argument(
|
||||||
"-o",
|
"-o",
|
||||||
"--out_dir",
|
"--out_dir",
|
||||||
@ -129,4 +137,7 @@ class CliArguments():
|
|||||||
# Set enums
|
# Set enums
|
||||||
config['enums'] = not args.disable_enums
|
config['enums'] = not args.disable_enums
|
||||||
|
|
||||||
|
# Set bus
|
||||||
|
config['bus'] = args.bus
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
@ -11,6 +11,7 @@ from components.component import Component
|
|||||||
from components.regfile import RegFile
|
from components.regfile import RegFile
|
||||||
from components.register import Register
|
from components.register import Register
|
||||||
from . import templates
|
from . import templates
|
||||||
|
from . import widgets
|
||||||
|
|
||||||
|
|
||||||
class AddrMap(Component):
|
class AddrMap(Component):
|
||||||
@ -32,6 +33,10 @@ class AddrMap(Component):
|
|||||||
(glbl_settings['field_reset'], glbl_settings['cpuif_reset']) = \
|
(glbl_settings['field_reset'], glbl_settings['cpuif_reset']) = \
|
||||||
self.__process_global_resets()
|
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
|
# Use global settings to define whether a component is already in a generate block
|
||||||
glbl_settings['generate_active'] = False
|
glbl_settings['generate_active'] = False
|
||||||
|
|
||||||
@ -69,6 +74,9 @@ class AddrMap(Component):
|
|||||||
|
|
||||||
self.logger.info("Done generating all child-regfiles/registers")
|
self.logger.info("Done generating all child-regfiles/registers")
|
||||||
|
|
||||||
|
# Add bus widget ports
|
||||||
|
self.__add_bus_widget_ports()
|
||||||
|
|
||||||
# Start assembling addrmap module
|
# Start assembling addrmap module
|
||||||
self.logger.info("Starting to assemble input & output ports")
|
self.logger.info("Starting to assemble input & output ports")
|
||||||
|
|
||||||
@ -147,7 +155,53 @@ class AddrMap(Component):
|
|||||||
inputs = '\n'.join(input_ports_rtl),
|
inputs = '\n'.join(input_ports_rtl),
|
||||||
outputs = '\n'.join(output_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
|
# 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([
|
genvars = ''.join([
|
||||||
'\ngenvar ',
|
'\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())]),
|
||||||
@ -156,9 +210,6 @@ class AddrMap(Component):
|
|||||||
|
|
||||||
self.rtl_header.append(genvars)
|
self.rtl_header.append(genvars)
|
||||||
|
|
||||||
# Add endmodule keyword
|
|
||||||
self.rtl_footer.append('endmodule')
|
|
||||||
|
|
||||||
def __process_global_resets(self):
|
def __process_global_resets(self):
|
||||||
field_reset_list = \
|
field_reset_list = \
|
||||||
[x for x in self.obj.signals() if x.get_property('field_reset')]
|
[x for x in self.obj.signals() if x.get_property('field_reset')]
|
||||||
|
@ -66,23 +66,18 @@ class Component():
|
|||||||
return self.ports[port_type]
|
return self.ports[port_type]
|
||||||
|
|
||||||
def get_max_dim_depth(self) -> int:
|
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 "\
|
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([
|
return max([
|
||||||
total_dimensions,
|
self.total_dimensions,
|
||||||
*[x.get_max_dim_depth() for x in self.children]
|
*[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")
|
self.logger.debug("Return signal list")
|
||||||
|
|
||||||
|
if not no_children:
|
||||||
for x in self.children:
|
for x in self.children:
|
||||||
self.signals |= x.get_signals()
|
self.signals |= x.get_signals()
|
||||||
|
|
||||||
@ -171,7 +166,7 @@ class Component():
|
|||||||
return path\
|
return path\
|
||||||
.replace('[]', '')\
|
.replace('[]', '')\
|
||||||
.replace('{}.'.format(owning_addrmap), '')\
|
.replace('{}.'.format(owning_addrmap), '')\
|
||||||
.replace('.', '_')
|
.replace('.', '__')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def split_dimensions(path: str):
|
def split_dimensions(path: str):
|
||||||
@ -179,8 +174,7 @@ class Component():
|
|||||||
new_path = re_dimensions.sub('', path)
|
new_path = re_dimensions.sub('', path)
|
||||||
return (new_path, ''.join(re_dimensions.findall(path)))
|
return (new_path, ''.join(re_dimensions.findall(path)))
|
||||||
|
|
||||||
@staticmethod
|
def get_signal_name(self, obj):
|
||||||
def get_signal_name(obj):
|
|
||||||
name = []
|
name = []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -199,9 +193,11 @@ class Component():
|
|||||||
if isinstance(obj, node.FieldNode):
|
if isinstance(obj, node.FieldNode):
|
||||||
name.append('_q')
|
name.append('_q')
|
||||||
elif isinstance(obj, node.SignalNode):
|
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:
|
else:
|
||||||
name.append('_')
|
name.append('__')
|
||||||
name.append(obj.name)
|
name.append(obj.name)
|
||||||
|
|
||||||
name.append(split_name[1])
|
name.append(split_name[1])
|
||||||
|
@ -133,10 +133,7 @@ class Field(Component):
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
# In case of an AttributeError, the encode property is None. Hence,
|
# In case of an AttributeError, the encode property is None. Hence,
|
||||||
# the field has a simple width
|
# the field has a simple width
|
||||||
if self.obj.width > 1:
|
|
||||||
self.field_type = 'logic [{}:0]'.format(self.obj.width-1)
|
self.field_type = 'logic [{}:0]'.format(self.obj.width-1)
|
||||||
else:
|
|
||||||
self.field_type = 'logic'
|
|
||||||
|
|
||||||
def __process_variables(self, obj: FieldNode, array_dimensions: list, glbl_settings: dict):
|
def __process_variables(self, obj: FieldNode, array_dimensions: list, glbl_settings: dict):
|
||||||
# Create full name
|
# Create full name
|
||||||
@ -213,7 +210,6 @@ class Field(Component):
|
|||||||
|
|
||||||
self.rtl_header.append(
|
self.rtl_header.append(
|
||||||
Field.templ_dict[sense_list]['rtl'].format(
|
Field.templ_dict[sense_list]['rtl'].format(
|
||||||
clk_name = "clk",
|
|
||||||
rst_edge = self.rst['edge'],
|
rst_edge = self.rst['edge'],
|
||||||
rst_name = self.rst['name']))
|
rst_name = self.rst['name']))
|
||||||
|
|
||||||
@ -252,25 +248,25 @@ class Field(Component):
|
|||||||
|
|
||||||
# Define hardware access (if applicable)
|
# Define hardware access (if applicable)
|
||||||
if self.hw_access in (AccessType.rw, AccessType.w):
|
if self.hw_access in (AccessType.rw, AccessType.w):
|
||||||
if self.we_or_wel:
|
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'] = ([
|
access_rtl['hw_write'] = ([
|
||||||
Field.templ_dict['hw_access_we_wel']['rtl'].format(
|
Field.templ_dict[write_condition]['rtl'].format(
|
||||||
negl = '!' if self.obj.get_property('wel') else '',
|
negl = '!' if self.obj.get_property('wel') else '',
|
||||||
path = self.path_underscored,
|
path = self.path_underscored,
|
||||||
genvars = self.genvars_str)
|
genvars = self.genvars_str)
|
||||||
],
|
],
|
||||||
False)
|
write_condition == 'hw_access_no_we_wel') # Abort if no condition is set
|
||||||
else:
|
|
||||||
access_rtl['hw_write'] = ([
|
|
||||||
Field.templ_dict['hw_access_no_we_wel']['rtl']
|
|
||||||
],
|
|
||||||
True)
|
|
||||||
|
|
||||||
|
# Actual assignment of register
|
||||||
access_rtl['hw_write'][0].append(
|
access_rtl['hw_write'][0].append(
|
||||||
Field.templ_dict['hw_access_field']['rtl'].format(
|
Field.templ_dict['hw_access_field']['rtl'].format(
|
||||||
path = self.path_underscored,
|
path = self.path_underscored,
|
||||||
genvars = self.genvars_str))
|
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'])
|
self.yaml_signals_to_list(Field.templ_dict['hw_access_field'])
|
||||||
else:
|
else:
|
||||||
access_rtl['hw_write'] = ([], False)
|
access_rtl['hw_write'] = ([], False)
|
||||||
@ -287,13 +283,13 @@ class Field(Component):
|
|||||||
Field.templ_dict['sw_access_field_swwe']['rtl'].format(
|
Field.templ_dict['sw_access_field_swwe']['rtl'].format(
|
||||||
path_wo_field = self.path_wo_field,
|
path_wo_field = self.path_wo_field,
|
||||||
genvars = self.genvars_str,
|
genvars = self.genvars_str,
|
||||||
swwe = Component.get_signal_name(swwe)))
|
swwe = self.get_signal_name(swwe)))
|
||||||
elif isinstance(swwel, (FieldNode, SignalNode)):
|
elif isinstance(swwel, (FieldNode, SignalNode)):
|
||||||
access_rtl['sw_write'][0].append(
|
access_rtl['sw_write'][0].append(
|
||||||
Field.templ_dict['sw_access_field_swwel']['rtl'].format(
|
Field.templ_dict['sw_access_field_swwel']['rtl'].format(
|
||||||
path_wo_field = self.path_wo_field,
|
path_wo_field = self.path_wo_field,
|
||||||
genvars = self.genvars_str,
|
genvars = self.genvars_str,
|
||||||
swwel = Component.get_signal_name(swwel)))
|
swwel = self.get_signal_name(swwel)))
|
||||||
else:
|
else:
|
||||||
access_rtl['sw_write'][0].append(
|
access_rtl['sw_write'][0].append(
|
||||||
Field.templ_dict['sw_access_field']['rtl'].format(
|
Field.templ_dict['sw_access_field']['rtl'].format(
|
||||||
|
@ -7,6 +7,7 @@ module_declaration:
|
|||||||
// Clock & Resets
|
// Clock & Resets
|
||||||
input reg_clk,
|
input reg_clk,
|
||||||
input bus_clk,
|
input bus_clk,
|
||||||
|
input bus_rst_n,
|
||||||
{resets}
|
{resets}
|
||||||
|
|
||||||
// Bus I/O
|
// Bus I/O
|
||||||
@ -30,6 +31,8 @@ input_port:
|
|||||||
output_port:
|
output_port:
|
||||||
rtl:
|
rtl:
|
||||||
output {signal_type:{signal_width}} {name:{name_width}}{unpacked_dim},
|
output {signal_type:{signal_width}} {name:{name_width}}{unpacked_dim},
|
||||||
|
signal_declaration: |-
|
||||||
|
{type:{signal_width}} {name:{name_width}}{unpacked_dim};
|
||||||
package_declaration:
|
package_declaration:
|
||||||
rtl: |-
|
rtl: |-
|
||||||
package {name}_pkg;
|
package {name}_pkg;
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
---
|
---
|
||||||
sense_list_rst:
|
sense_list_rst:
|
||||||
rtl: |-
|
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:
|
sense_list_no_rst:
|
||||||
rtl: |-
|
rtl: |-
|
||||||
always_ff @(posedge {clk_name})
|
always_ff @(posedge reg_clk)
|
||||||
rst_field_assign:
|
rst_field_assign:
|
||||||
rtl: |-
|
rtl: |-
|
||||||
if ({rst_negl}{rst_name})
|
if ({rst_negl}{rst_name})
|
||||||
@ -37,6 +37,9 @@ sw_access_byte:
|
|||||||
hw_access_we_wel:
|
hw_access_we_wel:
|
||||||
rtl: |-
|
rtl: |-
|
||||||
if ({negl}{path}_hw_wr{genvars})
|
if ({negl}{path}_hw_wr{genvars})
|
||||||
|
input_ports:
|
||||||
|
- name: '{path}_hw_wr'
|
||||||
|
signal_type: '{field_type}'
|
||||||
hw_access_no_we_wel:
|
hw_access_no_we_wel:
|
||||||
rtl: |-
|
rtl: |-
|
||||||
// we or wel property not set
|
// 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 sys
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
|
import importlib.resources as pkg_resources
|
||||||
|
|
||||||
# Imported modules
|
# Imported modules
|
||||||
from systemrdl import RDLCompiler, RDLCompileError
|
from systemrdl import RDLCompiler, RDLCompileError
|
||||||
@ -12,6 +13,7 @@ from systemrdl import RDLCompiler, RDLCompileError
|
|||||||
from components.addrmap import AddrMap
|
from components.addrmap import AddrMap
|
||||||
from cli.cli import CliArguments
|
from cli.cli import CliArguments
|
||||||
from log.log import create_logger
|
from log.log import create_logger
|
||||||
|
from components import widgets
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# Take start timestamp
|
# Take start timestamp
|
||||||
@ -74,4 +76,12 @@ if __name__ == "__main__":
|
|||||||
with open('{}/{}_pkg.sv'.format(config['output_dir'], key), 'w') as file:
|
with open('{}/{}_pkg.sv'.format(config['output_dir'], key), 'w') as file:
|
||||||
file.write(value)
|
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)
|
logger.info("Elapsed time: %f seconds", time.time() - start)
|
||||||
|
Loading…
Reference in New Issue
Block a user