Repository navigation
analog: PSP103 drain and gate charge tables (tt, ss), the charge-aware table solver, the 500 fF inverter within 0.02 % of ngspice (Closes #10880) - #10893
Draft
gHashTag wants to merge 1 commit into
Conversation
…e table solver, the 500 fF inverter within 0.02 % of ngspice (Closes #10880) M3c of #10486, the charge half of #10777 (Part of #10777). - specs/analog/decks/psp103_q_tt.cir, psp103_q_ss.cir: the drain and gate charge of sg13_lv_nmos / sg13_lv_pmos on the M3b grid, taken from the terminal currents of one backward Euler step (PSP103 reports no terminal charge), with the current tables and ngspice's own op-point capacitances printed in the same run. - mos_psp103_data.t27: TT_QD_N TT_QG_N TT_QD_P TT_QG_P and the SS_ four, the 401-sample ngspice backward Euler waveform at 500 fF (INV500_BE, printed by psp103_inv_be_500f.cir), pins. - mos_table.t27: the solver generalized with the two drain-charge tables and the previous step's gate (the *_q functions); the current-only functions are those with zero charge tables, nothing is copied, M3a's pinned run is untouched. Three tests: zero charge is the old path, a plane of charge gives the closed form of the gate-edge kick, the mirror holds with four tables swapped. - mos_psp103.t27: tt inverter at 500 fF and dt = 100 ps against ngspice backward Euler on the same grid, tpLH 0.020 % and tpHL 0.0041 % (3.09 % and 3.63 % without charge); the three errors apart; the ss charge tables in the tt run fail the check; the table slopes agree with ngspice's op-point capacitances within 0.3 %; the weak-inversion 1 % bound stated with its reasons (follow-up #10881). Corners ff, fs, sf: #10882. Part of #10486 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
gHashTag
force-pushed
the
claude/analog-m3c-charge-10777
branch
from
October 19, 2026 05:49
d38e80d to
c948f4d
Compare
16 of 21 tasks
This was referenced Oct 19, 2026
Merged
Contributor
This was referenced Oct 19, 2026
gHashTag
enabled auto-merge (squash)
October 19, 2026 06:38
This was referenced Oct 19, 2026
gHashTag
disabled auto-merge
October 19, 2026 07:11
gHashTag
marked this pull request as draft
October 19, 2026 07:11
This was referenced Oct 19, 2026
Merged
Merged
This was referenced Oct 19, 2026
This branch has not been deployed
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.
What
M3c of #10486, the charge half of #10777. The IHP SG13G2
sg13_lv_nmos/sg13_lv_pmosPSP103 drain and gate charge as tables on the M3b grid (corners tt and ss), the M3a table solver generalized to use them, and the CMOS inverter at 500 fF checked against ngspice backward Euler on the same grid: both 50 percent delays are within 0.020 percent and 0.0041 percent (the issue asked for 1 percent; today, without charge, 3.09 and 3.63 percent).Closes #10880. Part of #10777. Part of #10486. The weak-inversion read is not done here (see #10881); charge for ff, fs, sf is #10882.
The tables
21133f219b1a6da10d803e345761e77415ceff40,cornerMOSlv.lib(PSP 103.6 rev 200310),psp103.vacompiled by OpenVAF-Reloaded v24.0.2mob; ngspice-47psp103_tab_tt.cir)TT_QD_N TT_QG_N TT_QD_P TT_QG_Pand theSS_four: drain and gate charge of each devicespecs/analog/decks/psp103_q_tt.cir,psp103_q_ss.cir(new);psp103_inv_be_500f.cirnow also prints the 401-sample waveform (its two.measnumbers are unchanged)Which variables. PSP103 reports no terminal charge as an output variable:
showon the OSDI instance lists currents (ids ige ...), conductances (gm gmb gds) and capacitances (cdd cdg cgg cgd ..., with the overlapscgsol cgdoland the junctionscjs cjdeach reported apart), and noq*. So the deck takes the whole terminal charge (channel, overlap, fringe, junction) from the terminal current of one backward Euler step, which is what ngspice integrates:i(B) = Idc(B) + (Q(B) - Q(A)) / dt. A staircase B source visits each grid node B from the origin A and goes back; the return step is the one measured (its end state is the off origin, so the subtracted DC current is picoamps, not the 400 uA of a node in strong inversion). dt = 10 ns, long against the model's gate resistance; the same tables at dt = 1 ns differ by at most 52 units of a 277901-unit range (checked offline, not a test).FR-001, one run. The same deck run prints
grid_n/grid_p, which are byte for byteTT_N,TT_P(andSS_N,SS_Pfor the ss deck): the current tables and the charge tables come from one run of one netlist. All pasted arrays were regenerated from the committed decks and compared with the spec, identical (12 tables, the 401-sample waveform, the six op-point numbers).An independent check. The tables are made from currents and never saw ngspice's own capacitance numbers. At Vgs = 0.9 V, Vds = 0.75 V (the deck's
op_nblock printscdd cdg cgg cgsol cgdol cjd) the slopes ofTT_QD_NandTT_QG_Nare within 0.16 %, 0.29 % and 0.19 % ofcdd + cjd + cgdol,-(cdg + cgdol)andcgg + cgsol + cgdol(1024, -2013, 4739 aF). The ss table's gate-drain coupling at the same point is 2.6 % off tt's, which the 1 % test sees.The solver (FR-002, FR-003)
mos_table.t27is generalized, not copied. The output node holdsC y + Qd_n - Qd_p, so the step is(y - y0) + (qn(A, y) - qn(A0, y0)) - (qp(Vdd - A, Vdd - y) - qp(Vdd - A0, Vdd - y0)) + In - Ip = 0with
A0the gate of the previous step (a gate edge is a jump of charge, the Miller kick). The Newton derivative adds the Vds slope of each charge table, read off the same table as the value (gds_cell; a test over all 576 cells of all eight tables). New:gq_pos gq_neg gq_deriv g_resid_q newton_iter_q inv_step_q board_step_q run_fix_q(u32 words, no float) andnewton_iter_qf run_tabf_q(f64 side),monotone_along,NOQ. The current-only functions (newton_iter,inv_step,board_step,run_fix,g_resid,newton_iter_f,run_tabf) are now the charge-aware ones with the zero tablesNOQ: same signatures, same values; all 14 M3a tests and M3a's pinned run (EXP_S) pass unchanged.python3 -I tools/dupe_scan.py: no new duplicate body.Three new tests in
mos_table.t27: zero charge tables give the current-only path (77 asserts); a synthetic plane of charge with no device current gives the closed-form gate-edge kick and load (y0 - K1' Vdd / (1 + K2'), within 3 units, for an NMOS-side and a PMOS-side charge; a still gate with any charge does not move the node); the mirror holds bit for bit with the four tables swapped (63 states). That last one pins the sign convention of the negated PMOS table.The inverter against ngspice (tt, 500 fF, dt = 100 ps, 400 steps, same grid)
The tests hold: both delays within 1 % (the issue's bar), then the measured values from both sides (0.020 %: between 0.019 and 0.021; 0.0041 %: between 0.0039 and 0.0044), the waveform under 6700 units, the fold of the 400 fixed-point samples pinned (
EXP_S_TT_Q), the last Newton residual at most 2 units (the bound) at every step, K = 1 leaves 11636.The three errors, apart.
All three together, the fixed-point model against ngspice's converged run: 0.54 % and 0.67 %: now all of it is the scheme's, not the model's. The charge removes 99.4 % (tpLH) and 99.9 % (tpHL) of the delay gap and 98.5 % of the waveform's.
Negative controls (tests that pass by seeing the failure)
The check is the tt 500 fF check: both delays and the waveform against ngspice tt backward Euler, bounds 0.05 % and 6700 units. The tt current tables with the tt charge pass.
Part 3, the weak-inversion read: not met, and why
The relative error with a 1e-9 A floor stays at the measured 0.55 .. 0.73. A test records two facts of the tables that no read of them can undo: a table word is 298 pA, so rounding alone is up to 149 pA, 15 % of the 1 nA floor where 1 % allows 10 pA; and the NMOS current grows 6.5 .. 7 times per 62.5 mV cell in weak inversion (ngspice's own midpoint currents), where a chord is more than 41 % above the exponential at the middle. A table in 0.3 pA units has 1.3e9 for its largest word, over the 2^23 the u64 interpolation allows. The reader that meets it is a different reader (a log-domain table in finer units with an integer exp), filed as #10881 with its own criteria. I did not measure a log-domain read; no number about one is claimed.
Checks run
t27c test-report:mos_table17/17 (FAIL 0, vacuous passes 0 of 17),mos_psp103_data7/7 (0 of 7),mos_psp10317/17 (0 of 17);t27b testthe same.t27c seal --savethen--verify: all hashes MATCH formos_table,mos_psp103_data,mos_psp103;sar_comparatorandsar_switchimportmos_table, so their closure hash moved and their seals are renewed (their text is untouched;--verifyMATCH). No home path and no blocked verdict in any of the five. Thebuilt_byfield shows the compiler build I used.python3 -I tools/dupe_scan.py: ok, no new duplicate body.tools/check_assertionless_spec_tests.py: ok.t27c check-calls --specs-dir specs/analog: 0.tri types ratchet: CLEAN on this branch's own changes (the only new struct isCheckQ, unique in the corpus). On top of current master it reports one new name,Range, which issar_adc.t27's (master's, not this PR's).2c35ace22after the PR opened: master had re-sealedanalog_AnalogSarSwitch.json(itssar_cdac.t27moved), so that one seal was minted again on the merged state; the other four are as first sealed.$TMPDIR(not committed). ngspice itself rounds each value to table units (nintin the deck).What this does not claim
may_claim_speedupinbench.t27stays no).board_step_qis the exact-integer step; no board top.🤖 Generated with Claude Code