-- File: [Thyme]System>CSIM01>spModels.mesa -- Last editted: -- SChen April 29, 1983 12:03 PM -- Wilhelm April 12, 1982 9:28 AM, reformated by Barth and stored under -- [Cherry]Thyme>1.97> . -- Details at end of file. DIRECTORY AltoDefs, Real, RealFns, spModelDefs; spModels: PROGRAM IMPORTS RealFns, spModelDefs = BEGIN modelError: SIGNAL[s: STRING] = CODE; -- Temporary square root kluge until RealFns is fixed. SingleReal: TYPE = RECORD[m2: CARDINAL, -- Backwards!!!! sign: BOOLEAN, exp: [0..256), m1: [0..128)]; SquareReal: TYPE = RECORD[m2: CARDINAL, -- Backwards!!!! sign: BOOLEAN, expD2: [0..128), index: [0..16), m1: [0..16)]; guesses: ARRAY[0..16) OF REAL; SqRt: PROCEDURE[x: REAL] RETURNS[y: REAL] = BEGIN xFmt: SquareReal; yFmt: SingleReal; IF x < 0.0 THEN SIGNAL modelError["SqRt of non-positive"]; xFmt _ LOOPHOLE[x, SquareReal]; yFmt _ LOOPHOLE[guesses[xFmt.index], SingleReal]; yFmt.exp _ yFmt.exp + xFmt.expD2 - 63; y _ LOOPHOLE[yFmt, REAL]; y _ LOOPHOLE[LOOPHOLE[y + x/y, LONG CARDINAL] - 40000000B, REAL]; y _ LOOPHOLE[LOOPHOLE[y + x/y, LONG CARDINAL] - 40000000B, REAL]; END; initSqRt: PROCEDURE = BEGIN i: CARDINAL; x1, x2: REAL; xFmt: SquareReal; FOR i IN [0..16) DO xFmt _ [0, FALSE, 63, i, 0]; x1 _ LOOPHOLE[xFmt, REAL]; IF i < 15 THEN xFmt _ [0, FALSE, 63, i + 1, 0] ELSE xFmt _ [0, FALSE, 64, 0, 0]; x2 _ LOOPHOLE[xFmt, REAL]; guesses[i] _ 2.0*(RealFns.SqRt[x1]*x2 - RealFns.SqRt[x2]*x1)/(x2-x1) ENDLOOP END; NFET: spModelDefs.model = BEGIN VgX: CARDINAL = 0; VsX: CARDINAL = 1; VdX: CARDINAL = 2; VbX: CARDINAL = 3; VtX: CARDINAL = 0; hKp: CARDINAL = 1; Phi2: CARDINAL = 2; Phi2fb: CARDINAL = 3; Kb: CARDINAL = 4; ftKb: CARDINAL = 5; hKbsq: CARDINAL = 6; qKbsq: CARDINAL = 7; Vfb: CARDINAL = 8; Cox: CARDINAL = 9; Cgsd0: CARDINAL = 10; Cgsdp: CARDINAL = 11; Ioff: CARDINAL = 12; Io: CARDINAL = 13; kTq: CARDINAL = 14; expMax: CARDINAL = 15; IdX: CARDINAL = 0; CgbX: CARDINAL = 1; CgsX: CARDINAL = 2; CgdX: CARDINAL = 3; Vg, Vs, Vd, Vb, Id: REAL; Cgs, Cgd: REAL; Vt, Vgst, Vgdt, VdSAT, Vsbphi2, Vdx, SqrtV: REAL; t1, t2: REAL; reverse: BOOLEAN _ FALSE; Vg _ args[VgX]; Vb _ args[VbX]; Vd _ args[VdX]; Vs _ args[VsX]; t1 _ Vb - Vs; IF t1 > 0.0 THEN BEGIN t1 _ t1/parms[kTq]; IF t1 >= parms[expMax] THEN SIGNAL spModelDefs.Retreat["NFET -- Source."]; results[4] _ parms[Io]*(RealFns.Exp[t1] - 1.0) END ELSE results[4] _ -parms[Io]; t2 _ Vb - Vd; IF t2 > 0.0 THEN BEGIN t2 _ t2/parms[kTq]; IF t2 >= parms[expMax] THEN SIGNAL spModelDefs.Retreat["NFET -- Drain."]; results[5] _ parms[Io]*(RealFns.Exp[t2] - 1.0) END ELSE results[5] _ -parms[Io]; IF Vs > Vd THEN BEGIN reverse _ TRUE; t1 _ Vs; Vs _ Vd; Vd _ t1 END; Vsbphi2 _ MAX[Vs - Vb + parms[Phi2], 0.0]; SqrtV _ SqRt[MAX[0.0, parms[qKbsq] + Vg - parms[Vfb] - Vb]]; Vt _ IF Vs = Vb THEN parms[VtX] ELSE parms[Phi2fb] + parms[Kb]*SqRt[Vsbphi2]; Vgst _ Vg - Vs - Vt; IF Vgst > 0 THEN BEGIN VdSAT _ Vg - parms[Phi2fb] + parms[hKbsq] - parms[Kb]*SqrtV; IF VdSAT < Vs THEN SIGNAL modelError["Negative VdSAT"]; Vdx _ IF Vd > VdSAT THEN VdSAT ELSE Vd; t1 _ Vsbphi2*SqRt[Vsbphi2]; t2 _ Vdx - Vb + parms[Phi2]; t2 _ t2*SqRt[t2]; Id _ parms[hKp]*((2.0*(Vg - parms[Phi2fb]) - Vs - Vdx)* (Vdx - Vs) + parms[ftKb]*(t1 - t2)) END ELSE Id _ parms[Ioff]; IF Id < 0.0 THEN IF Id < -parms[Ioff]THEN SIGNAL modelError["Negative drain current"] ELSE Id _ parms[Ioff]; t1 _ Vg - Vb - parms[Vfb]; IF t1 <= 0.0 THEN results[CgbX] _ parms[Cox] ELSE results[CgbX] _ 0.5*parms[Kb]*parms[Cox]/SqrtV; Vgdt _ Vg - Vd - Vt; t1 _ Vgst + Vgdt; t1 _ t1*t1; IF Vgst <= 0.0 THEN Cgs _ parms[Cgsdp] ELSE IF Vgdt < 0.0 THEN Cgs _ parms[Cgsd0] + parms[Cgsdp] ELSE Cgs _ parms[Cgsdp] + parms[Cgsd0]*(1.0 - Vgdt*Vgdt/t1); IF Vgdt <= 0.0 THEN Cgd _ parms[Cgsdp] ELSE Cgd _ parms[Cgsdp] + parms[Cgsd0]*(1.0 - Vgst*Vgst/t1); IF reverse THEN BEGIN results[IdX] _ -Id; results[CgsX] _ Cgd; results[CgdX] _ Cgs END ELSE BEGIN results[IdX] _ Id; results[CgsX] _ Cgs; results[CgdX] _ Cgd END END; PFET: spModelDefs.model = BEGIN VgX: CARDINAL = 0; VsX: CARDINAL = 1; VdX: CARDINAL = 2; VbX: CARDINAL = 3; VtX: CARDINAL = 0; hKp: CARDINAL = 1; Phi2: CARDINAL = 2; Phi2fb: CARDINAL = 3; Kb : CARDINAL = 4; ftKb: CARDINAL = 5; hKbsq: CARDINAL = 6; qKbsq: CARDINAL = 7; Vfb: CARDINAL = 8; Cox: CARDINAL = 9; Cgsd0: CARDINAL = 10; Cgsdp: CARDINAL = 11; Ioff: CARDINAL = 12; Io: CARDINAL = 13; kTq: CARDINAL = 14; expMax: CARDINAL = 15; IdX: CARDINAL = 0; CgbX: CARDINAL = 1; CgsX: CARDINAL = 2; CgdX: CARDINAL = 3; Vg, Vs, Vd, Vb, Id: REAL; Cgs, Cgd: REAL; Vt, Vgst, Vgdt, VdSAT, Vsbphi2, Vdx, SqrtV: REAL; t1, t2: REAL; reverse: BOOLEAN _ FALSE; Vg _ args[VgX]; Vb _ args[VbX]; Vd _ args[VdX]; Vs _ args[VsX]; t1 _ Vs - Vb; IF t1 > 0.0 THEN BEGIN t1 _ t1/parms[kTq]; IF t1 >= parms[expMax] THEN SIGNAL spModelDefs.Retreat["PFET -- Source."]; results[4] _ parms[Io]*(RealFns.Exp[t1] - 1.0) END ELSE results[4] _ -parms[Io]; t2 _ Vd - Vb; IF t2 > 0.0 THEN BEGIN t2 _ t2/parms[kTq]; IF t2 >= parms[expMax] THEN SIGNAL spModelDefs.Retreat["PFET -- Drain."]; results[5] _ parms[Io]*(RealFns.Exp[t2] - 1.0) END ELSE results[5] _ -parms[Io]; IF Vs < Vd THEN BEGIN reverse _ TRUE; t1 _ Vs; Vs _ Vd; Vd _ t1 END; Vsbphi2 _ MIN[Vs - Vb + parms[Phi2], 0.0]; SqrtV _ SqRt[-MIN[0.0, -parms[qKbsq] + Vg - parms[Vfb] - Vb]]; Vt _ IF Vs = Vb THEN parms[VtX] ELSE parms[Phi2fb] - parms[Kb]*SqRt[-Vsbphi2]; Vgst _ Vg - Vs - Vt; IF Vgst < 0 THEN BEGIN VdSAT _ Vg - parms[Phi2fb] - parms[hKbsq] + parms[Kb]*SqrtV; IF VdSAT > Vs THEN SIGNAL modelError["Positive VdSAT"]; Vdx _ IF Vd < VdSAT THEN VdSAT ELSE Vd; t1 _ Vsbphi2*SqRt[-Vsbphi2]; t2 _ Vdx - Vb + parms[Phi2]; t2 _ t2*SqRt[-t2]; Id _ parms[hKp]*((2.0*(Vg - parms[Phi2fb]) - Vs - Vdx)* (Vdx - Vs) - parms[ftKb]*(t1 - t2)) END ELSE Id _ parms[Ioff]; IF Id < 0.0 THEN IF Id < -parms[Ioff]THEN SIGNAL modelError["Negative drain current"] ELSE Id _ parms[Ioff]; t1 _ Vg - Vb - parms[Vfb]; IF t1 >= 0.0 THEN results[CgbX] _ parms[Cox] ELSE results[CgbX] _ 0.5*parms[Kb]*parms[Cox]/SqrtV; Vgdt _ Vg - Vd - Vt; t1 _ Vgst + Vgdt; t1 _ t1*t1; IF Vgst >= 0.0 THEN Cgs _ parms[Cgsdp] ELSE IF Vgdt > 0.0 THEN Cgs _ parms[Cgsd0] + parms[Cgsdp] ELSE Cgs _ parms[Cgsdp] + parms[Cgsd0]*(1.0 - Vgdt*Vgdt/t1); IF Vgdt >= 0.0 THEN Cgd _ parms[Cgsdp] ELSE Cgd _ parms[Cgsdp] + parms[Cgsd0]*(1.0 - Vgst*Vgst/t1); IF reverse THEN BEGIN results[IdX] _ -Id; results[CgsX] _ Cgd; results[CgdX] _ Cgs END ELSE BEGIN results[IdX] _ Id; results[CgsX] _ Cgs; results[CgdX] _ Cgd END END; XMOS: spModelDefs.model = BEGIN VgX: CARDINAL = 0; VsX: CARDINAL = 1; VdX: CARDINAL = 2; VbX: CARDINAL = 3; Beta0: CARDINAL = 0; Theta0: CARDINAL = 1; Vth0: CARDINAL = 2; v1: CARDINAL = 3; v2: CARDINAL = 4; TwoPhi: CARDINAL = 5; sq2Phi: CARDINAL = 6; A: CARDINAL = 7; Az: CARDINAL = 8; B: CARDINAL = 9; Bz: CARDINAL = 10; C0: CARDINAL = 11; C0z: CARDINAL = 12; C1: CARDINAL = 13; C2: CARDINAL = 14; Cox: CARDINAL = 15; Cgxp: CARDINAL = 16; Cgx0: CARDINAL = 17; Cdep: CARDINAL = 18; Vfb: CARDINAL = 19; Io: CARDINAL = 20; kTq: CARDINAL = 21; expMax: CARDINAL = 22; leak: CARDINAL = 23; IdX: CARDINAL = 0; CgbX: CARDINAL = 1; CgsX: CARDINAL = 2; CgdX: CARDINAL = 3; Sjunc: CARDINAL = 4; Djunc: CARDINAL = 5; reverse: BOOLEAN _ FALSE; Vg, Vs, Vd, Vb, Id: REAL; Vds, Vth, Vgsth, VdsSAT, beta, IdSAT, At, As, z: REAL; Cgs, Cgd, RCdep, V1, V2, Fs, Fd: REAL; t1, t2: REAL; Vg _ args[VgX]; Vb _ args[VbX]; Vd _ args[VdX]; Vs _ args[VsX]; t1 _ Vb - Vs; IF t1 >= 0.0 THEN BEGIN t1 _ t1/parms[kTq]; IF t1 >= parms[expMax] THEN SIGNAL spModelDefs.Retreat["XMOS -- Source."]; results[Sjunc] _ parms[Io]*(RealFns.Exp[t1] - 1.0) END ELSE results[Sjunc] _ -parms[Io]; t2 _ Vb - Vd; IF t2 >= 0.0 THEN BEGIN t2 _ t2/parms[kTq]; IF t2 >= parms[expMax] THEN SIGNAL spModelDefs.Retreat["XMOS -- Drain."]; results[Djunc] _ parms[Io]*(RealFns.Exp[t2] - 1.0) END ELSE results[Djunc] _ -parms[Io]; IF Vs > Vd THEN BEGIN reverse _ TRUE; t1 _ Vs; Vs _ Vd; Vd _ t1 END; Vds _ Vd - Vs; z _ SqRt[Vs - Vb + TwoPhi]; t1 _ z - parms[sq2Phi]; Vth _ parms[Vth0] + (parms[v1] + parms[v2]*t1)*t1; Vgsth _ Vg - Vs - Vth; V1 _ Vgsth + 0.5*(Vth - parms[Vfb]); IF Vgsth > 0.0 THEN BEGIN At _ parms[A] + parms[Az]/z + (parms[B] + parms[Bz]/z)*Vgsth; VdsSAT _ Vgsth/At; beta _ parms[Beta0]/(1.0 + parms[Theta0]*Vgsth); IF Vds > VdsSAT THEN BEGIN IdSAT _ 0.5*beta*At*VdsSAT*VdsSAT; As _ 1.0/SqRt[parms[C0] + parms[C0z]/z + (parms[C1] + parms[C2]*IdSAT)*IdSAT]; Id _ IdSAT/(1.0 - As*SqRt[Vds - VdsSAT]) END ELSE Id _ beta*Vds*(Vgsth - 0.5*At*Vds); IF V1 > Vds THEN BEGIN t1 _ 2.0*V1 - Vds; t1 _ t1*t1; Fs _ V1*(3.0*V1 - 2.0*Vds)/t1; t2 _ V1 - Vds; Fd _ 3.0*t2*t2/t1; V2 _ Vth - parms[Vfb] + 0.5*Vds + Vs - Vb END ELSE BEGIN Fs _ 1.0; Fd _ 0.0; V2 _ Vth - parms[Vfb] + 0.5*V1 + Vs - Vb END END ELSE BEGIN Fs _ IF V1 < 0.0 THEN 0.0 ELSE 2.0*V1/(Vth - parms[Vfb]); Fd _ 0.0; V2 _ IF V1 > 0.0 THEN IF V1 > Vds THEN V1 + 0.5*(Vth - parms[Vfb] + Vds) + Vs - Vb ELSE Vds + 0.5*(Vth - parms[Vfb] + Vds) + Vs - Vb ELSE IF Vg - Vb < parms[Vfb] THEN 0.0 ELSE Vg - Vb - parms[Vfb]; Id _ parms[Io] + parms[leak]*Vds END; Cgs _ Fs*parms[Cgx0]; Cgd _ Fd*parms[CgdX]; t1 _ Cox - Cgs - Cgd; IF t1 <= 0.0 THEN modelError["Bulk capacitance -- XMOS"]; RCdep _ SqRt[V2]/parms[Cdep]; results[CgbX] _ t1/(1.0 + RCdep*t1); IF reverse THEN BEGIN results[IdX] _ -Id; results[CgsX] _ Cgd; results[CgdX] _ Cgs END ELSE BEGIN results[IdX] _ Id; results[CgsX] _ Cgs; results[CgdX] _ Cgd END END; dcDiode: spModelDefs.model = BEGIN Vd, e: REAL; Va: CARDINAL = 0; Vc: CARDINAL = 1; Io: CARDINAL = 0; kTq: CARDINAL = 1; expMax: CARDINAL = 2; Vd _ args[Va] - args[Vc]; IF Vd + parms[kTq] <= 0.0 THEN results[0] _ -parms[Io] ELSE BEGIN e _ Vd/parms[kTq]; IF e >= parms[expMax] THEN SIGNAL spModelDefs.Retreat["dcDiode."]; results[0] _ parms[Io]*(RealFns.Exp[e] - 1.0) END END; CSIM: spModelDefs.model= BEGIN -- args VgX: CARDINAL= 0; VsX: CARDINAL= 1; VdX: CARDINAL= 2; VbX: CARDINAL= 3; -- parms vfb: CARDINAL= 0; twoPhiF: CARDINAL= 1; k1: CARDINAL= 2; k2: CARDINAL= 3; eta: CARDINAL= 4; beta0: CARDINAL= 5; u0: CARDINAL= 6; u1: CARDINAL= 7; -- above are the 8 electrical parameters of CSIM model -- cf. Scharfetter's memo of 12/30/82. MCgbo: CARDINAL= 8; Cgbo23rds: CARDINAL= 9; Cov: CARDINAL= 10; Cbso: CARDINAL= 11; Cbdo: CARDINAL= 12; phiB: CARDINAL= 13; -- above 6 parameters are used for capacitances calculation. -- cf. MOSAID model by Dick Foss Ios: CARDINAL= 14; Iod: CARDINAL= 15; kTq: CARDINAL= 16; expMax: CARDINAL= 17; NoCap: CARDINAL= 18; nChannel: CARDINAL= 19; -- -1: pType; else nType; -- results IdX : CARDINAL= 0; CgbX: CARDINAL= 1; CgsX: CARDINAL= 2; CgdX: CARDINAL= 3; CbsX: CARDINAL= 4; CbdX: CARDINAL= 5; Ibs: CARDINAL= 6; Ibd: CARDINAL= 7; Vg, Vs, Vd, Vb, Vds, Vgs, Vbs, Vbd: REAL; Id, Cgs, Cgd, Cbs, Cbd: REAL; reverse: BOOLEAN_ FALSE; t1, TwoPhiFMVbs, Sqrt2PhiFMVbs, EtaVds, VgsMVth, VgdMVth, Vth: REAL; IF parms[nChannel]= -1 THEN {Vg_ -args[VgX]; Vb_ -args[VbX]; Vd_ -args[VdX]; Vs_ -args[VsX]} ELSE {parms[nChannel]_ 1; Vg_ args[VgX]; Vb_ args[VbX]; Vd_ args[VdX]; Vs_ args[VsX]}; -- get Ibs IF Vb > Vs THEN BEGIN t1_ (Vb-Vs)/parms[kTq]; IF t1 >= parms[expMax] THEN SIGNAL spModelDefs.Retreat[ "CSIM -> Vbs forward biased too much"]; results[Ibs]_ parms[nChannel]*parms[Ios]*(RealFns.Exp[t1]- 1.0); END ELSE results[Ibs]_ -parms[nChannel]*parms[Ios]; -- get Ibd IF Vb > Vd THEN BEGIN t1_ (Vb-Vd)/parms[kTq]; IF t1 >= parms[expMax] THEN SIGNAL spModelDefs.Retreat[ "CSIM -> Vbd forward biased too much"]; results[Ibd]_ parms[nChannel]*parms[Iod]*(RealFns.Exp[t1]- 1.0); END ELSE results[Ibd]_ -parms[nChannel]*parms[Iod]; IF Vs > Vd THEN {reverse_ TRUE; t1_ Vs; Vs_ Vd; Vd_ t1}; Vds_ Vd - Vs; Vgs_ Vg - Vs; Vbs_ Vb - Vs; Vbd_ Vb - Vd; -- if it ever reaches here, Vbs must be less than 2phif. -- cf. expMax calculation in ThymeBasics.thy TwoPhiFMVbs_ parms[twoPhiF]-Vbs; Sqrt2PhiFMVbs_ RealFns.SqRt[TwoPhiFMVbs]; EtaVds_ parms[eta]*Vds; Vth_ parms[vfb]+parms[twoPhiF]+parms[k1]*Sqrt2PhiFMVbs-EtaVds -parms[k2]*TwoPhiFMVbs; VgsMVth_ Vgs - Vth; IF VgsMVth <= 0.0 THEN Id_ 0 ELSE BEGIN -- Vgs>Vth: g: REAL_ 1.0-1.0/(1.744+0.8364*TwoPhiFMVbs); a: REAL_ 1.0 + 0.5*g*parms[k1]/Sqrt2PhiFMVbs; alpha: REAL_ a*(1.0 + parms[u1]*VgsMVth); -- a(1+u1*(Vgs-Vth)) VdSat: REAL_ VgsMVth/alpha; BetaP: REAL_ parms[nChannel]*parms[beta0] /(1.0+parms[u0]*VgsMVth); -- beta0/(1+u0(Vgs-Vth)) Id_ IF VdsVth IF parms[NoCap]#0 THEN { results[CgbX]_ results[CgsX]_ results[CgdX]_ results[CbsX]_ results[CbdX]_ 0; results[IdX]_ IF reverse THEN -Id ELSE Id; RETURN}; VgdMVth_ Vg - Vd - Vth; -- Cgb: results[CgbX]_ IF VgsMVth <= 0 THEN parms[MCgbo] ELSE 0; -- Cgs and Cgd: t1_ VgsMVth+VgdMVth; t1_ t1*t1; -- (Vgs + Vgd - 2Vth)^2 Cgs_ IF VgsMVth <= 0.0 THEN parms[Cov] ELSE IF VgdMVth <= 0.0 THEN parms[Cgbo23rds] + parms[Cov] ELSE parms[Cov] + parms[Cgbo23rds]*(1.0 - VgdMVth*VgdMVth/t1); Cgd_ IF VgdMVth <= 0.0 THEN parms[Cov] ELSE parms[Cov] + parms[Cgbo23rds]*(1.0 - VgsMVth*VgsMVth/t1); -- Cbs and Cbd -- as phiB>2phif, the following should never blow up. Cbs_ parms[Cbso]/SqRt[1.0 - Vbs/parms[phiB]]; Cbd_ parms[Cbdo]/SqRt[1.0 - Vbd/parms[phiB]]; IF reverse THEN BEGIN results[IdX] _ -Id; results[CgsX]_ Cgd; results[CgdX]_ Cgs; results[CbsX]_ Cbd; results[CbdX]_ Cbs; END ELSE BEGIN results[IdX] _ Id; results[CgsX]_ Cgs; results[CgdX]_ Cgd; results[CbsX]_ Cbs; results[CbdX]_ Cbd; END; END; -- CSIM acDiode: spModelDefs.model= BEGIN Vc: CARDINAL= 0; -- cathode voltage index Va: CARDINAL= 1; -- anode voltage index Co: CARDINAL= 0; Pb: CARDINAL= 1; Vt: CARDINAL= 2; Io: CARDINAL= 3; expMax: CARDINAL= 4; C: CARDINAL= 0; I: CARDINAL= 1; t1: REAL; V: REAL_ args[Va] - args[Vc]; IF V > 0 THEN BEGIN -- forward biased t1_ V/parms[Vt]; IF t1 >= parms[expMax] THEN SIGNAL spModelDefs.Retreat[ "acDiode forward biased too much"]; results[I]_ -parms[Io]*(RealFns.Exp[t1]- 1.0); END ELSE results[I]_ parms[Io]; results[C]_ parms[Co]/SqRt[1.0 - V/parms[Pb]]; END; -- acDiode initSqRt[]; spModelDefs.EnterModels["CSIM", CSIM, 4, 20, 8]; spModelDefs.EnterModels["acDiode", acDiode, 2, 5, 2]; spModelDefs.EnterModels["dcDiode", dcDiode, 2, 3, 1]; spModelDefs.EnterModels["NFET", NFET, 4, 16, 6]; spModelDefs.EnterModels["PFET", PFET, 4, 16, 6]; spModelDefs.EnterModels["XMOS", XMOS, 4, 24, 6]; END. 4/29/83:- original: [Cherry]Thyme>1.97>spModels.mesa changes: added and "enter"ed CSIM and acDiode model.