siliconcompiler 0.28.7__py3-none-any.whl → 0.28.9__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 (36) hide show
  1. siliconcompiler/_metadata.py +1 -1
  2. siliconcompiler/report/dashboard/components/graph.py +11 -6
  3. siliconcompiler/report/dashboard/layouts/vertical_flowgraph.py +1 -1
  4. siliconcompiler/report/dashboard/layouts/vertical_flowgraph_node_tab.py +1 -1
  5. siliconcompiler/report/dashboard/layouts/vertical_flowgraph_sac_tabs.py +1 -1
  6. siliconcompiler/report/report.py +20 -1
  7. siliconcompiler/scheduler/send_messages.py +37 -33
  8. siliconcompiler/scheduler/validation/email_credentials.json +7 -0
  9. siliconcompiler/targets/fpgaflow_demo.py +6 -7
  10. siliconcompiler/tools/_common/__init__.py +2 -2
  11. siliconcompiler/tools/_common/asic.py +47 -0
  12. siliconcompiler/tools/klayout/klayout_show.py +53 -13
  13. siliconcompiler/tools/openroad/openroad.py +121 -4
  14. siliconcompiler/tools/openroad/scripts/sc_procs.tcl +9 -0
  15. siliconcompiler/tools/openroad/scripts/sc_report.tcl +19 -0
  16. siliconcompiler/tools/vivado/bitstream.py +8 -2
  17. siliconcompiler/tools/vivado/place.py +6 -2
  18. siliconcompiler/tools/vivado/route.py +6 -2
  19. siliconcompiler/tools/vivado/scripts/sc_bitstream.tcl +1 -1
  20. siliconcompiler/tools/vivado/scripts/sc_place.tcl +1 -1
  21. siliconcompiler/tools/vivado/scripts/sc_route.tcl +1 -1
  22. siliconcompiler/tools/vivado/scripts/sc_run.tcl +4 -2
  23. siliconcompiler/tools/vivado/syn_fpga.py +5 -1
  24. siliconcompiler/tools/vivado/vivado.py +26 -10
  25. siliconcompiler/tools/vpr/vpr.py +11 -0
  26. siliconcompiler/tools/yosys/syn_asic.tcl +3 -0
  27. siliconcompiler/toolscripts/_tools.json +2 -2
  28. siliconcompiler/utils/__init__.py +12 -5
  29. siliconcompiler/utils/showtools.py +2 -0
  30. {siliconcompiler-0.28.7.dist-info → siliconcompiler-0.28.9.dist-info}/METADATA +48 -47
  31. {siliconcompiler-0.28.7.dist-info → siliconcompiler-0.28.9.dist-info}/RECORD +35 -36
  32. {siliconcompiler-0.28.7.dist-info → siliconcompiler-0.28.9.dist-info}/WHEEL +1 -1
  33. siliconcompiler/toolscripts/rhel8/install-openroad.sh +0 -31
  34. {siliconcompiler-0.28.7.dist-info → siliconcompiler-0.28.9.dist-info}/LICENSE +0 -0
  35. {siliconcompiler-0.28.7.dist-info → siliconcompiler-0.28.9.dist-info}/entry_points.txt +0 -0
  36. {siliconcompiler-0.28.7.dist-info → siliconcompiler-0.28.9.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,5 @@
1
1
  # Version number following semver standard.
2
- version = '0.28.7'
2
+ version = '0.28.9'
3
3
 
4
4
  # Default server address for remote runs, if unspecified.
5
5
  default_server = 'https://server.siliconcompiler.com'
@@ -133,7 +133,7 @@ def graph(metrics, nodes, node_to_step_index_map, graph_number):
133
133
 
134
134
  data, metric_unit = report.get_chart_data(_get_report_chips(), metric, nodes_as_step_and_index)
135
135
  if metric_unit:
136
- y_axis_label = f'{metric}({metric_unit})'
136
+ y_axis_label = f'{metric} ({metric_unit})'
137
137
 
138
138
  # Prepare plot data
139
139
  filtered_data = {
@@ -142,7 +142,12 @@ def graph(metrics, nodes, node_to_step_index_map, graph_number):
142
142
  color_label: []
143
143
  }
144
144
 
145
- if not nodes.empty:
145
+ labels = {
146
+ "runs": state.get_key(state.GRAPH_JOBS),
147
+ "nodes": [f'{step}{index}' for step, index in data]
148
+ }
149
+
150
+ if nodes:
146
151
  # filtering through data
147
152
  for job_name in state.get_key(state.GRAPH_JOBS):
148
153
  for step, index in data:
@@ -154,7 +159,7 @@ def graph(metrics, nodes, node_to_step_index_map, graph_number):
154
159
  filtered_data[y_axis_label].append(data[(step, index)][job_name])
155
160
 
156
161
  # Setup chart
157
- x_axis = altair.X(x_axis_label, axis=altair.Axis(labelAngle=-75))
162
+ x_axis = altair.X(x_axis_label, axis=altair.Axis(labelAngle=-75), sort=labels[x_axis_label])
158
163
 
159
164
  y_axis = y_axis_label
160
165
  if log_scale and chart_type != 'bar':
@@ -183,9 +188,9 @@ def graph(metrics, nodes, node_to_step_index_map, graph_number):
183
188
  streamlit.altair_chart(chart, use_container_width=True, theme='streamlit')
184
189
 
185
190
 
186
- def viewer(metric_dataframe, node_to_step_index_map, metric_to_metric_unit_map):
187
- metrics = metric_dataframe.index.map(lambda x: metric_to_metric_unit_map[x])
188
- nodes = metric_dataframe.columns
191
+ def viewer(node_to_step_index_map):
192
+ nodes, metrics = report.get_chart_selection_options(_get_report_chips())
193
+ metrics = sorted(metrics)
189
194
 
190
195
  job_selector_col, graph_adder_col = streamlit.columns(2, gap='large')
191
196
  with job_selector_col:
@@ -91,6 +91,6 @@ def layout():
91
91
 
92
92
  if "Graphs" in tabs:
93
93
  with tabs["Graphs"]:
94
- graph.viewer(metric_dataframe, node_to_step_index_map, metric_to_metric_unit_map)
94
+ graph.viewer(node_to_step_index_map)
95
95
 
96
96
  _common.check_rerun()
@@ -112,6 +112,6 @@ def layout():
112
112
  components.file_viewer(chip, f'{chip.getworkdir()}/{chip.design}.png')
113
113
 
114
114
  if tab_selected == "Graphs":
115
- graph.viewer(metric_dataframe, node_to_step_index_map, metric_to_metric_unit_map)
115
+ graph.viewer(node_to_step_index_map)
116
116
 
117
117
  _common.check_rerun()
@@ -105,6 +105,6 @@ def layout():
105
105
  components.file_viewer(chip, f'{chip.getworkdir()}/{chip.design}.png')
106
106
 
107
107
  if tab_selected == "Graphs":
108
- graph.viewer(metric_dataframe, node_to_step_index_map, metric_to_metric_unit_map)
108
+ graph.viewer(node_to_step_index_map)
109
109
 
110
110
  _common.check_rerun()
@@ -335,9 +335,28 @@ def get_files(chip, step, index):
335
335
  return logs_and_reports
336
336
 
337
337
 
338
+ def get_chart_selection_options(chips):
339
+ '''
340
+ Returns all the nodes and metrics available in the provided chips
341
+
342
+ Args:
343
+ chips (list) : A list of dictionaries with the form
344
+ {'chip_object': chip, 'chip_name': name}.
345
+ '''
346
+ nodes = set()
347
+ metrics = set()
348
+ for chip_and_chip_name in chips:
349
+ chip = chip_and_chip_name['chip_object']
350
+ nodes_list, _, _, _, chip_metrics, _ = \
351
+ utils._collect_data(chip, format_as_string=False)
352
+ nodes.update(set([f'{step}{index}' for step, index in nodes_list]))
353
+ metrics.update(set(chip_metrics))
354
+ return nodes, metrics
355
+
356
+
338
357
  def get_chart_data(chips, metric, nodes):
339
358
  '''
340
- Returns returns a a tuple where the first element is a 2d dictionary of
359
+ Returns returns a tuple where the first element is a 2d dictionary of
341
360
  data points, following the forms {step+index: {chip_name: value}} where
342
361
  each dictionary can have many keys. The second element is a string that represents the unit.
343
362
 
@@ -81,40 +81,44 @@ def send(chip, msg_type, step, index):
81
81
  msg['To'] = ", ".join(to)
82
82
  msg['X-Entity-Ref-ID'] = uuid.uuid4().hex # keep emails from getting grouped
83
83
 
84
- if msg_type == "summary":
85
- layout_img = report_utils._find_summary_image(chip)
86
- if layout_img and os.path.isfile(layout_img):
87
- with open(layout_img, 'rb') as img_file:
88
- img_attach = MIMEApplication(img_file.read())
89
- img_attach.add_header('Content-Disposition',
90
- 'attachment',
91
- filename=os.path.basename(layout_img))
92
- msg.attach(img_attach)
93
-
94
- nodes_to_execute = get_executed_nodes(chip, flow)
95
- nodes, errors, metrics, metrics_unit, metrics_to_show, _ = \
96
- report_utils._collect_data(chip, flow=flow, flowgraph_nodes=nodes_to_execute)
97
-
98
- text_msg = get_file_template('email/summary.j2').render(
99
- design=chip.design,
100
- nodes=nodes,
101
- errors=errors,
102
- metrics=metrics,
103
- metrics_unit=metrics_unit,
104
- metric_keys=metrics_to_show)
105
- else:
106
- # Attach logs
107
- for log in (f'sc_{step}{index}.log', f'{step}.log'):
108
- log_file = f'{chip.getworkdir(step=step, index=index)}/{log}'
109
- if os.path.exists(log_file):
110
- with sc_open(log_file) as f:
111
- log_attach = MIMEApplication(f.read())
112
- log_name, _ = os.path.splitext(log)
113
- # Make attachment a txt file to avoid issues with tools not loading .log
114
- log_attach.add_header('Content-Disposition',
84
+ if cred["max_file_size"] > 0:
85
+ if msg_type == "summary":
86
+ layout_img = report_utils._find_summary_image(chip)
87
+ if layout_img and os.path.isfile(layout_img):
88
+ with open(layout_img, 'rb') as img_file:
89
+ img_attach = MIMEApplication(img_file.read())
90
+ img_attach.add_header('Content-Disposition',
115
91
  'attachment',
116
- filename=f'{log_name}.txt')
117
- msg.attach(log_attach)
92
+ filename=os.path.basename(layout_img))
93
+ msg.attach(img_attach)
94
+
95
+ nodes_to_execute = get_executed_nodes(chip, flow)
96
+ nodes, errors, metrics, metrics_unit, metrics_to_show, _ = \
97
+ report_utils._collect_data(chip, flow=flow, flowgraph_nodes=nodes_to_execute)
98
+
99
+ text_msg = get_file_template('email/summary.j2').render(
100
+ design=chip.design,
101
+ nodes=nodes,
102
+ errors=errors,
103
+ metrics=metrics,
104
+ metrics_unit=metrics_unit,
105
+ metric_keys=metrics_to_show)
106
+ else:
107
+ # Attach logs
108
+ for log in (f'sc_{step}{index}.log', f'{step}.log'):
109
+ log_file = f'{chip.getworkdir(step=step, index=index)}/{log}'
110
+ if os.path.exists(log_file):
111
+ with sc_open(log_file) as f:
112
+ file_content = f.read().splitlines()
113
+ # Limit to max_file_size
114
+ file_content = file_content[-cred["max_file_size"]:]
115
+ log_attach = MIMEApplication("\n".join(file_content))
116
+ log_name, _ = os.path.splitext(log)
117
+ # Make attachment a txt file to avoid issues with tools not loading .log
118
+ log_attach.add_header('Content-Disposition',
119
+ 'attachment',
120
+ filename=f'{log_name}.txt')
121
+ msg.attach(log_attach)
118
122
 
119
123
  records = {}
120
124
  for record in chip.getkeys('record'):
@@ -47,6 +47,13 @@
47
47
  "examples": [true],
48
48
  "type": "boolean",
49
49
  "default": true
50
+ },
51
+ "max_file_size": {
52
+ "title": "Max line in log file",
53
+ "description": "Maximum number of file lines to include in log",
54
+ "examples": [1000],
55
+ "type": "integer",
56
+ "default": 1000
50
57
  }
51
58
  },
52
59
 
@@ -16,25 +16,24 @@ def make_docs(chip):
16
16
  ####################################################
17
17
  # Target Setup
18
18
  ####################################################
19
- def setup(chip):
19
+ def setup(chip, partname=None):
20
20
  '''
21
21
  Demonstration target for running the open-source fpgaflow.
22
22
  '''
23
23
 
24
24
  # 1. Configure fpga part
25
- part_name = chip.get('fpga', 'partname')
26
- if not part_name:
25
+ if not partname:
26
+ partname = chip.get('fpga', 'partname')
27
+
28
+ if not partname:
27
29
  raise SiliconCompilerError('FPGA partname has not been set.', chip=chip)
28
30
 
29
31
  # 2. Load all available FPGAs
30
32
  chip.use(lattice_ice40)
31
33
  chip.use(vpr_example)
32
34
 
33
- if part_name not in chip.getkeys('fpga'):
34
- raise SiliconCompilerError(f'{part_name} has not been loaded', chip=chip)
35
-
36
35
  # 3. Load flow
37
- chip.use(fpgaflow, partname=part_name)
36
+ chip.use(fpgaflow, partname=partname)
38
37
 
39
38
  # 4. Select default flow
40
39
  chip.set('option', 'flow', 'fpgaflow', clobber=False)
@@ -115,17 +115,17 @@ def get_input_files(chip, *key, add_library_files=True):
115
115
  add_library_files (bool): When True, files from library keys
116
116
  will be included
117
117
  '''
118
- step = chip.get('arg', 'step')
119
- index = chip.get('arg', 'index')
120
118
 
121
119
  files = []
122
120
  for key in __get_keys(chip, *key, include_library_files=False):
121
+ step, index = __get_step_index(chip, *key)
123
122
  files.extend(chip.find_files(*key, step=step, index=index))
124
123
 
125
124
  if add_library_files:
126
125
  for item in get_libraries(chip, include_asic=False):
127
126
  lib_key = ('library', item, *key)
128
127
  if __is_key_valid(chip, *lib_key):
128
+ step, index = __get_step_index(chip, *lib_key)
129
129
  files.extend(chip.find_files(*lib_key, step=step, index=index))
130
130
 
131
131
  return __remove_duplicates(chip, files, list(key))
@@ -1,4 +1,5 @@
1
1
  from .. import _common
2
+ import json
2
3
 
3
4
 
4
5
  def get_mainlib(chip):
@@ -169,3 +170,49 @@ def get_tool_task_var(chip,
169
170
  _, value = _common.pick_key(chip, reversed(check_keys), step=step, index=index)
170
171
 
171
172
  return value
173
+
174
+
175
+ class CellArea:
176
+ def __init__(self):
177
+ self.__areas = {}
178
+
179
+ def addCell(self, name=None, module=None,
180
+ cellarea=None, cellcount=None,
181
+ macroarea=None, macrocount=None,
182
+ stdcellarea=None, stdcellcount=None):
183
+ if not name and not module:
184
+ return
185
+
186
+ if all([metric is None for metric in (
187
+ cellarea, cellcount,
188
+ macroarea, macrocount,
189
+ stdcellarea, stdcellcount)]):
190
+ return
191
+
192
+ if not name:
193
+ name = module
194
+
195
+ # ensure name is unique
196
+ check_name = name
197
+ idx = 0
198
+ while check_name in self.__areas:
199
+ check_name = f'{name}{idx}'
200
+ idx += 1
201
+ name = check_name
202
+
203
+ self.__areas[name] = {
204
+ "module": module,
205
+ "cellarea": cellarea,
206
+ "cellcount": cellcount,
207
+ "macroarea": macroarea,
208
+ "macrocount": macrocount,
209
+ "stdcellarea": stdcellarea,
210
+ "stdcellcount": stdcellcount
211
+ }
212
+
213
+ def size(self):
214
+ return len(self.__areas)
215
+
216
+ def writeReport(self, path):
217
+ with open(path, 'w') as f:
218
+ json.dump(self.__areas, f, indent=4)
@@ -3,7 +3,7 @@ import os
3
3
  import sys
4
4
 
5
5
 
6
- def show(schema, tech, input_path, output_path, screenshot=False):
6
+ def show(schema, tech, input_path, output_path, screenshot=False, report=None):
7
7
  # Extract info from manifest
8
8
  flow = schema.get('option', 'flow')
9
9
  step = schema.get('arg', 'step')
@@ -80,6 +80,14 @@ def show(schema, tech, input_path, output_path, screenshot=False):
80
80
  __screenshot(schema, layout_view, output_path)
81
81
  else:
82
82
  __screenshot_montage(schema, layout_view, xbins, ybins)
83
+ else:
84
+ if report:
85
+ rdb_id = layout_view.create_rdb(os.path.basename(report))
86
+ rdb = layout_view.rdb(rdb_id)
87
+ print(f"[INFO] reading DRC report: {report}")
88
+ rdb.load(report)
89
+
90
+ layout_view.show_rdb(rdb_id, cell_view.index())
83
91
 
84
92
 
85
93
  def __screenshot(schema, layout_view, output_path):
@@ -215,24 +223,56 @@ def main():
215
223
  if not design:
216
224
  design = schema.get('design')
217
225
 
218
- if 'show_filepath' in schema.getkeys('tool', 'klayout', 'task', task, 'var') and \
219
- schema.get('tool', 'klayout', 'task', task, 'var', 'show_filepath',
220
- step=step, index=index):
221
- sc_filename = schema.get('tool', 'klayout', 'task', task, 'var', 'show_filepath',
222
- step=step, index=index)[0]
223
- else:
224
- sc_fileext = schema.get('tool', 'klayout', 'task', task, 'var', 'show_filetype',
225
- step=step, index=index)[0]
226
- for ext in (f'{sc_fileext}.gz', sc_fileext):
227
- sc_filename = f"inputs/{design}.{ext}"
228
- if os.path.exists(sc_filename):
226
+ sc_fileext = schema.get('tool', 'klayout', 'task', task, 'var', 'show_filetype',
227
+ step=step, index=index)[0]
228
+ sc_report = None
229
+ if sc_fileext in ('lyrdb', 'ascii'):
230
+ sc_report = schema.get('tool', 'klayout', 'task', task, 'var', 'show_filepath',
231
+ step=step, index=index)[0]
232
+
233
+ sc_filename = None
234
+ for fileext in ('gds', 'oas'):
235
+ for ext in (f'{fileext}.gz', fileext):
236
+ sc_filename = f"inputs/{design}.{ext}"
237
+ if os.path.exists(sc_filename):
238
+ break
239
+ sc_filename = None
240
+ if sc_filename:
229
241
  break
230
242
 
243
+ if not sc_filename:
244
+ show_step = schema.get('arg', 'step')
245
+ if schema.valid('tool', 'klayout', 'task', task, 'var', 'show_step'):
246
+ show_index = schema.get('tool', 'klayout', 'task', task, 'var', 'show_step',
247
+ step=step, index=index)[0]
248
+ show_index = schema.get('arg', 'index')
249
+ if schema.valid('tool', 'klayout', 'task', task, 'var', 'show_index'):
250
+ show_index = schema.get('tool', 'klayout', 'task', task, 'var', 'show_index',
251
+ step=step, index=index)[0]
252
+ for fileext in ('gds', 'oas'):
253
+ if schema.valid('input', 'layout', fileext) and \
254
+ schema.get('input', 'layout', fileext, step=show_step, index=show_index):
255
+ sc_filename = schema.get('input', 'layout', fileext,
256
+ step=show_step, index=show_index)[0]
257
+ if sc_filename:
258
+ break
259
+ else:
260
+ if 'show_filepath' in schema.getkeys('tool', 'klayout', 'task', task, 'var') and \
261
+ schema.get('tool', 'klayout', 'task', task, 'var', 'show_filepath',
262
+ step=step, index=index):
263
+ sc_filename = schema.get('tool', 'klayout', 'task', task, 'var', 'show_filepath',
264
+ step=step, index=index)[0]
265
+ else:
266
+ for ext in (f'{sc_fileext}.gz', sc_fileext):
267
+ sc_filename = f"inputs/{design}.{ext}"
268
+ if os.path.exists(sc_filename):
269
+ break
270
+
231
271
  sc_exit = schema.get('tool', 'klayout', 'task', task, 'var', 'show_exit',
232
272
  step=step, index=index) == ["true"]
233
273
 
234
274
  show(schema, technology(design, schema), sc_filename, f'outputs/{design}.png',
235
- screenshot=(task == 'screenshot'))
275
+ screenshot=(task == 'screenshot'), report=sc_report)
236
276
 
237
277
  if sc_exit:
238
278
  pya.Application.instance().exit(0)
@@ -17,7 +17,8 @@ from siliconcompiler import sc_open
17
17
  from siliconcompiler import utils
18
18
  from siliconcompiler.tools._common import input_provides, add_common_file, \
19
19
  get_tool_task, record_metric
20
- from siliconcompiler.tools._common.asic import get_mainlib, set_tool_task_var, get_libraries
20
+ from siliconcompiler.tools._common.asic import get_mainlib, set_tool_task_var, get_libraries, \
21
+ CellArea
21
22
  from siliconcompiler.targets import asap7_demo
22
23
 
23
24
 
@@ -268,8 +269,12 @@ def post_process(chip):
268
269
  "timing/hold.rpt",
269
270
  "timing/hold.topN.rpt"],
270
271
  "holdpaths": ["timing/hold.topN.rpt"],
271
- "unconstrained": ["timing/unconstrained.topN.rpt"],
272
- "peakpower": [f"power/{corner}.rpt" for corner in chip.getkeys('constraint', 'timing')],
272
+ "unconstrained": ["timing/unconstrained.rpt", "timing/unconstrained.topN.rpt"],
273
+ "peakpower": [
274
+ *[f"power/{corner}.rpt" for corner in chip.getkeys('constraint', 'timing')],
275
+ *[f"images/heatmap/power_density/{corner}.png"
276
+ for corner in chip.getkeys('constraint', 'timing')]
277
+ ],
273
278
  "drvs": ["timing/drv_violators.rpt",
274
279
  "floating_nets.rpt",
275
280
  f"{chip.design}_antenna.rpt",
@@ -277,7 +282,9 @@ def post_process(chip):
277
282
  "drcs": [f"{chip.design}_drc.rpt",
278
283
  f"markers/{chip.design}.drc.rpt",
279
284
  f"markers/{chip.design}.drc.json",
280
- f"images/markers/{chip.design}.drc.png"]
285
+ f"images/markers/{chip.design}.drc.png"],
286
+ "utilization": ["images/heatmap/placement_density.png"],
287
+ "wirelength": [f"images/{chip.design}.routing.png"]
281
288
  }
282
289
  metric_reports["leakagepower"] = metric_reports["peakpower"]
283
290
 
@@ -300,6 +307,8 @@ def post_process(chip):
300
307
  chip.logger.error(f'Unable to parse metrics from OpenROAD: {e}')
301
308
  metrics = {}
302
309
 
310
+ _generate_cell_area_report(chip.top(), metrics)
311
+
303
312
  or_units = {}
304
313
  for unit, or_unit in [('time', 'run__flow__platform__time_units'),
305
314
  ('capacitance', 'run__flow__platform__capacitance_units'),
@@ -424,6 +433,114 @@ def post_process(chip):
424
433
  record_metric(chip, step, index, 'drcs', drcs, get_metric_sources('drcs'))
425
434
 
426
435
 
436
+ def _generate_cell_area_report(design, ord_metrics):
437
+ cellarea_report = CellArea()
438
+
439
+ prefix = "sc__cellarea__design__instance"
440
+
441
+ filtered_data = {}
442
+ for key, value in ord_metrics.items():
443
+ if key.startswith(prefix):
444
+ filtered_data[key[len(prefix)+2:]] = value
445
+
446
+ modules = set()
447
+ modules.add("")
448
+ for key in filtered_data.keys():
449
+ if "__in_module:" in key:
450
+ module = key[key.find("__in_module:"):]
451
+ modules.add(module)
452
+
453
+ def process_cell(group):
454
+ data = {}
455
+ for key, value in filtered_data.items():
456
+ if (group != "" and key.endswith(group)):
457
+ key = key[:key.find("__in_module:")]
458
+ data[key] = value
459
+ elif (group == "" and "__in_module" not in key):
460
+ data[key] = value
461
+
462
+ cell_type = None
463
+ cell_name = None
464
+
465
+ if not group:
466
+ cell_type = design
467
+ cell_name = design
468
+ else:
469
+ cell_type = group[len("__in_module:"):]
470
+
471
+ cellarea = None
472
+ cellcount = None
473
+
474
+ macroarea = None
475
+ macrocount = None
476
+
477
+ stdcell_types = (
478
+ 'tie_cell',
479
+ 'standard_cell',
480
+ 'buffer',
481
+ 'clock_buffer',
482
+ 'timing_repair_buffer',
483
+ 'inverter',
484
+ 'clock_inverter',
485
+ 'timing_Repair_inverter',
486
+ 'clock_gate_cell',
487
+ 'level_shifter_cell',
488
+ 'sequential_cell',
489
+ 'multi_input_combinational_cell',
490
+ 'other'
491
+ )
492
+
493
+ stdcell_info_area = []
494
+ stdcell_info_count = []
495
+ stdcellarea = None
496
+ stdcellcount = None
497
+
498
+ for key, value in data.items():
499
+ if key == 'name':
500
+ cell_name = value
501
+ elif key == 'count':
502
+ cellcount = value
503
+ elif key == 'area':
504
+ cellarea = value
505
+ elif key.startswith('count__class'):
506
+ _, cell_class = key.split(':')
507
+ if cell_class == 'macro':
508
+ macrocount = value
509
+ elif cell_class in stdcell_types:
510
+ stdcell_info_count.append(value)
511
+ elif key.startswith('area__class'):
512
+ _, cell_class = key.split(':')
513
+ if cell_class == 'macro':
514
+ macroarea = value
515
+ elif cell_class in stdcell_types:
516
+ stdcell_info_area.append(value)
517
+
518
+ if stdcell_info_count:
519
+ stdcellcount = sum(stdcell_info_count)
520
+ if stdcell_info_area:
521
+ stdcellarea = sum(stdcell_info_area)
522
+
523
+ cellarea_report.addCell(
524
+ name=cell_name,
525
+ module=cell_type,
526
+ cellarea=cellarea,
527
+ cellcount=cellcount,
528
+ macroarea=macroarea,
529
+ macrocount=macrocount,
530
+ stdcellarea=stdcellarea,
531
+ stdcellcount=stdcellcount)
532
+
533
+ if filtered_data:
534
+ return True
535
+ return False
536
+
537
+ for module in modules:
538
+ process_cell(module)
539
+
540
+ if cellarea_report.size() > 0:
541
+ cellarea_report.writeReport("reports/hierarchical_cell_area.json")
542
+
543
+
427
544
  ######
428
545
  def get_library_timing_keypaths(chip, lib):
429
546
  step = chip.get('arg', 'step')
@@ -483,3 +483,12 @@ proc sc_convert_rotation { rot } {
483
483
  default { utl::error FLW 1 "$rot not recognized" }
484
484
  }
485
485
  }
486
+
487
+ proc sc_check_version { min_required } {
488
+ set version [split [ord::openroad_version] "-"]
489
+ if { [lindex $version 0] != "v2.0" } {
490
+ return false
491
+ }
492
+
493
+ return [expr { [lindex $version 1] >= $min_required }]
494
+ }
@@ -168,3 +168,22 @@ foreach markerdb [[ord::get_db_block] getMarkerCategories] {
168
168
  $markerdb writeTR "reports/markers/${sc_design}.[$markerdb getName].rpt"
169
169
  $markerdb writeJSON "reports/markers/${sc_design}.[$markerdb getName].json"
170
170
  }
171
+
172
+ if { [sc_check_version 17038] } {
173
+ utl::push_metrics_stage "sc__cellarea__{}"
174
+ tee -file reports/cell_usage.rpt {report_cell_usage -verbose}
175
+
176
+ foreach modinst [[ord::get_db_block] getModInsts] {
177
+ tee -quiet -append -file reports/cell_usage.rpt { puts "" }
178
+ tee -quiet -append -file reports/cell_usage.rpt {
179
+ puts "########################################################"
180
+ }
181
+ tee -quiet -append -file reports/cell_usage.rpt { puts "" }
182
+
183
+ utl::metric "design__instance__name__in_module:[[$modinst getMaster] getName]" \
184
+ [$modinst getHierarchicalName]
185
+ tee -quiet -append -file reports/cell_usage.rpt \
186
+ "report_cell_usage -verbose [$modinst getHierarchicalName]"
187
+ }
188
+ utl::pop_metrics_stage
189
+ }
@@ -11,9 +11,15 @@ def setup(chip):
11
11
  vivado.setup_task(chip, task)
12
12
 
13
13
  design = chip.top()
14
- chip.set('tool', tool, 'task', task, 'input', f'{design}_checkpoint.dcp',
14
+ chip.set('tool', tool, 'task', task, 'input', f'{design}.dcp',
15
15
  step=step, index=index)
16
- chip.set('tool', tool, 'task', task, 'output', f'{design}.bit',
16
+ chip.set('tool', tool, 'task', task, 'output', f'{design}.dcp',
17
+ step=step, index=index)
18
+ chip.add('tool', tool, 'task', task, 'output', f'{design}.xdc',
19
+ step=step, index=index)
20
+ chip.add('tool', tool, 'task', task, 'output', f'{design}.vg',
21
+ step=step, index=index)
22
+ chip.add('tool', tool, 'task', task, 'output', f'{design}.bit',
17
23
  step=step, index=index)
18
24
 
19
25
 
@@ -11,9 +11,13 @@ def setup(chip):
11
11
  vivado.setup_task(chip, task)
12
12
 
13
13
  design = chip.top()
14
- chip.set('tool', tool, 'task', task, 'input', f'{design}_checkpoint.dcp',
14
+ chip.set('tool', tool, 'task', task, 'input', f'{design}.dcp',
15
15
  step=step, index=index)
16
- chip.set('tool', tool, 'task', task, 'output', f'{design}_checkpoint.dcp',
16
+ chip.set('tool', tool, 'task', task, 'output', f'{design}.dcp',
17
+ step=step, index=index)
18
+ chip.add('tool', tool, 'task', task, 'output', f'{design}.xdc',
19
+ step=step, index=index)
20
+ chip.add('tool', tool, 'task', task, 'output', f'{design}.vg',
17
21
  step=step, index=index)
18
22
 
19
23
 
@@ -11,9 +11,13 @@ def setup(chip):
11
11
  vivado.setup_task(chip, task)
12
12
 
13
13
  design = chip.top()
14
- chip.set('tool', tool, 'task', task, 'input', f'{design}_checkpoint.dcp',
14
+ chip.set('tool', tool, 'task', task, 'input', f'{design}.dcp',
15
15
  step=step, index=index)
16
- chip.set('tool', tool, 'task', task, 'output', f'{design}_checkpoint.dcp',
16
+ chip.set('tool', tool, 'task', task, 'output', f'{design}.dcp',
17
+ step=step, index=index)
18
+ chip.add('tool', tool, 'task', task, 'output', f'{design}.xdc',
19
+ step=step, index=index)
20
+ chip.add('tool', tool, 'task', task, 'output', f'{design}.vg',
17
21
  step=step, index=index)
18
22
 
19
23
 
@@ -1,4 +1,4 @@
1
- open_checkpoint "inputs/${sc_design}_checkpoint.dcp"
1
+ open_checkpoint "inputs/${sc_design}.dcp"
2
2
  if { $sc_constraint != "" } {
3
3
  write_bitstream -force -file "outputs/${sc_design}.bit"
4
4
  } else {