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,776 @@
|
|
|
1
|
+
"""MUTATE-HARNESS: systematic incorrect-design generator.
|
|
2
|
+
|
|
3
|
+
Each operator stages scratch COPIES of its base fixture files, then
|
|
4
|
+
mutates the copy — vendored and committed fixture trees are never
|
|
5
|
+
touched in place. Variant selection is `seed % len(variants)`, so
|
|
6
|
+
every mutation is reproducible from its seed. The OPERATORS table is
|
|
7
|
+
the operator→verdict map: each entry declares the engine operation
|
|
8
|
+
that rechecks it plus the expected verdict and rules.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import shutil
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
from . import operators
|
|
15
|
+
from .operators import MutationError
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"OPERATORS",
|
|
19
|
+
"SERV_WATCHDOG_UNITS",
|
|
20
|
+
"MutationError",
|
|
21
|
+
"apply_operator",
|
|
22
|
+
"copy_base_files",
|
|
23
|
+
"operator_variant",
|
|
24
|
+
"stage_design_extras",
|
|
25
|
+
"stage_good_design",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
# VALIDATE-D staging watchdog for SERV runs. The good hello run
|
|
29
|
+
# finishes below 4M units (bisected: PASS at 4M, watchdog at 3M), so
|
|
30
|
+
# 5M keeps a margin over good while holding mutant sims to seconds
|
|
31
|
+
# instead of the 200M-harness default (33 s per hang).
|
|
32
|
+
SERV_WATCHDOG_UNITS = 5000000
|
|
33
|
+
|
|
34
|
+
# SERV sim file list (VALIDATE-D): vendored rel paths under
|
|
35
|
+
# fixtures/upstream/serv, mirrored by the committed
|
|
36
|
+
# tests/adapters/fixtures/hdl/serv_sources.txt manifest (a validate
|
|
37
|
+
# test asserts the two stay equal). Staged with structure kept.
|
|
38
|
+
_SERV_FILES = [
|
|
39
|
+
"rtl/serv_aligner.v",
|
|
40
|
+
"rtl/serv_alu.v",
|
|
41
|
+
"rtl/serv_bufreg2.v",
|
|
42
|
+
"rtl/serv_bufreg.v",
|
|
43
|
+
"rtl/serv_compdec.v",
|
|
44
|
+
"rtl/serv_csr.v",
|
|
45
|
+
"rtl/serv_ctrl.v",
|
|
46
|
+
"rtl/serv_debug.v",
|
|
47
|
+
"rtl/serv_decode.v",
|
|
48
|
+
"rtl/serv_immdec.v",
|
|
49
|
+
"rtl/serv_mem_if.v",
|
|
50
|
+
"rtl/serv_rf_if.v",
|
|
51
|
+
"rtl/serv_rf_ram_if.v",
|
|
52
|
+
"rtl/serv_rf_ram.v",
|
|
53
|
+
"rtl/serv_rf_top.v",
|
|
54
|
+
"rtl/serv_state.v",
|
|
55
|
+
"rtl/serv_synth_wrapper.v",
|
|
56
|
+
"rtl/serv_top.v",
|
|
57
|
+
"servile/servile_arbiter.v",
|
|
58
|
+
"servile/servile_mux.v",
|
|
59
|
+
"servile/servile_rf_mem_if.v",
|
|
60
|
+
"servile/servile.v",
|
|
61
|
+
"servant/servant.v",
|
|
62
|
+
"servant/servant_mux.v",
|
|
63
|
+
"servant/servant_ram.v",
|
|
64
|
+
"servant/servant_timer.v",
|
|
65
|
+
"servant/servant_gpio.v",
|
|
66
|
+
"bench/servant_sim.v",
|
|
67
|
+
"bench/uart_decoder.v",
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
_PICO_FILES = ["picorv32.v", "testbench_ez.v"]
|
|
71
|
+
|
|
72
|
+
# VALIDATE-A bandgap snapshot (2amlogic sky130-bandgap): the
|
|
73
|
+
# output-voltage-tc netlist that the signoff envelope 1a grades
|
|
74
|
+
# 45/45 PASS on DR-005 [1.176, 1.224] V. Staged flat.
|
|
75
|
+
_BANDGAP_SNAPSHOT = "20260817-015751-13476b7.spice"
|
|
76
|
+
_BANDGAP_FILES = [_BANDGAP_SNAPSHOT]
|
|
77
|
+
_BANDGAP_BASE = (
|
|
78
|
+
"fixtures/upstream/sky130-bandgap/sim/output-voltage-tc/netlist-snapshots"
|
|
79
|
+
)
|
|
80
|
+
# DR-005 ratified accuracy row: 1.20 V +/-2% untrimmed.
|
|
81
|
+
_BANDGAP_VREF_MIN = 1.176
|
|
82
|
+
_BANDGAP_VREF_MAX = 1.224
|
|
83
|
+
|
|
84
|
+
# VALIDATE-P MZI pair: the SAX-notebook balanced circuit
|
|
85
|
+
# (tests/adapters/fixtures/sax/mzi.yml) plus the cspdk reference
|
|
86
|
+
# si340 MZI GDS as layout truth. Documented CORNERSTONE min rules
|
|
87
|
+
# for GDS 3/0: 350 nm feature, 200 nm gap (49th-call guidelines
|
|
88
|
+
# section 5.3-5.4, Table 4). Staged flat as mzi.yml + mzi_ref.gds.
|
|
89
|
+
_MZI_CIRCUIT = "mzi.yml"
|
|
90
|
+
_MZI_REF_GDS = "fixtures/upstream/cspdk/tests/gds_ref_si340/mzi.gds"
|
|
91
|
+
_MZI_STAGED_GDS = "mzi_ref.gds"
|
|
92
|
+
_MZI_TECH = "cornerstone-si340"
|
|
93
|
+
_MZI_CELL = "mzi"
|
|
94
|
+
_MZI_RULES = {"layer": [3, 0], "width_um": 0.35, "space_um": 0.2}
|
|
95
|
+
_MZI_RULES_REF = (
|
|
96
|
+
"CORNERSTONE-49th-Call-Design-Guidelines-1.pdf section 5.3-5.4 "
|
|
97
|
+
"Table 4 (vendored cspdk references/)"
|
|
98
|
+
)
|
|
99
|
+
_MZI_TIMEOUT_S = 120
|
|
100
|
+
|
|
101
|
+
# VALIDATE-M sigma-delta seam pairs: the digital wrapper sdm_rx.v
|
|
102
|
+
# (fixtures/upstream/ttsky-sigma-delta/rtl) plus the committed
|
|
103
|
+
# Verilog bench and the cleaned PEX bitstream vector (the one-way
|
|
104
|
+
# seam handoff), and the analog macro sd_top PEX netlist
|
|
105
|
+
# (fixtures/upstream/ttsky-sigma-delta/spice). Staged flat.
|
|
106
|
+
_SDM_FILES = ["sdm_rx.v"]
|
|
107
|
+
_SDM_BASE = "fixtures/upstream/ttsky-sigma-delta/rtl"
|
|
108
|
+
_SDM_BENCH = "tests/adapters/fixtures/hdl/sdm_rx_bench.v"
|
|
109
|
+
_SDM_VECTOR = "fixtures/upstream/ttsky-sigma-delta/rtl/tb/vectors/pex_bits.txt"
|
|
110
|
+
_SDM_STAGED_VECTOR = "pex_bits_clean.txt"
|
|
111
|
+
_SDM_TIMEOUT_S = 120
|
|
112
|
+
_SDTOP_SNAPSHOT = "sd_top_pex.spice"
|
|
113
|
+
_SDTOP_FILES = [_SDTOP_SNAPSHOT]
|
|
114
|
+
_SDTOP_BASE = "fixtures/upstream/ttsky-sigma-delta/spice"
|
|
115
|
+
# Integrator monitor UA1 DC ~0.9 V mean (docs/09b Phase 1.1).
|
|
116
|
+
_SDTOP_INT_MIN = 0.8
|
|
117
|
+
_SDTOP_INT_MAX = 1.0
|
|
118
|
+
# Mixed-flow testbench wrapper: the PEX is a bare .subckt (no
|
|
119
|
+
# top-level instantiation), so the staged sim dir carries this
|
|
120
|
+
# bench alongside the macro copy. Stimuli mirror the acceptance
|
|
121
|
+
# sim/top_tb.py at DC mid-scale: 3.3 V analog / 1.8 V digital rails,
|
|
122
|
+
# 50 MHz clock, UA0 = VIN_MID 1.65 V through 50 ohms, 1 pF loads on
|
|
123
|
+
# the bitstream outputs, 50 fF on the integrator probe node. PEX
|
|
124
|
+
# port order: UA0 UO0 UO1 CLK VDPWR UA1 VGND VAPWR.
|
|
125
|
+
_SDTOP_TB_NAME = "sd_top_tb.spice"
|
|
126
|
+
_SDTOP_TB = """* sd_top mixed-flow testbench (staged; mirrors sim/top_tb.py stimuli)
|
|
127
|
+
VAP vapwr 0 3.3
|
|
128
|
+
VDP vdpwr 0 1.8
|
|
129
|
+
VGN vgnd 0 0
|
|
130
|
+
VCLK clk 0 PULSE(0 1.8 0 0.2n 0.2n 10n 20n)
|
|
131
|
+
VIN vsrc 0 1.65
|
|
132
|
+
RS vsrc ua0 50
|
|
133
|
+
CU0 uo0 0 1p
|
|
134
|
+
CU1 uo1 0 1p
|
|
135
|
+
CA1 ua1 0 50f
|
|
136
|
+
XDUT ua0 uo0 uo1 clk vdpwr ua1 vgnd vapwr sd_top
|
|
137
|
+
"""
|
|
138
|
+
# Solver conditioning for the registered store: X99 (bias-startup
|
|
139
|
+
# PFET, w=5 l=50) sits outside every hv-FET model bin (lmax 20.2 um),
|
|
140
|
+
# so ngspice aborts ("could not find a valid modelname") once the
|
|
141
|
+
# wrapper instantiates the macro. The STAGED copy is clamped to the
|
|
142
|
+
# top bin edge; the settled int_dc mean moves 38 uV between l=15 and
|
|
143
|
+
# l=20, so the clamp is bench conditioning, not a design change.
|
|
144
|
+
_SDTOP_X99_OLD = (
|
|
145
|
+
"X99 VAPWR VGND bias_layout_0/nst VAPWR "
|
|
146
|
+
"sky130_fd_pr__pfet_g5v0d10v5 ad=1.45 pd=10.58 as=1.45 ps=10.58 w=5 l=50"
|
|
147
|
+
)
|
|
148
|
+
_SDTOP_X99_NEW = _SDTOP_X99_OLD.replace("l=50", "l=20")
|
|
149
|
+
# Settled-window clocked mean: the static loop has no in-band OP, so
|
|
150
|
+
# the probe is a 2 us 50 MHz transient recorded from 1 us on.
|
|
151
|
+
_SDTOP_ANALYSES = ["tran 0.5n 2u 1u"]
|
|
152
|
+
_SDTOP_OPTIONS = [
|
|
153
|
+
"wnflag=1",
|
|
154
|
+
"method=gear",
|
|
155
|
+
"reltol=1e-4",
|
|
156
|
+
"vntol=1e-6",
|
|
157
|
+
"abstol=1e-10",
|
|
158
|
+
"itl4=200",
|
|
159
|
+
]
|
|
160
|
+
|
|
161
|
+
OPERATORS = {
|
|
162
|
+
"digital_reset_break": {
|
|
163
|
+
"domain": "digital",
|
|
164
|
+
"operation": "run_hdl_test",
|
|
165
|
+
"target_file": "counter.v",
|
|
166
|
+
"files": ["counter.v", "tb_pass.v"],
|
|
167
|
+
"base": "tests/adapters/fixtures/hdl",
|
|
168
|
+
"expected_verdict": "FAIL",
|
|
169
|
+
"expected_rules": ["assert_fatal"],
|
|
170
|
+
"variants": 2,
|
|
171
|
+
"doc": "Break the async reset (inverted or stuck); tb $fatal fires.",
|
|
172
|
+
},
|
|
173
|
+
"digital_truncation": {
|
|
174
|
+
"domain": "digital",
|
|
175
|
+
"operation": "run_hdl_test",
|
|
176
|
+
"target_file": "counter.v",
|
|
177
|
+
"files": ["counter.v", "tb_pass.v"],
|
|
178
|
+
"base": "tests/adapters/fixtures/hdl",
|
|
179
|
+
"expected_verdict": "FAIL",
|
|
180
|
+
"expected_rules": ["assert_fatal"],
|
|
181
|
+
"variants": 3,
|
|
182
|
+
"doc": "Narrow the count update; the sequence never reaches 10.",
|
|
183
|
+
},
|
|
184
|
+
"digital_unconnected_port": {
|
|
185
|
+
"domain": "digital",
|
|
186
|
+
"operation": "run_hdl_test",
|
|
187
|
+
"target_file": "tb_pass.v",
|
|
188
|
+
"files": ["counter.v", "tb_pass.v"],
|
|
189
|
+
"base": "tests/adapters/fixtures/hdl",
|
|
190
|
+
"expected_verdict": "FAIL",
|
|
191
|
+
"expected_rules": ["assert_fatal"],
|
|
192
|
+
"variants": 2,
|
|
193
|
+
"doc": "Leave a DUT port open in the harness; the count mismatches.",
|
|
194
|
+
},
|
|
195
|
+
"serv_reset_break": {
|
|
196
|
+
"domain": "digital",
|
|
197
|
+
"design": "serv",
|
|
198
|
+
"operation": "run_hdl_test",
|
|
199
|
+
"target_file": "servant/servant.v",
|
|
200
|
+
"files": list(_SERV_FILES),
|
|
201
|
+
"base": "fixtures/upstream/serv",
|
|
202
|
+
"expected_verdict": "FAIL",
|
|
203
|
+
"expected_rules": ["assert_fatal"],
|
|
204
|
+
"variants": 2,
|
|
205
|
+
"doc": "Hold the servant CPU in reset (stuck or inverted); watchdog fires.",
|
|
206
|
+
},
|
|
207
|
+
"serv_truncation": {
|
|
208
|
+
"domain": "digital",
|
|
209
|
+
"design": "serv",
|
|
210
|
+
"operation": "run_hdl_test",
|
|
211
|
+
"target_file": "rtl/serv_bufreg.v",
|
|
212
|
+
"files": list(_SERV_FILES),
|
|
213
|
+
"base": "fixtures/upstream/serv",
|
|
214
|
+
"expected_verdict": "FAIL",
|
|
215
|
+
"expected_rules": ["assert_fatal"],
|
|
216
|
+
"variants": 3,
|
|
217
|
+
"doc": "Narrow the data-bus address; MMIO unreachable, no HALT.",
|
|
218
|
+
},
|
|
219
|
+
"serv_unconnected_port": {
|
|
220
|
+
"domain": "digital",
|
|
221
|
+
"design": "serv",
|
|
222
|
+
"operation": "run_hdl_test",
|
|
223
|
+
"target_file": "servant/servant.v",
|
|
224
|
+
"files": list(_SERV_FILES),
|
|
225
|
+
"base": "fixtures/upstream/serv",
|
|
226
|
+
"expected_verdict": "FAIL",
|
|
227
|
+
"expected_rules": ["assert_fatal"],
|
|
228
|
+
"variants": 2,
|
|
229
|
+
"doc": "Leave a servant CPU port open; firmware never boots.",
|
|
230
|
+
},
|
|
231
|
+
"picorv32_reset_break": {
|
|
232
|
+
"domain": "digital",
|
|
233
|
+
"design": "picorv32",
|
|
234
|
+
"operation": "run_hdl_test",
|
|
235
|
+
"target_file": "testbench_ez.v",
|
|
236
|
+
"files": list(_PICO_FILES),
|
|
237
|
+
"base": "fixtures/upstream/picorv32",
|
|
238
|
+
"expected_verdict": "FAIL",
|
|
239
|
+
"expected_rules": ["assert_fatal"],
|
|
240
|
+
"variants": 2,
|
|
241
|
+
"doc": "Hold test_ez in reset (stuck or re-asserted); no progress.",
|
|
242
|
+
},
|
|
243
|
+
"picorv32_truncation": {
|
|
244
|
+
"domain": "digital",
|
|
245
|
+
"design": "picorv32",
|
|
246
|
+
"operation": "run_hdl_test",
|
|
247
|
+
"target_file": "picorv32.v",
|
|
248
|
+
"files": list(_PICO_FILES),
|
|
249
|
+
"base": "fixtures/upstream/picorv32",
|
|
250
|
+
"expected_verdict": "FAIL",
|
|
251
|
+
"expected_rules": ["assert_fatal"],
|
|
252
|
+
"variants": 3,
|
|
253
|
+
"doc": "Narrow the ALU add path; the ez counter never reaches 10.",
|
|
254
|
+
},
|
|
255
|
+
"picorv32_unconnected_port": {
|
|
256
|
+
"domain": "digital",
|
|
257
|
+
"design": "picorv32",
|
|
258
|
+
"operation": "run_hdl_test",
|
|
259
|
+
"target_file": "testbench_ez.v",
|
|
260
|
+
"files": list(_PICO_FILES),
|
|
261
|
+
"base": "fixtures/upstream/picorv32",
|
|
262
|
+
"expected_verdict": "FAIL",
|
|
263
|
+
"expected_rules": ["assert_fatal"],
|
|
264
|
+
"variants": 2,
|
|
265
|
+
"doc": "Leave a CPU port open in the ez bench; fetches stall.",
|
|
266
|
+
},
|
|
267
|
+
"analog_sizing_out_of_spec": {
|
|
268
|
+
"domain": "analog",
|
|
269
|
+
"operation": "run_spice",
|
|
270
|
+
"target_file": "rc_divider.spice",
|
|
271
|
+
"files": ["rc_divider.spice"],
|
|
272
|
+
"base": "tests/adapters/fixtures/ngspice",
|
|
273
|
+
"expected_verdict": "FAIL",
|
|
274
|
+
"expected_rules": ["measurement"],
|
|
275
|
+
"variants": 3,
|
|
276
|
+
"doc": "Move R2 off nominal; Vout leaves its [1.199, 1.201] V bound.",
|
|
277
|
+
},
|
|
278
|
+
"analog_open_net": {
|
|
279
|
+
"domain": "analog",
|
|
280
|
+
"operation": "run_spice",
|
|
281
|
+
"target_file": "rc_divider.spice",
|
|
282
|
+
"files": ["rc_divider.spice"],
|
|
283
|
+
"base": "tests/adapters/fixtures/ngspice",
|
|
284
|
+
"expected_verdict": "FAIL",
|
|
285
|
+
"expected_rules": ["measurement"],
|
|
286
|
+
"variants": 2,
|
|
287
|
+
"doc": "Lift R2 from the divider; out rises to the 1.8 V rail.",
|
|
288
|
+
},
|
|
289
|
+
"layout_drc_violation": {
|
|
290
|
+
"domain": "layout",
|
|
291
|
+
"operation": "run_drc",
|
|
292
|
+
"target_file": "good.mag",
|
|
293
|
+
"files": ["good.mag"],
|
|
294
|
+
"base": "tests/adapters/fixtures/drc",
|
|
295
|
+
"expected_verdict": "FAIL",
|
|
296
|
+
"expected_rules": ["spacing", "width"],
|
|
297
|
+
"variants": 2,
|
|
298
|
+
"doc": "Shift/shrink a rect into an scmos spacing/width violation.",
|
|
299
|
+
},
|
|
300
|
+
"netlist_lvs_mismatch": {
|
|
301
|
+
"domain": "layout",
|
|
302
|
+
"operation": "run_lvs",
|
|
303
|
+
"target_file": "schematic.spice",
|
|
304
|
+
"files": ["layout.spice", "schematic.spice"],
|
|
305
|
+
"base": "tests/mutate/fixtures/lvs_inv",
|
|
306
|
+
"expected_verdict": "FAIL",
|
|
307
|
+
"expected_rules": ["lvs_net_mismatch"],
|
|
308
|
+
"variants": 2,
|
|
309
|
+
"doc": "Rename a schematic bulk net; layout vs schematic mismatch.",
|
|
310
|
+
},
|
|
311
|
+
"photonic_geometry_mistune": {
|
|
312
|
+
"domain": "photonic",
|
|
313
|
+
"design": "mzi",
|
|
314
|
+
"operation": "run_optical",
|
|
315
|
+
"target_file": "mzi.yml",
|
|
316
|
+
"files": ["mzi.yml"],
|
|
317
|
+
"base": "tests/adapters/fixtures/sax",
|
|
318
|
+
"expected_verdict": "FAIL",
|
|
319
|
+
"expected_rules": ["transmission"],
|
|
320
|
+
"variants": 2,
|
|
321
|
+
"doc": "Lengthen the MZI bottom arm; cross-port target misses.",
|
|
322
|
+
},
|
|
323
|
+
"photonic_circuit_mistune": {
|
|
324
|
+
"domain": "photonic",
|
|
325
|
+
"design": "mzi",
|
|
326
|
+
"operation": "run_optical",
|
|
327
|
+
"target_file": "mzi.yml",
|
|
328
|
+
"files": ["mzi.yml"],
|
|
329
|
+
"base": "tests/adapters/fixtures/sax",
|
|
330
|
+
"expected_verdict": "FAIL",
|
|
331
|
+
"expected_rules": ["transmission"],
|
|
332
|
+
"variants": 1,
|
|
333
|
+
"doc": "Detune the output coupler; cross-port target misses.",
|
|
334
|
+
},
|
|
335
|
+
"bandgap_sizing_out_of_spec": {
|
|
336
|
+
"domain": "analog",
|
|
337
|
+
"design": "bandgap",
|
|
338
|
+
"operation": "run_spice",
|
|
339
|
+
"target_file": _BANDGAP_SNAPSHOT,
|
|
340
|
+
"files": list(_BANDGAP_FILES),
|
|
341
|
+
"base": _BANDGAP_BASE,
|
|
342
|
+
"expected_verdict": "FAIL",
|
|
343
|
+
"expected_rules": ["measurement"],
|
|
344
|
+
"variants": 3,
|
|
345
|
+
"doc": "Move n_r2 off 51; Vref leaves DR-005 [1.176, 1.224] V.",
|
|
346
|
+
},
|
|
347
|
+
"bandgap_open_net": {
|
|
348
|
+
"domain": "analog",
|
|
349
|
+
"design": "bandgap",
|
|
350
|
+
"operation": "run_spice",
|
|
351
|
+
"target_file": _BANDGAP_SNAPSHOT,
|
|
352
|
+
"files": list(_BANDGAP_FILES),
|
|
353
|
+
"base": _BANDGAP_BASE,
|
|
354
|
+
"expected_verdict": "FAIL",
|
|
355
|
+
"expected_rules": ["measurement"],
|
|
356
|
+
"variants": 2,
|
|
357
|
+
"doc": "Lift XR2A from VOUT; feedback cut, Vref misses.",
|
|
358
|
+
},
|
|
359
|
+
"sdm_reset_break": {
|
|
360
|
+
"domain": "digital",
|
|
361
|
+
"design": "sdm_rx",
|
|
362
|
+
"operation": "run_hdl_test",
|
|
363
|
+
"target_file": "sdm_rx.v",
|
|
364
|
+
"files": list(_SDM_FILES),
|
|
365
|
+
"base": _SDM_BASE,
|
|
366
|
+
"expected_verdict": "FAIL",
|
|
367
|
+
"expected_rules": ["assert_fatal"],
|
|
368
|
+
"variants": 2,
|
|
369
|
+
"doc": "Break the sinc3-path reset (inverted or stuck); bench $fatal fires.",
|
|
370
|
+
},
|
|
371
|
+
"sdm_truncation": {
|
|
372
|
+
"domain": "digital",
|
|
373
|
+
"design": "sdm_rx",
|
|
374
|
+
"operation": "run_hdl_test",
|
|
375
|
+
"target_file": "sdm_rx.v",
|
|
376
|
+
"files": list(_SDM_FILES),
|
|
377
|
+
"base": _SDM_BASE,
|
|
378
|
+
"expected_verdict": "FAIL",
|
|
379
|
+
"expected_rules": ["assert_fatal"],
|
|
380
|
+
"variants": 3,
|
|
381
|
+
"doc": "Narrow data_fast; DC full scale never reaches 25^3.",
|
|
382
|
+
},
|
|
383
|
+
"sdm_unconnected_port": {
|
|
384
|
+
"domain": "digital",
|
|
385
|
+
"design": "sdm_rx",
|
|
386
|
+
"operation": "run_hdl_test",
|
|
387
|
+
"target_file": "sdm_rx.v",
|
|
388
|
+
"files": list(_SDM_FILES),
|
|
389
|
+
"base": _SDM_BASE,
|
|
390
|
+
"expected_verdict": "FAIL",
|
|
391
|
+
"expected_rules": ["assert_fatal"],
|
|
392
|
+
"variants": 2,
|
|
393
|
+
"doc": "Break the bitstream input path (bit_ce/bit_i as if unconnected).",
|
|
394
|
+
},
|
|
395
|
+
"sdtop_sizing_out_of_spec": {
|
|
396
|
+
"domain": "analog",
|
|
397
|
+
"design": "sd_top",
|
|
398
|
+
"operation": "run_spice",
|
|
399
|
+
"target_file": _SDTOP_SNAPSHOT,
|
|
400
|
+
"files": list(_SDTOP_FILES),
|
|
401
|
+
"base": _SDTOP_BASE,
|
|
402
|
+
"expected_verdict": "FAIL",
|
|
403
|
+
"expected_rules": ["measurement"],
|
|
404
|
+
"variants": 3,
|
|
405
|
+
"doc": "Move RIN l off 102.57; integrator DC leaves [0.8, 1.0] V.",
|
|
406
|
+
},
|
|
407
|
+
"sdtop_open_net": {
|
|
408
|
+
"domain": "analog",
|
|
409
|
+
"design": "sd_top",
|
|
410
|
+
"operation": "run_spice",
|
|
411
|
+
"target_file": _SDTOP_SNAPSHOT,
|
|
412
|
+
"files": list(_SDTOP_FILES),
|
|
413
|
+
"base": _SDTOP_BASE,
|
|
414
|
+
"expected_verdict": "FAIL",
|
|
415
|
+
"expected_rules": ["measurement"],
|
|
416
|
+
"variants": 2,
|
|
417
|
+
"doc": "Lift X64 from UA0; input open, integrator DC misses.",
|
|
418
|
+
},
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
def operator_variant(name, seed):
|
|
423
|
+
"""Variant index for (operator, seed): seed mod variant count.
|
|
424
|
+
|
|
425
|
+
Args:
|
|
426
|
+
name: Operator name selecting the variant count.
|
|
427
|
+
seed: Integer seed selecting the variant.
|
|
428
|
+
|
|
429
|
+
Returns:
|
|
430
|
+
Variant index in range.
|
|
431
|
+
|
|
432
|
+
Raises:
|
|
433
|
+
MutationError: Non-integer seed.
|
|
434
|
+
"""
|
|
435
|
+
if isinstance(seed, bool) or not isinstance(seed, int):
|
|
436
|
+
raise MutationError(f"{name}: seed must be an int, got {seed!r}.")
|
|
437
|
+
return seed % OPERATORS[name]["variants"]
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
def copy_base_files(entry, src_dir, dest_dir):
|
|
441
|
+
"""Copy an entry's base files into dest_dir; return staged names.
|
|
442
|
+
|
|
443
|
+
Repo-relative paths (SERV rtl/ + servile/ + servant/ + bench/)
|
|
444
|
+
keep their structure under dest_dir; flat fixtures stay flat.
|
|
445
|
+
|
|
446
|
+
Args:
|
|
447
|
+
entry: Operator table entry naming the base files.
|
|
448
|
+
src_dir: Directory the base files copy from.
|
|
449
|
+
dest_dir: Directory the copies stage into.
|
|
450
|
+
|
|
451
|
+
Returns:
|
|
452
|
+
Staged file names.
|
|
453
|
+
|
|
454
|
+
Raises:
|
|
455
|
+
FileNotFoundError: Missing base file under src_dir.
|
|
456
|
+
"""
|
|
457
|
+
src = Path(src_dir)
|
|
458
|
+
dest = Path(dest_dir)
|
|
459
|
+
dest.mkdir(parents=True, exist_ok=True)
|
|
460
|
+
staged = []
|
|
461
|
+
for filename in entry["files"]:
|
|
462
|
+
out = dest / filename
|
|
463
|
+
out.parent.mkdir(parents=True, exist_ok=True)
|
|
464
|
+
shutil.copy(src / filename, out)
|
|
465
|
+
staged.append(filename)
|
|
466
|
+
return staged
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
def apply_operator(name, dest_dir, seed, src_dir):
|
|
470
|
+
"""Stage base files into dest_dir and mutate the target copy.
|
|
471
|
+
|
|
472
|
+
Args:
|
|
473
|
+
name: Operator name to apply.
|
|
474
|
+
dest_dir: Directory the mutant stages into.
|
|
475
|
+
seed: Integer seed selecting the variant.
|
|
476
|
+
src_dir: Directory the base files copy from.
|
|
477
|
+
|
|
478
|
+
Returns:
|
|
479
|
+
JSON-native evidence (operator, seed, variant, expected
|
|
480
|
+
verdict/rules, plus operator specifics).
|
|
481
|
+
|
|
482
|
+
Raises:
|
|
483
|
+
KeyError: Unknown operator.
|
|
484
|
+
MutationError: Drifted probe site (fixture changed).
|
|
485
|
+
FileNotFoundError: Missing base file under src_dir.
|
|
486
|
+
"""
|
|
487
|
+
entry = OPERATORS[name]
|
|
488
|
+
variant = operator_variant(name, seed)
|
|
489
|
+
dest = Path(dest_dir)
|
|
490
|
+
staged = copy_base_files(entry, src_dir, dest)
|
|
491
|
+
target = dest / entry["target_file"]
|
|
492
|
+
mutate = getattr(operators, name)
|
|
493
|
+
mutated, extra = mutate(target.read_text(encoding="utf-8"), variant)
|
|
494
|
+
target.write_text(mutated, encoding="utf-8")
|
|
495
|
+
evidence = {
|
|
496
|
+
"operator": name,
|
|
497
|
+
"domain": entry["domain"],
|
|
498
|
+
"operation": entry["operation"],
|
|
499
|
+
"seed": seed,
|
|
500
|
+
"variant": variant,
|
|
501
|
+
"target_file": entry["target_file"],
|
|
502
|
+
"staged_files": staged,
|
|
503
|
+
"expected_verdict": entry["expected_verdict"],
|
|
504
|
+
"expected_rules": list(entry["expected_rules"]),
|
|
505
|
+
"expected_rule": extra.pop("expected_rule", entry["expected_rules"][0]),
|
|
506
|
+
}
|
|
507
|
+
evidence.update(extra)
|
|
508
|
+
return evidence
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
# VALIDATE-D/A/P/M design staging: base files come from
|
|
512
|
+
# apply_operator / copy_base_files; the extras below (committed
|
|
513
|
+
# harness or monitor or bench, vendored firmware or vector, watchdog,
|
|
514
|
+
# defines, the bandgap/sd_top run_spice job shapes, or the mzi
|
|
515
|
+
# circuit+layout pair) complete a runnable sim dir. Shared by
|
|
516
|
+
# tests/validate, scripts/mutate.py, and scripts/scenarios.py.
|
|
517
|
+
|
|
518
|
+
_DESIGNS = ("serv", "picorv32", "bandgap", "mzi", "sdm_rx", "sd_top")
|
|
519
|
+
_HARNESS = "tests/adapters/fixtures/hdl/serv_harness.v"
|
|
520
|
+
_MONITOR = "tests/adapters/fixtures/hdl/picorv32_monitor.v"
|
|
521
|
+
_FIRMWARE = "fixtures/upstream/serv/sw/hello_uart.hex"
|
|
522
|
+
_WATCHDOG_DEFAULT = "parameter watchdog_units = 200000000"
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
def _design_entry(design):
|
|
526
|
+
for entry in OPERATORS.values():
|
|
527
|
+
if entry.get("design") == design:
|
|
528
|
+
return entry
|
|
529
|
+
raise KeyError(f"unknown vendored design: {design!r}.")
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
def stage_design_extras(design, dest_dir, root):
|
|
533
|
+
"""Copy a design's extras into a staged sim dir; return job args.
|
|
534
|
+
|
|
535
|
+
Base files must already be staged (via apply_operator for a
|
|
536
|
+
mutant). Digital designs return sources/defines/timeout_s/
|
|
537
|
+
workdir for a run_hdl_test job (plus watchdog_units for SERV);
|
|
538
|
+
the bandgap/sd_top return sources/measurements/analyses/options/
|
|
539
|
+
params/corner/temp_c/timeout_s/workdir for a run_spice job
|
|
540
|
+
(the PDK pin is resolved by the caller from its own store, so
|
|
541
|
+
a missing store skips loudly at the call site, never here);
|
|
542
|
+
the mzi returns sources/workdir/timeout_s for a run_optical
|
|
543
|
+
job plus a layout sidecar (staged reference GDS + documented
|
|
544
|
+
CORNERSTONE rules) for a run_drc job; sdm_rx pairs the vendored
|
|
545
|
+
DUT with the committed Verilog bench + the cleaned PEX vector.
|
|
546
|
+
Missing pieces raise FileNotFoundError; a drifted harness
|
|
547
|
+
watchdog raises MutationError — never a silent
|
|
548
|
+
unmutated-shaped run.
|
|
549
|
+
|
|
550
|
+
Args:
|
|
551
|
+
design: Vendored design name (serv/picorv32/bandgap/mzi/
|
|
552
|
+
sdm_rx/sd_top).
|
|
553
|
+
dest_dir: Staged sim dir receiving the extras.
|
|
554
|
+
root: Repo root the extras copy from.
|
|
555
|
+
|
|
556
|
+
Returns:
|
|
557
|
+
Runnable job args for the design's operation (plus the mzi
|
|
558
|
+
layout sidecar).
|
|
559
|
+
|
|
560
|
+
Raises:
|
|
561
|
+
KeyError: Unknown design.
|
|
562
|
+
FileNotFoundError: Missing harness/firmware/vector/base
|
|
563
|
+
piece.
|
|
564
|
+
MutationError: Drifted probe or shim site.
|
|
565
|
+
"""
|
|
566
|
+
if design not in _DESIGNS:
|
|
567
|
+
raise KeyError(f"unknown vendored design: {design!r}.")
|
|
568
|
+
root = Path(root)
|
|
569
|
+
dest = Path(dest_dir)
|
|
570
|
+
dest.mkdir(parents=True, exist_ok=True)
|
|
571
|
+
if design == "mzi":
|
|
572
|
+
sources = [str(dest / name) for name in _staged_names(design, dest)]
|
|
573
|
+
ref_gds = root / _MZI_REF_GDS
|
|
574
|
+
if not ref_gds.is_file():
|
|
575
|
+
raise FileNotFoundError(
|
|
576
|
+
f"mzi staging: cspdk reference GDS missing: {ref_gds} "
|
|
577
|
+
"(scripts/fetch_fixtures.py --only cspdk)"
|
|
578
|
+
)
|
|
579
|
+
staged_gds = dest / _MZI_STAGED_GDS
|
|
580
|
+
shutil.copy(ref_gds, staged_gds)
|
|
581
|
+
return {
|
|
582
|
+
"sources": sources,
|
|
583
|
+
"workdir": str(dest),
|
|
584
|
+
"timeout_s": _MZI_TIMEOUT_S,
|
|
585
|
+
"layout": {
|
|
586
|
+
"gds_file": str(staged_gds),
|
|
587
|
+
"cell": _MZI_CELL,
|
|
588
|
+
"tech": _MZI_TECH,
|
|
589
|
+
"rules": {
|
|
590
|
+
"layer": list(_MZI_RULES["layer"]),
|
|
591
|
+
"width_um": _MZI_RULES["width_um"],
|
|
592
|
+
"space_um": _MZI_RULES["space_um"],
|
|
593
|
+
},
|
|
594
|
+
"rules_ref": _MZI_RULES_REF,
|
|
595
|
+
},
|
|
596
|
+
}
|
|
597
|
+
if design == "bandgap":
|
|
598
|
+
sources = [str(dest / name) for name in _staged_names(design, dest)]
|
|
599
|
+
return {
|
|
600
|
+
"sources": sources,
|
|
601
|
+
"workdir": str(dest),
|
|
602
|
+
"timeout_s": 300,
|
|
603
|
+
"measurements": [
|
|
604
|
+
{
|
|
605
|
+
"name": "vref",
|
|
606
|
+
"expr": "v(vref)",
|
|
607
|
+
"unit": "V",
|
|
608
|
+
"min": _BANDGAP_VREF_MIN,
|
|
609
|
+
"max": _BANDGAP_VREF_MAX,
|
|
610
|
+
}
|
|
611
|
+
],
|
|
612
|
+
"analyses": ["op"],
|
|
613
|
+
"options": ["wnflag=1"],
|
|
614
|
+
"params": {"vsup": 3.3},
|
|
615
|
+
"corner": "tt",
|
|
616
|
+
"temp_c": 27,
|
|
617
|
+
}
|
|
618
|
+
if design == "sd_top":
|
|
619
|
+
sources = [str(dest / name) for name in _staged_names(design, dest)]
|
|
620
|
+
tb_dest = dest / _SDTOP_TB_NAME
|
|
621
|
+
tb_dest.write_text(_SDTOP_TB, encoding="utf-8")
|
|
622
|
+
sources.append(str(tb_dest))
|
|
623
|
+
# Model-bin clamp on the STAGED macro copy only (the vendored
|
|
624
|
+
# PEX is never touched): see _SDTOP_X99_OLD. Mutants rewrite
|
|
625
|
+
# X64, never X99, so the site must still occur exactly once.
|
|
626
|
+
pex_path = dest / _SDTOP_SNAPSHOT
|
|
627
|
+
pex_text = pex_path.read_text(encoding="utf-8")
|
|
628
|
+
if pex_text.count(_SDTOP_X99_OLD) != 1:
|
|
629
|
+
raise MutationError(
|
|
630
|
+
"sd_top staging: X99 clamp site drifted "
|
|
631
|
+
f"({_SDTOP_X99_OLD[:24]!r} occurs "
|
|
632
|
+
f"{pex_text.count(_SDTOP_X99_OLD)}x, want 1)."
|
|
633
|
+
)
|
|
634
|
+
pex_path.write_text(
|
|
635
|
+
pex_text.replace(_SDTOP_X99_OLD, _SDTOP_X99_NEW),
|
|
636
|
+
encoding="utf-8",
|
|
637
|
+
)
|
|
638
|
+
return {
|
|
639
|
+
"sources": sources,
|
|
640
|
+
"workdir": str(dest),
|
|
641
|
+
"timeout_s": 300,
|
|
642
|
+
"measurements": [
|
|
643
|
+
{
|
|
644
|
+
"name": "int_dc",
|
|
645
|
+
"expr": "mean(v(ua1))",
|
|
646
|
+
"unit": "V",
|
|
647
|
+
"min": _SDTOP_INT_MIN,
|
|
648
|
+
"max": _SDTOP_INT_MAX,
|
|
649
|
+
}
|
|
650
|
+
],
|
|
651
|
+
"analyses": list(_SDTOP_ANALYSES),
|
|
652
|
+
"options": list(_SDTOP_OPTIONS),
|
|
653
|
+
"params": {"vsup": 3.3},
|
|
654
|
+
"corner": "tt",
|
|
655
|
+
"temp_c": 27,
|
|
656
|
+
}
|
|
657
|
+
if design == "sdm_rx":
|
|
658
|
+
bench_src = root / _SDM_BENCH
|
|
659
|
+
if not bench_src.is_file():
|
|
660
|
+
raise FileNotFoundError(f"sdm_rx bench missing: {bench_src}")
|
|
661
|
+
bench_dest = dest / Path(_SDM_BENCH).name
|
|
662
|
+
shutil.copy(bench_src, bench_dest)
|
|
663
|
+
vector_src = root / _SDM_VECTOR
|
|
664
|
+
if not vector_src.is_file():
|
|
665
|
+
raise FileNotFoundError(f"sdm_rx PEX vector missing: {vector_src}")
|
|
666
|
+
lines = vector_src.read_text(encoding="utf-8").splitlines()
|
|
667
|
+
clean = [line.strip() for line in lines[1:] if line.strip() in ("0", "1")]
|
|
668
|
+
if len(clean) != 2048:
|
|
669
|
+
raise MutationError(
|
|
670
|
+
f"sdm_rx staging: PEX vector has {len(clean)} bits, want 2048."
|
|
671
|
+
)
|
|
672
|
+
(dest / _SDM_STAGED_VECTOR).write_text("\n".join(clean) + "\n", encoding="utf-8")
|
|
673
|
+
# iverilog-14 elaboration shim (behavior-preserving, no value
|
|
674
|
+
# change): the vendored sdm_rx.v declares `fast_strobe /
|
|
675
|
+
# prec_strobe` after their first use (line 172 vs 135), which
|
|
676
|
+
# the vendor's older iverilog accepted but oss-cad-suite
|
|
677
|
+
# iverilog 14.0 rejects ("declaration after use"). Move the
|
|
678
|
+
# declaration earlier in the STAGED copy only (vendored bytes
|
|
679
|
+
# stay pristine); mutants patch the same way after apply_operator.
|
|
680
|
+
dut_path = dest / "sdm_rx.v"
|
|
681
|
+
dut_text = dut_path.read_text(encoding="utf-8")
|
|
682
|
+
strobe_decl = " reg fast_strobe, prec_strobe;\n"
|
|
683
|
+
anchor = " reg [15:0] osr_fast, osr_prec; // active copies, load on clear\n"
|
|
684
|
+
if dut_text.count(strobe_decl) != 1 or dut_text.count(anchor) != 1:
|
|
685
|
+
raise MutationError(
|
|
686
|
+
"sdm_rx staging: strobe-decl shim site drifted "
|
|
687
|
+
f"({dut_text.count(strobe_decl)}x decl, {dut_text.count(anchor)}x anchor)."
|
|
688
|
+
)
|
|
689
|
+
dut_text = dut_text.replace(strobe_decl, "")
|
|
690
|
+
dut_text = dut_text.replace(anchor, anchor + strobe_decl)
|
|
691
|
+
dut_path.write_text(dut_text, encoding="utf-8")
|
|
692
|
+
sources = [str(dest / name) for name in _staged_names(design, dest)]
|
|
693
|
+
sources.append(str(bench_dest))
|
|
694
|
+
return {
|
|
695
|
+
"sources": sources,
|
|
696
|
+
"defines": [],
|
|
697
|
+
"timeout_s": _SDM_TIMEOUT_S,
|
|
698
|
+
"watchdog_units": None,
|
|
699
|
+
"workdir": str(dest),
|
|
700
|
+
}
|
|
701
|
+
if design == "serv":
|
|
702
|
+
harness_src = root / _HARNESS
|
|
703
|
+
if not harness_src.is_file():
|
|
704
|
+
raise FileNotFoundError(f"SERV harness missing: {harness_src}")
|
|
705
|
+
text = harness_src.read_text(encoding="utf-8")
|
|
706
|
+
if text.count(_WATCHDOG_DEFAULT) != 1:
|
|
707
|
+
raise MutationError(
|
|
708
|
+
f"serv staging: watchdog site occurs "
|
|
709
|
+
f"{text.count(_WATCHDOG_DEFAULT)}x, want 1."
|
|
710
|
+
)
|
|
711
|
+
text = text.replace(
|
|
712
|
+
_WATCHDOG_DEFAULT,
|
|
713
|
+
f"parameter watchdog_units = {SERV_WATCHDOG_UNITS}",
|
|
714
|
+
)
|
|
715
|
+
harness_dest = dest / Path(_HARNESS).name
|
|
716
|
+
harness_dest.write_text(text, encoding="utf-8")
|
|
717
|
+
hex_src = root / _FIRMWARE
|
|
718
|
+
if not hex_src.is_file():
|
|
719
|
+
raise FileNotFoundError(f"SERV firmware missing: {hex_src}")
|
|
720
|
+
shutil.copy(hex_src, dest / Path(_FIRMWARE).name)
|
|
721
|
+
sources = [str(dest / name) for name in _staged_names(design, dest)]
|
|
722
|
+
sources.append(str(harness_dest))
|
|
723
|
+
return {
|
|
724
|
+
"sources": sources,
|
|
725
|
+
"defines": [],
|
|
726
|
+
"timeout_s": 300,
|
|
727
|
+
"watchdog_units": SERV_WATCHDOG_UNITS,
|
|
728
|
+
"workdir": str(dest),
|
|
729
|
+
}
|
|
730
|
+
monitor_src = root / _MONITOR
|
|
731
|
+
if not monitor_src.is_file():
|
|
732
|
+
raise FileNotFoundError(f"picorv32 monitor missing: {monitor_src}")
|
|
733
|
+
monitor_dest = dest / Path(_MONITOR).name
|
|
734
|
+
shutil.copy(monitor_src, monitor_dest)
|
|
735
|
+
sources = [str(dest / name) for name in _staged_names(design, dest)]
|
|
736
|
+
sources.append(str(monitor_dest))
|
|
737
|
+
return {
|
|
738
|
+
"sources": sources,
|
|
739
|
+
"defines": ["COMPRESSED_ISA"],
|
|
740
|
+
"timeout_s": 120,
|
|
741
|
+
"watchdog_units": None,
|
|
742
|
+
"workdir": str(dest),
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
def _staged_names(design, dest):
|
|
747
|
+
entry = _design_entry(design)
|
|
748
|
+
names = []
|
|
749
|
+
for filename in entry["files"]:
|
|
750
|
+
name = filename
|
|
751
|
+
if not (Path(dest) / name).is_file():
|
|
752
|
+
raise FileNotFoundError(f"{design} staging: base file missing: {name}")
|
|
753
|
+
names.append(name)
|
|
754
|
+
return names
|
|
755
|
+
|
|
756
|
+
|
|
757
|
+
def stage_good_design(design, dest_dir, root):
|
|
758
|
+
"""Stage an unmutated design sim dir; return runnable job args.
|
|
759
|
+
|
|
760
|
+
Args:
|
|
761
|
+
design: Vendored design name to stage unmutated.
|
|
762
|
+
dest_dir: Staged sim dir receiving base files + extras.
|
|
763
|
+
root: Repo root the base files copy from.
|
|
764
|
+
|
|
765
|
+
Returns:
|
|
766
|
+
Runnable job args for the design's operation.
|
|
767
|
+
|
|
768
|
+
Raises:
|
|
769
|
+
KeyError: Unknown design.
|
|
770
|
+
FileNotFoundError: Missing base file or extra.
|
|
771
|
+
MutationError: Drifted probe or shim site.
|
|
772
|
+
"""
|
|
773
|
+
entry = _design_entry(design)
|
|
774
|
+
dest = Path(dest_dir)
|
|
775
|
+
copy_base_files(entry, Path(root) / entry["base"], dest)
|
|
776
|
+
return stage_design_extras(design, dest, root)
|