siliconcompiler 0.26.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.
- siliconcompiler/__init__.py +24 -0
- siliconcompiler/__main__.py +12 -0
- siliconcompiler/_common.py +49 -0
- siliconcompiler/_metadata.py +36 -0
- siliconcompiler/apps/__init__.py +0 -0
- siliconcompiler/apps/_common.py +76 -0
- siliconcompiler/apps/sc.py +92 -0
- siliconcompiler/apps/sc_dashboard.py +94 -0
- siliconcompiler/apps/sc_issue.py +178 -0
- siliconcompiler/apps/sc_remote.py +199 -0
- siliconcompiler/apps/sc_server.py +39 -0
- siliconcompiler/apps/sc_show.py +142 -0
- siliconcompiler/apps/smake.py +232 -0
- siliconcompiler/checklists/__init__.py +0 -0
- siliconcompiler/checklists/oh_tapeout.py +41 -0
- siliconcompiler/core.py +3221 -0
- siliconcompiler/data/RobotoMono/LICENSE.txt +202 -0
- siliconcompiler/data/RobotoMono/RobotoMono-Regular.ttf +0 -0
- siliconcompiler/data/heartbeat.v +18 -0
- siliconcompiler/data/logo.png +0 -0
- siliconcompiler/flowgraph.py +570 -0
- siliconcompiler/flows/__init__.py +0 -0
- siliconcompiler/flows/_common.py +67 -0
- siliconcompiler/flows/asicflow.py +180 -0
- siliconcompiler/flows/asictopflow.py +38 -0
- siliconcompiler/flows/dvflow.py +86 -0
- siliconcompiler/flows/fpgaflow.py +202 -0
- siliconcompiler/flows/generate_openroad_rcx.py +66 -0
- siliconcompiler/flows/lintflow.py +35 -0
- siliconcompiler/flows/screenshotflow.py +51 -0
- siliconcompiler/flows/showflow.py +59 -0
- siliconcompiler/flows/signoffflow.py +53 -0
- siliconcompiler/flows/synflow.py +128 -0
- siliconcompiler/fpgas/__init__.py +0 -0
- siliconcompiler/fpgas/lattice_ice40.py +42 -0
- siliconcompiler/fpgas/vpr_example.py +109 -0
- siliconcompiler/issue.py +300 -0
- siliconcompiler/libs/__init__.py +0 -0
- siliconcompiler/libs/asap7sc7p5t.py +8 -0
- siliconcompiler/libs/gf180mcu.py +8 -0
- siliconcompiler/libs/nangate45.py +8 -0
- siliconcompiler/libs/sky130hd.py +8 -0
- siliconcompiler/libs/sky130io.py +8 -0
- siliconcompiler/package.py +412 -0
- siliconcompiler/pdks/__init__.py +0 -0
- siliconcompiler/pdks/asap7.py +8 -0
- siliconcompiler/pdks/freepdk45.py +8 -0
- siliconcompiler/pdks/gf180.py +8 -0
- siliconcompiler/pdks/skywater130.py +8 -0
- siliconcompiler/remote/__init__.py +36 -0
- siliconcompiler/remote/client.py +891 -0
- siliconcompiler/remote/schema.py +106 -0
- siliconcompiler/remote/server.py +507 -0
- siliconcompiler/remote/server_schema/requests/cancel_job.json +51 -0
- siliconcompiler/remote/server_schema/requests/check_progress.json +61 -0
- siliconcompiler/remote/server_schema/requests/check_server.json +38 -0
- siliconcompiler/remote/server_schema/requests/delete_job.json +51 -0
- siliconcompiler/remote/server_schema/requests/get_results.json +48 -0
- siliconcompiler/remote/server_schema/requests/remote_run.json +40 -0
- siliconcompiler/remote/server_schema/responses/cancel_job.json +18 -0
- siliconcompiler/remote/server_schema/responses/check_progress.json +30 -0
- siliconcompiler/remote/server_schema/responses/check_server.json +32 -0
- siliconcompiler/remote/server_schema/responses/delete_job.json +18 -0
- siliconcompiler/remote/server_schema/responses/get_results.json +21 -0
- siliconcompiler/remote/server_schema/responses/remote_run.json +25 -0
- siliconcompiler/report/__init__.py +13 -0
- siliconcompiler/report/html_report.py +74 -0
- siliconcompiler/report/report.py +355 -0
- siliconcompiler/report/streamlit_report.py +137 -0
- siliconcompiler/report/streamlit_viewer.py +944 -0
- siliconcompiler/report/summary_image.py +117 -0
- siliconcompiler/report/summary_table.py +105 -0
- siliconcompiler/report/utils.py +163 -0
- siliconcompiler/scheduler/__init__.py +2092 -0
- siliconcompiler/scheduler/docker_runner.py +253 -0
- siliconcompiler/scheduler/run_node.py +138 -0
- siliconcompiler/scheduler/send_messages.py +178 -0
- siliconcompiler/scheduler/slurm.py +208 -0
- siliconcompiler/scheduler/validation/email_credentials.json +54 -0
- siliconcompiler/schema/__init__.py +7 -0
- siliconcompiler/schema/schema_cfg.py +4014 -0
- siliconcompiler/schema/schema_obj.py +1841 -0
- siliconcompiler/schema/utils.py +93 -0
- siliconcompiler/sphinx_ext/__init__.py +0 -0
- siliconcompiler/sphinx_ext/dynamicgen.py +1006 -0
- siliconcompiler/sphinx_ext/schemagen.py +221 -0
- siliconcompiler/sphinx_ext/utils.py +166 -0
- siliconcompiler/targets/__init__.py +0 -0
- siliconcompiler/targets/asap7_demo.py +68 -0
- siliconcompiler/targets/asic_demo.py +38 -0
- siliconcompiler/targets/fpgaflow_demo.py +47 -0
- siliconcompiler/targets/freepdk45_demo.py +59 -0
- siliconcompiler/targets/gf180_demo.py +77 -0
- siliconcompiler/targets/skywater130_demo.py +70 -0
- siliconcompiler/templates/email/general.j2 +66 -0
- siliconcompiler/templates/email/summary.j2 +43 -0
- siliconcompiler/templates/issue/README.txt +26 -0
- siliconcompiler/templates/issue/run.sh +6 -0
- siliconcompiler/templates/report/bootstrap.min.css +7 -0
- siliconcompiler/templates/report/bootstrap.min.js +7 -0
- siliconcompiler/templates/report/bootstrap_LICENSE.md +24 -0
- siliconcompiler/templates/report/sc_report.j2 +427 -0
- siliconcompiler/templates/slurm/run.sh +9 -0
- siliconcompiler/templates/tcl/manifest.tcl.j2 +137 -0
- siliconcompiler/tools/__init__.py +0 -0
- siliconcompiler/tools/_common/__init__.py +432 -0
- siliconcompiler/tools/_common/asic.py +115 -0
- siliconcompiler/tools/_common/sdc/sc_constraints.sdc +76 -0
- siliconcompiler/tools/_common/tcl/sc_pin_constraints.tcl +63 -0
- siliconcompiler/tools/bambu/bambu.py +32 -0
- siliconcompiler/tools/bambu/convert.py +77 -0
- siliconcompiler/tools/bluespec/bluespec.py +40 -0
- siliconcompiler/tools/bluespec/convert.py +103 -0
- siliconcompiler/tools/builtin/_common.py +155 -0
- siliconcompiler/tools/builtin/builtin.py +26 -0
- siliconcompiler/tools/builtin/concatenate.py +85 -0
- siliconcompiler/tools/builtin/join.py +27 -0
- siliconcompiler/tools/builtin/maximum.py +46 -0
- siliconcompiler/tools/builtin/minimum.py +57 -0
- siliconcompiler/tools/builtin/mux.py +70 -0
- siliconcompiler/tools/builtin/nop.py +38 -0
- siliconcompiler/tools/builtin/verify.py +83 -0
- siliconcompiler/tools/chisel/SCDriver.scala +10 -0
- siliconcompiler/tools/chisel/build.sbt +27 -0
- siliconcompiler/tools/chisel/chisel.py +37 -0
- siliconcompiler/tools/chisel/convert.py +140 -0
- siliconcompiler/tools/execute/exec_input.py +41 -0
- siliconcompiler/tools/execute/execute.py +17 -0
- siliconcompiler/tools/genfasm/bitstream.py +61 -0
- siliconcompiler/tools/genfasm/genfasm.py +40 -0
- siliconcompiler/tools/ghdl/convert.py +87 -0
- siliconcompiler/tools/ghdl/ghdl.py +41 -0
- siliconcompiler/tools/icarus/compile.py +87 -0
- siliconcompiler/tools/icarus/icarus.py +36 -0
- siliconcompiler/tools/icepack/bitstream.py +20 -0
- siliconcompiler/tools/icepack/icepack.py +43 -0
- siliconcompiler/tools/klayout/export.py +117 -0
- siliconcompiler/tools/klayout/klayout.py +119 -0
- siliconcompiler/tools/klayout/klayout_export.py +205 -0
- siliconcompiler/tools/klayout/klayout_operations.py +363 -0
- siliconcompiler/tools/klayout/klayout_show.py +242 -0
- siliconcompiler/tools/klayout/klayout_utils.py +176 -0
- siliconcompiler/tools/klayout/operations.py +194 -0
- siliconcompiler/tools/klayout/screenshot.py +98 -0
- siliconcompiler/tools/klayout/show.py +101 -0
- siliconcompiler/tools/magic/drc.py +49 -0
- siliconcompiler/tools/magic/extspice.py +19 -0
- siliconcompiler/tools/magic/magic.py +85 -0
- siliconcompiler/tools/magic/sc_drc.tcl +96 -0
- siliconcompiler/tools/magic/sc_extspice.tcl +54 -0
- siliconcompiler/tools/magic/sc_magic.tcl +47 -0
- siliconcompiler/tools/montage/montage.py +30 -0
- siliconcompiler/tools/montage/tile.py +66 -0
- siliconcompiler/tools/netgen/count_lvs.py +132 -0
- siliconcompiler/tools/netgen/lvs.py +90 -0
- siliconcompiler/tools/netgen/netgen.py +36 -0
- siliconcompiler/tools/netgen/sc_lvs.tcl +46 -0
- siliconcompiler/tools/nextpnr/apr.py +24 -0
- siliconcompiler/tools/nextpnr/nextpnr.py +59 -0
- siliconcompiler/tools/openfpgaloader/openfpgaloader.py +39 -0
- siliconcompiler/tools/openroad/__init__.py +0 -0
- siliconcompiler/tools/openroad/cts.py +45 -0
- siliconcompiler/tools/openroad/dfm.py +66 -0
- siliconcompiler/tools/openroad/export.py +131 -0
- siliconcompiler/tools/openroad/floorplan.py +70 -0
- siliconcompiler/tools/openroad/openroad.py +977 -0
- siliconcompiler/tools/openroad/physyn.py +27 -0
- siliconcompiler/tools/openroad/place.py +41 -0
- siliconcompiler/tools/openroad/rcx_bench.py +95 -0
- siliconcompiler/tools/openroad/rcx_extract.py +34 -0
- siliconcompiler/tools/openroad/route.py +45 -0
- siliconcompiler/tools/openroad/screenshot.py +60 -0
- siliconcompiler/tools/openroad/scripts/sc_apr.tcl +499 -0
- siliconcompiler/tools/openroad/scripts/sc_cts.tcl +64 -0
- siliconcompiler/tools/openroad/scripts/sc_dfm.tcl +20 -0
- siliconcompiler/tools/openroad/scripts/sc_export.tcl +98 -0
- siliconcompiler/tools/openroad/scripts/sc_floorplan.tcl +413 -0
- siliconcompiler/tools/openroad/scripts/sc_metrics.tcl +158 -0
- siliconcompiler/tools/openroad/scripts/sc_physyn.tcl +7 -0
- siliconcompiler/tools/openroad/scripts/sc_place.tcl +84 -0
- siliconcompiler/tools/openroad/scripts/sc_procs.tcl +423 -0
- siliconcompiler/tools/openroad/scripts/sc_rcx.tcl +63 -0
- siliconcompiler/tools/openroad/scripts/sc_rcx_bench.tcl +20 -0
- siliconcompiler/tools/openroad/scripts/sc_rcx_extract.tcl +12 -0
- siliconcompiler/tools/openroad/scripts/sc_route.tcl +133 -0
- siliconcompiler/tools/openroad/scripts/sc_screenshot.tcl +21 -0
- siliconcompiler/tools/openroad/scripts/sc_write.tcl +5 -0
- siliconcompiler/tools/openroad/scripts/sc_write_images.tcl +361 -0
- siliconcompiler/tools/openroad/show.py +94 -0
- siliconcompiler/tools/openroad/templates/pex.tcl +8 -0
- siliconcompiler/tools/opensta/__init__.py +101 -0
- siliconcompiler/tools/opensta/report_libraries.py +28 -0
- siliconcompiler/tools/opensta/scripts/sc_procs.tcl +47 -0
- siliconcompiler/tools/opensta/scripts/sc_report_libraries.tcl +74 -0
- siliconcompiler/tools/opensta/scripts/sc_timing.tcl +268 -0
- siliconcompiler/tools/opensta/timing.py +214 -0
- siliconcompiler/tools/slang/__init__.py +49 -0
- siliconcompiler/tools/slang/lint.py +101 -0
- siliconcompiler/tools/surelog/__init__.py +123 -0
- siliconcompiler/tools/surelog/parse.py +183 -0
- siliconcompiler/tools/surelog/templates/output.v +7 -0
- siliconcompiler/tools/sv2v/convert.py +46 -0
- siliconcompiler/tools/sv2v/sv2v.py +37 -0
- siliconcompiler/tools/template/template.py +125 -0
- siliconcompiler/tools/verilator/compile.py +139 -0
- siliconcompiler/tools/verilator/lint.py +19 -0
- siliconcompiler/tools/verilator/parse.py +27 -0
- siliconcompiler/tools/verilator/verilator.py +172 -0
- siliconcompiler/tools/vivado/__init__.py +7 -0
- siliconcompiler/tools/vivado/bitstream.py +21 -0
- siliconcompiler/tools/vivado/place.py +21 -0
- siliconcompiler/tools/vivado/route.py +21 -0
- siliconcompiler/tools/vivado/scripts/sc_bitstream.tcl +6 -0
- siliconcompiler/tools/vivado/scripts/sc_place.tcl +2 -0
- siliconcompiler/tools/vivado/scripts/sc_route.tcl +4 -0
- siliconcompiler/tools/vivado/scripts/sc_run.tcl +45 -0
- siliconcompiler/tools/vivado/scripts/sc_syn_fpga.tcl +25 -0
- siliconcompiler/tools/vivado/syn_fpga.py +20 -0
- siliconcompiler/tools/vivado/vivado.py +147 -0
- siliconcompiler/tools/vpr/_json_constraint.py +63 -0
- siliconcompiler/tools/vpr/_xml_constraint.py +109 -0
- siliconcompiler/tools/vpr/place.py +137 -0
- siliconcompiler/tools/vpr/route.py +124 -0
- siliconcompiler/tools/vpr/screenshot.py +54 -0
- siliconcompiler/tools/vpr/show.py +88 -0
- siliconcompiler/tools/vpr/vpr.py +357 -0
- siliconcompiler/tools/xyce/xyce.py +36 -0
- siliconcompiler/tools/yosys/lec.py +56 -0
- siliconcompiler/tools/yosys/prepareLib.py +59 -0
- siliconcompiler/tools/yosys/sc_lec.tcl +84 -0
- siliconcompiler/tools/yosys/sc_syn.tcl +79 -0
- siliconcompiler/tools/yosys/syn_asic.py +565 -0
- siliconcompiler/tools/yosys/syn_asic.tcl +377 -0
- siliconcompiler/tools/yosys/syn_asic_fpga_shared.tcl +31 -0
- siliconcompiler/tools/yosys/syn_fpga.py +146 -0
- siliconcompiler/tools/yosys/syn_fpga.tcl +233 -0
- siliconcompiler/tools/yosys/syn_strategies.tcl +81 -0
- siliconcompiler/tools/yosys/techmaps/lcu_kogge_stone.v +39 -0
- siliconcompiler/tools/yosys/templates/abc.const +2 -0
- siliconcompiler/tools/yosys/yosys.py +147 -0
- siliconcompiler/units.py +259 -0
- siliconcompiler/use.py +177 -0
- siliconcompiler/utils/__init__.py +423 -0
- siliconcompiler/utils/asic.py +158 -0
- siliconcompiler/utils/showtools.py +25 -0
- siliconcompiler-0.26.5.dist-info/LICENSE +190 -0
- siliconcompiler-0.26.5.dist-info/METADATA +195 -0
- siliconcompiler-0.26.5.dist-info/RECORD +251 -0
- siliconcompiler-0.26.5.dist-info/WHEEL +5 -0
- siliconcompiler-0.26.5.dist-info/entry_points.txt +12 -0
- siliconcompiler-0.26.5.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
import contextlib
|
|
2
|
+
import os
|
|
3
|
+
import re
|
|
4
|
+
import psutil
|
|
5
|
+
import shutil
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from siliconcompiler._metadata import version as sc_version
|
|
8
|
+
from jinja2 import Environment, FileSystemLoader
|
|
9
|
+
|
|
10
|
+
import sys
|
|
11
|
+
if sys.version_info < (3, 10):
|
|
12
|
+
from importlib_metadata import entry_points
|
|
13
|
+
else:
|
|
14
|
+
from importlib.metadata import entry_points
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
PACKAGE_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
18
|
+
|
|
19
|
+
_siliconcompiler_data_path = 'git+https://github.com/siliconcompiler/siliconcompiler'
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def link_symlink_copy(srcfile, dstfile):
|
|
23
|
+
# first try hard linking, then symbolic linking,
|
|
24
|
+
# and finally just copy the file
|
|
25
|
+
for method in [os.link, os.symlink, shutil.copy2]:
|
|
26
|
+
try:
|
|
27
|
+
# create link
|
|
28
|
+
return method(srcfile, dstfile)
|
|
29
|
+
# success, no need to continue trying
|
|
30
|
+
except OSError:
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def link_copy(srcfile, dstfile):
|
|
35
|
+
# first try hard linking, then symbolic linking,
|
|
36
|
+
# and finally just copy the file
|
|
37
|
+
for method in [os.link, shutil.copy2]:
|
|
38
|
+
try:
|
|
39
|
+
# create link
|
|
40
|
+
return method(srcfile, dstfile)
|
|
41
|
+
# success, no need to continue trying
|
|
42
|
+
except OSError:
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def terminate_process(pid, timeout=3):
|
|
47
|
+
'''Terminates a process and all its (grand+)children.
|
|
48
|
+
|
|
49
|
+
Based on https://psutil.readthedocs.io/en/latest/#psutil.wait_procs and
|
|
50
|
+
https://psutil.readthedocs.io/en/latest/#kill-process-tree.
|
|
51
|
+
'''
|
|
52
|
+
assert pid != os.getpid(), "won't terminate myself"
|
|
53
|
+
parent = psutil.Process(pid)
|
|
54
|
+
children = parent.children(recursive=True)
|
|
55
|
+
children.append(parent)
|
|
56
|
+
for p in children:
|
|
57
|
+
try:
|
|
58
|
+
p.terminate()
|
|
59
|
+
except psutil.NoSuchProcess:
|
|
60
|
+
# Process may have terminated on its own in the meantime
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
_, alive = psutil.wait_procs(children, timeout=timeout)
|
|
64
|
+
for p in alive:
|
|
65
|
+
# If processes are still alive after timeout seconds, send more
|
|
66
|
+
# aggressive signal.
|
|
67
|
+
p.kill()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def get_file_ext(filename):
|
|
71
|
+
'''Get base file extension for a given path, disregarding .gz.'''
|
|
72
|
+
if filename.lower().endswith('.gz'):
|
|
73
|
+
filename = os.path.splitext(filename)[0]
|
|
74
|
+
filetype = os.path.splitext(filename)[1].lower().lstrip('.')
|
|
75
|
+
return filetype
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def get_default_iomap():
|
|
79
|
+
"""
|
|
80
|
+
Default input file map for SC with filesets and extensions
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
# Record extensions:
|
|
84
|
+
|
|
85
|
+
# High level languages
|
|
86
|
+
hll_c = ('c', 'cc', 'cpp', 'c++', 'cp', 'cxx', 'hpp')
|
|
87
|
+
hll_bsv = ('bsv',)
|
|
88
|
+
hll_scala = ('scala',)
|
|
89
|
+
hll_python = ('py',)
|
|
90
|
+
|
|
91
|
+
config_chisel = ('sbt',)
|
|
92
|
+
|
|
93
|
+
# Register transfer languages
|
|
94
|
+
rtl_verilog = ('v', 'verilog')
|
|
95
|
+
rtl_systemverilog = ('sv',)
|
|
96
|
+
rtl_vhdl = ('vhd', 'vhdl')
|
|
97
|
+
|
|
98
|
+
# Timing libraries
|
|
99
|
+
timing_liberty = ('lib', 'ccs')
|
|
100
|
+
|
|
101
|
+
# Layout
|
|
102
|
+
layout_def = ('def',)
|
|
103
|
+
layout_lef = ('lef',)
|
|
104
|
+
layout_gds = ('gds', 'gds2', 'gdsii')
|
|
105
|
+
layout_oas = ('oas', 'oasis')
|
|
106
|
+
layout_gerber = ('gbr', 'gerber')
|
|
107
|
+
layout_odb = ('odb',)
|
|
108
|
+
|
|
109
|
+
# Netlist
|
|
110
|
+
netlist_cdl = ('cdl',)
|
|
111
|
+
netlist_sp = ('sp', 'spice')
|
|
112
|
+
netlist_verilog = ('vg',)
|
|
113
|
+
|
|
114
|
+
# Waveform
|
|
115
|
+
waveform_vcd = ('vcd',)
|
|
116
|
+
|
|
117
|
+
# Constraint
|
|
118
|
+
constraint_sdc = ('sdc', )
|
|
119
|
+
constraint_upf = ('upf', )
|
|
120
|
+
|
|
121
|
+
# FPGA constraints
|
|
122
|
+
fpga_xdc = ('xdc',)
|
|
123
|
+
constraint_pcf = ('pcf',)
|
|
124
|
+
fpga_vpr_place = ('place',)
|
|
125
|
+
fpga_vpr_route = ('route',)
|
|
126
|
+
|
|
127
|
+
# Build default map with fileset and type
|
|
128
|
+
default_iomap = {}
|
|
129
|
+
default_iomap.update({ext: ('hll', 'c') for ext in hll_c})
|
|
130
|
+
default_iomap.update({ext: ('hll', 'bsv') for ext in hll_bsv})
|
|
131
|
+
default_iomap.update({ext: ('hll', 'scala') for ext in hll_scala})
|
|
132
|
+
default_iomap.update({ext: ('hll', 'python') for ext in hll_python})
|
|
133
|
+
default_iomap.update({ext: ('config', 'chisel') for ext in config_chisel})
|
|
134
|
+
|
|
135
|
+
default_iomap.update({ext: ('rtl', 'verilog') for ext in rtl_verilog})
|
|
136
|
+
default_iomap.update({ext: ('rtl', 'systemverilog') for ext in rtl_systemverilog})
|
|
137
|
+
default_iomap.update({ext: ('rtl', 'vhdl') for ext in rtl_vhdl})
|
|
138
|
+
|
|
139
|
+
default_iomap.update({ext: ('timing', 'liberty') for ext in timing_liberty})
|
|
140
|
+
|
|
141
|
+
default_iomap.update({ext: ('layout', 'def') for ext in layout_def})
|
|
142
|
+
default_iomap.update({ext: ('layout', 'lef') for ext in layout_lef})
|
|
143
|
+
default_iomap.update({ext: ('layout', 'gds') for ext in layout_gds})
|
|
144
|
+
default_iomap.update({ext: ('layout', 'oas') for ext in layout_oas})
|
|
145
|
+
default_iomap.update({ext: ('layout', 'gerber') for ext in layout_gerber})
|
|
146
|
+
default_iomap.update({ext: ('layout', 'odb') for ext in layout_odb})
|
|
147
|
+
|
|
148
|
+
default_iomap.update({ext: ('netlist', 'cdl') for ext in netlist_cdl})
|
|
149
|
+
default_iomap.update({ext: ('netlist', 'sp') for ext in netlist_sp})
|
|
150
|
+
default_iomap.update({ext: ('netlist', 'verilog') for ext in netlist_verilog})
|
|
151
|
+
|
|
152
|
+
default_iomap.update({ext: ('waveform', 'vcd') for ext in waveform_vcd})
|
|
153
|
+
|
|
154
|
+
default_iomap.update({ext: ('constraint', 'sdc') for ext in constraint_sdc})
|
|
155
|
+
default_iomap.update({ext: ('constraint', 'upf') for ext in constraint_upf})
|
|
156
|
+
default_iomap.update({ext: ('constraint', 'pcf') for ext in constraint_pcf})
|
|
157
|
+
|
|
158
|
+
default_iomap.update({ext: ('fpga', 'xdc') for ext in fpga_xdc})
|
|
159
|
+
default_iomap.update({ext: ('fpga', 'vpr_place') for ext in fpga_vpr_place})
|
|
160
|
+
default_iomap.update({ext: ('fpga', 'vpr_route') for ext in fpga_vpr_route})
|
|
161
|
+
|
|
162
|
+
return default_iomap
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def format_fileset_type_table(indent=12):
|
|
166
|
+
'''
|
|
167
|
+
Generate a table to use in the __doc__ of the input function which auto
|
|
168
|
+
updates based on the iomap
|
|
169
|
+
'''
|
|
170
|
+
table = "filetype | fileset | suffix (case insensitive)\n"
|
|
171
|
+
indent = " " * indent
|
|
172
|
+
table += f"{indent}--------------|------------|---------------------------------------------\n"
|
|
173
|
+
|
|
174
|
+
iobytype = {}
|
|
175
|
+
for ext, settype in get_default_iomap().items():
|
|
176
|
+
fileset, filetype = settype
|
|
177
|
+
iobytype.setdefault((fileset, filetype), []).append(ext)
|
|
178
|
+
|
|
179
|
+
for settype, exts in iobytype.items():
|
|
180
|
+
fileset, filetype = settype
|
|
181
|
+
ext = ",".join(exts)
|
|
182
|
+
table += f"{indent}{filetype:<14}| {fileset:<11}| {ext}\n"
|
|
183
|
+
|
|
184
|
+
return table
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def default_credentials_file():
|
|
188
|
+
cfg_file = os.path.join(Path.home(), '.sc', 'credentials')
|
|
189
|
+
|
|
190
|
+
return cfg_file
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def default_cache_dir():
|
|
194
|
+
cfg_file = os.path.join(Path.home(), '.sc', 'cache')
|
|
195
|
+
|
|
196
|
+
return cfg_file
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def default_email_credentials_file():
|
|
200
|
+
cfg_file = os.path.join(Path.home(), '.sc', 'email.json')
|
|
201
|
+
|
|
202
|
+
return cfg_file
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def register_sc_data_source(chip):
|
|
206
|
+
chip.register_source('siliconcompiler_data',
|
|
207
|
+
_siliconcompiler_data_path,
|
|
208
|
+
'v'+sc_version)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
@contextlib.contextmanager
|
|
212
|
+
def sc_open(path, *args, **kwargs):
|
|
213
|
+
kwargs['errors'] = 'ignore_with_warning'
|
|
214
|
+
fobj = open(path, *args, **kwargs)
|
|
215
|
+
try:
|
|
216
|
+
with contextlib.closing(fobj):
|
|
217
|
+
yield fobj
|
|
218
|
+
finally:
|
|
219
|
+
pass
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def get_file_template(path, root=os.path.join(PACKAGE_ROOT, 'templates')):
|
|
223
|
+
if os.path.isabs(path):
|
|
224
|
+
root = os.path.dirname(path)
|
|
225
|
+
path = os.path.basename(path)
|
|
226
|
+
|
|
227
|
+
env = Environment(loader=FileSystemLoader(root))
|
|
228
|
+
return env.get_template(path)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
#######################################
|
|
232
|
+
def safecompare(chip, value, op, goal):
|
|
233
|
+
# supported relational operations
|
|
234
|
+
# >, >=, <=, <. ==, !=
|
|
235
|
+
if op == ">":
|
|
236
|
+
return bool(value > goal)
|
|
237
|
+
elif op == ">=":
|
|
238
|
+
return bool(value >= goal)
|
|
239
|
+
elif op == "<":
|
|
240
|
+
return bool(value < goal)
|
|
241
|
+
elif op == "<=":
|
|
242
|
+
return bool(value <= goal)
|
|
243
|
+
elif op == "==":
|
|
244
|
+
return bool(value == goal)
|
|
245
|
+
elif op == "!=":
|
|
246
|
+
return bool(value != goal)
|
|
247
|
+
else:
|
|
248
|
+
chip.error(f"Illegal comparison operation {op}")
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
###########################################################################
|
|
252
|
+
def grep(chip, args, line):
|
|
253
|
+
"""
|
|
254
|
+
Emulates the Unix grep command on a string.
|
|
255
|
+
|
|
256
|
+
Emulates the behavior of the Unix grep command that is etched into
|
|
257
|
+
our muscle memory. Partially implemented, not all features supported.
|
|
258
|
+
The function returns None if no match is found.
|
|
259
|
+
|
|
260
|
+
Args:
|
|
261
|
+
arg (string): Command line arguments for grep command
|
|
262
|
+
line (string): Line to process
|
|
263
|
+
|
|
264
|
+
Returns:
|
|
265
|
+
Result of grep command (string).
|
|
266
|
+
|
|
267
|
+
"""
|
|
268
|
+
|
|
269
|
+
# Quick return if input is None
|
|
270
|
+
if line is None:
|
|
271
|
+
return None
|
|
272
|
+
|
|
273
|
+
# Partial list of supported grep options
|
|
274
|
+
options = {
|
|
275
|
+
'-v': False, # Invert the sense of matching
|
|
276
|
+
'-i': False, # Ignore case distinctions in patterns and data
|
|
277
|
+
'-E': False, # Interpret PATTERNS as extended regular expressions.
|
|
278
|
+
'-e': False, # Safe interpretation of pattern starting with "-"
|
|
279
|
+
'-x': False, # Select only matches that exactly match the whole line.
|
|
280
|
+
'-o': False, # Print only the match parts of a matching line
|
|
281
|
+
'-w': False} # Select only lines containing matches that form whole words.
|
|
282
|
+
|
|
283
|
+
# Split into repeating switches and everything else
|
|
284
|
+
match = re.match(r'\s*((?:\-\w\s)*)(.*)', args)
|
|
285
|
+
|
|
286
|
+
pattern = match.group(2)
|
|
287
|
+
|
|
288
|
+
# Split space separated switch string into list
|
|
289
|
+
switches = match.group(1).strip().split(' ')
|
|
290
|
+
|
|
291
|
+
# Find special -e switch update the pattern
|
|
292
|
+
for i in range(len(switches)):
|
|
293
|
+
if switches[i] == "-e":
|
|
294
|
+
if i != (len(switches)):
|
|
295
|
+
pattern = ' '.join(switches[i + 1:]) + " " + pattern
|
|
296
|
+
switches = switches[0:i + 1]
|
|
297
|
+
break
|
|
298
|
+
options["-e"] = True
|
|
299
|
+
elif switches[i] in options.keys():
|
|
300
|
+
options[switches[i]] = True
|
|
301
|
+
elif switches[i] != '':
|
|
302
|
+
chip.logger.error(switches[i])
|
|
303
|
+
|
|
304
|
+
# REGEX
|
|
305
|
+
# TODO: add all the other optinos
|
|
306
|
+
match = re.search(rf"({pattern})", line)
|
|
307
|
+
if bool(match) == bool(options["-v"]):
|
|
308
|
+
return None
|
|
309
|
+
else:
|
|
310
|
+
return line
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
#######################################
|
|
314
|
+
def _resolve_env_vars(chip, filepath):
|
|
315
|
+
if not filepath:
|
|
316
|
+
return None
|
|
317
|
+
|
|
318
|
+
env_save = os.environ.copy()
|
|
319
|
+
for env in chip.getkeys('option', 'env'):
|
|
320
|
+
os.environ[env] = chip.get('option', 'env', env)
|
|
321
|
+
resolved_path = os.path.expandvars(filepath)
|
|
322
|
+
os.environ.clear()
|
|
323
|
+
os.environ.update(env_save)
|
|
324
|
+
|
|
325
|
+
# variables that don't exist in environment get ignored by `expandvars`,
|
|
326
|
+
# but we can do our own error checking to ensure this doesn't result in
|
|
327
|
+
# silent bugs
|
|
328
|
+
envvars = re.findall(r'\$(\w+)', resolved_path)
|
|
329
|
+
for var in envvars:
|
|
330
|
+
chip.logger.warning(f'Variable {var} in {filepath} not defined in environment')
|
|
331
|
+
|
|
332
|
+
return resolved_path
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
###########################################################################
|
|
336
|
+
def find_sc_file(chip, filename, missing_ok=False, search_paths=None):
|
|
337
|
+
"""
|
|
338
|
+
Returns the absolute path for the filename provided.
|
|
339
|
+
|
|
340
|
+
Searches the for the filename provided and returns the absolute path.
|
|
341
|
+
If no valid absolute path is found during the search, None is returned.
|
|
342
|
+
|
|
343
|
+
Shell variables ('$' followed by strings consisting of numbers,
|
|
344
|
+
underscores, and digits) are replaced with the variable value.
|
|
345
|
+
|
|
346
|
+
Args:
|
|
347
|
+
filename (str): Relative or absolute filename.
|
|
348
|
+
missing_ok (bool): If False, error out if no valid absolute path
|
|
349
|
+
found, rather than returning None.
|
|
350
|
+
search_paths (list): List of directories to search under instead of
|
|
351
|
+
the defaults.
|
|
352
|
+
|
|
353
|
+
Returns:
|
|
354
|
+
Returns absolute path of 'filename' if found, otherwise returns
|
|
355
|
+
None.
|
|
356
|
+
|
|
357
|
+
Examples:
|
|
358
|
+
>>> chip._find_sc_file('flows/asicflow.py')
|
|
359
|
+
Returns the absolute path based on the sc installation directory.
|
|
360
|
+
|
|
361
|
+
"""
|
|
362
|
+
|
|
363
|
+
if not filename:
|
|
364
|
+
return None
|
|
365
|
+
|
|
366
|
+
# Replacing environment variables
|
|
367
|
+
filename = _resolve_env_vars(chip, filename)
|
|
368
|
+
|
|
369
|
+
# If we have an absolute path, pass-through here
|
|
370
|
+
if os.path.isabs(filename) and os.path.exists(filename):
|
|
371
|
+
return filename
|
|
372
|
+
|
|
373
|
+
# Otherwise, search relative to search_paths
|
|
374
|
+
if search_paths is None:
|
|
375
|
+
search_paths = [chip.cwd]
|
|
376
|
+
|
|
377
|
+
searchdirs = ', '.join([str(p) for p in search_paths])
|
|
378
|
+
chip.logger.debug(f"Searching for file {filename} in {searchdirs}")
|
|
379
|
+
|
|
380
|
+
result = None
|
|
381
|
+
for searchdir in search_paths:
|
|
382
|
+
if not os.path.isabs(searchdir):
|
|
383
|
+
searchdir = os.path.join(chip.cwd, searchdir)
|
|
384
|
+
|
|
385
|
+
abspath = os.path.abspath(os.path.join(searchdir, filename))
|
|
386
|
+
if os.path.exists(abspath):
|
|
387
|
+
result = abspath
|
|
388
|
+
break
|
|
389
|
+
|
|
390
|
+
if result is None and not missing_ok:
|
|
391
|
+
chip.error(f"File {filename} was not found")
|
|
392
|
+
|
|
393
|
+
return result
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
def get_plugins(system):
|
|
397
|
+
'''
|
|
398
|
+
Search for python modules with a specific function
|
|
399
|
+
'''
|
|
400
|
+
|
|
401
|
+
plugins = []
|
|
402
|
+
discovered_plugins = entry_points(group=f'siliconcompiler.{system}')
|
|
403
|
+
for plugin in discovered_plugins:
|
|
404
|
+
plugins.append(plugin.load())
|
|
405
|
+
|
|
406
|
+
return plugins
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
def truncate_text(text, width):
|
|
410
|
+
if len(text) <= width:
|
|
411
|
+
return text
|
|
412
|
+
|
|
413
|
+
keep_end = 0
|
|
414
|
+
while text[-1 - keep_end].isnumeric():
|
|
415
|
+
if keep_end >= 2:
|
|
416
|
+
break
|
|
417
|
+
keep_end += 1
|
|
418
|
+
|
|
419
|
+
while len(text) > width:
|
|
420
|
+
break_at = len(text) - keep_end - 3
|
|
421
|
+
text = text[:break_at-1] + '...' + text[break_at+3:]
|
|
422
|
+
|
|
423
|
+
return text
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import math
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
###########################################################################
|
|
5
|
+
def calc_area(chip, step=None, index=None):
|
|
6
|
+
'''Calculates the area of a rectilinear diearea.
|
|
7
|
+
|
|
8
|
+
Uses the shoelace formulate to calculate the design area using
|
|
9
|
+
the (x,y) point tuples from the 'diearea' parameter. If only diearea
|
|
10
|
+
parameter only contains two points, then the first and second point
|
|
11
|
+
must be the lower left and upper right points of the rectangle.
|
|
12
|
+
(Ref: https://en.wikipedia.org/wiki/Shoelace_formula)
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
step (str): name of the step to calculate the area from
|
|
16
|
+
index (str): name of the step to calculate the area from
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
Design area (float).
|
|
20
|
+
|
|
21
|
+
Examples:
|
|
22
|
+
>>> area = chip.calc_area()
|
|
23
|
+
|
|
24
|
+
'''
|
|
25
|
+
|
|
26
|
+
if not step:
|
|
27
|
+
step = chip.get('arg', 'step')
|
|
28
|
+
|
|
29
|
+
if not index:
|
|
30
|
+
index = chip.get('arg', 'index')
|
|
31
|
+
|
|
32
|
+
vertices = chip.get('constraint', 'outline', step=step, index=index)
|
|
33
|
+
|
|
34
|
+
if len(vertices) == 2:
|
|
35
|
+
width = vertices[1][0] - vertices[0][0]
|
|
36
|
+
height = vertices[1][1] - vertices[0][1]
|
|
37
|
+
area = width * height
|
|
38
|
+
else:
|
|
39
|
+
area = 0.0
|
|
40
|
+
for i in range(len(vertices)):
|
|
41
|
+
j = (i + 1) % len(vertices)
|
|
42
|
+
area += vertices[i][0] * vertices[j][1]
|
|
43
|
+
area -= vertices[j][0] * vertices[i][1]
|
|
44
|
+
area = abs(area) / 2
|
|
45
|
+
|
|
46
|
+
return area
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
###########################################################################
|
|
50
|
+
def calc_yield(chip, step=None, index=None, model='poisson'):
|
|
51
|
+
'''Calculates raw die yield.
|
|
52
|
+
|
|
53
|
+
Calculates the raw yield of the design as a function of design area
|
|
54
|
+
and d0 defect density. Calculation can be done based on the poisson
|
|
55
|
+
model (default) or the murphy model. The die area and the d0
|
|
56
|
+
parameters are taken from the chip dictionary.
|
|
57
|
+
|
|
58
|
+
* Poisson model: dy = exp(-area * d0/100).
|
|
59
|
+
* Murphy model: dy = ((1-exp(-area * d0/100))/(area * d0/100))^2.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
step (str): name of the step use for calculation
|
|
63
|
+
index (str): name of the step use for calculation
|
|
64
|
+
model (string): Model to use for calculation (poisson or murphy)
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
Design yield percentage (float).
|
|
68
|
+
|
|
69
|
+
Examples:
|
|
70
|
+
>>> yield = chip.calc_yield()
|
|
71
|
+
Yield variable gets yield value based on the chip manifest.
|
|
72
|
+
'''
|
|
73
|
+
|
|
74
|
+
pdk = chip.get('option', 'pdk')
|
|
75
|
+
d0 = chip.get('pdk', pdk, 'd0')
|
|
76
|
+
if d0 is None:
|
|
77
|
+
chip.error(f"['pdk', {pdk}, 'd0'] has not been set")
|
|
78
|
+
diearea = calc_area(chip, step=step, index=index)
|
|
79
|
+
|
|
80
|
+
# diearea is um^2, but d0 looking for cm^2
|
|
81
|
+
diearea = diearea / 10000.0**2
|
|
82
|
+
|
|
83
|
+
if model == 'poisson':
|
|
84
|
+
dy = math.exp(-diearea * d0 / 100)
|
|
85
|
+
elif model == 'murphy':
|
|
86
|
+
dy = ((1 - math.exp(-diearea * d0 / 100)) / (diearea * d0 / 100))**2
|
|
87
|
+
else:
|
|
88
|
+
chip.error(f'Unknown yield model: {model}')
|
|
89
|
+
|
|
90
|
+
return dy
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
##########################################################################
|
|
94
|
+
def calc_dpw(chip, step=None, index=None):
|
|
95
|
+
'''Calculates dies per wafer.
|
|
96
|
+
|
|
97
|
+
Calculates the gross dies per wafer based on the design area, wafersize,
|
|
98
|
+
wafer edge margin, and scribe lines. The calculation is done by starting
|
|
99
|
+
at the center of the wafer and placing as many complete design
|
|
100
|
+
footprints as possible within a legal placement area.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
step (str): name of the step use for calculation
|
|
104
|
+
index (str): name of the step use for calculation
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
Number of gross dies per wafer (int).
|
|
108
|
+
|
|
109
|
+
Examples:
|
|
110
|
+
>>> dpw = chip.calc_dpw()
|
|
111
|
+
Variable dpw gets gross dies per wafer value based on the chip manifest.
|
|
112
|
+
'''
|
|
113
|
+
|
|
114
|
+
# PDK information
|
|
115
|
+
pdk = chip.get('option', 'pdk')
|
|
116
|
+
wafersize = chip.get('pdk', pdk, 'wafersize')
|
|
117
|
+
edgemargin = chip.get('pdk', pdk, 'edgemargin')
|
|
118
|
+
hscribe, vscribe = chip.get('pdk', pdk, 'scribe')
|
|
119
|
+
|
|
120
|
+
# Design parameters
|
|
121
|
+
diesize = chip.get('constraint', 'outline', step=step, index=index)
|
|
122
|
+
|
|
123
|
+
# Convert to mm
|
|
124
|
+
diewidth = (diesize[1][0] - diesize[0][0]) / 1000.0
|
|
125
|
+
dieheight = (diesize[1][1] - diesize[0][1]) / 1000.0
|
|
126
|
+
|
|
127
|
+
# Derived parameters
|
|
128
|
+
radius = wafersize / 2 - edgemargin
|
|
129
|
+
stepwidth = diewidth + hscribe
|
|
130
|
+
stepheight = dieheight + vscribe
|
|
131
|
+
|
|
132
|
+
# Raster dies out from center until you touch edge margin
|
|
133
|
+
# Work quadrant by quadrant
|
|
134
|
+
dies = 0
|
|
135
|
+
for quad in ('q1', 'q2', 'q3', 'q4'):
|
|
136
|
+
x = 0
|
|
137
|
+
y = 0
|
|
138
|
+
if quad == "q1":
|
|
139
|
+
xincr = stepwidth
|
|
140
|
+
yincr = stepheight
|
|
141
|
+
elif quad == "q2":
|
|
142
|
+
xincr = -stepwidth
|
|
143
|
+
yincr = stepheight
|
|
144
|
+
elif quad == "q3":
|
|
145
|
+
xincr = -stepwidth
|
|
146
|
+
yincr = -stepheight
|
|
147
|
+
elif quad == "q4":
|
|
148
|
+
xincr = stepwidth
|
|
149
|
+
yincr = -stepheight
|
|
150
|
+
# loop through all y values from center
|
|
151
|
+
while math.hypot(0, y) < radius:
|
|
152
|
+
y = y + yincr
|
|
153
|
+
x = xincr
|
|
154
|
+
while math.hypot(x, y) < radius:
|
|
155
|
+
x = x + xincr
|
|
156
|
+
dies = dies + 1
|
|
157
|
+
|
|
158
|
+
return dies
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from siliconcompiler.tools.klayout import show as klayout_show
|
|
2
|
+
from siliconcompiler.tools.klayout import screenshot as klayout_screenshot
|
|
3
|
+
from siliconcompiler.tools.openroad import show as openroad_show
|
|
4
|
+
from siliconcompiler.tools.openroad import screenshot as openroad_screenshot
|
|
5
|
+
from siliconcompiler.tools.vpr import show as vpr_show
|
|
6
|
+
from siliconcompiler.tools.vpr import screenshot as vpr_screenshot
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def setup(chip):
|
|
10
|
+
chip.register_showtool('gds', klayout_show)
|
|
11
|
+
chip.register_showtool('gds', klayout_screenshot)
|
|
12
|
+
chip.register_showtool('oas', klayout_show)
|
|
13
|
+
chip.register_showtool('oas', klayout_screenshot)
|
|
14
|
+
chip.register_showtool('lef', klayout_show)
|
|
15
|
+
chip.register_showtool('lef', klayout_screenshot)
|
|
16
|
+
|
|
17
|
+
chip.register_showtool('odb', openroad_show)
|
|
18
|
+
chip.register_showtool('odb', openroad_screenshot)
|
|
19
|
+
chip.register_showtool('def', openroad_show)
|
|
20
|
+
chip.register_showtool('def', openroad_screenshot)
|
|
21
|
+
|
|
22
|
+
chip.register_showtool('route', vpr_show)
|
|
23
|
+
chip.register_showtool('route', vpr_screenshot)
|
|
24
|
+
chip.register_showtool('place', vpr_show)
|
|
25
|
+
chip.register_showtool('place', vpr_screenshot)
|