From 382bde5b964fd4267f8545f06d0490727751ed17 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Oct 2026 23:05:52 +0700 Subject: [PATCH] analog M4e-kick (partial): four ngspice decks for the comparator's clock-edge kick -- gate-charge table, edge waveform, aperture, plate-node capacitance (Part of #10942) Decks only, no spec yet. sar_kick_qg.cir: Q_G(Vg, Vs, Vd) of the input pair's device, bulk on ground, 50 C, three gate levels (M3c's table is bulk-at-source, 27 C: +38 percent on the edge charge). sar_kick_edge.cir: tail and drain waveforms and the gate charge at the first decision's clock edge, gates held. sar_kick_aperture.cir: how much a step of the input at tau still decides. sar_kick_cnode.cir: the two-port capacitance the idle bottom-plate drivers hang on Bit and Bit_n. Co-Authored-By: Claude Sonnet 5.5 --- specs/analog/decks/sar_kick_aperture.cir | 81 ++++++++++++++++++++++++ specs/analog/decks/sar_kick_cnode.cir | 46 ++++++++++++++ specs/analog/decks/sar_kick_edge.cir | 80 +++++++++++++++++++++++ specs/analog/decks/sar_kick_qg.cir | 66 +++++++++++++++++++ 4 files changed, 273 insertions(+) create mode 100644 specs/analog/decks/sar_kick_aperture.cir create mode 100644 specs/analog/decks/sar_kick_cnode.cir create mode 100644 specs/analog/decks/sar_kick_edge.cir create mode 100644 specs/analog/decks/sar_kick_qg.cir diff --git a/specs/analog/decks/sar_kick_aperture.cir b/specs/analog/decks/sar_kick_aperture.cir new file mode 100644 index 0000000000..59b4352511 --- /dev/null +++ b/specs/analog/decks/sar_kick_aperture.cir @@ -0,0 +1,81 @@ +The golden comparator's aperture: how much a step of its input at time tau still matters to the decision (M4e-kick, #10942) +* specs/analog/decks/sar_kick_aperture.cir -- sar_kick_edge.cir (the golden comparator, SAR_logic and clock_gen with the two gates on ideal sources, the plates' tracking history tp = 14 ns) with ONE thing +* added: the gate of VDP takes a step of dv = 1 mV at the time tau (20 ps ramp), and the decision is read as the difference of the latch's two outputs, v(dp) - v(dn), 4.8 ns after the +* clock edge's 0.1 V crossing (104.107 ns; 5.0 ns after gives the same ratios). The latch amplifies a small difference of its inputs exponentially, so the response is proportional to dv for a +* small step and the ratio of the response to a step at tau to the response to a step before the edge is the share of the decision that the input still decides at tau: 1 until the pair +* begins to lose its gain and 0 once the latch has locked. The kick of the comparator's own plates moves VDP - VDN through that window, and sar_kick_net.t27 weighs it by this aperture. +* The unperturbed run has dp = dn (the plates are alike); the steps at 98.3069 ns (before the edge), at 0.5 mV and at 2 mV, give the same response to 0.1 percent (LINEAR rows). +* Paths are NOT in this file: IHP_PDK, IHP_OSDI and SAR_GOLDEN_SUBCKTS as in sar_kick_edge.cir. Run: ngspice -b sar_kick_aperture.cir (ngspice-47, about two minutes) +* It prints one row per tau between BEGIN aperture and END aperture: tau - 99.3069 ns (the clkc 0.1 V crossing of the unperturbed run) in ns, and the response in volts. +.param vg=0.742 +.param tp=14n +.param tau=1 +.param dv=0 +.lib $IHP_PDK/ihp-sg13g2/libs.tech/ngspice/models/cornerMOSlv.lib mos_tt +.lib $IHP_PDK/ihp-sg13g2/libs.tech/ngspice/models/cornerCAP.lib cap_typ +.include $SAR_GOLDEN_SUBCKTS +VDD4 vdda 0 1.5 +VDD6 vdd 0 1.5 +VDD1 vss 0 0 +V2 c 0 0 +V5 b 0 0 +V6 a 0 0 +VCLKS clks 0 PULSE(0 1.5 0n 2n 2n 80n 500n) +BPD vdpi 0 V = {vg}*(1-exp(-time/{tp}))+{dv}*min(max((time-{tau})/20p,0),1) +BND vdni 0 V = {vg}*(1-exp(-time/{tp})) +VMP vdpi vdp 0 +VMN vdni vdn 0 +x3 vocp vocn valid vdp vdn clkc vdd 0 dynamic_comparator_top +x7 ck3 ck11 ck7 ck2 ck6 ck10 ck1 ck9 ck5 ck8 ck4 vdd 0 vdd valid 0 clks SAR_logic +x4 vdd clkc 0 clks valid ck1 a b c clock_gen +C9 clkc 0 4f +C10 vocp 0 4f +C11 valid 0 4f +C12 vocn 0 4f +C13 clkc 0 4f +C14 clks 0 4f +C15 valid 0 4f +C16 ck1 0 4f +C17 a 0 4f +C18 b 0 4f +C19 c 0 4f +C20 clks 0 4f +C21 valid 0 4f +.options temp=50 +.options klu +.control +pre_osdi $IHP_OSDI/psp103.osdi +pre_osdi $IHP_OSDI/psp103_nqs.osdi +pre_osdi $IHP_OSDI/r3_cmc.osdi +pre_osdi $IHP_OSDI/mosvar.osdi +pre_osdi $IHP_OSDI/cap_cmomi.osdi +pre_osdi $IHP_OSDI/cap_cmomf.osdi +set num_threads=4 +echo BEGIN aperture +foreach tauv 98.3069n 102.3069n 102.4319n 102.5569n 102.6819n 102.8069n 102.9319n 103.0569n 103.1819n 103.3069n 103.4319n 103.5569n 103.6819n 103.8069n 103.9319n 104.0569n 104.1819n + alterparam vg = 0.742 + alterparam tp = 14n + alterparam tau = $tauv + alterparam dv = 0.001 + reset + tran 0.05n 107n + meas tran dd find v(x3.dp) at=104.1069n + meas tran de find v(x3.dn) at=104.1069n + echo APERTURE $tauv + print dd de +end +foreach dvv 0 0.0005 0.002 + alterparam vg = 0.742 + alterparam tp = 14n + alterparam tau = 98.3069n + alterparam dv = $dvv + reset + tran 0.05n 107n + meas tran dd find v(x3.dp) at=104.1069n + meas tran de find v(x3.dn) at=104.1069n + echo LINEAR $dvv + print dd de +end +echo END aperture +.endc +.end diff --git a/specs/analog/decks/sar_kick_cnode.cir b/specs/analog/decks/sar_kick_cnode.cir new file mode 100644 index 0000000000..4f0a9b9cc6 --- /dev/null +++ b/specs/analog/decks/sar_kick_cnode.cir @@ -0,0 +1,46 @@ +The capacitance the bottom-plate drivers hang on an idle bit's two plate nodes (M4e-kick, #10942) +* specs/analog/decks/sar_kick_cnode.cir -- one bit of the golden SAR ADC's bottom-plate logic, idle: DAC_control (its inverter, its tgate x2 to VCM, the tgates x3 and x8, two dffs) and +* neg_bottom_plate_logic (the tgates x11 and x10 and x15, the inverters x12, x13, x14) of the uberWAVE golden deck (wp2-parser/golden/top.spice, GPL-2.0: read at run time, never +* vendored; the subcircuits come from the run-time file SAR_GOLDEN_SUBCKTS, made as in sar_off_base.cir), with its clock CK11 low so that the bit is idle: Bit (the P half's plate node) is held at VCM +* by the tgate x2 and Bit_n (the N half's) reaches Bit through the tgate x11. The two plate nodes are the two ports; the DAC's capacitors are NOT here (they are the capacitor network's own), +* so what is measured is what the drivers add to the nodes: junction, overlap and channel charge of the devices of the golden subcircuits at the idle bias, through the PSP103 model (OSDI). +* Each port is held at 0.75 V by a source with a 1 V small-signal part in turn and the current of both sources is read at 100 MHz (and 300 MHz): the admittance matrix Y = G + j w C of the two-port. +* It prints, between BEGIN y and END y, one row per run (port 1 excited, port 2 excited) and frequency: the real and imaginary parts of the two currents into the ports, in A (volts are 1). +* The network model reads C11 + C12 (Bit to ground), C22 + C21 (Bit_n to ground) and -C12 (Bit to Bit_n), C_ij = Im Y_ij / w; Re Y11 is 1 / R(x2) + 1 / R(x11) and -Re Y12 = 1 / R(x11): +* the tgates' resistances (sar_off_ron.cir measures one at 10 mV) again, in situ. +* Paths are NOT in this file: IHP_PDK, IHP_OSDI and SAR_GOLDEN_SUBCKTS as in sar_off_base.cir. Run: ngspice -b sar_kick_cnode.cir (ngspice-47, seconds). TEMP 50 as in the golden deck. +.lib $IHP_PDK/ihp-sg13g2/libs.tech/ngspice/models/cornerMOSlv.lib mos_tt +.lib $IHP_PDK/ihp-sg13g2/libs.tech/ngspice/models/cornerCAP.lib cap_typ +.include $SAR_GOLDEN_SUBCKTS +VDD vdd 0 1.5 +VCM vcm 0 0.75 +VCK ck 0 0 +VIN vin 0 0.75 +VCLK clks 0 0 +VST set 0 0 +VRS reset 0 0 +XD vdd 0 sar vcm bitp vin ck set reset clks DAC_control +XN vdd 0 ck bitp bitn neg_bottom_plate_logic +VPB bitp 0 0.75 ac 1 +VNB bitn 0 0.75 ac 0 +.options temp=50 +.control +pre_osdi $IHP_OSDI/psp103.osdi +pre_osdi $IHP_OSDI/psp103_nqs.osdi +set numdgt=8 +echo BEGIN y +foreach fr 1e8 3e8 + alter vpb ac = 1 + alter vnb ac = 0 + ac lin 1 $fr $fr + echo PORT1 $fr + print i(vpb) i(vnb) + alter vpb ac = 0 + alter vnb ac = 1 + ac lin 1 $fr $fr + echo PORT2 $fr + print i(vpb) i(vnb) +end +echo END y +.endc +.end diff --git a/specs/analog/decks/sar_kick_edge.cir b/specs/analog/decks/sar_kick_edge.cir new file mode 100644 index 0000000000..90b17dd7b6 --- /dev/null +++ b/specs/analog/decks/sar_kick_edge.cir @@ -0,0 +1,80 @@ +The golden comparator and its clock generator at the first decision's clock edge, the two gates held (M4e-kick, #10942) +* specs/analog/decks/sar_kick_edge.cir -- the golden dynamic_comparator_top, SAR_logic and clock_gen of the SAR ADC deck of uberWAVE (wp2-parser/golden/top.spice, GPL-2.0: fetched at run +* time, never vendored; the subcircuits come from the run-time file SAR_GOLDEN_SUBCKTS, made as in sar_off_base.cir) with the two top plates replaced by ideal sources, so that what the +* input pair does at the clock edge is read with nothing in the way: the tail node net1, the drains ap and an, and the charge the gates take from the plates. The sources reach the plates' +* level of the first decision, vg = 0.742 V (VDP 0.739 V and VDN 0.745 V in sar_off_base.cir), along vg (1 - exp(-t / tp)) with tp = 14 ns: the tracking switch of the golden deck settles the +* plates in that time, and net1, which floats in the clock's low phase and is charged by the pair's subthreshold current from the drains, is where that history leaves it at the edge: +* 0.654 V here at 97.6 ns, 0.659 V in sar_off_base.cir at 98 ns (read from its x3.x1.net1). Each gate's source is read through a zero-volt meter (VMP, VMN): its current is the gate current. +* Everything else is sar_off_base.cir's: supplies, the clks pulse of the sampling clock, the 4 fF loads on clkc, the comparator outputs, valid, ck1, a b c and clks; the first decision's +* clock edge comes 99.3 ns after the start (clkc crosses 0.1 V at 99.307 ns and 0.75 V at 103.118 ns in this deck, 103.102 ns in sar_off_base.cir with the plates moving). +* Paths are NOT in this file: IHP_PDK (the IHP-Open-PDK checkout, commit 21133f21), IHP_OSDI (the directory with the compiled psp103.osdi, psp103_nqs.osdi, r3_cmc.osdi, mosvar.osdi, +* cap_cmomi.osdi, cap_cmomf.osdi) and SAR_GOLDEN_SUBCKTS, in the environment. Run: IHP_PDK= IHP_OSDI= SAR_GOLDEN_SUBCKTS= ngspice -b sar_kick_edge.cir (ngspice-47, seconds) +* It prints, between BEGIN wave and END wave, 67 rows at 0.1 ns from 97.8 ns to 104.4 ns (index k: time 97.8 ns + 0.1 ns k): the tail node n1 and the drain ap in volts, an +* (equal to ap to 1 uV: the plates are alike) and the charge the gate of VDP has taken from its source since 97.8 ns, in coulomb, qg = the integral of i(VMP) dt; and the crossing times tc01, tc075. +.param vg=0.742 +.param tp=14n +.lib $IHP_PDK/ihp-sg13g2/libs.tech/ngspice/models/cornerMOSlv.lib mos_tt +.lib $IHP_PDK/ihp-sg13g2/libs.tech/ngspice/models/cornerCAP.lib cap_typ +.include $SAR_GOLDEN_SUBCKTS +VDD4 vdda 0 1.5 +VDD6 vdd 0 1.5 +VDD1 vss 0 0 +V2 c 0 0 +V5 b 0 0 +V6 a 0 0 +VCLKS clks 0 PULSE(0 1.5 0n 2n 2n 80n 500n) +BPD vdpi 0 V = {vg}*(1-exp(-time/{tp})) +BND vdni 0 V = {vg}*(1-exp(-time/{tp})) +VMP vdpi vdp 0 +VMN vdni vdn 0 +x3 vocp vocn valid vdp vdn clkc vdd 0 dynamic_comparator_top +x7 ck3 ck11 ck7 ck2 ck6 ck10 ck1 ck9 ck5 ck8 ck4 vdd 0 vdd valid 0 clks SAR_logic +x4 vdd clkc 0 clks valid ck1 a b c clock_gen +C9 clkc 0 4f +C10 vocp 0 4f +C11 valid 0 4f +C12 vocn 0 4f +C13 clkc 0 4f +C14 clks 0 4f +C15 valid 0 4f +C16 ck1 0 4f +C17 a 0 4f +C18 b 0 4f +C19 c 0 4f +C20 clks 0 4f +C21 valid 0 4f +.options temp=50 +.options klu +.control +pre_osdi $IHP_OSDI/psp103.osdi +pre_osdi $IHP_OSDI/psp103_nqs.osdi +pre_osdi $IHP_OSDI/r3_cmc.osdi +pre_osdi $IHP_OSDI/mosvar.osdi +pre_osdi $IHP_OSDI/cap_cmomi.osdi +pre_osdi $IHP_OSDI/cap_cmomf.osdi +set num_threads=4 +tran 0.05n 107n +meas tran tc01 when v(clkc)=0.1 rise=1 +meas tran tc075 when v(clkc)=0.75 rise=1 +linearize v(x3.x1.net1) v(x3.x1.ap) v(x3.x1.an) i(vmp) +let qint = integ(i(vmp)) +let n1w = unitvec(67) +let apw = unitvec(67) +let anw = unitvec(67) +let qgw = unitvec(67) +let k = 0 +while k < 67 + let j = 1956 + 2*k + let n1w[k] = v(x3.x1.net1)[j] + let apw[k] = v(x3.x1.ap)[j] + let anw[k] = v(x3.x1.an)[j] + let qgw[k] = qint[j] - qint[1956] + let k = k + 1 +end +set numdgt=8 +set noprintscale +echo BEGIN wave +print n1w apw anw qgw +echo END wave +.endc +.end diff --git a/specs/analog/decks/sar_kick_qg.cir b/specs/analog/decks/sar_kick_qg.cir new file mode 100644 index 0000000000..93ebfe1f62 --- /dev/null +++ b/specs/analog/decks/sar_kick_qg.cir @@ -0,0 +1,66 @@ +The gate charge of the comparator's input device, bulk on ground, at 50 C: Q_G(Vg, Vs, Vd) on three gate levels, 25 x 25 each (M4e-kick, #10942) +* specs/analog/decks/sar_kick_qg.cir -- the input pair of the golden dynamic comparator (XM3, XM4: sg13_lv_nmos W 1.0 um, L 0.45 um, 36 in parallel) has its bulk on VSS and its source on the tail +* node, which sits 0.2 .. 0.7 V above ground while it falls at the clock edge; M3c's gate-charge table (psp103_q_tt.cir, TT_QG_N) is for the bulk tied to the source and 27 C. This deck is that +* recipe with the two things the comparator has: the bulk at 0 V and TEMP 50 (the golden deck's `.options temp=50`), and with the gate as a third axis. The gate sits at one of three levels, +* Vg = 0.742 V + (jg - 1) * 25 mV (jg = 0, 1, 2: 0.717, 0.742, 0.767 V; the plates of the first decision rest at 0.74 V and move by tens of millivolts), the SOURCE is on a staircase of 25 levels, +* Vs = ix * 31.25 mV, and the drain on 25 levels, Vd = iy * 62.5 mV; the index is jg * 625 + ix * 25 + iy. Each node of the grid is visited from ONE origin (Vg = 0.742 V, Vs = Vd = 0) for 10 ns +* and the bias returns to the origin for 10 ns, and the gate's terminal current at the end of the return step, against the one before the first jump, is the gate charge +* Q_G(Vg, Vs, Vd) - Q_G(0.742, 0, 0) of M3c's recipe: Q(B) - Q(A) = (i_A - i_return) dt (the gate current is a few pA at the origin, where the device conducts with Vds = 0, so no +* DC current needs subtracting). Because the origin is the same for the three levels, a difference of two levels is the charge a change of the gate moves. The unit and the offset are M3c's: +* one unit is Q / 500 fF in 2^-24 V (2.98e-20 C), entry = nint(2e12 * 2^24 * (Q(B) - Q(A))) + 2^21, for the one device (m = 1); the comparator's pair is 36 of them. +* Model: IHP-Open-PDK commit 21133f219b1a6da10d803e345761e77415ceff40, mos_tt (PSP 103.6), the OSDI models psp103.osdi and psp103_nqs.osdi compiled from the same commit. +* Paths are NOT in this file: ngspice reads IHP_PDK (the checkout) and IHP_OSDI (the directory of the compiled .osdi files). +* Run: IHP_PDK= IHP_OSDI= ngspice -b sar_kick_qg.cir (ngspice-47, seconds) +* It prints, between BEGIN qg and END qg, the 1875 entries, and between BEGIN cap_o and END cap_o the gate capacitances ngspice itself reports at one operating point (Vg 0.742, Vs 0.4, +* Vd 1.3, in aF) as a cross-check. +.lib $IHP_PDK/ihp-sg13g2/libs.tech/ngspice/models/cornerMOSlv.lib mos_tt +.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 jgf() {floor(nd()/625)} +.func ixf() {floor((nd()-625*jgf())/25)} +.func iyf() {nd()-625*jgf()-25*ixf()} +BSN tsn 0 V = act()*0.03125*ixf() +BDN tdn 0 V = act()*0.0625*iyf() +BGN tgn 0 V = 0.742+act()*0.025*(jgf()-1) +VMGN tgn tgnn 0 +XTN tdn tgnn tsn 0 sg13_lv_nmos w=1.0u l=0.45u ng=1 m=1 +* a second copy at one fixed bias, for ngspice's own capacitances +VSO so 0 0.4 +VDO dO 0 1.3 +VGO go 0 0.742 +XMO dO go so 0 sg13_lv_nmos w=1.0u l=0.45u ng=1 m=1 +.options temp=50 +.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 +op +let c_gg = nint(@n.xmo.nsg13_lv_nmos[cgg] * 1e18) +let c_gsol = nint(@n.xmo.nsg13_lv_nmos[cgsol] * 1e18) +let c_gdol = nint(@n.xmo.nsg13_lv_nmos[cgdol] * 1e18) +echo BEGIN cap_o +print c_gg c_gsol c_gdol +echo END cap_o +tran 7.8125n 37.6u 0 10n +let g0 = i(vmgn)[8] +let qgn = unitvec(1875) +let tchk = abs(time[8] - 1e-8) +let k = 0 +while k < 1875 + let r = 2*k + 10 + let tchk = max(tchk, abs(time[r] - (2*k+3)*1e-8)) + let qgn[k] = nint((g0 - i(vmgn)[r]) * 1e-8 * 2e12 * 16777216) + 2097152 + let k = k + 1 +end +echo BEGIN qg +print qgn +echo END qg +echo BEGIN tchk +print tchk +echo END tchk +.endc +.end