Repository navigation
epic: t27 analog emulation v0.1 -- SPICE netlist + IHP SG13G2 models to a t27 spec, on the FPGA per corner #10486
Description
Goal
Release t27 analog emulation v0.1: an analog circuit, given as a SPICE netlist with IHP SG13G2 device models, becomes one .t27 spec that is at once the software reference and the FPGA design, runs on the board per process corner, and is checked against ngspice and against Symbiotic EDA's self-checking analog evaluator, with its waveforms readable in uberWAVE.
This is the "analog chip circuit emulation" problem Symbiotic EDA named as unsolved: port an analog circuit (netlist + Verilog-A device models from the PDK) to a t27 spec, deploy it as Verilog on an FPGA, and eventually emulate a full mixed-signal chip (reference design: ckdur/asicone_sg13g2). Their constraint, which shapes the whole plan: chip designers will not learn t27, so the entry point is the netlist they already have, not hand-written t27.
Target: v0.1 in hand by mid-November 2026, so it can be cited as measured, reproducible work before the end of the month.
Where we stand (2026-10-18)
M0 is done: cpphdl's rc_filter as specs/fpga/rc_filter_ax7203.t27 (#10276, PR #10278, follow-ups #10294 #10296 #10300 #10313). One spec, 200 backward-Euler steps in Q8.24, at most 2.65 LSB from float64, 0.992396 V at 5 us (same as cpphdl), 520 LUT / 601 FF / 0 DSP / 0 BRAM, Fmax 120.7 MHz, 10 us of circuit time in 12 us on the AX7203, more than 1,300 UART receipts bit-exact, truncation mutant refused. The circuit was hand-written and its coefficient is compiled in: no netlist input, no nonlinear device, no corner.
The plan
Each milestone ends in a measurement, a negative control and a receipt, the way M0 did. A milestone's status is earned (spec merged, tests green on the lab, board receipt, oracle comparison), never declared.
| # | Milestone | Acceptance (what must be measured) | Target |
|---|---|---|---|
| M0 | RC low-pass, hand-written, AX7203 | done, see above | 2026-10-18 |
| M1 | Linear state-space cell. Any linear R/C/L/V/I circuit of up to N nodes with a fixed step: MNA (G + C/dt) x' = (C/dt) x + B u folded at compile time to x' = M x + N u in fixed point. Spec module specs/analog/linear.t27. Circuits: RC (must reproduce M0 bit for bit), series RLC, 3- and 5-node RC ladder |
tests: error vs float64 bounded per circuit; an invariant that the quantized M stays stable (spectral radius < 1); M0's samples reproduced exactly; board receipts for RLC and the 5-node ladder; negative control: a mis-stamped element fails the tests and the seal |
2026-10-23 |
| M2 | Netlist in, spec out. A SPICE subset (R, C, L, V, I, PWL/PULSE sources, .tran, then .subckt, instance parameters and .lib corners) read by a new t27o front end, specs/tools/t27o/spice_convert.t27 beside rust_convert.t27, run as tri t27o deck.cir, and turned into the M1 spec, with no hand-written t27 per circuit |
cpphdl rc_filter and the M1 circuits imported from their decks give the same samples as M1; a netlist outside the subset is refused with the line and the reason, never approximated silently |
2026-10-27 |
| M3 | First IHP device: CMOS inverter, per corner. MOS currents from the IHP SG13G2 PSP103 models (ngspice + OpenVAF/OSDI on the Railway lab), tabulated per corner (tt, ff, ss, fs, sf) and evaluated on the FPGA by table interpolation; node charge from tabulated or constant capacitance, labelled as such | DC transfer and a transient within stated tolerance of ngspice for each of the 5 corners; one bitstream per corner; negative control: the tt table in the ss bitstream is caught by the receipt | 2026-11-03 |
| M4 | The SAR ADC of the golden deck (re-targeted 2026-10-18 by Symbiotic EDA: the ring oscillator is digital and not relevant; the ADC is). Capacitive DAC, dynamic comparator, sampling switch, SAR logic, then the whole converter (#10524) | every conversion code of the golden 16 us run equals ngspice's; each block checked against ngspice with the same IHP models first | 2026-11-09 |
| M5 | Waveforms and the oracle. Board samples streamed to the host and written as files uberWAVE opens (VCD real or the format uberWAVE reads); the same traces fed to Symbiotic EDA's self-checking analog evaluator | the evaluator passes M3 and M4 traces and fails a deliberately broken one; uberWAVE screenshot in the receipt | 2026-11-12 |
| M6 | Release v0.1. Tag, release notes with every number and what it does not claim, a course lesson and a blog post with a widget, a one-page technical summary for partners | everything above reproducible from the tag on the lab; the summary uses only measured numbers | 2026-11-16 |
| M7 | After v0.1: the YPCB Kintex-7 480T + RPi5 board over PCIe (regymm/pcie_7x, their DMA) instead of UART; the SAR ADC comparator path; Verilog-A to t27 for compact models | separate issues, opened when M6 lands | - |
Design choices, and why
- Fixed step, compile-time matrices. For a linear circuit with a fixed
dt,(G + C/dt)^-1is a constant, so a step is a matrix-vector product with constants: no division and no solve on the FPGA. M0 is the 1x1 case (g = 1/21). Stiff circuits pay in a smallerdt, not in hardware. - Tables first for nonlinear devices, compact models later. PSP103 is far too large to compile into fabric in one step. A per-corner
Id(Vgs, Vds)table generated from the PDK's own model in ngspice keeps the PDK as the authority and makes "one bitstream per corner" literal. Direct Verilog-A ingest is M7 research, not a v0.1 promise. - ngspice is the reference, the evaluator is the judge. ngspice with the IHP models is the per-corner reference; Symbiotic EDA's self-checking evaluator decides pass/fail, so the claim is checked by their tool, not ours.
- Only t27. Every new piece of logic is a
.t27spec (the netlist reader, the table converter, the cell, the report). ngspice, OpenVAF, yosys and nextpnr are external tools, invoked like the existing flow.
Progress
| Date | What | Where |
|---|---|---|
| 2026-10-18 | Plan published; M1 opened | #10486, #10487 |
| 2026-10-18 | Skill analog-emulation merged: milestone loop, claim guard, report template |
#10490 |
| 2026-10-18 | Cost rule for the work: Opus 5.5 plans and reviews, Sonnet 5.5 runs sub-tasks (specs/claw/model_route.t27, 6/6 tests, mutant caught) |
#10492, PR #10493 |
| 2026-10-18 | t27c 0.5.2 built on the bench Mac: specs are tested and sealed locally before the lab | - |
| 2026-10-18 | Competitors and ten weaknesses mapped; plan adjusted (exact discretization #10503, ngspice wall-time bench #10505, run-time BRAM and charge tables for M3) | PR #10506 |
| 2026-10-18 | uberWAVE reads ngspice RAW files, so M5 writes RAW; a real SAR ADC netlist (xschem, IHP SG13G2, 16 subckt, 57 MOS lines, 1265 MOS after flattening) becomes the M2 acceptance deck (corrected: 16, not 20) | #10509 |
| 2026-10-18 | tri test now fails on vacuous passes |
PR #10507 (#10497) |
| 2026-10-18 | M1 merged: one linear cell for R/C/L circuits, M0 bit-exact, four circuits within bounds, stability proved; t27b passes it natively | PR #10511 |
| 2026-10-18 | M4 re-targeted to the SAR ADC at the partner's request; the golden deck and its ngspice RAW are the reference | #10524 |
| 2026-10-18 | M2a built: tri t27o reads the whole golden SAR deck -- 16 subckt, 57 MOS lines, 1265 MOS and 128 cap_cmim after flattening, tran 0.1n 16u, corners mos_tt / cap_typ; 22/22 tests |
PR #10530 |
| 2026-10-18 | M1c merged: exact zero-order-hold constants for the same hardware. LC tank Q = 200 after 100 periods: exact scheme amplitude ratio 1.0003 (Q.24), backward Euler 1.78e-7. A type-name collision it caused on master (Ring) was fixed by #10539 | PR #10528, #10539 |
| 2026-10-19 | M4a built: the SAR ADC split DAC by charge redistribution on the M1 cell, all 1024 codes of a half vs the closed form and ngspice (1.74 units of 2^-24 V at most). Correction of my premise: the 1-unit bridge is the ideal one for a 31-unit LSB array, so INL is 0 and only a gain error of at most 0.5 LSB remains | PR #10575 |
Status dashboard (private artifact, shared by the owner): the skill analog-emulation names it.
Boundary
- New specs under
specs/analog/(cell, netlist reader, device tables, report), board tops underspecs/fpga/, seals and ledger rows as usual. - No hand-written Verilog, XDC or scripts. Generated files are never hand-edited (L2).
- Runs that need ngspice + IHP PDK run on the Railway lab, not on the Mac. Board runs on the AX7203 bench.
- Not claimed in v0.1: power, accuracy beyond the measured circuits, the full SAR ADC, Verilog-A input, PCIe speed.
Scenarios
- Given a linear netlist in the supported subset, When it is imported and its spec tested on the lab, Then the tests pass with 0 vacuous and the board receipt matches the spec bit for bit.
- Given the inverter spec built for corner ss, When it runs on the board, Then its transfer curve is within the stated tolerance of ngspice ss and outside it for ff.
- Given the ring oscillator traces, When they are fed to the self-checking evaluator, Then it passes, and a trace with one stage removed fails.
Requirements
- FR-001: Every milestone MUST have a negative control that fails.
- FR-002: Every number quoted outside this repository MUST come from a receipt or a test in this repository.
- FR-003: The netlist reader MUST refuse what it does not support, with the line and the reason.
- FR-004: Per-corner results MUST name the corner and the PDK revision they came from.
Needs from Symbiotic EDA
- Access to the self-checking analog evaluator (or its input format) - for M5
- The uberWAVE input format - ngspice RAW (binary or ASCII), per its README and WP2 parser
- Priority block - the ADC (answered 2026-10-18); the ring-oscillator netlist is no longer needed
- The YPCB Kintex-7 480T + RPi5 board, when it is up - for M7
Sub-issues
Opened one at a time as each milestone starts.
- M1 analog M1: linear state-space cell -- any linear R/C/L circuit, fixed step, folded to x' = Mx + Nu #10487 linear state-space cell (spec, tests, seal) -- PR analog: linear.t27 -- linear state-space cell, MNA folded to x' = x + rnd(Dx + Nu), reproduces M0 bit for bit (Closes #10487) #10511 merged
- M1b analog M1b: board receipts for the linear cell -- series RLC and 5-node RC ladder on the AX7203 #10496 board receipts for the RLC and the 5-node ladder (local openXC7 flow found: build/fpga/openxc7, fbg484 chipdb; no lab needed)
- M1c analog M1c: exact zero-order-hold discretization for the linear cell, and the h / h/2 convergence check #10503 exact zero-order-hold discretization and the h / h/2 check -- PR analog: linear_zoh.t27 -- exact zero-order-hold constants for the linear cell, and the h/2 convergence check (Closes #10503) #10528 + analog: linear_zoh.t27 -- rename struct Ring to RingPeak, it collided with another type named Ring and moved the types ratchet 107 -> 108 (Closes #10503) #10539 merged
- M2a analog M2a: SPICE front end for t27o -- parse, flatten and inventory an ngspice netlist, or refuse with the line #10509 SPICE front end for t27o (parse, flatten, inventory, refuse)
- Bench analog bench: wall time of ngspice against the board for the same circuits -- no speed claim without it #10505 ngspice wall time against the board
- M3b analog M3b: IHP SG13G2 PSP103 tables per corner from ngspice, plugged into the M3a solver -- inverter against ngspice #10516 IHP SG13G2 PSP103 tables per corner from ngspice
- M4 analog M4: the SAR ADC of the golden deck -- capacitive DAC, dynamic comparator, sampling switch, SAR logic, then the whole converter against ngspice #10524 the SAR ADC: DAC, comparator, sampling switch, SAR logic, whole converter
- M4a analog M4a: the SAR ADC capacitive DAC -- split array with a 1-unit bridge capacitor, charge redistribution against ngspice #10540 split capacitive DAC with its 1-unit bridge, against ngspice -- PR analog: sar_cdac.t27 -- the SAR ADC split capacitive DAC with its 1-unit bridge, charge redistribution against ngspice (Closes #10540) #10575
- M4b analog M4b: the SAR ADC dynamic comparator -- multi-node Newton on the M3a solver, square-law first, against ngspice LEVEL=1 #10583 dynamic comparator: multi-node Newton, square law vs ngspice LEVEL=1, then PSP103 tables
- M3a analog M3a: nonlinear table-device cell -- CMOS inverter with a tabulated square-law MOS, backward Euler and a fixed Newton count, against cpphdl #10515 nonlinear table-device cell: CMOS inverter, tabulated square-law MOS, backward Euler + fixed Newton, against cpphdl
Status dashboard and progress reports: the skill analog-emulation (.claude/skills/analog-emulation/SKILL.md).
Success Criteria
- SC-001:
specs/analog/linear.t27reproduces the 200 samples ofspecs/fpga/rc_filter_ax7203.t27bit for bit (M1). - SC-002: a SPICE deck in the supported subset produces a spec whose tests pass with 0 vacuous, and
t27c sealrefuses each milestone's negative control (exit code != 0). - SC-003: for each of 5 IHP SG13G2 corners, the inverter's board receipt reads PASS and its error against ngspice is within the bound its spec states (M3).
- SC-004: the 13-stage ring oscillator's frequency on the board is within 5 % of ngspice for each corner (M4).
- SC-005: the v0.1 tag exists and its release notes quote only numbers that appear in a test or receipt in this repository (M6).
Activity
github-actions commentedon Oct 18, 2026
Closed by the issue-shape gate (specs/policy/issue_shape.t27, #7498): an issue must have the template's sections. Edit the body; an edit that passes reopens it.
exit 0, or a backticked commandskill: analog-emulation -- milestone loop, claim guard and progress r…
skill: analog-emulation -- milestone loop, claim guard and progress r…
gHashTag commentedon Oct 18, 2026
Loop ledger (15 min ticks, started 2026-10-18 ~22:20 local)
This comment is the loop's state. Every tick reads it first, edits it last, and never starts work that a row below says is already running.
tribuilt. M1 split: spec/tests/seal stay in #10487, board receipts moved to #10496. M1 implementation started (Sonnet, own worktree, branchclaude/analog-m1-linear-10487).t27tdoes not exist in the repo;t27b verilogrefuses signed types (told the M1 lane: sign-magnitude); t27o is Rust-only, so the SPICE reader becomes a t27o front end (epic M2 updated). Filed #10497 (tri test ignores vacuous), #10498 (no ax7203 in fpga-build/flash), #10499 (skills). Skills PR #10500 open, auto-merge + auto-fix on.tristatus command for the epic from a .t27 plan, #10496 board topsdocs/analog/competitors.mdPR #10506 (auto-merge, auto-fix); plan changes filed: #10503 M1c exact ZOH + h/h2 check (W1, W10), #10505 ngspice wall-time bench (W7); M3 moves to run-time BRAM tables + charge tables (W3, W4). uberWAVE reads ngspice RAW (binary/ASCII): M5 writes RAW. Found the SAR ADC golden netlist (uberWAVE wp2-parser/golden/top.spice, GPL-2.0, not vendored) and its ngspice-46 + OpenVAF + IHP Dockerfile. M2a filed #10509 and started (Sonnet lane). #10497 done as PR #10507 (gen file regenerated and compared byte for byte on review; auto-merge, auto-fix). #10501 filed (claw-sarif token order).Rules for every tick: check
git ls-remoteand open PRs foranalogbefore starting a lane; at most 3 subagents; merge only when the required checks are green; an inherited red is inherited only if it is a subset of master's (claw-sarif is the known App-permission red); nothing private from the partner conversation goes here.docs(analog): competitors, prior art and ten weaknesses of the analog…
analog: linear.t27 -- linear state-space cell, MNA folded to x' = x +…
analog: mos_table.t27 -- CMOS inverter with a tabulated square-law MO…
gHashTag commentedon Oct 18, 2026
t27o loop linked here: #10522 tracks t27o's own weaknesses (dogfood on the roadmap repos, t27b-fast
--check, refusal classes, competitors). It feeds M2 by making the converter thatspice_convert.t27(#10509) sits beside faster and better measured. It does not touch #10509's files orspecs/analog/; its ledger is a comment on #10522, separate from this epic's ledger.analog: linear_zoh.t27 -- exact zero-order-hold constants for the lin…