Skip to content

epic: t27 analog emulation v0.1 -- SPICE netlist + IHP SG13G2 models to a t27 spec, on the FPGA per corner #10486

Open

Description

@gHashTag

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)^-1 is 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 smaller dt, 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 .t27 spec (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 under specs/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.

Status dashboard and progress reports: the skill analog-emulation (.claude/skills/analog-emulation/SKILL.md).

Success Criteria

  • SC-001: specs/analog/linear.t27 reproduces the 200 samples of specs/fpga/rc_filter_ax7203.t27 bit for bit (M1).
  • SC-002: a SPICE deck in the supported subset produces a spec whose tests pass with 0 vacuous, and t27c seal refuses 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

  1. added
    shape-refusedClosed by the issue-shape gate (specs/policy/issue_shape.t27); a passing edit reopens it
    on Oct 18, 2026
  2. github-actions commented on Oct 18, 2026

    @github-actions
    Contributor

    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.

    • missing: ## Success Criteria -- an outcome a machine can settle: a number with a unit, a backticked file, exit 0, or a backticked command
  3. removed
    shape-refusedClosed by the issue-shape gate (specs/policy/issue_shape.t27); a passing edit reopens it
    on Oct 18, 2026
  4. gHashTag commented on Oct 18, 2026

    @gHashTag
    OwnerAuthor

    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.

    Tick Time (UTC) Did Running / waiting on Next
    1 2026-10-18 15:25 #10493 merged (model routing law). Competitor + weakness research started (Sonnet). Toolchain survey (tri, tri-mcp, TRI CLAW, t27b, t27t, t27o) running (Sonnet). tri built. M1 split: spec/tests/seal stay in #10487, board receipts moved to #10496. M1 implementation started (Sonnet, own worktree, branch claude/analog-m1-linear-10487). research, survey, M1 lane when M1 PR is up: review-final on Opus; then M1b board tops
    1b 2026-10-18 15:27 Toolchain survey done: t27t does not exist in the repo; t27b verilog refuses 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. competitor research, M1 lane review M1 PR; lanes queued: #10497 (tri test vacuity), tri status command for the epic from a .t27 plan, #10496 board tops
    2 2026-10-18 15:45 Competitor research done -> docs/analog/competitors.md PR #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). M1 lane, M2a lane review M1 PR; M3 lab env from the Dockerfile recipe; M1b board tops
    3 2026-10-18 15:55 M1 done as PR #10511: 14/14 tests, 0 vacuous; M0 A/B/S bit-exact; max error RC 2.65, RLC 8.44, ladder3 9.45, ladder5 40.03 LSB; M_q^256
    4 2026-10-18 15:50 Session restarted (cron survived; M2a lane had only a probe file, resumed with its context). Anomaly found and self-repaired: #10500 (mine) removed two dead tri mentions without lowering the equality ratchet, so "Documented t27c subcommands exist" went red on master and every later PR -> #10513 / PR #10514 (MAX_DEAD_TRI 140 -> 138, check prints ok locally; auto-merge + auto-fix). #10507 merged (tri test fails on vacuous). Railway MCP added to Claude Code (owner request; 68 tools via the proxy), but sandboxed Bash still cannot ssh the lab. M2a lane #10511 merge, then M1c + M1b sim half
    5 2026-10-18 16:15 M1 merged (#10511). Owner installed ngspice-47. Found the full openXC7 flow + fbg484 chipdb already on the Mac (correction: the lab is not needed for board runs). Lanes: M1b (board, local), M1c (exact ZOH), M2a (SPICE front end), M3a, bench. Bench PR #10517: ngspice reproduces fixed-step backward Euler on our grid to 1e-15 V (gear maxord=1, trtol=1e7, a B source instead of PWL); ngspice .tran ~1 ms, wall ~14 ms = process start-up. Review on Opus tightened the claim rule (no speedup claim without a measured build time; M0 not claimable) and pushed it to the PR. M3a PR #10518: 13/13, K=3 Newton, Y(4 us) = 0 V (cpphdl: <= 1 mV), errors arithmetic 29 nV / table 0.43 mV / discretization 27.2 mV; reviewed, notes carried to M3b #10516.
    6 2026-10-18 16:45 The partner answered: the ADC is the priority, not the ring oscillator -> M4 re-targeted to the SAR ADC of the golden deck (#10524). Their verification report (shared privately) defines per-block checks for the 13 SAR designs; publication of its limits asked. Self-repair: #10518 and #10520 merged with a /Users home path (a seal written without the zig cache recorded a false blocked verdict) -> #10521 / PR #10523, scan green on the PR. Bench PR #10517 claim rule tightened on review. Speed: seal-keyed reuse (t27c frontier --only: 3/3 REUSE in 1.8 s), t27b test inner loop, tri hot bitstream cache; skills in #10520. M3b environment facts added (PDK 21133f21, psp103 + cap_cmom osdi, openvaf-r). M1b, M1c, M2a M4 sub-issues when M2a and M3b land
    7 2026-10-18 16:55 M2a done as PR #10530 (reviewed: frontier REUSE, seal MATCH, gen-rust regenerated byte-identical, 9 lines of hand Rust, dupes ok; auto-merge + auto-fix): tri t27o reads the whole golden SAR deck, 16 subckt (my earlier "20" corrected everywhere), 1265 MOS / 128 cap_cmim flattened. Splice-by-name evidence added to #9881. The DAC is a split array with a 1-unit bridge (ideal 32/31): M4a filed #10540 and started. Answered the peer merge session with my PR list. M1b, M1c, M4a M2b after #10530 merges; M3b when OpenVAF + IHP PDK are installed
    8 2026-10-19 01:05 Owner connected the board: openFPGALoader sees the AX7203 from the terminal (HS2 000:004, idcode 0x3636093); sandboxed Bash cannot reach USB, so the orchestrator flashes. OpenVAF-Reloaded installed and IHP PDK pinned at 21133f21 in the home dir, but its bundled dylibs have invalid signatures (Killed: 9): re-signing is the owner's call. M1c merged (#10528) and its Ring type clash fixed (#10539). #10530 own-language fixed by deleting dead nownote.rs functions (+9/-38), coordinated with the t27o peer. M4a done as PR #10575 (reviewed in a temp worktree; my bridge premise was wrong and is corrected on #10524). trinity-fpga studied: flash recipe, receipt framing, 1144744-baud UART, the fasm2frames trap. M4b filed #10583 and started. Local t27c is older than master (frontier says toolchain). M1b, M4b rebuild t27c; flash M1b bitstreams; M4c/M4d when disk allows

    Rules for every tick: check git ls-remote and open PRs for analog before 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.

  5. gHashTag commented on Oct 18, 2026

    @gHashTag
    OwnerAuthor

    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 that spice_convert.t27 (#10509) sits beside faster and better measured. It does not touch #10509's files or specs/analog/; its ledger is a comment on #10522, separate from this epic's ledger.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions