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.
Files changed (251) hide show
  1. siliconcompiler/__init__.py +24 -0
  2. siliconcompiler/__main__.py +12 -0
  3. siliconcompiler/_common.py +49 -0
  4. siliconcompiler/_metadata.py +36 -0
  5. siliconcompiler/apps/__init__.py +0 -0
  6. siliconcompiler/apps/_common.py +76 -0
  7. siliconcompiler/apps/sc.py +92 -0
  8. siliconcompiler/apps/sc_dashboard.py +94 -0
  9. siliconcompiler/apps/sc_issue.py +178 -0
  10. siliconcompiler/apps/sc_remote.py +199 -0
  11. siliconcompiler/apps/sc_server.py +39 -0
  12. siliconcompiler/apps/sc_show.py +142 -0
  13. siliconcompiler/apps/smake.py +232 -0
  14. siliconcompiler/checklists/__init__.py +0 -0
  15. siliconcompiler/checklists/oh_tapeout.py +41 -0
  16. siliconcompiler/core.py +3221 -0
  17. siliconcompiler/data/RobotoMono/LICENSE.txt +202 -0
  18. siliconcompiler/data/RobotoMono/RobotoMono-Regular.ttf +0 -0
  19. siliconcompiler/data/heartbeat.v +18 -0
  20. siliconcompiler/data/logo.png +0 -0
  21. siliconcompiler/flowgraph.py +570 -0
  22. siliconcompiler/flows/__init__.py +0 -0
  23. siliconcompiler/flows/_common.py +67 -0
  24. siliconcompiler/flows/asicflow.py +180 -0
  25. siliconcompiler/flows/asictopflow.py +38 -0
  26. siliconcompiler/flows/dvflow.py +86 -0
  27. siliconcompiler/flows/fpgaflow.py +202 -0
  28. siliconcompiler/flows/generate_openroad_rcx.py +66 -0
  29. siliconcompiler/flows/lintflow.py +35 -0
  30. siliconcompiler/flows/screenshotflow.py +51 -0
  31. siliconcompiler/flows/showflow.py +59 -0
  32. siliconcompiler/flows/signoffflow.py +53 -0
  33. siliconcompiler/flows/synflow.py +128 -0
  34. siliconcompiler/fpgas/__init__.py +0 -0
  35. siliconcompiler/fpgas/lattice_ice40.py +42 -0
  36. siliconcompiler/fpgas/vpr_example.py +109 -0
  37. siliconcompiler/issue.py +300 -0
  38. siliconcompiler/libs/__init__.py +0 -0
  39. siliconcompiler/libs/asap7sc7p5t.py +8 -0
  40. siliconcompiler/libs/gf180mcu.py +8 -0
  41. siliconcompiler/libs/nangate45.py +8 -0
  42. siliconcompiler/libs/sky130hd.py +8 -0
  43. siliconcompiler/libs/sky130io.py +8 -0
  44. siliconcompiler/package.py +412 -0
  45. siliconcompiler/pdks/__init__.py +0 -0
  46. siliconcompiler/pdks/asap7.py +8 -0
  47. siliconcompiler/pdks/freepdk45.py +8 -0
  48. siliconcompiler/pdks/gf180.py +8 -0
  49. siliconcompiler/pdks/skywater130.py +8 -0
  50. siliconcompiler/remote/__init__.py +36 -0
  51. siliconcompiler/remote/client.py +891 -0
  52. siliconcompiler/remote/schema.py +106 -0
  53. siliconcompiler/remote/server.py +507 -0
  54. siliconcompiler/remote/server_schema/requests/cancel_job.json +51 -0
  55. siliconcompiler/remote/server_schema/requests/check_progress.json +61 -0
  56. siliconcompiler/remote/server_schema/requests/check_server.json +38 -0
  57. siliconcompiler/remote/server_schema/requests/delete_job.json +51 -0
  58. siliconcompiler/remote/server_schema/requests/get_results.json +48 -0
  59. siliconcompiler/remote/server_schema/requests/remote_run.json +40 -0
  60. siliconcompiler/remote/server_schema/responses/cancel_job.json +18 -0
  61. siliconcompiler/remote/server_schema/responses/check_progress.json +30 -0
  62. siliconcompiler/remote/server_schema/responses/check_server.json +32 -0
  63. siliconcompiler/remote/server_schema/responses/delete_job.json +18 -0
  64. siliconcompiler/remote/server_schema/responses/get_results.json +21 -0
  65. siliconcompiler/remote/server_schema/responses/remote_run.json +25 -0
  66. siliconcompiler/report/__init__.py +13 -0
  67. siliconcompiler/report/html_report.py +74 -0
  68. siliconcompiler/report/report.py +355 -0
  69. siliconcompiler/report/streamlit_report.py +137 -0
  70. siliconcompiler/report/streamlit_viewer.py +944 -0
  71. siliconcompiler/report/summary_image.py +117 -0
  72. siliconcompiler/report/summary_table.py +105 -0
  73. siliconcompiler/report/utils.py +163 -0
  74. siliconcompiler/scheduler/__init__.py +2092 -0
  75. siliconcompiler/scheduler/docker_runner.py +253 -0
  76. siliconcompiler/scheduler/run_node.py +138 -0
  77. siliconcompiler/scheduler/send_messages.py +178 -0
  78. siliconcompiler/scheduler/slurm.py +208 -0
  79. siliconcompiler/scheduler/validation/email_credentials.json +54 -0
  80. siliconcompiler/schema/__init__.py +7 -0
  81. siliconcompiler/schema/schema_cfg.py +4014 -0
  82. siliconcompiler/schema/schema_obj.py +1841 -0
  83. siliconcompiler/schema/utils.py +93 -0
  84. siliconcompiler/sphinx_ext/__init__.py +0 -0
  85. siliconcompiler/sphinx_ext/dynamicgen.py +1006 -0
  86. siliconcompiler/sphinx_ext/schemagen.py +221 -0
  87. siliconcompiler/sphinx_ext/utils.py +166 -0
  88. siliconcompiler/targets/__init__.py +0 -0
  89. siliconcompiler/targets/asap7_demo.py +68 -0
  90. siliconcompiler/targets/asic_demo.py +38 -0
  91. siliconcompiler/targets/fpgaflow_demo.py +47 -0
  92. siliconcompiler/targets/freepdk45_demo.py +59 -0
  93. siliconcompiler/targets/gf180_demo.py +77 -0
  94. siliconcompiler/targets/skywater130_demo.py +70 -0
  95. siliconcompiler/templates/email/general.j2 +66 -0
  96. siliconcompiler/templates/email/summary.j2 +43 -0
  97. siliconcompiler/templates/issue/README.txt +26 -0
  98. siliconcompiler/templates/issue/run.sh +6 -0
  99. siliconcompiler/templates/report/bootstrap.min.css +7 -0
  100. siliconcompiler/templates/report/bootstrap.min.js +7 -0
  101. siliconcompiler/templates/report/bootstrap_LICENSE.md +24 -0
  102. siliconcompiler/templates/report/sc_report.j2 +427 -0
  103. siliconcompiler/templates/slurm/run.sh +9 -0
  104. siliconcompiler/templates/tcl/manifest.tcl.j2 +137 -0
  105. siliconcompiler/tools/__init__.py +0 -0
  106. siliconcompiler/tools/_common/__init__.py +432 -0
  107. siliconcompiler/tools/_common/asic.py +115 -0
  108. siliconcompiler/tools/_common/sdc/sc_constraints.sdc +76 -0
  109. siliconcompiler/tools/_common/tcl/sc_pin_constraints.tcl +63 -0
  110. siliconcompiler/tools/bambu/bambu.py +32 -0
  111. siliconcompiler/tools/bambu/convert.py +77 -0
  112. siliconcompiler/tools/bluespec/bluespec.py +40 -0
  113. siliconcompiler/tools/bluespec/convert.py +103 -0
  114. siliconcompiler/tools/builtin/_common.py +155 -0
  115. siliconcompiler/tools/builtin/builtin.py +26 -0
  116. siliconcompiler/tools/builtin/concatenate.py +85 -0
  117. siliconcompiler/tools/builtin/join.py +27 -0
  118. siliconcompiler/tools/builtin/maximum.py +46 -0
  119. siliconcompiler/tools/builtin/minimum.py +57 -0
  120. siliconcompiler/tools/builtin/mux.py +70 -0
  121. siliconcompiler/tools/builtin/nop.py +38 -0
  122. siliconcompiler/tools/builtin/verify.py +83 -0
  123. siliconcompiler/tools/chisel/SCDriver.scala +10 -0
  124. siliconcompiler/tools/chisel/build.sbt +27 -0
  125. siliconcompiler/tools/chisel/chisel.py +37 -0
  126. siliconcompiler/tools/chisel/convert.py +140 -0
  127. siliconcompiler/tools/execute/exec_input.py +41 -0
  128. siliconcompiler/tools/execute/execute.py +17 -0
  129. siliconcompiler/tools/genfasm/bitstream.py +61 -0
  130. siliconcompiler/tools/genfasm/genfasm.py +40 -0
  131. siliconcompiler/tools/ghdl/convert.py +87 -0
  132. siliconcompiler/tools/ghdl/ghdl.py +41 -0
  133. siliconcompiler/tools/icarus/compile.py +87 -0
  134. siliconcompiler/tools/icarus/icarus.py +36 -0
  135. siliconcompiler/tools/icepack/bitstream.py +20 -0
  136. siliconcompiler/tools/icepack/icepack.py +43 -0
  137. siliconcompiler/tools/klayout/export.py +117 -0
  138. siliconcompiler/tools/klayout/klayout.py +119 -0
  139. siliconcompiler/tools/klayout/klayout_export.py +205 -0
  140. siliconcompiler/tools/klayout/klayout_operations.py +363 -0
  141. siliconcompiler/tools/klayout/klayout_show.py +242 -0
  142. siliconcompiler/tools/klayout/klayout_utils.py +176 -0
  143. siliconcompiler/tools/klayout/operations.py +194 -0
  144. siliconcompiler/tools/klayout/screenshot.py +98 -0
  145. siliconcompiler/tools/klayout/show.py +101 -0
  146. siliconcompiler/tools/magic/drc.py +49 -0
  147. siliconcompiler/tools/magic/extspice.py +19 -0
  148. siliconcompiler/tools/magic/magic.py +85 -0
  149. siliconcompiler/tools/magic/sc_drc.tcl +96 -0
  150. siliconcompiler/tools/magic/sc_extspice.tcl +54 -0
  151. siliconcompiler/tools/magic/sc_magic.tcl +47 -0
  152. siliconcompiler/tools/montage/montage.py +30 -0
  153. siliconcompiler/tools/montage/tile.py +66 -0
  154. siliconcompiler/tools/netgen/count_lvs.py +132 -0
  155. siliconcompiler/tools/netgen/lvs.py +90 -0
  156. siliconcompiler/tools/netgen/netgen.py +36 -0
  157. siliconcompiler/tools/netgen/sc_lvs.tcl +46 -0
  158. siliconcompiler/tools/nextpnr/apr.py +24 -0
  159. siliconcompiler/tools/nextpnr/nextpnr.py +59 -0
  160. siliconcompiler/tools/openfpgaloader/openfpgaloader.py +39 -0
  161. siliconcompiler/tools/openroad/__init__.py +0 -0
  162. siliconcompiler/tools/openroad/cts.py +45 -0
  163. siliconcompiler/tools/openroad/dfm.py +66 -0
  164. siliconcompiler/tools/openroad/export.py +131 -0
  165. siliconcompiler/tools/openroad/floorplan.py +70 -0
  166. siliconcompiler/tools/openroad/openroad.py +977 -0
  167. siliconcompiler/tools/openroad/physyn.py +27 -0
  168. siliconcompiler/tools/openroad/place.py +41 -0
  169. siliconcompiler/tools/openroad/rcx_bench.py +95 -0
  170. siliconcompiler/tools/openroad/rcx_extract.py +34 -0
  171. siliconcompiler/tools/openroad/route.py +45 -0
  172. siliconcompiler/tools/openroad/screenshot.py +60 -0
  173. siliconcompiler/tools/openroad/scripts/sc_apr.tcl +499 -0
  174. siliconcompiler/tools/openroad/scripts/sc_cts.tcl +64 -0
  175. siliconcompiler/tools/openroad/scripts/sc_dfm.tcl +20 -0
  176. siliconcompiler/tools/openroad/scripts/sc_export.tcl +98 -0
  177. siliconcompiler/tools/openroad/scripts/sc_floorplan.tcl +413 -0
  178. siliconcompiler/tools/openroad/scripts/sc_metrics.tcl +158 -0
  179. siliconcompiler/tools/openroad/scripts/sc_physyn.tcl +7 -0
  180. siliconcompiler/tools/openroad/scripts/sc_place.tcl +84 -0
  181. siliconcompiler/tools/openroad/scripts/sc_procs.tcl +423 -0
  182. siliconcompiler/tools/openroad/scripts/sc_rcx.tcl +63 -0
  183. siliconcompiler/tools/openroad/scripts/sc_rcx_bench.tcl +20 -0
  184. siliconcompiler/tools/openroad/scripts/sc_rcx_extract.tcl +12 -0
  185. siliconcompiler/tools/openroad/scripts/sc_route.tcl +133 -0
  186. siliconcompiler/tools/openroad/scripts/sc_screenshot.tcl +21 -0
  187. siliconcompiler/tools/openroad/scripts/sc_write.tcl +5 -0
  188. siliconcompiler/tools/openroad/scripts/sc_write_images.tcl +361 -0
  189. siliconcompiler/tools/openroad/show.py +94 -0
  190. siliconcompiler/tools/openroad/templates/pex.tcl +8 -0
  191. siliconcompiler/tools/opensta/__init__.py +101 -0
  192. siliconcompiler/tools/opensta/report_libraries.py +28 -0
  193. siliconcompiler/tools/opensta/scripts/sc_procs.tcl +47 -0
  194. siliconcompiler/tools/opensta/scripts/sc_report_libraries.tcl +74 -0
  195. siliconcompiler/tools/opensta/scripts/sc_timing.tcl +268 -0
  196. siliconcompiler/tools/opensta/timing.py +214 -0
  197. siliconcompiler/tools/slang/__init__.py +49 -0
  198. siliconcompiler/tools/slang/lint.py +101 -0
  199. siliconcompiler/tools/surelog/__init__.py +123 -0
  200. siliconcompiler/tools/surelog/parse.py +183 -0
  201. siliconcompiler/tools/surelog/templates/output.v +7 -0
  202. siliconcompiler/tools/sv2v/convert.py +46 -0
  203. siliconcompiler/tools/sv2v/sv2v.py +37 -0
  204. siliconcompiler/tools/template/template.py +125 -0
  205. siliconcompiler/tools/verilator/compile.py +139 -0
  206. siliconcompiler/tools/verilator/lint.py +19 -0
  207. siliconcompiler/tools/verilator/parse.py +27 -0
  208. siliconcompiler/tools/verilator/verilator.py +172 -0
  209. siliconcompiler/tools/vivado/__init__.py +7 -0
  210. siliconcompiler/tools/vivado/bitstream.py +21 -0
  211. siliconcompiler/tools/vivado/place.py +21 -0
  212. siliconcompiler/tools/vivado/route.py +21 -0
  213. siliconcompiler/tools/vivado/scripts/sc_bitstream.tcl +6 -0
  214. siliconcompiler/tools/vivado/scripts/sc_place.tcl +2 -0
  215. siliconcompiler/tools/vivado/scripts/sc_route.tcl +4 -0
  216. siliconcompiler/tools/vivado/scripts/sc_run.tcl +45 -0
  217. siliconcompiler/tools/vivado/scripts/sc_syn_fpga.tcl +25 -0
  218. siliconcompiler/tools/vivado/syn_fpga.py +20 -0
  219. siliconcompiler/tools/vivado/vivado.py +147 -0
  220. siliconcompiler/tools/vpr/_json_constraint.py +63 -0
  221. siliconcompiler/tools/vpr/_xml_constraint.py +109 -0
  222. siliconcompiler/tools/vpr/place.py +137 -0
  223. siliconcompiler/tools/vpr/route.py +124 -0
  224. siliconcompiler/tools/vpr/screenshot.py +54 -0
  225. siliconcompiler/tools/vpr/show.py +88 -0
  226. siliconcompiler/tools/vpr/vpr.py +357 -0
  227. siliconcompiler/tools/xyce/xyce.py +36 -0
  228. siliconcompiler/tools/yosys/lec.py +56 -0
  229. siliconcompiler/tools/yosys/prepareLib.py +59 -0
  230. siliconcompiler/tools/yosys/sc_lec.tcl +84 -0
  231. siliconcompiler/tools/yosys/sc_syn.tcl +79 -0
  232. siliconcompiler/tools/yosys/syn_asic.py +565 -0
  233. siliconcompiler/tools/yosys/syn_asic.tcl +377 -0
  234. siliconcompiler/tools/yosys/syn_asic_fpga_shared.tcl +31 -0
  235. siliconcompiler/tools/yosys/syn_fpga.py +146 -0
  236. siliconcompiler/tools/yosys/syn_fpga.tcl +233 -0
  237. siliconcompiler/tools/yosys/syn_strategies.tcl +81 -0
  238. siliconcompiler/tools/yosys/techmaps/lcu_kogge_stone.v +39 -0
  239. siliconcompiler/tools/yosys/templates/abc.const +2 -0
  240. siliconcompiler/tools/yosys/yosys.py +147 -0
  241. siliconcompiler/units.py +259 -0
  242. siliconcompiler/use.py +177 -0
  243. siliconcompiler/utils/__init__.py +423 -0
  244. siliconcompiler/utils/asic.py +158 -0
  245. siliconcompiler/utils/showtools.py +25 -0
  246. siliconcompiler-0.26.5.dist-info/LICENSE +190 -0
  247. siliconcompiler-0.26.5.dist-info/METADATA +195 -0
  248. siliconcompiler-0.26.5.dist-info/RECORD +251 -0
  249. siliconcompiler-0.26.5.dist-info/WHEEL +5 -0
  250. siliconcompiler-0.26.5.dist-info/entry_points.txt +12 -0
  251. siliconcompiler-0.26.5.dist-info/top_level.txt +1 -0
@@ -0,0 +1,205 @@
1
+ # KLayout script to export a .GDS file from a .DEF-formatted design.
2
+ #
3
+ # Source: The OpenROAD Project.
4
+ # https://github.com/The-OpenROAD-Project/OpenROAD-flow-scripts/blob/master/flow/util/def2stream.py
5
+ #
6
+ # License: BSD 3-Clause.
7
+ #
8
+ # Copyright (c) 2018, The Regents of the University of California
9
+ # All rights reserved.
10
+ #
11
+ # Redistribution and use in source and binary forms, with or without
12
+ # modification, are permitted provided that the following conditions are met:
13
+ #
14
+ # * Redistributions of source code must retain the above copyright notice, this
15
+ # list of conditions and the following disclaimer.
16
+ #
17
+ # * Redistributions in binary form must reproduce the above copyright notice,
18
+ # this list of conditions and the following disclaimer in the documentation
19
+ # and/or other materials provided with the distribution.
20
+ #
21
+ # * Neither the name of the copyright holder nor the names of its
22
+ # contributors may be used to endorse or promote products derived from
23
+ # this software without specific prior written permission.
24
+ #
25
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
29
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
+
36
+ import pya
37
+ import os
38
+ import sys
39
+ import fnmatch
40
+
41
+
42
+ def gds_export(design_name, in_def, in_files, out_file, tech, allow_missing, config_file='',
43
+ seal_file='',
44
+ timestamps=True):
45
+ from tools.klayout.klayout_utils import get_write_options # noqa E402
46
+
47
+ # Load def file
48
+ main_layout = pya.Layout()
49
+ main_layout.technology_name = tech.name
50
+ main_layout.read(in_def, tech.load_layout_options)
51
+
52
+ # List cells
53
+ def_cells = []
54
+ for def_cell in main_layout.each_cell():
55
+ def_cells.append(def_cell.name)
56
+
57
+ def_cells.remove(design_name)
58
+ # Remove vias
59
+ def_cells = sorted([cell for cell in def_cells if not cell.startswith("VIA_")])
60
+ print(f"[INFO] Read in {len(def_cells)} cells from DEF file")
61
+ for cell in def_cells:
62
+ print(f" [INFO] DEF cell: {cell}")
63
+
64
+ # Load in the gds to merge
65
+ print("[INFO] Merging GDS/OAS files...")
66
+ for fil in in_files:
67
+ macro_layout = pya.Layout()
68
+ macro_layout.read(fil)
69
+ print(f"[INFO] Read in {fil}")
70
+ for cell in list(def_cells):
71
+ if macro_layout.has_cell(cell):
72
+ subcell = main_layout.cell(cell)
73
+ print(f" [INFO] Merging in {cell}")
74
+ subcell.copy_tree(macro_layout.cell(cell))
75
+ def_cells.remove(cell)
76
+
77
+ # Copy the top level only to a new layout
78
+ print("[INFO] Copying toplevel cell '{0}'".format(design_name))
79
+ top_only_layout = pya.Layout()
80
+ top_only_layout.dbu = main_layout.dbu
81
+ top = top_only_layout.create_cell(design_name)
82
+ top.copy_tree(main_layout.cell(design_name))
83
+
84
+ print("[INFO] Checking for missing GDS/OAS...")
85
+ missing_cell = False
86
+ for check_cell in def_cells:
87
+ missing_cell = True
88
+ allowed_missing = any([fnmatch.fnmatch(check_cell, pattern) for pattern in allow_missing])
89
+ print(f"[{'WARNING' if allowed_missing else 'ERROR'}] LEF Cell '{check_cell}' has no "
90
+ "matching GDS/OAS cell. Cell will be empty")
91
+
92
+ if not missing_cell:
93
+ print("[INFO] All LEF cells have matching GDS/OAS cells")
94
+
95
+ print("[INFO] Checking for orphan cell in the final layout...")
96
+ for i in top_only_layout.each_cell():
97
+ if i.name != design_name and i.parent_cells() == 0:
98
+ print("[ERROR] Found orphan cell '{0}'".format(i.name))
99
+
100
+ if seal_file:
101
+ top_cell = top_only_layout.top_cell()
102
+
103
+ print("[INFO] Reading seal GDS/OAS file...")
104
+ print("\t{0}".format(seal_file))
105
+ top_only_layout.read(seal_file)
106
+
107
+ for cell in top_only_layout.top_cells():
108
+ if cell != top_cell:
109
+ print("[INFO] Merging '{0}' as child of '{1}'".format(cell.name, top_cell.name))
110
+ top.insert(pya.CellInstArray(cell.cell_index(), pya.Trans()))
111
+
112
+ # Write out the GDS
113
+ print("[INFO] Writing out GDS/OAS '{0}'".format(out_file))
114
+ top_only_layout.write(out_file, get_write_options(out_file, timestamps))
115
+
116
+
117
+ def main():
118
+ # SC_ROOT provided by CLI
119
+ sys.path.append(SC_ROOT) # noqa: F821
120
+
121
+ from tools.klayout.klayout_utils import (
122
+ technology,
123
+ get_streams,
124
+ save_technology,
125
+ get_schema
126
+ )
127
+ from tools.klayout.klayout_show import show
128
+ from tools._common.asic import get_libraries
129
+
130
+ schema = get_schema(manifest='sc_manifest.json')
131
+
132
+ # Extract info from manifest
133
+ sc_step = schema.get('arg', 'step')
134
+ sc_index = schema.get('arg', 'index')
135
+ sc_pdk = schema.get('option', 'pdk')
136
+ sc_flow = schema.get('option', 'flow')
137
+ sc_task = schema.get('flowgraph', sc_flow, sc_step, sc_index, 'task')
138
+ sc_klayout_vars = schema.getkeys('tool', 'klayout', 'task', sc_task, 'var')
139
+ sc_stream = schema.get('tool', 'klayout', 'task', sc_task, 'var', 'stream',
140
+ step=sc_step, index=sc_index)[0]
141
+
142
+ if schema.valid('option', 'stackup'):
143
+ sc_stackup = schema.get('option', 'stackup')
144
+ else:
145
+ sc_stackup = schema.get('pdk', sc_pdk, 'stackup')[0]
146
+
147
+ design = schema.get('option', 'entrypoint')
148
+ if not design:
149
+ design = schema.get('design')
150
+
151
+ in_def = None
152
+ for ext in ('def.gz', 'def'):
153
+ in_def = os.path.join('inputs', f'{design}.{ext}')
154
+ if os.path.exists(in_def):
155
+ break
156
+ in_def = None
157
+ if not in_def:
158
+ in_def = schema.get('input', 'layout', 'def', step=sc_step, index=sc_index)[0]
159
+
160
+ out_file = os.path.join('outputs', f'{design}.{sc_stream}')
161
+
162
+ libs = get_libraries(schema, 'logic')
163
+ libs += get_libraries(schema, 'macro')
164
+
165
+ in_files = []
166
+ for lib in libs:
167
+ for s in get_streams(schema):
168
+ if schema.valid('library', lib, 'output', sc_stackup, s):
169
+ in_files.extend(schema.get('library', lib, 'output', sc_stackup, s,
170
+ step=sc_step, index=sc_index))
171
+ break
172
+
173
+ allow_missing = []
174
+ for lib in libs:
175
+ if schema.valid('library', lib, 'option', 'var', 'klayout_allow_missing_cell'):
176
+ patterns = [pattern for pattern in schema.get('library', lib, 'option', 'var',
177
+ 'klayout_allow_missing_cell') if pattern]
178
+ allow_missing.extend(patterns)
179
+
180
+ if 'timestamps' in sc_klayout_vars:
181
+ sc_timestamps = schema.get('tool', 'klayout', 'task', sc_task, 'var', 'timestamps',
182
+ step=sc_step, index=sc_index) == ['true']
183
+ else:
184
+ sc_timestamps = False
185
+
186
+ if 'screenshot' in sc_klayout_vars:
187
+ sc_screenshot = schema.get('tool', 'klayout', 'task', sc_task, 'var', 'screenshot',
188
+ step=sc_step, index=sc_index) == ['true']
189
+ else:
190
+ sc_screenshot = True
191
+
192
+ sc_tech = technology(design, schema)
193
+
194
+ gds_export(design, in_def, in_files, out_file, sc_tech, allow_missing,
195
+ config_file='', seal_file='', timestamps=sc_timestamps)
196
+
197
+ if sc_screenshot:
198
+ show(schema, sc_tech, out_file, f'outputs/{design}.png', screenshot=True)
199
+
200
+ # Save tech files
201
+ save_technology(design, sc_tech)
202
+
203
+
204
+ if __name__ == '__main__':
205
+ main()
@@ -0,0 +1,363 @@
1
+ import pya
2
+ import sys
3
+ import os
4
+
5
+
6
+ def read_layout(stream_file):
7
+ print(f"[INFO] Reading '{stream_file}'")
8
+ layout = pya.Layout()
9
+ layout.read(stream_file)
10
+
11
+ return layout
12
+
13
+
14
+ def __with_timestamps(schema):
15
+ sc_step = schema.get('arg', 'step')
16
+ sc_index = schema.get('arg', 'index')
17
+
18
+ return schema.get('tool', 'klayout', 'task', 'operations', 'var', 'timestamps',
19
+ step=sc_step, index=sc_index) == ['true']
20
+
21
+
22
+ def __get_keypath_step_index(schema, *keypath):
23
+ ret = {
24
+ 'step': schema.get('arg', 'step'),
25
+ 'index': schema.get('arg', 'index')
26
+ }
27
+ pernode = schema.get(*keypath, field='pernode')
28
+ if pernode == 'never':
29
+ ret['step'] = None
30
+ ret['index'] = None
31
+
32
+ return ret
33
+
34
+
35
+ def __do_cell_swap(parent, old_cell_idx, new_cell, checked):
36
+ if (parent.cell_index() in checked):
37
+ return 0
38
+
39
+ checked.append(parent.cell_index())
40
+ replacements = 0
41
+ for inst in parent.each_inst():
42
+ if (inst.cell_index == old_cell_idx):
43
+ inst.cell = new_cell
44
+ replacements += 1
45
+ else:
46
+ replacements += __do_cell_swap(inst.cell, old_cell_idx, new_cell, checked)
47
+ return replacements
48
+
49
+
50
+ def swap_cells(base_layout, oldcell, newcell):
51
+ top_cell = base_layout.top_cell()
52
+ old_cell = base_layout.cell(oldcell)
53
+ new_cell = base_layout.cell(newcell)
54
+
55
+ if (old_cell is None):
56
+ return base_layout
57
+ if (new_cell is None):
58
+ return base_layout
59
+
60
+ checked = []
61
+ replacements = __do_cell_swap(top_cell, old_cell.cell_index(), new_cell, checked)
62
+ print(f"[INFO] Swapping '{old_cell.name}' to '{new_cell.name}' in "
63
+ f"'{top_cell.name}': {replacements} occurrences")
64
+ base_layout.delete_cell(old_cell.cell_index())
65
+
66
+ return base_layout
67
+
68
+
69
+ def add_outline(base_layout, layer):
70
+ top_cell = base_layout.top_cell()
71
+ bbox = top_cell.bbox()
72
+
73
+ layer_info = base_layout.get_info(layer)
74
+ print(f"[INFO] Adding outline to '{top_cell.name}' on layer '{layer_info.to_s()}'")
75
+
76
+ shapes = top_cell.shapes(layer)
77
+ shapes.insert(pya.Box(bbox))
78
+
79
+ return base_layout
80
+
81
+
82
+ def add_layout(base_layout, layout):
83
+ top_cell = base_layout.top_cell()
84
+
85
+ other_layout_top = layout.top_cell()
86
+
87
+ print(f"[INFO] Adding layout from '{other_layout_top.name}' to '{top_cell.name}'")
88
+ new_cell = base_layout.create_cell(other_layout_top.name)
89
+ new_cell.copy_tree(other_layout_top)
90
+
91
+ cell_inst = pya.CellInstArray(new_cell.cell_index(), pya.Trans())
92
+ top_cell.insert(cell_inst)
93
+
94
+ return base_layout
95
+
96
+
97
+ def add_layout_to_top(base_layout, new_top_cell_name):
98
+ top_cell = base_layout.top_cell()
99
+
100
+ print(f"[INFO] Adding layout from '{top_cell.name}' to new top cell '{new_top_cell_name}'")
101
+ new_cell = base_layout.create_cell(new_top_cell_name)
102
+
103
+ cell_inst = pya.CellInstArray(top_cell.cell_index(), pya.Trans())
104
+ new_cell.insert(cell_inst)
105
+
106
+ return base_layout
107
+
108
+
109
+ def merge_layouts(layout1, layout2):
110
+ cell1 = layout1.top_cell()
111
+ cell2 = layout2.top_cell()
112
+
113
+ print(f"[INFO] Merging cells '{cell1.name}' and '{cell2.name}' into '{cell1.name}'")
114
+
115
+ cell1.copy_tree(cell2)
116
+
117
+ return layout1
118
+
119
+
120
+ def rotate_layout(base_layout):
121
+ top_cell = base_layout.top_cell()
122
+ bbox = top_cell.bbox()
123
+
124
+ print(f"[INFO] Rotating layout '{top_cell.name}' 90 degrees")
125
+
126
+ transform = pya.Trans.R270
127
+ transform = pya.Trans(transform, pya.Vector(0, bbox.p2.x))
128
+
129
+ top_cell.transform(transform)
130
+
131
+ return base_layout
132
+
133
+
134
+ def rename_top(base_layout, new_name):
135
+ top_cell = base_layout.top_cell()
136
+ print(f"[INFO] Renaming '{top_cell.name}' to '{new_name}' layout: '{top_cell.name}'")
137
+ top_cell.name = new_name
138
+ return base_layout
139
+
140
+
141
+ def rename_cell(base_layout, old_name, new_name):
142
+ cell = base_layout.cell(old_name)
143
+ if not cell:
144
+ print(f"[WARNING] Unable to find '{old_name}' to rename")
145
+ print(f"[INFO] Renaming '{cell.name}' to '{new_name}' layout: '{base_layout.top_cell().name}'")
146
+ cell.name = new_name
147
+ return base_layout
148
+
149
+
150
+ def write_stream(layout, outfile, timestamps):
151
+ from tools.klayout.klayout_utils import get_write_options
152
+
153
+ print(f"[INFO] Writing layout: '{outfile}'")
154
+
155
+ layout.write(outfile, get_write_options(outfile, timestamps))
156
+
157
+
158
+ def make_property_text(layout, property_layer, property_name, destination_layer):
159
+ property_layer_info = layout.get_info(property_layer)
160
+ destination_layer_info = layout.get_info(destination_layer)
161
+ print(f"[INFO] Generating properties from {property_layer_info.to_s()} "
162
+ f"/ {property_name} on {destination_layer_info.to_s()}")
163
+
164
+ top_cell = layout.top_cell()
165
+ # Generate list of text objects
166
+ source_shapes_itr = top_cell.begin_shapes_rec(property_layer)
167
+ dest_shapes = []
168
+ while (not source_shapes_itr.at_end()):
169
+ shape = source_shapes_itr.shape()
170
+ shape_prop = shape.property(property_name)
171
+ if (shape_prop is not None and (shape.is_box() or shape.is_polygon())):
172
+ shape_center = shape.bbox().center()
173
+ dest_shapes.append(pya.Text(shape_prop, shape_center.x, shape_center.y))
174
+ source_shapes_itr.next()
175
+
176
+ # Insert objects
177
+ dest_shapes_layer = top_cell.shapes(destination_layer)
178
+ for shape in dest_shapes:
179
+ dest_shapes_layer.insert(shape)
180
+
181
+ print(f"[INFO] Generated {len(dest_shapes)} text shapes.")
182
+
183
+ return layout
184
+
185
+
186
+ def delete_layers(layout, layers):
187
+ for cell in layout.each_cell():
188
+ print(f'[INFO] Deleting layers from {cell.name}')
189
+ for layer in layers:
190
+ layer_info = layout.get_info(layer)
191
+ print(f"[INFO] Deleting layer {layer_info.to_s()}")
192
+
193
+ cell.shapes(layer).clear()
194
+
195
+ return layout
196
+
197
+
198
+ def merge_shapes(layout, layers):
199
+ if layers == ['all']:
200
+ layers = layout.layer_indexes()
201
+
202
+ for cell in layout.each_cell():
203
+ print(f"[INFO] Merging shapes in {cell.name}")
204
+ for layer in layers:
205
+ layer_info = layout.get_info(layer)
206
+ print(f"[INFO] Merging shapes on layer {layer_info.to_s()}")
207
+
208
+ shape_proc = pya.ShapeProcessor()
209
+ output_shapes = pya.Shapes()
210
+
211
+ cell_layout = cell.layout()
212
+ print(" Shape count (old):", cell.shapes(layer).size())
213
+ shape_proc.boolean(cell_layout,
214
+ cell,
215
+ layer,
216
+ cell_layout,
217
+ cell,
218
+ layer,
219
+ output_shapes,
220
+ pya.EdgeProcessor.ModeOr,
221
+ True,
222
+ True,
223
+ True)
224
+ print(" Shape count (new):", output_shapes.size())
225
+ cell.shapes(layer).clear()
226
+ cell.shapes(layer).insert(output_shapes)
227
+
228
+
229
+ def flatten(layout):
230
+ top_cell = layout.top_cell()
231
+
232
+ print(f"[INFO] Flattening: {top_cell.name}")
233
+ top_cell.flatten(True)
234
+
235
+ return layout
236
+
237
+
238
+ def parse_operations(schema, base_layout, steps):
239
+ for step in steps:
240
+ step = step.split(":")
241
+ step_name = step[0]
242
+ step_args = ":".join(step[1:])
243
+ args_key = step_args.split(',')
244
+
245
+ if (step_name == "merge" or step_name == "add"):
246
+ files = []
247
+ if len(args_key) > 1:
248
+ if 'file' not in schema.get(*args_key, field='type'):
249
+ raise ValueError(f'{step_name} requires {args_key} be a file type')
250
+ files = schema.get(*args_key, **__get_keypath_step_index(schema, *args_key))
251
+ else:
252
+ files = [f'inputs/{step_args}']
253
+ for op_file in files:
254
+ if step_name == "add":
255
+ base_layout = add_layout(base_layout, read_layout(op_file))
256
+ else:
257
+ base_layout = merge_layouts(base_layout, read_layout(op_file))
258
+ elif (step_name == "rotate"):
259
+ base_layout = rotate_layout(base_layout)
260
+ elif (step_name == "outline"):
261
+ outline_layer = [int(layer) for layer in schema.get(
262
+ *args_key, **__get_keypath_step_index(schema, *args_key))]
263
+ if len(outline_layer) != 2:
264
+ raise ValueError('outline layer requires two entries for layer and purpose, '
265
+ f'received: {len(outline_layer)}')
266
+ base_layout = add_outline(base_layout,
267
+ base_layout.layer(outline_layer[0], outline_layer[1]))
268
+ elif (step_name == "convert_property"):
269
+ options = schema.get(*args_key, **__get_keypath_step_index(schema, *args_key))
270
+ if len(options) != 3 and len(options) != 5:
271
+ raise ValueError(f'{step_name} requires 3 or 5 arguments in {args_key}')
272
+ prop_layer = [int(layer) for layer in options[0:2]]
273
+ prop_number = options[2]
274
+ if prop_number.isnumeric():
275
+ prop_number = int(prop_number)
276
+ if (len(options) == 5):
277
+ dest_layer = [int(layer) for layer in options[3:]]
278
+ else:
279
+ dest_layer = prop_layer
280
+ base_layout = make_property_text(base_layout,
281
+ base_layout.layer(prop_layer[0], prop_layer[1]),
282
+ prop_number,
283
+ base_layout.layer(dest_layer[0], dest_layer[1]))
284
+ elif (step_name == "rename"):
285
+ new_name = schema.get(*args_key, **__get_keypath_step_index(schema, *args_key))[0]
286
+ base_layout = rename_top(base_layout, new_name)
287
+ elif (step_name == "rename_cell"):
288
+ new_name = schema.get(*args_key, **__get_keypath_step_index(schema, *args_key))[0]
289
+ for renameset in schema.get(*args_key, **__get_keypath_step_index(schema, *args_key)):
290
+ oldcell, newcell = renameset.split("=")
291
+ base_layout = rename_cell(base_layout, oldcell, newcell)
292
+ elif (step_name == "swap"):
293
+ for swapset in schema.get(*args_key, **__get_keypath_step_index(schema, *args_key)):
294
+ oldcell, newcell = swapset.split("=")
295
+ base_layout = swap_cells(base_layout, oldcell, newcell)
296
+ elif (step_name == "add_top"):
297
+ new_name = schema.get(*args_key, **__get_keypath_step_index(schema, *args_key))[0]
298
+ base_layout = add_layout_to_top(base_layout, new_name)
299
+ elif (step_name == "write"):
300
+ write_stream(base_layout, f'outputs/{step_args}', __with_timestamps(schema))
301
+ elif (step_name == "flatten"):
302
+ base_layout = flatten(base_layout)
303
+ elif (step_name == "delete_layers"):
304
+ layers = []
305
+ for layer in schema.get(*args_key, **__get_keypath_step_index(schema, *args_key)):
306
+ layer_num = None
307
+ layer_purpose = None
308
+ if '/' in layer:
309
+ layer_num, layer_purpose = layer.split('/')
310
+ elif ' ' in layer:
311
+ layer_num, layer_purpose = layer.split(' ')
312
+ elif ':' in layer:
313
+ layer_num, layer_purpose = layer.split(':')
314
+ else:
315
+ raise ValueError(f'Unable to determine layer purpose pair for {layer}')
316
+ layers.append(base_layout.layer(int(layer_num), int(layer_purpose)))
317
+ base_layout = delete_layers(base_layout, layers)
318
+ elif (step_name == "merge_shapes"):
319
+ layers = schema.get(*args_key, **__get_keypath_step_index(schema, *args_key))
320
+ base_layout = merge_shapes(base_layout, layers)
321
+ else:
322
+ raise ValueError(f"Unknown step: {step_name}")
323
+
324
+
325
+ if __name__ == "__main__":
326
+ # SC_ROOT provided by CLI
327
+ sys.path.append(SC_ROOT) # noqa: F821
328
+
329
+ from tools.klayout.klayout_utils import (
330
+ technology,
331
+ get_streams,
332
+ get_schema
333
+ )
334
+
335
+ schema = get_schema(manifest='sc_manifest.json')
336
+
337
+ # Extract info from manifest
338
+ sc_step = schema.get('arg', 'step')
339
+ sc_index = schema.get('arg', 'index')
340
+ sc_tool = 'klayout'
341
+ sc_task = 'operations'
342
+
343
+ sc_ext = get_streams(schema)[0]
344
+ design = schema.get('option', 'entrypoint')
345
+ if not design:
346
+ design = schema.get('design')
347
+
348
+ in_gds = os.path.join('inputs', f'{design}.{sc_ext}.gz')
349
+ if not os.path.exists(in_gds):
350
+ in_gds = os.path.join('inputs', f'{design}.{sc_ext}')
351
+ if not os.path.exists(in_gds):
352
+ in_gds = schema.get('input', 'layout', sc_ext)[0]
353
+ out_gds = os.path.join('outputs', f'{design}.{sc_ext}')
354
+
355
+ tech = technology(design, schema)
356
+ base_layout = read_layout(in_gds)
357
+ base_layout.technology_name = tech.name
358
+
359
+ sc_klayout_ops = schema.get('tool', sc_tool, 'task', sc_task, 'var', 'operations',
360
+ step=sc_step, index=sc_index)
361
+ parse_operations(schema, base_layout, sc_klayout_ops)
362
+
363
+ write_stream(base_layout, out_gds, __with_timestamps(schema))