siliconcompiler 0.28.9__py3-none-any.whl → 0.29.0__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 (109) hide show
  1. siliconcompiler/_metadata.py +1 -1
  2. siliconcompiler/apps/sc_remote.py +15 -14
  3. siliconcompiler/apps/sc_show.py +5 -5
  4. siliconcompiler/apps/utils/replay.py +136 -0
  5. siliconcompiler/core.py +14 -12
  6. siliconcompiler/flows/_common.py +11 -13
  7. siliconcompiler/flows/asicflow.py +83 -42
  8. siliconcompiler/remote/__init__.py +11 -0
  9. siliconcompiler/remote/client.py +753 -815
  10. siliconcompiler/report/report.py +2 -0
  11. siliconcompiler/report/summary_table.py +1 -1
  12. siliconcompiler/scheduler/__init__.py +51 -9
  13. siliconcompiler/schema/schema_cfg.py +15 -3
  14. siliconcompiler/schema/schema_obj.py +16 -0
  15. siliconcompiler/sphinx_ext/dynamicgen.py +4 -3
  16. siliconcompiler/targets/gf180_demo.py +3 -3
  17. siliconcompiler/templates/replay/requirements.txt +6 -0
  18. siliconcompiler/templates/replay/run.py.j2 +22 -0
  19. siliconcompiler/templates/replay/setup.sh +17 -0
  20. siliconcompiler/tools/_common/__init__.py +15 -1
  21. siliconcompiler/tools/_common/asic.py +10 -3
  22. siliconcompiler/tools/builtin/concatenate.py +1 -1
  23. siliconcompiler/tools/openroad/__init__.py +103 -0
  24. siliconcompiler/tools/openroad/{openroad.py → _apr.py} +413 -422
  25. siliconcompiler/tools/openroad/antenna_repair.py +78 -0
  26. siliconcompiler/tools/openroad/clock_tree_synthesis.py +64 -0
  27. siliconcompiler/tools/openroad/detailed_placement.py +59 -0
  28. siliconcompiler/tools/openroad/detailed_route.py +62 -0
  29. siliconcompiler/tools/openroad/endcap_tapcell_insertion.py +52 -0
  30. siliconcompiler/tools/openroad/fillercell_insertion.py +58 -0
  31. siliconcompiler/tools/openroad/{dfm.py → fillmetal_insertion.py} +35 -19
  32. siliconcompiler/tools/openroad/global_placement.py +58 -0
  33. siliconcompiler/tools/openroad/global_route.py +63 -0
  34. siliconcompiler/tools/openroad/init_floorplan.py +103 -0
  35. siliconcompiler/tools/openroad/macro_placement.py +65 -0
  36. siliconcompiler/tools/openroad/metrics.py +23 -8
  37. siliconcompiler/tools/openroad/pin_placement.py +56 -0
  38. siliconcompiler/tools/openroad/power_grid.py +65 -0
  39. siliconcompiler/tools/openroad/rcx_bench.py +7 -4
  40. siliconcompiler/tools/openroad/rcx_extract.py +2 -1
  41. siliconcompiler/tools/openroad/rdlroute.py +4 -4
  42. siliconcompiler/tools/openroad/repair_design.py +59 -0
  43. siliconcompiler/tools/openroad/repair_timing.py +63 -0
  44. siliconcompiler/tools/openroad/screenshot.py +9 -20
  45. siliconcompiler/tools/openroad/scripts/apr/postamble.tcl +44 -0
  46. siliconcompiler/tools/openroad/scripts/apr/preamble.tcl +95 -0
  47. siliconcompiler/tools/openroad/scripts/apr/sc_antenna_repair.tcl +51 -0
  48. siliconcompiler/tools/openroad/scripts/apr/sc_clock_tree_synthesis.tcl +62 -0
  49. siliconcompiler/tools/openroad/scripts/apr/sc_detailed_placement.tcl +41 -0
  50. siliconcompiler/tools/openroad/scripts/apr/sc_detailed_route.tcl +71 -0
  51. siliconcompiler/tools/openroad/scripts/apr/sc_endcap_tapcell_insertion.tcl +55 -0
  52. siliconcompiler/tools/openroad/scripts/apr/sc_fillercell_insertion.tcl +27 -0
  53. siliconcompiler/tools/openroad/scripts/apr/sc_fillmetal_insertion.tcl +36 -0
  54. siliconcompiler/tools/openroad/scripts/apr/sc_global_placement.tcl +26 -0
  55. siliconcompiler/tools/openroad/scripts/apr/sc_global_route.tcl +61 -0
  56. siliconcompiler/tools/openroad/scripts/apr/sc_init_floorplan.tcl +333 -0
  57. siliconcompiler/tools/openroad/scripts/apr/sc_macro_placement.tcl +123 -0
  58. siliconcompiler/tools/openroad/scripts/apr/sc_metrics.tcl +22 -0
  59. siliconcompiler/tools/openroad/scripts/apr/sc_pin_placement.tcl +41 -0
  60. siliconcompiler/tools/openroad/scripts/apr/sc_power_grid.tcl +60 -0
  61. siliconcompiler/tools/openroad/scripts/apr/sc_repair_design.tcl +68 -0
  62. siliconcompiler/tools/openroad/scripts/apr/sc_repair_timing.tcl +83 -0
  63. siliconcompiler/tools/openroad/scripts/apr/sc_write_data.tcl +125 -0
  64. siliconcompiler/tools/openroad/scripts/common/debugging.tcl +28 -0
  65. siliconcompiler/tools/openroad/scripts/common/procs.tcl +675 -0
  66. siliconcompiler/tools/openroad/scripts/common/read_input_files.tcl +59 -0
  67. siliconcompiler/tools/openroad/scripts/common/read_liberty.tcl +20 -0
  68. siliconcompiler/tools/openroad/scripts/common/read_timing_constraints.tcl +16 -0
  69. siliconcompiler/tools/openroad/scripts/common/reports.tcl +180 -0
  70. siliconcompiler/tools/openroad/scripts/common/screenshot.tcl +18 -0
  71. siliconcompiler/tools/openroad/scripts/common/write_images.tcl +395 -0
  72. siliconcompiler/tools/openroad/scripts/{sc_rcx_bench.tcl → rcx/sc_rcx_bench.tcl} +5 -5
  73. siliconcompiler/tools/openroad/scripts/{sc_rcx_extract.tcl → rcx/sc_rcx_extract.tcl} +0 -0
  74. siliconcompiler/tools/openroad/scripts/sc_rcx.tcl +5 -16
  75. siliconcompiler/tools/openroad/scripts/sc_rdlroute.tcl +51 -51
  76. siliconcompiler/tools/openroad/scripts/sc_show.tcl +105 -0
  77. siliconcompiler/tools/openroad/show.py +28 -23
  78. siliconcompiler/tools/openroad/{export.py → write_data.py} +31 -26
  79. siliconcompiler/tools/opensta/__init__.py +1 -1
  80. siliconcompiler/tools/yosys/syn_asic.py +7 -0
  81. siliconcompiler/tools/yosys/syn_asic.tcl +27 -6
  82. siliconcompiler/tools/yosys/syn_fpga.tcl +26 -18
  83. siliconcompiler/toolscripts/_tools.json +4 -4
  84. {siliconcompiler-0.28.9.dist-info → siliconcompiler-0.29.0.dist-info}/METADATA +14 -12
  85. {siliconcompiler-0.28.9.dist-info → siliconcompiler-0.29.0.dist-info}/RECORD +90 -63
  86. siliconcompiler/tools/openroad/cts.py +0 -45
  87. siliconcompiler/tools/openroad/floorplan.py +0 -75
  88. siliconcompiler/tools/openroad/physyn.py +0 -27
  89. siliconcompiler/tools/openroad/place.py +0 -41
  90. siliconcompiler/tools/openroad/route.py +0 -45
  91. siliconcompiler/tools/openroad/scripts/__init__.py +0 -0
  92. siliconcompiler/tools/openroad/scripts/sc_apr.tcl +0 -514
  93. siliconcompiler/tools/openroad/scripts/sc_cts.tcl +0 -68
  94. siliconcompiler/tools/openroad/scripts/sc_dfm.tcl +0 -22
  95. siliconcompiler/tools/openroad/scripts/sc_export.tcl +0 -100
  96. siliconcompiler/tools/openroad/scripts/sc_floorplan.tcl +0 -456
  97. siliconcompiler/tools/openroad/scripts/sc_metrics.tcl +0 -1
  98. siliconcompiler/tools/openroad/scripts/sc_physyn.tcl +0 -6
  99. siliconcompiler/tools/openroad/scripts/sc_place.tcl +0 -84
  100. siliconcompiler/tools/openroad/scripts/sc_procs.tcl +0 -494
  101. siliconcompiler/tools/openroad/scripts/sc_report.tcl +0 -189
  102. siliconcompiler/tools/openroad/scripts/sc_route.tcl +0 -143
  103. siliconcompiler/tools/openroad/scripts/sc_screenshot.tcl +0 -18
  104. siliconcompiler/tools/openroad/scripts/sc_write_images.tcl +0 -393
  105. /siliconcompiler/tools/openroad/scripts/{sc_write.tcl → common/write_data.tcl} +0 -0
  106. {siliconcompiler-0.28.9.dist-info → siliconcompiler-0.29.0.dist-info}/LICENSE +0 -0
  107. {siliconcompiler-0.28.9.dist-info → siliconcompiler-0.29.0.dist-info}/WHEEL +0 -0
  108. {siliconcompiler-0.28.9.dist-info → siliconcompiler-0.29.0.dist-info}/entry_points.txt +0 -0
  109. {siliconcompiler-0.28.9.dist-info → siliconcompiler-0.29.0.dist-info}/top_level.txt +0 -0
@@ -60,6 +60,8 @@ def get_flowgraph_nodes(chip, step, index):
60
60
  if value is not None:
61
61
  if key == 'inputnode':
62
62
  value = ", ".join([f'{step}{index}' for step, index in value])
63
+ if key == 'pythonpackage':
64
+ value = ", ".join(value)
63
65
  nodes[key] = str(value)
64
66
  return nodes
65
67
 
@@ -14,7 +14,7 @@ def _show_summary_table(chip, flow, flowgraph_nodes, show_all_indices):
14
14
  # Display data
15
15
  column_width = 15
16
16
 
17
- max_line_width = max(2 * column_width, int(0.95*shutil.get_terminal_size().columns))
17
+ max_line_width = max(4 * column_width, int(0.95*shutil.get_terminal_size().columns))
18
18
 
19
19
  nodes, _, metrics, metrics_unit, metrics_to_show, _ = \
20
20
  _collect_data(chip, flow, flowgraph_nodes)
@@ -20,7 +20,7 @@ from datetime import datetime
20
20
  from siliconcompiler import sc_open
21
21
  from siliconcompiler import utils
22
22
  from siliconcompiler import _metadata
23
- from siliconcompiler.remote import client
23
+ from siliconcompiler.remote import Client
24
24
  from siliconcompiler.schema import Schema
25
25
  from siliconcompiler.scheduler import slurm
26
26
  from siliconcompiler.scheduler import docker_runner
@@ -92,6 +92,7 @@ def run(chip):
92
92
  copy_old_run_dir(chip, org_jobname)
93
93
  clean_build_dir(chip)
94
94
  _reset_flow_nodes(chip, flow, nodes_to_execute(chip, flow))
95
+ __record_packages(chip)
95
96
 
96
97
  # Save current environment
97
98
  environment = copy.deepcopy(os.environ)
@@ -101,7 +102,8 @@ def run(chip):
101
102
  os.environ[envvar] = val
102
103
 
103
104
  if chip.get('option', 'remote'):
104
- client.remote_process(chip)
105
+ client = Client(chip)
106
+ client.run()
105
107
  else:
106
108
  _local_process(chip, flow)
107
109
 
@@ -427,7 +429,7 @@ def _check_version(chip, reported_version, tool, step, index):
427
429
 
428
430
 
429
431
  ###########################################################################
430
- def _runtask(chip, flow, step, index, exec_func, replay=False):
432
+ def _runtask(chip, flow, step, index, exec_func, pipe=None, replay=False):
431
433
  '''
432
434
  Private per node run method called by run().
433
435
 
@@ -477,6 +479,9 @@ def _runtask(chip, flow, step, index, exec_func, replay=False):
477
479
  os.chdir(cwd)
478
480
  chip.schema._stop_journal()
479
481
 
482
+ if pipe:
483
+ pipe.send(chip._packages)
484
+
480
485
 
481
486
  ###########################################################################
482
487
  def _haltstep(chip, flow, step, index, log=True):
@@ -1389,7 +1394,10 @@ def _reset_flow_nodes(chip, flow, nodes_to_execute):
1389
1394
  for metric in chip.getkeys('metric'):
1390
1395
  _clear_metric(chip, step, index, metric)
1391
1396
  for record in chip.getkeys('record'):
1392
- _clear_record(chip, step, index, record, preserve=['remoteid', 'status'])
1397
+ _clear_record(chip, step, index, record, preserve=[
1398
+ 'remoteid',
1399
+ 'status',
1400
+ 'pythonpackage'])
1393
1401
 
1394
1402
  # Mark all nodes as pending
1395
1403
  for step, index in _get_flowgraph_nodes(chip, flow):
@@ -1464,8 +1472,18 @@ def _prepare_nodes(chip, nodes_to_run, processes, local_processes, flow):
1464
1472
  else:
1465
1473
  local_processes.append((step, index))
1466
1474
 
1467
- processes[node] = multiprocessing.Process(target=_runtask,
1468
- args=(chip, flow, step, index, exec_func))
1475
+ process = {
1476
+ "child_pipe": None,
1477
+ "parent_pipe": None,
1478
+ "proc": None
1479
+ }
1480
+ process["parent_pipe"], process["child_pipe"] = multiprocessing.Pipe()
1481
+ process["proc"] = multiprocessing.Process(
1482
+ target=_runtask,
1483
+ args=(chip, flow, step, index, exec_func),
1484
+ kwargs={"pipe": process["child_pipe"]})
1485
+
1486
+ processes[node] = process
1469
1487
 
1470
1488
  for init_func in init_funcs:
1471
1489
  init_func(chip)
@@ -1563,7 +1581,7 @@ def _launch_nodes(chip, nodes_to_run, processes, local_processes):
1563
1581
  chip.set('record', 'status', NodeStatus.RUNNING, step=node[0], index=node[1])
1564
1582
  changed = True
1565
1583
 
1566
- processes[node].start()
1584
+ processes[node]["proc"].start()
1567
1585
  del nodes_to_run[node]
1568
1586
  running_nodes[node] = requested_threads
1569
1587
 
@@ -1586,7 +1604,7 @@ def _launch_nodes(chip, nodes_to_run, processes, local_processes):
1586
1604
  def _process_completed_nodes(chip, processes, running_nodes):
1587
1605
  changed = False
1588
1606
  for node in list(running_nodes.keys()):
1589
- if not processes[node].is_alive():
1607
+ if not processes[node]["proc"].is_alive():
1590
1608
  step, index = node
1591
1609
  manifest = os.path.join(chip.getworkdir(step=step, index=index),
1592
1610
  'outputs',
@@ -1595,8 +1613,16 @@ def _process_completed_nodes(chip, processes, running_nodes):
1595
1613
  if os.path.exists(manifest):
1596
1614
  chip.schema.read_journal(manifest)
1597
1615
 
1616
+ if processes[node]["parent_pipe"] and processes[node]["parent_pipe"].poll(1):
1617
+ try:
1618
+ packages = processes[node]["parent_pipe"].recv()
1619
+ if isinstance(packages, dict):
1620
+ chip._packages.update(packages)
1621
+ except: # noqa E722
1622
+ pass
1623
+
1598
1624
  del running_nodes[node]
1599
- if processes[node].exitcode > 0:
1625
+ if processes[node]["proc"].exitcode > 0:
1600
1626
  status = NodeStatus.ERROR
1601
1627
  else:
1602
1628
  status = chip.get('record', 'status', step=step, index=index)
@@ -1627,6 +1653,22 @@ def _check_nodes_status(chip, flow):
1627
1653
  #######################################
1628
1654
  def __record_version(chip, step, index):
1629
1655
  chip.set('record', 'scversion', _metadata.version, step=step, index=index)
1656
+ chip.set('record', 'pythonversion', platform.python_version(), step=step, index=index)
1657
+
1658
+
1659
+ #######################################
1660
+ def __record_packages(chip):
1661
+ try:
1662
+ from pip._internal.operations.freeze import freeze
1663
+ except: # noqa E722
1664
+ freeze = None
1665
+
1666
+ if freeze:
1667
+ # clear record
1668
+ chip.set('record', 'pythonpackage', [])
1669
+
1670
+ for pkg in freeze():
1671
+ chip.add('record', 'pythonpackage', pkg)
1630
1672
 
1631
1673
 
1632
1674
  #######################################
@@ -10,7 +10,7 @@ try:
10
10
  except ImportError:
11
11
  from siliconcompiler.schema.utils import trim
12
12
 
13
- SCHEMA_VERSION = '0.48.4'
13
+ SCHEMA_VERSION = '0.48.5'
14
14
 
15
15
  #############################################################################
16
16
  # PARAM DEFINITION
@@ -2482,6 +2482,9 @@ def schema_record(cfg, step='default', index='default'):
2482
2482
  'toolargs': ['tool CLI arguments',
2483
2483
  '-I include/ foo.v',
2484
2484
  'Arguments passed to tool via CLI.'],
2485
+ 'pythonversion': ['Python version',
2486
+ '3.12.3',
2487
+ """Version of python used to run this task."""],
2485
2488
  'osversion': ['O/S version',
2486
2489
  '20.04.1-Ubuntu',
2487
2490
  """Since there is not standard version system for operating
@@ -2515,16 +2518,25 @@ def schema_record(cfg, step='default', index='default'):
2515
2518
  pernode='required',
2516
2519
  schelp='Record tracking the tool exit code per step and index basis.')
2517
2520
 
2518
- # Unlike most other 'record' fields, job ID is not set per-node.
2521
+ # Non-per-node records.
2519
2522
  scparam(cfg, ['record', 'remoteid'],
2520
2523
  sctype='str',
2521
2524
  shorthelp="Record: remote job ID",
2522
- switch="-record_remoteid 'step index <str>'",
2525
+ switch="-record_remoteid '<str>'",
2523
2526
  example=[
2524
2527
  "cli: -record_remoteid '0123456789abcdeffedcba9876543210'",
2525
2528
  "api: chip.set('record', 'remoteid', '0123456789abcdeffedcba9876543210')"],
2526
2529
  schelp='Record tracking the job ID for a remote run.')
2527
2530
 
2531
+ scparam(cfg, ['record', 'pythonpackage'],
2532
+ sctype='[str]',
2533
+ shorthelp="Record: python packages",
2534
+ switch="-record_pythonpackage '<str>'",
2535
+ example=[
2536
+ "cli: -record_pythonpackage 'siliconcompiler==0.28.0'",
2537
+ "api: chip.set('record', 'pythonpackage', 'siliconcompiler==0.28.0')"],
2538
+ schelp='Record tracking for the python packages installed.')
2539
+
2528
2540
  # flowgraph status
2529
2541
  scparam(cfg, ['record', 'status'],
2530
2542
  sctype='enum',
@@ -506,6 +506,22 @@ class Schema:
506
506
  else:
507
507
  self.set(*key, values, step=step, index=index)
508
508
 
509
+ ###########################################################################
510
+ def copy_key(self, src, dst):
511
+ '''
512
+ Copy a parameters information from the source keypath to the destination
513
+ keypath.
514
+
515
+ Args:
516
+ src (list): Key to use as source.
517
+ dst (list): Key to use as destination
518
+ '''
519
+
520
+ data = self.getdict(*src)
521
+
522
+ cfg = self.__search(*dst[0:-1], insert_defaults=True)
523
+ cfg[dst[-1]] = data
524
+
509
525
  ###########################################################################
510
526
  def remove(self, *keypath):
511
527
  '''
@@ -9,6 +9,7 @@ from sphinx.util.docutils import SphinxDirective
9
9
  from sphinx.domains.std import StandardDomain
10
10
  from sphinx.addnodes import pending_xref
11
11
  import docutils
12
+ from siliconcompiler import __version__ as sc_version
12
13
 
13
14
  import importlib
14
15
  import pkgutil
@@ -324,7 +325,7 @@ class DynamicGen(SphinxDirective):
324
325
 
325
326
  if builtin:
326
327
  relpath = path[len(SC_ROOT) + 1:]
327
- gh_root = 'https://github.com/siliconcompiler/siliconcompiler/blob/main'
328
+ gh_root = f'https://github.com/siliconcompiler/siliconcompiler/blob/v{sc_version}'
328
329
  gh_link = f'{gh_root}/{relpath}'
329
330
  filename = os.path.basename(relpath)
330
331
  p = para('Setup file: ')
@@ -753,8 +754,8 @@ class ToolGen(DynamicGen):
753
754
  path = os.path.abspath(path)
754
755
  module_dir = os.path.dirname(path)
755
756
  for taskfile in os.listdir(module_dir):
756
- if taskfile == "__init__.py":
757
- # skip init
757
+ if taskfile.startswith("_"):
758
+ # skip private file
758
759
  continue
759
760
 
760
761
  task_path = os.path.join(module_dir, taskfile)
@@ -1,7 +1,7 @@
1
1
  import siliconcompiler
2
2
  from siliconcompiler.flows import asicflow, asictopflow, signoffflow, synflow
3
3
  from siliconcompiler.checklists import oh_tapeout
4
- from siliconcompiler.tools.openroad import openroad
4
+ from siliconcompiler.tools import openroad
5
5
  from siliconcompiler.tools._common import get_tool_tasks
6
6
 
7
7
  from lambdapdk import gf180
@@ -66,8 +66,8 @@ def setup(chip, syn_np=1, floorplan_np=1, physyn_np=1, place_np=1, cts_np=1, rou
66
66
 
67
67
  # PSM gets stuck in a loop, must be disabled for now on gf180
68
68
  for task in get_tool_tasks(chip, openroad):
69
- chip.set('tool', 'openroad', 'task', task, 'var', 'psm_enable', 'false')
70
- chip.set('tool', 'openroad', 'task', 'route', 'var', 'ant_check', 'false')
69
+ chip.set('tool', 'openroad', 'task', task, 'var', 'psm_enable', False)
70
+ chip.set('tool', 'openroad', 'task', 'route', 'var', 'ant_check', False)
71
71
 
72
72
 
73
73
  #########################
@@ -0,0 +1,6 @@
1
+ # SiliconCompiler Replay Environment
2
+ # From {{ source }}
3
+ # Jobname: {{ jobname }}
4
+
5
+ {% for pkg in pkgs %}{{ pkg }}
6
+ {% endfor %}
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env python3
2
+ # SiliconCompiler Replay
3
+ # From {{ source }}
4
+ # Jobname: {{ jobname }}
5
+
6
+ from siliconcompiler import Chip
7
+
8
+
9
+ if __name__ == "__main__":
10
+ chip = Chip("{{ design }}")
11
+
12
+ # Read manifest{% for cfg in cfgs %}
13
+ chip.read_manifest("{{ cfg }}"){% endfor %}
14
+
15
+ # Set tool versions{% for node, tool, version in tool_versions %}
16
+ chip.set("tool", "{{ tool }}", "version", "=={{ version }}", step="{{ node[0] }}", index="{{ node[1] }}"){% endfor %}
17
+
18
+ # Run
19
+ chip.run()
20
+
21
+ # Report summary
22
+ chip.summary()
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env bash
2
+ # SiliconCompiler Replay Setup
3
+ # From {{ source }}
4
+ # Jobname: {{ jobname }}
5
+
6
+ if [ "$(python3 -V)" != "Python {{ pythonversion }}" ]; then
7
+ echo "Python version mismatch: $(python3 -V) != {{ pythonversion }}"
8
+ fi
9
+
10
+ python3 -m venv {{ design }}_venv --clear
11
+ echo "*" > gcd_venv/.gitignore
12
+
13
+ . {{ design }}_venv/bin/activate
14
+ pip3 install -r requirements.txt
15
+
16
+ echo "To enable run environment: . {{ design }}_venv/bin/activate"
17
+ echo "To replay: ./run.py"
@@ -411,11 +411,16 @@ def get_tool_task(chip, step, index, flow=None):
411
411
 
412
412
  def get_tool_tasks(chip, tool):
413
413
  tool_dir = os.path.dirname(tool.__file__)
414
- tool_base_module = tool.__name__.split('.')[0:-1]
415
414
  tool_name = tool.__name__.split('.')[-1]
415
+ tool_base_module = tool.__name__.split('.')
416
+ if not tool.__file__.endswith('__init__.py'):
417
+ tool_base_module = tool_base_module[0:-1]
416
418
 
417
419
  task_candidates = []
418
420
  for task_mod in pkgutil.iter_modules([tool_dir]):
421
+ if task_mod.name.startswith('_'):
422
+ continue
423
+
419
424
  if task_mod.name == tool_name:
420
425
  continue
421
426
  task_candidates.append(task_mod.name)
@@ -468,3 +473,12 @@ def record_metric(chip, step, index, metric, value, source, source_unit=None):
468
473
  tool, task = get_tool_task(chip, step, index, flow=flow)
469
474
 
470
475
  chip.add('tool', tool, 'task', task, 'report', metric, source, step=step, index=index)
476
+
477
+
478
+ def has_pre_post_script(chip):
479
+ step = chip.get('arg', 'step')
480
+ index = chip.get('arg', 'index')
481
+ tool, task = get_tool_task(chip, step, index)
482
+
483
+ return chip.get('tool', tool, 'task', task, 'prescript', step=step, index=index) or \
484
+ chip.get('tool', tool, 'task', task, 'postscript', step=step, index=index)
@@ -102,11 +102,18 @@ def set_tool_task_var(chip,
102
102
  ','.join(check_keys[-1]),
103
103
  step=step, index=index)
104
104
 
105
+ def check_value(val):
106
+ if isinstance(val, (list, tuple)):
107
+ return len(val) > 0
108
+ return val is not None
109
+
105
110
  require_key, value = _common.pick_key(chip, reversed(check_keys), step=step, index=index)
106
- if not value:
111
+ if not check_value(value):
107
112
  value = default_value
108
113
 
109
- if value:
114
+ has_value = check_value(value)
115
+
116
+ if has_value:
110
117
  chip.set('tool', tool, 'task', task, 'var', param_key, value,
111
118
  step=step, index=index, clobber=False)
112
119
 
@@ -115,7 +122,7 @@ def set_tool_task_var(chip,
115
122
  ','.join(require_key),
116
123
  step=step, index=index)
117
124
 
118
- if value or 'key' in require:
125
+ if has_value or 'key' in require:
119
126
  chip.add('tool', tool, 'task', task, 'require',
120
127
  ','.join(['tool', tool, 'task', task, 'var', param_key]),
121
128
  step=step, index=index)
@@ -15,7 +15,7 @@ def make_docs(chip):
15
15
  for step, index in flowgraph._get_flowgraph_entry_nodes(chip, 'asicflow'):
16
16
  scheduler._setup_node(chip, step, index)
17
17
 
18
- chip.set('arg', 'step', 'combine')
18
+ chip.set('arg', 'step', 'import.combine')
19
19
  chip.set('arg', 'index', '0')
20
20
  setup(chip)
21
21
 
@@ -0,0 +1,103 @@
1
+ '''
2
+ OpenROAD is an automated physical design platform for
3
+ integrated circuit design with a complete set of features
4
+ needed to translate a synthesized netlist to a tapeout ready
5
+ GDSII.
6
+
7
+ Documentation: https://openroad.readthedocs.io/
8
+
9
+ Sources: https://github.com/The-OpenROAD-Project/OpenROAD
10
+
11
+ Installation: https://github.com/The-OpenROAD-Project/OpenROAD
12
+ '''
13
+ from siliconcompiler.tools._common import get_tool_task
14
+ from siliconcompiler.targets import asap7_demo
15
+
16
+
17
+ ####################################################################
18
+ # Make Docs
19
+ ####################################################################
20
+ def make_docs(chip):
21
+ chip.use(asap7_demo)
22
+
23
+
24
+ ################################
25
+ # Setup Tool (pre executable)
26
+ ################################
27
+ def setup(chip, exit=True, clobber=False):
28
+ step = chip.get('arg', 'step')
29
+ index = chip.get('arg', 'index')
30
+ tool, task = get_tool_task(chip, step, index)
31
+
32
+ chip.set('tool', tool, 'exe', 'openroad')
33
+ chip.set('tool', tool, 'vswitch', '-version')
34
+ chip.set('tool', tool, 'version', '>=v2.0-17598', clobber=clobber)
35
+ chip.set('tool', tool, 'format', 'tcl', clobber=clobber)
36
+
37
+ option = [
38
+ "-no_init",
39
+ "-metrics", "reports/metrics.json"
40
+ ]
41
+
42
+ # exit automatically in batch mode and not breakpoint
43
+ if exit and \
44
+ not chip.get('option', 'breakpoint', step=step, index=index):
45
+ option.append("-exit")
46
+
47
+ chip.set('tool', tool, 'task', task, 'option', option,
48
+ step=step, index=index, clobber=clobber)
49
+
50
+ chip.set('tool', tool, 'task', task, 'refdir',
51
+ 'tools/openroad/scripts',
52
+ step=step, index=index, package='siliconcompiler')
53
+
54
+ # basic warning and error grep check on logfile
55
+ chip.set('tool', tool, 'task', task, 'regex', 'warnings',
56
+ r'^\[WARNING|Warning',
57
+ step=step, index=index, clobber=clobber)
58
+ chip.set('tool', tool, 'task', task, 'regex', 'errors',
59
+ r'^\[ERROR',
60
+ step=step, index=index, clobber=clobber)
61
+
62
+ chip.set('tool', tool, 'task', task, 'var', 'debug_level',
63
+ 'list of "tool key level" to enable debugging of OpenROAD',
64
+ field='help')
65
+
66
+ if chip.get('option', 'nodisplay'):
67
+ # Tells QT to use the offscreen platform if nodisplay is used
68
+ chip.set('tool', tool, 'task', task, 'env',
69
+ 'QT_QPA_PLATFORM', 'offscreen',
70
+ step=step, index=index)
71
+
72
+
73
+ ################################
74
+ # Version Check
75
+ ################################
76
+ def parse_version(stdout):
77
+ # stdout will be in one of the following forms:
78
+ # - 1 08de3b46c71e329a10aa4e753dcfeba2ddf54ddd
79
+ # - 1 v2.0-880-gd1c7001ad
80
+ # - v2.0-1862-g0d785bd84
81
+
82
+ # strip off the "1" prefix if it's there
83
+ version = stdout.split()[-1]
84
+
85
+ pieces = version.split('-')
86
+ if len(pieces) > 1:
87
+ # strip off the hash in the new version style
88
+ return '-'.join(pieces[:-1])
89
+ else:
90
+ return pieces[0]
91
+
92
+
93
+ def normalize_version(version):
94
+ if '.' in version:
95
+ return version.lstrip('v')
96
+ else:
97
+ return '0'
98
+
99
+
100
+ ##################################################
101
+ if __name__ == "__main__":
102
+ chip = make_docs()
103
+ chip.write_manifest("openroad.json")