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,700 @@
|
|
|
1
|
+
"""One mutation function per MUTATE-HARNESS operator.
|
|
2
|
+
|
|
3
|
+
Each function takes the base file text plus a variant index and
|
|
4
|
+
returns (mutated_text, extra_evidence). Every site is probe-guarded:
|
|
5
|
+
the expected base string must occur exactly once, else MutationError
|
|
6
|
+
— a fixture that drifted must fail loudly, never silently pass
|
|
7
|
+
through unmutated. Variant selection is `seed % len(variants)`,
|
|
8
|
+
computed by the caller, so every mutation is reproducible from seed.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import math
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class MutationError(ValueError):
|
|
15
|
+
"""A mutation site is missing or ambiguous (fixture drift)."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _once(text, old, operator):
|
|
19
|
+
found = text.count(old)
|
|
20
|
+
if found != 1:
|
|
21
|
+
raise MutationError(
|
|
22
|
+
f"{operator}: probe site {old!r} occurs {found}x, want 1."
|
|
23
|
+
)
|
|
24
|
+
return found
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def digital_reset_break(text, variant):
|
|
28
|
+
"""Break the async reset: inverted condition or stuck active.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
text: Base file text to mutate.
|
|
32
|
+
variant: Variant index selecting the rewrite.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
(mutated_text, extra_evidence) pair.
|
|
36
|
+
|
|
37
|
+
Raises:
|
|
38
|
+
MutationError: Probe site missing or ambiguous.
|
|
39
|
+
"""
|
|
40
|
+
old = "if (!rst_n)"
|
|
41
|
+
_once(text, old, "digital_reset_break")
|
|
42
|
+
new = ["if (rst_n)", "if (1'b1)"][variant % 2]
|
|
43
|
+
desc = [
|
|
44
|
+
"reset condition inverted (counts in reset, clears on release)",
|
|
45
|
+
"reset stuck active (count held at zero)",
|
|
46
|
+
][variant % 2]
|
|
47
|
+
return text.replace(old, new), {"variant_desc": desc}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def digital_truncation(text, variant):
|
|
51
|
+
"""Narrow the count update so the sequence never reaches 10.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
text: Base file text to mutate.
|
|
55
|
+
variant: Variant index selecting the rewrite.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
(mutated_text, extra_evidence) pair.
|
|
59
|
+
|
|
60
|
+
Raises:
|
|
61
|
+
MutationError: Probe site missing or ambiguous.
|
|
62
|
+
"""
|
|
63
|
+
old = "count <= count + 4'd1;"
|
|
64
|
+
_once(text, old, "digital_truncation")
|
|
65
|
+
alts = [
|
|
66
|
+
("count <= (count + 4'd1) & 4'h7;", "count masked to 3 bits (max 7)"),
|
|
67
|
+
("count <= (count + 4'd1) & 4'h3;", "count masked to 2 bits (max 3)"),
|
|
68
|
+
(
|
|
69
|
+
"count <= {1'b0, count[2:0]} + 4'd1;",
|
|
70
|
+
"count zero-extended from 3 bits (max 8)",
|
|
71
|
+
),
|
|
72
|
+
]
|
|
73
|
+
new, desc = alts[variant % len(alts)]
|
|
74
|
+
return text.replace(old, new), {"variant_desc": desc}
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def digital_unconnected_port(text, variant):
|
|
78
|
+
"""Leave a DUT port unconnected in the harness instantiation.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
text: Base file text to mutate.
|
|
82
|
+
variant: Variant index selecting the rewrite.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
(mutated_text, extra_evidence) pair.
|
|
86
|
+
|
|
87
|
+
Raises:
|
|
88
|
+
MutationError: Probe site missing or ambiguous.
|
|
89
|
+
"""
|
|
90
|
+
alts = [
|
|
91
|
+
(".rst_n(rst_n)", ".rst_n()", "reset input left unconnected (floats)"),
|
|
92
|
+
(".clk(clk)", ".clk()", "clock input left unconnected (no edges)"),
|
|
93
|
+
]
|
|
94
|
+
old, new, desc = alts[variant % len(alts)]
|
|
95
|
+
_once(text, old, "digital_unconnected_port")
|
|
96
|
+
return text.replace(old, new), {"variant_desc": desc}
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def serv_reset_break(text, variant):
|
|
100
|
+
"""Break the servant CPU reset: stuck in reset or inverted.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
text: Base file text to mutate.
|
|
104
|
+
variant: Variant index selecting the rewrite.
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
(mutated_text, extra_evidence) pair.
|
|
108
|
+
|
|
109
|
+
Raises:
|
|
110
|
+
MutationError: Probe site missing or ambiguous.
|
|
111
|
+
"""
|
|
112
|
+
old = ".i_rst (wb_rst),"
|
|
113
|
+
_once(text, old, "serv_reset_break")
|
|
114
|
+
alts = [
|
|
115
|
+
(
|
|
116
|
+
".i_rst (1'b1),",
|
|
117
|
+
"CPU reset stuck active (firmware never boots, watchdog fires)",
|
|
118
|
+
),
|
|
119
|
+
(
|
|
120
|
+
".i_rst (~wb_rst),",
|
|
121
|
+
"CPU reset inverted (held in reset while the system runs)",
|
|
122
|
+
),
|
|
123
|
+
]
|
|
124
|
+
new, desc = alts[variant % len(alts)]
|
|
125
|
+
return text.replace(old, new), {"variant_desc": desc}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def serv_truncation(text, variant):
|
|
129
|
+
"""Narrow the servile data-bus address so MMIO is unreachable.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
text: Base file text to mutate.
|
|
133
|
+
variant: Variant index selecting the rewrite.
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
(mutated_text, extra_evidence) pair.
|
|
137
|
+
|
|
138
|
+
Raises:
|
|
139
|
+
MutationError: Probe site missing or ambiguous.
|
|
140
|
+
"""
|
|
141
|
+
old = "assign o_dbus_adr = {data[31:2], 2'b00};"
|
|
142
|
+
_once(text, old, "serv_truncation")
|
|
143
|
+
alts = [
|
|
144
|
+
(
|
|
145
|
+
"assign o_dbus_adr = 32'b0;",
|
|
146
|
+
"data-bus address zeroed (GPIO/HALT stores hit RAM, no halt)",
|
|
147
|
+
),
|
|
148
|
+
(
|
|
149
|
+
"assign o_dbus_adr = {data[31:2] & 30'h0FFFFFFF, 2'b00};",
|
|
150
|
+
"address top 2 bits dropped (0x4/0x9xxxxxxx unreachable)",
|
|
151
|
+
),
|
|
152
|
+
(
|
|
153
|
+
"assign o_dbus_adr = {data[31:2] & 30'h00FFFFFF, 2'b00};",
|
|
154
|
+
"address top 6 bits dropped (0x4/0x9xxxxxxx unreachable)",
|
|
155
|
+
),
|
|
156
|
+
]
|
|
157
|
+
new, desc = alts[variant % len(alts)]
|
|
158
|
+
return text.replace(old, new), {"variant_desc": desc}
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def serv_unconnected_port(text, variant):
|
|
162
|
+
"""Leave a servant CPU port unconnected in the SoC wiring.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
text: Base file text to mutate.
|
|
166
|
+
variant: Variant index selecting the rewrite.
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
(mutated_text, extra_evidence) pair.
|
|
170
|
+
|
|
171
|
+
Raises:
|
|
172
|
+
MutationError: Probe site missing or ambiguous.
|
|
173
|
+
"""
|
|
174
|
+
alts = [
|
|
175
|
+
(
|
|
176
|
+
".i_clk (wb_clk),",
|
|
177
|
+
".i_clk (),",
|
|
178
|
+
"CPU clock left unconnected (no edges, firmware never runs)",
|
|
179
|
+
),
|
|
180
|
+
(
|
|
181
|
+
".i_rst (wb_rst),",
|
|
182
|
+
".i_rst (),",
|
|
183
|
+
"CPU reset left unconnected (floats, firmware never boots)",
|
|
184
|
+
),
|
|
185
|
+
]
|
|
186
|
+
old, new, desc = alts[variant % len(alts)]
|
|
187
|
+
_once(text, old, "serv_unconnected_port")
|
|
188
|
+
return text.replace(old, new), {"variant_desc": desc}
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def picorv32_reset_break(text, variant):
|
|
192
|
+
"""Break the test_ez reset: stuck in reset or re-asserted.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
text: Base file text to mutate.
|
|
196
|
+
variant: Variant index selecting the rewrite.
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
(mutated_text, extra_evidence) pair.
|
|
200
|
+
|
|
201
|
+
Raises:
|
|
202
|
+
MutationError: Probe site missing or ambiguous.
|
|
203
|
+
"""
|
|
204
|
+
if variant % 2 == 0:
|
|
205
|
+
old = "resetn <= 1;"
|
|
206
|
+
_once(text, old, "picorv32_reset_break")
|
|
207
|
+
new = "resetn <= 0;"
|
|
208
|
+
desc = "reset stuck active (CPU never fetches, counter stays put)"
|
|
209
|
+
else:
|
|
210
|
+
old = "repeat (1000) @(posedge clk);"
|
|
211
|
+
_once(text, old, "picorv32_reset_break")
|
|
212
|
+
new = (
|
|
213
|
+
"repeat (100) @(posedge clk); "
|
|
214
|
+
"resetn <= 0; repeat (900) @(posedge clk);"
|
|
215
|
+
)
|
|
216
|
+
desc = "reset re-asserted after 100 cycles (run aborted early)"
|
|
217
|
+
return text.replace(old, new), {"variant_desc": desc}
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def picorv32_truncation(text, variant):
|
|
221
|
+
"""Narrow the ALU add path so the ez counter never reaches 10.
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
text: Base file text to mutate.
|
|
225
|
+
variant: Variant index selecting the rewrite.
|
|
226
|
+
|
|
227
|
+
Returns:
|
|
228
|
+
(mutated_text, extra_evidence) pair.
|
|
229
|
+
|
|
230
|
+
Raises:
|
|
231
|
+
MutationError: Probe site missing or ambiguous.
|
|
232
|
+
"""
|
|
233
|
+
old = "alu_add_sub = instr_sub ? reg_op1 - reg_op2 : reg_op1 + reg_op2;"
|
|
234
|
+
_once(text, old, "picorv32_truncation")
|
|
235
|
+
alts = [
|
|
236
|
+
(
|
|
237
|
+
"alu_add_sub = instr_sub ? reg_op1 - reg_op2 : "
|
|
238
|
+
"((reg_op1 + reg_op2) & 32'h00000007);",
|
|
239
|
+
"ALU add masked to 3 bits (max 7)",
|
|
240
|
+
),
|
|
241
|
+
(
|
|
242
|
+
"alu_add_sub = instr_sub ? reg_op1 - reg_op2 : "
|
|
243
|
+
"((reg_op1 + reg_op2) & 32'h00000003);",
|
|
244
|
+
"ALU add masked to 2 bits (max 3)",
|
|
245
|
+
),
|
|
246
|
+
(
|
|
247
|
+
"alu_add_sub = instr_sub ? reg_op1 - reg_op2 : "
|
|
248
|
+
"{29'b0, reg_op1[2:0] + reg_op2[2:0]};",
|
|
249
|
+
"ALU add zero-extended from 3 bits (max 8)",
|
|
250
|
+
),
|
|
251
|
+
]
|
|
252
|
+
new, desc = alts[variant % len(alts)]
|
|
253
|
+
return text.replace(old, new), {"variant_desc": desc}
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def picorv32_unconnected_port(text, variant):
|
|
257
|
+
"""Leave a picorv32 port unconnected in the ez bench wiring.
|
|
258
|
+
|
|
259
|
+
Args:
|
|
260
|
+
text: Base file text to mutate.
|
|
261
|
+
variant: Variant index selecting the rewrite.
|
|
262
|
+
|
|
263
|
+
Returns:
|
|
264
|
+
(mutated_text, extra_evidence) pair.
|
|
265
|
+
|
|
266
|
+
Raises:
|
|
267
|
+
MutationError: Probe site missing or ambiguous.
|
|
268
|
+
"""
|
|
269
|
+
alts = [
|
|
270
|
+
(
|
|
271
|
+
".clk (clk ),",
|
|
272
|
+
".clk (),",
|
|
273
|
+
"CPU clock left unconnected (no edges, trap unresolved)",
|
|
274
|
+
),
|
|
275
|
+
(
|
|
276
|
+
".mem_rdata (mem_rdata )",
|
|
277
|
+
".mem_rdata ()",
|
|
278
|
+
"memory read data left unconnected (fetches unknown)",
|
|
279
|
+
),
|
|
280
|
+
]
|
|
281
|
+
old, new, desc = alts[variant % len(alts)]
|
|
282
|
+
_once(text, old, "picorv32_unconnected_port")
|
|
283
|
+
return text.replace(old, new), {"variant_desc": desc}
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def analog_sizing_out_of_spec(text, variant):
|
|
287
|
+
"""Move R2 off its 8k nominal so Vout leaves [1.199, 1.201] V.
|
|
288
|
+
|
|
289
|
+
Args:
|
|
290
|
+
text: Base file text to mutate.
|
|
291
|
+
variant: Variant index selecting the rewrite.
|
|
292
|
+
|
|
293
|
+
Returns:
|
|
294
|
+
(mutated_text, extra_evidence) pair.
|
|
295
|
+
|
|
296
|
+
Raises:
|
|
297
|
+
MutationError: Probe site missing or ambiguous.
|
|
298
|
+
"""
|
|
299
|
+
old = "R2 out 0 8k"
|
|
300
|
+
_once(text, old, "analog_sizing_out_of_spec")
|
|
301
|
+
r2 = ["4k", "2k", "16k"][variant % 3]
|
|
302
|
+
ohms = {"2k": 2000.0, "4k": 4000.0, "16k": 16000.0}[r2]
|
|
303
|
+
expected_vout = 1.8 * ohms / (4000.0 + ohms)
|
|
304
|
+
extra = {
|
|
305
|
+
"variant_desc": f"R2 8k -> {r2} (divider ratio out of spec)",
|
|
306
|
+
"resistor": r2,
|
|
307
|
+
"expected_vout": expected_vout,
|
|
308
|
+
}
|
|
309
|
+
return text.replace(old, f"R2 out 0 {r2}"), extra
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def analog_open_net(text, variant):
|
|
313
|
+
"""Open the divider: R2 lifted from `out`, which rises to the rail.
|
|
314
|
+
|
|
315
|
+
Args:
|
|
316
|
+
text: Base file text to mutate.
|
|
317
|
+
variant: Variant index selecting the rewrite.
|
|
318
|
+
|
|
319
|
+
Returns:
|
|
320
|
+
(mutated_text, extra_evidence) pair.
|
|
321
|
+
|
|
322
|
+
Raises:
|
|
323
|
+
MutationError: Probe site missing or ambiguous.
|
|
324
|
+
"""
|
|
325
|
+
old = "R2 out 0 8k"
|
|
326
|
+
_once(text, old, "analog_open_net")
|
|
327
|
+
alts = [
|
|
328
|
+
("R2 out_open 0 8k", "R2 high side lifted onto out_open"),
|
|
329
|
+
(
|
|
330
|
+
"* R2 out 0 8k (MUTATE-HARNESS analog_open_net: device lifted)",
|
|
331
|
+
"R2 commented out (device lifted)",
|
|
332
|
+
),
|
|
333
|
+
]
|
|
334
|
+
new, desc = alts[variant % len(alts)]
|
|
335
|
+
return text.replace(old, new), {"variant_desc": desc}
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def bandgap_sizing_out_of_spec(text, variant):
|
|
339
|
+
"""Move n_r2 off its 51 nominal; Vref leaves DR-005 [1.176, 1.224] V.
|
|
340
|
+
|
|
341
|
+
Expected values are live-verified at the gate's single corner
|
|
342
|
+
(ngspice + the sky130 store, tt/27C; otherwise quarantined, see
|
|
343
|
+
docs/tickets/NGSPICE-LIVE.md): the header's documented 1.1744 /
|
|
344
|
+
1.22507 numbers are sweep extremes, but at tt/27C n_r2=50 reads
|
|
345
|
+
1.2016 V and n_r2=52 reads 1.2194 V — both in-band, so the gate
|
|
346
|
+
PASSes them. The variants are strengthened past that: n_r2=46
|
|
347
|
+
reads 1.166 V, n_r2=54 reads 1.237 V, n_r2=55 reads 1.246 V.
|
|
348
|
+
The verdict mapping is pinned by canned-envelope parse tests.
|
|
349
|
+
|
|
350
|
+
Args:
|
|
351
|
+
text: Base file text to mutate.
|
|
352
|
+
variant: Variant index selecting the rewrite.
|
|
353
|
+
|
|
354
|
+
Returns:
|
|
355
|
+
(mutated_text, extra_evidence) pair.
|
|
356
|
+
|
|
357
|
+
Raises:
|
|
358
|
+
MutationError: Probe site missing or ambiguous.
|
|
359
|
+
"""
|
|
360
|
+
old = ".param n_r2=51"
|
|
361
|
+
_once(text, old, "bandgap_sizing_out_of_spec")
|
|
362
|
+
alts = [
|
|
363
|
+
(46, 1.166, "n_r2 51 -> 46 (K low, vref below the 1.176 V floor)"),
|
|
364
|
+
(54, 1.237, "n_r2 51 -> 54 (K high, vref above the 1.224 V ceiling)"),
|
|
365
|
+
(55, 1.246, "n_r2 51 -> 55 (extreme, vref further above ceiling)"),
|
|
366
|
+
]
|
|
367
|
+
n_r2, expected_vref, desc = alts[variant % len(alts)]
|
|
368
|
+
extra = {
|
|
369
|
+
"variant_desc": desc,
|
|
370
|
+
"n_r2": n_r2,
|
|
371
|
+
"expected_vref": expected_vref,
|
|
372
|
+
}
|
|
373
|
+
return text.replace(old, f".param n_r2={n_r2}"), extra
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def bandgap_open_net(text, variant):
|
|
377
|
+
"""Open the bandgap R2 leg: XR2A lifted from VOUT.
|
|
378
|
+
|
|
379
|
+
Variant 0 renames the output net (feedback cut, Vref
|
|
380
|
+
collapses); variant 1 comments the device (leg open). No value
|
|
381
|
+
changes — the topology break pushes Vref outside DR-005
|
|
382
|
+
[1.176, 1.224] V. Same quarantine/parse story as sizing.
|
|
383
|
+
|
|
384
|
+
Args:
|
|
385
|
+
text: Base file text to mutate.
|
|
386
|
+
variant: Variant index selecting the rewrite.
|
|
387
|
+
|
|
388
|
+
Returns:
|
|
389
|
+
(mutated_text, extra_evidence) pair.
|
|
390
|
+
|
|
391
|
+
Raises:
|
|
392
|
+
MutationError: Probe site missing or ambiguous.
|
|
393
|
+
"""
|
|
394
|
+
old = (
|
|
395
|
+
"XR2A R2A_HD2 VOUT VSS sky130_fd_pr__res_high_po "
|
|
396
|
+
"W='r_w' L='r_lseg*n_r2+r_lseg_trim*n_r2_trim-n_r2_ov*r_ov_seg' "
|
|
397
|
+
"mult=1 m=1"
|
|
398
|
+
)
|
|
399
|
+
_once(text, old, "bandgap_open_net")
|
|
400
|
+
alts = [
|
|
401
|
+
(
|
|
402
|
+
old.replace("XR2A R2A_HD2 VOUT VSS", "XR2A R2A_HD2 VOUT_OPEN VSS"),
|
|
403
|
+
"XR2A output lifted onto VOUT_OPEN (feedback cut)",
|
|
404
|
+
),
|
|
405
|
+
(
|
|
406
|
+
f"* {old} (MUTATE-HARNESS bandgap_open_net: device lifted)",
|
|
407
|
+
"XR2A commented out (R2A leg open)",
|
|
408
|
+
),
|
|
409
|
+
]
|
|
410
|
+
new, desc = alts[variant % len(alts)]
|
|
411
|
+
return text.replace(old, new), {"variant_desc": desc}
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
def layout_drc_violation(text, variant):
|
|
415
|
+
"""Shift or shrink a rect into an scmos DRC violation.
|
|
416
|
+
|
|
417
|
+
Args:
|
|
418
|
+
text: Base file text to mutate.
|
|
419
|
+
variant: Variant index selecting the rewrite.
|
|
420
|
+
|
|
421
|
+
Returns:
|
|
422
|
+
(mutated_text, extra_evidence) pair.
|
|
423
|
+
|
|
424
|
+
Raises:
|
|
425
|
+
MutationError: Probe site missing or ambiguous.
|
|
426
|
+
"""
|
|
427
|
+
if variant % 2 == 0:
|
|
428
|
+
old, new = "rect 6 0 9 3", "rect 4 0 7 3"
|
|
429
|
+
rule, desc = "spacing", "second rect shifted left (1λ spacing)"
|
|
430
|
+
else:
|
|
431
|
+
old, new = "rect 0 0 3 3", "rect 0 0 1 5"
|
|
432
|
+
rule, desc = "width", "first rect narrowed (1λ width)"
|
|
433
|
+
_once(text, old, "layout_drc_violation")
|
|
434
|
+
return text.replace(old, new), {"variant_desc": desc, "expected_rule": rule}
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
def netlist_lvs_mismatch(text, variant):
|
|
438
|
+
"""Rename one device bulk net on the schematic side only.
|
|
439
|
+
|
|
440
|
+
Args:
|
|
441
|
+
text: Base file text to mutate.
|
|
442
|
+
variant: Variant index selecting the rewrite.
|
|
443
|
+
|
|
444
|
+
Returns:
|
|
445
|
+
(mutated_text, extra_evidence) pair.
|
|
446
|
+
|
|
447
|
+
Raises:
|
|
448
|
+
MutationError: Probe site missing or ambiguous.
|
|
449
|
+
"""
|
|
450
|
+
alts = [
|
|
451
|
+
(
|
|
452
|
+
"Y A VPWR VPB sky130_fd_pr__pfet_01v8_hvt",
|
|
453
|
+
"Y A VPWR VPB_BAD sky130_fd_pr__pfet_01v8_hvt",
|
|
454
|
+
"VPB_BAD",
|
|
455
|
+
"pfet bulk VPB renamed to VPB_BAD",
|
|
456
|
+
),
|
|
457
|
+
(
|
|
458
|
+
"Y A VGND VNB sky130_fd_pr__nfet_01v8",
|
|
459
|
+
"Y A VGND VNB_BAD sky130_fd_pr__nfet_01v8",
|
|
460
|
+
"VNB_BAD",
|
|
461
|
+
"nfet bulk VNB renamed to VNB_BAD",
|
|
462
|
+
),
|
|
463
|
+
]
|
|
464
|
+
old, new, bad_net, desc = alts[variant % len(alts)]
|
|
465
|
+
_once(text, old, "netlist_lvs_mismatch")
|
|
466
|
+
return text.replace(old, new), {"variant_desc": desc, "bad_net": bad_net}
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
def _db(linear):
|
|
470
|
+
return round(10.0 * math.log10(linear), 3)
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
def photonic_geometry_mistune(text, variant):
|
|
474
|
+
"""Lengthen the MZI bottom arm; cross-port transmission collapses.
|
|
475
|
+
|
|
476
|
+
Expected values verified against sax 0.18.2 (in0 -> out1 @1550nm):
|
|
477
|
+
+0.2 um -> 0.33972 (-4.689 dB), +0.4 um -> 0.10276 (-9.882 dB).
|
|
478
|
+
|
|
479
|
+
Args:
|
|
480
|
+
text: Base file text to mutate.
|
|
481
|
+
variant: Variant index selecting the rewrite.
|
|
482
|
+
|
|
483
|
+
Returns:
|
|
484
|
+
(mutated_text, extra_evidence) pair.
|
|
485
|
+
|
|
486
|
+
Raises:
|
|
487
|
+
MutationError: Probe site missing or ambiguous.
|
|
488
|
+
"""
|
|
489
|
+
old = "s_bot: {component: straight, settings: {length: 10.0}}"
|
|
490
|
+
_once(text, old, "photonic_geometry_mistune")
|
|
491
|
+
delta, linear = [(0.2, 0.33972), (0.4, 0.10276)][variant % 2]
|
|
492
|
+
new = (
|
|
493
|
+
"s_bot: {component: straight, settings: "
|
|
494
|
+
f"{{length: {10.0 + delta:.1f}}}}}"
|
|
495
|
+
)
|
|
496
|
+
extra = {
|
|
497
|
+
"variant_desc": f"bottom arm lengthened by {delta} um",
|
|
498
|
+
"arm_delta_um": delta,
|
|
499
|
+
"expected_linear": linear,
|
|
500
|
+
"expected_db": _db(linear),
|
|
501
|
+
}
|
|
502
|
+
return text.replace(old, new), extra
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
def photonic_circuit_mistune(text, variant):
|
|
506
|
+
"""Detune the output coupler; cross-port transmission drops.
|
|
507
|
+
|
|
508
|
+
Expected value verified against sax 0.18.2 (in0 -> out1 @1550nm):
|
|
509
|
+
coupling 0.1 -> 0.8 (-0.969 dB).
|
|
510
|
+
|
|
511
|
+
Args:
|
|
512
|
+
text: Base file text to mutate.
|
|
513
|
+
variant: Variant index selecting the rewrite.
|
|
514
|
+
|
|
515
|
+
Returns:
|
|
516
|
+
(mutated_text, extra_evidence) pair.
|
|
517
|
+
|
|
518
|
+
Raises:
|
|
519
|
+
MutationError: Probe site missing or ambiguous.
|
|
520
|
+
"""
|
|
521
|
+
old = "c2: {component: coupler_ideal, settings: {coupling: 0.5}}"
|
|
522
|
+
_once(text, old, "photonic_circuit_mistune")
|
|
523
|
+
_ = variant
|
|
524
|
+
linear = 0.8
|
|
525
|
+
new = "c2: {component: coupler_ideal, settings: {coupling: 0.1}}"
|
|
526
|
+
extra = {
|
|
527
|
+
"variant_desc": "output coupler coupling 0.5 -> 0.1",
|
|
528
|
+
"coupling": 0.1,
|
|
529
|
+
"expected_linear": linear,
|
|
530
|
+
"expected_db": _db(linear),
|
|
531
|
+
}
|
|
532
|
+
return text.replace(old, new), extra
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
def sdm_reset_break(text, variant):
|
|
536
|
+
"""Break the sdm_rx sinc3-path reset: inverted or stuck clearing.
|
|
537
|
+
|
|
538
|
+
Args:
|
|
539
|
+
text: Base file text to mutate.
|
|
540
|
+
variant: Variant index selecting the rewrite.
|
|
541
|
+
|
|
542
|
+
Returns:
|
|
543
|
+
(mutated_text, extra_evidence) pair.
|
|
544
|
+
|
|
545
|
+
Raises:
|
|
546
|
+
MutationError: Probe site missing or ambiguous.
|
|
547
|
+
"""
|
|
548
|
+
old = "if (!aresetn || clear_pulse)"
|
|
549
|
+
_once(text, old, "sdm_reset_break")
|
|
550
|
+
alts = [
|
|
551
|
+
(
|
|
552
|
+
"if (aresetn || clear_pulse)",
|
|
553
|
+
"sinc3 reset inverted (clears while running, runs in reset)",
|
|
554
|
+
),
|
|
555
|
+
(
|
|
556
|
+
"if (1'b1)",
|
|
557
|
+
"sinc3 reset stuck active (counters held at zero)",
|
|
558
|
+
),
|
|
559
|
+
]
|
|
560
|
+
new, desc = alts[variant % len(alts)]
|
|
561
|
+
return text.replace(old, new), {"variant_desc": desc}
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
def sdm_truncation(text, variant):
|
|
565
|
+
"""Narrow the fast-path output so DC full scale never reaches OSR^3.
|
|
566
|
+
|
|
567
|
+
Args:
|
|
568
|
+
text: Base file text to mutate.
|
|
569
|
+
variant: Variant index selecting the rewrite.
|
|
570
|
+
|
|
571
|
+
Returns:
|
|
572
|
+
(mutated_text, extra_evidence) pair.
|
|
573
|
+
|
|
574
|
+
Raises:
|
|
575
|
+
MutationError: Probe site missing or ambiguous.
|
|
576
|
+
"""
|
|
577
|
+
old = "data_fast <= f_c3[31:0];"
|
|
578
|
+
_once(text, old, "sdm_truncation")
|
|
579
|
+
alts = [
|
|
580
|
+
(
|
|
581
|
+
"data_fast <= f_c3[31:0] & 32'h000000FF;",
|
|
582
|
+
"data_fast masked to 8 bits (max 255, want 15625)",
|
|
583
|
+
),
|
|
584
|
+
(
|
|
585
|
+
"data_fast <= f_c3[31:0] & 32'h0000000F;",
|
|
586
|
+
"data_fast masked to 4 bits (max 15, want 15625)",
|
|
587
|
+
),
|
|
588
|
+
(
|
|
589
|
+
"data_fast <= {24'b0, f_c3[7:0]};",
|
|
590
|
+
"data_fast zero-extended from 8 bits (max 255)",
|
|
591
|
+
),
|
|
592
|
+
]
|
|
593
|
+
new, desc = alts[variant % len(alts)]
|
|
594
|
+
return text.replace(old, new), {"variant_desc": desc}
|
|
595
|
+
|
|
596
|
+
|
|
597
|
+
def sdm_unconnected_port(text, variant):
|
|
598
|
+
"""Break the bitstream input path, as if its port were left open.
|
|
599
|
+
|
|
600
|
+
Args:
|
|
601
|
+
text: Base file text to mutate.
|
|
602
|
+
variant: Variant index selecting the rewrite.
|
|
603
|
+
|
|
604
|
+
Returns:
|
|
605
|
+
(mutated_text, extra_evidence) pair.
|
|
606
|
+
|
|
607
|
+
Raises:
|
|
608
|
+
MutationError: Probe site missing or ambiguous.
|
|
609
|
+
"""
|
|
610
|
+
if variant % 2 == 0:
|
|
611
|
+
old = "wire step = ctrl_enable && bit_ce;"
|
|
612
|
+
_once(text, old, "sdm_unconnected_port")
|
|
613
|
+
new = "wire step = ctrl_enable && 1'b0;"
|
|
614
|
+
desc = "bit_ce path tied low (never steps, as if unconnected)"
|
|
615
|
+
else:
|
|
616
|
+
old = "wire signed [1:0] din = bit_i ? 2'sd1 : -2'sd1;"
|
|
617
|
+
_once(text, old, "sdm_unconnected_port")
|
|
618
|
+
new = "wire signed [1:0] din = 2'sd0;"
|
|
619
|
+
desc = "bit_i path tied to zero (input ignored, as if unconnected)"
|
|
620
|
+
return text.replace(old, new), {"variant_desc": desc}
|
|
621
|
+
|
|
622
|
+
|
|
623
|
+
def sdtop_sizing_out_of_spec(text, variant):
|
|
624
|
+
"""Move the RIN input-leg length off its 102.57 nominal; the input
|
|
625
|
+
gain shifts, the integrator DC leaves its [0.8, 1.0] V window.
|
|
626
|
+
|
|
627
|
+
Expected values are live-verified (ngspice + the sky130 store,
|
|
628
|
+
tt/27C settled-window clocked mean; otherwise quarantined per
|
|
629
|
+
NGSPICE-LIVE): the closed loop servos mild halve/double moves
|
|
630
|
+
back in-band, so the variants are strengthened past the servo to
|
|
631
|
+
actually violate the checked window — l=30 drives the integrator
|
|
632
|
+
to 0.17 V, l=400 pushes it to 1.03 V, and the 10.0 extreme rails
|
|
633
|
+
it at 0.01 V. The verdict mapping is pinned by canned-envelope
|
|
634
|
+
parse tests.
|
|
635
|
+
|
|
636
|
+
Args:
|
|
637
|
+
text: Base file text to mutate.
|
|
638
|
+
variant: Variant index selecting the rewrite.
|
|
639
|
+
|
|
640
|
+
Returns:
|
|
641
|
+
(mutated_text, extra_evidence) pair.
|
|
642
|
+
|
|
643
|
+
Raises:
|
|
644
|
+
MutationError: Probe site missing or ambiguous.
|
|
645
|
+
"""
|
|
646
|
+
old = (
|
|
647
|
+
"X64 ota_layout_0/INM UA0 VGND "
|
|
648
|
+
"sky130_fd_pr__res_high_po_0p35 l=102.57"
|
|
649
|
+
)
|
|
650
|
+
_once(text, old, "sdtop_sizing_out_of_spec")
|
|
651
|
+
alts = [
|
|
652
|
+
(30, 0.173, "RIN l 102.57 -> 30 (gain high, integrator driven low)"),
|
|
653
|
+
(400, 1.030, "RIN l 102.57 -> 400 (gain low, integrator pushed high)"),
|
|
654
|
+
(10.0, 0.015, "RIN l 102.57 -> 10.0 (extreme, integrator rails)"),
|
|
655
|
+
]
|
|
656
|
+
rin_l, expected_int_dc, desc = alts[variant % len(alts)]
|
|
657
|
+
new = old.replace("l=102.57", f"l={rin_l}")
|
|
658
|
+
extra = {
|
|
659
|
+
"variant_desc": desc,
|
|
660
|
+
"rin_l": rin_l,
|
|
661
|
+
"expected_int_dc": expected_int_dc,
|
|
662
|
+
}
|
|
663
|
+
return text.replace(old, new), extra
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
def sdtop_open_net(text, variant):
|
|
667
|
+
"""Open the RIN input leg: X64 lifted from UA0.
|
|
668
|
+
|
|
669
|
+
Variant 0 renames the input net (leg floats on UA0_OPEN);
|
|
670
|
+
variant 1 comments the device (leg open). No value changes —
|
|
671
|
+
the topology break starves the integrator and its DC misses
|
|
672
|
+
[0.8, 1.0] V. Same quarantine/parse story as sizing.
|
|
673
|
+
|
|
674
|
+
Args:
|
|
675
|
+
text: Base file text to mutate.
|
|
676
|
+
variant: Variant index selecting the rewrite.
|
|
677
|
+
|
|
678
|
+
Returns:
|
|
679
|
+
(mutated_text, extra_evidence) pair.
|
|
680
|
+
|
|
681
|
+
Raises:
|
|
682
|
+
MutationError: Probe site missing or ambiguous.
|
|
683
|
+
"""
|
|
684
|
+
old = (
|
|
685
|
+
"X64 ota_layout_0/INM UA0 VGND "
|
|
686
|
+
"sky130_fd_pr__res_high_po_0p35 l=102.57"
|
|
687
|
+
)
|
|
688
|
+
_once(text, old, "sdtop_open_net")
|
|
689
|
+
alts = [
|
|
690
|
+
(
|
|
691
|
+
old.replace("X64 ota_layout_0/INM UA0 VGND", "X64 ota_layout_0/INM UA0_OPEN VGND"),
|
|
692
|
+
"X64 input lifted onto UA0_OPEN (input open)",
|
|
693
|
+
),
|
|
694
|
+
(
|
|
695
|
+
f"* {old} (MUTATE-HARNESS sdtop_open_net: device lifted)",
|
|
696
|
+
"X64 commented out (RIN leg open)",
|
|
697
|
+
),
|
|
698
|
+
]
|
|
699
|
+
new, desc = alts[variant % len(alts)]
|
|
700
|
+
return text.replace(old, new), {"variant_desc": desc}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Engine op-dispatch machinery (REFACTOR-COMPOSITION split)."""
|