siliconcompiler 0.28.3__py3-none-any.whl → 0.28.5__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 (86) hide show
  1. siliconcompiler/_metadata.py +1 -1
  2. siliconcompiler/apps/_common.py +88 -56
  3. siliconcompiler/apps/sc.py +33 -14
  4. siliconcompiler/apps/sc_dashboard.py +17 -10
  5. siliconcompiler/apps/sc_show.py +17 -15
  6. siliconcompiler/core.py +95 -55
  7. siliconcompiler/flows/drcflow.py +13 -0
  8. siliconcompiler/flows/interposerflow.py +17 -0
  9. siliconcompiler/fpgas/vpr_example.py +8 -0
  10. siliconcompiler/libs/interposer.py +8 -0
  11. siliconcompiler/package.py +3 -2
  12. siliconcompiler/pdks/interposer.py +8 -0
  13. siliconcompiler/remote/schema.py +11 -1
  14. siliconcompiler/remote/server.py +7 -2
  15. siliconcompiler/report/dashboard/__init__.py +9 -0
  16. siliconcompiler/report/dashboard/components/__init__.py +13 -1
  17. siliconcompiler/report/dashboard/layouts/vertical_flowgraph.py +4 -3
  18. siliconcompiler/report/dashboard/layouts/vertical_flowgraph_node_tab.py +4 -1
  19. siliconcompiler/report/dashboard/layouts/vertical_flowgraph_sac_tabs.py +4 -1
  20. siliconcompiler/report/dashboard/state.py +3 -1
  21. siliconcompiler/report/summary_table.py +1 -2
  22. siliconcompiler/report/utils.py +1 -2
  23. siliconcompiler/scheduler/__init__.py +95 -0
  24. siliconcompiler/schema/schema_cfg.py +15 -3
  25. siliconcompiler/schema/schema_obj.py +51 -1
  26. siliconcompiler/sphinx_ext/dynamicgen.py +6 -0
  27. siliconcompiler/targets/interposer_demo.py +56 -0
  28. siliconcompiler/templates/tcl/manifest.tcl.j2 +2 -0
  29. siliconcompiler/tools/_common/__init__.py +44 -6
  30. siliconcompiler/tools/_common/asic.py +79 -23
  31. siliconcompiler/tools/genfasm/genfasm.py +7 -0
  32. siliconcompiler/tools/ghdl/convert.py +7 -0
  33. siliconcompiler/tools/klayout/convert_drc_db.py +60 -0
  34. siliconcompiler/tools/klayout/drc.py +156 -0
  35. siliconcompiler/tools/klayout/export.py +9 -4
  36. siliconcompiler/tools/klayout/klayout.py +0 -1
  37. siliconcompiler/tools/klayout/klayout_convert_drc_db.py +182 -0
  38. siliconcompiler/tools/klayout/klayout_export.py +3 -0
  39. siliconcompiler/tools/klayout/klayout_utils.py +8 -2
  40. siliconcompiler/tools/klayout/operations.py +2 -0
  41. siliconcompiler/tools/klayout/screenshot.py +2 -0
  42. siliconcompiler/tools/klayout/show.py +4 -4
  43. siliconcompiler/tools/magic/drc.py +21 -0
  44. siliconcompiler/tools/magic/extspice.py +21 -0
  45. siliconcompiler/tools/magic/magic.py +29 -0
  46. siliconcompiler/tools/magic/sc_drc.tcl +2 -12
  47. siliconcompiler/tools/magic/sc_extspice.tcl +3 -15
  48. siliconcompiler/tools/openroad/metrics.py +45 -0
  49. siliconcompiler/tools/openroad/openroad.py +47 -2
  50. siliconcompiler/tools/openroad/rdlroute.py +97 -0
  51. siliconcompiler/tools/openroad/scripts/sc_apr.tcl +16 -1
  52. siliconcompiler/tools/openroad/scripts/sc_floorplan.tcl +55 -9
  53. siliconcompiler/tools/openroad/scripts/sc_metrics.tcl +0 -159
  54. siliconcompiler/tools/openroad/scripts/sc_procs.tcl +3 -1
  55. siliconcompiler/tools/openroad/scripts/sc_rdlroute.tcl +184 -0
  56. siliconcompiler/tools/openroad/scripts/sc_report.tcl +170 -0
  57. siliconcompiler/tools/openroad/scripts/sc_route.tcl +8 -2
  58. siliconcompiler/tools/openroad/scripts/sc_screenshot.tcl +0 -5
  59. siliconcompiler/tools/openroad/scripts/sc_write_images.tcl +36 -6
  60. siliconcompiler/tools/opensta/scripts/sc_report_libraries.tcl +11 -1
  61. siliconcompiler/tools/surelog/__init__.py +12 -0
  62. siliconcompiler/tools/verilator/compile.py +27 -0
  63. siliconcompiler/tools/verilator/verilator.py +9 -0
  64. siliconcompiler/tools/vpr/vpr.py +18 -0
  65. siliconcompiler/tools/xyce/__init__.py +1 -1
  66. siliconcompiler/tools/yosys/{syn_asic_fpga_shared.tcl → procs.tcl} +23 -0
  67. siliconcompiler/tools/yosys/sc_screenshot.tcl +104 -0
  68. siliconcompiler/tools/yosys/sc_syn.tcl +7 -9
  69. siliconcompiler/tools/yosys/screenshot.py +153 -0
  70. siliconcompiler/tools/yosys/syn_asic.py +3 -0
  71. siliconcompiler/tools/yosys/syn_asic.tcl +1 -3
  72. siliconcompiler/tools/yosys/syn_fpga.tcl +3 -2
  73. siliconcompiler/toolscripts/_tools.json +5 -6
  74. siliconcompiler/toolscripts/rhel8/install-xyce.sh +4 -5
  75. siliconcompiler/toolscripts/rhel9/install-xyce.sh +4 -5
  76. siliconcompiler/toolscripts/ubuntu20/install-xyce.sh +5 -5
  77. siliconcompiler/toolscripts/ubuntu22/install-xyce.sh +2 -2
  78. siliconcompiler/toolscripts/ubuntu24/install-xyce.sh +2 -2
  79. siliconcompiler/utils/__init__.py +30 -1
  80. siliconcompiler/utils/showtools.py +4 -0
  81. {siliconcompiler-0.28.3.dist-info → siliconcompiler-0.28.5.dist-info}/METADATA +18 -5
  82. {siliconcompiler-0.28.3.dist-info → siliconcompiler-0.28.5.dist-info}/RECORD +86 -72
  83. {siliconcompiler-0.28.3.dist-info → siliconcompiler-0.28.5.dist-info}/WHEEL +1 -1
  84. {siliconcompiler-0.28.3.dist-info → siliconcompiler-0.28.5.dist-info}/LICENSE +0 -0
  85. {siliconcompiler-0.28.3.dist-info → siliconcompiler-0.28.5.dist-info}/entry_points.txt +0 -0
  86. {siliconcompiler-0.28.3.dist-info → siliconcompiler-0.28.5.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,8 @@
1
+ import siliconcompiler
2
+ from lambdapdk.interposer import setup
3
+
4
+
5
+ #########################
6
+ if __name__ == "__main__":
7
+ pdk = setup(siliconcompiler.Chip('<lib>'))
8
+ pdk.write_manifest(f'{pdk.top()}.json')
@@ -2,7 +2,7 @@ from siliconcompiler.schema.schema_cfg import scparam
2
2
  from siliconcompiler.schema import Schema
3
3
 
4
4
 
5
- SCHEMA_VERSION = '0.0.1'
5
+ SCHEMA_VERSION = '0.0.2'
6
6
 
7
7
 
8
8
  def schema_cfg():
@@ -93,6 +93,16 @@ def schema_cfg():
93
93
  schelp="""
94
94
  Provides explicit control over the level of debug logging printed.""")
95
95
 
96
+ scparam(cfg, ['option', 'checkinterval'],
97
+ sctype='int',
98
+ defvalue=30,
99
+ shorthelp="Interval for client",
100
+ switch="-checkinterval <int>",
101
+ example=["cli: -checkinterval 10",
102
+ "api: chip.set('option', 'checkinterval', 10)"],
103
+ schelp="""
104
+ Interval between checks to announce to clients""")
105
+
96
106
  return cfg
97
107
 
98
108
 
@@ -239,7 +239,7 @@ class Server:
239
239
 
240
240
  # Return a response to the client.
241
241
  return web.json_response({'message': f"Starting job: {job_hash}",
242
- 'interval': 30,
242
+ 'interval': self.checkinterval,
243
243
  'job_hash': job_hash})
244
244
 
245
245
  ####################
@@ -375,7 +375,7 @@ class Server:
375
375
  'sc_schema': sc_schema_version,
376
376
  'sc_server': Server.__version__,
377
377
  },
378
- 'progress_interval': 30
378
+ 'progress_interval': self.checkinterval
379
379
  }
380
380
 
381
381
  username = job_params['username']
@@ -490,6 +490,11 @@ class Server:
490
490
  # Ensure that NFS mounting path is absolute.
491
491
  return os.path.abspath(self.get('option', 'nfsmount'))
492
492
 
493
+ ###################
494
+ @property
495
+ def checkinterval(self):
496
+ return self.get('option', 'checkinterval')
497
+
493
498
  def get(self, *keypath, field='value'):
494
499
  return self.schema.get(*keypath, field=field)
495
500
 
@@ -12,6 +12,7 @@ import atexit
12
12
  import shutil
13
13
  import fasteners
14
14
  import signal
15
+ import socketserver
15
16
 
16
17
  from siliconcompiler.report.dashboard import utils
17
18
 
@@ -25,6 +26,8 @@ class Dashboard():
25
26
  pass
26
27
 
27
28
  def __init__(self, chip, port=None, graph_chips=None):
29
+ if not port:
30
+ port = Dashboard.get_next_port()
28
31
  if not port:
29
32
  port = Dashboard.__port
30
33
 
@@ -172,3 +175,9 @@ class Dashboard():
172
175
 
173
176
  if os.path.exists(self.__directory):
174
177
  shutil.rmtree(self.__directory)
178
+
179
+ @staticmethod
180
+ def get_next_port():
181
+ with socketserver.TCPServer(("localhost", 0), None) as s:
182
+ return s.server_address[1]
183
+ return None
@@ -194,7 +194,7 @@ def setup_page():
194
194
  menu_items=SC_MENU)
195
195
 
196
196
 
197
- def file_viewer(chip, path, header_col_width=0.89):
197
+ def file_viewer(chip, path, page_key=None, header_col_width=0.89):
198
198
  if not path:
199
199
  streamlit.error('Select a file')
200
200
  return
@@ -243,14 +243,25 @@ def file_viewer(chip, path, header_col_width=0.89):
243
243
 
244
244
  file_section = streamlit.container()
245
245
 
246
+ if page_key:
247
+ if state.get_key(page_key) is None:
248
+ state.set_key(page_key, 1)
249
+ index = state.get_key(page_key)
250
+ else:
251
+ index = 1
252
+
246
253
  page = sac.pagination(
247
254
  align='center',
255
+ index=index,
248
256
  jump=True,
249
257
  show_total=True,
250
258
  page_size=page_size,
251
259
  total=max_pages,
252
260
  disabled=max_pages < state.get_key(state.MAX_FILE_LINES_TO_SHOW))
253
261
 
262
+ if page_key:
263
+ state.set_key(page_key, page)
264
+
254
265
  start_idx = (page - 1) * state.get_key(state.MAX_FILE_LINES_TO_SHOW)
255
266
  end_idx = start_idx + state.get_key(state.MAX_FILE_LINES_TO_SHOW)
256
267
  file_show = file_data[start_idx:end_idx]
@@ -465,6 +476,7 @@ def node_file_tree_viewer(chip, step, index):
465
476
 
466
477
  if selected and os.path.isfile(selected):
467
478
  state.set_key(state.SELECTED_FILE, selected)
479
+ state.set_key(state.SELECTED_FILE_PAGE, None)
468
480
 
469
481
 
470
482
  def node_viewer(chip, step, index, metric_dataframe, height=None):
@@ -80,9 +80,10 @@ def layout():
80
80
  components.manifest_viewer(chip)
81
81
 
82
82
  with tabs["File Viewer"]:
83
- path = state.get_key(state.SELECTED_FILE)
84
-
85
- components.file_viewer(chip, path)
83
+ components.file_viewer(
84
+ chip,
85
+ state.get_key(state.SELECTED_FILE),
86
+ page_key=state.SELECTED_FILE_PAGE)
86
87
 
87
88
  if "Design Preview" in tabs:
88
89
  with tabs["Design Preview"]:
@@ -103,7 +103,10 @@ def layout():
103
103
  components.manifest_viewer(chip)
104
104
 
105
105
  if tab_selected == "File Viewer":
106
- components.file_viewer(chip, state.get_key(state.SELECTED_FILE))
106
+ components.file_viewer(
107
+ chip,
108
+ state.get_key(state.SELECTED_FILE),
109
+ page_key=state.SELECTED_FILE_PAGE)
107
110
 
108
111
  if tab_selected == "Design Preview":
109
112
  components.file_viewer(chip, f'{chip.getworkdir()}/{chip.design}.png')
@@ -96,7 +96,10 @@ def layout():
96
96
  components.manifest_viewer(chip)
97
97
 
98
98
  if tab_selected == "File Viewer":
99
- components.file_viewer(chip, state.get_key(state.SELECTED_FILE))
99
+ components.file_viewer(
100
+ chip,
101
+ state.get_key(state.SELECTED_FILE),
102
+ page_key=state.SELECTED_FILE_PAGE)
100
103
 
101
104
  if tab_selected == "Design Preview":
102
105
  components.file_viewer(chip, f'{chip.getworkdir()}/{chip.design}.png')
@@ -16,6 +16,7 @@ SELECTED_FLOWGRAPH_NODE = "selected_flowgraph_node"
16
16
  SELECTED_SELECTOR_NODE = "selected_selector_node"
17
17
  NODE_SOURCE = "node_source"
18
18
  SELECTED_FILE = "selected_file"
19
+ SELECTED_FILE_PAGE = "selected_file_page"
19
20
  LOADED_CHIPS = "loaded_chips"
20
21
  UI_WIDTH = "ui_width"
21
22
  MANIFEST_FILE = "manifest_file"
@@ -73,6 +74,7 @@ def init():
73
74
  _add_default(SELECTED_SELECTOR_NODE, None)
74
75
  _add_default(NODE_SOURCE, None)
75
76
  _add_default(SELECTED_FILE, None)
77
+ _add_default(SELECTED_FILE_PAGE, None)
76
78
  _add_default(LOADED_CHIPS, {})
77
79
  _add_default(MANIFEST_FILE, None)
78
80
  _add_default(MANIFEST_LOCK, None)
@@ -80,7 +82,7 @@ def init():
80
82
  _add_default(IS_RUNNING, False)
81
83
  _add_default(GRAPH_JOBS, None)
82
84
  _add_default(UI_WIDTH, None)
83
- _add_default(APP_LAYOUT, "vertical_flowgraph")
85
+ _add_default(APP_LAYOUT, "vertical_flowgraph_sac_tabs")
84
86
  _add_default(APP_RERUN, None)
85
87
  _add_default(APP_RUNNING_REFRESH, 2 * 1000)
86
88
  _add_default(APP_STOPPED_REFRESH, 30 * 1000)
@@ -12,10 +12,9 @@ def _show_summary_table(chip, flow, flowgraph_nodes, show_all_indices):
12
12
  '''
13
13
 
14
14
  # Display data
15
- max_line_width = 135
16
15
  column_width = 15
17
16
 
18
- max_line_width = max(max_line_width, int(0.9*shutil.get_terminal_size((80, 20)).columns))
17
+ max_line_width = max(2 * column_width, int(0.95*shutil.get_terminal_size().columns))
19
18
 
20
19
  nodes, _, metrics, metrics_unit, metrics_to_show, _ = \
21
20
  _collect_data(chip, flow, flowgraph_nodes)
@@ -143,8 +143,7 @@ def _get_flowgraph_path(chip, flow, nodes_to_execute, only_include_successful=Fa
143
143
  end_nodes = _get_flowgraph_exit_nodes(chip, flow, steps=flowgraph_steps)
144
144
  for node in end_nodes:
145
145
  if only_include_successful:
146
- if chip.get('record', 'status', step=node[0], index=node[1]) == \
147
- NodeStatus.SUCCESS:
146
+ if NodeStatus.is_success(chip.get('record', 'status', step=node[0], index=node[1])):
148
147
  selected_nodes.add(node)
149
148
  to_search.append(node)
150
149
  else:
@@ -688,7 +688,9 @@ def _makecmd(chip, tool, task, step, index, script_name='replay.sh', include_pat
688
688
  runtime_options = getattr(chip._get_tool_module(step, index), 'runtime_options', None)
689
689
  if runtime_options:
690
690
  try:
691
+ chip.schema._start_record_access()
691
692
  cmdlist.extend(parse_options(runtime_options(chip)))
693
+ chip.schema._stop_record_access()
692
694
  except Exception as e:
693
695
  chip.logger.error(f'Failed to get runtime options for {tool}/{task}')
694
696
  raise e
@@ -898,6 +900,7 @@ def _run_executable_or_builtin(chip, step, index, version, toolpath, workdir, ru
898
900
 
899
901
  cmd_start_time = time.time()
900
902
  proc = subprocess.Popen(cmdlist,
903
+ stdin=subprocess.DEVNULL,
901
904
  stdout=stdout_writer,
902
905
  stderr=stderr_writer,
903
906
  preexec_fn=preexec_fn)
@@ -982,7 +985,9 @@ def _post_process(chip, step, index):
982
985
  func = getattr(chip._get_task_module(step, index, flow=flow), 'post_process', None)
983
986
  if func:
984
987
  try:
988
+ chip.schema._start_record_access()
985
989
  func(chip)
990
+ chip.schema._stop_record_access()
986
991
  except Exception as e:
987
992
  chip.logger.error(f'Failed to run post-process for {tool}/{task}.')
988
993
  print_traceback(chip, e)
@@ -1075,7 +1080,9 @@ def _pre_process(chip, step, index):
1075
1080
  func = getattr(chip._get_task_module(step, index, flow=flow), 'pre_process', None)
1076
1081
  if func:
1077
1082
  try:
1083
+ chip.schema._start_record_access()
1078
1084
  func(chip)
1085
+ chip.schema._stop_record_access()
1079
1086
  except Exception as e:
1080
1087
  chip.logger.error(f"Pre-processing failed for '{tool}/{task}'.")
1081
1088
  raise e
@@ -1087,6 +1094,8 @@ def _pre_process(chip, step, index):
1087
1094
  def _set_env_vars(chip, step, index):
1088
1095
  flow = chip.get('option', 'flow')
1089
1096
  tool, task = get_tool_task(chip, step, index, flow)
1097
+
1098
+ chip.schema._start_record_access()
1090
1099
  # License file configuration.
1091
1100
  for item in chip.getkeys('tool', tool, 'licenseserver'):
1092
1101
  license_file = chip.get('tool', tool, 'licenseserver', item, step=step, index=index)
@@ -1099,6 +1108,8 @@ def _set_env_vars(chip, step, index):
1099
1108
  if val:
1100
1109
  os.environ[item] = val
1101
1110
 
1111
+ chip.schema._stop_record_access()
1112
+
1102
1113
 
1103
1114
  def _check_tool_version(chip, step, index, run_func=None):
1104
1115
  '''
@@ -1118,6 +1129,7 @@ def _check_tool_version(chip, step, index, run_func=None):
1118
1129
  cmdlist = [exe]
1119
1130
  cmdlist.extend(veropt)
1120
1131
  proc = subprocess.run(cmdlist,
1132
+ stdin=subprocess.DEVNULL,
1121
1133
  stdout=subprocess.PIPE,
1122
1134
  stderr=subprocess.STDOUT,
1123
1135
  universal_newlines=True)
@@ -1189,6 +1201,9 @@ def _hash_files(chip, step, index, setup=False):
1189
1201
 
1190
1202
 
1191
1203
  def _finalizenode(chip, step, index, replay):
1204
+ if chip.schema._do_record_access():
1205
+ assert_required_accesses(chip, step, index)
1206
+
1192
1207
  flow = chip.get('option', 'flow')
1193
1208
  tool, task = get_tool_task(chip, step, index, flow)
1194
1209
  quiet = (
@@ -1284,6 +1299,86 @@ def assert_output_files(chip, step, index):
1284
1299
  chip=chip)
1285
1300
 
1286
1301
 
1302
+ def assert_required_accesses(chip, step, index):
1303
+ flow = chip.get('option', 'flow')
1304
+ jobname = chip.get('option', 'jobname')
1305
+ tool, task = get_tool_task(chip, step, index, flow)
1306
+
1307
+ if tool == 'builtin':
1308
+ return
1309
+
1310
+ gets = chip.schema._get_record_access()
1311
+ logfile = os.path.join(
1312
+ chip.getworkdir(jobname=jobname, step=step, index=index),
1313
+ f'{step}.log')
1314
+
1315
+ with sc_open(logfile) as f:
1316
+ for line in f:
1317
+ if line.startswith(Schema._RECORD_ACCESS_IDENTIFIER):
1318
+ key = line[len(Schema._RECORD_ACCESS_IDENTIFIER):].strip().split(',')
1319
+ if chip.valid(*key, check_complete=True):
1320
+ gets.add(tuple(key))
1321
+
1322
+ def get_value(*key):
1323
+ if chip.get(*key, field='pernode') == 'never':
1324
+ return chip.get(*key)
1325
+ else:
1326
+ return chip.get(*key, step=step, index=index)
1327
+
1328
+ getkeys = set()
1329
+ # Remove keys with empty values
1330
+ for key in set(sorted(gets)):
1331
+ if get_value(*key):
1332
+ getkeys.add(key)
1333
+
1334
+ # Remove keys that dont matter
1335
+ exempt = [
1336
+ ('design',),
1337
+ ('arg', 'step'), ('arg', 'index'),
1338
+ ('option', 'jobname'), ('option', 'flow'), ('option', 'strict'), ('option', 'builddir'),
1339
+ ('option', 'quiet'),
1340
+ ('tool', tool, 'exe'),
1341
+ ('tool', tool, 'task', task, 'require'),
1342
+ ('tool', tool, 'task', task, 'threads'),
1343
+ ('flowgraph', flow, step, index, 'tool'), ('flowgraph', flow, step, index, 'task'),
1344
+ ('flowgraph', flow, step, index, 'taskmodule')]
1345
+ for key in chip.getkeys('metric'):
1346
+ exempt.append(('metric', key))
1347
+ for key in chip.getkeys('tool', tool, 'task', task, 'report'):
1348
+ exempt.append(('tool', tool, 'task', task, 'report', key))
1349
+
1350
+ # Get exempted keys from task
1351
+ func = getattr(chip._get_task_module(step, index, flow=flow), 'exempt_keys', None)
1352
+ if func:
1353
+ # No need for try / except since this must work properly
1354
+ exempt.extend(func(chip))
1355
+
1356
+ required = set(
1357
+ [tuple(key.split(',')) for key in chip.get('tool', tool, 'task', task, 'require',
1358
+ step=step, index=index)])
1359
+
1360
+ for key in set(exempt):
1361
+ if key in getkeys:
1362
+ getkeys.remove(key)
1363
+ if key in required:
1364
+ required.remove(key)
1365
+
1366
+ excess_require = required.difference(getkeys)
1367
+ if True:
1368
+ for key in sorted(excess_require):
1369
+ chip.logger.error(f"{step}{index} does not require requirement: {','.join(key)}")
1370
+ missing_require = getkeys.difference(required)
1371
+ for key in sorted(missing_require):
1372
+ chip.logger.error(f"{step}{index} has an unexpressed requirement: "
1373
+ f"{','.join(key)} = {get_value(*key)}")
1374
+
1375
+ if missing_require:
1376
+ raise SiliconCompilerError(
1377
+ f'Requirements for {step}{index} does not match access list: '
1378
+ f'{", ".join([",".join(key) for key in sorted(missing_require)])}',
1379
+ chip=chip)
1380
+
1381
+
1287
1382
  def _reset_flow_nodes(chip, flow, nodes_to_execute):
1288
1383
  # Reset flowgraph/records/metrics by probing build directory. We need
1289
1384
  # to set values to None for steps we may re-run so that merging
@@ -10,7 +10,7 @@ try:
10
10
  except ImportError:
11
11
  from siliconcompiler.schema.utils import trim
12
12
 
13
- SCHEMA_VERSION = '0.48.2'
13
+ SCHEMA_VERSION = '0.48.4'
14
14
 
15
15
  #############################################################################
16
16
  # PARAM DEFINITION
@@ -1252,7 +1252,6 @@ def schema_datasheet(cfg, name='default', mode='default'):
1252
1252
  # Package Description
1253
1253
  #########################
1254
1254
 
1255
- # high level description
1256
1255
  scparam(cfg, ['datasheet', 'package', name, 'type'],
1257
1256
  sctype='enum',
1258
1257
  enum=['bga', 'lga', 'csp', 'qfn', 'qfp', 'sop', 'die', 'wafer'],
@@ -1263,6 +1262,16 @@ def schema_datasheet(cfg, name='default', mode='default'):
1263
1262
  "api: chip.set('datasheet', 'package', 'abcd', 'type', 'bga')"],
1264
1263
  schelp="""Package type specified on a named package basis.""")
1265
1264
 
1265
+ scparam(cfg, ['datasheet', 'package', name, 'footprint'],
1266
+ sctype='str',
1267
+ shorthelp="Datasheet: package footprint",
1268
+ switch="-datasheet_package_footprint 'name <str>'",
1269
+ example=[
1270
+ "cli: -datasheet_package_footprint 'abcd soic8'",
1271
+ "api: chip.set('datasheet', 'package', 'abcd', 'footprint', 'soic8')"],
1272
+ schelp="""Package footprint name. The name of the footprint can be a standard
1273
+ footprint name or a reference designator from a footprint library.""")
1274
+
1266
1275
  scparam(cfg, ['datasheet', 'package', name, 'drawing'],
1267
1276
  sctype='[file]',
1268
1277
  shorthelp="Datasheet: package drawing",
@@ -2158,7 +2167,10 @@ def schema_metric(cfg, step='default', index='default'):
2158
2167
  device families.""")
2159
2168
 
2160
2169
  metrics = {'cellarea': 'cell area (ignoring fillers)',
2161
- 'totalarea': 'physical die area'}
2170
+ 'totalarea': 'physical die area',
2171
+ 'macroarea': 'macro cell area',
2172
+ 'padcellarea': 'io pad cell area',
2173
+ 'stdcellarea': 'standard cell area'}
2162
2174
 
2163
2175
  for item, val in metrics.items():
2164
2176
  scparam(cfg, ['metric', item],
@@ -61,6 +61,8 @@ class Schema:
61
61
  logger (logging.Logger): instance of the parent logger if available
62
62
  """
63
63
 
64
+ _RECORD_ACCESS_IDENTIFIER = "SC_CFG_ACCESS_KEY"
65
+
64
66
  # Special key in node dict that represents a value corresponds to a
65
67
  # global default for all steps/indices.
66
68
  GLOBAL_KEY = 'global'
@@ -70,6 +72,9 @@ class Schema:
70
72
  if cfg is not None and manifest is not None:
71
73
  raise ValueError('You may not specify both cfg and manifest')
72
74
 
75
+ # Use during testing to record calls to Schema.get
76
+ self._init_record_access()
77
+
73
78
  self._init_logger(logger)
74
79
 
75
80
  self._stop_journal()
@@ -256,6 +261,10 @@ class Schema:
256
261
 
257
262
  See :meth:`~siliconcompiler.core.Chip.get` for detailed documentation.
258
263
  """
264
+
265
+ if self.__record_access["recording"]:
266
+ self.__record_access["record"].add(tuple(keypath))
267
+
259
268
  # Prevent accidental modifications of the schema content by not passing a reference
260
269
  return copy.copy(self.__get(*keypath, field=field, job=job, step=step, index=index))
261
270
 
@@ -1087,7 +1096,9 @@ class Schema:
1087
1096
 
1088
1097
  if template:
1089
1098
  fout.write(template.render(manifest_dict='\n'.join(tcl_set_cmds),
1090
- scroot=os.path.abspath(PACKAGE_ROOT)))
1099
+ scroot=os.path.abspath(PACKAGE_ROOT),
1100
+ record_access=self._do_record_access(),
1101
+ record_access_id=Schema._RECORD_ACCESS_IDENTIFIER))
1091
1102
  else:
1092
1103
  for cmd in tcl_set_cmds:
1093
1104
  fout.write(cmd + '\n')
@@ -1305,6 +1316,45 @@ class Schema:
1305
1316
  except Exception as e:
1306
1317
  self.logger.error(f'Exception: {e}')
1307
1318
 
1319
+ #######################################
1320
+ def _do_record_access(self):
1321
+ '''
1322
+ Determine if Schema should record calls to .get
1323
+ '''
1324
+ return False
1325
+
1326
+ #######################################
1327
+ def _init_record_access(self):
1328
+ '''
1329
+ Initialize record access data record
1330
+ '''
1331
+ self.__record_access = {
1332
+ "do": self._do_record_access(),
1333
+ "recording": False,
1334
+ "record": set()
1335
+ }
1336
+
1337
+ #######################################
1338
+ def _start_record_access(self):
1339
+ '''
1340
+ Start recording calls to .get
1341
+ '''
1342
+ self.__record_access["recording"] = True
1343
+
1344
+ #######################################
1345
+ def _stop_record_access(self):
1346
+ '''
1347
+ Stop recording calls to .get
1348
+ '''
1349
+ self.__record_access["recording"] = False
1350
+
1351
+ #######################################
1352
+ def _get_record_access(self):
1353
+ '''
1354
+ Return calls to record_access
1355
+ '''
1356
+ return self.__record_access["record"].copy()
1357
+
1308
1358
  #######################################
1309
1359
  def get_default(self, *keypath):
1310
1360
  '''Returns default value of a parameter.
@@ -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)
@@ -0,0 +1,56 @@
1
+ from siliconcompiler import Chip
2
+ from siliconcompiler.flows import interposerflow, drcflow
3
+
4
+ from lambdapdk import interposer
5
+ from lambdapdk.interposer.libs import bumps
6
+
7
+
8
+ ####################################################
9
+ # Target Setup
10
+ ####################################################
11
+ def setup(chip):
12
+ '''
13
+ Interposer Demo Target
14
+ '''
15
+
16
+ # 1. Load PDK, flow, libs
17
+ chip.use(interposer)
18
+ chip.use(bumps)
19
+ chip.use(interposerflow)
20
+ chip.use(drcflow)
21
+
22
+ # 2. Set default targets
23
+ chip.set('option', 'flow', 'interposerflow', clobber=False)
24
+ chip.set('option', 'pdk', 'interposer', clobber=False)
25
+ chip.set('option', 'stackup', '3ML_0400', clobber=False)
26
+ chip.set('option', 'var', 'openroad_libtype', 'none', clobber=False)
27
+ chip.set('option', 'var', 'klayout_libtype', 'none', clobber=False)
28
+
29
+ # 3. Set project specific design choices
30
+ chip.set('asic', 'macrolib', 'interposer_bumps', clobber=False)
31
+
32
+ # 4. get project specific design choices
33
+ chip.set('asic', 'delaymodel', 'nldm', clobber=False)
34
+
35
+ # 5. Timing corners
36
+ chip.set('constraint', 'timing', 'slow', 'libcorner', 'slow', clobber=False)
37
+ chip.set('constraint', 'timing', 'slow', 'pexcorner', 'maximum', clobber=False)
38
+ chip.set('constraint', 'timing', 'slow', 'mode', 'func', clobber=False)
39
+ chip.set('constraint', 'timing', 'slow', 'check', ['setup', 'hold'], clobber=False)
40
+
41
+ chip.set('constraint', 'timing', 'fast', 'libcorner', 'fast', clobber=False)
42
+ chip.set('constraint', 'timing', 'fast', 'pexcorner', 'minimum', clobber=False)
43
+ chip.set('constraint', 'timing', 'fast', 'mode', 'func', clobber=False)
44
+ chip.set('constraint', 'timing', 'fast', 'check', ['setup', 'hold'], clobber=False)
45
+
46
+ chip.set('constraint', 'timing', 'typical', 'libcorner', 'typ', clobber=False)
47
+ chip.set('constraint', 'timing', 'typical', 'pexcorner', 'typical', clobber=False)
48
+ chip.set('constraint', 'timing', 'typical', 'mode', 'func', clobber=False)
49
+ chip.set('constraint', 'timing', 'typical', 'check', ['setup', 'hold'], clobber=False)
50
+
51
+
52
+ #########################
53
+ if __name__ == "__main__":
54
+ target = Chip('<target>')
55
+ setup(target)
56
+ target.write_manifest('interposer_demo.json')
@@ -16,6 +16,8 @@ proc sc_cfg_get { args } {
16
16
  # Refer to global sc_cfg dictionary
17
17
  global sc_cfg
18
18
 
19
+ {% if record_access %}puts "{{ record_access_id }} [join $args ,]"{% endif %}
20
+
19
21
  if { ![sc_cfg_exists {*}$args] } {
20
22
  throw {FLOW KEYERROR} "key \"$args\" is not in the siliconcompiler configuration"
21
23
  }