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.
- siliconcompiler/_metadata.py +1 -1
- siliconcompiler/report/dashboard/components/graph.py +11 -6
- siliconcompiler/report/dashboard/layouts/vertical_flowgraph.py +1 -1
- siliconcompiler/report/dashboard/layouts/vertical_flowgraph_node_tab.py +1 -1
- siliconcompiler/report/dashboard/layouts/vertical_flowgraph_sac_tabs.py +1 -1
- siliconcompiler/report/report.py +20 -1
- siliconcompiler/scheduler/send_messages.py +37 -33
- siliconcompiler/scheduler/validation/email_credentials.json +7 -0
- siliconcompiler/targets/fpgaflow_demo.py +6 -7
- siliconcompiler/tools/_common/__init__.py +2 -2
- siliconcompiler/tools/_common/asic.py +47 -0
- siliconcompiler/tools/klayout/klayout_show.py +53 -13
- siliconcompiler/tools/openroad/openroad.py +121 -4
- siliconcompiler/tools/openroad/scripts/sc_procs.tcl +9 -0
- siliconcompiler/tools/openroad/scripts/sc_report.tcl +19 -0
- siliconcompiler/tools/vivado/bitstream.py +8 -2
- siliconcompiler/tools/vivado/place.py +6 -2
- siliconcompiler/tools/vivado/route.py +6 -2
- siliconcompiler/tools/vivado/scripts/sc_bitstream.tcl +1 -1
- siliconcompiler/tools/vivado/scripts/sc_place.tcl +1 -1
- siliconcompiler/tools/vivado/scripts/sc_route.tcl +1 -1
- siliconcompiler/tools/vivado/scripts/sc_run.tcl +4 -2
- siliconcompiler/tools/vivado/syn_fpga.py +5 -1
- siliconcompiler/tools/vivado/vivado.py +26 -10
- siliconcompiler/tools/vpr/vpr.py +11 -0
- siliconcompiler/tools/yosys/syn_asic.tcl +3 -0
- siliconcompiler/toolscripts/_tools.json +2 -2
- siliconcompiler/utils/__init__.py +12 -5
- siliconcompiler/utils/showtools.py +2 -0
- {siliconcompiler-0.28.7.dist-info → siliconcompiler-0.28.9.dist-info}/METADATA +48 -47
- {siliconcompiler-0.28.7.dist-info → siliconcompiler-0.28.9.dist-info}/RECORD +35 -36
- {siliconcompiler-0.28.7.dist-info → siliconcompiler-0.28.9.dist-info}/WHEEL +1 -1
- siliconcompiler/toolscripts/rhel8/install-openroad.sh +0 -31
- {siliconcompiler-0.28.7.dist-info → siliconcompiler-0.28.9.dist-info}/LICENSE +0 -0
- {siliconcompiler-0.28.7.dist-info → siliconcompiler-0.28.9.dist-info}/entry_points.txt +0 -0
- {siliconcompiler-0.28.7.dist-info → siliconcompiler-0.28.9.dist-info}/top_level.txt +0 -0
siliconcompiler/_metadata.py
CHANGED
|
@@ -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
|
-
|
|
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(
|
|
187
|
-
metrics =
|
|
188
|
-
|
|
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:
|
|
@@ -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(
|
|
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(
|
|
108
|
+
graph.viewer(node_to_step_index_map)
|
|
109
109
|
|
|
110
110
|
_common.check_rerun()
|
siliconcompiler/report/report.py
CHANGED
|
@@ -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
|
|
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
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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=
|
|
117
|
-
msg.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
|
-
|
|
26
|
-
|
|
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=
|
|
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
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
for
|
|
227
|
-
|
|
228
|
-
|
|
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": [
|
|
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}
|
|
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}.
|
|
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}
|
|
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}
|
|
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}
|
|
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}
|
|
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
|
|