rocket-engine 0.0.2b1__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 (241) hide show
  1. rocket_engine/__init__.py +8 -0
  2. rocket_engine/__main__.py +12 -0
  3. rocket_engine/adapters/README.md +54 -0
  4. rocket_engine/adapters/__init__.py +7 -0
  5. rocket_engine/adapters/api.py +39 -0
  6. rocket_engine/adapters/base.py +46 -0
  7. rocket_engine/adapters/cace/__init__.py +163 -0
  8. rocket_engine/adapters/circulax/README.md +10 -0
  9. rocket_engine/adapters/circulax/__init__.py +112 -0
  10. rocket_engine/adapters/circulax/_driver.py +190 -0
  11. rocket_engine/adapters/circulax/adapter.py +538 -0
  12. rocket_engine/adapters/circulax/results.py +291 -0
  13. rocket_engine/adapters/cli/README.md +34 -0
  14. rocket_engine/adapters/cli/__init__.py +305 -0
  15. rocket_engine/adapters/connectivity/__init__.py +196 -0
  16. rocket_engine/adapters/connectivity/results.py +214 -0
  17. rocket_engine/adapters/cosim/README.md +9 -0
  18. rocket_engine/adapters/cosim/__init__.py +1390 -0
  19. rocket_engine/adapters/cosim/results.py +214 -0
  20. rocket_engine/adapters/devsim/__init__.py +171 -0
  21. rocket_engine/adapters/digital_flow/README.md +9 -0
  22. rocket_engine/adapters/digital_flow/__init__.py +1121 -0
  23. rocket_engine/adapters/digital_flow/results.py +227 -0
  24. rocket_engine/adapters/digital_flow/state.py +462 -0
  25. rocket_engine/adapters/drc/README.klayout.md +7 -0
  26. rocket_engine/adapters/drc/README.md +7 -0
  27. rocket_engine/adapters/drc/__init__.py +1 -0
  28. rocket_engine/adapters/drc/klayout.py +952 -0
  29. rocket_engine/adapters/drc/magic.py +287 -0
  30. rocket_engine/adapters/drc/results.py +184 -0
  31. rocket_engine/adapters/drc/results_kl.py +188 -0
  32. rocket_engine/adapters/elmer/__init__.py +163 -0
  33. rocket_engine/adapters/envelope.py +120 -0
  34. rocket_engine/adapters/equivalence/__init__.py +156 -0
  35. rocket_engine/adapters/errors.py +181 -0
  36. rocket_engine/adapters/extract_magic/README.md +15 -0
  37. rocket_engine/adapters/extract_magic/__init__.py +425 -0
  38. rocket_engine/adapters/extract_magic/results.py +209 -0
  39. rocket_engine/adapters/formal_sby/README.md +7 -0
  40. rocket_engine/adapters/formal_sby/__init__.py +773 -0
  41. rocket_engine/adapters/formal_sby/formal_edge.py +195 -0
  42. rocket_engine/adapters/formal_sby/results.py +185 -0
  43. rocket_engine/adapters/gdsfactory/__init__.py +194 -0
  44. rocket_engine/adapters/gdsfactory/_driver.py +459 -0
  45. rocket_engine/adapters/gdsfactory/adapter.py +609 -0
  46. rocket_engine/adapters/gdsfactory/results.py +181 -0
  47. rocket_engine/adapters/hdl_sim/README.md +7 -0
  48. rocket_engine/adapters/hdl_sim/__init__.py +369 -0
  49. rocket_engine/adapters/hdl_sim/ghdl.py +155 -0
  50. rocket_engine/adapters/hdl_sim/results.py +178 -0
  51. rocket_engine/adapters/hdl_sim/verilator.py +167 -0
  52. rocket_engine/adapters/http/README.md +15 -0
  53. rocket_engine/adapters/http/__init__.py +458 -0
  54. rocket_engine/adapters/http/events.py +63 -0
  55. rocket_engine/adapters/ipc/README.md +9 -0
  56. rocket_engine/adapters/ipc/__init__.py +111 -0
  57. rocket_engine/adapters/lvs_netgen/README.md +20 -0
  58. rocket_engine/adapters/lvs_netgen/__init__.py +889 -0
  59. rocket_engine/adapters/lvs_netgen/results.py +168 -0
  60. rocket_engine/adapters/mcp/README.md +19 -0
  61. rocket_engine/adapters/mcp/__init__.py +85 -0
  62. rocket_engine/adapters/mcp/api-schema.json +6107 -0
  63. rocket_engine/adapters/mcp/pull.py +246 -0
  64. rocket_engine/adapters/mcp/server.py +794 -0
  65. rocket_engine/adapters/meep/__init__.py +167 -0
  66. rocket_engine/adapters/meow/README.md +7 -0
  67. rocket_engine/adapters/meow/__init__.py +190 -0
  68. rocket_engine/adapters/meow/_driver.py +227 -0
  69. rocket_engine/adapters/meow/_envelope.py +108 -0
  70. rocket_engine/adapters/meow/adapter.py +491 -0
  71. rocket_engine/adapters/meow/results.py +218 -0
  72. rocket_engine/adapters/mutation/__init__.py +192 -0
  73. rocket_engine/adapters/ngspice/README.md +28 -0
  74. rocket_engine/adapters/ngspice/__init__.py +627 -0
  75. rocket_engine/adapters/ngspice/results.py +215 -0
  76. rocket_engine/adapters/postlayout/README.md +28 -0
  77. rocket_engine/adapters/postlayout/__init__.py +17 -0
  78. rocket_engine/adapters/postlayout/adapter.py +1062 -0
  79. rocket_engine/adapters/postlayout/results.py +330 -0
  80. rocket_engine/adapters/postlayout/translate.py +71 -0
  81. rocket_engine/adapters/profile.py +220 -0
  82. rocket_engine/adapters/sax/README.md +23 -0
  83. rocket_engine/adapters/sax/__init__.py +516 -0
  84. rocket_engine/adapters/sax/_driver.py +148 -0
  85. rocket_engine/adapters/sax/results.py +291 -0
  86. rocket_engine/adapters/stdio_console.py +1151 -0
  87. rocket_engine/adapters/syntax/README.md +5 -0
  88. rocket_engine/adapters/syntax/__init__.py +366 -0
  89. rocket_engine/adapters/syntax/results.py +181 -0
  90. rocket_engine/adapters/synth_yosys/README.md +7 -0
  91. rocket_engine/adapters/synth_yosys/__init__.py +655 -0
  92. rocket_engine/adapters/synth_yosys/amaranth.py +120 -0
  93. rocket_engine/adapters/synth_yosys/ghdl.py +128 -0
  94. rocket_engine/adapters/synth_yosys/results.py +173 -0
  95. rocket_engine/adapters/timing_sta/README.md +9 -0
  96. rocket_engine/adapters/timing_sta/__init__.py +726 -0
  97. rocket_engine/adapters/view_sync/__init__.py +185 -0
  98. rocket_engine/adapters/view_sync/results.py +189 -0
  99. rocket_engine/adapters/vlsir/__init__.py +142 -0
  100. rocket_engine/adapters/xschem/__init__.py +440 -0
  101. rocket_engine/adapters/xschem/deck.py +266 -0
  102. rocket_engine/clients/__init__.py +5 -0
  103. rocket_engine/clients/runtime.py +255 -0
  104. rocket_engine/composition.py +2279 -0
  105. rocket_engine/execution/README.md +30 -0
  106. rocket_engine/execution/__init__.py +150 -0
  107. rocket_engine/execution/apig/__init__.py +1 -0
  108. rocket_engine/execution/apig/pool.py +463 -0
  109. rocket_engine/execution/apig/submit.py +124 -0
  110. rocket_engine/execution/block_runs_scope.py +479 -0
  111. rocket_engine/execution/coalesce.py +414 -0
  112. rocket_engine/execution/console/__init__.py +1 -0
  113. rocket_engine/execution/console/apply_session.py +318 -0
  114. rocket_engine/execution/console/lifecycle.py +265 -0
  115. rocket_engine/execution/dispatch.py +205 -0
  116. rocket_engine/execution/errors.py +31 -0
  117. rocket_engine/execution/ports.py +797 -0
  118. rocket_engine/execution/pyexec/__init__.py +1 -0
  119. rocket_engine/execution/pyexec/apply_context.py +547 -0
  120. rocket_engine/execution/pyexec/approvals.py +173 -0
  121. rocket_engine/execution/pyexec/runner.py +404 -0
  122. rocket_engine/execution/pyexec/support.py +464 -0
  123. rocket_engine/execution/python_exec.py +897 -0
  124. rocket_engine/execution/queue.py +85 -0
  125. rocket_engine/execution/replay_safe.py +601 -0
  126. rocket_engine/execution/routing/__init__.py +1 -0
  127. rocket_engine/execution/routing/calls.py +364 -0
  128. rocket_engine/execution/routing/namespace.py +785 -0
  129. rocket_engine/execution/routing/ports.py +102 -0
  130. rocket_engine/execution/routing/tools.py +346 -0
  131. rocket_engine/execution/runner.py +311 -0
  132. rocket_engine/execution/runtime.py +1149 -0
  133. rocket_engine/execution/service.py +279 -0
  134. rocket_engine/execution/worker.py +464 -0
  135. rocket_engine/interfaces/README.md +26 -0
  136. rocket_engine/interfaces/__init__.py +58 -0
  137. rocket_engine/interfaces/apig_assets.py +407 -0
  138. rocket_engine/interfaces/celllink.py +461 -0
  139. rocket_engine/interfaces/documents.py +92 -0
  140. rocket_engine/interfaces/envelopes.py +131 -0
  141. rocket_engine/interfaces/errors.py +16 -0
  142. rocket_engine/interfaces/layout.py +410 -0
  143. rocket_engine/interfaces/layout_schema.yaml +278 -0
  144. rocket_engine/interfaces/paths.py +223 -0
  145. rocket_engine/interfaces/pdks.py +550 -0
  146. rocket_engine/interfaces/ports.py +72 -0
  147. rocket_engine/interfaces/references.py +115 -0
  148. rocket_engine/interfaces/refs.py +85 -0
  149. rocket_engine/interfaces/runparams.py +304 -0
  150. rocket_engine/interfaces/setup.py +552 -0
  151. rocket_engine/interfaces/setup_catalogue.yaml +243 -0
  152. rocket_engine/interfaces/setup_probes.py +66 -0
  153. rocket_engine/interfaces/vocabulary.py +58 -0
  154. rocket_engine/interfaces/yaml_dump.py +31 -0
  155. rocket_engine/library/README.md +22 -0
  156. rocket_engine/library/__init__.py +13 -0
  157. rocket_engine/library/apig_catalog.py +371 -0
  158. rocket_engine/library/catalog.py +185 -0
  159. rocket_engine/library/errors.py +16 -0
  160. rocket_engine/mutate/__init__.py +776 -0
  161. rocket_engine/mutate/operators.py +700 -0
  162. rocket_engine/ops/__init__.py +1 -0
  163. rocket_engine/ops/deferred.py +279 -0
  164. rocket_engine/ops/editors.py +404 -0
  165. rocket_engine/ops/evidence.py +194 -0
  166. rocket_engine/ops/gates.py +262 -0
  167. rocket_engine/ops/ports.py +76 -0
  168. rocket_engine/ops/queries.py +417 -0
  169. rocket_engine/ops/runs.py +553 -0
  170. rocket_engine/ops/submit.py +614 -0
  171. rocket_engine/project/README.md +27 -0
  172. rocket_engine/project/__init__.py +6 -0
  173. rocket_engine/project/canvas/__init__.py +55 -0
  174. rocket_engine/project/canvas/compile.py +109 -0
  175. rocket_engine/project/canvas/integrate.py +48 -0
  176. rocket_engine/project/canvas/schema.py +241 -0
  177. rocket_engine/project/canvas/templates.py +46 -0
  178. rocket_engine/project/canvas/validate.py +603 -0
  179. rocket_engine/project/edit/__init__.py +5 -0
  180. rocket_engine/project/edit/cas.py +87 -0
  181. rocket_engine/project/edit/transactions.py +282 -0
  182. rocket_engine/project/errors.py +16 -0
  183. rocket_engine/project/frontend13.py +685 -0
  184. rocket_engine/project/geometry/__init__.py +23 -0
  185. rocket_engine/project/geometry/ops.py +451 -0
  186. rocket_engine/project/geometry/snap.py +103 -0
  187. rocket_engine/project/ip/__init__.py +1 -0
  188. rocket_engine/project/ip/blocks.py +195 -0
  189. rocket_engine/project/ip/entry.schema.json +78 -0
  190. rocket_engine/project/ip/lifecycle.py +402 -0
  191. rocket_engine/project/ip/verbs.py +123 -0
  192. rocket_engine/project/layers/__init__.py +6 -0
  193. rocket_engine/project/layers/bindings.py +115 -0
  194. rocket_engine/project/layers/catalog.py +228 -0
  195. rocket_engine/project/layers/presets.py +43 -0
  196. rocket_engine/project/ledger/__init__.py +1 -0
  197. rocket_engine/project/ledger/docs.py +167 -0
  198. rocket_engine/project/ledger/entities.py +176 -0
  199. rocket_engine/project/ledger/events.py +29 -0
  200. rocket_engine/project/ledger/runs.py +257 -0
  201. rocket_engine/project/ledger/shared.py +174 -0
  202. rocket_engine/project/ledger/snapshots.py +385 -0
  203. rocket_engine/project/ledger/wires.py +552 -0
  204. rocket_engine/project/process/__init__.py +14 -0
  205. rocket_engine/project/process/model.py +193 -0
  206. rocket_engine/project/process/recipes.py +121 -0
  207. rocket_engine/project/schematic/__init__.py +1 -0
  208. rocket_engine/project/schematic/hierarchy.py +312 -0
  209. rocket_engine/project/schematic/instances.py +393 -0
  210. rocket_engine/project/schematic/sheets.py +198 -0
  211. rocket_engine/project/service.py +2941 -0
  212. rocket_engine/project/symbols/__init__.py +1 -0
  213. rocket_engine/project/symbols/cells.py +324 -0
  214. rocket_engine/project/symbols/linkage.py +356 -0
  215. rocket_engine/project/symbols/symbols.py +352 -0
  216. rocket_engine/project/templates/__init__.py +303 -0
  217. rocket_engine/project/templates/errors.py +25 -0
  218. rocket_engine/project/testbench/__init__.py +49 -0
  219. rocket_engine/project/testbench/blocks.py +619 -0
  220. rocket_engine/project/testbench/templates.py +134 -0
  221. rocket_engine/stores/README.md +12 -0
  222. rocket_engine/stores/__init__.py +6 -0
  223. rocket_engine/stores/ecs.py +1508 -0
  224. rocket_engine/stores/layers.py +1023 -0
  225. rocket_engine/stores/settings.py +1188 -0
  226. rocket_engine/stores/wireplace.py +1324 -0
  227. rocket_engine/workflows/README.md +18 -0
  228. rocket_engine/workflows/__init__.py +53 -0
  229. rocket_engine/workflows/capability_plan.py +102 -0
  230. rocket_engine/workflows/completion.py +228 -0
  231. rocket_engine/workflows/connectgraph.py +734 -0
  232. rocket_engine/workflows/connectgraph_emit.py +336 -0
  233. rocket_engine/workflows/gates.py +144 -0
  234. rocket_engine/workflows/photonic_wire.py +76 -0
  235. rocket_engine/workflows/stages.py +324 -0
  236. rocket_engine/workflows/viewsync.py +399 -0
  237. rocket_engine-0.0.2b1.dist-info/METADATA +200 -0
  238. rocket_engine-0.0.2b1.dist-info/RECORD +241 -0
  239. rocket_engine-0.0.2b1.dist-info/WHEEL +4 -0
  240. rocket_engine-0.0.2b1.dist-info/entry_points.txt +2 -0
  241. rocket_engine-0.0.2b1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,55 @@
1
+ """Project canvas: editable design intent (`canvas.toml`).
2
+
3
+ The canvas states what the design must achieve — clocks, power,
4
+ analog specs, photonic targets, tool knobs — versioned,
5
+ closure-hashed, and failing loudly on any rule violation. It
6
+ builds on PDK data but never regurgitates it. The compiler
7
+ (SDC/decks) is CANVAS-CST-COMPILE scope; this package is the
8
+ foundation: schema tables, validation, closure, emission.
9
+ """
10
+
11
+ from .schema import (
12
+ CANVAS_SCHEMA,
13
+ GENERIC_TOOL_KNOBS,
14
+ HDL_LANGUAGES,
15
+ KNOWN_METRICS,
16
+ KNOWN_UNITS,
17
+ OPERATORS,
18
+ REF_SCOPES,
19
+ TOOL_KNOBS,
20
+ )
21
+ from .validate import (
22
+ CANVAS_FILENAME,
23
+ CANVAS_VERSION,
24
+ LEGACY_FILENAME,
25
+ CanvasError,
26
+ canvas_closure,
27
+ dump_canvas_toml,
28
+ load_project_canvas,
29
+ validate_canvas,
30
+ )
31
+ from . import compile as compile_mod
32
+ from . import integrate as integrate_mod
33
+ from . import templates as templates_mod
34
+
35
+ __all__ = [
36
+ "CANVAS_FILENAME",
37
+ "CANVAS_SCHEMA",
38
+ "CANVAS_VERSION",
39
+ "GENERIC_TOOL_KNOBS",
40
+ "HDL_LANGUAGES",
41
+ "KNOWN_METRICS",
42
+ "KNOWN_UNITS",
43
+ "LEGACY_FILENAME",
44
+ "OPERATORS",
45
+ "REF_SCOPES",
46
+ "TOOL_KNOBS",
47
+ "CanvasError",
48
+ "canvas_closure",
49
+ "compile_mod",
50
+ "dump_canvas_toml",
51
+ "integrate_mod",
52
+ "load_project_canvas",
53
+ "templates_mod",
54
+ "validate_canvas",
55
+ ]
@@ -0,0 +1,109 @@
1
+ """Canvas compiler: canvas to SDC, decks, fragments."""
2
+
3
+ import math
4
+
5
+ from .schema import KNOWN_METRICS
6
+ from .validate import CanvasError
7
+
8
+
9
+ def _targets(doc):
10
+ """Return the target list of a canvas mapping.
11
+
12
+ Args:
13
+ doc: Canvas mapping with a targets list.
14
+
15
+ Returns:
16
+ Target list (empty when absent).
17
+ """
18
+ targets = doc.get("targets") or []
19
+ return targets if isinstance(targets, list) else []
20
+
21
+
22
+ def _limit_mhz(target):
23
+ """Convert one clock target limit to MHz.
24
+
25
+ Args:
26
+ target: Target mapping with a limit value/unit.
27
+
28
+ Returns:
29
+ Frequency in MHz.
30
+ """
31
+ limit = target.get("limit") or {}
32
+ value = float(limit.get("value", 0))
33
+ unit = limit.get("unit", "MHz")
34
+ scale = {"Hz": 1e-6, "kHz": 1e-3, "MHz": 1.0, "GHz": 1e3}
35
+ return value * scale.get(unit, 1.0)
36
+
37
+
38
+ def compile_sdc(doc):
39
+ """Compile a digital canvas to SDC tool-native text.
40
+
41
+ Args:
42
+ doc: Validated canvas mapping with clock targets.
43
+
44
+ Returns:
45
+ SDC text with create_clock plus operating conditions.
46
+
47
+ Raises:
48
+ CanvasError: bad_target when no clock target exists.
49
+ """
50
+ clocks = [t for t in _targets(doc)
51
+ if t.get("metric") in ("clock.frequency", "filter.cutoff")]
52
+ if not clocks:
53
+ raise CanvasError("bad_target",
54
+ "canvas.targets: no clock target for SDC.")
55
+ mhz = _limit_mhz(clocks[0])
56
+ if not math.isfinite(mhz) or mhz <= 0:
57
+ raise CanvasError("bad_limit",
58
+ "canvas.targets: clock limit must be positive.")
59
+ period_ns = 1000.0 / mhz
60
+ lines = [f"create_clock -name clk -period {period_ns:.4f} "
61
+ "[get_ports clk]",
62
+ "set_clock_uncertainty 0.050 [get_clocks clk]",
63
+ "set_input_delay 0.200 -clock clk [all_inputs]",
64
+ "set_output_delay 0.200 -clock clk [all_outputs]"]
65
+ return "\n".join(lines) + "\n"
66
+
67
+
68
+ def compile_spice_bounds(doc):
69
+ """Compile an analog canvas to run_spice measurement bounds.
70
+
71
+ Args:
72
+ doc: Validated canvas mapping with analog targets.
73
+
74
+ Returns:
75
+ Bounds mapping of metric to {min, max} floats.
76
+ """
77
+ bounds = {}
78
+ for target in _targets(doc):
79
+ metric = target.get("metric")
80
+ if metric in ("clock.frequency", "filter.cutoff"):
81
+ continue
82
+ operator = target.get("operator", "ge")
83
+ value = float((target.get("limit") or {}).get("value", 0))
84
+ entry = bounds.setdefault(metric, {})
85
+ if operator in ("ge", "gt", "eq"):
86
+ entry["min"] = value
87
+ if operator in ("le", "lt", "eq"):
88
+ entry["max"] = value
89
+ return bounds
90
+
91
+
92
+ def compile_librelane(doc):
93
+ """Compile canvas librelane knobs to a config fragment.
94
+
95
+ Args:
96
+ doc: Canvas mapping with tools.librelane knobs.
97
+
98
+ Returns:
99
+ Fragment mapping with density, effort, corners.
100
+ """
101
+ knobs = (doc.get("tools") or {}).get("librelane") or {}
102
+ frag = {}
103
+ if knobs.get("density") is not None:
104
+ frag["density"] = float(knobs["density"])
105
+ if knobs.get("effort") is not None:
106
+ frag["effort"] = str(knobs["effort"])
107
+ if knobs.get("corners") is not None:
108
+ frag["corners"] = list(knobs["corners"])
109
+ return frag
@@ -0,0 +1,48 @@
1
+ """Canvas integration: project, submit, and I28 run closure."""
2
+
3
+ from pathlib import Path
4
+
5
+ from .templates import generate
6
+ from .validate import CANVAS_FILENAME, dump_canvas_toml, load_project_canvas
7
+
8
+
9
+ def wizard_create(project_root, pdk_id):
10
+ """Create a project canvas through the creation wizard.
11
+
12
+ Args:
13
+ project_root: Project dir the canvas.toml lands in.
14
+ pdk_id: PDK id the template is generated for.
15
+
16
+ Returns:
17
+ Path to the written canvas.toml (validates clean).
18
+ """
19
+ root = Path(project_root)
20
+ root.mkdir(parents=True, exist_ok=True)
21
+ doc = generate(pdk_id)
22
+ (root / CANVAS_FILENAME).write_text(dump_canvas_toml(doc))
23
+ loaded = load_project_canvas(root)
24
+ return Path(loaded["path"])
25
+
26
+
27
+ def canvas_run_closure(project_root):
28
+ """Load the canvas closure for one I28 run.
29
+
30
+ Args:
31
+ project_root: Project dir holding canvas.toml.
32
+
33
+ Returns:
34
+ Closure mapping pinning canvas plus refs.
35
+ """
36
+ return load_project_canvas(project_root)["closure"]
37
+
38
+
39
+ def validate_submit_canvas(project_root):
40
+ """Validate the canvas on the submit path.
41
+
42
+ Args:
43
+ project_root: Project dir holding canvas.toml.
44
+
45
+ Returns:
46
+ Validated config mapping (raises CanvasError otherwise).
47
+ """
48
+ return load_project_canvas(project_root)["config"]
@@ -0,0 +1,241 @@
1
+ """Canvas registry tables: metrics, tool knobs, UI schema descriptor.
2
+
3
+ Every table here is evidence-backed: metric names and units come
4
+ from the shipped demo canvases (`waveform-generator/canvas.toml`,
5
+ `photonic_matmul/canvas.toml`) and the fuel constraint checks the
6
+ COMPILE slice migrates 1:1 (`rocket_fuel/examples/*/`). Adding a
7
+ metric or knob is a table edit here plus a test — never a silent
8
+ accept.
9
+ """
10
+
11
+ #: Metric name -> (dimension, allowed units). Flat fuel names ride
12
+ #: alongside dotted canvas names so the migration probe reads 1:1.
13
+ KNOWN_METRICS = {
14
+ "clock.frequency": ("frequency", ("Hz", "kHz", "MHz", "GHz")),
15
+ "filter.cutoff": ("frequency", ("Hz", "kHz", "MHz", "GHz")),
16
+ "ugbw_mhz": ("frequency", ("Hz", "kHz", "MHz", "GHz")),
17
+ "supply.voltage": ("voltage", ("V", "mV")),
18
+ "supply.current": ("current", ("A", "mA", "uA")),
19
+ "power.dissipation": ("power", ("W", "mW", "uW")),
20
+ "dc_gain_db": ("gain", ("dB",)),
21
+ "gain.dc": ("gain", ("dB",)),
22
+ "phase_margin_deg": ("phase", ("deg",)),
23
+ "phase.margin": ("phase", ("deg",)),
24
+ "dac.resolution": ("resolution", ("bit",)),
25
+ "dac.dnl": ("mismatch", ("LSB",)),
26
+ "dac.inl": ("mismatch", ("LSB",)),
27
+ "sim.temperature": ("temperature", ("C", "K")),
28
+ "drc.violations": ("count", ("count",)),
29
+ "drc_violations": ("count", ("count",)),
30
+ }
31
+
32
+ #: Every unit any metric or quantity accepts (union for quantity
33
+ #: checks on spice knobs such as abstol/vntol/temperature).
34
+ KNOWN_UNITS = sorted(
35
+ {unit for _, units in KNOWN_METRICS.values() for unit in units}
36
+ | {"Ohm", "kOhm", "F", "pF", "fF", "s", "ms", "us", "ns", "ps"}
37
+ )
38
+
39
+ #: Comparison operators a target may state.
40
+ OPERATORS = ("lt", "le", "eq", "ge", "gt")
41
+
42
+ #: Authored HDL dialects, one per canvas (frozen contract enum).
43
+ HDL_LANGUAGES = ("verilog", "systemverilog", "vhdl", "amaranth")
44
+
45
+ #: Reference scopes (frozen contract PinnedRef/WorkingRef).
46
+ REF_SCOPES = ("project", "library", "pdk", "package", "engine")
47
+
48
+ #: Tool name -> knob name -> knob spec. Spec kinds: ref (a Pinned
49
+ #: or Working Ref), text (delegated file path or inline text),
50
+ #: hash (pinned sha256), number (plain float with optional
51
+ #: bounds), enum, string_list, boolean, quantity (value + unit).
52
+ TOOL_KNOBS = {
53
+ "librelane": {
54
+ "profile": {"kind": "ref"},
55
+ "configuration": {"kind": "text"},
56
+ "sha256": {"kind": "hash"},
57
+ "density": {"kind": "number", "min_exclusive": 0, "max": 1},
58
+ "effort": {"kind": "enum", "values": ("low", "standard", "high")},
59
+ "corners": {"kind": "string_list"},
60
+ },
61
+ "ngspice": {
62
+ "profile": {"kind": "ref"},
63
+ "configuration": {"kind": "text"},
64
+ "sha256": {"kind": "hash"},
65
+ "temperature": {"kind": "quantity", "units": ("C", "K")},
66
+ "reltol": {"kind": "number", "min_exclusive": 0},
67
+ "abstol": {"kind": "quantity"},
68
+ "vntol": {"kind": "quantity"},
69
+ "method": {"kind": "enum", "values": ("trap", "gear")},
70
+ "max_order": {"kind": "integer", "min": 1, "max": 6},
71
+ },
72
+ "xyce": {
73
+ "profile": {"kind": "ref"},
74
+ "configuration": {"kind": "text"},
75
+ "sha256": {"kind": "hash"},
76
+ "temperature": {"kind": "quantity", "units": ("C", "K")},
77
+ "reltol": {"kind": "number", "min_exclusive": 0},
78
+ "abstol": {"kind": "quantity"},
79
+ "vntol": {"kind": "quantity"},
80
+ "method": {"kind": "enum", "values": ("trap", "gear")},
81
+ "max_order": {"kind": "integer", "min": 1, "max": 6},
82
+ },
83
+ "yosys": {
84
+ "profile": {"kind": "ref"},
85
+ "configuration": {"kind": "text"},
86
+ "sha256": {"kind": "hash"},
87
+ "flatten": {"kind": "boolean"},
88
+ "optimization": {
89
+ "kind": "enum", "values": ("area", "delay", "balanced")
90
+ },
91
+ },
92
+ "openroad": {
93
+ "profile": {"kind": "ref"},
94
+ "configuration": {"kind": "text"},
95
+ "sha256": {"kind": "hash"},
96
+ "density": {"kind": "number", "min_exclusive": 0, "max": 1},
97
+ "effort": {"kind": "enum", "values": ("low", "standard", "high")},
98
+ },
99
+ }
100
+
101
+ #: Knobs any unlisted tool accepts (the generic ToolSetting: a
102
+ #: profile plus an optional delegated configuration).
103
+ GENERIC_TOOL_KNOBS = ("profile", "configuration", "sha256")
104
+
105
+ _CANVAS_VERSION = "rocketeda/canvas/v1"
106
+
107
+
108
+ def ui_schema():
109
+ """Describe every canvas section for rendering and editing.
110
+
111
+ The UI renders and edits every section from this descriptor
112
+ alone — no section, metric, or knob exists that is not
113
+ listed here.
114
+
115
+ Returns:
116
+ Descriptor with the canvas version and one entry per
117
+ section (name, description, fields or item shape).
118
+ """
119
+ metric_field = {
120
+ "name": "metric",
121
+ "type": "enum",
122
+ "required": True,
123
+ "values": sorted(KNOWN_METRICS),
124
+ }
125
+ sections = [
126
+ {
127
+ "name": "schema",
128
+ "description": "Canvas version pin.",
129
+ "fields": [
130
+ {
131
+ "name": "schema",
132
+ "type": "const",
133
+ "required": True,
134
+ "values": [_CANVAS_VERSION],
135
+ }
136
+ ],
137
+ },
138
+ {
139
+ "name": "hdl",
140
+ "description": "One authored HDL dialect per canvas; "
141
+ "omit the section when there is no authored digital "
142
+ "content (photonic-only).",
143
+ "fields": [
144
+ {
145
+ "name": "language",
146
+ "type": "enum",
147
+ "required": True,
148
+ "values": list(HDL_LANGUAGES),
149
+ },
150
+ {
151
+ "name": "top",
152
+ "type": "string",
153
+ "required": False,
154
+ },
155
+ ],
156
+ },
157
+ {
158
+ "name": "technology",
159
+ "description": "Sealed technology reference (PDK pin).",
160
+ "fields": [
161
+ {"name": "scope", "type": "enum", "required": True,
162
+ "values": list(REF_SCOPES)},
163
+ {"name": "id", "type": "string", "required": True},
164
+ {"name": "revision", "type": "string", "required": True},
165
+ ],
166
+ },
167
+ {
168
+ "name": "pdks",
169
+ "description": "Pinned PDK references the intent builds on.",
170
+ "item": {
171
+ "type": "ref",
172
+ "fields": [
173
+ {"name": "scope", "type": "enum",
174
+ "required": True, "values": list(REF_SCOPES)},
175
+ {"name": "id", "type": "string", "required": True},
176
+ {"name": "revision", "type": "string",
177
+ "required": True},
178
+ ],
179
+ },
180
+ },
181
+ {
182
+ "name": "targets",
183
+ "description": "Design targets: one metric, one "
184
+ "operator, one limit with units.",
185
+ "item": {
186
+ "type": "target",
187
+ "fields": [
188
+ metric_field,
189
+ {
190
+ "name": "operator",
191
+ "type": "enum",
192
+ "required": True,
193
+ "values": list(OPERATORS),
194
+ },
195
+ {
196
+ "name": "limit",
197
+ "type": "quantity",
198
+ "required": True,
199
+ },
200
+ {
201
+ "name": "required",
202
+ "type": "boolean",
203
+ "required": False,
204
+ },
205
+ ],
206
+ },
207
+ },
208
+ {
209
+ "name": "tools",
210
+ "description": "Per-tool knobs: inline values or one "
211
+ "delegated configuration file, never both.",
212
+ "tools": {
213
+ name: {
214
+ "knobs": sorted(spec),
215
+ "spec": {
216
+ knob: dict(details)
217
+ for knob, details in spec.items()
218
+ },
219
+ }
220
+ for name, spec in TOOL_KNOBS.items()
221
+ },
222
+ },
223
+ {
224
+ "name": "references",
225
+ "description": "Project-relative content refs hashed "
226
+ "into the run closure.",
227
+ "item": {
228
+ "type": "reference",
229
+ "fields": [
230
+ {"name": "path", "type": "string",
231
+ "required": True},
232
+ {"name": "sha256", "type": "hash",
233
+ "required": False},
234
+ ],
235
+ },
236
+ },
237
+ ]
238
+ return {"canvas": _CANVAS_VERSION, "sections": sections}
239
+
240
+
241
+ CANVAS_SCHEMA = ui_schema()
@@ -0,0 +1,46 @@
1
+ """Per-PDK canvas templates plus the creation generator."""
2
+
3
+ _SUPPORTED = ("sky130A", "sky130GF", "gf180", "ihp", "asap7", "lxt",
4
+ "cspdk", "ubc", "vtt")
5
+
6
+
7
+ def supported_pdks():
8
+ """List PDK ids with a shipped canvas template.
9
+
10
+ Returns:
11
+ Sorted PDK ids the generator accepts.
12
+ """
13
+ return sorted(_SUPPORTED)
14
+
15
+
16
+ def generate(pdk_id):
17
+ """Generate a filled canvas document for one PDK.
18
+
19
+ Args:
20
+ pdk_id: PDK id the template is generated for.
21
+
22
+ Returns:
23
+ Canvas mapping that validates clean via validate_canvas.
24
+
25
+ Raises:
26
+ ValueError: For an unsupported PDK id.
27
+ """
28
+ if pdk_id not in _SUPPORTED:
29
+ raise ValueError(f"Unsupported PDK for canvas template: {pdk_id!r}.")
30
+ return {
31
+ "schema": "rocketeda/canvas/v1",
32
+ "pdks": [{"scope": "pdk", "id": "sky130A"
33
+ if pdk_id in ("sky130A", "sky130GF") else pdk_id,
34
+ "revision": "pinned-rev"}],
35
+ "targets": [
36
+ {"metric": "clock.frequency", "operator": "ge",
37
+ "limit": {"value": 100, "unit": "MHz"}},
38
+ {"metric": "drc.violations", "operator": "le",
39
+ "limit": {"value": 0, "unit": "count"}},
40
+ ],
41
+ "tools": {"yosys": {"flatten": True},
42
+ "ngspice": {"reltol": 0.001},
43
+ "librelane": {"density": 0.6, "effort": "standard",
44
+ "corners": ["tt"]}},
45
+ "hdl": {"language": "verilog", "top": "top"},
46
+ }