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.
- rocket_engine/__init__.py +8 -0
- rocket_engine/__main__.py +12 -0
- rocket_engine/adapters/README.md +54 -0
- rocket_engine/adapters/__init__.py +7 -0
- rocket_engine/adapters/api.py +39 -0
- rocket_engine/adapters/base.py +46 -0
- rocket_engine/adapters/cace/__init__.py +163 -0
- rocket_engine/adapters/circulax/README.md +10 -0
- rocket_engine/adapters/circulax/__init__.py +112 -0
- rocket_engine/adapters/circulax/_driver.py +190 -0
- rocket_engine/adapters/circulax/adapter.py +538 -0
- rocket_engine/adapters/circulax/results.py +291 -0
- rocket_engine/adapters/cli/README.md +34 -0
- rocket_engine/adapters/cli/__init__.py +305 -0
- rocket_engine/adapters/connectivity/__init__.py +196 -0
- rocket_engine/adapters/connectivity/results.py +214 -0
- rocket_engine/adapters/cosim/README.md +9 -0
- rocket_engine/adapters/cosim/__init__.py +1390 -0
- rocket_engine/adapters/cosim/results.py +214 -0
- rocket_engine/adapters/devsim/__init__.py +171 -0
- rocket_engine/adapters/digital_flow/README.md +9 -0
- rocket_engine/adapters/digital_flow/__init__.py +1121 -0
- rocket_engine/adapters/digital_flow/results.py +227 -0
- rocket_engine/adapters/digital_flow/state.py +462 -0
- rocket_engine/adapters/drc/README.klayout.md +7 -0
- rocket_engine/adapters/drc/README.md +7 -0
- rocket_engine/adapters/drc/__init__.py +1 -0
- rocket_engine/adapters/drc/klayout.py +952 -0
- rocket_engine/adapters/drc/magic.py +287 -0
- rocket_engine/adapters/drc/results.py +184 -0
- rocket_engine/adapters/drc/results_kl.py +188 -0
- rocket_engine/adapters/elmer/__init__.py +163 -0
- rocket_engine/adapters/envelope.py +120 -0
- rocket_engine/adapters/equivalence/__init__.py +156 -0
- rocket_engine/adapters/errors.py +181 -0
- rocket_engine/adapters/extract_magic/README.md +15 -0
- rocket_engine/adapters/extract_magic/__init__.py +425 -0
- rocket_engine/adapters/extract_magic/results.py +209 -0
- rocket_engine/adapters/formal_sby/README.md +7 -0
- rocket_engine/adapters/formal_sby/__init__.py +773 -0
- rocket_engine/adapters/formal_sby/formal_edge.py +195 -0
- rocket_engine/adapters/formal_sby/results.py +185 -0
- rocket_engine/adapters/gdsfactory/__init__.py +194 -0
- rocket_engine/adapters/gdsfactory/_driver.py +459 -0
- rocket_engine/adapters/gdsfactory/adapter.py +609 -0
- rocket_engine/adapters/gdsfactory/results.py +181 -0
- rocket_engine/adapters/hdl_sim/README.md +7 -0
- rocket_engine/adapters/hdl_sim/__init__.py +369 -0
- rocket_engine/adapters/hdl_sim/ghdl.py +155 -0
- rocket_engine/adapters/hdl_sim/results.py +178 -0
- rocket_engine/adapters/hdl_sim/verilator.py +167 -0
- rocket_engine/adapters/http/README.md +15 -0
- rocket_engine/adapters/http/__init__.py +458 -0
- rocket_engine/adapters/http/events.py +63 -0
- rocket_engine/adapters/ipc/README.md +9 -0
- rocket_engine/adapters/ipc/__init__.py +111 -0
- rocket_engine/adapters/lvs_netgen/README.md +20 -0
- rocket_engine/adapters/lvs_netgen/__init__.py +889 -0
- rocket_engine/adapters/lvs_netgen/results.py +168 -0
- rocket_engine/adapters/mcp/README.md +19 -0
- rocket_engine/adapters/mcp/__init__.py +85 -0
- rocket_engine/adapters/mcp/api-schema.json +6107 -0
- rocket_engine/adapters/mcp/pull.py +246 -0
- rocket_engine/adapters/mcp/server.py +794 -0
- rocket_engine/adapters/meep/__init__.py +167 -0
- rocket_engine/adapters/meow/README.md +7 -0
- rocket_engine/adapters/meow/__init__.py +190 -0
- rocket_engine/adapters/meow/_driver.py +227 -0
- rocket_engine/adapters/meow/_envelope.py +108 -0
- rocket_engine/adapters/meow/adapter.py +491 -0
- rocket_engine/adapters/meow/results.py +218 -0
- rocket_engine/adapters/mutation/__init__.py +192 -0
- rocket_engine/adapters/ngspice/README.md +28 -0
- rocket_engine/adapters/ngspice/__init__.py +627 -0
- rocket_engine/adapters/ngspice/results.py +215 -0
- rocket_engine/adapters/postlayout/README.md +28 -0
- rocket_engine/adapters/postlayout/__init__.py +17 -0
- rocket_engine/adapters/postlayout/adapter.py +1062 -0
- rocket_engine/adapters/postlayout/results.py +330 -0
- rocket_engine/adapters/postlayout/translate.py +71 -0
- rocket_engine/adapters/profile.py +220 -0
- rocket_engine/adapters/sax/README.md +23 -0
- rocket_engine/adapters/sax/__init__.py +516 -0
- rocket_engine/adapters/sax/_driver.py +148 -0
- rocket_engine/adapters/sax/results.py +291 -0
- rocket_engine/adapters/stdio_console.py +1151 -0
- rocket_engine/adapters/syntax/README.md +5 -0
- rocket_engine/adapters/syntax/__init__.py +366 -0
- rocket_engine/adapters/syntax/results.py +181 -0
- rocket_engine/adapters/synth_yosys/README.md +7 -0
- rocket_engine/adapters/synth_yosys/__init__.py +655 -0
- rocket_engine/adapters/synth_yosys/amaranth.py +120 -0
- rocket_engine/adapters/synth_yosys/ghdl.py +128 -0
- rocket_engine/adapters/synth_yosys/results.py +173 -0
- rocket_engine/adapters/timing_sta/README.md +9 -0
- rocket_engine/adapters/timing_sta/__init__.py +726 -0
- rocket_engine/adapters/view_sync/__init__.py +185 -0
- rocket_engine/adapters/view_sync/results.py +189 -0
- rocket_engine/adapters/vlsir/__init__.py +142 -0
- rocket_engine/adapters/xschem/__init__.py +440 -0
- rocket_engine/adapters/xschem/deck.py +266 -0
- rocket_engine/clients/__init__.py +5 -0
- rocket_engine/clients/runtime.py +255 -0
- rocket_engine/composition.py +2279 -0
- rocket_engine/execution/README.md +30 -0
- rocket_engine/execution/__init__.py +150 -0
- rocket_engine/execution/apig/__init__.py +1 -0
- rocket_engine/execution/apig/pool.py +463 -0
- rocket_engine/execution/apig/submit.py +124 -0
- rocket_engine/execution/block_runs_scope.py +479 -0
- rocket_engine/execution/coalesce.py +414 -0
- rocket_engine/execution/console/__init__.py +1 -0
- rocket_engine/execution/console/apply_session.py +318 -0
- rocket_engine/execution/console/lifecycle.py +265 -0
- rocket_engine/execution/dispatch.py +205 -0
- rocket_engine/execution/errors.py +31 -0
- rocket_engine/execution/ports.py +797 -0
- rocket_engine/execution/pyexec/__init__.py +1 -0
- rocket_engine/execution/pyexec/apply_context.py +547 -0
- rocket_engine/execution/pyexec/approvals.py +173 -0
- rocket_engine/execution/pyexec/runner.py +404 -0
- rocket_engine/execution/pyexec/support.py +464 -0
- rocket_engine/execution/python_exec.py +897 -0
- rocket_engine/execution/queue.py +85 -0
- rocket_engine/execution/replay_safe.py +601 -0
- rocket_engine/execution/routing/__init__.py +1 -0
- rocket_engine/execution/routing/calls.py +364 -0
- rocket_engine/execution/routing/namespace.py +785 -0
- rocket_engine/execution/routing/ports.py +102 -0
- rocket_engine/execution/routing/tools.py +346 -0
- rocket_engine/execution/runner.py +311 -0
- rocket_engine/execution/runtime.py +1149 -0
- rocket_engine/execution/service.py +279 -0
- rocket_engine/execution/worker.py +464 -0
- rocket_engine/interfaces/README.md +26 -0
- rocket_engine/interfaces/__init__.py +58 -0
- rocket_engine/interfaces/apig_assets.py +407 -0
- rocket_engine/interfaces/celllink.py +461 -0
- rocket_engine/interfaces/documents.py +92 -0
- rocket_engine/interfaces/envelopes.py +131 -0
- rocket_engine/interfaces/errors.py +16 -0
- rocket_engine/interfaces/layout.py +410 -0
- rocket_engine/interfaces/layout_schema.yaml +278 -0
- rocket_engine/interfaces/paths.py +223 -0
- rocket_engine/interfaces/pdks.py +550 -0
- rocket_engine/interfaces/ports.py +72 -0
- rocket_engine/interfaces/references.py +115 -0
- rocket_engine/interfaces/refs.py +85 -0
- rocket_engine/interfaces/runparams.py +304 -0
- rocket_engine/interfaces/setup.py +552 -0
- rocket_engine/interfaces/setup_catalogue.yaml +243 -0
- rocket_engine/interfaces/setup_probes.py +66 -0
- rocket_engine/interfaces/vocabulary.py +58 -0
- rocket_engine/interfaces/yaml_dump.py +31 -0
- rocket_engine/library/README.md +22 -0
- rocket_engine/library/__init__.py +13 -0
- rocket_engine/library/apig_catalog.py +371 -0
- rocket_engine/library/catalog.py +185 -0
- rocket_engine/library/errors.py +16 -0
- rocket_engine/mutate/__init__.py +776 -0
- rocket_engine/mutate/operators.py +700 -0
- rocket_engine/ops/__init__.py +1 -0
- rocket_engine/ops/deferred.py +279 -0
- rocket_engine/ops/editors.py +404 -0
- rocket_engine/ops/evidence.py +194 -0
- rocket_engine/ops/gates.py +262 -0
- rocket_engine/ops/ports.py +76 -0
- rocket_engine/ops/queries.py +417 -0
- rocket_engine/ops/runs.py +553 -0
- rocket_engine/ops/submit.py +614 -0
- rocket_engine/project/README.md +27 -0
- rocket_engine/project/__init__.py +6 -0
- rocket_engine/project/canvas/__init__.py +55 -0
- rocket_engine/project/canvas/compile.py +109 -0
- rocket_engine/project/canvas/integrate.py +48 -0
- rocket_engine/project/canvas/schema.py +241 -0
- rocket_engine/project/canvas/templates.py +46 -0
- rocket_engine/project/canvas/validate.py +603 -0
- rocket_engine/project/edit/__init__.py +5 -0
- rocket_engine/project/edit/cas.py +87 -0
- rocket_engine/project/edit/transactions.py +282 -0
- rocket_engine/project/errors.py +16 -0
- rocket_engine/project/frontend13.py +685 -0
- rocket_engine/project/geometry/__init__.py +23 -0
- rocket_engine/project/geometry/ops.py +451 -0
- rocket_engine/project/geometry/snap.py +103 -0
- rocket_engine/project/ip/__init__.py +1 -0
- rocket_engine/project/ip/blocks.py +195 -0
- rocket_engine/project/ip/entry.schema.json +78 -0
- rocket_engine/project/ip/lifecycle.py +402 -0
- rocket_engine/project/ip/verbs.py +123 -0
- rocket_engine/project/layers/__init__.py +6 -0
- rocket_engine/project/layers/bindings.py +115 -0
- rocket_engine/project/layers/catalog.py +228 -0
- rocket_engine/project/layers/presets.py +43 -0
- rocket_engine/project/ledger/__init__.py +1 -0
- rocket_engine/project/ledger/docs.py +167 -0
- rocket_engine/project/ledger/entities.py +176 -0
- rocket_engine/project/ledger/events.py +29 -0
- rocket_engine/project/ledger/runs.py +257 -0
- rocket_engine/project/ledger/shared.py +174 -0
- rocket_engine/project/ledger/snapshots.py +385 -0
- rocket_engine/project/ledger/wires.py +552 -0
- rocket_engine/project/process/__init__.py +14 -0
- rocket_engine/project/process/model.py +193 -0
- rocket_engine/project/process/recipes.py +121 -0
- rocket_engine/project/schematic/__init__.py +1 -0
- rocket_engine/project/schematic/hierarchy.py +312 -0
- rocket_engine/project/schematic/instances.py +393 -0
- rocket_engine/project/schematic/sheets.py +198 -0
- rocket_engine/project/service.py +2941 -0
- rocket_engine/project/symbols/__init__.py +1 -0
- rocket_engine/project/symbols/cells.py +324 -0
- rocket_engine/project/symbols/linkage.py +356 -0
- rocket_engine/project/symbols/symbols.py +352 -0
- rocket_engine/project/templates/__init__.py +303 -0
- rocket_engine/project/templates/errors.py +25 -0
- rocket_engine/project/testbench/__init__.py +49 -0
- rocket_engine/project/testbench/blocks.py +619 -0
- rocket_engine/project/testbench/templates.py +134 -0
- rocket_engine/stores/README.md +12 -0
- rocket_engine/stores/__init__.py +6 -0
- rocket_engine/stores/ecs.py +1508 -0
- rocket_engine/stores/layers.py +1023 -0
- rocket_engine/stores/settings.py +1188 -0
- rocket_engine/stores/wireplace.py +1324 -0
- rocket_engine/workflows/README.md +18 -0
- rocket_engine/workflows/__init__.py +53 -0
- rocket_engine/workflows/capability_plan.py +102 -0
- rocket_engine/workflows/completion.py +228 -0
- rocket_engine/workflows/connectgraph.py +734 -0
- rocket_engine/workflows/connectgraph_emit.py +336 -0
- rocket_engine/workflows/gates.py +144 -0
- rocket_engine/workflows/photonic_wire.py +76 -0
- rocket_engine/workflows/stages.py +324 -0
- rocket_engine/workflows/viewsync.py +399 -0
- rocket_engine-0.0.2b1.dist-info/METADATA +200 -0
- rocket_engine-0.0.2b1.dist-info/RECORD +241 -0
- rocket_engine-0.0.2b1.dist-info/WHEEL +4 -0
- rocket_engine-0.0.2b1.dist-info/entry_points.txt +2 -0
- rocket_engine-0.0.2b1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
"""Intended-vs-extracted view comparison (VIEW-SYNC, photonic P14).
|
|
2
|
+
|
|
3
|
+
`compare_views` reduces two schematics through the shared
|
|
4
|
+
CONNECT-GRAPH extraction (`prepare_netlist_structs`), correlates
|
|
5
|
+
pins through CellLink identity (never a second naming scheme),
|
|
6
|
+
and reports missing/wrong/extra ports, missing/unexpected
|
|
7
|
+
connections, and unmapped objects with per-finding identity
|
|
8
|
+
references. Every net name flows from the cited view's shared
|
|
9
|
+
`Connectivity.net_name` authority.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
|
|
14
|
+
from ..interfaces.celllink import REFERENCE, ContractError, resolve_link
|
|
15
|
+
from .connectgraph import ConnectGraphError, prepare_netlist_structs
|
|
16
|
+
|
|
17
|
+
RULE_MISSING_PORT = "view_sync.missing_port"
|
|
18
|
+
RULE_EXTRA_PORT = "view_sync.extra_port"
|
|
19
|
+
RULE_WRONG_PORT = "view_sync.wrong_port"
|
|
20
|
+
RULE_MISSING_CONNECTION = "view_sync.missing_connection"
|
|
21
|
+
RULE_UNEXPECTED_CONNECTION = "view_sync.unexpected_connection"
|
|
22
|
+
RULE_UNMAPPED = "view_sync.unmapped"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ViewSyncError(ValueError):
|
|
26
|
+
"""Bad view-sync input: malformed view or bad identity mapping."""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _identity_maps(links, variant):
|
|
30
|
+
"""Per-instance symbol-to-cell maps plus their inverses."""
|
|
31
|
+
if links is None:
|
|
32
|
+
links = []
|
|
33
|
+
if not isinstance(links, list):
|
|
34
|
+
raise ViewSyncError(f"links must be a list, got {links!r}.")
|
|
35
|
+
base_variant = variant in (None, REFERENCE)
|
|
36
|
+
if not base_variant:
|
|
37
|
+
if not isinstance(variant, str) or not variant:
|
|
38
|
+
raise ViewSyncError(
|
|
39
|
+
f"variant must be a non-empty string, got {variant!r}."
|
|
40
|
+
)
|
|
41
|
+
if not links:
|
|
42
|
+
raise ViewSyncError(f"Unknown variant {variant!r}: no links define it.")
|
|
43
|
+
forward = {}
|
|
44
|
+
for index, entry in enumerate(links):
|
|
45
|
+
if not isinstance(entry, dict):
|
|
46
|
+
raise ViewSyncError(f"links[{index}] must be a mapping, got {entry!r}.")
|
|
47
|
+
block_id = entry.get("id")
|
|
48
|
+
if not isinstance(block_id, str) or not block_id:
|
|
49
|
+
raise ViewSyncError(f"links[{index}] needs a non-empty string id.")
|
|
50
|
+
if block_id in forward:
|
|
51
|
+
raise ViewSyncError(f"Duplicate link id: {block_id!r}.")
|
|
52
|
+
block = {"id": block_id}
|
|
53
|
+
if "CellLink" in entry:
|
|
54
|
+
block["CellLink"] = entry["CellLink"]
|
|
55
|
+
try:
|
|
56
|
+
resolved = resolve_link(block, variant=variant)
|
|
57
|
+
except ContractError as exc:
|
|
58
|
+
raise ViewSyncError(f"link {block_id!r}: {exc}") from exc
|
|
59
|
+
mapping = {item["symPin"]: item["cellPin"] for item in resolved["pinMap"]}
|
|
60
|
+
targets = sorted(mapping.values())
|
|
61
|
+
if len(set(targets)) != len(targets):
|
|
62
|
+
raise ViewSyncError(
|
|
63
|
+
f"link {block_id!r}: pinMap collision: two symbol pins "
|
|
64
|
+
f"resolve to one cell pin ({', '.join(targets)})."
|
|
65
|
+
)
|
|
66
|
+
forward[block_id] = mapping
|
|
67
|
+
reverse = {
|
|
68
|
+
name: {cell: sym for sym, cell in mapping.items()}
|
|
69
|
+
for name, mapping in forward.items()
|
|
70
|
+
}
|
|
71
|
+
return forward, reverse
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _extract_side(schematic, side):
|
|
75
|
+
"""Extract one view, naming the side on failure."""
|
|
76
|
+
try:
|
|
77
|
+
return prepare_netlist_structs(schematic)
|
|
78
|
+
except ConnectGraphError as exc:
|
|
79
|
+
raise ViewSyncError(f"{side} schematic: {exc}") from exc
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _net_id_by_name(connectivity, name, side):
|
|
83
|
+
"""Net id for a port name (ports always name an extracted net)."""
|
|
84
|
+
for net in connectivity.nets:
|
|
85
|
+
if net.name == name:
|
|
86
|
+
return net.id
|
|
87
|
+
raise ViewSyncError(f"{side} port {name!r} names no extracted net.")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _port_findings(intended_structs, extracted_structs):
|
|
91
|
+
"""Missing/wrong/extra port findings with authority net names."""
|
|
92
|
+
findings = []
|
|
93
|
+
iconn = intended_structs.connectivity
|
|
94
|
+
econn = extracted_structs.connectivity
|
|
95
|
+
intended_ports = {p["name"]: p["direction"] for p in intended_structs.ports}
|
|
96
|
+
extracted_ports = {p["name"]: p["direction"] for p in extracted_structs.ports}
|
|
97
|
+
for name in sorted(set(intended_ports) - set(extracted_ports)):
|
|
98
|
+
net_id = _net_id_by_name(iconn, name, "intended")
|
|
99
|
+
findings.append(
|
|
100
|
+
{
|
|
101
|
+
"rule": RULE_MISSING_PORT,
|
|
102
|
+
"severity": "error",
|
|
103
|
+
"message": (
|
|
104
|
+
f"port {name} is missing in extracted "
|
|
105
|
+
f"(intended direction {intended_ports[name]})"
|
|
106
|
+
),
|
|
107
|
+
"view": "intended",
|
|
108
|
+
"port": name,
|
|
109
|
+
"expected_direction": intended_ports[name],
|
|
110
|
+
"net": iconn.net_name(net_id),
|
|
111
|
+
"net_id": net_id,
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
for name in sorted(set(extracted_ports) - set(intended_ports)):
|
|
115
|
+
net_id = _net_id_by_name(econn, name, "extracted")
|
|
116
|
+
findings.append(
|
|
117
|
+
{
|
|
118
|
+
"rule": RULE_EXTRA_PORT,
|
|
119
|
+
"severity": "error",
|
|
120
|
+
"message": (
|
|
121
|
+
f"port {name} is unexpected in extracted "
|
|
122
|
+
f"(direction {extracted_ports[name]})"
|
|
123
|
+
),
|
|
124
|
+
"view": "extracted",
|
|
125
|
+
"port": name,
|
|
126
|
+
"actual_direction": extracted_ports[name],
|
|
127
|
+
"net": econn.net_name(net_id),
|
|
128
|
+
"net_id": net_id,
|
|
129
|
+
}
|
|
130
|
+
)
|
|
131
|
+
for name in sorted(set(intended_ports) & set(extracted_ports)):
|
|
132
|
+
if intended_ports[name] == extracted_ports[name]:
|
|
133
|
+
continue
|
|
134
|
+
intended_id = _net_id_by_name(iconn, name, "intended")
|
|
135
|
+
extracted_id = _net_id_by_name(econn, name, "extracted")
|
|
136
|
+
findings.append(
|
|
137
|
+
{
|
|
138
|
+
"rule": RULE_WRONG_PORT,
|
|
139
|
+
"severity": "error",
|
|
140
|
+
"message": (
|
|
141
|
+
f"port {name} direction {extracted_ports[name]}, "
|
|
142
|
+
f"expected {intended_ports[name]}"
|
|
143
|
+
),
|
|
144
|
+
"view": "extracted",
|
|
145
|
+
"port": name,
|
|
146
|
+
"expected_direction": intended_ports[name],
|
|
147
|
+
"actual_direction": extracted_ports[name],
|
|
148
|
+
"net": econn.net_name(extracted_id),
|
|
149
|
+
"net_id": extracted_id,
|
|
150
|
+
"intended_net_id": intended_id,
|
|
151
|
+
"extracted_net_id": extracted_id,
|
|
152
|
+
}
|
|
153
|
+
)
|
|
154
|
+
return findings
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _correlate(intended_structs, extracted_structs, forward, reverse):
|
|
158
|
+
"""Correlate pins through CellLink identity (mapped + unmapped)."""
|
|
159
|
+
intended_by_inst = {i.name: i for i in intended_structs.instances}
|
|
160
|
+
extracted_by_inst = {i.name: i for i in extracted_structs.instances}
|
|
161
|
+
findings = []
|
|
162
|
+
for name in sorted(set(intended_by_inst) - set(extracted_by_inst)):
|
|
163
|
+
pins = sorted(p for p, _ in intended_by_inst[name].pins)
|
|
164
|
+
findings.append(
|
|
165
|
+
{
|
|
166
|
+
"rule": RULE_UNMAPPED,
|
|
167
|
+
"severity": "error",
|
|
168
|
+
"message": (
|
|
169
|
+
f"instance {name} has no extracted counterpart "
|
|
170
|
+
f"({len(pins)} pins)"
|
|
171
|
+
),
|
|
172
|
+
"view": "intended",
|
|
173
|
+
"kind": "instance",
|
|
174
|
+
"instance": name,
|
|
175
|
+
"side": "intended",
|
|
176
|
+
"pins": pins,
|
|
177
|
+
}
|
|
178
|
+
)
|
|
179
|
+
for name in sorted(set(extracted_by_inst) - set(intended_by_inst)):
|
|
180
|
+
pins = sorted(p for p, _ in extracted_by_inst[name].pins)
|
|
181
|
+
findings.append(
|
|
182
|
+
{
|
|
183
|
+
"rule": RULE_UNMAPPED,
|
|
184
|
+
"severity": "error",
|
|
185
|
+
"message": (
|
|
186
|
+
f"instance {name} has no intended counterpart "
|
|
187
|
+
f"({len(pins)} pins)"
|
|
188
|
+
),
|
|
189
|
+
"view": "extracted",
|
|
190
|
+
"kind": "instance",
|
|
191
|
+
"instance": name,
|
|
192
|
+
"side": "extracted",
|
|
193
|
+
"pins": pins,
|
|
194
|
+
}
|
|
195
|
+
)
|
|
196
|
+
mapped = []
|
|
197
|
+
for name in sorted(set(intended_by_inst) & set(extracted_by_inst)):
|
|
198
|
+
pin_map = forward.get(name, {})
|
|
199
|
+
back_map = reverse.get(name, {})
|
|
200
|
+
intended_pins = {p: n for p, n in intended_by_inst[name].pins}
|
|
201
|
+
extracted_pins = {p: n for p, n in extracted_by_inst[name].pins}
|
|
202
|
+
matched = set()
|
|
203
|
+
for sym in sorted(intended_pins):
|
|
204
|
+
cell = pin_map.get(sym, sym)
|
|
205
|
+
if cell in extracted_pins:
|
|
206
|
+
matched.add(cell)
|
|
207
|
+
mapped.append(
|
|
208
|
+
(name, sym, cell, intended_pins[sym], extracted_pins[cell])
|
|
209
|
+
)
|
|
210
|
+
continue
|
|
211
|
+
conn = intended_structs.connectivity
|
|
212
|
+
net_id = intended_pins[sym]
|
|
213
|
+
findings.append(
|
|
214
|
+
{
|
|
215
|
+
"rule": RULE_UNMAPPED,
|
|
216
|
+
"severity": "error",
|
|
217
|
+
"message": (
|
|
218
|
+
f"pin {name}.{sym} has no extracted counterpart "
|
|
219
|
+
f"(cell pin {cell})"
|
|
220
|
+
),
|
|
221
|
+
"view": "intended",
|
|
222
|
+
"kind": "pin",
|
|
223
|
+
"instance": name,
|
|
224
|
+
"pin": sym,
|
|
225
|
+
"cell_pin": cell,
|
|
226
|
+
"side": "intended",
|
|
227
|
+
"net": conn.net_name(net_id),
|
|
228
|
+
"net_id": net_id,
|
|
229
|
+
}
|
|
230
|
+
)
|
|
231
|
+
for cell in sorted(set(extracted_pins) - matched):
|
|
232
|
+
conn = extracted_structs.connectivity
|
|
233
|
+
net_id = extracted_pins[cell]
|
|
234
|
+
findings.append(
|
|
235
|
+
{
|
|
236
|
+
"rule": RULE_UNMAPPED,
|
|
237
|
+
"severity": "error",
|
|
238
|
+
"message": (
|
|
239
|
+
f"pin {name}.{cell} has no intended counterpart "
|
|
240
|
+
f"(symbol pin {back_map.get(cell, cell)})"
|
|
241
|
+
),
|
|
242
|
+
"view": "extracted",
|
|
243
|
+
"kind": "pin",
|
|
244
|
+
"instance": name,
|
|
245
|
+
"pin": cell,
|
|
246
|
+
"sym_pin": back_map.get(cell, cell),
|
|
247
|
+
"side": "extracted",
|
|
248
|
+
"net": conn.net_name(net_id),
|
|
249
|
+
"net_id": net_id,
|
|
250
|
+
}
|
|
251
|
+
)
|
|
252
|
+
return mapped, findings
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def _connection_findings(intended_structs, extracted_structs, mapped):
|
|
256
|
+
"""Split (missing) and joined (unexpected) net findings."""
|
|
257
|
+
findings = []
|
|
258
|
+
iconn = intended_structs.connectivity
|
|
259
|
+
econn = extracted_structs.connectivity
|
|
260
|
+
by_intended = {}
|
|
261
|
+
for inst, sym, cell, intended_id, extracted_id in mapped:
|
|
262
|
+
by_intended.setdefault(intended_id, []).append(
|
|
263
|
+
(inst, sym, cell, extracted_id)
|
|
264
|
+
)
|
|
265
|
+
for intended_id in sorted(by_intended):
|
|
266
|
+
members = by_intended[intended_id]
|
|
267
|
+
landed = sorted({extracted_id for (_, _, _, extracted_id) in members})
|
|
268
|
+
if len(landed) > 1:
|
|
269
|
+
split = [{"net": econn.net_name(x), "net_id": x} for x in landed]
|
|
270
|
+
pin_list = sorted(f"{i}.{s}" for (i, s, _, _) in members)
|
|
271
|
+
findings.append(
|
|
272
|
+
{
|
|
273
|
+
"rule": RULE_MISSING_CONNECTION,
|
|
274
|
+
"severity": "error",
|
|
275
|
+
"message": (
|
|
276
|
+
f"net {iconn.net_name(intended_id)} splits across "
|
|
277
|
+
f"{', '.join(s['net'] for s in split)} in extracted: "
|
|
278
|
+
+ ", ".join(pin_list)
|
|
279
|
+
),
|
|
280
|
+
"view": "intended",
|
|
281
|
+
"net": iconn.net_name(intended_id),
|
|
282
|
+
"net_id": intended_id,
|
|
283
|
+
"split_across": split,
|
|
284
|
+
"members": [
|
|
285
|
+
{"instance": i, "pin": s, "cell_pin": c}
|
|
286
|
+
for (i, s, c, _) in sorted(members)
|
|
287
|
+
],
|
|
288
|
+
}
|
|
289
|
+
)
|
|
290
|
+
by_extracted = {}
|
|
291
|
+
for inst, sym, cell, intended_id, extracted_id in mapped:
|
|
292
|
+
by_extracted.setdefault(extracted_id, []).append(
|
|
293
|
+
(inst, sym, cell, intended_id)
|
|
294
|
+
)
|
|
295
|
+
for extracted_id in sorted(by_extracted):
|
|
296
|
+
members = by_extracted[extracted_id]
|
|
297
|
+
sources = sorted({intended_id for (_, _, _, intended_id) in members})
|
|
298
|
+
if len(sources) > 1:
|
|
299
|
+
merged = [{"net": iconn.net_name(i), "net_id": i} for i in sources]
|
|
300
|
+
pin_list = sorted(f"{i}.{c}" for (i, _, c, _) in members)
|
|
301
|
+
findings.append(
|
|
302
|
+
{
|
|
303
|
+
"rule": RULE_UNEXPECTED_CONNECTION,
|
|
304
|
+
"severity": "error",
|
|
305
|
+
"message": (
|
|
306
|
+
f"net {econn.net_name(extracted_id)} joins "
|
|
307
|
+
f"{', '.join(m['net'] for m in merged)} in extracted: "
|
|
308
|
+
+ ", ".join(pin_list)
|
|
309
|
+
),
|
|
310
|
+
"view": "extracted",
|
|
311
|
+
"net": econn.net_name(extracted_id),
|
|
312
|
+
"net_id": extracted_id,
|
|
313
|
+
"merged_from": merged,
|
|
314
|
+
"members": [
|
|
315
|
+
{"instance": i, "pin": c, "sym_pin": s}
|
|
316
|
+
for (i, s, c, _) in sorted(members)
|
|
317
|
+
],
|
|
318
|
+
}
|
|
319
|
+
)
|
|
320
|
+
return findings
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def _coverage(intended_structs, extracted_structs, mapped, count):
|
|
324
|
+
"""Coverage mapping with the explicit sync statement."""
|
|
325
|
+
pinless = sum(1 for n in intended_structs.connectivity.nets if not n.pins)
|
|
326
|
+
pinless += sum(1 for n in extracted_structs.connectivity.nets if not n.pins)
|
|
327
|
+
intended_nets = len(intended_structs.connectivity.nets)
|
|
328
|
+
extracted_nets = len(extracted_structs.connectivity.nets)
|
|
329
|
+
sizes = (
|
|
330
|
+
f"{intended_nets} vs {extracted_nets} nets, {len(mapped)} mapped pins"
|
|
331
|
+
)
|
|
332
|
+
if count == 0:
|
|
333
|
+
statement = (
|
|
334
|
+
"view_sync: intended and extracted are in sync "
|
|
335
|
+
f"(0 findings, {sizes})"
|
|
336
|
+
)
|
|
337
|
+
else:
|
|
338
|
+
noun = "finding" if count == 1 else "findings"
|
|
339
|
+
statement = (
|
|
340
|
+
f"view_sync: {count} {noun}; intended vs extracted out of sync "
|
|
341
|
+
f"({sizes})"
|
|
342
|
+
)
|
|
343
|
+
return {
|
|
344
|
+
"compared_views": ["intended", "extracted"],
|
|
345
|
+
"intended_nets": intended_nets,
|
|
346
|
+
"extracted_nets": extracted_nets,
|
|
347
|
+
"mapped_pins": len(mapped),
|
|
348
|
+
"pinless_nets_skipped": pinless,
|
|
349
|
+
"statement": statement,
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def compare_views(intended, extracted, links=None, variant=None):
|
|
354
|
+
"""Diff intended vs extracted schematics over shared connectivity.
|
|
355
|
+
|
|
356
|
+
Both views reduce through CONNECT-GRAPH extraction, pins
|
|
357
|
+
correlate through CellLink identity, and ports, connections,
|
|
358
|
+
and unmapped objects diff with per-finding identity
|
|
359
|
+
references; every net name resolves through the cited view's
|
|
360
|
+
`Connectivity.net_name` authority.
|
|
361
|
+
|
|
362
|
+
Args:
|
|
363
|
+
intended: Intended-view schematic record (symbol-pin space;
|
|
364
|
+
see workflows.connectgraph for the shape).
|
|
365
|
+
extracted: Extracted-view schematic record (cell-pin space).
|
|
366
|
+
links: CellLink block links ([{id, CellLink?}]) mapping
|
|
367
|
+
intended symbol pins to extracted cell pins; None or []
|
|
368
|
+
correlates by identity.
|
|
369
|
+
variant: Variant selector applied to every link; None and
|
|
370
|
+
REFERENCE resolve each stored base link.
|
|
371
|
+
|
|
372
|
+
Returns:
|
|
373
|
+
Mapping with findings (sorted by rule, deterministic),
|
|
374
|
+
coverage (compared views, net counts, mapped pins,
|
|
375
|
+
pinless skips, statement), and a text report.
|
|
376
|
+
|
|
377
|
+
Raises:
|
|
378
|
+
ViewSyncError: Malformed schematic (naming its side),
|
|
379
|
+
malformed links, an unknown variant, or a pinMap
|
|
380
|
+
collision.
|
|
381
|
+
|
|
382
|
+
Caution: Optical view comparison, never transistor LVS —
|
|
383
|
+
findings judge connectivity sync only, not device
|
|
384
|
+
equivalence.
|
|
385
|
+
"""
|
|
386
|
+
forward, reverse = _identity_maps(links, variant)
|
|
387
|
+
intended_structs = _extract_side(intended, "intended")
|
|
388
|
+
extracted_structs = _extract_side(extracted, "extracted")
|
|
389
|
+
mapped, unmapped = _correlate(
|
|
390
|
+
intended_structs, extracted_structs, forward, reverse
|
|
391
|
+
)
|
|
392
|
+
findings = _port_findings(intended_structs, extracted_structs)
|
|
393
|
+
findings.extend(unmapped)
|
|
394
|
+
findings.extend(_connection_findings(intended_structs, extracted_structs, mapped))
|
|
395
|
+
findings.sort(key=lambda f: (f["rule"], json.dumps(f, sort_keys=True)))
|
|
396
|
+
coverage = _coverage(intended_structs, extracted_structs, mapped, len(findings))
|
|
397
|
+
lines = [coverage["statement"]]
|
|
398
|
+
lines.extend(f"- [{f['rule']}] {f['message']}" for f in findings)
|
|
399
|
+
return {"findings": findings, "coverage": coverage, "report": "\n".join(lines)}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: rocket-engine
|
|
3
|
+
Version: 0.0.2b1
|
|
4
|
+
Summary: Shared tooling engine used by the RocketEDA IDE (manual actions and MCP invoke the same operations).
|
|
5
|
+
License: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Classifier: Development Status :: 4 - Beta
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: Intended Audience :: Science/Research
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)
|
|
14
|
+
Requires-Python: >=3.12
|
|
15
|
+
Requires-Dist: amaranth>=0.5.10
|
|
16
|
+
Requires-Dist: anyio>=4.0
|
|
17
|
+
Requires-Dist: cace==2.13.0
|
|
18
|
+
Requires-Dist: circulax
|
|
19
|
+
Requires-Dist: cocotb>=1.9
|
|
20
|
+
Requires-Dist: devsim==2.11.2
|
|
21
|
+
Requires-Dist: fastapi>=0.115
|
|
22
|
+
Requires-Dist: gdsfactory<10,>=9.51
|
|
23
|
+
Requires-Dist: gplugins<3,>=2.1
|
|
24
|
+
Requires-Dist: httpx>=0.27
|
|
25
|
+
Requires-Dist: jsonschema>=4.0
|
|
26
|
+
Requires-Dist: matplotlib>=3.8
|
|
27
|
+
Requires-Dist: mcp<3,>=1.0
|
|
28
|
+
Requires-Dist: meow-sim>=0.15
|
|
29
|
+
Requires-Dist: pydantic>=2.0
|
|
30
|
+
Requires-Dist: pyslang>=12.1.0
|
|
31
|
+
Requires-Dist: pyspice>=1.5
|
|
32
|
+
Requires-Dist: pywellen>=0.25.7
|
|
33
|
+
Requires-Dist: pyyaml>=6
|
|
34
|
+
Requires-Dist: ruamel-yaml>=0.18
|
|
35
|
+
Requires-Dist: sax>=0.18
|
|
36
|
+
Requires-Dist: scikit-rf>=1.0
|
|
37
|
+
Requires-Dist: uvicorn>=0.30
|
|
38
|
+
Requires-Dist: vlsirtools>=7.0.0
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
|
|
41
|
+
<p align="center">
|
|
42
|
+
<img src=".github/assets/rocketide-logo.svg" width="72" height="72" alt="RocketIDE logo">
|
|
43
|
+
</p>
|
|
44
|
+
|
|
45
|
+
<h1 align="center">rocket-engine</h1>
|
|
46
|
+
|
|
47
|
+
<p align="center"><sub>Part of <a href="https://github.com/Team-RocketEDA/RocketIDE"><b>RocketIDE</b></a> · the engine</sub></p>
|
|
48
|
+
|
|
49
|
+
`rocket-engine` is RocketEDA's headless Python engine for chip-design projects. It owns the shared operation surface, project revisions and events, tool dispatch, capability reporting, and verification evidence used by manual clients and the agent harness.
|
|
50
|
+
|
|
51
|
+
The product serves digital, analog, photonic, and mixed-domain work. The engine coordinates existing EDA tools through adapters; it does not implement an agent loop or physics solvers. Product direction lives in the sibling [PRD](../PRD/README.md). The agent harness is in [rocket_fuel](../rocket_fuel/README.md), the current workbench is in [UIUX](../UIUX/README.md), and [RocketIDE](../RocketIDE/README.md) is the planned packaging layer.
|
|
52
|
+
|
|
53
|
+
## Requirements
|
|
54
|
+
|
|
55
|
+
<!-- REQUIREMENTS:START -->
|
|
56
|
+
pip ships the engine, not the tools. Native binaries, PDK trees,
|
|
57
|
+
and cloud keys arrive via provision recipes, your own PATH, or
|
|
58
|
+
explicit opt-in. The engine resolves provisioned roots first, then
|
|
59
|
+
ambient PATH, then per-job `tool_dir`; `report_capabilities` tells
|
|
60
|
+
you exactly what resolved and the remedy for what did not.
|
|
61
|
+
|
|
62
|
+
### Native tools (provision or PATH)
|
|
63
|
+
|
|
64
|
+
| Capability | Provides | How to get it |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| Digital bundle (oss-cad-suite) | `iverilog`, `vvp`, `verilator`, `slang`, `yosys`, `ghdl`, `sby` | scripts/provision_toolchain.sh: pinned tarball 20261025 + asserts (PROV phase 1). |
|
|
67
|
+
| LibreLane (RTL-to-GDS flow) | `librelane` | scripts/provision_toolchain.sh (PROV phase 1; upstream AppImage/Nix install docs). |
|
|
68
|
+
| OpenSTA (static timing) | `sta` | scripts/provision_toolchain.sh (PROV phase 1; upstream OpenSTA README source build). |
|
|
69
|
+
| ngspice (SPICE) | `ngspice` | docs/provision-plan.md: apt pin or source build (B10). |
|
|
70
|
+
| Netgen (LVS) | `netgen` | docs/tickets/NGSPICE-LIVE.md: opencircuitdesign source build (B10). |
|
|
71
|
+
| Magic (DRC + extraction) | `magic` | docs/provision-plan.md: source build with --prefix into the app-owned tools dir (B10). |
|
|
72
|
+
| KLayout (batch DRC) | `klayout` | docs/provision-plan.md: ambient install kept and version-asserted (B10). |
|
|
73
|
+
| Xyce (parallel SPICE) | `Xyce` | scripts/provision_toolchain.sh (PROV phase 2; Xyce building guide recipe). |
|
|
74
|
+
| Xschem (schematic) | `xschem` | scripts/provision_toolchain.sh (PROV phase 2; upstream xschem source build). |
|
|
75
|
+
| Bubblewrap (isolation) | `bwrap` | docs/probe-bwrap-isolation.md (B10). |
|
|
76
|
+
| cvc (SMT solvers) | `cvc4`, `cvc5` | scripts/provision_toolchain.sh: pinned tarball 20261025 ships cvc4/cvc5 (PROV phase 1). |
|
|
77
|
+
| OpenROAD | `openroad` | scripts/provision_toolchain.sh (PROV phase 1; LibreLane closure ships openroad). |
|
|
78
|
+
| openEMS (EC-FDTD) | `openEMS` | scripts/provision_toolchain.sh (PROV-DEFERRED; docs.openEMS.de recipe). |
|
|
79
|
+
| Elmer (thermal/FEM) | `ElmerSolver` | scripts/provision_toolchain.sh (PROV-DEFERRED; CSC PPA apt route). |
|
|
80
|
+
| Palace (full-wave FEM) | `palace` | docs/provision-sources.md §12 (unsourced — no recipe yet). |
|
|
81
|
+
|
|
82
|
+
### Python libraries (ride the wheel)
|
|
83
|
+
|
|
84
|
+
| Capability | Provides | How to get it |
|
|
85
|
+
|---|---|---|
|
|
86
|
+
| CACE (characterization) | `cace` | scripts/provision_toolchain.sh (PROV phase 2; pip into the engine venv). |
|
|
87
|
+
| SAX (photonic sim) | `sax` | pyproject.toml [project] dependencies: plain `uv sync` installs everything (core library). |
|
|
88
|
+
| Circulax (time-domain circuit sim) | `circulax` | pyproject.toml [project] dependencies: plain `uv sync` installs everything (core library). |
|
|
89
|
+
| Meow (EME mode/field solver) | `meow` | pyproject.toml [project] dependencies: plain `uv sync` installs everything (core library). |
|
|
90
|
+
| gdsfactory (layout views) | `gdsfactory` | pyproject.toml [project] dependencies: plain `uv sync` installs everything (core library). |
|
|
91
|
+
| pymeep (FDTD) | `meep` | scripts/provision_toolchain.sh (PROV-DEFERRED; conda-forge pymeep env). |
|
|
92
|
+
| DEVSIM (TCAD) | `devsim` | scripts/provision_toolchain.sh (PROV-DEFERRED; pip into the engine venv). |
|
|
93
|
+
|
|
94
|
+
### PDKs (registered trees, never in the wheel)
|
|
95
|
+
|
|
96
|
+
| Capability | Provides | How to get it |
|
|
97
|
+
|---|---|---|
|
|
98
|
+
| PDK sky130A | `sky130A` + 4 decks | scripts/install.sh --pdk-only (PDK_SOURCE/PDK_ID/PDK_REVISION; see docs/demo-runbook.md). |
|
|
99
|
+
| PDK ihp (IHP SG13G2 BiCMOS + RF) | `ihp` + 1 decks | docs/pdk/ihp/recipe.md (PDK-IHP lane). |
|
|
100
|
+
|
|
101
|
+
### Cloud (opt-in only, never default)
|
|
102
|
+
|
|
103
|
+
| Capability | Provides | How to get it |
|
|
104
|
+
|---|---|---|
|
|
105
|
+
| Tidy3D web (cloud) | BYOC: tidy3d web | CLOUD-AUTH (Backlog): OS keyring preferred, encrypted file fallback. |
|
|
106
|
+
| GDSFactory+ (cloud) | BYOC: gdsfactory+ | CLOUD-AUTH (Backlog): OS keyring preferred, encrypted file fallback. |
|
|
107
|
+
<!-- REQUIREMENTS:END -->
|
|
108
|
+
|
|
109
|
+
## Current shape
|
|
110
|
+
|
|
111
|
+
- `src/` is the package root and installs as `rocket_engine`.
|
|
112
|
+
- `composition.py` is the composition root. It binds project and execution services, operation/query handlers, and solver adapters.
|
|
113
|
+
- Transports use the same operation vocabulary. The live CLI and MCP server are implemented. HTTP and IPC currently provide JSON envelope handlers; listening servers, SSE delivery, and length-prefixed IPC framing are not implemented here.
|
|
114
|
+
- Project mutations are revision-gated and actor-attributed. A durable project ledger is available when an engine root is configured; an engine without one keeps project state in memory.
|
|
115
|
+
- Engine `submit` runs normal solver operations inline and returns their completion. `run_job` remains the explicit deferred/batch pump and idempotent completion fetch.
|
|
116
|
+
- Tool registration describes what the engine can route. Machine-specific availability and PDK/deck readiness come from `get_capabilities`; registration alone does not mean a flow is qualified or installed.
|
|
117
|
+
|
|
118
|
+
## Architecture
|
|
119
|
+
|
|
120
|
+
```text
|
|
121
|
+
UI / CLI / Rocket Fuel
|
|
122
|
+
│
|
|
123
|
+
adapters/{http,ipc,mcp,cli}
|
|
124
|
+
│ commands and queries
|
|
125
|
+
composition.Engine
|
|
126
|
+
├── project/ revisions, documents, components, events
|
|
127
|
+
├── execution/ dispatch, isolation, run state, verdicts
|
|
128
|
+
├── library/ PDK and cell catalogs
|
|
129
|
+
└── workflows/ D/A/P/M check plans and completion gates
|
|
130
|
+
│
|
|
131
|
+
adapters/<solver> ──> native EDA tools and Python libraries
|
|
132
|
+
│
|
|
133
|
+
normalized findings, measurements, artifacts
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`interfaces/` defines the shared vocabulary, data shapes, and ports. Transport adapters translate client requests into engine calls. Solver adapters preflight project inputs, invoke tools, and normalize their output. The engine evaluates findings and publishes project events; transports do not own verification rules.
|
|
137
|
+
|
|
138
|
+
| Module | Responsibility |
|
|
139
|
+
|---|---|
|
|
140
|
+
| [`src/interfaces/`](src/interfaces/README.md) | Operation/query vocabulary, contracts, ports, path and design-data types |
|
|
141
|
+
| [`src/project/`](src/project/README.md) | Revision-gated documents, ECS components, snapshots, and event ledger |
|
|
142
|
+
| [`src/execution/`](src/execution/README.md) | Run lifecycle, bounded dispatch, isolation, Python execution approvals, and verdicts |
|
|
143
|
+
| [`src/library/`](src/library/README.md) | PDK registration/readiness and reusable cell catalogs |
|
|
144
|
+
| [`src/workflows/`](src/workflows/README.md) | Digital, analog, photonic, and mixed-domain stage plans and completion checks |
|
|
145
|
+
| [`src/adapters/`](src/adapters/README.md) | CLI, MCP, HTTP/IPC envelope handlers, and solver integrations |
|
|
146
|
+
|
|
147
|
+
## Registered solver operations
|
|
148
|
+
|
|
149
|
+
| Operations | Adapter(s) |
|
|
150
|
+
|---|---|
|
|
151
|
+
| `run_drc` | Magic (default), KLayout |
|
|
152
|
+
| `run_hdl_test`, `run_syntax`, `run_formal`, `run_synth`, `run_timing` | Icarus, Slang, SBY, Yosys, OpenSTA |
|
|
153
|
+
| `run_spice`, `run_post_layout`, `run_cosim` | ngspice; co-simulation also uses Icarus |
|
|
154
|
+
| `run_optical`, `run_em` | SAX/Circulax, MEOW |
|
|
155
|
+
| `run_extraction`, `run_lvs` | Magic, Netgen |
|
|
156
|
+
| `run_connectivity`, `run_erc`, `run_view_sync` | connectgraph |
|
|
157
|
+
| `generate_views` | GDSFactory |
|
|
158
|
+
| `run_digital_flow` | LibreLane |
|
|
159
|
+
|
|
160
|
+
This is a routing map, not a support guarantee. Consult `get_capabilities` for installed tools, profiles, PDKs, and decks. The LibreLane adapter is registered and has hermetic coverage; its live RTL-to-GDS qualification is currently blocked on the pinned LibreLane distribution and a compatible PDK root. See the [DIGITAL-FLOW report](docs/work/DIGITAL-FLOW/report.md) and the [sprint board](docs/sprint-board.md) for current work status.
|
|
161
|
+
|
|
162
|
+
## API contract
|
|
163
|
+
|
|
164
|
+
**Next implementation contract:** the [v1 contract bundle](contracts/README.md)
|
|
165
|
+
freezes six methods (`describe`, `query`, `edit`, `run`, `script`, `watch`),
|
|
166
|
+
typed editors/components/testbenches, tool tasks and `canvas.toml`.
|
|
167
|
+
It includes generated client types/help and validated examples. Provider and
|
|
168
|
+
consumer migration is pending; the current running API below is v0.
|
|
169
|
+
[ADR-014](docs/adr/014-contract-first-editor-and-tool-api.md) records the
|
|
170
|
+
supersession and deployment gates. Check the design contract with
|
|
171
|
+
`.venv/bin/python scripts/check_v1_contract.py`.
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
The operation and query vocabulary is in [`src/interfaces/vocabulary.py`](src/interfaces/vocabulary.py). Handler docstrings are the source for the generated [`docs/engine-api.md`](docs/engine-api.md), [`docs/api-schema.json`](docs/api-schema.json), and [`docs/api-help.json`](docs/api-help.json). Do not hand-edit those generated files; regenerate them with `scripts/api_spec.py --write`.
|
|
175
|
+
|
|
176
|
+
Every accepted mutation checks `expected_revision`, advances the project revision, and records its actor. A stale revision returns `revision_conflict`; callers re-read and retry. Run verdicts are engine-owned. Exit status and tool process output alone never establish PASS.
|
|
177
|
+
|
|
178
|
+
The current MCP bridge derives descriptions from handler docstrings. Its wire input schemas are still generic for most tools; only `python_execute` currently has a specific schema. See [MCP-SCHEMA](docs/tickets/MCP-SCHEMA.md).
|
|
179
|
+
|
|
180
|
+
## Setup and common commands
|
|
181
|
+
|
|
182
|
+
Use the repository installer as the only supported Python environment setup. It creates the pinned Python 3.12 environment, installs the base and development dependencies, installs a sealed engine copy, registers the configured PDK, and probes selected host tools.
|
|
183
|
+
|
|
184
|
+
```sh
|
|
185
|
+
scripts/install.sh --install
|
|
186
|
+
.venv/bin/python -m rocket_engine --help
|
|
187
|
+
scripts/install.sh --check-only
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Native tool provisioning is documented in [`docs/provision-plan.md`](docs/provision-plan.md) and managed by `scripts/provision_toolchain.sh`. `get_capabilities` reports what is usable on the current machine. After editing `src/`, rerun `scripts/install.sh --install` so the sealed package matches the source tree.
|
|
191
|
+
|
|
192
|
+
For operation docstring and generated-contract conventions, read [`AGENTS.md`](AGENTS.md). It also documents the test and fixture workflow. The [scenario guide](scenarios/README.md) describes live-tool prerequisites and the scenario CLI.
|
|
193
|
+
|
|
194
|
+
## Where to look next
|
|
195
|
+
|
|
196
|
+
- Project requirements and decisions: [`../PRD/README.md`](../PRD/README.md)
|
|
197
|
+
- Current engine work and open tickets: [`docs/sprint-board.md`](docs/sprint-board.md), [`docs/tickets/`](docs/tickets/)
|
|
198
|
+
- Fuel integration contract: [`docs/fuel-contract.md`](docs/fuel-contract.md)
|
|
199
|
+
- Generated engine API: [`docs/engine-api.md`](docs/engine-api.md)
|
|
200
|
+
- Storage ownership: [`docs/storage-policy.md`](docs/storage-policy.md) and [`docs/adr/`](docs/adr/README.md)
|