siliconcompiler 0.26.2__cp39-cp39-win_amd64.whl → 0.26.4.post1__cp39-cp39-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- siliconcompiler/_metadata.py +1 -1
- siliconcompiler/apps/sc_issue.py +4 -11
- siliconcompiler/apps/smake.py +59 -19
- siliconcompiler/core.py +158 -56
- siliconcompiler/flowgraph.py +2 -1
- siliconcompiler/flows/dvflow.py +13 -8
- siliconcompiler/issue.py +3 -0
- siliconcompiler/report/html_report.py +1 -1
- siliconcompiler/report/summary_table.py +26 -14
- siliconcompiler/report/utils.py +1 -1
- siliconcompiler/scheduler/__init__.py +11 -6
- siliconcompiler/schema/schema_cfg.py +8 -8
- siliconcompiler/schema/schema_obj.py +6 -5
- siliconcompiler/templates/tcl/manifest.tcl.j2 +52 -0
- siliconcompiler/tools/_common/__init__.py +10 -2
- siliconcompiler/tools/_common/asic.py +26 -6
- siliconcompiler/tools/klayout/export.py +3 -2
- siliconcompiler/tools/klayout/klayout_export.py +4 -4
- siliconcompiler/tools/klayout/klayout_utils.py +4 -4
- siliconcompiler/tools/magic/sc_drc.tcl +1 -1
- siliconcompiler/tools/magic/sc_extspice.tcl +3 -2
- siliconcompiler/tools/netgen/sc_lvs.tcl +1 -1
- siliconcompiler/tools/openroad/export.py +3 -3
- siliconcompiler/tools/openroad/openroad.py +5 -5
- siliconcompiler/tools/openroad/scripts/sc_apr.tcl +2 -2
- siliconcompiler/tools/opensta/__init__.py +3 -2
- siliconcompiler/tools/opensta/scripts/sc_report_libraries.tcl +2 -2
- siliconcompiler/tools/opensta/scripts/sc_timing.tcl +2 -2
- siliconcompiler/tools/surelog/bin/surelog.exe +0 -0
- siliconcompiler/tools/verilator/compile.py +9 -3
- siliconcompiler/tools/yosys/sc_lec.tcl +1 -1
- siliconcompiler/tools/yosys/syn_asic.py +21 -17
- siliconcompiler/tools/yosys/syn_asic.tcl +3 -3
- siliconcompiler/use.py +12 -0
- siliconcompiler/utils/__init__.py +17 -0
- {siliconcompiler-0.26.2.dist-info → siliconcompiler-0.26.4.post1.dist-info}/METADATA +4 -2
- {siliconcompiler-0.26.2.dist-info → siliconcompiler-0.26.4.post1.dist-info}/RECORD +41 -41
- {siliconcompiler-0.26.2.dist-info → siliconcompiler-0.26.4.post1.dist-info}/WHEEL +1 -1
- {siliconcompiler-0.26.2.dist-info → siliconcompiler-0.26.4.post1.dist-info}/LICENSE +0 -0
- {siliconcompiler-0.26.2.dist-info → siliconcompiler-0.26.4.post1.dist-info}/entry_points.txt +0 -0
- {siliconcompiler-0.26.2.dist-info → siliconcompiler-0.26.4.post1.dist-info}/top_level.txt +0 -0
siliconcompiler/_metadata.py
CHANGED
siliconcompiler/apps/sc_issue.py
CHANGED
|
@@ -25,13 +25,13 @@ Restricted SC app that generates a sharable testcase from a
|
|
|
25
25
|
failed flow or runs an issue generated with this program.
|
|
26
26
|
|
|
27
27
|
To generate a testcase, use:
|
|
28
|
-
sc-issue -
|
|
28
|
+
sc-issue -cfg <stepdir>/outputs/<design>.pkg.json
|
|
29
29
|
|
|
30
30
|
or include a different step/index than what the cfg_file is pointing to:
|
|
31
|
-
sc-issue -
|
|
31
|
+
sc-issue -cfg <otherdir>/outputs/<design>.pkg.json -arg_step <step> -arg_index <index>
|
|
32
32
|
|
|
33
33
|
or include specific libraries while excluding others:
|
|
34
|
-
sc-issue -
|
|
34
|
+
sc-issue -cfg <stepdir>/outputs/<design>.pkg.json -exclude_libraries -add_library sram -add_library gpio
|
|
35
35
|
|
|
36
36
|
To run a testcase, use:
|
|
37
37
|
sc-issue -run -file sc_issue_<...>.tar.gz
|
|
@@ -39,10 +39,6 @@ To run a testcase, use:
|
|
|
39
39
|
""" # noqa E501
|
|
40
40
|
|
|
41
41
|
issue_arguments = {
|
|
42
|
-
'-generate': {'action': 'store_true',
|
|
43
|
-
'help': 'generate a testcase',
|
|
44
|
-
'sc_print': False},
|
|
45
|
-
|
|
46
42
|
'-exclude_libraries': {'action': 'store_true',
|
|
47
43
|
'help': 'flag to ensure libraries are excluded in the testcase',
|
|
48
44
|
'sc_print': False},
|
|
@@ -88,10 +84,7 @@ To run a testcase, use:
|
|
|
88
84
|
chip.logger.error(e)
|
|
89
85
|
return 1
|
|
90
86
|
|
|
91
|
-
if
|
|
92
|
-
raise ValueError('Only one of -generate or -run can be used')
|
|
93
|
-
|
|
94
|
-
if switches['generate']:
|
|
87
|
+
if not switches['run']:
|
|
95
88
|
step = chip.get('arg', 'step')
|
|
96
89
|
index = chip.get('arg', 'index')
|
|
97
90
|
|
siliconcompiler/apps/smake.py
CHANGED
|
@@ -41,7 +41,20 @@ def __process_file(path):
|
|
|
41
41
|
arg_type = str
|
|
42
42
|
if arg in func_spec.annotations:
|
|
43
43
|
arg_type = func_spec.annotations[arg]
|
|
44
|
-
func_args[arg] =
|
|
44
|
+
func_args[arg] = {
|
|
45
|
+
"type": arg_type
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if func_spec.defaults:
|
|
49
|
+
for arg, defval in zip(reversed(func_spec.args), reversed(func_spec.defaults)):
|
|
50
|
+
func_args[arg]["default"] = defval
|
|
51
|
+
|
|
52
|
+
if defval is None:
|
|
53
|
+
continue
|
|
54
|
+
|
|
55
|
+
if type(defval) is not func_args[arg]["type"]:
|
|
56
|
+
if isinstance(defval, (bool, str, float, int)):
|
|
57
|
+
func_args[arg]["type"] = type(defval)
|
|
45
58
|
|
|
46
59
|
args[name] = {
|
|
47
60
|
"function": func,
|
|
@@ -62,7 +75,7 @@ def __process_file(path):
|
|
|
62
75
|
return args, default_arg, module_help
|
|
63
76
|
|
|
64
77
|
|
|
65
|
-
def main():
|
|
78
|
+
def main(source_file=None):
|
|
66
79
|
progname = "smake"
|
|
67
80
|
description = f"""-----------------------------------------------------------
|
|
68
81
|
SC app that provides an Makefile like interface to python
|
|
@@ -90,16 +103,18 @@ To run a target with supported arguments, use:
|
|
|
90
103
|
-----------------------------------------------------------"""
|
|
91
104
|
|
|
92
105
|
# handle source file identification before arg parse
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
106
|
+
file_args = None
|
|
107
|
+
if not source_file:
|
|
108
|
+
source_file = __default_source_file
|
|
109
|
+
file_args = ('--file', '-f')
|
|
110
|
+
for file_arg in file_args:
|
|
111
|
+
if file_arg in sys.argv:
|
|
112
|
+
source_file_idx = sys.argv.index(file_arg) + 1
|
|
113
|
+
if source_file_idx < len(sys.argv):
|
|
114
|
+
source_file = sys.argv[source_file_idx]
|
|
115
|
+
else:
|
|
116
|
+
source_file = None
|
|
117
|
+
break
|
|
103
118
|
|
|
104
119
|
# handle directory identification before arg parse
|
|
105
120
|
source_dir = os.getcwd()
|
|
@@ -135,10 +150,11 @@ To run a target with supported arguments, use:
|
|
|
135
150
|
description=description,
|
|
136
151
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
137
152
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
153
|
+
if file_args:
|
|
154
|
+
parser.add_argument(
|
|
155
|
+
*file_args,
|
|
156
|
+
metavar='<file>',
|
|
157
|
+
help=f'Use file as makefile, default is {__default_source_file}')
|
|
142
158
|
|
|
143
159
|
parser.add_argument(
|
|
144
160
|
*dir_args,
|
|
@@ -159,14 +175,38 @@ To run a target with supported arguments, use:
|
|
|
159
175
|
subparse = targetparsers.add_parser(
|
|
160
176
|
arg,
|
|
161
177
|
description=info['full_help'],
|
|
162
|
-
help=info['help']
|
|
178
|
+
help=info['help'],
|
|
179
|
+
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
180
|
+
|
|
181
|
+
for subarg, subarg_info in info['args'].items():
|
|
182
|
+
# print(subarg, subarg_info)
|
|
183
|
+
add_args = {}
|
|
184
|
+
|
|
185
|
+
if "default" not in subarg_info:
|
|
186
|
+
add_args["required"] = True
|
|
187
|
+
else:
|
|
188
|
+
if type(subarg_info["default"]) is subarg_info["type"]:
|
|
189
|
+
add_args["default"] = subarg_info["default"]
|
|
190
|
+
|
|
191
|
+
if subarg_info["type"] is bool:
|
|
192
|
+
def str2bool(v):
|
|
193
|
+
# modified from:
|
|
194
|
+
# https://github.com/pypa/distutils/blob/8993718731b951ee36d08cb784f02aa13542ce15/distutils/util.py
|
|
195
|
+
val = v.lower()
|
|
196
|
+
if val in ('y', 'yes', 't', 'true', 'on', '1'):
|
|
197
|
+
return True
|
|
198
|
+
elif val in ('n', 'no', 'f', 'false', 'off', '0'):
|
|
199
|
+
return False
|
|
200
|
+
else:
|
|
201
|
+
raise ValueError(f"invalid truth value {val!r}")
|
|
202
|
+
subarg_info["type"] = str2bool
|
|
163
203
|
|
|
164
|
-
for subarg, subarg_type in info['args'].items():
|
|
165
204
|
subparse.add_argument(
|
|
166
205
|
f'--{subarg}',
|
|
167
206
|
dest=f'sub_{subarg}',
|
|
168
207
|
metavar=f'<{subarg}>',
|
|
169
|
-
type=
|
|
208
|
+
type=subarg_info["type"],
|
|
209
|
+
**add_args)
|
|
170
210
|
|
|
171
211
|
args = parser.parse_args()
|
|
172
212
|
target = args.target
|
siliconcompiler/core.py
CHANGED
|
@@ -15,6 +15,7 @@ import inspect
|
|
|
15
15
|
import textwrap
|
|
16
16
|
import graphviz
|
|
17
17
|
import codecs
|
|
18
|
+
import copy
|
|
18
19
|
from siliconcompiler.remote import client
|
|
19
20
|
from siliconcompiler.schema import Schema, SCHEMA_VERSION
|
|
20
21
|
from siliconcompiler.schema import utils as schema_utils
|
|
@@ -234,6 +235,7 @@ class Chip:
|
|
|
234
235
|
for future_step, future_index in nodes_to_run:
|
|
235
236
|
max_step_len = max(len(future_step), max_step_len)
|
|
236
237
|
max_index_len = max(len(future_index), max_index_len)
|
|
238
|
+
max_step_len = min(max_step_len, 20)
|
|
237
239
|
|
|
238
240
|
jobname = self.get('option', 'jobname')
|
|
239
241
|
|
|
@@ -243,7 +245,7 @@ class Chip:
|
|
|
243
245
|
index = '-' * max(max_index_len // 4, 1)
|
|
244
246
|
|
|
245
247
|
log_format.append(jobname)
|
|
246
|
-
log_format.append(f'{step: <{max_step_len}}')
|
|
248
|
+
log_format.append(f'{utils.truncate_text(step, max_step_len): <{max_step_len}}')
|
|
247
249
|
log_format.append(f'{index: >{max_index_len}}')
|
|
248
250
|
|
|
249
251
|
log_format.append('%(message)s')
|
|
@@ -555,7 +557,12 @@ class Chip:
|
|
|
555
557
|
|
|
556
558
|
elif isinstance(use_module, (Library, Chip)):
|
|
557
559
|
self._loaded_modules['libs'].append(use_module.design)
|
|
558
|
-
|
|
560
|
+
cfg = use_module.schema.cfg
|
|
561
|
+
keep_inputs = True
|
|
562
|
+
if not isinstance(use_module, Library):
|
|
563
|
+
keep_inputs = False
|
|
564
|
+
self.__import_library(use_module.design, cfg,
|
|
565
|
+
keep_input=keep_inputs)
|
|
559
566
|
|
|
560
567
|
is_auto_enable = getattr(use_module, 'is_auto_enable', None)
|
|
561
568
|
if is_auto_enable:
|
|
@@ -1001,8 +1008,8 @@ class Chip:
|
|
|
1001
1008
|
package (str): Name of package where this file can be found
|
|
1002
1009
|
'''
|
|
1003
1010
|
|
|
1004
|
-
self.
|
|
1005
|
-
|
|
1011
|
+
self._add_input_output('input', filename, fileset, filetype, iomap,
|
|
1012
|
+
step=step, index=index, package=package)
|
|
1006
1013
|
# Replace {iotable} in __doc__ with actual table for fileset/filetype and extension mapping
|
|
1007
1014
|
input.__doc__ = input.__doc__.replace("{iotable}",
|
|
1008
1015
|
utils.format_fileset_type_table())
|
|
@@ -1012,14 +1019,14 @@ class Chip:
|
|
|
1012
1019
|
step=None, index=None, package=None):
|
|
1013
1020
|
'''Same as input'''
|
|
1014
1021
|
|
|
1015
|
-
self.
|
|
1016
|
-
|
|
1022
|
+
self._add_input_output('output', filename, fileset, filetype, iomap,
|
|
1023
|
+
step=step, index=index, package=package)
|
|
1017
1024
|
# Copy input functions __doc__ and replace 'input' with 'output' to make constant
|
|
1018
1025
|
output.__doc__ = input.__doc__.replace("input", "output")
|
|
1019
1026
|
|
|
1020
1027
|
###########################################################################
|
|
1021
|
-
def
|
|
1022
|
-
|
|
1028
|
+
def _add_input_output(self, category, filename, fileset, filetype, iomap,
|
|
1029
|
+
step=None, index=None, package=None, quiet=False):
|
|
1023
1030
|
'''
|
|
1024
1031
|
Adds file to input or output groups.
|
|
1025
1032
|
Performs a lookup in the io map for the fileset and filetype
|
|
@@ -1051,12 +1058,13 @@ class Chip:
|
|
|
1051
1058
|
if not use_fileset or not use_filetype:
|
|
1052
1059
|
self.logger.error(f'Unable to infer {category} fileset and/or filetype for '
|
|
1053
1060
|
f'{filename} based on file extension.')
|
|
1054
|
-
elif not
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1061
|
+
elif not quiet:
|
|
1062
|
+
if not fileset and not filetype:
|
|
1063
|
+
self.logger.info(f'{filename} inferred as {use_fileset}/{use_filetype}')
|
|
1064
|
+
elif not filetype:
|
|
1065
|
+
self.logger.info(f'{filename} inferred as filetype {use_filetype}')
|
|
1066
|
+
elif not fileset:
|
|
1067
|
+
self.logger.info(f'{filename} inferred as fileset {use_fileset}')
|
|
1060
1068
|
|
|
1061
1069
|
self.add(category, use_fileset, use_filetype, filename,
|
|
1062
1070
|
step=step, index=index, package=package)
|
|
@@ -1162,6 +1170,10 @@ class Chip:
|
|
|
1162
1170
|
|
|
1163
1171
|
result = []
|
|
1164
1172
|
|
|
1173
|
+
collection_dir = self._getcollectdir(jobname=job)
|
|
1174
|
+
if not os.path.exists(collection_dir):
|
|
1175
|
+
collection_dir = None
|
|
1176
|
+
|
|
1165
1177
|
# Special cases for various ['tool', ...] files that may be implicitly
|
|
1166
1178
|
# under the workdir (or refdir in the case of scripts).
|
|
1167
1179
|
# TODO: it may be cleaner to have a file resolution scope flag in schema
|
|
@@ -1190,10 +1202,8 @@ class Chip:
|
|
|
1190
1202
|
search_paths = self.__convert_paths_to_posix(search_paths)
|
|
1191
1203
|
|
|
1192
1204
|
for (dependency, path) in zip(dependencies, paths):
|
|
1193
|
-
if not search_paths:
|
|
1194
|
-
import_path = self.__find_sc_imported_file(path,
|
|
1195
|
-
dependency,
|
|
1196
|
-
self._getcollectdir(jobname=job))
|
|
1205
|
+
if not search_paths and collection_dir:
|
|
1206
|
+
import_path = self.__find_sc_imported_file(path, dependency, collection_dir)
|
|
1197
1207
|
if import_path:
|
|
1198
1208
|
result.append(import_path)
|
|
1199
1209
|
continue
|
|
@@ -1238,6 +1248,10 @@ class Chip:
|
|
|
1238
1248
|
if not path:
|
|
1239
1249
|
return None
|
|
1240
1250
|
|
|
1251
|
+
collected_files = os.listdir(collected_dir)
|
|
1252
|
+
if not collected_files:
|
|
1253
|
+
return None
|
|
1254
|
+
|
|
1241
1255
|
path_paths = pathlib.PurePosixPath(path).parts
|
|
1242
1256
|
for n in range(len(path_paths)):
|
|
1243
1257
|
# Search through the path elements to see if any of the previous path parts
|
|
@@ -1247,7 +1261,11 @@ class Chip:
|
|
|
1247
1261
|
basename = str(pathlib.PurePosixPath(*path_paths[0:n]))
|
|
1248
1262
|
endname = str(pathlib.PurePosixPath(*path_paths[n:]))
|
|
1249
1263
|
|
|
1250
|
-
|
|
1264
|
+
import_name = self.__get_imported_filename(basename, package)
|
|
1265
|
+
if import_name not in collected_files:
|
|
1266
|
+
continue
|
|
1267
|
+
|
|
1268
|
+
abspath = os.path.join(collected_dir, import_name)
|
|
1251
1269
|
if endname:
|
|
1252
1270
|
abspath = os.path.join(abspath, endname)
|
|
1253
1271
|
abspath = os.path.abspath(abspath)
|
|
@@ -1256,19 +1274,18 @@ class Chip:
|
|
|
1256
1274
|
|
|
1257
1275
|
return None
|
|
1258
1276
|
|
|
1259
|
-
|
|
1260
|
-
def find_result(self, filetype, step, jobname=None, index='0'):
|
|
1277
|
+
def find_node_file(self, path, step, jobname=None, index='0'):
|
|
1261
1278
|
"""
|
|
1262
|
-
Returns the absolute path of a
|
|
1279
|
+
Returns the absolute path of a file from a particular node.
|
|
1263
1280
|
|
|
1264
|
-
Utility function that returns the absolute path to a
|
|
1281
|
+
Utility function that returns the absolute path to a node
|
|
1265
1282
|
file based on the provided arguments. The result directory
|
|
1266
1283
|
structure is:
|
|
1267
1284
|
|
|
1268
|
-
<dir>/<design>/<jobname>/<step>/<index
|
|
1285
|
+
<dir>/<design>/<jobname>/<step>/<index>/<path>
|
|
1269
1286
|
|
|
1270
1287
|
Args:
|
|
1271
|
-
|
|
1288
|
+
path (str): Path to file inside node run directory
|
|
1272
1289
|
step (str): Task step name ('syn', 'place', etc)
|
|
1273
1290
|
jobname (str): Jobid directory name
|
|
1274
1291
|
index (str): Task index
|
|
@@ -1277,23 +1294,54 @@ class Chip:
|
|
|
1277
1294
|
Returns absolute path to file.
|
|
1278
1295
|
|
|
1279
1296
|
Examples:
|
|
1280
|
-
>>> manifest_filepath = chip.
|
|
1281
|
-
Returns the absolute path to the
|
|
1297
|
+
>>> manifest_filepath = chip.find_node_file('outputs/heartbeat.vg', 'syn')
|
|
1298
|
+
Returns the absolute path to the gate level verilog.
|
|
1282
1299
|
"""
|
|
1283
1300
|
if jobname is None:
|
|
1284
1301
|
jobname = self.get('option', 'jobname')
|
|
1285
1302
|
|
|
1286
1303
|
workdir = self.getworkdir(jobname, step, index)
|
|
1287
|
-
|
|
1288
|
-
filename = f"{workdir}/outputs/{design}.{filetype}"
|
|
1304
|
+
filename = f"{workdir}/{path}"
|
|
1289
1305
|
|
|
1290
|
-
self.logger.debug("Finding
|
|
1306
|
+
self.logger.debug(f"Finding node file: {filename}")
|
|
1291
1307
|
|
|
1292
1308
|
if os.path.exists(filename):
|
|
1293
1309
|
return filename
|
|
1294
1310
|
else:
|
|
1295
1311
|
return None
|
|
1296
1312
|
|
|
1313
|
+
###########################################################################
|
|
1314
|
+
def find_result(self, filetype, step, jobname=None, index='0'):
|
|
1315
|
+
"""
|
|
1316
|
+
Returns the absolute path of a compilation result.
|
|
1317
|
+
|
|
1318
|
+
Utility function that returns the absolute path to a results
|
|
1319
|
+
file based on the provided arguments. The result directory
|
|
1320
|
+
structure is:
|
|
1321
|
+
|
|
1322
|
+
<dir>/<design>/<jobname>/<step>/<index>/outputs/<design>.filetype
|
|
1323
|
+
|
|
1324
|
+
Args:
|
|
1325
|
+
filetype (str): File extension (v, def, etc)
|
|
1326
|
+
step (str): Task step name ('syn', 'place', etc)
|
|
1327
|
+
jobname (str): Jobid directory name
|
|
1328
|
+
index (str): Task index
|
|
1329
|
+
|
|
1330
|
+
Returns:
|
|
1331
|
+
Returns absolute path to file.
|
|
1332
|
+
|
|
1333
|
+
Examples:
|
|
1334
|
+
>>> vg_filepath = chip.find_result('vg', 'syn')
|
|
1335
|
+
Returns the absolute path to the gate level verilog.
|
|
1336
|
+
"""
|
|
1337
|
+
|
|
1338
|
+
design = self.top()
|
|
1339
|
+
return self.find_node_file(
|
|
1340
|
+
f"outputs/{design}.{filetype}",
|
|
1341
|
+
step=step,
|
|
1342
|
+
jobname=jobname,
|
|
1343
|
+
index=index)
|
|
1344
|
+
|
|
1297
1345
|
###########################################################################
|
|
1298
1346
|
def __abspath(self):
|
|
1299
1347
|
'''
|
|
@@ -1568,13 +1616,15 @@ class Chip:
|
|
|
1568
1616
|
if not os.path.exists(os.path.dirname(filepath)):
|
|
1569
1617
|
os.makedirs(os.path.dirname(filepath))
|
|
1570
1618
|
|
|
1619
|
+
schema = self.schema
|
|
1571
1620
|
# resolve absolute paths
|
|
1572
1621
|
if abspath:
|
|
1573
1622
|
schema = self.__abspath()
|
|
1574
|
-
else:
|
|
1575
|
-
schema = self.schema.copy()
|
|
1576
1623
|
|
|
1577
1624
|
if prune:
|
|
1625
|
+
if schema is self.schema:
|
|
1626
|
+
schema = schema.copy()
|
|
1627
|
+
|
|
1578
1628
|
self.logger.debug('Pruning dictionary before writing file %s', filepath)
|
|
1579
1629
|
schema.prune()
|
|
1580
1630
|
|
|
@@ -1797,7 +1847,7 @@ class Chip:
|
|
|
1797
1847
|
return not error
|
|
1798
1848
|
|
|
1799
1849
|
###########################################################################
|
|
1800
|
-
def __import_library(self, libname, libcfg, job=None, clobber=True):
|
|
1850
|
+
def __import_library(self, libname, libcfg, job=None, clobber=True, keep_input=True):
|
|
1801
1851
|
'''Helper to import library with config 'libconfig' as a library
|
|
1802
1852
|
'libname' in current Chip object.'''
|
|
1803
1853
|
if job:
|
|
@@ -1808,19 +1858,22 @@ class Chip:
|
|
|
1808
1858
|
if 'library' in libcfg:
|
|
1809
1859
|
for sublib_name, sublibcfg in libcfg['library'].items():
|
|
1810
1860
|
self.__import_library(sublib_name, sublibcfg,
|
|
1811
|
-
job=job, clobber=clobber)
|
|
1812
|
-
|
|
1813
|
-
del libcfg['library']
|
|
1861
|
+
job=job, clobber=clobber, keep_input=keep_input)
|
|
1814
1862
|
|
|
1815
1863
|
if libname in cfg:
|
|
1816
1864
|
if not clobber:
|
|
1817
1865
|
return
|
|
1818
1866
|
|
|
1819
|
-
cfg[libname] = libcfg
|
|
1820
1867
|
self.__import_data_sources(libcfg)
|
|
1868
|
+
cfg[libname] = {}
|
|
1821
1869
|
|
|
1822
|
-
|
|
1823
|
-
|
|
1870
|
+
# Only keep some sections to avoid recursive bloat
|
|
1871
|
+
keeps = ['asic', 'design', 'fpga', 'option', 'output', 'package']
|
|
1872
|
+
if keep_input:
|
|
1873
|
+
keeps.append('input')
|
|
1874
|
+
for section in list(libcfg.keys()):
|
|
1875
|
+
if section in keeps:
|
|
1876
|
+
cfg[libname][section] = copy.deepcopy(libcfg[section])
|
|
1824
1877
|
|
|
1825
1878
|
###########################################################################
|
|
1826
1879
|
def write_flowgraph(self, filename, flow=None,
|
|
@@ -1946,7 +1999,7 @@ class Chip:
|
|
|
1946
1999
|
|
|
1947
2000
|
###########################################################################
|
|
1948
2001
|
def write_dependencygraph(self, filename, flow=None,
|
|
1949
|
-
|
|
2002
|
+
fontcolor='#000000', color_scheme=None,
|
|
1950
2003
|
background='transparent', fontsize='14',
|
|
1951
2004
|
border=True, landscape=False):
|
|
1952
2005
|
r'''
|
|
@@ -1964,8 +2017,9 @@ class Chip:
|
|
|
1964
2017
|
Args:
|
|
1965
2018
|
filename (filepath): Output filepath
|
|
1966
2019
|
flow (str): Name of flowgraph to render
|
|
1967
|
-
fillcolor(str): Node fill RGB color hex value
|
|
1968
2020
|
fontcolor (str): Node font RGB color hex value
|
|
2021
|
+
color_scheme (str): Name of the color scheme to apply to the nodes.
|
|
2022
|
+
Valid choices are: "none", "simple", "detailed"
|
|
1969
2023
|
background (str): Background color
|
|
1970
2024
|
fontsize (str): Node text font size
|
|
1971
2025
|
border (bool): Enables node border if True
|
|
@@ -1981,6 +2035,33 @@ class Chip:
|
|
|
1981
2035
|
fileroot, ext = os.path.splitext(filepath)
|
|
1982
2036
|
fileformat = ext.replace(".", "")
|
|
1983
2037
|
|
|
2038
|
+
color_schemes = {
|
|
2039
|
+
"none": {
|
|
2040
|
+
"design": "white",
|
|
2041
|
+
"library": "white",
|
|
2042
|
+
"logiclib": "white",
|
|
2043
|
+
"macrolib": "white"
|
|
2044
|
+
},
|
|
2045
|
+
"simple": {
|
|
2046
|
+
"design": "lightgreen",
|
|
2047
|
+
"library": "white",
|
|
2048
|
+
"logiclib": "lightgreen",
|
|
2049
|
+
"macrolib": "lightgreen"
|
|
2050
|
+
},
|
|
2051
|
+
"detailed": {
|
|
2052
|
+
"design": "lightgreen",
|
|
2053
|
+
"library": "white",
|
|
2054
|
+
"logiclib": "lightskyblue",
|
|
2055
|
+
"macrolib": "lightgoldenrod2"
|
|
2056
|
+
},
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
if not color_scheme:
|
|
2060
|
+
color_scheme = "none"
|
|
2061
|
+
|
|
2062
|
+
if color_scheme not in color_schemes:
|
|
2063
|
+
raise ValueError(f'{color_scheme} is not a valid color scheme')
|
|
2064
|
+
|
|
1984
2065
|
# controlling border width
|
|
1985
2066
|
if border:
|
|
1986
2067
|
penwidth = '1'
|
|
@@ -2006,7 +2087,7 @@ class Chip:
|
|
|
2006
2087
|
nodes.add(node)
|
|
2007
2088
|
dot.node(node, label=node, bordercolor=fontcolor, style='filled',
|
|
2008
2089
|
fontcolor=fontcolor, fontsize=fontsize, ordering="in",
|
|
2009
|
-
penwidth=penwidth, fillcolor=
|
|
2090
|
+
penwidth=penwidth, fillcolor="white")
|
|
2010
2091
|
return node
|
|
2011
2092
|
|
|
2012
2093
|
nodes = {}
|
|
@@ -2019,32 +2100,53 @@ class Chip:
|
|
|
2019
2100
|
if root_label in nodes:
|
|
2020
2101
|
return
|
|
2021
2102
|
|
|
2022
|
-
in_libs = lib.get('option', 'library',
|
|
2023
|
-
step=Schema.GLOBAL_KEY, index=Schema.GLOBAL_KEY) + \
|
|
2024
|
-
lib.get('asic', 'logiclib',
|
|
2025
|
-
step=Schema.GLOBAL_KEY, index=Schema.GLOBAL_KEY) + \
|
|
2026
|
-
lib.get('asic', 'macrolib',
|
|
2027
|
-
step=Schema.GLOBAL_KEY, index=Schema.GLOBAL_KEY)
|
|
2028
|
-
|
|
2029
2103
|
in_labels = []
|
|
2030
|
-
for in_lib in
|
|
2104
|
+
for in_lib in lib.get('option', 'library',
|
|
2105
|
+
step=Schema.GLOBAL_KEY, index=Schema.GLOBAL_KEY):
|
|
2031
2106
|
in_labels.append(f'library-{in_lib}')
|
|
2107
|
+
for in_lib in lib.get('asic', 'logiclib',
|
|
2108
|
+
step=Schema.GLOBAL_KEY, index=Schema.GLOBAL_KEY):
|
|
2109
|
+
in_labels.append(f'logiclib-{in_lib}')
|
|
2110
|
+
for in_lib in lib.get('asic', 'macrolib',
|
|
2111
|
+
step=Schema.GLOBAL_KEY, index=Schema.GLOBAL_KEY):
|
|
2112
|
+
in_labels.append(f'macrolib-{in_lib}')
|
|
2113
|
+
|
|
2114
|
+
shape = "oval"
|
|
2115
|
+
if root_type == "logiclib":
|
|
2116
|
+
shape = "box"
|
|
2117
|
+
elif root_type == "macrolib":
|
|
2118
|
+
shape = "box"
|
|
2119
|
+
elif root_type == "design":
|
|
2120
|
+
shape = "box"
|
|
2121
|
+
|
|
2122
|
+
color = color_schemes[color_scheme][root_type]
|
|
2032
2123
|
|
|
2033
2124
|
nodes[root_label] = {
|
|
2034
2125
|
"text": name,
|
|
2035
|
-
"shape":
|
|
2126
|
+
"shape": shape,
|
|
2127
|
+
"color": color,
|
|
2036
2128
|
"connects_to": set(in_labels)
|
|
2037
2129
|
}
|
|
2038
2130
|
|
|
2039
|
-
for in_lib in
|
|
2040
|
-
|
|
2131
|
+
for in_lib in lib.get('option', 'library',
|
|
2132
|
+
step=Schema.GLOBAL_KEY, index=Schema.GLOBAL_KEY):
|
|
2133
|
+
collect_library("library", Schema(cfg=self.getdict('library', in_lib)),
|
|
2134
|
+
name=in_lib)
|
|
2135
|
+
for in_lib in lib.get('asic', 'logiclib',
|
|
2136
|
+
step=Schema.GLOBAL_KEY, index=Schema.GLOBAL_KEY):
|
|
2137
|
+
collect_library("logiclib", Schema(cfg=self.getdict('library', in_lib)),
|
|
2138
|
+
name=in_lib)
|
|
2139
|
+
for in_lib in lib.get('asic', 'macrolib',
|
|
2140
|
+
step=Schema.GLOBAL_KEY, index=Schema.GLOBAL_KEY):
|
|
2141
|
+
collect_library("macrolib", Schema(cfg=self.getdict('library', in_lib)),
|
|
2142
|
+
name=in_lib)
|
|
2041
2143
|
|
|
2042
2144
|
collect_library("design", self)
|
|
2043
2145
|
|
|
2044
2146
|
for label, info in nodes.items():
|
|
2045
2147
|
dot.node(label, label=info['text'], bordercolor=fontcolor, style='filled',
|
|
2046
2148
|
fontcolor=fontcolor, fontsize=fontsize, ordering="in",
|
|
2047
|
-
penwidth=penwidth, fillcolor=
|
|
2149
|
+
penwidth=penwidth, fillcolor=info["color"], shape=info['shape'])
|
|
2048
2150
|
|
|
2049
2151
|
for conn in info['connects_to']:
|
|
2050
2152
|
dot.edge(label, conn, dir='back')
|
|
@@ -2086,7 +2188,7 @@ class Chip:
|
|
|
2086
2188
|
step=r_step, index=r_index)
|
|
2087
2189
|
else:
|
|
2088
2190
|
self.set(*key,
|
|
2089
|
-
list(map(lambda x: x
|
|
2191
|
+
list(map(lambda x: new_library if x == org_library else x, val)),
|
|
2090
2192
|
step=r_step, index=r_index)
|
|
2091
2193
|
else:
|
|
2092
2194
|
for val, r_step, r_index in self.schema._getvals(*key):
|
|
@@ -2100,7 +2202,7 @@ class Chip:
|
|
|
2100
2202
|
step=r_step, index=r_index)
|
|
2101
2203
|
else:
|
|
2102
2204
|
self.set(*key,
|
|
2103
|
-
list(map(lambda x: x
|
|
2205
|
+
list(map(lambda x: new_library if x == org_library else x, val)),
|
|
2104
2206
|
step=r_step, index=r_index)
|
|
2105
2207
|
|
|
2106
2208
|
swap('option', 'library')
|
siliconcompiler/flowgraph.py
CHANGED
|
@@ -423,7 +423,8 @@ def _get_flowgraph_information(chip, flow, io=True):
|
|
|
423
423
|
from siliconcompiler.tools._common import input_provides, input_file_node_name
|
|
424
424
|
|
|
425
425
|
# Save schema to avoid making permanent changes
|
|
426
|
-
org_schema = chip.schema
|
|
426
|
+
org_schema = chip.schema
|
|
427
|
+
chip.schema = chip.schema.copy()
|
|
427
428
|
|
|
428
429
|
# Setup nodes
|
|
429
430
|
node_exec_order = _get_flowgraph_execution_order(chip, flow)
|
siliconcompiler/flows/dvflow.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import siliconcompiler
|
|
2
2
|
|
|
3
3
|
from siliconcompiler.tools.icarus import compile as icarus_compile
|
|
4
|
+
from siliconcompiler.tools.verilator import compile as verilator_compile
|
|
4
5
|
from siliconcompiler.tools.execute import exec_input
|
|
5
6
|
|
|
6
7
|
|
|
@@ -44,17 +45,21 @@ def setup(chip,
|
|
|
44
45
|
if tool == 'icarus':
|
|
45
46
|
tasks['compile'] = icarus_compile
|
|
46
47
|
tasks['sim'] = exec_input
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
]
|
|
51
|
-
flow_np = {
|
|
52
|
-
'compile': 1,
|
|
53
|
-
'sim': np
|
|
54
|
-
}
|
|
48
|
+
elif tool == 'verilator':
|
|
49
|
+
tasks['compile'] = verilator_compile
|
|
50
|
+
tasks['sim'] = exec_input
|
|
55
51
|
else:
|
|
56
52
|
raise ValueError(f'{tool} is not a supported tool for {flowname}: icarus')
|
|
57
53
|
|
|
54
|
+
flowpipe = [
|
|
55
|
+
'compile',
|
|
56
|
+
'sim'
|
|
57
|
+
]
|
|
58
|
+
flow_np = {
|
|
59
|
+
'compile': 1,
|
|
60
|
+
'sim': np
|
|
61
|
+
}
|
|
62
|
+
|
|
58
63
|
prevstep = None
|
|
59
64
|
# Flow setup
|
|
60
65
|
for step in flowpipe:
|
siliconcompiler/issue.py
CHANGED
|
@@ -153,6 +153,8 @@ def generate_testcase(chip,
|
|
|
153
153
|
os.chdir(new_work_dir)
|
|
154
154
|
|
|
155
155
|
# Rewrite replay.sh
|
|
156
|
+
prev_quiet = chip.get('option', 'quiet', step=step, index=index)
|
|
157
|
+
chip.set('option', 'quiet', True, step=step, index=index)
|
|
156
158
|
from siliconcompiler import SiliconCompilerError
|
|
157
159
|
try:
|
|
158
160
|
# Rerun setup
|
|
@@ -167,6 +169,7 @@ def generate_testcase(chip,
|
|
|
167
169
|
pass
|
|
168
170
|
except SiliconCompilerError:
|
|
169
171
|
pass
|
|
172
|
+
chip.set('option', 'quiet', prev_quiet, step=step, index=index)
|
|
170
173
|
|
|
171
174
|
flow = chip.get('option', 'flow')
|
|
172
175
|
is_python_tool = hasattr(chip._get_task_module(step, index, flow=flow), 'run')
|
|
@@ -14,7 +14,7 @@ def _generate_html_report(chip, flow, flowgraph_nodes, results_html):
|
|
|
14
14
|
'''
|
|
15
15
|
|
|
16
16
|
# only report tool based steps functions
|
|
17
|
-
for (step, index) in flowgraph_nodes
|
|
17
|
+
for (step, index) in list(flowgraph_nodes):
|
|
18
18
|
tool, task = get_tool_task(chip, step, '0', flow=flow)
|
|
19
19
|
if tool == 'builtin':
|
|
20
20
|
index = flowgraph_nodes.index((step, index))
|