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,570 @@
1
+ import os
2
+ import math
3
+ from siliconcompiler import SiliconCompilerError, NodeStatus
4
+ from siliconcompiler.tools._common import input_file_node_name, get_tool_task
5
+
6
+
7
+ def _check_execution_nodes_inputs(chip, flow):
8
+ for node in nodes_to_execute(chip, flow):
9
+ if node in _get_execution_entry_nodes(chip, flow):
10
+ continue
11
+ pruned_node_inputs = set(_get_pruned_node_inputs(chip, flow, node))
12
+ node_inputs = set(_get_flowgraph_node_inputs(chip, flow, node))
13
+ tool, task = get_tool_task(chip, node[0], node[1], flow=flow)
14
+ if tool == 'builtin' and not pruned_node_inputs or \
15
+ tool != 'builtin' and pruned_node_inputs != node_inputs:
16
+ chip.logger.warning(
17
+ f'Flowgraph connection from {node_inputs.difference(pruned_node_inputs)} '
18
+ f'to {node} is missing. '
19
+ f'Double check your flowgraph and from/to/prune options.')
20
+ return False
21
+ return True
22
+
23
+
24
+ def _nodes_to_execute(chip, flow, from_nodes, to_nodes, prune_nodes):
25
+ '''
26
+ Assumes a flowgraph with valid edges for the inputs
27
+ '''
28
+ nodes_to_execute = []
29
+ for from_node in from_nodes:
30
+ for node in _nodes_to_execute_recursive(chip, flow, from_node, to_nodes, prune_nodes):
31
+ if node not in nodes_to_execute:
32
+ nodes_to_execute.append(node)
33
+ return nodes_to_execute
34
+
35
+
36
+ def _nodes_to_execute_recursive(chip, flow, from_node, to_nodes, prune_nodes, path=[]):
37
+ path = path.copy()
38
+ nodes_to_execute = []
39
+
40
+ if from_node in prune_nodes:
41
+ return []
42
+ if from_node in path:
43
+ raise SiliconCompilerError(f'Path {path} would form a circle with {from_node}')
44
+ path.append(from_node)
45
+
46
+ if from_node in to_nodes:
47
+ for node in path:
48
+ nodes_to_execute.append(node)
49
+ for output_node in _get_flowgraph_node_outputs(chip, flow, from_node):
50
+ for node in _nodes_to_execute_recursive(chip, flow, output_node, to_nodes,
51
+ prune_nodes, path=path):
52
+ if node not in nodes_to_execute:
53
+ nodes_to_execute.append(node)
54
+
55
+ return nodes_to_execute
56
+
57
+
58
+ def _unreachable_steps_to_execute(chip, flow, cond=lambda _: True):
59
+ from_nodes = set(_get_execution_entry_nodes(chip, flow))
60
+ to_nodes = set(_get_execution_exit_nodes(chip, flow))
61
+ prune_nodes = chip.get('option', 'prune')
62
+ reachable_nodes = set(_reachable_flowgraph_nodes(chip, flow, from_nodes, cond=cond,
63
+ prune_nodes=prune_nodes))
64
+ unreachable_nodes = to_nodes.difference(reachable_nodes)
65
+ unreachable_steps = set()
66
+ for unreachable_node in unreachable_nodes:
67
+ if not any(filter(lambda node: node[0] == unreachable_node[0], reachable_nodes)):
68
+ unreachable_steps.add(unreachable_node[0])
69
+ return unreachable_steps
70
+
71
+
72
+ def _reachable_flowgraph_nodes(chip, flow, from_nodes, cond=lambda _: True, prune_nodes=[]):
73
+ visited_nodes = set()
74
+ current_nodes = from_nodes.copy()
75
+ while current_nodes:
76
+ current_nodes_copy = current_nodes.copy()
77
+ for current_node in current_nodes_copy:
78
+ if current_node in prune_nodes:
79
+ current_nodes.remove(current_node)
80
+ continue
81
+ if cond(current_node):
82
+ visited_nodes.add(current_node)
83
+ current_nodes.remove(current_node)
84
+ outputs = _get_flowgraph_node_outputs(chip, flow, current_node)
85
+ current_nodes.update(outputs)
86
+ if current_nodes == current_nodes_copy:
87
+ break
88
+ return visited_nodes
89
+
90
+
91
+ def _get_flowgraph_node_inputs(chip, flow, node):
92
+ step, index = node
93
+ inputs = set()
94
+ for in_node in chip.get('flowgraph', flow, step, index, 'input'):
95
+ if chip.get('record', 'status', step=in_node[0], index=in_node[1]) == \
96
+ NodeStatus.SKIPPED:
97
+ inputs.update(_get_flowgraph_node_inputs(chip, flow, in_node))
98
+ else:
99
+ inputs.add(in_node)
100
+ return list(inputs)
101
+
102
+
103
+ def _get_pruned_flowgraph_nodes(chip, flow, prune_nodes):
104
+ # Ignore option from/to, we want reachable nodes of the whole flowgraph
105
+ from_nodes = set(_get_flowgraph_entry_nodes(chip, flow))
106
+ return _reachable_flowgraph_nodes(chip, flow, from_nodes, prune_nodes=prune_nodes)
107
+
108
+
109
+ def _get_pruned_node_inputs(chip, flow, node):
110
+ prune_nodes = chip.get('option', 'prune')
111
+ pruned_flowgraph_nodes = _get_pruned_flowgraph_nodes(chip, flow, prune_nodes)
112
+ return list(filter(lambda node: node in pruned_flowgraph_nodes,
113
+ _get_flowgraph_node_inputs(chip, flow, node)))
114
+
115
+
116
+ def _get_flowgraph_node_outputs(chip, flow, node):
117
+ node_outputs = []
118
+
119
+ iter_nodes = _get_flowgraph_nodes(chip, flow)
120
+ for iter_node in iter_nodes:
121
+ iter_node_inputs = chip.get('flowgraph', flow, *iter_node, 'input')
122
+ if node in iter_node_inputs:
123
+ node_outputs.append(iter_node)
124
+
125
+ return node_outputs
126
+
127
+
128
+ def _get_flowgraph_nodes(chip, flow, steps=None, indices=None):
129
+ nodes = []
130
+ for step in chip.getkeys('flowgraph', flow):
131
+ if steps and step not in steps:
132
+ continue
133
+ for index in chip.getkeys('flowgraph', flow, step):
134
+ if indices and index not in indices:
135
+ continue
136
+ nodes.append((step, index))
137
+ return nodes
138
+
139
+
140
+ #######################################
141
+ def _get_execution_entry_nodes(chip, flow):
142
+ if chip.get('arg', 'step') and chip.get('arg', 'index'):
143
+ return [(chip.get('arg', 'step'), chip.get('arg', 'index'))]
144
+ if chip.get('arg', 'step'):
145
+ return _get_flowgraph_nodes(chip, flow, steps=[chip.get('arg', 'step')])
146
+ # If we explicitly get the nodes for a flow other than the current one,
147
+ # Ignore the 'option' 'from'
148
+ if chip.get('option', 'flow') == flow and chip.get('option', 'from'):
149
+ return _get_flowgraph_nodes(chip, flow, steps=chip.get('option', 'from'))
150
+ return _get_flowgraph_entry_nodes(chip, flow)
151
+
152
+
153
+ def _get_flowgraph_entry_nodes(chip, flow, steps=None):
154
+ '''
155
+ Collect all step/indices that represent the entry
156
+ nodes for the flowgraph
157
+ '''
158
+ nodes = []
159
+ for (step, index) in _get_flowgraph_nodes(chip, flow, steps=steps):
160
+ if not chip.get('flowgraph', flow, step, index, 'input'):
161
+ nodes.append((step, index))
162
+ return nodes
163
+
164
+
165
+ def _get_execution_exit_nodes(chip, flow):
166
+ if chip.get('arg', 'step') and chip.get('arg', 'index'):
167
+ return [(chip.get('arg', 'step'), chip.get('arg', 'index'))]
168
+ if chip.get('arg', 'step'):
169
+ return _get_flowgraph_nodes(chip, flow, steps=[chip.get('arg', 'step')])
170
+ # If we explicitly get the nodes for a flow other than the current one,
171
+ # Ignore the 'option' 'to'
172
+ if chip.get('option', 'flow') == flow and chip.get('option', 'to'):
173
+ return _get_flowgraph_nodes(chip, flow, steps=chip.get('option', 'to'))
174
+ return _get_flowgraph_exit_nodes(chip, flow)
175
+
176
+
177
+ #######################################
178
+ def _get_flowgraph_exit_nodes(chip, flow, steps=None):
179
+ '''
180
+ Collect all step/indices that represent the exit
181
+ nodes for the flowgraph
182
+ '''
183
+ inputnodes = []
184
+ for (step, index) in _get_flowgraph_nodes(chip, flow, steps=steps):
185
+ inputnodes.extend(chip.get('flowgraph', flow, step, index, 'input'))
186
+ nodes = []
187
+ for (step, index) in _get_flowgraph_nodes(chip, flow, steps=steps):
188
+ if (step, index) not in inputnodes:
189
+ nodes.append((step, index))
190
+ return nodes
191
+
192
+
193
+ #######################################
194
+ def _get_flowgraph_execution_order(chip, flow, reverse=False):
195
+ '''
196
+ Generates a list of nodes in the order they will be executed.
197
+ '''
198
+
199
+ # Generate execution edges lookup map
200
+ ex_map = {}
201
+ for step, index in _get_flowgraph_nodes(chip, flow):
202
+ for istep, iindex in chip.get('flowgraph', flow, step, index, 'input'):
203
+ if reverse:
204
+ ex_map.setdefault((step, index), set()).add((istep, iindex))
205
+ else:
206
+ ex_map.setdefault((istep, iindex), set()).add((step, index))
207
+
208
+ # Collect execution order of nodes
209
+ if reverse:
210
+ order = [set(_get_flowgraph_exit_nodes(chip, flow))]
211
+ else:
212
+ order = [set(_get_flowgraph_entry_nodes(chip, flow))]
213
+
214
+ while True:
215
+ next_level = set()
216
+ for step, index in order[-1]:
217
+ if (step, index) in ex_map and \
218
+ not any([(step, index) in v for v in ex_map.values()]):
219
+ next_level.update(ex_map.pop((step, index)))
220
+
221
+ if not next_level:
222
+ break
223
+
224
+ order.append(next_level)
225
+
226
+ # Filter duplicates from flow
227
+ used_nodes = set()
228
+ exec_order = []
229
+ order.reverse()
230
+ for n, level_nodes in enumerate(order):
231
+ exec_order.append(list(level_nodes.difference(used_nodes)))
232
+ used_nodes.update(level_nodes)
233
+
234
+ exec_order.reverse()
235
+
236
+ return exec_order
237
+
238
+
239
+ def get_executed_nodes(chip, flow):
240
+ from_nodes = _get_flowgraph_entry_nodes(chip, flow)
241
+ return get_nodes_from(chip, flow, from_nodes)
242
+
243
+
244
+ def get_nodes_from(chip, flow, nodes):
245
+ to_nodes = _get_execution_exit_nodes(chip, flow)
246
+ return _nodes_to_execute(chip,
247
+ flow,
248
+ set(nodes),
249
+ set(to_nodes),
250
+ set(chip.get('option', 'prune')))
251
+
252
+
253
+ ###########################################################################
254
+ def nodes_to_execute(chip, flow=None):
255
+ '''
256
+ Returns an ordered list of flowgraph nodes which will be executed.
257
+ This takes the from/to options into account if flow is the current flow or None.
258
+
259
+ Returns:
260
+ A list of nodes that will get executed during run() (or a specific flow).
261
+
262
+ Example:
263
+ >>> nodes = nodes_to_execute()
264
+ '''
265
+ if flow is None:
266
+ flow = chip.get('option', 'flow')
267
+
268
+ from_nodes = _get_execution_entry_nodes(chip, flow)
269
+ to_nodes = _get_execution_exit_nodes(chip, flow)
270
+ prune_nodes = chip.get('option', 'prune')
271
+ if from_nodes == to_nodes:
272
+ return list(filter(lambda node: node not in prune_nodes, from_nodes))
273
+ return _nodes_to_execute(chip, flow, set(from_nodes), set(to_nodes), set(prune_nodes))
274
+
275
+
276
+ ###########################################################################
277
+ def _check_flowgraph(chip, flow=None):
278
+ '''
279
+ Check if flowgraph is valid.
280
+
281
+ * Checks if all edges have valid nodes
282
+ * Checks that there are no duplicate edges
283
+ * Checks if from/to is valid
284
+
285
+ Returns True if valid, False otherwise.
286
+ '''
287
+
288
+ if not flow:
289
+ flow = chip.get('option', 'flow')
290
+
291
+ error = False
292
+
293
+ nodes = set()
294
+ for (step, index) in _get_flowgraph_nodes(chip, flow):
295
+ nodes.add((step, index))
296
+ input_nodes = chip.get('flowgraph', flow, step, index, 'input')
297
+ nodes.update(input_nodes)
298
+
299
+ for node in set(input_nodes):
300
+ if input_nodes.count(node) > 1:
301
+ in_step, in_index = node
302
+ chip.logger.error(f'Duplicate edge from {in_step}{in_index} to '
303
+ f'{step}{index} in the {flow} flowgraph')
304
+ error = True
305
+
306
+ for step, index in nodes:
307
+ # For each task, check input requirements.
308
+ tool, task = get_tool_task(chip, step, index, flow=flow)
309
+
310
+ if not tool:
311
+ chip.logger.error(f'{step}{index} is missing a tool definition in the {flow} '
312
+ 'flowgraph')
313
+ error = True
314
+
315
+ if not task:
316
+ chip.logger.error(f'{step}{index} is missing a task definition in the {flow} '
317
+ 'flowgraph')
318
+ error = True
319
+
320
+ for step in chip.get('option', 'from'):
321
+ if step not in chip.getkeys('flowgraph', flow):
322
+ chip.logger.error(f'{step} is not defined in the {flow} flowgraph')
323
+ error = True
324
+
325
+ for step in chip.get('option', 'to'):
326
+ if step not in chip.getkeys('flowgraph', flow):
327
+ chip.logger.error(f'{step} is not defined in the {flow} flowgraph')
328
+ error = True
329
+
330
+ if not _check_execution_nodes_inputs(chip, flow):
331
+ error = True
332
+
333
+ unreachable_steps = _unreachable_steps_to_execute(chip, flow)
334
+ if unreachable_steps:
335
+ chip.logger.error(f'These final steps in {flow} can not be reached: '
336
+ f'{list(unreachable_steps)}')
337
+ error = True
338
+
339
+ return not error
340
+
341
+
342
+ ###########################################################################
343
+ def _check_flowgraph_io(chip, nodes=None):
344
+ '''Check if flowgraph is valid in terms of input and output files.
345
+
346
+ Returns True if valid, False otherwise.
347
+ '''
348
+ flow = chip.get('option', 'flow')
349
+ if not nodes:
350
+ nodes = nodes_to_execute(chip)
351
+ for (step, index) in nodes:
352
+ # For each task, check input requirements.
353
+ tool, task = get_tool_task(chip, step, index, flow=flow)
354
+
355
+ if tool == 'builtin':
356
+ # We can skip builtins since they don't have any particular
357
+ # input requirements -- they just pass through what they
358
+ # receive.
359
+ continue
360
+
361
+ # Get files we receive from input nodes.
362
+ in_nodes = _get_flowgraph_node_inputs(chip, flow, (step, index))
363
+ all_inputs = set()
364
+ requirements = chip.get('tool', tool, 'task', task, 'input', step=step, index=index)
365
+ for in_step, in_index in in_nodes:
366
+ if (in_step, in_index) not in nodes:
367
+ # If we're not running the input step, the required
368
+ # inputs need to already be copied into the build
369
+ # directory.
370
+ workdir = chip.getworkdir(step=in_step, index=in_index)
371
+ in_step_out_dir = os.path.join(workdir, 'outputs')
372
+
373
+ if not os.path.isdir(in_step_out_dir):
374
+ # This means this step hasn't been run, but that
375
+ # will be flagged by a different check. No error
376
+ # message here since it would be redundant.
377
+ inputs = []
378
+ continue
379
+
380
+ design = chip.get('design')
381
+ manifest = f'{design}.pkg.json'
382
+ inputs = [inp for inp in os.listdir(in_step_out_dir) if inp != manifest]
383
+ else:
384
+ inputs = _gather_outputs(chip, in_step, in_index)
385
+
386
+ for inp in inputs:
387
+ node_inp = input_file_node_name(inp, in_step, in_index)
388
+ if node_inp in requirements:
389
+ inp = node_inp
390
+ if inp in all_inputs:
391
+ chip.logger.error(f'Invalid flow: {step}{index} '
392
+ f'receives {inp} from multiple input tasks')
393
+ return False
394
+ all_inputs.add(inp)
395
+
396
+ for requirement in requirements:
397
+ if requirement not in all_inputs:
398
+ chip.logger.error(f'Invalid flow: {step}{index} will '
399
+ f'not receive required input {requirement}.')
400
+ return False
401
+
402
+ return True
403
+
404
+
405
+ ###########################################################################
406
+ def _gather_outputs(chip, step, index):
407
+ '''Return set of filenames that are guaranteed to be in outputs
408
+ directory after a successful run of step/index.'''
409
+
410
+ flow = chip.get('option', 'flow')
411
+ task_gather = getattr(chip._get_task_module(step, index, flow=flow, error=False),
412
+ '_gather_outputs',
413
+ None)
414
+ if task_gather:
415
+ return set(task_gather(chip, step, index))
416
+
417
+ tool, task = get_tool_task(chip, step, index, flow=flow)
418
+ return set(chip.get('tool', tool, 'task', task, 'output', step=step, index=index))
419
+
420
+
421
+ def _get_flowgraph_information(chip, flow, io=True):
422
+ from siliconcompiler.scheduler import _setup_node
423
+ from siliconcompiler.tools._common import input_provides, input_file_node_name
424
+
425
+ # Save schema to avoid making permanent changes
426
+ org_schema = chip.schema
427
+ chip.schema = chip.schema.copy()
428
+
429
+ # Setup nodes
430
+ node_exec_order = _get_flowgraph_execution_order(chip, flow)
431
+ if io:
432
+ # try:
433
+ for layer_nodes in node_exec_order:
434
+ for step, index in layer_nodes:
435
+ _setup_node(chip, step, index, flow=flow)
436
+ # except: # noqa E722
437
+ # io = False
438
+
439
+ node_rank = {}
440
+ for rank, rank_nodes in enumerate(node_exec_order):
441
+ for step, index in rank_nodes:
442
+ node_rank[f'{step}{index}'] = rank
443
+
444
+ graph_inputs = {}
445
+ all_graph_inputs = set()
446
+ if io:
447
+ for step, index in _get_flowgraph_nodes(chip, flow):
448
+ tool, task = get_tool_task(chip, step, index, flow=flow)
449
+ for keypath in chip.get('tool', tool, 'task', task, 'require', step=step, index=index):
450
+ key = tuple(keypath.split(','))
451
+ if key[0] == 'input':
452
+ graph_inputs.setdefault((step, index), set()).add(keypath)
453
+
454
+ for inputs in graph_inputs.values():
455
+ all_graph_inputs.update(inputs)
456
+
457
+ exit_nodes = [f'{step}{index}' for step, index in _get_flowgraph_exit_nodes(chip, flow)]
458
+
459
+ nodes = {}
460
+ edges = []
461
+
462
+ def clean_label(label):
463
+ return label.replace("<", "").replace(">", "")
464
+
465
+ def clean_text(label):
466
+ return label.replace("<", r"\<").replace(">", r"\>")
467
+
468
+ all_nodes = [(step, index) for step, index in sorted(_get_flowgraph_nodes(chip, flow))
469
+ if chip.get('record', 'status', step=step, index=index) != NodeStatus.SKIPPED]
470
+ for step, index in all_nodes:
471
+ tool, task = get_tool_task(chip, step, index, flow=flow)
472
+
473
+ if io:
474
+ inputs = chip.get('tool', tool, 'task', task, 'input', step=step, index=index)
475
+ outputs = chip.get('tool', tool, 'task', task, 'output', step=step, index=index)
476
+ if chip.get('record', 'status', step=step, index=index) == NodeStatus.SKIPPED:
477
+ continue
478
+ else:
479
+ inputs = []
480
+ outputs = []
481
+
482
+ node = f'{step}{index}'
483
+ if io and (step, index) in graph_inputs:
484
+ inputs.extend(graph_inputs[(step, index)])
485
+
486
+ nodes[node] = {
487
+ "node": (step, index),
488
+ "file_inputs": inputs,
489
+ "inputs": {clean_text(f): f'input-{clean_label(f)}' for f in sorted(inputs)},
490
+ "outputs": {clean_text(f): f'output-{clean_label(f)}' for f in sorted(outputs)},
491
+ "task": f'{tool}/{task}' if tool != 'builtin' else task,
492
+ "is_input": node_rank[node] == 0,
493
+ "rank": node_rank[node]
494
+ }
495
+ nodes[node]["width"] = max(len(nodes[node]["inputs"]), len(nodes[node]["outputs"]))
496
+
497
+ if tool is None or task is None:
498
+ nodes[node]["task"] = None
499
+
500
+ rank_diff = {}
501
+ for in_step, in_index in _get_flowgraph_node_inputs(chip, flow, (step, index)):
502
+ rank_diff[f'{in_step}{in_index}'] = node_rank[node] - node_rank[f'{in_step}{in_index}']
503
+ nodes[node]["rank_diff"] = rank_diff
504
+
505
+ for step, index in all_nodes:
506
+ node = f'{step}{index}'
507
+ if io:
508
+ # get inputs
509
+ edge_stats = {}
510
+ for infile, in_nodes in input_provides(chip, step, index, flow=flow).items():
511
+ outfile = infile
512
+ for in_step, in_index in in_nodes:
513
+ infile = outfile
514
+ if infile not in nodes[node]["file_inputs"]:
515
+ infile = input_file_node_name(infile, in_step, in_index)
516
+ if infile not in nodes[node]["file_inputs"]:
517
+ continue
518
+ in_node_name = f"{in_step}{in_index}"
519
+ outlabel = f"{in_node_name}:output-{clean_label(outfile)}"
520
+ inlabel = f"{step}{index}:input-{clean_label(infile)}"
521
+
522
+ if in_node_name not in edge_stats:
523
+ edge_stats[in_node_name] = {
524
+ "count": 0,
525
+ "pairs": [],
526
+ "weight": min(nodes[node]["width"], nodes[in_node_name]["width"])
527
+ }
528
+ edge_stats[in_node_name]["count"] += 1
529
+ edge_stats[in_node_name]["pairs"].append((outlabel, inlabel))
530
+
531
+ # assign edge weights
532
+
533
+ # scale multiple weights
534
+ for edge_data in edge_stats.values():
535
+ edge_data["weight"] = int(
536
+ math.floor(max(1, edge_data["weight"] / edge_data["count"])))
537
+
538
+ # lower exit nodes weights
539
+ if node in exit_nodes:
540
+ for edge_data in edge_stats.values():
541
+ edge_data["weight"] = 1
542
+ else:
543
+ for edge_data in edge_stats.values():
544
+ edge_data["weight"] *= 2
545
+
546
+ # adjust for rank differences, lower weight if rankdiff is greater than 1
547
+ for in_node, edge_data in edge_stats.items():
548
+ if nodes[node]["rank_diff"][in_node] > 1:
549
+ edge_data["weight"] = 1
550
+
551
+ # create edges
552
+ for edge_data in edge_stats.values():
553
+ for outlabel, inlabel in edge_data["pairs"]:
554
+ edges.append([outlabel, inlabel, edge_data["weight"]])
555
+
556
+ if (step, index) in graph_inputs:
557
+ for key in graph_inputs[(step, index)]:
558
+ inlabel = f"{step}{index}:input-{clean_label(key)}"
559
+ edges.append((key, inlabel, 1))
560
+ else:
561
+ all_inputs = []
562
+ for in_step, in_index in chip.get('flowgraph', flow, step, index, 'input'):
563
+ all_inputs.append(f'{in_step}{in_index}')
564
+ for item in all_inputs:
565
+ edges.append((item, node, 1 if node in exit_nodes else 2))
566
+
567
+ # Restore schema
568
+ chip.schema = org_schema
569
+
570
+ return all_graph_inputs, nodes, edges, io
File without changes
@@ -0,0 +1,67 @@
1
+ from siliconcompiler.tools.surelog import parse as surelog_parse
2
+ from siliconcompiler.tools.chisel import convert as chisel_convert
3
+ from siliconcompiler.tools.bambu import convert as bambu_convert
4
+ from siliconcompiler.tools.bluespec import convert as bluespec_convert
5
+ from siliconcompiler.tools.ghdl import convert as ghdl_convert
6
+ from siliconcompiler.tools.sv2v import convert as sv2v_convert
7
+
8
+ from siliconcompiler.tools.builtin import concatenate
9
+
10
+
11
+ def _make_docs(chip):
12
+ from siliconcompiler.targets import freepdk45_demo
13
+ chip.set('input', 'rtl', 'vhdl', 'test')
14
+ chip.set('input', 'rtl', 'verilog', 'test')
15
+ chip.set('input', 'rtl', 'systemverilog', 'test')
16
+ chip.set('input', 'hll', 'c', 'test')
17
+ chip.set('input', 'hll', 'bsv', 'test')
18
+ chip.set('input', 'hll', 'scala', 'test')
19
+
20
+ chip.load_target(freepdk45_demo)
21
+
22
+
23
+ def __get_frontends(allow_system_verilog):
24
+ systemverilog_frontend = [
25
+ ('import', surelog_parse)
26
+ ]
27
+ if not allow_system_verilog:
28
+ systemverilog_frontend.append(('convert', sv2v_convert))
29
+
30
+ return {
31
+ "verilog": systemverilog_frontend,
32
+ "chisel": [('import', chisel_convert)],
33
+ "c": [('import', bambu_convert)],
34
+ "bluespec": [('import', bluespec_convert)],
35
+ "vhdl": [('import', ghdl_convert)]
36
+ }
37
+
38
+
39
+ def setup_multiple_frontends(chip, flow, allow_system_verilog=False):
40
+ '''
41
+ Sets of multiple frontends if different frontends are required.
42
+
43
+ Returns name of final step from the setup.
44
+ '''
45
+
46
+ concat_nodes = []
47
+ flowname = flow.design
48
+ for frontend, pipe in __get_frontends(allow_system_verilog).items():
49
+ prev_step = None
50
+ for step, task in pipe:
51
+ step_name = f'{step}_{frontend}'
52
+
53
+ flow.node(flowname, step_name, task)
54
+ if prev_step:
55
+ flow.edge(flowname, prev_step, step_name)
56
+
57
+ prev_step = step_name
58
+
59
+ if prev_step:
60
+ concat_nodes.append(prev_step)
61
+
62
+ final_node = 'combine'
63
+ flow.node(flowname, final_node, concatenate)
64
+ for node in concat_nodes:
65
+ flow.edge(flowname, node, final_node)
66
+
67
+ return final_node