siliconcompiler 0.28.3__py3-none-any.whl → 0.28.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- siliconcompiler/_metadata.py +1 -1
- siliconcompiler/apps/sc_dashboard.py +1 -1
- siliconcompiler/core.py +93 -55
- siliconcompiler/fpgas/vpr_example.py +8 -0
- siliconcompiler/package.py +3 -2
- siliconcompiler/report/dashboard/__init__.py +9 -0
- siliconcompiler/report/dashboard/components/__init__.py +13 -1
- siliconcompiler/report/dashboard/layouts/vertical_flowgraph.py +4 -3
- siliconcompiler/report/dashboard/layouts/vertical_flowgraph_node_tab.py +4 -1
- siliconcompiler/report/dashboard/layouts/vertical_flowgraph_sac_tabs.py +4 -1
- siliconcompiler/report/dashboard/state.py +3 -1
- siliconcompiler/report/summary_table.py +1 -2
- siliconcompiler/report/utils.py +1 -2
- siliconcompiler/scheduler/__init__.py +2 -0
- siliconcompiler/sphinx_ext/dynamicgen.py +6 -0
- siliconcompiler/tools/_common/__init__.py +44 -6
- siliconcompiler/tools/_common/asic.py +79 -23
- siliconcompiler/tools/genfasm/genfasm.py +7 -0
- siliconcompiler/tools/ghdl/convert.py +7 -0
- siliconcompiler/tools/klayout/convert_drc_db.py +60 -0
- siliconcompiler/tools/klayout/drc.py +156 -0
- siliconcompiler/tools/klayout/export.py +2 -0
- siliconcompiler/tools/klayout/klayout.py +0 -1
- siliconcompiler/tools/klayout/klayout_convert_drc_db.py +182 -0
- siliconcompiler/tools/klayout/operations.py +2 -0
- siliconcompiler/tools/klayout/screenshot.py +2 -0
- siliconcompiler/tools/klayout/show.py +4 -4
- siliconcompiler/tools/magic/drc.py +21 -0
- siliconcompiler/tools/magic/extspice.py +21 -0
- siliconcompiler/tools/magic/magic.py +29 -0
- siliconcompiler/tools/magic/sc_drc.tcl +2 -12
- siliconcompiler/tools/magic/sc_extspice.tcl +3 -15
- siliconcompiler/tools/openroad/openroad.py +44 -2
- siliconcompiler/tools/openroad/scripts/sc_apr.tcl +15 -0
- siliconcompiler/tools/openroad/scripts/sc_floorplan.tcl +55 -9
- siliconcompiler/tools/openroad/scripts/sc_metrics.tcl +10 -0
- siliconcompiler/tools/openroad/scripts/sc_procs.tcl +3 -1
- siliconcompiler/tools/openroad/scripts/sc_route.tcl +8 -2
- siliconcompiler/tools/openroad/scripts/sc_screenshot.tcl +0 -5
- siliconcompiler/tools/openroad/scripts/sc_write_images.tcl +36 -6
- siliconcompiler/tools/surelog/__init__.py +12 -0
- siliconcompiler/tools/verilator/compile.py +27 -0
- siliconcompiler/tools/verilator/verilator.py +9 -0
- siliconcompiler/tools/vpr/vpr.py +18 -0
- siliconcompiler/tools/yosys/{syn_asic_fpga_shared.tcl → procs.tcl} +23 -0
- siliconcompiler/tools/yosys/sc_screenshot.tcl +104 -0
- siliconcompiler/tools/yosys/sc_syn.tcl +7 -9
- siliconcompiler/tools/yosys/screenshot.py +153 -0
- siliconcompiler/tools/yosys/syn_asic.py +3 -0
- siliconcompiler/tools/yosys/syn_asic.tcl +1 -3
- siliconcompiler/tools/yosys/syn_fpga.tcl +3 -2
- siliconcompiler/toolscripts/_tools.json +3 -3
- siliconcompiler/utils/__init__.py +30 -1
- siliconcompiler/utils/showtools.py +4 -0
- {siliconcompiler-0.28.3.dist-info → siliconcompiler-0.28.4.dist-info}/METADATA +16 -3
- {siliconcompiler-0.28.3.dist-info → siliconcompiler-0.28.4.dist-info}/RECORD +60 -55
- {siliconcompiler-0.28.3.dist-info → siliconcompiler-0.28.4.dist-info}/WHEEL +1 -1
- {siliconcompiler-0.28.3.dist-info → siliconcompiler-0.28.4.dist-info}/LICENSE +0 -0
- {siliconcompiler-0.28.3.dist-info → siliconcompiler-0.28.4.dist-info}/entry_points.txt +0 -0
- {siliconcompiler-0.28.3.dist-info → siliconcompiler-0.28.4.dist-info}/top_level.txt +0 -0
|
@@ -47,7 +47,8 @@ def set_tool_task_var(chip,
|
|
|
47
47
|
option_key=None,
|
|
48
48
|
pdk_key=None,
|
|
49
49
|
lib_key=None,
|
|
50
|
-
require=None
|
|
50
|
+
require=None,
|
|
51
|
+
skip=None):
|
|
51
52
|
'''
|
|
52
53
|
Set parameter from PDK -> main library -> option -> default_value
|
|
53
54
|
'''
|
|
@@ -56,7 +57,11 @@ def set_tool_task_var(chip,
|
|
|
56
57
|
tool, task = _common.get_tool_task(chip, step, index)
|
|
57
58
|
pdkname = chip.get('option', 'pdk')
|
|
58
59
|
stackup = chip.get('option', 'stackup')
|
|
59
|
-
|
|
60
|
+
|
|
61
|
+
if not skip:
|
|
62
|
+
skip = []
|
|
63
|
+
if not isinstance(skip, (list, tuple)):
|
|
64
|
+
skip = [skip]
|
|
60
65
|
|
|
61
66
|
if not require:
|
|
62
67
|
require = []
|
|
@@ -66,31 +71,35 @@ def set_tool_task_var(chip,
|
|
|
66
71
|
check_keys = []
|
|
67
72
|
|
|
68
73
|
# Add PDK key
|
|
69
|
-
if not
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
if 'pdk' not in skip:
|
|
75
|
+
if not pdk_key:
|
|
76
|
+
pdk_key = param_key
|
|
77
|
+
check_keys.append(['pdk', pdkname, 'var', tool, stackup, pdk_key])
|
|
78
|
+
if 'pdk' in require:
|
|
79
|
+
chip.add('tool', tool, 'task', task, 'require',
|
|
80
|
+
','.join(check_keys[-1]),
|
|
81
|
+
step=step, index=index)
|
|
76
82
|
|
|
77
83
|
# Add library key
|
|
78
|
-
if not
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
84
|
+
if 'lib' not in skip:
|
|
85
|
+
mainlib = get_mainlib(chip)
|
|
86
|
+
if not lib_key:
|
|
87
|
+
lib_key = f'{tool}_{param_key}'
|
|
88
|
+
check_keys.append(['library', mainlib, 'option', 'var', lib_key])
|
|
89
|
+
if 'lib' in require:
|
|
90
|
+
chip.add('tool', tool, 'task', task, 'require',
|
|
91
|
+
','.join(check_keys[-1]),
|
|
92
|
+
step=step, index=index)
|
|
85
93
|
|
|
86
94
|
# Add option key
|
|
87
|
-
if not
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
95
|
+
if 'option' not in skip:
|
|
96
|
+
if not option_key:
|
|
97
|
+
option_key = f'{tool}_{param_key}'
|
|
98
|
+
check_keys.append(['option', 'var', option_key])
|
|
99
|
+
if 'option' in require:
|
|
100
|
+
chip.add('tool', tool, 'task', task, 'require',
|
|
101
|
+
','.join(check_keys[-1]),
|
|
102
|
+
step=step, index=index)
|
|
94
103
|
|
|
95
104
|
require_key, value = _common.pick_key(chip, reversed(check_keys), step=step, index=index)
|
|
96
105
|
if not value:
|
|
@@ -113,3 +122,50 @@ def set_tool_task_var(chip,
|
|
|
113
122
|
if schelp:
|
|
114
123
|
chip.set('tool', tool, 'task', task, 'var', param_key,
|
|
115
124
|
schelp, field='help')
|
|
125
|
+
|
|
126
|
+
return value
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def get_tool_task_var(chip,
|
|
130
|
+
param_key,
|
|
131
|
+
option_key=None,
|
|
132
|
+
pdk_key=None,
|
|
133
|
+
lib_key=None,
|
|
134
|
+
skip=None):
|
|
135
|
+
'''
|
|
136
|
+
Get parameter from PDK -> main library -> option -> default_value
|
|
137
|
+
'''
|
|
138
|
+
step = chip.get('arg', 'step')
|
|
139
|
+
index = chip.get('arg', 'index')
|
|
140
|
+
tool, _ = _common.get_tool_task(chip, step, index)
|
|
141
|
+
pdkname = chip.get('option', 'pdk')
|
|
142
|
+
stackup = chip.get('option', 'stackup')
|
|
143
|
+
|
|
144
|
+
if not skip:
|
|
145
|
+
skip = []
|
|
146
|
+
if not isinstance(skip, (list, tuple)):
|
|
147
|
+
skip = [skip]
|
|
148
|
+
|
|
149
|
+
check_keys = []
|
|
150
|
+
# Add PDK key
|
|
151
|
+
if 'pdk' not in skip:
|
|
152
|
+
if not pdk_key:
|
|
153
|
+
pdk_key = param_key
|
|
154
|
+
check_keys.append(['pdk', pdkname, 'var', tool, stackup, pdk_key])
|
|
155
|
+
|
|
156
|
+
# Add library key
|
|
157
|
+
if 'lib' not in skip:
|
|
158
|
+
mainlib = get_mainlib(chip)
|
|
159
|
+
if not lib_key:
|
|
160
|
+
lib_key = f'{tool}_{param_key}'
|
|
161
|
+
check_keys.append(['library', mainlib, 'option', 'var', lib_key])
|
|
162
|
+
|
|
163
|
+
# Add option key
|
|
164
|
+
if 'option' not in skip:
|
|
165
|
+
if not option_key:
|
|
166
|
+
option_key = f'{tool}_{param_key}'
|
|
167
|
+
check_keys.append(['option', 'var', option_key])
|
|
168
|
+
|
|
169
|
+
_, value = _common.pick_key(chip, reversed(check_keys), step=step, index=index)
|
|
170
|
+
|
|
171
|
+
return value
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from siliconcompiler.tools.vpr.vpr import parse_version as vpr_parse_version
|
|
2
2
|
from siliconcompiler.tools.vpr.vpr import normalize_version as vpr_normalize_version
|
|
3
|
+
from siliconcompiler.tools.vpr.vpr import add_tool_requirements as add_vpr_requirements
|
|
3
4
|
|
|
4
5
|
'''
|
|
5
6
|
Generate a `FSAM <https://github.com/chipsalliance/fasm>`_ file from the output of
|
|
@@ -25,6 +26,12 @@ def setup(chip):
|
|
|
25
26
|
chip.set('tool', 'genfasm', 'vswitch', '--version')
|
|
26
27
|
chip.set('tool', 'genfasm', 'version', '>=8.1.0', clobber=False)
|
|
27
28
|
|
|
29
|
+
add_tool_requirements(chip)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def add_tool_requirements(chip):
|
|
33
|
+
add_vpr_requirements(chip)
|
|
34
|
+
|
|
28
35
|
|
|
29
36
|
def parse_version(chip):
|
|
30
37
|
return vpr_parse_version(chip)
|
|
@@ -40,6 +40,13 @@ def setup(chip):
|
|
|
40
40
|
|
|
41
41
|
chip.set('tool', tool, 'task', task, 'output', f'{design}.v', step=step, index=index)
|
|
42
42
|
|
|
43
|
+
chip.set('tool', tool, 'task', task, 'var', 'extraopts', 'extra options to pass to ghdl',
|
|
44
|
+
field='help')
|
|
45
|
+
if chip.get('tool', tool, 'task', task, 'var', 'extraopts', step=step, index=index):
|
|
46
|
+
chip.add('tool', tool, 'task', task, 'require',
|
|
47
|
+
','.join(['tool', tool, 'task', task, 'var', 'extraopts']),
|
|
48
|
+
step=step, index=index)
|
|
49
|
+
|
|
43
50
|
|
|
44
51
|
################################
|
|
45
52
|
# Custom runtime options
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from siliconcompiler.tools._common import input_provides, input_file_node_name, get_tool_task
|
|
2
|
+
|
|
3
|
+
from siliconcompiler.tools.klayout import klayout
|
|
4
|
+
from siliconcompiler.tools.klayout.klayout import setup as setup_tool
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def make_docs(chip):
|
|
8
|
+
klayout.make_docs(chip)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def setup(chip):
|
|
12
|
+
'''
|
|
13
|
+
Convert a DRC db from .lyrdb or .ascii to an openroad json marker file
|
|
14
|
+
'''
|
|
15
|
+
|
|
16
|
+
# Generic tool setup.
|
|
17
|
+
setup_tool(chip)
|
|
18
|
+
|
|
19
|
+
step = chip.get('arg', 'step')
|
|
20
|
+
index = chip.get('arg', 'index')
|
|
21
|
+
tool, task = get_tool_task(chip, step, index)
|
|
22
|
+
design = chip.top()
|
|
23
|
+
|
|
24
|
+
clobber = False
|
|
25
|
+
|
|
26
|
+
chip.set('tool', tool, 'task', task, 'threads', 1,
|
|
27
|
+
step=step, index=index, clobber=clobber)
|
|
28
|
+
|
|
29
|
+
script = 'klayout_convert_drc_db.py'
|
|
30
|
+
option = ['-z', '-nc', '-rx', '-r']
|
|
31
|
+
chip.set('tool', tool, 'task', task, 'script', script,
|
|
32
|
+
step=step, index=index, clobber=clobber)
|
|
33
|
+
chip.set('tool', tool, 'task', task, 'option', option,
|
|
34
|
+
step=step, index=index, clobber=clobber)
|
|
35
|
+
|
|
36
|
+
input_nodes = set()
|
|
37
|
+
for nodes in input_provides(chip, step, index).values():
|
|
38
|
+
input_nodes.update(nodes)
|
|
39
|
+
|
|
40
|
+
chip.set('tool', tool, 'task', task, 'input', [], step=step, index=index)
|
|
41
|
+
chip.set('tool', tool, 'task', task, 'output', [], step=step, index=index)
|
|
42
|
+
for file, nodes in input_provides(chip, step, index).items():
|
|
43
|
+
if file not in (f'{design}.lyrdb', f'{design}.ascii'):
|
|
44
|
+
continue
|
|
45
|
+
|
|
46
|
+
if len(input_nodes) == 1:
|
|
47
|
+
chip.add('tool', tool, 'task', task, 'input',
|
|
48
|
+
file,
|
|
49
|
+
step=step, index=index)
|
|
50
|
+
else:
|
|
51
|
+
for in_step, in_index in nodes:
|
|
52
|
+
chip.add('tool', tool, 'task', task, 'input',
|
|
53
|
+
input_file_node_name(file, in_step, in_index),
|
|
54
|
+
step=step, index=index)
|
|
55
|
+
if not chip.get('tool', tool, 'task', task, 'input', step=step, index=index):
|
|
56
|
+
chip.add('tool', tool, 'task', task, 'input', f'{design}.lyrdb',
|
|
57
|
+
step=step, index=index)
|
|
58
|
+
|
|
59
|
+
chip.set('tool', tool, 'task', task, 'output', f'{design}.json',
|
|
60
|
+
step=step, index=index)
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import shlex
|
|
3
|
+
|
|
4
|
+
from siliconcompiler.tools._common import input_provides, has_input_files, \
|
|
5
|
+
get_input_files, get_tool_task, record_metric
|
|
6
|
+
from siliconcompiler.tools._common.asic import set_tool_task_var, get_tool_task_var
|
|
7
|
+
|
|
8
|
+
from siliconcompiler.tools.klayout import klayout
|
|
9
|
+
from siliconcompiler.tools.klayout.klayout import setup as setup_tool
|
|
10
|
+
import xml.etree.ElementTree as ET
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def make_docs(chip):
|
|
14
|
+
klayout.make_docs(chip)
|
|
15
|
+
chip.set('tool', 'klayout', 'task', 'drc', 'var', 'drc_name', '<drc_name>',
|
|
16
|
+
step='<step>', index='<index>')
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def setup(chip):
|
|
20
|
+
'''
|
|
21
|
+
Performs a design rule check on the provided layout
|
|
22
|
+
'''
|
|
23
|
+
|
|
24
|
+
# Generic tool setup.
|
|
25
|
+
setup_tool(chip)
|
|
26
|
+
|
|
27
|
+
step = chip.get('arg', 'step')
|
|
28
|
+
index = chip.get('arg', 'index')
|
|
29
|
+
tool, task = get_tool_task(chip, step, index)
|
|
30
|
+
design = chip.top()
|
|
31
|
+
|
|
32
|
+
clobber = False
|
|
33
|
+
|
|
34
|
+
option = ['-z', '-nc', '-rx']
|
|
35
|
+
chip.set('tool', tool, 'task', task, 'option', option,
|
|
36
|
+
step=step, index=index, clobber=clobber)
|
|
37
|
+
|
|
38
|
+
chip.set('tool', tool, 'task', task, 'threads', os.cpu_count(),
|
|
39
|
+
step=step, index=index, clobber=clobber)
|
|
40
|
+
|
|
41
|
+
chip.add('tool', tool, 'task', task, 'require', 'option,pdk')
|
|
42
|
+
chip.add('tool', tool, 'task', task, 'require', 'option,stackup')
|
|
43
|
+
|
|
44
|
+
chip.set('tool', tool, 'task', task, 'var', 'drc_name', 'drc',
|
|
45
|
+
step=step, index=index, clobber=False)
|
|
46
|
+
chip.add('tool', tool, 'task', task, 'require', f'tool,{tool},task,{task},var,drc_name',
|
|
47
|
+
step=step, index=index)
|
|
48
|
+
|
|
49
|
+
drc_name = chip.get('tool', tool, 'task', task, 'var', 'drc_name', step=step, index=index)
|
|
50
|
+
if not drc_name:
|
|
51
|
+
raise ValueError('drc_name is required')
|
|
52
|
+
drc_name = drc_name[0]
|
|
53
|
+
|
|
54
|
+
pdk = chip.get('option', 'pdk')
|
|
55
|
+
stackup = chip.get('option', 'stackup')
|
|
56
|
+
chip.add('tool', tool, 'task', task, 'require',
|
|
57
|
+
f'pdk,{pdk},drc,runset,klayout,{stackup},{drc_name}')
|
|
58
|
+
|
|
59
|
+
if f'{design}.gds' in input_provides(chip, step, index):
|
|
60
|
+
chip.add('tool', tool, 'task', task, 'input', design + '.gds',
|
|
61
|
+
step=step, index=index)
|
|
62
|
+
elif f'{design}.oas' in input_provides(chip, step, index):
|
|
63
|
+
chip.add('tool', tool, 'task', task, 'input', design + '.oas',
|
|
64
|
+
step=step, index=index)
|
|
65
|
+
elif has_input_files(chip, 'input', 'layout', 'oas', check_library_files=False):
|
|
66
|
+
chip.add('tool', tool, 'task', task, 'require', 'input,layout,oas',
|
|
67
|
+
step=step, index=index)
|
|
68
|
+
else:
|
|
69
|
+
chip.add('tool', tool, 'task', task, 'require', 'input,layout,gds',
|
|
70
|
+
step=step, index=index)
|
|
71
|
+
|
|
72
|
+
chip.add('tool', tool, 'task', task, 'output', design + '.lyrdb',
|
|
73
|
+
step=step, index=index)
|
|
74
|
+
|
|
75
|
+
set_tool_task_var(
|
|
76
|
+
chip,
|
|
77
|
+
f'drc_params:{drc_name}',
|
|
78
|
+
schelp="Input parameter to DRC script, in the form of key=value, if the value "
|
|
79
|
+
"is <topcell>, <input>, <report>, <threads> these will be automatically "
|
|
80
|
+
"determined.",
|
|
81
|
+
skip='lib')
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def runtime_options(chip):
|
|
85
|
+
design = chip.top()
|
|
86
|
+
|
|
87
|
+
step = chip.get('arg', 'step')
|
|
88
|
+
index = chip.get('arg', 'index')
|
|
89
|
+
tool, task = get_tool_task(chip, step, index)
|
|
90
|
+
|
|
91
|
+
pdk = chip.get('option', 'pdk')
|
|
92
|
+
stackup = chip.get('option', 'stackup')
|
|
93
|
+
|
|
94
|
+
layout = None
|
|
95
|
+
for file in [f'inputs/{design}.gds', f'inputs/{design}.oas']:
|
|
96
|
+
if os.path.isfile(file):
|
|
97
|
+
layout = file
|
|
98
|
+
break
|
|
99
|
+
|
|
100
|
+
if not layout:
|
|
101
|
+
for file in [
|
|
102
|
+
get_input_files(chip, 'input', 'layout', 'oas', add_library_files=False),
|
|
103
|
+
get_input_files(chip, 'input', 'layout', 'gds', add_library_files=False)]:
|
|
104
|
+
if file:
|
|
105
|
+
layout = file[0]
|
|
106
|
+
|
|
107
|
+
threads = chip.get('tool', tool, 'task', task, 'threads', step=step, index=index)
|
|
108
|
+
if not threads:
|
|
109
|
+
threads = 1
|
|
110
|
+
|
|
111
|
+
drc_name = chip.get('tool', tool, 'task', task, 'var', 'drc_name',
|
|
112
|
+
step=step, index=index)[0]
|
|
113
|
+
report = os.path.abspath(f"outputs/{chip.top()}.lyrdb")
|
|
114
|
+
|
|
115
|
+
runset = chip.find_files('pdk', pdk, 'drc', 'runset', 'klayout', stackup, drc_name)[0]
|
|
116
|
+
|
|
117
|
+
params_lookup = {
|
|
118
|
+
"<topcell>": chip.top(),
|
|
119
|
+
"<report>": shlex.quote(report),
|
|
120
|
+
"<threads>": threads,
|
|
121
|
+
"<input>": shlex.quote(layout)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
args = [
|
|
125
|
+
'-r', shlex.quote(runset)
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
for param in get_tool_task_var(chip, f'drc_params:{drc_name}', skip='lib'):
|
|
129
|
+
for lookup, value in params_lookup.items():
|
|
130
|
+
param = param.replace(lookup, str(value))
|
|
131
|
+
args.extend(
|
|
132
|
+
['-rd', param]
|
|
133
|
+
)
|
|
134
|
+
return args
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def post_process(chip):
|
|
138
|
+
step = chip.get('arg', 'step')
|
|
139
|
+
index = chip.get('arg', 'index')
|
|
140
|
+
|
|
141
|
+
drc_db = f"outputs/{chip.top()}.lyrdb"
|
|
142
|
+
|
|
143
|
+
drc_report = None
|
|
144
|
+
if os.path.isfile(drc_db):
|
|
145
|
+
with open(drc_db, "r") as f:
|
|
146
|
+
drc_report = ET.fromstring(f.read())
|
|
147
|
+
if drc_report is None:
|
|
148
|
+
drc_db = []
|
|
149
|
+
|
|
150
|
+
violation_count = 0
|
|
151
|
+
if drc_report:
|
|
152
|
+
violations = drc_report.find('items')
|
|
153
|
+
if violations:
|
|
154
|
+
violation_count = len(violations.findall('item'))
|
|
155
|
+
|
|
156
|
+
record_metric(chip, step, index, 'drcs', violation_count, drc_db)
|
|
@@ -19,6 +19,8 @@ def setup(chip):
|
|
|
19
19
|
_, task = get_tool_task(chip, step, index)
|
|
20
20
|
clobber = False
|
|
21
21
|
|
|
22
|
+
chip.set('tool', tool, 'task', task, 'threads', 1, step=step, index=index, clobber=clobber)
|
|
23
|
+
|
|
22
24
|
script = 'klayout_export.py'
|
|
23
25
|
option = ['-z', '-nc', '-rx', '-r']
|
|
24
26
|
chip.set('tool', tool, 'task', task, 'script', script, step=step, index=index, clobber=clobber)
|
|
@@ -82,7 +82,6 @@ def setup(chip, mode="batch"):
|
|
|
82
82
|
|
|
83
83
|
chip.set('tool', tool, 'task', task, 'refdir', refdir, step=step, index=index,
|
|
84
84
|
package='siliconcompiler', clobber=clobber)
|
|
85
|
-
chip.set('tool', tool, 'task', task, 'threads', 1, step=step, index=index, clobber=clobber)
|
|
86
85
|
|
|
87
86
|
if chip.get('option', 'nodisplay'):
|
|
88
87
|
# Tells QT to use the offscreen platform if nodisplay is used
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# KLayout script to export an OpenROAD marker DB from a DRC db
|
|
2
|
+
#
|
|
3
|
+
# Based on:
|
|
4
|
+
# https://github.com/The-OpenROAD-Project/OpenROAD-flow-scripts/blob/master/flow/util/convertDrc.py
|
|
5
|
+
|
|
6
|
+
import pya
|
|
7
|
+
import glob
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def convert_drc(view, path):
|
|
14
|
+
rdb_id = view.create_rdb(os.path.basename(path))
|
|
15
|
+
rdb = view.rdb(rdb_id)
|
|
16
|
+
print(f"[INFO] reading {path}")
|
|
17
|
+
rdb.load(path)
|
|
18
|
+
|
|
19
|
+
source = os.path.abspath(path)
|
|
20
|
+
|
|
21
|
+
ordb = {
|
|
22
|
+
"source": source,
|
|
23
|
+
"description": "KLayout DRC conversion",
|
|
24
|
+
"category": {}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
for category in rdb.each_category():
|
|
28
|
+
if category.num_items() == 0:
|
|
29
|
+
# ignore categories with no data
|
|
30
|
+
continue
|
|
31
|
+
|
|
32
|
+
ordb_category = {
|
|
33
|
+
"description": category.description,
|
|
34
|
+
"source": source,
|
|
35
|
+
"violations": []
|
|
36
|
+
}
|
|
37
|
+
ordb["category"][category.name()] = ordb_category
|
|
38
|
+
|
|
39
|
+
for item in rdb.each_item_per_category(category.rdb_id()):
|
|
40
|
+
violation = {
|
|
41
|
+
"visited": item.is_visited(),
|
|
42
|
+
"visible": True,
|
|
43
|
+
"waived": "waived" in item.tags_str
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
ordb_category["violations"].append(violation)
|
|
47
|
+
|
|
48
|
+
shapes = []
|
|
49
|
+
violation["shape"] = shapes
|
|
50
|
+
|
|
51
|
+
text = []
|
|
52
|
+
|
|
53
|
+
for value in item.each_value():
|
|
54
|
+
if value.is_box():
|
|
55
|
+
shapes.append({
|
|
56
|
+
"type": "box",
|
|
57
|
+
"points": [{
|
|
58
|
+
"x": value.box().left,
|
|
59
|
+
"y": value.box().bottom
|
|
60
|
+
}, {
|
|
61
|
+
"x": value.box().right,
|
|
62
|
+
"y": value.box().top
|
|
63
|
+
}]
|
|
64
|
+
})
|
|
65
|
+
elif value.is_edge():
|
|
66
|
+
shapes.append({
|
|
67
|
+
"type": "line",
|
|
68
|
+
"points": [{
|
|
69
|
+
"x": value.edge().p1.x,
|
|
70
|
+
"y": value.edge().p1.y
|
|
71
|
+
}, {
|
|
72
|
+
"x": value.edge().p2.x,
|
|
73
|
+
"y": value.edge().p2.y
|
|
74
|
+
}]
|
|
75
|
+
})
|
|
76
|
+
elif value.is_edge_pair():
|
|
77
|
+
edge1 = value.edge_pair().first
|
|
78
|
+
edge2 = value.edge_pair().second
|
|
79
|
+
|
|
80
|
+
shapes.append({
|
|
81
|
+
"type": "line",
|
|
82
|
+
"points": [{
|
|
83
|
+
"x": edge1.p1.x,
|
|
84
|
+
"y": edge1.p1.y
|
|
85
|
+
}, {
|
|
86
|
+
"x": edge1.p2.x,
|
|
87
|
+
"y": edge1.p2.y
|
|
88
|
+
}]
|
|
89
|
+
})
|
|
90
|
+
shapes.append({
|
|
91
|
+
"type": "line",
|
|
92
|
+
"points": [{
|
|
93
|
+
"x": edge2.p1.x,
|
|
94
|
+
"y": edge2.p1.y
|
|
95
|
+
}, {
|
|
96
|
+
"x": edge2.p2.x,
|
|
97
|
+
"y": edge2.p2.y
|
|
98
|
+
}]
|
|
99
|
+
})
|
|
100
|
+
elif value.is_polygon():
|
|
101
|
+
points = []
|
|
102
|
+
for edge in value.polygon().each_edge():
|
|
103
|
+
points.append({
|
|
104
|
+
"x": edge.p1.x,
|
|
105
|
+
"y": edge.p1.y
|
|
106
|
+
})
|
|
107
|
+
points.append({
|
|
108
|
+
"x": edge.p2.x,
|
|
109
|
+
"y": edge.p2.y
|
|
110
|
+
})
|
|
111
|
+
shapes.append({
|
|
112
|
+
"type": "polygon",
|
|
113
|
+
"points": points
|
|
114
|
+
})
|
|
115
|
+
elif value.is_path():
|
|
116
|
+
points = []
|
|
117
|
+
for edge in value.path().polygon().each_edge():
|
|
118
|
+
points.append({
|
|
119
|
+
"x": edge.p1.x,
|
|
120
|
+
"y": edge.p1.y
|
|
121
|
+
})
|
|
122
|
+
points.append({
|
|
123
|
+
"x": edge.p2.x,
|
|
124
|
+
"y": edge.p2.y
|
|
125
|
+
})
|
|
126
|
+
shapes.append({
|
|
127
|
+
"type": "polygon",
|
|
128
|
+
"points": points
|
|
129
|
+
})
|
|
130
|
+
elif value.is_text():
|
|
131
|
+
text.append(value.text())
|
|
132
|
+
elif value.is_string():
|
|
133
|
+
text.append(value.string())
|
|
134
|
+
else:
|
|
135
|
+
print("[WARN] Unknown violation shape:", value)
|
|
136
|
+
|
|
137
|
+
comment = ""
|
|
138
|
+
if hasattr(item, 'comment'):
|
|
139
|
+
comment = item.comment
|
|
140
|
+
if text:
|
|
141
|
+
if comment:
|
|
142
|
+
comment += ": "
|
|
143
|
+
comment += ", ".join(text)
|
|
144
|
+
|
|
145
|
+
if comment:
|
|
146
|
+
violation["comment"] = comment
|
|
147
|
+
|
|
148
|
+
return ordb
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def main():
|
|
152
|
+
# SC_ROOT provided by CLI
|
|
153
|
+
sys.path.append(SC_ROOT) # noqa: F821
|
|
154
|
+
|
|
155
|
+
from tools.klayout.klayout_utils import get_schema
|
|
156
|
+
|
|
157
|
+
schema = get_schema(manifest='sc_manifest.json')
|
|
158
|
+
|
|
159
|
+
design = schema.get('design')
|
|
160
|
+
|
|
161
|
+
app = pya.Application.instance()
|
|
162
|
+
win = app.main_window()
|
|
163
|
+
|
|
164
|
+
# Create a dummy view to use for loading
|
|
165
|
+
cell_view = win.create_layout(0)
|
|
166
|
+
layout_view = cell_view.view()
|
|
167
|
+
|
|
168
|
+
ordb = {}
|
|
169
|
+
for file in glob.glob(f'inputs/{design}*.lyrdb') + glob.glob('inputs/{design}*.ascii'):
|
|
170
|
+
name = os.path.basename(file)
|
|
171
|
+
|
|
172
|
+
ordb[name] = convert_drc(layout_view, file)
|
|
173
|
+
|
|
174
|
+
with open(f"outputs/{design}.json", "w") as outfile:
|
|
175
|
+
json.dump(
|
|
176
|
+
ordb,
|
|
177
|
+
outfile,
|
|
178
|
+
indent=2)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
if __name__ == '__main__':
|
|
182
|
+
main()
|
|
@@ -109,6 +109,8 @@ def setup(chip):
|
|
|
109
109
|
_, task = get_tool_task(chip, step, index)
|
|
110
110
|
clobber = False
|
|
111
111
|
|
|
112
|
+
chip.set('tool', tool, 'task', task, 'threads', 1, step=step, index=index, clobber=clobber)
|
|
113
|
+
|
|
112
114
|
script = 'klayout_operations.py'
|
|
113
115
|
option = ['-z', '-nc', '-rx', '-r']
|
|
114
116
|
chip.set('tool', tool, 'task', task, 'script', script, step=step, index=index, clobber=clobber)
|
|
@@ -73,12 +73,12 @@ def setup(chip):
|
|
|
73
73
|
|
|
74
74
|
step = chip.get('arg', 'step')
|
|
75
75
|
index = chip.get('arg', 'index')
|
|
76
|
-
|
|
76
|
+
tool, task = get_tool_task(chip, step, index)
|
|
77
|
+
clobber = False
|
|
77
78
|
|
|
78
|
-
|
|
79
|
+
chip.set('tool', tool, 'task', task, 'threads', 1, step=step, index=index, clobber=clobber)
|
|
79
80
|
|
|
80
|
-
|
|
81
|
-
clobber = False
|
|
81
|
+
general_gui_setup(chip, task, False)
|
|
82
82
|
|
|
83
83
|
option = ['-nc', '-rm']
|
|
84
84
|
chip.set('tool', tool, 'task', task, 'option', option, step=step, index=index, clobber=clobber)
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import re
|
|
2
2
|
|
|
3
3
|
from siliconcompiler.tools.magic.magic import setup as setup_tool
|
|
4
|
+
from siliconcompiler.tools.magic.magic import process_file
|
|
4
5
|
from siliconcompiler import sc_open
|
|
5
6
|
from siliconcompiler.tools._common import get_tool_task, record_metric
|
|
7
|
+
from siliconcompiler.tools._common.asic import get_mainlib, get_libraries
|
|
6
8
|
|
|
7
9
|
|
|
8
10
|
def setup(chip):
|
|
@@ -22,6 +24,25 @@ def setup(chip):
|
|
|
22
24
|
chip.set('tool', tool, 'task', task, 'output', f'{design}.drc.mag', step=step, index=index)
|
|
23
25
|
|
|
24
26
|
|
|
27
|
+
def pre_process(chip):
|
|
28
|
+
step = chip.get('arg', 'step')
|
|
29
|
+
index = chip.get('arg', 'index')
|
|
30
|
+
tool, task = get_tool_task(chip, step, index)
|
|
31
|
+
|
|
32
|
+
pdk = chip.get('option', 'pdk')
|
|
33
|
+
stackup = chip.get('option', 'stackup')
|
|
34
|
+
mainlib = get_mainlib(chip)
|
|
35
|
+
libtype = chip.get('library', mainlib, 'asic', 'libarch', step=step, index=index)
|
|
36
|
+
process_file('lef', chip, 'pdk', pdk, 'aprtech', 'magic', stackup, libtype, 'lef')
|
|
37
|
+
|
|
38
|
+
for lib in get_libraries(chip, 'logic'):
|
|
39
|
+
process_file('lef', chip, 'library', lib, 'output', stackup, 'lef')
|
|
40
|
+
|
|
41
|
+
for lib in get_libraries(chip, 'macro'):
|
|
42
|
+
if lib in chip.get('tool', tool, 'task', task, 'var', 'exclude', step=step, index=index):
|
|
43
|
+
process_file('lef', chip, 'library', lib, 'output', stackup, 'lef')
|
|
44
|
+
|
|
45
|
+
|
|
25
46
|
################################
|
|
26
47
|
# Post_process (post executable)
|
|
27
48
|
################################
|