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.
Files changed (117) hide show
  1. siliconcompiler/_common.py +12 -0
  2. siliconcompiler/_metadata.py +1 -1
  3. siliconcompiler/apps/sc_dashboard.py +6 -2
  4. siliconcompiler/apps/sc_install.py +61 -13
  5. siliconcompiler/apps/sc_remote.py +1 -1
  6. siliconcompiler/core.py +132 -68
  7. siliconcompiler/fpgas/vpr_example.py +8 -0
  8. siliconcompiler/package.py +3 -2
  9. siliconcompiler/remote/client.py +41 -10
  10. siliconcompiler/report/__init__.py +1 -1
  11. siliconcompiler/report/{streamlit_report.py → dashboard/__init__.py} +56 -10
  12. siliconcompiler/report/dashboard/components/__init__.py +546 -0
  13. siliconcompiler/report/dashboard/components/flowgraph.py +114 -0
  14. siliconcompiler/report/dashboard/components/graph.py +208 -0
  15. siliconcompiler/report/dashboard/layouts/__init__.py +20 -0
  16. siliconcompiler/report/dashboard/layouts/_common.py +43 -0
  17. siliconcompiler/report/dashboard/layouts/vertical_flowgraph.py +96 -0
  18. siliconcompiler/report/dashboard/layouts/vertical_flowgraph_node_tab.py +117 -0
  19. siliconcompiler/report/dashboard/layouts/vertical_flowgraph_sac_tabs.py +110 -0
  20. siliconcompiler/report/dashboard/state.py +217 -0
  21. siliconcompiler/report/dashboard/utils/__init__.py +73 -0
  22. siliconcompiler/report/dashboard/utils/file_utils.py +120 -0
  23. siliconcompiler/report/dashboard/viewer.py +36 -0
  24. siliconcompiler/report/report.py +22 -4
  25. siliconcompiler/report/summary_table.py +1 -2
  26. siliconcompiler/report/utils.py +1 -2
  27. siliconcompiler/scheduler/__init__.py +45 -6
  28. siliconcompiler/schema/schema_obj.py +4 -2
  29. siliconcompiler/sphinx_ext/dynamicgen.py +6 -0
  30. siliconcompiler/tools/_common/__init__.py +44 -6
  31. siliconcompiler/tools/_common/asic.py +79 -23
  32. siliconcompiler/tools/genfasm/genfasm.py +7 -0
  33. siliconcompiler/tools/ghdl/convert.py +7 -0
  34. siliconcompiler/tools/klayout/convert_drc_db.py +60 -0
  35. siliconcompiler/tools/klayout/drc.py +156 -0
  36. siliconcompiler/tools/klayout/export.py +2 -0
  37. siliconcompiler/tools/klayout/klayout.py +0 -1
  38. siliconcompiler/tools/klayout/klayout_convert_drc_db.py +182 -0
  39. siliconcompiler/tools/klayout/operations.py +2 -0
  40. siliconcompiler/tools/klayout/screenshot.py +2 -0
  41. siliconcompiler/tools/klayout/show.py +4 -4
  42. siliconcompiler/tools/magic/drc.py +21 -0
  43. siliconcompiler/tools/magic/extspice.py +21 -0
  44. siliconcompiler/tools/magic/magic.py +29 -0
  45. siliconcompiler/tools/magic/sc_drc.tcl +2 -12
  46. siliconcompiler/tools/magic/sc_extspice.tcl +3 -15
  47. siliconcompiler/tools/openroad/floorplan.py +5 -0
  48. siliconcompiler/tools/openroad/openroad.py +56 -5
  49. siliconcompiler/tools/openroad/scripts/sc_apr.tcl +15 -0
  50. siliconcompiler/tools/openroad/scripts/sc_cts.tcl +18 -13
  51. siliconcompiler/tools/openroad/scripts/sc_floorplan.tcl +61 -10
  52. siliconcompiler/tools/openroad/scripts/sc_metrics.tcl +10 -0
  53. siliconcompiler/tools/openroad/scripts/sc_procs.tcl +31 -1
  54. siliconcompiler/tools/openroad/scripts/sc_route.tcl +8 -2
  55. siliconcompiler/tools/openroad/scripts/sc_screenshot.tcl +0 -5
  56. siliconcompiler/tools/openroad/scripts/sc_write_images.tcl +36 -6
  57. siliconcompiler/tools/surelog/__init__.py +12 -0
  58. siliconcompiler/tools/verilator/compile.py +27 -0
  59. siliconcompiler/tools/verilator/verilator.py +9 -0
  60. siliconcompiler/tools/vpr/vpr.py +18 -0
  61. siliconcompiler/tools/yosys/{syn_asic_fpga_shared.tcl → procs.tcl} +23 -0
  62. siliconcompiler/tools/yosys/sc_screenshot.tcl +104 -0
  63. siliconcompiler/tools/yosys/sc_syn.tcl +7 -9
  64. siliconcompiler/tools/yosys/screenshot.py +153 -0
  65. siliconcompiler/tools/yosys/syn_asic.py +3 -0
  66. siliconcompiler/tools/yosys/syn_asic.tcl +1 -3
  67. siliconcompiler/tools/yosys/syn_fpga.tcl +3 -2
  68. siliconcompiler/toolscripts/_tools.json +10 -5
  69. siliconcompiler/toolscripts/rhel8/install-chisel.sh +26 -0
  70. siliconcompiler/toolscripts/rhel8/install-ghdl.sh +25 -0
  71. siliconcompiler/toolscripts/rhel8/install-icarus.sh +40 -0
  72. siliconcompiler/toolscripts/rhel8/install-klayout.sh +17 -0
  73. siliconcompiler/toolscripts/rhel8/install-magic.sh +26 -0
  74. siliconcompiler/toolscripts/rhel8/install-montage.sh +5 -0
  75. siliconcompiler/toolscripts/rhel8/install-netgen.sh +25 -0
  76. siliconcompiler/toolscripts/rhel8/install-openroad.sh +31 -0
  77. siliconcompiler/toolscripts/rhel8/install-slang.sh +31 -0
  78. siliconcompiler/toolscripts/rhel8/install-surelog.sh +32 -0
  79. siliconcompiler/toolscripts/rhel8/install-sv2v.sh +27 -0
  80. siliconcompiler/toolscripts/rhel8/install-verible.sh +24 -0
  81. siliconcompiler/toolscripts/rhel8/install-verilator.sh +40 -0
  82. siliconcompiler/toolscripts/rhel8/install-xyce.sh +64 -0
  83. siliconcompiler/toolscripts/rhel8/install-yosys.sh +23 -0
  84. siliconcompiler/toolscripts/rhel9/install-chisel.sh +26 -0
  85. siliconcompiler/toolscripts/rhel9/install-ghdl.sh +25 -0
  86. siliconcompiler/toolscripts/rhel9/install-icarus.sh +40 -0
  87. siliconcompiler/toolscripts/rhel9/install-klayout.sh +17 -0
  88. siliconcompiler/toolscripts/rhel9/install-magic.sh +26 -0
  89. siliconcompiler/toolscripts/rhel9/install-montage.sh +5 -0
  90. siliconcompiler/toolscripts/rhel9/install-netgen.sh +25 -0
  91. siliconcompiler/toolscripts/rhel9/install-slang.sh +31 -0
  92. siliconcompiler/toolscripts/rhel9/install-surelog.sh +32 -0
  93. siliconcompiler/toolscripts/rhel9/install-sv2v.sh +27 -0
  94. siliconcompiler/toolscripts/rhel9/install-verible.sh +24 -0
  95. siliconcompiler/toolscripts/rhel9/install-verilator.sh +40 -0
  96. siliconcompiler/toolscripts/rhel9/install-xdm.sh +43 -0
  97. siliconcompiler/toolscripts/rhel9/install-xyce.sh +64 -0
  98. siliconcompiler/toolscripts/rhel9/install-yosys.sh +23 -0
  99. siliconcompiler/toolscripts/ubuntu20/install-icepack.sh +1 -1
  100. siliconcompiler/toolscripts/ubuntu20/install-xdm.sh +40 -0
  101. siliconcompiler/toolscripts/ubuntu20/install-yosys.sh +2 -2
  102. siliconcompiler/toolscripts/ubuntu22/install-icepack.sh +1 -1
  103. siliconcompiler/toolscripts/ubuntu22/install-xdm.sh +40 -0
  104. siliconcompiler/toolscripts/ubuntu22/install-yosys.sh +2 -2
  105. siliconcompiler/toolscripts/ubuntu24/install-icepack.sh +1 -1
  106. siliconcompiler/toolscripts/ubuntu24/install-klayout.sh +2 -0
  107. siliconcompiler/toolscripts/ubuntu24/install-xdm.sh +40 -0
  108. siliconcompiler/toolscripts/ubuntu24/install-yosys.sh +2 -2
  109. siliconcompiler/utils/__init__.py +30 -1
  110. siliconcompiler/utils/showtools.py +4 -0
  111. {siliconcompiler-0.28.2.dist-info → siliconcompiler-0.28.4.dist-info}/METADATA +22 -8
  112. {siliconcompiler-0.28.2.dist-info → siliconcompiler-0.28.4.dist-info}/RECORD +116 -67
  113. {siliconcompiler-0.28.2.dist-info → siliconcompiler-0.28.4.dist-info}/WHEEL +1 -1
  114. siliconcompiler/report/streamlit_viewer.py +0 -944
  115. {siliconcompiler-0.28.2.dist-info → siliconcompiler-0.28.4.dist-info}/LICENSE +0 -0
  116. {siliconcompiler-0.28.2.dist-info → siliconcompiler-0.28.4.dist-info}/entry_points.txt +0 -0
  117. {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
- record_metric(chip, step, index, 'errors', errors, f'{step}.log')
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
- record_metric(chip, step, index, 'warnings', warnings, f'{step}.log')
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, task = get_tool_task(chip, step, index)
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 in_status != NodeStatus.PENDING:
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 in_status == NodeStatus.ERROR:
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
- return Schema._is_leaf(cfg)
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 get_libraries(chip, include_asic=True, library=None, libraries=None):
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
- return chip.get(*key, step=step, index=index)
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
- for lib in get_libs(*pref_key, 'option', 'library'):
35
- if lib in libs or lib in libraries:
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
- libs.append(lib)
38
- libs.extend(get_libraries(chip, include_asic=include_asic, library=lib, libraries=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
- mainlib = get_mainlib(chip)
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 pdk_key:
70
- pdk_key = param_key
71
- check_keys.append(['pdk', pdkname, 'var', tool, stackup, pdk_key])
72
- if 'pdk' in require:
73
- chip.add('tool', tool, 'task', task, 'require',
74
- ','.join(check_keys[-1]),
75
- step=step, index=index)
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 lib_key:
79
- lib_key = f'{tool}_{param_key}'
80
- check_keys.append(['library', mainlib, 'option', 'var', lib_key])
81
- if 'lib' in require:
82
- chip.add('tool', tool, 'task', task, 'require',
83
- ','.join(check_keys[-1]),
84
- step=step, index=index)
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 option_key:
88
- option_key = f'{tool}_{param_key}'
89
- check_keys.append(['option', 'var', option_key])
90
- if 'option' in require:
91
- chip.add('tool', tool, 'task', task, 'require',
92
- ','.join(check_keys[-1]),
93
- step=step, index=index)
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