Skip to content

analog: mos_psp103.t27 -- IHP SG13G2 PSP103 tables for five corners from ngspice, run by M3a's solver, inverter against ngspice (Closes #10516) - #10778

Merged
gHashTag merged 1 commit into
masterfrom
claude/analog-m3b-psp103-10516
Oct 19, 2026
Merged

gHashTag merged 1 commit into
masterfrom
claude/analog-m3b-psp103-10516

Conversation

@gHashTag

Copy link
Copy Markdown
Owner

What

M3b of #10486. The IHP SG13G2 sg13_lv_nmos / sg13_lv_pmos PSP103 current tables, one pair per corner (tt ff ss fs sf), made by ngspice-47 and run by M3a's solver (specs/analog/mos_table.t27) in place of the square law, and the CMOS inverter checked against ngspice with the same model. Closes #10516.

Three specs and nine decks:

  • specs/analog/mos_psp103_data.t27 -- the numbers only (6250 table words, 245 inverter DC points, 4752 held-out currents, 802 waveform samples) with order-sensitive pins, as M3a pins its run. 4 tests.
  • specs/analog/mos_psp103.t27 -- the held-out statistics, the DC bisection, the delay crossings, the tt check and its negative controls. 11 tests. Nothing is copied from M3a; its reader, Newton step and run are used.
  • specs/analog/mos_table.t27 -- one change: the solver takes the NMOS table tn and the PMOS table tp as two arguments (g_resid, newton_iter, inv_step, board_step, run_fix, newton_iter_f, run_tabf). Every M3a test passes the same table twice (the call sites changed, nothing else): the pinned run (EXP_S) and all 13 old tests give what they gave, and one new test checks the mirror with two different tables. sar_comparator.t27 is untouched (it uses none of those names); its seal is renewed because the closure hash of mos_table.t27 moved (the built_by field shows the compiler build I used).
  • specs/analog/decks/psp103_tab_{tt,ff,ss,fs,sf}.cir, psp103_inv_{be,fine}.cir, psp103_inv_{be,fine}_500f.cir -- plain netlists with a .control block that prints the numbers.

The tables

model IHP-Open-PDK commit 21133f219b1a6da10d803e345761e77415ceff40, cornerMOSlv.lib (PSP 103.6 rev 200310), psp103.va compiled by OpenVAF-Reloaded v24.0.2mob; ngspice-47
corners mos_tt, mos_ff, mos_ss, mos_fs, mos_sf, 27 C (TNOM 27 C)
devices sg13_lv_nmos W 1.0 um, sg13_lv_pmos W 3.0 um, L 0.45 um, ng 1, m 1 (the inverter of the uberWAVE golden SAR deck; its text is not copied)
grid Id(Vgs, Vds), 25 x 25 nodes, 24 cells of 62.5 mV over 0 .. 1.5 V: M3a's reader as it is (24 cells of 2^20 units, a unit is 2^-24 V)
entry Id * dt/C in units, dt/C = 200 V/A, so a unit is 0.298 nA; the largest, tt NMOS at 1.5 V / 1.5 V, is 1349912 (402.3 uA)
solver options reltol 1e-6, vntol 1e-9, abstol 1e-14 (ngspice's defaults leave the nested sweeps up to 0.1 % off)
paths none in any deck: ngspice reads IHP_PDK and IHP_OSDI from the environment

gm and gds come from the same nodes as the value (FR-002): across every one of the 576 cells of each of the ten tables the interpolant moves by gm_cell / gds_cell to within 2 units (5760 cell checks). Every table is nondecreasing along both axes, zero at Vds = 0 (the gate current that leaves through the drain, at most 2 units, is held at 0 by the deck), has an off current of at most 10 units, and the corners are in the foundry's order (fs: fast NMOS, slow PMOS; trip points fs < ff < tt < ss < sf).

Interpolation error against ngspice (a test, both sides)

Held-out points are never nodes: tt has the 576 cell midpoints (where a chord is worst) and 1000 points of the R2 sequence per device; the other corners the first 200 R2 points.

tt NMOS PMOS
absolute 6.51e-7 A (0.16 % of 402 uA) 4.39e-7 A (0.15 % of 301 uA)
relative, Id >= 100 uA 0.56 % 0.41 %
relative, Id >= 10 uA 4.3 % 3.2 %
relative, Id >= 1 uA 21 % 17 %
relative, floor 1e-9 A (the issue's measure) 0.55 .. 0.62 0.64 .. 0.73

ff ss fs sf: absolute at most 5.7e-7 A (NMOS) and 4.4e-7 A (PMOS), relative for Id >= 100 uA at most 0.38 % and 0.26 %.

The proposal of #10516 (1 %, floor 1e-9 A) is not met, and cannot be by a chord over a 62.5 mV cell. In weak inversion Id grows by a factor of about 6 per cell, where the chord at the midpoint is 43 % off, and below a few nA the rounding to 0.298 nA is a tenth of the current. 1 % holds where Id >= 100 uA. The bounds in the test are the measured ones. A finer grid or a log-domain read is in #10777.

The inverter against ngspice

DC transfer, 49 points (Vin = k * 31.25 mV), tables against ngspice, every corner:

| | worst |dVout| | trip point (0.75 V crossing) shift |
|---|---|---|
| tt | 5.48 mV (bound 5.51) | 11 uV (bound 12.5) |
| ff / ss / fs / sf | 6.3 / 4.2 / 6.6 / 4.0 mV | 71 / 48 / 255 / 196 uV (bound 266) |

Transient, tt, 400 steps: gate at Vdd and the output at rest, gate to 0 V at step 0, back to Vdd at step 200; C = 10 pF, dt = 2 ns (dt/C = 200 V/A). The fixed-point model is M3a's run_fix with K = 3 Newton iterations; its last residual is at most 1 unit at every step (bound 2).

THE THREE ERRORS, kept apart:

error what it compares waveform delay tpLH / tpHL
arithmetic fixed point vs the f64 run of the same iteration 4.78 units (0.28 uV) none (< 1e-5 step)
table + model f64 model vs ngspice backward Euler, same grid (bound 21500 units, 0.18 %) 1.28 mV (0.085 % of Vdd) 0.142 % / 0.172 % (37 ps / 34 ps) shorter
discretization ngspice backward Euler at 2 ns vs ngspice converged (<= 20 ps steps) 14.4 mV 0.51 % / 0.66 % longer

All three together, the model against ngspice's converged run: tpLH 26.04 ns vs 25.94 ns (0.37 %), tpHL 19.63 ns vs 19.53 ns (0.51 %); the model's error and the scheme's partly cancel.

Most of the "table + model" row is not the table. The same 400 steps (dimensionless) against the same circuit at 500 fF / 100 ps: the model is 3.09 % / 3.63 % faster than ngspice backward Euler. The gap grows 21.8 and 21.1 times for a load 20 times smaller, i.e. it scales with 1/C: it is the device capacitance (gate-drain, drain junctions), which these current-only tables do not have. Charge tables are #10777.

Negative controls (tests that pass by seeing the failure)

check_tt holds a table pair to the tt bounds: Id at the 1000 R2 points of each device, the DC transfer and the 10 pF transient against ngspice tt.

  • tt pair: passes.
  • ss pair where tt is expected: fails every measure, by a factor of 36 to 830 over its bound (59 uA at a held-out point, 283 mV of DC output, 10.3 mV of trip point, 112 mV of waveform, 6.5 % / 16 % of delay).
  • ff, fs, sf used as tt: fail.
  • NMOS and PMOS tables in each other's slots: fail, by 100 to 10000.
  • K = 1 Newton iteration: residual 8586 units against the bound 2 (K = 2 already meets it; the board's K = 3 has margin).

Checks run

  • t27c test-report: mos_table 14/14, mos_psp103_data 4/4, mos_psp103 11/11, vacuous passes 0 in each (about 15 s, 11 s, 16 s warm).
  • t27c seal --save then --verify: all hashes MATCH for the four renewed or new seals; no home path and no blocked verdict in them.
  • tools/dupe_scan.py: ok, no new duplicate body. tools/check_seal_currency.py: 0 stale. t27c check-calls --specs-dir specs/analog: 0. check_assertionless_spec_tests.py: ok.
  • Every committed deck was re-run from its repository copy, and its output regenerated the pasted arrays byte for byte (a diff of the wrapped text, identical). ngspice ran on the Mac here, per the lane brief.
  • The rows were wrapped onto lines and the pins computed with a throwaway python3 script under $TMPDIR (not committed); ngspice itself rounds each current to table units (nint in the deck) and clamps the sign.
  • t27b-native-ratchet may show UNLISTED rows for the two new specs; spec PRs do not edit the ledger (t27b ledger steward: the rules and the job card, so spec PRs stop editing the ledger (Closes #8654) #8656).

What this does not claim

  • It is a TABLE MODEL of PSP103, bilinear, at 27 C for two device sizes -- not PSP103 and not "the IHP transistor model". No body effect (bulk at source), no Vds < 0, no Vgs < 0, nothing about another W, L, m, temperature, the HV devices, mismatch or Monte Carlo.
  • No charge: the model is 3 .. 4 % off at 500 fF; a circuit with fF loads (the golden SAR comparator) needs charge tables.
  • The transient is checked for tt only, on one input (an ideal two-level step) and two circuits of the same dt/C; the other corners are checked on Id and on the DC transfer.
  • No speed claim (may_claim_speedup in bench.t27 stays no), no power, no board: no bitstream, BRAM, LUT, DSP, Fmax or UART line.
  • The uberWAVE deck (GPL-2.0) is not run or copied; only the W, L and Vdd of its inverter are used.

Left

#10777: terminal-charge tables, and a table read that is accurate in weak inversion (the 1 % proposal).

🤖 Generated with Claude Code

…rom ngspice, run by M3a's solver, inverter against ngspice (Closes #10516)

M3b of the analog emulation epic (#10486). Id(Vgs, Vds) of sg13_lv_nmos (W 1.0 um) and sg13_lv_pmos (W 3.0 um), L 0.45 um, from
ngspice-47 with PSP 103.6 over OSDI, IHP-Open-PDK commit 21133f21, 27 C, for mos_tt, mos_ff, mos_ss, mos_fs and mos_sf: 25 x 25 nodes
of 62.5 mV over 0 .. 1.5 V, which is M3a's reader exactly. The decks (specs/analog/decks/psp103_*.cir) print the numbers, rounded to
table units by ngspice itself; mos_psp103_data.t27 holds them with order-sensitive pins; mos_psp103.t27 judges them.

mos_table.t27 changes only so that the solver takes the NMOS table and the PMOS table as two arguments (g_resid, newton_iter,
inv_step, board_step, run_fix, newton_iter_f, run_tabf); every M3a test passes the same table twice and its pinned run is unchanged
bit for bit. A new test checks the mirror with two different tables. sar_comparator.t27 is untouched; its seal is renewed because the
closure hash of mos_table.t27 moved.

Measured against ngspice tt: Id at 576 midpoints and 1000 R2 points per device within 6.5e-7 A (NMOS) and 4.4e-7 A (PMOS), relative
error 0.56 % / 0.41 % where Id >= 100 uA; the proposed 1 % with a floor of 1e-9 A is NOT met (0.55 .. 0.73, weak inversion). DC
transfer of the inverter within 5.5 mV and 11 uV of trip point (every corner within 6.6 mV and 0.26 mV). Transient at 10 pF, 400
steps: arithmetic 4.8 units, table + model 1.28 mV and 0.14 / 0.17 % of the delay, discretization 14.4 mV and 0.5 / 0.7 %. The gap
to ngspice at 500 fF is 3.1 / 3.6 % and scales with 1 / C: it is the device capacitance, which these current-only tables lack.
Negative controls: ss tables used as tt, any other corner used as tt, and the tables in the wrong slots all fail the tt check.
test-report: 14 + 4 + 11 pass, 0 vacuous. Left for the charge tables and the weak-inversion read: see #10777.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-19 02:23:48 UTC

Summary

Status Count
Total Open PRs 50
PRs with Failing Checks 43
PRs with All Checks Green 7
READY 2
FAILING 43
PENDING 0
NO CHECKS YET 0

These columns do not partition: 2 + 43 + 0 + 0 = 45, and there are 50 open PRs. A PR is being counted twice or not at all.

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=fad12492937a != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

@gHashTag
gHashTag merged commit 6f21327 into master Oct 19, 2026
33 of 35 checks passed
gHashTag pushed a commit that referenced this pull request Oct 19, 2026
… and sar_switch (Closes #10753)

M3b changed mos_table.t27 (two tables) and renewed sar_comparator's seal for its closure; this branch
changed sar_comparator.t27 itself. The only conflict was that seal: both seals are made again on the
merged tree. mos_table 14/14, sar_comparator 20/20, sar_switch 14/14, mos_psp103 11/11,
mos_psp103_data 4/4, 0 vacuous each; seal --verify all MATCH; every closure hash current; dupe_scan ok.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

analog M3b: IHP SG13G2 PSP103 tables per corner from ngspice, plugged into the M3a solver -- inverter against ngspice

2 participants