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,336 @@
|
|
|
1
|
+
"""Raw-IR netlist emitters (CONNECT-GRAPH): SPICE, Verilog, VHDL.
|
|
2
|
+
|
|
3
|
+
`to_raw_ir` resolves one language-neutral record from extracted
|
|
4
|
+
structs — pins to canonical net names through `Connectivity.net_name`
|
|
5
|
+
plus the 4-level format chain — and each printer only arranges raw
|
|
6
|
+
lines and runs its small textual post-pass. Emitters never walk the
|
|
7
|
+
graph: they accept raw-IR mappings only. Bus expansion and line
|
|
8
|
+
joinery each live in exactly one shared helper.
|
|
9
|
+
|
|
10
|
+
Format chain, first non-empty template wins:
|
|
11
|
+
|
|
12
|
+
- instance_custom: instance `custom[language]`.
|
|
13
|
+
- symbol_custom: symbol `custom[language]`.
|
|
14
|
+
- instance_format: instance `format[language]`.
|
|
15
|
+
- symbol_format: symbol `format[language]`.
|
|
16
|
+
|
|
17
|
+
Templates substitute {name}, {symbol}, {cell}, {pins[PIN]},
|
|
18
|
+
{pin_nets} (pin-order nets, space-joined), and {generics[KEY]}.
|
|
19
|
+
Custom lines emit verbatim after substitution; format lines also run
|
|
20
|
+
the language post-pass. An instance with no template at any level is
|
|
21
|
+
skipped silently; a present-but-broken template raises loudly.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
import re
|
|
25
|
+
|
|
26
|
+
from .connectgraph import ConnectGraphError
|
|
27
|
+
|
|
28
|
+
RAW_IR_VERSION = 1
|
|
29
|
+
|
|
30
|
+
LANGUAGES = ("spice", "verilog", "vhdl")
|
|
31
|
+
|
|
32
|
+
FORMAT_LEVELS = (
|
|
33
|
+
"instance_custom",
|
|
34
|
+
"symbol_custom",
|
|
35
|
+
"instance_format",
|
|
36
|
+
"symbol_format",
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
_VHDL_DIRECTIONS = {"input": "in", "output": "out", "inout": "inout"}
|
|
40
|
+
_BUS_RE = re.compile(r"^(?P<base>.+)\[(?P<bit>\d+)\]$")
|
|
41
|
+
_SPICE_WIDTH = 80
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def resolve_format(instance, symbol, language):
|
|
45
|
+
"""Resolve one instance template through the 4-level chain.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
instance: Instance mapping with custom/format mappings.
|
|
49
|
+
symbol: Symbol mapping with custom/format mappings.
|
|
50
|
+
language: One of spice, verilog, vhdl.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
(level, template) with level from FORMAT_LEVELS, or
|
|
54
|
+
(None, None) when no level carries a template.
|
|
55
|
+
"""
|
|
56
|
+
candidates = (
|
|
57
|
+
("instance_custom", (instance.get("custom") or {}).get(language)),
|
|
58
|
+
("symbol_custom", (symbol.get("custom") or {}).get(language)),
|
|
59
|
+
("instance_format", (instance.get("format") or {}).get(language)),
|
|
60
|
+
("symbol_format", (symbol.get("format") or {}).get(language)),
|
|
61
|
+
)
|
|
62
|
+
for level, template in candidates:
|
|
63
|
+
if template:
|
|
64
|
+
return (level, template)
|
|
65
|
+
return (None, None)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def to_raw_ir(structs):
|
|
69
|
+
"""Build the language-neutral raw IR from extracted structs.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
structs: NetlistStructs from prepare_netlist_structs.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
Plain-data mapping (JSON-safe) with cell, nets, ports,
|
|
76
|
+
instances carrying per-language lines, and skipped names.
|
|
77
|
+
|
|
78
|
+
Raises:
|
|
79
|
+
ConnectGraphError: Broken template at a resolved level.
|
|
80
|
+
"""
|
|
81
|
+
connectivity = structs.connectivity
|
|
82
|
+
nets = [{"id": net.id, "name": connectivity.net_name(net.id)} for net in connectivity.nets]
|
|
83
|
+
nets.sort(key=lambda n: n["name"])
|
|
84
|
+
instances = []
|
|
85
|
+
skipped = []
|
|
86
|
+
for resolved in structs.instances:
|
|
87
|
+
symbol = structs.symbols[resolved.symbol]
|
|
88
|
+
pin_nets = {
|
|
89
|
+
pin: connectivity.net_name(net_id) for pin, net_id in resolved.pins
|
|
90
|
+
}
|
|
91
|
+
namespace = {
|
|
92
|
+
"name": resolved.name,
|
|
93
|
+
"symbol": resolved.symbol,
|
|
94
|
+
"cell": structs.cell,
|
|
95
|
+
"pins": pin_nets,
|
|
96
|
+
"pin_nets": " ".join(
|
|
97
|
+
pin_nets[pin] for pin, _ in resolved.pins
|
|
98
|
+
),
|
|
99
|
+
"generics": dict(resolved.generics),
|
|
100
|
+
}
|
|
101
|
+
lines = {}
|
|
102
|
+
resolutions = {}
|
|
103
|
+
view = {"custom": resolved.custom, "format": resolved.format}
|
|
104
|
+
for language in LANGUAGES:
|
|
105
|
+
level, template = resolve_format(view, symbol, language)
|
|
106
|
+
if level is None:
|
|
107
|
+
continue
|
|
108
|
+
try:
|
|
109
|
+
lines[language] = [template.format(**namespace)]
|
|
110
|
+
except (KeyError, IndexError, ValueError) as exc:
|
|
111
|
+
raise ConnectGraphError(
|
|
112
|
+
f"Instance {resolved.name}: broken {language} template "
|
|
113
|
+
f"at {level}: {exc}."
|
|
114
|
+
) from exc
|
|
115
|
+
resolutions[language] = level
|
|
116
|
+
if not resolutions:
|
|
117
|
+
skipped.append(resolved.name)
|
|
118
|
+
continue
|
|
119
|
+
instances.append(
|
|
120
|
+
{
|
|
121
|
+
"name": resolved.name,
|
|
122
|
+
"symbol": resolved.symbol,
|
|
123
|
+
"pins": [
|
|
124
|
+
{"pin": pin, "net": connectivity.net_name(net_id)}
|
|
125
|
+
for pin, net_id in resolved.pins
|
|
126
|
+
],
|
|
127
|
+
"generics": dict(resolved.generics),
|
|
128
|
+
"levels": resolutions,
|
|
129
|
+
"lines": lines,
|
|
130
|
+
}
|
|
131
|
+
)
|
|
132
|
+
instances.sort(key=lambda i: i["name"])
|
|
133
|
+
return {
|
|
134
|
+
"tool": "connectgraph",
|
|
135
|
+
"raw_ir_version": RAW_IR_VERSION,
|
|
136
|
+
"cell": structs.cell,
|
|
137
|
+
"nets": nets,
|
|
138
|
+
"ports": [dict(p) for p in structs.ports],
|
|
139
|
+
"instances": instances,
|
|
140
|
+
"skipped": sorted(skipped),
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def emit_netlists(raw_ir, languages=None):
|
|
145
|
+
"""Emit netlists for the requested languages.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
raw_ir: Raw-IR mapping from to_raw_ir.
|
|
149
|
+
languages: Subset of spice/verilog/vhdl; all when omitted.
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
Mapping of language to netlist text.
|
|
153
|
+
|
|
154
|
+
Raises:
|
|
155
|
+
ConnectGraphError: Unknown language requested.
|
|
156
|
+
"""
|
|
157
|
+
wanted = list(LANGUAGES) if languages is None else list(languages)
|
|
158
|
+
unknown = [language for language in wanted if language not in LANGUAGES]
|
|
159
|
+
if unknown:
|
|
160
|
+
raise ConnectGraphError(f"Unknown netlist language(s): {', '.join(unknown)}.")
|
|
161
|
+
printers = {"spice": emit_spice, "verilog": emit_verilog, "vhdl": emit_vhdl}
|
|
162
|
+
return {language: printers[language](raw_ir) for language in wanted}
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def emit_spice(raw_ir):
|
|
166
|
+
"""Print the SPICE netlist: subckt frame plus raw instance lines.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
raw_ir: Raw-IR mapping from to_raw_ir.
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
Byte-stable SPICE netlist text ending in one newline.
|
|
173
|
+
"""
|
|
174
|
+
_check_raw_ir(raw_ir)
|
|
175
|
+
ports = " ".join(p["name"] for p in raw_ir["ports"])
|
|
176
|
+
header = f".subckt {raw_ir['cell']}" + (f" {ports}" if ports else "")
|
|
177
|
+
body = []
|
|
178
|
+
for instance in raw_ir["instances"]:
|
|
179
|
+
for line in instance["lines"].get("spice", []):
|
|
180
|
+
if instance["levels"]["spice"] in ("instance_format", "symbol_format"):
|
|
181
|
+
body.extend(_wrap_continuation(line, _SPICE_WIDTH, "+"))
|
|
182
|
+
else:
|
|
183
|
+
body.append(line)
|
|
184
|
+
return _join_block(
|
|
185
|
+
f"* {raw_ir['cell']} - generated by connectgraph raw IR (do not edit)",
|
|
186
|
+
[header, *body, f".ends {raw_ir['cell']}"],
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def emit_verilog(raw_ir):
|
|
191
|
+
"""Print the Verilog netlist: module frame plus raw instances.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
raw_ir: Raw-IR mapping from to_raw_ir.
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
Byte-stable Verilog netlist text ending in one newline.
|
|
198
|
+
"""
|
|
199
|
+
_check_raw_ir(raw_ir)
|
|
200
|
+
decls = _verilog_port_decls(raw_ir["ports"])
|
|
201
|
+
header = f"module {raw_ir['cell']} ({', '.join(decls)});"
|
|
202
|
+
wires = _bus_declarations(
|
|
203
|
+
[n["name"] for n in raw_ir["nets"]],
|
|
204
|
+
{p["name"] for p in raw_ir["ports"]},
|
|
205
|
+
scalar="wire {name};",
|
|
206
|
+
vector="wire [{hi}:{lo}] {base};",
|
|
207
|
+
)
|
|
208
|
+
body = []
|
|
209
|
+
for instance in raw_ir["instances"]:
|
|
210
|
+
body.extend(instance["lines"].get("verilog", []))
|
|
211
|
+
return _join_block(
|
|
212
|
+
f"// {raw_ir['cell']} - generated by connectgraph raw IR (do not edit)",
|
|
213
|
+
[header, *wires, *body, "endmodule"],
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def emit_vhdl(raw_ir):
|
|
218
|
+
"""Print the VHDL netlist: entity plus raw port-map instances.
|
|
219
|
+
|
|
220
|
+
Args:
|
|
221
|
+
raw_ir: Raw-IR mapping from to_raw_ir.
|
|
222
|
+
|
|
223
|
+
Returns:
|
|
224
|
+
Byte-stable VHDL netlist text ending in one newline.
|
|
225
|
+
"""
|
|
226
|
+
_check_raw_ir(raw_ir)
|
|
227
|
+
ports = "; ".join(
|
|
228
|
+
f"{p['name']} : {_VHDL_DIRECTIONS[p['direction']]} std_logic"
|
|
229
|
+
for p in raw_ir["ports"]
|
|
230
|
+
)
|
|
231
|
+
signals = _bus_declarations(
|
|
232
|
+
[n["name"] for n in raw_ir["nets"]],
|
|
233
|
+
{p["name"] for p in raw_ir["ports"]},
|
|
234
|
+
scalar="signal {name} : std_logic;",
|
|
235
|
+
vector="signal {base} : std_logic_vector({hi} downto {lo});",
|
|
236
|
+
)
|
|
237
|
+
body = []
|
|
238
|
+
for instance in raw_ir["instances"]:
|
|
239
|
+
body.extend(instance["lines"].get("vhdl", []))
|
|
240
|
+
return _join_block(
|
|
241
|
+
f"-- {raw_ir['cell']} - generated by connectgraph raw IR (do not edit)",
|
|
242
|
+
[
|
|
243
|
+
"library ieee;",
|
|
244
|
+
"use ieee.std_logic_1164.all;",
|
|
245
|
+
f"entity {raw_ir['cell']} is",
|
|
246
|
+
f"port ({ports});" if ports else "port ();",
|
|
247
|
+
f"end entity {raw_ir['cell']};",
|
|
248
|
+
f"architecture raw of {raw_ir['cell']} is",
|
|
249
|
+
*signals,
|
|
250
|
+
"begin",
|
|
251
|
+
*body,
|
|
252
|
+
f"end architecture raw;",
|
|
253
|
+
],
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def _check_raw_ir(raw_ir):
|
|
258
|
+
if (
|
|
259
|
+
not isinstance(raw_ir, dict)
|
|
260
|
+
or raw_ir.get("raw_ir_version") != RAW_IR_VERSION
|
|
261
|
+
or not isinstance(raw_ir.get("instances"), list)
|
|
262
|
+
):
|
|
263
|
+
raise ConnectGraphError(
|
|
264
|
+
"Emitters accept raw-IR mappings from to_raw_ir only."
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def _join_block(comment, lines):
|
|
269
|
+
return comment + "\n" + "\n".join(lines) + "\n"
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def _wrap_continuation(line, width, marker):
|
|
273
|
+
"""Wrap one line with continuation markers (the line joinery)."""
|
|
274
|
+
if len(line) <= width:
|
|
275
|
+
return [line]
|
|
276
|
+
words = line.split(" ")
|
|
277
|
+
chunks = [words[0]]
|
|
278
|
+
for word in words[1:]:
|
|
279
|
+
if len(chunks[-1]) + 1 + len(word) > width and chunks[-1]:
|
|
280
|
+
chunks.append(marker + word)
|
|
281
|
+
else:
|
|
282
|
+
chunks[-1] = chunks[-1] + " " + word if chunks[-1] else word
|
|
283
|
+
fixed = []
|
|
284
|
+
for chunk in chunks[1:]:
|
|
285
|
+
fixed.append(chunk if chunk.startswith(marker) else marker + chunk)
|
|
286
|
+
return [chunks[0], *fixed]
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def _bus_groups(names, ports):
|
|
290
|
+
"""Expand bus-bit names into one declaration group each.
|
|
291
|
+
|
|
292
|
+
Scalars yield ("scalar", name); bits base[i] fold into one
|
|
293
|
+
("vector", base, lo, hi). Groups fully covered by ports are
|
|
294
|
+
dropped — the port header already declares them.
|
|
295
|
+
"""
|
|
296
|
+
bits = {}
|
|
297
|
+
scalars = set()
|
|
298
|
+
for name in names:
|
|
299
|
+
match = _BUS_RE.match(name)
|
|
300
|
+
if match:
|
|
301
|
+
bits.setdefault(match.group("base"), []).append(
|
|
302
|
+
(int(match.group("bit")), name)
|
|
303
|
+
)
|
|
304
|
+
else:
|
|
305
|
+
scalars.add(name)
|
|
306
|
+
groups = []
|
|
307
|
+
for base in sorted(set(bits) | scalars):
|
|
308
|
+
if base in scalars and base not in bits:
|
|
309
|
+
if base not in ports:
|
|
310
|
+
groups.append(("scalar", base))
|
|
311
|
+
continue
|
|
312
|
+
member_names = [name for _, name in bits.get(base, [])]
|
|
313
|
+
if member_names and all(name in ports for name in member_names):
|
|
314
|
+
continue
|
|
315
|
+
lo = min(bit for bit, _ in bits[base])
|
|
316
|
+
hi = max(bit for bit, _ in bits[base])
|
|
317
|
+
groups.append(("vector", base, lo, hi))
|
|
318
|
+
return groups
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def _bus_declarations(names, ports, scalar, vector):
|
|
322
|
+
"""Declare nets once: scalars flat, bus bits as one vector."""
|
|
323
|
+
declarations = []
|
|
324
|
+
for group in _bus_groups(names, ports):
|
|
325
|
+
if group[0] == "scalar":
|
|
326
|
+
declarations.append(scalar.format(name=group[1]))
|
|
327
|
+
else:
|
|
328
|
+
declarations.append(
|
|
329
|
+
vector.format(base=group[1], hi=group[3], lo=group[2])
|
|
330
|
+
)
|
|
331
|
+
return declarations
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def _verilog_port_decls(ports):
|
|
335
|
+
kinds = {"input": "input", "output": "output", "inout": "inout"}
|
|
336
|
+
return [f"{kinds[p['direction']]} {p['name']}" for p in ports]
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""Target+canvas gating over a flow plan (WIRE-DECLARED-OPS MC-25).
|
|
2
|
+
|
|
3
|
+
`plan_checks_report` plans a flow against backends only; this
|
|
4
|
+
module scopes that plan to a v1 target and canvas without
|
|
5
|
+
changing readiness. Every stage names its deck tools (joined
|
|
6
|
+
through the stages DECKS table), the canvas tool settings for
|
|
7
|
+
those tools, and the project-top metric budgets it must
|
|
8
|
+
satisfy — cost (settings) and evidence travel with the plan.
|
|
9
|
+
Constraints naming a `target` stay plan-level (`scoped_targets`)
|
|
10
|
+
for the run to scope; only project-top budgets gate stages.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from .stages import DECKS
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _target_or_raise(target):
|
|
17
|
+
"""Clean one v1 target to its kind plus project scope.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
target: Target mapping with a non-empty kind.
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
Cleaned target with kind plus project_id/cell when given.
|
|
24
|
+
|
|
25
|
+
Raises:
|
|
26
|
+
ValueError: Non-mapping target or a missing kind.
|
|
27
|
+
"""
|
|
28
|
+
if not isinstance(target, dict) or not isinstance(
|
|
29
|
+
target.get("kind"), str
|
|
30
|
+
) or not target["kind"]:
|
|
31
|
+
raise ValueError(f"Plan target needs a kind: {target!r}.")
|
|
32
|
+
clean = {"kind": target["kind"]}
|
|
33
|
+
for key in ("project_id", "cell"):
|
|
34
|
+
if target.get(key) is not None:
|
|
35
|
+
clean[key] = target[key]
|
|
36
|
+
return clean
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _canvas_or_raise(canvas):
|
|
40
|
+
"""Clean one canvas to metric budgets plus tool settings.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
canvas: Canvas mapping with optional `targets`
|
|
44
|
+
(MetricConstraint list) and `tools` (tool settings);
|
|
45
|
+
None means an empty canvas.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
(budgets, scoped, tools): project-top budget mappings,
|
|
49
|
+
target-scoped (metric, target) pairs, and the tool
|
|
50
|
+
settings mapping.
|
|
51
|
+
|
|
52
|
+
Raises:
|
|
53
|
+
ValueError: Non-mapping canvas, a non-list targets, or
|
|
54
|
+
a non-mapping tools.
|
|
55
|
+
"""
|
|
56
|
+
if canvas is None:
|
|
57
|
+
return [], [], {}
|
|
58
|
+
if not isinstance(canvas, dict):
|
|
59
|
+
raise ValueError(f"Plan canvas must be a mapping: {canvas!r}.")
|
|
60
|
+
targets = canvas.get("targets", [])
|
|
61
|
+
tools = canvas.get("tools", {})
|
|
62
|
+
if not isinstance(targets, list) or any(
|
|
63
|
+
not isinstance(item, dict) or not item.get("metric")
|
|
64
|
+
for item in targets
|
|
65
|
+
):
|
|
66
|
+
raise ValueError(f"Plan canvas targets malformed: {targets!r}.")
|
|
67
|
+
if not isinstance(tools, dict):
|
|
68
|
+
raise ValueError(f"Plan canvas tools malformed: {tools!r}.")
|
|
69
|
+
budgets = [
|
|
70
|
+
{"metric": item["metric"], "operator": item.get("operator"),
|
|
71
|
+
"limit": item.get("limit")}
|
|
72
|
+
for item in targets
|
|
73
|
+
if item.get("target") is None
|
|
74
|
+
]
|
|
75
|
+
scoped = [
|
|
76
|
+
{"metric": item["metric"], "target": item["target"]}
|
|
77
|
+
for item in targets
|
|
78
|
+
if item.get("target") is not None
|
|
79
|
+
]
|
|
80
|
+
return budgets, scoped, dict(tools)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _stage_tools(stage):
|
|
84
|
+
"""Sorted deck-tool names serving one stage's entrypoints.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
stage: Planned stage with entrypoints.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
Sorted tool names from the DECKS table (scripted and
|
|
91
|
+
uncovered entrypoints contribute none).
|
|
92
|
+
"""
|
|
93
|
+
tools = set()
|
|
94
|
+
for entrypoint in stage.get("entrypoints", []):
|
|
95
|
+
for cite in DECKS.get(entrypoint, []):
|
|
96
|
+
tools.add(cite["tool"])
|
|
97
|
+
return sorted(tools)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def gate_plan_for_target(plan, target, canvas=None):
|
|
101
|
+
"""Scope one flow plan to a target and canvas.
|
|
102
|
+
|
|
103
|
+
Readiness is untouched — the gate only joins cost and
|
|
104
|
+
evidence: per-stage deck tools, the canvas tool settings for
|
|
105
|
+
those tools, and the project-top metric budgets every stage
|
|
106
|
+
must satisfy.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
plan: Flow plan mapping with flow plus stages (as from
|
|
110
|
+
plan_checks_report).
|
|
111
|
+
target: v1 target the plan serves (kind required).
|
|
112
|
+
canvas: Canvas mapping with targets/tools; None means an
|
|
113
|
+
empty canvas.
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
Plan mapping plus target, canvas_metrics, canvas_tools,
|
|
117
|
+
scoped_targets, and per-stage target_kind, tools,
|
|
118
|
+
canvas_tools, and budgets.
|
|
119
|
+
|
|
120
|
+
Raises:
|
|
121
|
+
ValueError: Bad target or canvas shape.
|
|
122
|
+
"""
|
|
123
|
+
clean_target = _target_or_raise(target)
|
|
124
|
+
budgets, scoped, tools = _canvas_or_raise(canvas)
|
|
125
|
+
stages = []
|
|
126
|
+
for stage in plan.get("stages", []):
|
|
127
|
+
stage_tools = _stage_tools(stage)
|
|
128
|
+
stages.append({
|
|
129
|
+
**stage,
|
|
130
|
+
"target_kind": clean_target["kind"],
|
|
131
|
+
"tools": stage_tools,
|
|
132
|
+
"canvas_tools": {tool: tools[tool] for tool in stage_tools
|
|
133
|
+
if tool in tools},
|
|
134
|
+
"budgets": [dict(budget) for budget in budgets],
|
|
135
|
+
})
|
|
136
|
+
return {
|
|
137
|
+
**plan,
|
|
138
|
+
"target": clean_target,
|
|
139
|
+
"canvas_metrics": [b["metric"] for b in budgets]
|
|
140
|
+
+ [s["metric"] for s in scoped],
|
|
141
|
+
"canvas_tools": sorted(tools),
|
|
142
|
+
"scoped_targets": scoped,
|
|
143
|
+
"stages": stages,
|
|
144
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""PHOTONIC-WIRE lane: register the proven photonic solvers on an Engine.
|
|
2
|
+
|
|
3
|
+
Circulax (time-domain transient circuit sim) serves run_optical
|
|
4
|
+
behind deck.tool `circulax` as the second tool — sax stays first,
|
|
5
|
+
so the default never moves. Meow (EME mode/field solving with
|
|
6
|
+
two-resolution convergence evidence) serves run_em behind
|
|
7
|
+
deck.tool `meow` as the only tool. FDTD/FEM stay out: proposed,
|
|
8
|
+
not proven, so no other deck tool is registered here.
|
|
9
|
+
|
|
10
|
+
This helper is the executable form of the composition.py wiring
|
|
11
|
+
patch (see docs/work/PHOTONIC-WIRE/report.md): it performs the
|
|
12
|
+
same solver registrations the patch bakes into Engine.__init__,
|
|
13
|
+
plus the same SOLVER_DEPS detection rows the patch adds to
|
|
14
|
+
interfaces/setup.py, so dispatch and capabilities reporting are
|
|
15
|
+
provable on an unpatched tree. Post-patch it is an idempotent
|
|
16
|
+
re-registration of identical keys.
|
|
17
|
+
|
|
18
|
+
Generalization law: the adapters consume project specs (circuit
|
|
19
|
+
YAML in, transient out; device YAML in, S-params plus
|
|
20
|
+
convergence out). The RC/EME smokes qualify the installs; this
|
|
21
|
+
lane generalizes them and never hardcodes their values.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from ..interfaces.setup import SOLVER_DEPS
|
|
25
|
+
|
|
26
|
+
PHOTONIC_TOOLS = {"run_optical": "circulax", "run_em": "meow"}
|
|
27
|
+
|
|
28
|
+
# Detection rows mirroring the setup.py patch: each cites the
|
|
29
|
+
# solver's own import probe, the way the sax row cites sax. Deeper
|
|
30
|
+
# pip-transitive deps stay out — a solver present but broken fails
|
|
31
|
+
# loud at run time, never as a misreported capability.
|
|
32
|
+
PHOTONIC_DEPS = {
|
|
33
|
+
("run_optical", "circulax"): {"python": ["circulax"]},
|
|
34
|
+
("run_em", "meow"): {"python": ["meow"]},
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def wire_photonics(engine, *, runner=None):
|
|
39
|
+
"""Register the circulax and meow solvers on an Engine.
|
|
40
|
+
|
|
41
|
+
Circulax joins run_optical after sax (the default is the
|
|
42
|
+
first registered, so sax keeps it); meow opens run_em.
|
|
43
|
+
Detection rows land in SOLVER_DEPS only where the static
|
|
44
|
+
table has none, so an integrator-patched tree keeps its own
|
|
45
|
+
rows and capabilities reporting never raises unknown_solver
|
|
46
|
+
for a wired lane.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
engine: Engine to wire (composition root with
|
|
50
|
+
register_solver).
|
|
51
|
+
runner: Optional isolated runner handed to both
|
|
52
|
+
adapters; direct subprocess when None.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
Mapping of operation to deck-tool key registered
|
|
56
|
+
({"run_optical": "circulax", "run_em": "meow"}).
|
|
57
|
+
|
|
58
|
+
Raises:
|
|
59
|
+
ModuleNotFoundError: If the same-ticket adapter modules
|
|
60
|
+
(adapters.circulax.adapter, adapters.meow.adapter)
|
|
61
|
+
are not importable — the lane is missing, never
|
|
62
|
+
faked.
|
|
63
|
+
|
|
64
|
+
Caution: Mutates the shared SOLVER_DEPS map (additive rows
|
|
65
|
+
only, never overwrites) and the engine's solver registry
|
|
66
|
+
— call once per Engine; repeats re-register identically.
|
|
67
|
+
"""
|
|
68
|
+
from ..adapters.circulax.adapter import CirculaxAdapter
|
|
69
|
+
from ..adapters.meow.adapter import MeowAdapter
|
|
70
|
+
|
|
71
|
+
for key, spec in PHOTONIC_DEPS.items():
|
|
72
|
+
SOLVER_DEPS.setdefault(key, dict(spec))
|
|
73
|
+
engine.register_solver("run_optical", CirculaxAdapter(runner=runner),
|
|
74
|
+
tool="circulax")
|
|
75
|
+
engine.register_solver("run_em", MeowAdapter(runner=runner), tool="meow")
|
|
76
|
+
return dict(PHOTONIC_TOOLS)
|