siliconcompiler 0.28.2__py3-none-any.whl → 0.28.4__py3-none-any.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/_common.py +12 -0
- siliconcompiler/_metadata.py +1 -1
- siliconcompiler/apps/sc_dashboard.py +6 -2
- siliconcompiler/apps/sc_install.py +61 -13
- siliconcompiler/apps/sc_remote.py +1 -1
- siliconcompiler/core.py +132 -68
- siliconcompiler/fpgas/vpr_example.py +8 -0
- siliconcompiler/package.py +3 -2
- siliconcompiler/remote/client.py +41 -10
- siliconcompiler/report/__init__.py +1 -1
- siliconcompiler/report/{streamlit_report.py → dashboard/__init__.py} +56 -10
- siliconcompiler/report/dashboard/components/__init__.py +546 -0
- siliconcompiler/report/dashboard/components/flowgraph.py +114 -0
- siliconcompiler/report/dashboard/components/graph.py +208 -0
- siliconcompiler/report/dashboard/layouts/__init__.py +20 -0
- siliconcompiler/report/dashboard/layouts/_common.py +43 -0
- siliconcompiler/report/dashboard/layouts/vertical_flowgraph.py +96 -0
- siliconcompiler/report/dashboard/layouts/vertical_flowgraph_node_tab.py +117 -0
- siliconcompiler/report/dashboard/layouts/vertical_flowgraph_sac_tabs.py +110 -0
- siliconcompiler/report/dashboard/state.py +217 -0
- siliconcompiler/report/dashboard/utils/__init__.py +73 -0
- siliconcompiler/report/dashboard/utils/file_utils.py +120 -0
- siliconcompiler/report/dashboard/viewer.py +36 -0
- siliconcompiler/report/report.py +22 -4
- siliconcompiler/report/summary_table.py +1 -2
- siliconcompiler/report/utils.py +1 -2
- siliconcompiler/scheduler/__init__.py +45 -6
- siliconcompiler/schema/schema_obj.py +4 -2
- siliconcompiler/sphinx_ext/dynamicgen.py +6 -0
- siliconcompiler/tools/_common/__init__.py +44 -6
- siliconcompiler/tools/_common/asic.py +79 -23
- siliconcompiler/tools/genfasm/genfasm.py +7 -0
- siliconcompiler/tools/ghdl/convert.py +7 -0
- siliconcompiler/tools/klayout/convert_drc_db.py +60 -0
- siliconcompiler/tools/klayout/drc.py +156 -0
- siliconcompiler/tools/klayout/export.py +2 -0
- siliconcompiler/tools/klayout/klayout.py +0 -1
- siliconcompiler/tools/klayout/klayout_convert_drc_db.py +182 -0
- siliconcompiler/tools/klayout/operations.py +2 -0
- siliconcompiler/tools/klayout/screenshot.py +2 -0
- siliconcompiler/tools/klayout/show.py +4 -4
- siliconcompiler/tools/magic/drc.py +21 -0
- siliconcompiler/tools/magic/extspice.py +21 -0
- siliconcompiler/tools/magic/magic.py +29 -0
- siliconcompiler/tools/magic/sc_drc.tcl +2 -12
- siliconcompiler/tools/magic/sc_extspice.tcl +3 -15
- siliconcompiler/tools/openroad/floorplan.py +5 -0
- siliconcompiler/tools/openroad/openroad.py +56 -5
- siliconcompiler/tools/openroad/scripts/sc_apr.tcl +15 -0
- siliconcompiler/tools/openroad/scripts/sc_cts.tcl +18 -13
- siliconcompiler/tools/openroad/scripts/sc_floorplan.tcl +61 -10
- siliconcompiler/tools/openroad/scripts/sc_metrics.tcl +10 -0
- siliconcompiler/tools/openroad/scripts/sc_procs.tcl +31 -1
- siliconcompiler/tools/openroad/scripts/sc_route.tcl +8 -2
- siliconcompiler/tools/openroad/scripts/sc_screenshot.tcl +0 -5
- siliconcompiler/tools/openroad/scripts/sc_write_images.tcl +36 -6
- siliconcompiler/tools/surelog/__init__.py +12 -0
- siliconcompiler/tools/verilator/compile.py +27 -0
- siliconcompiler/tools/verilator/verilator.py +9 -0
- siliconcompiler/tools/vpr/vpr.py +18 -0
- siliconcompiler/tools/yosys/{syn_asic_fpga_shared.tcl → procs.tcl} +23 -0
- siliconcompiler/tools/yosys/sc_screenshot.tcl +104 -0
- siliconcompiler/tools/yosys/sc_syn.tcl +7 -9
- siliconcompiler/tools/yosys/screenshot.py +153 -0
- siliconcompiler/tools/yosys/syn_asic.py +3 -0
- siliconcompiler/tools/yosys/syn_asic.tcl +1 -3
- siliconcompiler/tools/yosys/syn_fpga.tcl +3 -2
- siliconcompiler/toolscripts/_tools.json +10 -5
- siliconcompiler/toolscripts/rhel8/install-chisel.sh +26 -0
- siliconcompiler/toolscripts/rhel8/install-ghdl.sh +25 -0
- siliconcompiler/toolscripts/rhel8/install-icarus.sh +40 -0
- siliconcompiler/toolscripts/rhel8/install-klayout.sh +17 -0
- siliconcompiler/toolscripts/rhel8/install-magic.sh +26 -0
- siliconcompiler/toolscripts/rhel8/install-montage.sh +5 -0
- siliconcompiler/toolscripts/rhel8/install-netgen.sh +25 -0
- siliconcompiler/toolscripts/rhel8/install-openroad.sh +31 -0
- siliconcompiler/toolscripts/rhel8/install-slang.sh +31 -0
- siliconcompiler/toolscripts/rhel8/install-surelog.sh +32 -0
- siliconcompiler/toolscripts/rhel8/install-sv2v.sh +27 -0
- siliconcompiler/toolscripts/rhel8/install-verible.sh +24 -0
- siliconcompiler/toolscripts/rhel8/install-verilator.sh +40 -0
- siliconcompiler/toolscripts/rhel8/install-xyce.sh +64 -0
- siliconcompiler/toolscripts/rhel8/install-yosys.sh +23 -0
- siliconcompiler/toolscripts/rhel9/install-chisel.sh +26 -0
- siliconcompiler/toolscripts/rhel9/install-ghdl.sh +25 -0
- siliconcompiler/toolscripts/rhel9/install-icarus.sh +40 -0
- siliconcompiler/toolscripts/rhel9/install-klayout.sh +17 -0
- siliconcompiler/toolscripts/rhel9/install-magic.sh +26 -0
- siliconcompiler/toolscripts/rhel9/install-montage.sh +5 -0
- siliconcompiler/toolscripts/rhel9/install-netgen.sh +25 -0
- siliconcompiler/toolscripts/rhel9/install-slang.sh +31 -0
- siliconcompiler/toolscripts/rhel9/install-surelog.sh +32 -0
- siliconcompiler/toolscripts/rhel9/install-sv2v.sh +27 -0
- siliconcompiler/toolscripts/rhel9/install-verible.sh +24 -0
- siliconcompiler/toolscripts/rhel9/install-verilator.sh +40 -0
- siliconcompiler/toolscripts/rhel9/install-xdm.sh +43 -0
- siliconcompiler/toolscripts/rhel9/install-xyce.sh +64 -0
- siliconcompiler/toolscripts/rhel9/install-yosys.sh +23 -0
- siliconcompiler/toolscripts/ubuntu20/install-icepack.sh +1 -1
- siliconcompiler/toolscripts/ubuntu20/install-xdm.sh +40 -0
- siliconcompiler/toolscripts/ubuntu20/install-yosys.sh +2 -2
- siliconcompiler/toolscripts/ubuntu22/install-icepack.sh +1 -1
- siliconcompiler/toolscripts/ubuntu22/install-xdm.sh +40 -0
- siliconcompiler/toolscripts/ubuntu22/install-yosys.sh +2 -2
- siliconcompiler/toolscripts/ubuntu24/install-icepack.sh +1 -1
- siliconcompiler/toolscripts/ubuntu24/install-klayout.sh +2 -0
- siliconcompiler/toolscripts/ubuntu24/install-xdm.sh +40 -0
- siliconcompiler/toolscripts/ubuntu24/install-yosys.sh +2 -2
- siliconcompiler/utils/__init__.py +30 -1
- siliconcompiler/utils/showtools.py +4 -0
- {siliconcompiler-0.28.2.dist-info → siliconcompiler-0.28.4.dist-info}/METADATA +22 -8
- {siliconcompiler-0.28.2.dist-info → siliconcompiler-0.28.4.dist-info}/RECORD +116 -67
- {siliconcompiler-0.28.2.dist-info → siliconcompiler-0.28.4.dist-info}/WHEEL +1 -1
- siliconcompiler/report/streamlit_viewer.py +0 -944
- {siliconcompiler-0.28.2.dist-info → siliconcompiler-0.28.4.dist-info}/LICENSE +0 -0
- {siliconcompiler-0.28.2.dist-info → siliconcompiler-0.28.4.dist-info}/entry_points.txt +0 -0
- {siliconcompiler-0.28.2.dist-info → siliconcompiler-0.28.4.dist-info}/top_level.txt +0 -0
|
@@ -134,6 +134,10 @@ def _finalize_run(chip, environment):
|
|
|
134
134
|
filepath = os.path.join(chip.getworkdir(), f"{chip.design}.pkg.json")
|
|
135
135
|
chip.write_manifest(filepath)
|
|
136
136
|
|
|
137
|
+
# Update dashboard
|
|
138
|
+
if chip._dash:
|
|
139
|
+
chip._dash.update_manifest()
|
|
140
|
+
|
|
137
141
|
send_messages.send(chip, 'summary', None, None)
|
|
138
142
|
|
|
139
143
|
|
|
@@ -278,6 +282,11 @@ def _local_process(chip, flow):
|
|
|
278
282
|
processes = {}
|
|
279
283
|
local_processes = []
|
|
280
284
|
_prepare_nodes(chip, nodes_to_run, processes, local_processes, flow)
|
|
285
|
+
|
|
286
|
+
# Update dashboard before run begins
|
|
287
|
+
if chip._dash:
|
|
288
|
+
chip._dash.update_manifest()
|
|
289
|
+
|
|
281
290
|
try:
|
|
282
291
|
_launch_nodes(chip, nodes_to_run, processes, local_processes)
|
|
283
292
|
except KeyboardInterrupt:
|
|
@@ -889,6 +898,7 @@ def _run_executable_or_builtin(chip, step, index, version, toolpath, workdir, ru
|
|
|
889
898
|
|
|
890
899
|
cmd_start_time = time.time()
|
|
891
900
|
proc = subprocess.Popen(cmdlist,
|
|
901
|
+
stdin=subprocess.DEVNULL,
|
|
892
902
|
stdout=stdout_writer,
|
|
893
903
|
stderr=stderr_writer,
|
|
894
904
|
preexec_fn=preexec_fn)
|
|
@@ -985,6 +995,8 @@ def _check_logfile(chip, step, index, quiet=False, run_func=None):
|
|
|
985
995
|
Check log file (must be after post-process)
|
|
986
996
|
'''
|
|
987
997
|
if run_func is None:
|
|
998
|
+
tool, task = get_tool_task(chip, step, index)
|
|
999
|
+
|
|
988
1000
|
log_file = os.path.join(chip.getworkdir(step=step, index=index), f'{step}.log')
|
|
989
1001
|
matches = check_logfile(chip, step=step, index=index,
|
|
990
1002
|
display=not quiet,
|
|
@@ -994,13 +1006,27 @@ def _check_logfile(chip, step, index, quiet=False, run_func=None):
|
|
|
994
1006
|
if errors is None:
|
|
995
1007
|
errors = 0
|
|
996
1008
|
errors += matches['errors']
|
|
997
|
-
|
|
1009
|
+
|
|
1010
|
+
sources = [f'{step}.log']
|
|
1011
|
+
if chip.valid('tool', tool, 'task', task, 'regex', 'errors'):
|
|
1012
|
+
if chip.get('tool', tool, 'task', task, 'regex', 'errors',
|
|
1013
|
+
step=step, index=index):
|
|
1014
|
+
sources.append(f'{step}.errors')
|
|
1015
|
+
|
|
1016
|
+
record_metric(chip, step, index, 'errors', errors, sources)
|
|
998
1017
|
if 'warnings' in matches:
|
|
999
1018
|
warnings = chip.get('metric', 'warnings', step=step, index=index)
|
|
1000
1019
|
if warnings is None:
|
|
1001
1020
|
warnings = 0
|
|
1002
1021
|
warnings += matches['warnings']
|
|
1003
|
-
|
|
1022
|
+
|
|
1023
|
+
sources = [f'{step}.log']
|
|
1024
|
+
if chip.valid('tool', tool, 'task', task, 'regex', 'warnings'):
|
|
1025
|
+
if chip.get('tool', tool, 'task', task, 'regex', 'warnings',
|
|
1026
|
+
step=step, index=index):
|
|
1027
|
+
sources.append(f'{step}.warnings')
|
|
1028
|
+
|
|
1029
|
+
record_metric(chip, step, index, 'warnings', warnings, sources)
|
|
1004
1030
|
|
|
1005
1031
|
|
|
1006
1032
|
def _executenode(chip, step, index, replay):
|
|
@@ -1093,6 +1119,7 @@ def _check_tool_version(chip, step, index, run_func=None):
|
|
|
1093
1119
|
cmdlist = [exe]
|
|
1094
1120
|
cmdlist.extend(veropt)
|
|
1095
1121
|
proc = subprocess.run(cmdlist,
|
|
1122
|
+
stdin=subprocess.DEVNULL,
|
|
1096
1123
|
stdout=subprocess.PIPE,
|
|
1097
1124
|
stderr=subprocess.STDOUT,
|
|
1098
1125
|
universal_newlines=True)
|
|
@@ -1354,16 +1381,16 @@ def _prepare_nodes(chip, nodes_to_run, processes, local_processes, flow):
|
|
|
1354
1381
|
def _check_node_dependencies(chip, node, deps, deps_was_successful):
|
|
1355
1382
|
had_deps = len(deps) > 0
|
|
1356
1383
|
step, index = node
|
|
1357
|
-
tool,
|
|
1384
|
+
tool, _ = get_tool_task(chip, step, index)
|
|
1358
1385
|
|
|
1359
1386
|
# Clear any nodes that have finished from dependency list.
|
|
1360
1387
|
for in_step, in_index in list(deps):
|
|
1361
1388
|
in_status = chip.get('record', 'status', step=in_step, index=in_index)
|
|
1362
|
-
if
|
|
1389
|
+
if NodeStatus.is_done(in_status):
|
|
1363
1390
|
deps.remove((in_step, in_index))
|
|
1364
1391
|
if in_status == NodeStatus.SUCCESS:
|
|
1365
1392
|
deps_was_successful[node] = True
|
|
1366
|
-
if
|
|
1393
|
+
if NodeStatus.is_error(in_status):
|
|
1367
1394
|
# Fail if any dependency failed for non-builtin task
|
|
1368
1395
|
if tool != 'builtin':
|
|
1369
1396
|
deps.clear()
|
|
@@ -1418,7 +1445,7 @@ def _launch_nodes(chip, nodes_to_run, processes, local_processes):
|
|
|
1418
1445
|
_get_callback('pre_run')(chip)
|
|
1419
1446
|
|
|
1420
1447
|
while len(nodes_to_run) > 0 or len(running_nodes) > 0:
|
|
1421
|
-
_process_completed_nodes(chip, processes, running_nodes)
|
|
1448
|
+
changed = _process_completed_nodes(chip, processes, running_nodes)
|
|
1422
1449
|
|
|
1423
1450
|
# Check for new nodes that can be launched.
|
|
1424
1451
|
for node, deps in list(nodes_to_run.items()):
|
|
@@ -1440,6 +1467,9 @@ def _launch_nodes(chip, nodes_to_run, processes, local_processes):
|
|
|
1440
1467
|
if _get_callback('pre_node'):
|
|
1441
1468
|
_get_callback('pre_node')(chip, *node)
|
|
1442
1469
|
|
|
1470
|
+
chip.set('record', 'status', NodeStatus.RUNNING, step=node[0], index=node[1])
|
|
1471
|
+
changed = True
|
|
1472
|
+
|
|
1443
1473
|
processes[node].start()
|
|
1444
1474
|
del nodes_to_run[node]
|
|
1445
1475
|
running_nodes[node] = requested_threads
|
|
@@ -1452,11 +1482,16 @@ def _launch_nodes(chip, nodes_to_run, processes, local_processes):
|
|
|
1452
1482
|
raise SiliconCompilerError(
|
|
1453
1483
|
'Nodes left to run, but no running nodes. From/to may be invalid.', chip=chip)
|
|
1454
1484
|
|
|
1485
|
+
if chip._dash and changed:
|
|
1486
|
+
# Update dashboard if the manifest changed
|
|
1487
|
+
chip._dash.update_manifest()
|
|
1488
|
+
|
|
1455
1489
|
# TODO: exponential back-off with max?
|
|
1456
1490
|
time.sleep(0.1)
|
|
1457
1491
|
|
|
1458
1492
|
|
|
1459
1493
|
def _process_completed_nodes(chip, processes, running_nodes):
|
|
1494
|
+
changed = False
|
|
1460
1495
|
for node in list(running_nodes.keys()):
|
|
1461
1496
|
if not processes[node].is_alive():
|
|
1462
1497
|
step, index = node
|
|
@@ -1477,9 +1512,13 @@ def _process_completed_nodes(chip, processes, running_nodes):
|
|
|
1477
1512
|
|
|
1478
1513
|
chip.set('record', 'status', status, step=step, index=index)
|
|
1479
1514
|
|
|
1515
|
+
changed = True
|
|
1516
|
+
|
|
1480
1517
|
if _get_callback('post_node'):
|
|
1481
1518
|
_get_callback('post_node')(chip, *node)
|
|
1482
1519
|
|
|
1520
|
+
return changed
|
|
1521
|
+
|
|
1483
1522
|
|
|
1484
1523
|
def _check_nodes_status(chip, flow):
|
|
1485
1524
|
def success(node):
|
|
@@ -628,7 +628,7 @@ class Schema:
|
|
|
628
628
|
return copy.deepcopy(cfg)
|
|
629
629
|
|
|
630
630
|
###########################################################################
|
|
631
|
-
def valid(self, *args, default_valid=False, job=None):
|
|
631
|
+
def valid(self, *args, default_valid=False, job=None, check_complete=False):
|
|
632
632
|
"""
|
|
633
633
|
Checks validity of a keypath.
|
|
634
634
|
|
|
@@ -653,7 +653,9 @@ class Schema:
|
|
|
653
653
|
cfg = cfg[default]
|
|
654
654
|
else:
|
|
655
655
|
return False
|
|
656
|
-
|
|
656
|
+
if check_complete:
|
|
657
|
+
return Schema._is_leaf(cfg)
|
|
658
|
+
return True
|
|
657
659
|
|
|
658
660
|
##########################################################################
|
|
659
661
|
def has_field(self, *args):
|
|
@@ -343,6 +343,8 @@ class DynamicGen(SphinxDirective):
|
|
|
343
343
|
type_heading = "Variables"
|
|
344
344
|
elif type == "file":
|
|
345
345
|
type_heading = "Files"
|
|
346
|
+
elif type == "dir":
|
|
347
|
+
type_heading = "Directories"
|
|
346
348
|
|
|
347
349
|
table = [[strong('Parameters'), strong('Help')]]
|
|
348
350
|
for key, params in cfg.items():
|
|
@@ -657,6 +659,9 @@ class ToolGen(DynamicGen):
|
|
|
657
659
|
'''Display config under `eda, <modname>` in a single table.'''
|
|
658
660
|
cfg = chip.getdict('tool', toolname, 'task', taskname)
|
|
659
661
|
schema = Schema(cfg=cfg)
|
|
662
|
+
for vals, step, index in schema._getvals('require'):
|
|
663
|
+
schema.set('require', sorted(set(vals)),
|
|
664
|
+
step=step, index=index)
|
|
660
665
|
schema.prune()
|
|
661
666
|
pruned = schema.cfg
|
|
662
667
|
table = build_schema_value_table(pruned, self.env.docname,
|
|
@@ -789,6 +794,7 @@ class ToolGen(DynamicGen):
|
|
|
789
794
|
key_path = ['tool', '<tool>', 'task', '<task>']
|
|
790
795
|
self._document_free_params(cfg, 'var', key_path + ['var'], reference_prefix, s)
|
|
791
796
|
self._document_free_params(cfg, 'file', key_path + ['file'], reference_prefix, s)
|
|
797
|
+
self._document_free_params(cfg, 'dir', key_path + ['dir'], reference_prefix, s)
|
|
792
798
|
|
|
793
799
|
def _handle_setup(self, chip, module):
|
|
794
800
|
setup = self.get_setup_method(module)
|
|
@@ -2,7 +2,7 @@ import os
|
|
|
2
2
|
import pkgutil
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
def
|
|
5
|
+
def __get_library_keys(chip, include_asic=True, library=None, libraries=None):
|
|
6
6
|
'''
|
|
7
7
|
Returns a list of libraries included in this step/index
|
|
8
8
|
|
|
@@ -24,18 +24,52 @@ def get_libraries(chip, include_asic=True, library=None, libraries=None):
|
|
|
24
24
|
|
|
25
25
|
def get_libs(*key):
|
|
26
26
|
if chip.valid(*key) and chip.get(*key, step=step, index=index):
|
|
27
|
-
|
|
27
|
+
if chip.get(*key, step=step, index=index):
|
|
28
|
+
return [key]
|
|
28
29
|
return []
|
|
29
30
|
|
|
30
31
|
if include_asic:
|
|
31
32
|
libs.extend(get_libs(*pref_key, 'asic', 'logiclib'))
|
|
32
33
|
libs.extend(get_libs(*pref_key, 'asic', 'macrolib'))
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
libnames = set()
|
|
36
|
+
if library:
|
|
37
|
+
libnames.add(library)
|
|
38
|
+
for lib_key in get_libs(*pref_key, 'option', 'library'):
|
|
39
|
+
if lib_key in libs:
|
|
36
40
|
continue
|
|
37
|
-
|
|
38
|
-
libs.
|
|
41
|
+
|
|
42
|
+
libs.append(lib_key)
|
|
43
|
+
|
|
44
|
+
for libname in chip.get(*lib_key, step=step, index=index):
|
|
45
|
+
if libname in libnames:
|
|
46
|
+
continue
|
|
47
|
+
|
|
48
|
+
libnames.add(libname)
|
|
49
|
+
libs.extend(__get_library_keys(
|
|
50
|
+
chip,
|
|
51
|
+
include_asic=include_asic,
|
|
52
|
+
library=libname,
|
|
53
|
+
libraries=libnames))
|
|
54
|
+
|
|
55
|
+
return set(libs)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def get_libraries(chip, include_asic=True):
|
|
59
|
+
'''
|
|
60
|
+
Returns a list of libraries included in this step/index
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
chip (Chip): Chip object
|
|
64
|
+
include_asic (bool): include the asic libraries.
|
|
65
|
+
'''
|
|
66
|
+
step = chip.get('arg', 'step')
|
|
67
|
+
index = chip.get('arg', 'index')
|
|
68
|
+
|
|
69
|
+
libs = []
|
|
70
|
+
|
|
71
|
+
for key in __get_library_keys(chip, include_asic=include_asic):
|
|
72
|
+
libs.extend(chip.get(*key, step=step, index=index))
|
|
39
73
|
|
|
40
74
|
return set(libs)
|
|
41
75
|
|
|
@@ -212,6 +246,10 @@ def add_frontend_requires(chip, supports=None):
|
|
|
212
246
|
step = chip.get('arg', 'step')
|
|
213
247
|
index = chip.get('arg', 'index')
|
|
214
248
|
tool, task = get_tool_task(chip, step, index)
|
|
249
|
+
|
|
250
|
+
for libkey in __get_library_keys(chip):
|
|
251
|
+
chip.add('tool', tool, 'task', task, 'require', ','.join(libkey), step=step, index=index)
|
|
252
|
+
|
|
215
253
|
for opt in supports:
|
|
216
254
|
for key in opt_keys[opt]:
|
|
217
255
|
chip.add('tool', tool, 'task', task, 'require', ','.join(key), step=step, index=index)
|
|
@@ -47,7 +47,8 @@ def set_tool_task_var(chip,
|
|
|
47
47
|
option_key=None,
|
|
48
48
|
pdk_key=None,
|
|
49
49
|
lib_key=None,
|
|
50
|
-
require=None
|
|
50
|
+
require=None,
|
|
51
|
+
skip=None):
|
|
51
52
|
'''
|
|
52
53
|
Set parameter from PDK -> main library -> option -> default_value
|
|
53
54
|
'''
|
|
@@ -56,7 +57,11 @@ def set_tool_task_var(chip,
|
|
|
56
57
|
tool, task = _common.get_tool_task(chip, step, index)
|
|
57
58
|
pdkname = chip.get('option', 'pdk')
|
|
58
59
|
stackup = chip.get('option', 'stackup')
|
|
59
|
-
|
|
60
|
+
|
|
61
|
+
if not skip:
|
|
62
|
+
skip = []
|
|
63
|
+
if not isinstance(skip, (list, tuple)):
|
|
64
|
+
skip = [skip]
|
|
60
65
|
|
|
61
66
|
if not require:
|
|
62
67
|
require = []
|
|
@@ -66,31 +71,35 @@ def set_tool_task_var(chip,
|
|
|
66
71
|
check_keys = []
|
|
67
72
|
|
|
68
73
|
# Add PDK key
|
|
69
|
-
if not
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
if 'pdk' not in skip:
|
|
75
|
+
if not pdk_key:
|
|
76
|
+
pdk_key = param_key
|
|
77
|
+
check_keys.append(['pdk', pdkname, 'var', tool, stackup, pdk_key])
|
|
78
|
+
if 'pdk' in require:
|
|
79
|
+
chip.add('tool', tool, 'task', task, 'require',
|
|
80
|
+
','.join(check_keys[-1]),
|
|
81
|
+
step=step, index=index)
|
|
76
82
|
|
|
77
83
|
# Add library key
|
|
78
|
-
if not
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
84
|
+
if 'lib' not in skip:
|
|
85
|
+
mainlib = get_mainlib(chip)
|
|
86
|
+
if not lib_key:
|
|
87
|
+
lib_key = f'{tool}_{param_key}'
|
|
88
|
+
check_keys.append(['library', mainlib, 'option', 'var', lib_key])
|
|
89
|
+
if 'lib' in require:
|
|
90
|
+
chip.add('tool', tool, 'task', task, 'require',
|
|
91
|
+
','.join(check_keys[-1]),
|
|
92
|
+
step=step, index=index)
|
|
85
93
|
|
|
86
94
|
# Add option key
|
|
87
|
-
if not
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
95
|
+
if 'option' not in skip:
|
|
96
|
+
if not option_key:
|
|
97
|
+
option_key = f'{tool}_{param_key}'
|
|
98
|
+
check_keys.append(['option', 'var', option_key])
|
|
99
|
+
if 'option' in require:
|
|
100
|
+
chip.add('tool', tool, 'task', task, 'require',
|
|
101
|
+
','.join(check_keys[-1]),
|
|
102
|
+
step=step, index=index)
|
|
94
103
|
|
|
95
104
|
require_key, value = _common.pick_key(chip, reversed(check_keys), step=step, index=index)
|
|
96
105
|
if not value:
|
|
@@ -113,3 +122,50 @@ def set_tool_task_var(chip,
|
|
|
113
122
|
if schelp:
|
|
114
123
|
chip.set('tool', tool, 'task', task, 'var', param_key,
|
|
115
124
|
schelp, field='help')
|
|
125
|
+
|
|
126
|
+
return value
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def get_tool_task_var(chip,
|
|
130
|
+
param_key,
|
|
131
|
+
option_key=None,
|
|
132
|
+
pdk_key=None,
|
|
133
|
+
lib_key=None,
|
|
134
|
+
skip=None):
|
|
135
|
+
'''
|
|
136
|
+
Get parameter from PDK -> main library -> option -> default_value
|
|
137
|
+
'''
|
|
138
|
+
step = chip.get('arg', 'step')
|
|
139
|
+
index = chip.get('arg', 'index')
|
|
140
|
+
tool, _ = _common.get_tool_task(chip, step, index)
|
|
141
|
+
pdkname = chip.get('option', 'pdk')
|
|
142
|
+
stackup = chip.get('option', 'stackup')
|
|
143
|
+
|
|
144
|
+
if not skip:
|
|
145
|
+
skip = []
|
|
146
|
+
if not isinstance(skip, (list, tuple)):
|
|
147
|
+
skip = [skip]
|
|
148
|
+
|
|
149
|
+
check_keys = []
|
|
150
|
+
# Add PDK key
|
|
151
|
+
if 'pdk' not in skip:
|
|
152
|
+
if not pdk_key:
|
|
153
|
+
pdk_key = param_key
|
|
154
|
+
check_keys.append(['pdk', pdkname, 'var', tool, stackup, pdk_key])
|
|
155
|
+
|
|
156
|
+
# Add library key
|
|
157
|
+
if 'lib' not in skip:
|
|
158
|
+
mainlib = get_mainlib(chip)
|
|
159
|
+
if not lib_key:
|
|
160
|
+
lib_key = f'{tool}_{param_key}'
|
|
161
|
+
check_keys.append(['library', mainlib, 'option', 'var', lib_key])
|
|
162
|
+
|
|
163
|
+
# Add option key
|
|
164
|
+
if 'option' not in skip:
|
|
165
|
+
if not option_key:
|
|
166
|
+
option_key = f'{tool}_{param_key}'
|
|
167
|
+
check_keys.append(['option', 'var', option_key])
|
|
168
|
+
|
|
169
|
+
_, value = _common.pick_key(chip, reversed(check_keys), step=step, index=index)
|
|
170
|
+
|
|
171
|
+
return value
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from siliconcompiler.tools.vpr.vpr import parse_version as vpr_parse_version
|
|
2
2
|
from siliconcompiler.tools.vpr.vpr import normalize_version as vpr_normalize_version
|
|
3
|
+
from siliconcompiler.tools.vpr.vpr import add_tool_requirements as add_vpr_requirements
|
|
3
4
|
|
|
4
5
|
'''
|
|
5
6
|
Generate a `FSAM <https://github.com/chipsalliance/fasm>`_ file from the output of
|
|
@@ -25,6 +26,12 @@ def setup(chip):
|
|
|
25
26
|
chip.set('tool', 'genfasm', 'vswitch', '--version')
|
|
26
27
|
chip.set('tool', 'genfasm', 'version', '>=8.1.0', clobber=False)
|
|
27
28
|
|
|
29
|
+
add_tool_requirements(chip)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def add_tool_requirements(chip):
|
|
33
|
+
add_vpr_requirements(chip)
|
|
34
|
+
|
|
28
35
|
|
|
29
36
|
def parse_version(chip):
|
|
30
37
|
return vpr_parse_version(chip)
|
|
@@ -40,6 +40,13 @@ def setup(chip):
|
|
|
40
40
|
|
|
41
41
|
chip.set('tool', tool, 'task', task, 'output', f'{design}.v', step=step, index=index)
|
|
42
42
|
|
|
43
|
+
chip.set('tool', tool, 'task', task, 'var', 'extraopts', 'extra options to pass to ghdl',
|
|
44
|
+
field='help')
|
|
45
|
+
if chip.get('tool', tool, 'task', task, 'var', 'extraopts', step=step, index=index):
|
|
46
|
+
chip.add('tool', tool, 'task', task, 'require',
|
|
47
|
+
','.join(['tool', tool, 'task', task, 'var', 'extraopts']),
|
|
48
|
+
step=step, index=index)
|
|
49
|
+
|
|
43
50
|
|
|
44
51
|
################################
|
|
45
52
|
# Custom runtime options
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from siliconcompiler.tools._common import input_provides, input_file_node_name, get_tool_task
|
|
2
|
+
|
|
3
|
+
from siliconcompiler.tools.klayout import klayout
|
|
4
|
+
from siliconcompiler.tools.klayout.klayout import setup as setup_tool
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def make_docs(chip):
|
|
8
|
+
klayout.make_docs(chip)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def setup(chip):
|
|
12
|
+
'''
|
|
13
|
+
Convert a DRC db from .lyrdb or .ascii to an openroad json marker file
|
|
14
|
+
'''
|
|
15
|
+
|
|
16
|
+
# Generic tool setup.
|
|
17
|
+
setup_tool(chip)
|
|
18
|
+
|
|
19
|
+
step = chip.get('arg', 'step')
|
|
20
|
+
index = chip.get('arg', 'index')
|
|
21
|
+
tool, task = get_tool_task(chip, step, index)
|
|
22
|
+
design = chip.top()
|
|
23
|
+
|
|
24
|
+
clobber = False
|
|
25
|
+
|
|
26
|
+
chip.set('tool', tool, 'task', task, 'threads', 1,
|
|
27
|
+
step=step, index=index, clobber=clobber)
|
|
28
|
+
|
|
29
|
+
script = 'klayout_convert_drc_db.py'
|
|
30
|
+
option = ['-z', '-nc', '-rx', '-r']
|
|
31
|
+
chip.set('tool', tool, 'task', task, 'script', script,
|
|
32
|
+
step=step, index=index, clobber=clobber)
|
|
33
|
+
chip.set('tool', tool, 'task', task, 'option', option,
|
|
34
|
+
step=step, index=index, clobber=clobber)
|
|
35
|
+
|
|
36
|
+
input_nodes = set()
|
|
37
|
+
for nodes in input_provides(chip, step, index).values():
|
|
38
|
+
input_nodes.update(nodes)
|
|
39
|
+
|
|
40
|
+
chip.set('tool', tool, 'task', task, 'input', [], step=step, index=index)
|
|
41
|
+
chip.set('tool', tool, 'task', task, 'output', [], step=step, index=index)
|
|
42
|
+
for file, nodes in input_provides(chip, step, index).items():
|
|
43
|
+
if file not in (f'{design}.lyrdb', f'{design}.ascii'):
|
|
44
|
+
continue
|
|
45
|
+
|
|
46
|
+
if len(input_nodes) == 1:
|
|
47
|
+
chip.add('tool', tool, 'task', task, 'input',
|
|
48
|
+
file,
|
|
49
|
+
step=step, index=index)
|
|
50
|
+
else:
|
|
51
|
+
for in_step, in_index in nodes:
|
|
52
|
+
chip.add('tool', tool, 'task', task, 'input',
|
|
53
|
+
input_file_node_name(file, in_step, in_index),
|
|
54
|
+
step=step, index=index)
|
|
55
|
+
if not chip.get('tool', tool, 'task', task, 'input', step=step, index=index):
|
|
56
|
+
chip.add('tool', tool, 'task', task, 'input', f'{design}.lyrdb',
|
|
57
|
+
step=step, index=index)
|
|
58
|
+
|
|
59
|
+
chip.set('tool', tool, 'task', task, 'output', f'{design}.json',
|
|
60
|
+
step=step, index=index)
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import shlex
|
|
3
|
+
|
|
4
|
+
from siliconcompiler.tools._common import input_provides, has_input_files, \
|
|
5
|
+
get_input_files, get_tool_task, record_metric
|
|
6
|
+
from siliconcompiler.tools._common.asic import set_tool_task_var, get_tool_task_var
|
|
7
|
+
|
|
8
|
+
from siliconcompiler.tools.klayout import klayout
|
|
9
|
+
from siliconcompiler.tools.klayout.klayout import setup as setup_tool
|
|
10
|
+
import xml.etree.ElementTree as ET
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def make_docs(chip):
|
|
14
|
+
klayout.make_docs(chip)
|
|
15
|
+
chip.set('tool', 'klayout', 'task', 'drc', 'var', 'drc_name', '<drc_name>',
|
|
16
|
+
step='<step>', index='<index>')
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def setup(chip):
|
|
20
|
+
'''
|
|
21
|
+
Performs a design rule check on the provided layout
|
|
22
|
+
'''
|
|
23
|
+
|
|
24
|
+
# Generic tool setup.
|
|
25
|
+
setup_tool(chip)
|
|
26
|
+
|
|
27
|
+
step = chip.get('arg', 'step')
|
|
28
|
+
index = chip.get('arg', 'index')
|
|
29
|
+
tool, task = get_tool_task(chip, step, index)
|
|
30
|
+
design = chip.top()
|
|
31
|
+
|
|
32
|
+
clobber = False
|
|
33
|
+
|
|
34
|
+
option = ['-z', '-nc', '-rx']
|
|
35
|
+
chip.set('tool', tool, 'task', task, 'option', option,
|
|
36
|
+
step=step, index=index, clobber=clobber)
|
|
37
|
+
|
|
38
|
+
chip.set('tool', tool, 'task', task, 'threads', os.cpu_count(),
|
|
39
|
+
step=step, index=index, clobber=clobber)
|
|
40
|
+
|
|
41
|
+
chip.add('tool', tool, 'task', task, 'require', 'option,pdk')
|
|
42
|
+
chip.add('tool', tool, 'task', task, 'require', 'option,stackup')
|
|
43
|
+
|
|
44
|
+
chip.set('tool', tool, 'task', task, 'var', 'drc_name', 'drc',
|
|
45
|
+
step=step, index=index, clobber=False)
|
|
46
|
+
chip.add('tool', tool, 'task', task, 'require', f'tool,{tool},task,{task},var,drc_name',
|
|
47
|
+
step=step, index=index)
|
|
48
|
+
|
|
49
|
+
drc_name = chip.get('tool', tool, 'task', task, 'var', 'drc_name', step=step, index=index)
|
|
50
|
+
if not drc_name:
|
|
51
|
+
raise ValueError('drc_name is required')
|
|
52
|
+
drc_name = drc_name[0]
|
|
53
|
+
|
|
54
|
+
pdk = chip.get('option', 'pdk')
|
|
55
|
+
stackup = chip.get('option', 'stackup')
|
|
56
|
+
chip.add('tool', tool, 'task', task, 'require',
|
|
57
|
+
f'pdk,{pdk},drc,runset,klayout,{stackup},{drc_name}')
|
|
58
|
+
|
|
59
|
+
if f'{design}.gds' in input_provides(chip, step, index):
|
|
60
|
+
chip.add('tool', tool, 'task', task, 'input', design + '.gds',
|
|
61
|
+
step=step, index=index)
|
|
62
|
+
elif f'{design}.oas' in input_provides(chip, step, index):
|
|
63
|
+
chip.add('tool', tool, 'task', task, 'input', design + '.oas',
|
|
64
|
+
step=step, index=index)
|
|
65
|
+
elif has_input_files(chip, 'input', 'layout', 'oas', check_library_files=False):
|
|
66
|
+
chip.add('tool', tool, 'task', task, 'require', 'input,layout,oas',
|
|
67
|
+
step=step, index=index)
|
|
68
|
+
else:
|
|
69
|
+
chip.add('tool', tool, 'task', task, 'require', 'input,layout,gds',
|
|
70
|
+
step=step, index=index)
|
|
71
|
+
|
|
72
|
+
chip.add('tool', tool, 'task', task, 'output', design + '.lyrdb',
|
|
73
|
+
step=step, index=index)
|
|
74
|
+
|
|
75
|
+
set_tool_task_var(
|
|
76
|
+
chip,
|
|
77
|
+
f'drc_params:{drc_name}',
|
|
78
|
+
schelp="Input parameter to DRC script, in the form of key=value, if the value "
|
|
79
|
+
"is <topcell>, <input>, <report>, <threads> these will be automatically "
|
|
80
|
+
"determined.",
|
|
81
|
+
skip='lib')
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def runtime_options(chip):
|
|
85
|
+
design = chip.top()
|
|
86
|
+
|
|
87
|
+
step = chip.get('arg', 'step')
|
|
88
|
+
index = chip.get('arg', 'index')
|
|
89
|
+
tool, task = get_tool_task(chip, step, index)
|
|
90
|
+
|
|
91
|
+
pdk = chip.get('option', 'pdk')
|
|
92
|
+
stackup = chip.get('option', 'stackup')
|
|
93
|
+
|
|
94
|
+
layout = None
|
|
95
|
+
for file in [f'inputs/{design}.gds', f'inputs/{design}.oas']:
|
|
96
|
+
if os.path.isfile(file):
|
|
97
|
+
layout = file
|
|
98
|
+
break
|
|
99
|
+
|
|
100
|
+
if not layout:
|
|
101
|
+
for file in [
|
|
102
|
+
get_input_files(chip, 'input', 'layout', 'oas', add_library_files=False),
|
|
103
|
+
get_input_files(chip, 'input', 'layout', 'gds', add_library_files=False)]:
|
|
104
|
+
if file:
|
|
105
|
+
layout = file[0]
|
|
106
|
+
|
|
107
|
+
threads = chip.get('tool', tool, 'task', task, 'threads', step=step, index=index)
|
|
108
|
+
if not threads:
|
|
109
|
+
threads = 1
|
|
110
|
+
|
|
111
|
+
drc_name = chip.get('tool', tool, 'task', task, 'var', 'drc_name',
|
|
112
|
+
step=step, index=index)[0]
|
|
113
|
+
report = os.path.abspath(f"outputs/{chip.top()}.lyrdb")
|
|
114
|
+
|
|
115
|
+
runset = chip.find_files('pdk', pdk, 'drc', 'runset', 'klayout', stackup, drc_name)[0]
|
|
116
|
+
|
|
117
|
+
params_lookup = {
|
|
118
|
+
"<topcell>": chip.top(),
|
|
119
|
+
"<report>": shlex.quote(report),
|
|
120
|
+
"<threads>": threads,
|
|
121
|
+
"<input>": shlex.quote(layout)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
args = [
|
|
125
|
+
'-r', shlex.quote(runset)
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
for param in get_tool_task_var(chip, f'drc_params:{drc_name}', skip='lib'):
|
|
129
|
+
for lookup, value in params_lookup.items():
|
|
130
|
+
param = param.replace(lookup, str(value))
|
|
131
|
+
args.extend(
|
|
132
|
+
['-rd', param]
|
|
133
|
+
)
|
|
134
|
+
return args
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def post_process(chip):
|
|
138
|
+
step = chip.get('arg', 'step')
|
|
139
|
+
index = chip.get('arg', 'index')
|
|
140
|
+
|
|
141
|
+
drc_db = f"outputs/{chip.top()}.lyrdb"
|
|
142
|
+
|
|
143
|
+
drc_report = None
|
|
144
|
+
if os.path.isfile(drc_db):
|
|
145
|
+
with open(drc_db, "r") as f:
|
|
146
|
+
drc_report = ET.fromstring(f.read())
|
|
147
|
+
if drc_report is None:
|
|
148
|
+
drc_db = []
|
|
149
|
+
|
|
150
|
+
violation_count = 0
|
|
151
|
+
if drc_report:
|
|
152
|
+
violations = drc_report.find('items')
|
|
153
|
+
if violations:
|
|
154
|
+
violation_count = len(violations.findall('item'))
|
|
155
|
+
|
|
156
|
+
record_metric(chip, step, index, 'drcs', violation_count, drc_db)
|
|
@@ -19,6 +19,8 @@ def setup(chip):
|
|
|
19
19
|
_, task = get_tool_task(chip, step, index)
|
|
20
20
|
clobber = False
|
|
21
21
|
|
|
22
|
+
chip.set('tool', tool, 'task', task, 'threads', 1, step=step, index=index, clobber=clobber)
|
|
23
|
+
|
|
22
24
|
script = 'klayout_export.py'
|
|
23
25
|
option = ['-z', '-nc', '-rx', '-r']
|
|
24
26
|
chip.set('tool', tool, 'task', task, 'script', script, step=step, index=index, clobber=clobber)
|
|
@@ -82,7 +82,6 @@ def setup(chip, mode="batch"):
|
|
|
82
82
|
|
|
83
83
|
chip.set('tool', tool, 'task', task, 'refdir', refdir, step=step, index=index,
|
|
84
84
|
package='siliconcompiler', clobber=clobber)
|
|
85
|
-
chip.set('tool', tool, 'task', task, 'threads', 1, step=step, index=index, clobber=clobber)
|
|
86
85
|
|
|
87
86
|
if chip.get('option', 'nodisplay'):
|
|
88
87
|
# Tells QT to use the offscreen platform if nodisplay is used
|