Repository navigation
t27o: emit the M1 cell constants from a SPICE deck -- rc, rlc, lad3 and lad5 bit-exact with linear.t27 (Closes #10766) - #10781
Merged
Conversation
…nd lad5 fold to linear.t27's pinned words, bit for bit (Closes #10766) M2b of the analog-emulation epic #10486. spice_convert.t27 reads a flat deck of R, C, L and one input source (a V source, or a B source that is a function of time alone) as the linear cell of specs/analog/linear.t27 and prints CELL_N, CELL_D and CELL_NV as t27: `tri t27o deck.cir --emit-cell`. The words come from the netlist alone; no per-circuit text. - One parser: the M2a front end is extended (a time-only B voltage is accepted as an input, ic= on C and L, .options method= maxord= trtol=), not copied. Decks the M2a reader accepted print the same inventory. - The fold: MNA stamps of the cards, linear.t27's eliminate and mn_of, and linear.t27's q_sm for the rounding, by `use`. The stamp is written again here (pair_add, src_add) because linear.t27's stamp hands a local array to a function that writes it and gen-rust lowers that to `&mut &(w)`; the tests hold the copy to the original. - States: free nodes in the order their names first appear in the R, C and L cards, then the inductors in card order (current times ZS = sqrt(L1/C1)); dt is the .tran tmax; the deck must say method=gear maxord=1 (backward Euler), else it is refused. - Refused with line and reason: a MOS or any other element letter, an X card, an I or E source, a B source that reads a node or is a current source, a second or floating input, m=, ic other than 0, C or L on the input node, a gnd node, more than 5 states, no .tran with four numbers, a matrix with no solution. - 39 tests, 0 vacuous: the four decks equal RC/RLC/LAD3/LAD5 _D and _NV word for word; one resistor changed gives other words; reordered cards give the permuted words; 12 mutants of the converter are each killed by a test. - Hand Rust in cli/tri: +6 -4 in main.rs (the flag and the dispatch), -26 in fpga.rs (the unreferenced #[cfg(test)] fn normalize_fixture_paths): net -24. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This was referenced Oct 19, 2026
Merged
gHashTag
enabled auto-merge (squash)
October 19, 2026 02:28
3 tasks
Contributor
16 of 21 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #10766
M2b of #10486 (M2a was #10509).
specs/tools/t27o/spice_convert.t27now reads a flat deck of R, C, L and one input source as the linear cell ofspecs/analog/linear.t27and prints its constants as t27:tri t27o deck.cir --emit-cellwritesCELL_N,CELL_DandCELL_NV, with no per-circuit text.linear.t27is not changed.What the converter does
python3 -I tools/dupe_scan.py: ok, no new duplicate body). It now also accepts aBvoltage source whose expression is a function of time alone (numbers,time,u u2 uramp abs sgn sin cos exp sqrt,+ - * / ^),ic=on C and L, and.options method= maxord= trtol=. Every deck the M2a reader accepted prints the same inventory as before (checked on the 17 decks ofspecs/analog/decksagainst the master build: the 4 SAR comparator decks are byte-identical; the 13 that differ were all refused before and are now read, or refused later for their own reason).Vsource, or a time-onlyBsource, from a node to ground0: its plus node is the cell's input node and the source is the column of B (its waveform does not matter, the run suppliesu). ABthat reads a node (v(,i(, a node name,@, a comparison) or is a current source is refused.[A | C/dt | B],eliminateandmn_ofoflinear.t27, andq_smoflinear.t27for the rounding, all byuse(explicit item imports;t27c test-reportcompiles), so a word cannot differ from the cell's by a rounding rule. Values are read as the f64 nearest to the decimal text (dec_f64: one multiplication or division of exact operands, a test shows it equals the literals1.0e-9,5.0e-9,1.0e-5,2.2e-6, ...).linear.t27'sstamphands a local array to a function that writes it (stamp_pair(&w, ...));t27c gen-rustlowers that to&mut &(w), which rustc refuses, and the Rust of this spec is whattriruns.pair_addandsrc_addtake and return the matrix instead. The tests hold the copy to the original: the four pinned circuits below fail if the stamp rule drifts (12 mutants of the converter, e.g. C stamped as C*dt, the b-node sign of the inductor row, ZS fixed at 1, dt from tstep, are each killed by a test).The four circuits, bit for bit
CELL_D/CELL_NVof each deck equallinear.t27's pinned constants word for word. Checked three ways: the spec tests (embedded text of the decks without their*lines), the Rust thattriruns on the real files, and the realtri t27o <deck> --emit-cellbinary (debug build, own target dir).rc_fixed.cirNEG | 798915)798915)RC_D,RC_NV: identicalrlc_fixed.cirRLC_D,RLC_NV: identicallad3_fixed.cirLAD3_D,LAD3_NV: identicallad5_fixed.cirLAD5_D,LAD5_NV: identicalRefusal and negative control
line 4: M element not supportedplus the card; a PDK device (XM1 ... sg13_lv_nmos) isnot in the M1 cellwith its line. Also refused, each with its line and a test: an I or E source, a second or floating or upside-down input, no input,m=,icother than 0 (card or.ic), a C or L on the input node, a node calledgnd, a value that is zero, negative or not exact in f64, no states or more thanNMAX= 5, no.tranwith all four numbers, two analyses, an integration that is notmethod=gear maxord=1, and a matrix with no solution (a floating pair). Real decks:lad10_fixed.ciris refused at its line 18, the sixth node (the M1 cell has 1 to 5 states),rc_adaptive.ciris refused for its.tran.NEG | 729444/729444(1/23) instead of 798915 (1/21); the ladder with R2 doubled changes the words;.tranwith tmax = 100n givesNEG | 1525201(1/11), so dt really is the fourth number.The ordering rule
The unknowns are the free nodes numbered 1, 2, ... in the order their names first appear in the R, C and L cards (names compared without case;
0is ground, the input node is NODE_IN,gndis refused rather than guessed), then one per inductor in card order, its current stored times ZS. ZS = sqrt(L1 / C1) with L1 the first inductor and C1 the first capacitor of the deck, 1 when either is missing (100 Ohm for the RLC, as pinned). dt is the.trantmax. The four decks name their nodes 1, 2, ... in that order, so the rule reproduces linear.t27's order without a per-circuit case; a deck that lists the far end of the ladder first gets the permuted words (tested against the permuted pinned arrays), and the emitted block lists which node or inductor each state is.Own-language line counts
Hand-written Rust:
cli/tri/src/main.rs+6 -4 (the--emit-cellflag and the dispatch,emit_cellist27c gen-rustoutput),cli/tri/src/fpga.rs-26 (normalize_fixture_paths, an unreferenced#[cfg(test)]fn:git grep -wfinds only its definition and a prose line in a report, andcargo check --tests -p triwarned it was never used). Net -24; 6 added, 30 deleted. No other hand-written code.gen/rust/tools/t27o/spice_convert.rsist27c gen-rustoutput (byte-identical on a second run).Gates
t27c test-report specs/tools/t27o/spice_convert.t27: 39 tests, 39 pass, FAIL 0, vacuous passes 0 of 39 (22 M2a tests unchanged except the B-source reason text, 17 new).t27b test: 39/39.t27c seal ... --savethen--verify: all five hashes MATCH;.trinity/seals/t27o_T27oSpice.jsoncommitted (closure:linear.t27,rust_convert.t27; no home path, not blocked).cargo check -p triandcargo check --tests -p tripass;docs/reports/t27b_expectations.jsonuntouched (spice_convert stayspass).Not done yet
Xcard (subcircuit or PDK device) is refused as outside the cell; wiring nodes through port maps is M4d (analog M4d: the SAR ADC logic and asynchronous clock -- gate level from the netlist, against ngspice LEVEL=1 edges #10754). No MOS or any nonlinear device (M3). No current source; one input only.m=on R, C, L is refused rather than applied. dt is the tmax of a four-number.tran.linear.t27could drop the duplicated stamp once gen-rust lends a local array to a writing function (a compiler defect to file on epic: self-host t27c -- rewrite the compiler from Rust into t27 #5980 with a minimal repro); the copy is then deleted..claude/skills/analog-emulation/SKILL.mdstill says "Rust only today"); the agent sandbox cannot write under.claude/.🤖 Generated with Claude Code