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,214 @@
|
|
|
1
|
+
"""Cosim v1 normalizer: v0 joint parse output to a ResultBundle.
|
|
2
|
+
|
|
3
|
+
Maps the ``run_cosim`` joint parse shape (``measurements[]``
|
|
4
|
+
with the SNDR gate plus ones-density bounds, and violations for
|
|
5
|
+
bitless analog halves or failing digital benches) onto a typed
|
|
6
|
+
measurement table, bound views, measurements, and findings. Pure
|
|
7
|
+
function of the parsed output: no I/O, no tool calls,
|
|
8
|
+
deterministic ids derived from the run id. PASS measurements keep
|
|
9
|
+
value, target, margin, and status.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
TASK = "run_cosim"
|
|
13
|
+
|
|
14
|
+
_DIAG_CAP = 240
|
|
15
|
+
|
|
16
|
+
_SEVERITY = {"error": "error", "warning": "warning"}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _cap(text):
|
|
20
|
+
"""Cap one diagnostic string at the bundle prose limit.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
text: Raw diagnostic text, possibly unbounded tool prose.
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
The text unchanged when short, else truncated with an
|
|
27
|
+
ellipsis marker.
|
|
28
|
+
"""
|
|
29
|
+
text = text if isinstance(text, str) else str(text)
|
|
30
|
+
if len(text) <= _DIAG_CAP:
|
|
31
|
+
return text
|
|
32
|
+
return text[: _DIAG_CAP - 3] + "..."
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _quantity(value, unit):
|
|
36
|
+
"""Build one v1 Quantity, mapping unitless to dimensionless.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
value: Numeric value.
|
|
40
|
+
unit: Unit string, possibly empty for unitless measures.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
Quantity mapping with an explicit unit.
|
|
44
|
+
"""
|
|
45
|
+
return {"value": float(value), "unit": unit if unit else "1"}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _limit(item):
|
|
49
|
+
"""Pick the binding target bound for one measurement.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
item: v0 measurement with a ``target`` min/max mapping.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
The bound closest to the measured value, or None when the
|
|
56
|
+
target is empty.
|
|
57
|
+
"""
|
|
58
|
+
target = item.get("target") or {}
|
|
59
|
+
scored = []
|
|
60
|
+
if target.get("min") is not None:
|
|
61
|
+
scored.append((float(item["value"]) - float(target["min"]),
|
|
62
|
+
float(target["min"])))
|
|
63
|
+
if target.get("max") is not None:
|
|
64
|
+
scored.append((float(target["max"]) - float(item["value"]),
|
|
65
|
+
float(target["max"])))
|
|
66
|
+
if not scored:
|
|
67
|
+
return None
|
|
68
|
+
return min(scored)[1]
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _provenance(project_id, run_id, tools, provenance):
|
|
72
|
+
"""Build ResultProvenance, defaulting to a placeholder closure.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
project_id: Project the run belongs to.
|
|
76
|
+
run_id: Run the bundle describes.
|
|
77
|
+
tools: Tool ingredient mappings (id, version, digest?).
|
|
78
|
+
provenance: Full provenance mapping when the caller has
|
|
79
|
+
one; a deterministic placeholder otherwise.
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
Provenance mapping valid against the v1 schema.
|
|
83
|
+
"""
|
|
84
|
+
if provenance is not None:
|
|
85
|
+
return provenance
|
|
86
|
+
ref = {"scope": "project", "id": project_id, "revision": "r1"}
|
|
87
|
+
return {
|
|
88
|
+
"snapshot": dict(ref),
|
|
89
|
+
"input_lock": dict(ref),
|
|
90
|
+
"closure_hash": "0" * 64,
|
|
91
|
+
"tools": [
|
|
92
|
+
{
|
|
93
|
+
"id": item["id"],
|
|
94
|
+
"version": item.get("version", ""),
|
|
95
|
+
"digest": item.get("digest", "0" * 64),
|
|
96
|
+
}
|
|
97
|
+
for item in tools
|
|
98
|
+
],
|
|
99
|
+
"parents": [],
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def normalize(parsed, *, run_id, project_id="project", target=None,
|
|
104
|
+
tools=(), provenance=None):
|
|
105
|
+
"""Normalize one cosim joint parse output to a v1 ResultBundle.
|
|
106
|
+
|
|
107
|
+
Joint measurement rows become a table dataset plus a bound
|
|
108
|
+
table view; violations (bitless halves, failed benches)
|
|
109
|
+
become findings with capped messages.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
parsed: v0 parse mapping with ``measurements[]`` and
|
|
113
|
+
``violations[]``.
|
|
114
|
+
run_id: Run the bundle describes (anchors all ids).
|
|
115
|
+
project_id: Project the run belongs to.
|
|
116
|
+
target: v1 target mapping; project kind by default.
|
|
117
|
+
tools: Tool ingredient mappings for provenance.
|
|
118
|
+
provenance: Full provenance mapping when the caller has
|
|
119
|
+
one; a deterministic placeholder otherwise.
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
Schema-valid ResultBundle mapping.
|
|
123
|
+
"""
|
|
124
|
+
measurements_in = parsed.get("measurements") or []
|
|
125
|
+
violations = parsed.get("violations") or []
|
|
126
|
+
table_id = f"{run_id}:dataset:measurements"
|
|
127
|
+
datasets = [
|
|
128
|
+
{
|
|
129
|
+
"id": table_id,
|
|
130
|
+
"kind": "table",
|
|
131
|
+
"row_count": len(measurements_in),
|
|
132
|
+
"columns": [
|
|
133
|
+
{
|
|
134
|
+
"id": f"{table_id}:name",
|
|
135
|
+
"name": "name",
|
|
136
|
+
"dtype": "utf8",
|
|
137
|
+
"unit": "1",
|
|
138
|
+
"data": [item["name"] for item in measurements_in],
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"id": f"{table_id}:value",
|
|
142
|
+
"name": "value",
|
|
143
|
+
"dtype": "float64",
|
|
144
|
+
"unit": "1",
|
|
145
|
+
"data": [float(item["value"]) for item in measurements_in],
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"id": f"{table_id}:margin",
|
|
149
|
+
"name": "margin",
|
|
150
|
+
"dtype": "float64",
|
|
151
|
+
"unit": "1",
|
|
152
|
+
"data": [float(item["margin"]) for item in measurements_in],
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
"id": f"{table_id}:status",
|
|
156
|
+
"name": "status",
|
|
157
|
+
"dtype": "utf8",
|
|
158
|
+
"unit": "1",
|
|
159
|
+
"data": [item["status"] for item in measurements_in],
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
"conditions": [],
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
views = [
|
|
166
|
+
{
|
|
167
|
+
"id": f"{run_id}:view:measurements",
|
|
168
|
+
"kind": "table",
|
|
169
|
+
"dataset_id": table_id,
|
|
170
|
+
"name": "joint measurements",
|
|
171
|
+
}
|
|
172
|
+
]
|
|
173
|
+
measurements = []
|
|
174
|
+
for item in measurements_in:
|
|
175
|
+
entry = {
|
|
176
|
+
"name": item["name"],
|
|
177
|
+
"value": _quantity(item["value"], item.get("unit", "")),
|
|
178
|
+
"margin": _quantity(item["margin"], item.get("unit", "")),
|
|
179
|
+
"status": "PASS" if item["status"] == "pass" else "FAIL",
|
|
180
|
+
}
|
|
181
|
+
bound = _limit(item)
|
|
182
|
+
if bound is not None:
|
|
183
|
+
entry["limit"] = _quantity(bound, item.get("unit", ""))
|
|
184
|
+
measurements.append(entry)
|
|
185
|
+
findings = [
|
|
186
|
+
{
|
|
187
|
+
"id": f"{run_id}:finding:{index}",
|
|
188
|
+
"severity": _SEVERITY.get(v.get("severity"), "info"),
|
|
189
|
+
"code": v.get("rule", "sim_fail"),
|
|
190
|
+
"message": _cap(v.get("message", "")),
|
|
191
|
+
}
|
|
192
|
+
for index, v in enumerate(violations)
|
|
193
|
+
]
|
|
194
|
+
converged = not any(v.get("rule") == "sim_fail" for v in violations)
|
|
195
|
+
return {
|
|
196
|
+
"schema": "rocketeda/results/v1",
|
|
197
|
+
"ref": {"scope": "project", "id": run_id, "revision": "r1"},
|
|
198
|
+
"run_id": run_id,
|
|
199
|
+
"task": TASK,
|
|
200
|
+
"target": dict(target)
|
|
201
|
+
if target is not None
|
|
202
|
+
else {"project_id": project_id, "kind": "project"},
|
|
203
|
+
"state": "complete",
|
|
204
|
+
"freshness": "current",
|
|
205
|
+
"convergence": "converged" if converged else "not_converged",
|
|
206
|
+
"provenance": _provenance(project_id, run_id, tools, provenance),
|
|
207
|
+
"datasets": datasets,
|
|
208
|
+
"views": views,
|
|
209
|
+
"measurements": measurements,
|
|
210
|
+
"findings": findings,
|
|
211
|
+
"artifacts": [],
|
|
212
|
+
"logs": [],
|
|
213
|
+
"gaps": [],
|
|
214
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"""Devsim TCAD adapter: run_tcad behind the ToolAdapter port."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import shutil
|
|
5
|
+
import subprocess
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from ...execution.errors import ExecutionError
|
|
9
|
+
from ...interfaces import ToolAdapter
|
|
10
|
+
from ..errors import AdapterError
|
|
11
|
+
|
|
12
|
+
OPERATION = "run_tcad"
|
|
13
|
+
_TOOL = "devsim"
|
|
14
|
+
_DUMP = "devsim_dump.json"
|
|
15
|
+
_TIMEOUT_S = 300
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class DevsimAdapter(ToolAdapter):
|
|
19
|
+
"""run_tcad via devsim: driver dump parsed to measurements.
|
|
20
|
+
|
|
21
|
+
Serves the run_tcad operation with tool `devsim`. The driver
|
|
22
|
+
script calls get_contact_current/get_*_model_values plus
|
|
23
|
+
solve(info=True) and dumps JSON; the adapter parses the dump
|
|
24
|
+
file, never stdout scraping.
|
|
25
|
+
|
|
26
|
+
Job keys:
|
|
27
|
+
script (required): Driver python script path.
|
|
28
|
+
workdir: Run directory (default ".").
|
|
29
|
+
timeout_s: Budget in seconds (default 300).
|
|
30
|
+
python: Driver python binary (default sys python).
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
runner: Optional isolated runner; direct subprocess when None.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self, runner=None):
|
|
37
|
+
self._runner = runner
|
|
38
|
+
|
|
39
|
+
def capabilities(self, target):
|
|
40
|
+
"""Report the served operation and tool.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
target: Target the capabilities are reported for.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
Capability mapping with operations and tool.
|
|
47
|
+
"""
|
|
48
|
+
return {"operations": [OPERATION], "tool": _TOOL,
|
|
49
|
+
"dump": _DUMP}
|
|
50
|
+
|
|
51
|
+
def preflight(self, job):
|
|
52
|
+
"""Check operation, script, and devsim importability.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
job: Solver job with operation run_tcad plus script.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
Checked mapping with script, timeout, and python.
|
|
59
|
+
|
|
60
|
+
Raises:
|
|
61
|
+
AdapterError: unsupported_operation, invalid_reference
|
|
62
|
+
for a missing script, missing_dependency with
|
|
63
|
+
BLOCKED-needs-host when devsim is not importable.
|
|
64
|
+
"""
|
|
65
|
+
if job.get("operation") != OPERATION:
|
|
66
|
+
raise AdapterError(
|
|
67
|
+
"unsupported_operation",
|
|
68
|
+
f"Devsim handles {OPERATION}, got {job.get('operation')}.",
|
|
69
|
+
)
|
|
70
|
+
script = job.get("script")
|
|
71
|
+
if not script or not Path(script).is_file():
|
|
72
|
+
raise AdapterError(
|
|
73
|
+
"invalid_reference", f"Driver script not found: {script}.")
|
|
74
|
+
try:
|
|
75
|
+
__import__(_TOOL)
|
|
76
|
+
except ImportError as exc:
|
|
77
|
+
raise AdapterError(
|
|
78
|
+
"missing_dependency",
|
|
79
|
+
"BLOCKED-needs-host: devsim not importable "
|
|
80
|
+
"(need devsim==2.11.2 in the engine venv).",
|
|
81
|
+
) from exc
|
|
82
|
+
timeout = job.get("timeout_s", _TIMEOUT_S)
|
|
83
|
+
if (not isinstance(timeout, (int, float))
|
|
84
|
+
or isinstance(timeout, bool) or not timeout > 0):
|
|
85
|
+
raise AdapterError("invalid_command", f"Bad timeout: {timeout!r}.")
|
|
86
|
+
checked = {"script": str(script), "timeout_s": timeout,
|
|
87
|
+
"python": job.get("python") or "python3"}
|
|
88
|
+
if self._runner is not None:
|
|
89
|
+
try:
|
|
90
|
+
self._runner.preflight()
|
|
91
|
+
except ExecutionError as exc:
|
|
92
|
+
raise AdapterError(exc.code, str(exc)) from exc
|
|
93
|
+
return checked
|
|
94
|
+
|
|
95
|
+
def execute(self, job):
|
|
96
|
+
"""Run the driver script under a timeout.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
job: Solver job with operation run_tcad plus script.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
Native output with exit_code, stdout/stderr, dump, file.
|
|
103
|
+
"""
|
|
104
|
+
checked = self.preflight(job)
|
|
105
|
+
workdir = job.get("workdir", ".")
|
|
106
|
+
if not Path(workdir).is_dir():
|
|
107
|
+
raise AdapterError(
|
|
108
|
+
"invalid_reference", f"Workdir not found: {workdir}.")
|
|
109
|
+
proc = self._run([checked["python"], checked["script"]],
|
|
110
|
+
workdir, checked["timeout_s"])
|
|
111
|
+
dump_path = Path(workdir) / _DUMP
|
|
112
|
+
dump = None
|
|
113
|
+
if dump_path.is_file():
|
|
114
|
+
try:
|
|
115
|
+
dump = json.loads(dump_path.read_text())
|
|
116
|
+
except ValueError:
|
|
117
|
+
dump = None
|
|
118
|
+
return {"exit_code": proc.returncode, "stdout": proc.stdout,
|
|
119
|
+
"stderr": proc.stderr, "dump": dump,
|
|
120
|
+
"dump_file": _DUMP}
|
|
121
|
+
|
|
122
|
+
def parse(self, native_output):
|
|
123
|
+
"""Parse the driver JSON dump to verdict plus measurements.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
native_output: Native output with the dump mapping.
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
{total, violations[], measurements[], source} with the
|
|
130
|
+
dump file as source.
|
|
131
|
+
|
|
132
|
+
Raises:
|
|
133
|
+
AdapterError: runner_unavailable when no dump is present.
|
|
134
|
+
"""
|
|
135
|
+
dump = native_output.get("dump")
|
|
136
|
+
if not isinstance(dump, dict):
|
|
137
|
+
raise AdapterError(
|
|
138
|
+
"runner_unavailable", "Devsim run left no dump JSON.")
|
|
139
|
+
solve = dump.get("solve") or {}
|
|
140
|
+
violations = []
|
|
141
|
+
if solve.get("converged") is False or not dump.get("currents"):
|
|
142
|
+
violations.append({"rule": "tcad_converge",
|
|
143
|
+
"severity": "error",
|
|
144
|
+
"message": "Devsim solve did not converge."})
|
|
145
|
+
measurements = []
|
|
146
|
+
for name, value in (dump.get("currents") or {}).items():
|
|
147
|
+
try:
|
|
148
|
+
measurements.append({"name": f"current.{name}",
|
|
149
|
+
"value": float(value), "unit": "A"})
|
|
150
|
+
except (TypeError, ValueError):
|
|
151
|
+
continue
|
|
152
|
+
pots = dump.get("potentials") or []
|
|
153
|
+
if pots:
|
|
154
|
+
measurements.append({"name": "potential.count",
|
|
155
|
+
"value": float(len(pots)), "unit": "count"})
|
|
156
|
+
return {"total": len(violations), "violations": violations,
|
|
157
|
+
"measurements": measurements, "source": "dump",
|
|
158
|
+
"dump_file": native_output.get("dump_file", _DUMP)}
|
|
159
|
+
|
|
160
|
+
def _run(self, argv, workdir, timeout_s):
|
|
161
|
+
if self._runner is not None:
|
|
162
|
+
try:
|
|
163
|
+
return self._runner.run(argv, workdir, timeout_s)
|
|
164
|
+
except ExecutionError as exc:
|
|
165
|
+
raise AdapterError(exc.code, str(exc)) from exc
|
|
166
|
+
try:
|
|
167
|
+
return subprocess.run(argv, capture_output=True, text=True,
|
|
168
|
+
timeout=timeout_s, cwd=workdir)
|
|
169
|
+
except subprocess.TimeoutExpired as exc:
|
|
170
|
+
raise AdapterError(
|
|
171
|
+
"runner_unavailable", "Devsim run timed out.") from exc
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# LibreLane digital-flow adapter
|
|
2
|
+
|
|
3
|
+
LibrelaneFlowAdapter serves run_digital_flow with the librelane deck tool. It stages project RTL and flow configuration, runs the Classic flow under a timeout, and parses stage output into findings, measurements, and artifact references for the D11–D27 gates.
|
|
4
|
+
|
|
5
|
+
The adapter requires the pinned LibreLane 3.0.17 distribution and a compatible PDK root. Tool resolution uses PATH or the job tool_dir; version mismatch refuses. When supplied, BwrapRunner confines the flow with tool and PDK roots read-only and the work directory writable.
|
|
6
|
+
|
|
7
|
+
Hermetic qualification covers synthetic run trees, parse outcomes, timeouts, and failure gates. The live SERV RTL-to-GDS proof is currently blocked because this environment lacks the pinned distribution and PDK root. Adapter registration is not a claim that the full flow has passed live qualification.
|
|
8
|
+
|
|
9
|
+
See the [DIGITAL-FLOW report](../../../docs/work/DIGITAL-FLOW/report.md) and [provision plan](../../../docs/provision-plan.md).
|