Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions .trinity/seals/analog_AnalogMosPsp103.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,31 @@
},
{
"spec": "specs/analog/mos_psp103_data.t27",
"spec_hash": "sha256:d5f3244ff1936f2b96e95b06e022d6b42b489ac49e025ec99486d6d36e6c6580"
"spec_hash": "sha256:be100dec66ee80de6cf520f79038e7668bc1171102db1fefe6a4c74559d029de"
},
{
"spec": "specs/analog/mos_table.t27",
"spec_hash": "sha256:9c0d1537ed5d8d60c4bdcb67d1e4c73ef80270e8cab224cb089c5b568fe11182"
"spec_hash": "sha256:16d28f10fa8663926dddb4bcced981cdc4cd8f38a6b748e4b7688f2e56bbab6c"
}
],
"config": "gen=c,rust,verilog,zig;tests=zig",
"gen_hash_c": "sha256:d7a49c643703a544723718186df74850018c4bf067fdb06ca9c860d775e069e8",
"gen_hash_rust": "sha256:32ee0d51345b936e45ff10956b90fdcafb6106bca46c2700de2bf43bf4407119",
"gen_hash_verilog": "sha256:0e3d19e85e67353129e8213c6135a5d1b518de4d7502c2d92512695b92de832e",
"gen_hash_zig": "sha256:445a5f05e794204ad3e4c198735c6fb1f4ab816e26fd36d3c408bba83168164f",
"gen_hash_c": "sha256:a5aeefd7abe3aee47919f32153161040121a31fba6fbfc6e3517fe1796191a8a",
"gen_hash_rust": "sha256:0660934f0f63c77f8b204796f1c8e3f5db1d35603797d7ddf912f66a2039d4a2",
"gen_hash_verilog": "sha256:06e55f455e71a7b274d2b8e766028a05ec666c1814b4ed64f8e7ad381706e61e",
"gen_hash_zig": "sha256:460548424dd136ec773917ebc3dd3c6ad31561cbde36cabf8a69266c2e8c7b6c",
"module": "AnalogMosPsp103",
"ring": 12,
"seal_schema": 2,
"sealed_at": "2026-10-19T02:10:22Z",
"sealed_at": "2026-10-19T05:34:01Z",
"sealed_by": "t27c-bootstrap@0.5.2",
"spec_hash": "sha256:c5bd55a847953654fbef792dcfc61da7f6434b8023341df9ab4a53e5d082bbe0",
"spec_hash": "sha256:811617266484683542dd1723db77687ad7fdf7f5a665953f5e6a920a7bdf0118",
"spec_path": "specs/analog/mos_psp103.t27",
"tests": {
"failed": 0,
"failing": [],
"forced": false,
"passed": 11,
"total": 11,
"passed": 17,
"total": 17,
"vacuous": 0
},
"toolchain": {
Expand Down
16 changes: 8 additions & 8 deletions .trinity/seals/analog_AnalogMosPsp103Data.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,23 @@
}
],
"config": "gen=c,rust,verilog,zig;tests=zig",
"gen_hash_c": "sha256:d0135ebcf91901c442dc8a0c3e3a431f50a57cbc563d430a34e45e68392c9dfe",
"gen_hash_rust": "sha256:9dad368c2549f028ae0828213c7231a0e8ff613988ff42ce7d3aac6fcf9c4e52",
"gen_hash_verilog": "sha256:52f448d5fe93db1de3faa5fa13cb881486ec67a2ed17d1db475cd4d8d222ac82",
"gen_hash_zig": "sha256:1bdd4c520cb0864ffa3c4d2f7ce80418e7a0752e37610b81b4a000c528c413f9",
"gen_hash_c": "sha256:be16cbf1fbac3021d77530b1e86f19bfacf626eb7cfe834900c984331491c060",
"gen_hash_rust": "sha256:cbd4b0ad5ced378295e73bec1bcc69ff8270b99f4a4e27064a6aa2b0aa02c222",
"gen_hash_verilog": "sha256:f062ed3fc219deec9fa254d48b0a8e3ac8de0d2c525810154d1f25ab20a95162",
"gen_hash_zig": "sha256:03d50a36f22f40daf936ade0b764ae11b4142c3f667bf1ab640007eb4fdbcb45",
"module": "AnalogMosPsp103Data",
"ring": 12,
"seal_schema": 2,
"sealed_at": "2026-10-19T02:10:08Z",
"sealed_at": "2026-10-19T05:33:43Z",
"sealed_by": "t27c-bootstrap@0.5.2",
"spec_hash": "sha256:d5f3244ff1936f2b96e95b06e022d6b42b489ac49e025ec99486d6d36e6c6580",
"spec_hash": "sha256:be100dec66ee80de6cf520f79038e7668bc1171102db1fefe6a4c74559d029de",
"spec_path": "specs/analog/mos_psp103_data.t27",
"tests": {
"failed": 0,
"failing": [],
"forced": false,
"passed": 4,
"total": 4,
"passed": 7,
"total": 7,
"vacuous": 0
},
"toolchain": {
Expand Down
18 changes: 9 additions & 9 deletions .trinity/seals/analog_AnalogMosTable.json
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
{
"built_by": "t27c-bootstrap@0.5.2+ea35d9b72",
"built_by": "t27c-bootstrap@0.5.2+c948f4df7",
"closure": [
{
"spec": "specs/analog/linear.t27",
"spec_hash": "sha256:3ddef7be183aba583ed285334ee389b48a65b41335e98914514235db7c4e5d62"
}
],
"config": "gen=c,rust,verilog,zig;tests=zig",
"gen_hash_c": "sha256:3de4432818944eab74fae03952b4b4cffd104b00b9cda80dd73bb6ed6e819f0c",
"gen_hash_rust": "sha256:775c36a7f0370d1bc3dd0752f72f435e3fbc6e4972ad9b5c77efc35fb2784750",
"gen_hash_verilog": "sha256:0f3b42817e930cb80890ec45f5ecb5ecdf2a73bb764d029149ab8519dfd43dfc",
"gen_hash_zig": "sha256:05393568aa75f13169560fb6fd1118d46141ae46931458fc181ac12ba42ca196",
"gen_hash_c": "sha256:e0ca09255f83209260afff210947c8af851f5412f9aa7a40f7f5b148a29ac739",
"gen_hash_rust": "sha256:dd4d433feaf2d937fc3acb769f6a9a8febc6d7cc58363dbc061ad9922eba3eb6",
"gen_hash_verilog": "sha256:b7e968dea3013590b323ce7c40e3be8df1d047bf6bde5b58768de36438102e7d",
"gen_hash_zig": "sha256:652d1bfbd355d08e8eca4a3f13a4957322006510c310d796111db8aac65ef1d0",
"module": "AnalogMosTable",
"ring": 12,
"seal_schema": 2,
"sealed_at": "2026-10-19T02:09:56Z",
"sealed_at": "2026-10-19T13:35:45Z",
"sealed_by": "t27c-bootstrap@0.5.2",
"spec_hash": "sha256:9c0d1537ed5d8d60c4bdcb67d1e4c73ef80270e8cab224cb089c5b568fe11182",
"spec_hash": "sha256:16d28f10fa8663926dddb4bcced981cdc4cd8f38a6b748e4b7688f2e56bbab6c",
"spec_path": "specs/analog/mos_table.t27",
"tests": {
"failed": 0,
"failing": [],
"forced": false,
"passed": 14,
"total": 14,
"passed": 17,
"total": 17,
"vacuous": 0
},
"toolchain": {
Expand Down
11 changes: 11 additions & 0 deletions specs/analog/decks/psp103_inv_be_500f.cir
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ IHP SG13G2 inverter, 500 fF, backward Euler on a fixed 100 ps grid, corner mos_t
* at (k + 2) dt; step 0 starts at t = dt = 100 ps and step 200 at 201 dt = 20.1 ns.
* What it prints (ngspice .meas, 6 digits, in s): tplh and tphl, the times at which the output crosses 0.75 V rising (after step 0's edge) and
* falling (after step 200's edge); the delays are these minus 100 ps and minus 20.1 ns.
* M3c adds the waveform: between "BEGIN tran_be" and "END tran_be", 401 rows "<index> TAB <time> TAB <y>", y the output in units of 2^-24 V at
* t = 100 ps, 200 ps, ... 40.1 ns (row 0 is the circuit at rest before step 0, row k + 1 the output after step k), as psp103_inv_be.cir does at 2 ns.
.lib $IHP_PDK/ihp-sg13g2/libs.tech/ngspice/models/cornerMOSlv.lib mos_tt
VDD vdd 0 1.5
Bin in 0 V = 1.5*(1-min(max(nint(time/1e-10)-1,0),1)+min(max(nint(time/1e-10)-201,0),1))
Expand All @@ -26,5 +28,14 @@ CL out 0 500f
pre_osdi $IHP_OSDI/psp103.osdi
pre_osdi $IHP_OSDI/psp103_nqs.osdi
run
* M3c (#10777): after the run, which prints the two .meas numbers as before, the waveform is printed the way psp103_inv_be.cir prints it.
set numdgt=10
set noprintscale
let y = nint(v(out) * 16777216)
let ts = time[8,408]
let ys = y[8,408]
echo BEGIN tran_be
print ts ys
echo END tran_be
.endc
.end
140 changes: 140 additions & 0 deletions specs/analog/decks/psp103_q_ss.cir
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
IHP SG13G2 PSP103 drain and gate charge tables, corner mos_ss
* specs/analog/decks/psp103_q_ss.cir -- charge table data for specs/analog/mos_psp103_data.t27 (M3c, #10777, epic #10486). A netlist plus a
* .control block that prints the numbers. The same deck exists for corner mos_tt (psp103_q_tt.cir); the two differ in the title and the .lib section.
* The IHP corner file is read at run time and never copied here.
* Model: IHP-Open-PDK commit 21133f219b1a6da10d803e345761e77415ceff40, ihp-sg13g2/libs.tech/ngspice/models/cornerMOSlv.lib (PSP 103.6,
* revision 200310), section mos_ss; the model code is libs.tech/verilog-a/psp103/psp103.va of the same commit, compiled with
* OpenVAF-Reloaded v24.0.2mob to psp103.osdi (and psp103_nqs.osdi). Temperature 27 C (TNOM 27 C). Devices: sg13_lv_nmos w=1.0u l=0.45u
* ng=1 m=1 and sg13_lv_pmos w=3.0u l=0.45u ng=1 m=1, exactly the devices of psp103_tab_ss.cir (the same netlist lines), on the same
* 25 x 25 grid of 62.5 mV over 0 .. 1.5 V.
* Solver options: reltol 1e-6, vntol 1e-9, abstol 1e-14, as psp103_tab_ss.cir.
* Paths are NOT in this file. ngspice reads two environment variables: IHP_PDK, the IHP-Open-PDK checkout, and IHP_OSDI, the directory that
* holds the compiled psp103.osdi and psp103_nqs.osdi.
* Run: IHP_PDK=<checkout> IHP_OSDI=<osdi dir> ngspice -b psp103_q_ss.cir > psp103_q_ss.out (ngspice-47)
* WHICH VARIABLES. PSP103 reports no terminal charge as an output variable: `show` on the OSDI instance lists currents (ids, ige, ...), conductances
* (gm, gmb, gds) and capacitances (cdd, cdg, cgg, cgd, ..., plus the overlap cgsol, cgdol and the junction cjs, cjd, each reported apart), and
* no q*. The charge is therefore taken from the terminal CURRENTS of a backward Euler step, which is what ngspice itself integrates: for a step
* of dt from state A to state B the current into a terminal is i(B) = Idc(B) + (Q(B) - Q(A)) / dt, with Q the terminal's whole charge
* (channel, overlap, fringe and junction parts together), so Q(B) - Q(A) = (i(B) - Idc(B)) dt. The drive is a staircase: node k of the grid
* (ix = k / 25 along Vgs, iy = k mod 25 along Vds) is visited from the origin A = (0, 0) and the bias goes back to A on the next step. The
* return step is the one measured: its end state is the origin, where the device is off and Idc(A) is the current of the first step, so the
* subtraction is of a current of picoamps, not of the 400 uA of a node in strong inversion. Then
* Q(B) - Q(A) = (i_A - i_return) dt with i_A the terminal current at the origin before the first jump and i_return at the end of the return step.
* The step is dt = 10 ns, long against the gate resistance of the model (about 29 ohm times a few fF is 0.1 ps), so the gate network has settled
* and the charge is the quasi-static one. (At dt = 100 ps the settling is 1 part in 1000 and the outgoing step, measured against the DC current of the
* node, shows it as a current deficit of tau gm dV, which is why the outgoing step is not used.)
* What it prints. Between "BEGIN name" and "END name" every row "<index> TAB <value>" is one number, in sweep order (index = ix * 25 + iy). The
* values are pasted into the spec in that order, none changed.
* grid_n, grid_p Id of the nmos at Vgs = ix * 62.5 mV, Vds = iy * 62.5 mV and of the pmos at Vsg, Vsd, exactly as psp103_tab_ss.cir prints them
* (units of 2^-24 V, dt/C = 200 V/A): the current tables and the charge tables come from one run of one netlist. Negative values held at 0.
* op_n cdd, cdg, cgg, cgsol, cgdol, cjd of the nmos at Vgs = 0.9 V, Vds = 0.75 V in aF, as ngspice reports them: the channel capacitances
* (cdd = dQd/dVd, cdg = dQd/dVg, cgg = dQg/dVg of the intrinsic charges), the gate-source and gate-drain overlaps and the drain junction, each apart.
* qd_n the DRAIN charge of the nmos. Unit: Q / 500 fF in units of 2^-24 V, that is the voltage a 500 fF node moves when it takes the charge, so
* one unit is 500 fF * 59.6 nV = 2.98e-20 C (0.19 electron). Entry = nint(2e12 * 2^24 * (Q(B) - Q(A))) + 2^21: the charge relative to the
* origin Vgs = Vds = 0, plus 2^21 so that no entry is negative. The offset is arbitrary; only differences are physical.
* qg_n the GATE charge of the nmos, the same unit and offset.
* qd_p the DRAIN charge of the pmos at Vsg = ix * 62.5 mV, Vsd = iy * 62.5 mV (source and bulk on the 1.5 V rail), NEGATED: entry =
* 2^21 - nint(2e12 * 2^24 * (Q(B) - Q(A))), so that it grows with Vsd as the nmos' does (capacitances are positive: the drain charge grows with
* the drain voltage, which falls as Vsd grows).
* qg_p the GATE charge of the pmos, negated the same way (grows with Vsg).
* tchk the largest distance of an ngspice time point used from the grid k * 10 ns, in s: 0 when every row used is a step end.
* nmos tran device: drain and gate on B sources through zero-volt current meters; the source and bulk at 0 V
.lib $IHP_PDK/ihp-sg13g2/libs.tech/ngspice/models/cornerMOSlv.lib mos_ss
.func kst() {nint(time/1e-8)}
.func nd() {max(floor(kst()/2)-1,0)}
.func act() {(time<1e-3)*(kst()>=2)*((kst()-2*floor(kst()/2))==0)}
.func ixf() {floor(nd()/25)}
.func iyf() {nd()-25*floor(nd()/25)}
* (act() is 0 in a DC sweep: ngspice puts the swept value into `time`, which is at least 62.5 mV there and below 13 us in the transient.)
BDN tdn 0 V = act()*0.0625*iyf()
BGN tgn 0 V = act()*0.0625*ixf()
VMDN tdn tdnn 0
VMGN tgn tgnn 0
XTN tdnn tgnn 0 0 sg13_lv_nmos w=1.0u l=0.45u ng=1 m=1
* pmos tran device: source and bulk at the 1.5 V rail; the origin is Vsg = Vsd = 0
VTSP tsp 0 1.5
BDP tdp 0 V = 1.5-act()*0.0625*iyf()
BGP tgp 0 V = 1.5-act()*0.0625*ixf()
VMDP tdp tdpp 0
VMGP tgp tgpp 0
XTP tdpp tgpp tsp tsp sg13_lv_pmos w=3.0u l=0.45u ng=1 m=1
* nmos table device: drain VDN, gate VGN, source and bulk at 0 V (as psp103_tab_ss.cir)
VDN dn 0 0
VGN gn 0 0
XMN dn gn 0 0 sg13_lv_nmos w=1.0u l=0.45u ng=1 m=1
* pmos table device: source and bulk at the 1.5 V rail, drain VDP and gate VGP, both swept downward from 1.5 V
VSP sp 0 1.5
VDP dp 0 1.5
VGP gp 0 1.5
XMP dp gp sp sp sg13_lv_pmos w=3.0u l=0.45u ng=1 m=1
.temp 27
.options reltol=1e-6 vntol=1e-9 abstol=1e-14
.options method=gear maxord=1 trtol=1e7 itl4=200
.control
pre_osdi $IHP_OSDI/psp103.osdi
pre_osdi $IHP_OSDI/psp103_nqs.osdi
set numdgt=10
set noprintscale
echo BEGIN grid_n
dc VDN 0 1.5 0.0625 VGN 0 1.5 0.0625
let u = nint(-i(VDN) * 200 * 16777216)
let u = (u + abs(u)) / 2
print u
echo END grid_n
echo BEGIN grid_p
dc VDP 1.5 0 -0.0625 VGP 1.5 0 -0.0625
let u = nint(i(VDP) * 200 * 16777216)
let u = (u + abs(u)) / 2
print u
echo END grid_p
* the capacitances ngspice itself reports at one operating point of the nmos, Vgs = 0.9 V, Vds = 0.75 V, in aF (nint(C * 1e18)): the cross-check of
* the charge tables, which are made from currents and never see these
alter VDN = 0.75
alter VGN = 0.9
op
let c_dd = nint(@n.xmn.nsg13_lv_nmos[cdd] * 1e18)
let c_dg = nint(@n.xmn.nsg13_lv_nmos[cdg] * 1e18)
let c_gg = nint(@n.xmn.nsg13_lv_nmos[cgg] * 1e18)
let c_gsol = nint(@n.xmn.nsg13_lv_nmos[cgsol] * 1e18)
let c_gdol = nint(@n.xmn.nsg13_lv_nmos[cgdol] * 1e18)
let c_jd = nint(@n.xmn.nsg13_lv_nmos[cjd] * 1e18)
echo BEGIN op_n
print c_dd c_dg c_gg c_gsol c_gdol c_jd
echo END op_n
tran 7.8125n 12.54u 0 10n
let dn0 = i(vmdn)[8]
let gn0 = i(vmgn)[8]
let dp0 = i(vmdp)[8]
let gp0 = i(vmgp)[8]
let qdn = unitvec(625)
let qgn = unitvec(625)
let qdp = unitvec(625)
let qgp = unitvec(625)
let tchk = abs(time[8] - 1e-8)
let k = 0
while k < 625
let r = 2*k + 10
let tchk = max(tchk, abs(time[r] - (2*k+3)*1e-8))
let qdn[k] = nint((dn0 - i(vmdn)[r]) * 1e-8 * 2e12 * 16777216) + 2097152
let qgn[k] = nint((gn0 - i(vmgn)[r]) * 1e-8 * 2e12 * 16777216) + 2097152
let qdp[k] = 2097152 - nint((dp0 - i(vmdp)[r]) * 1e-8 * 2e12 * 16777216)
let qgp[k] = 2097152 - nint((gp0 - i(vmgp)[r]) * 1e-8 * 2e12 * 16777216)
let k = k + 1
end
echo BEGIN qd_n
print qdn
echo END qd_n
echo BEGIN qg_n
print qgn
echo END qg_n
echo BEGIN qd_p
print qdp
echo END qd_p
echo BEGIN qg_p
print qgp
echo END qg_p
echo BEGIN tchk
print tchk
echo END tchk
.endc
.end
Loading
Loading