<> <> <> <> <> DIRECTORY Atom USING [PutPropOnList], IO USING [PutFR, PutR, real, rope], Rope USING [ROPE, Length, Substr], RealFns USING [Exp, SqRt], ThymeGlobals USING [argList, EnterModels, MakeStringNB, model, Retreat], ThymeGlobalsExtras USING [CombineInstancesProc, IsUsefulProc]; ThymeModels: CEDAR PROGRAM IMPORTS Atom, IO, RealFns, Rope, ThymeGlobals = BEGIN ModelError: SIGNAL[s: Rope.ROPE]= CODE; NFET: ThymeGlobals.model= { VgX: NAT= 0; VsX: NAT= 1; VdX: NAT= 2; VbX: NAT= 3; VtX: NAT= 0; hKp: NAT= 1; Phi2: NAT= 2; Phi2fb: NAT= 3; Kb: NAT= 4; ftKb: NAT= 5; hKbsq: NAT= 6; qKbsq: NAT= 7; Vfb: NAT= 8; Cox: NAT= 9; Cgsd0: NAT= 10; Cgsdp: NAT= 11; Ioff: NAT= 12; Io: NAT= 13; kTq: NAT= 14; expMax: NAT= 15; IdX: NAT= 0; CgbX: NAT= 1; CgsX: NAT= 2; CgdX: NAT= 3; Vg, Vs, Vd, Vb, Id: REAL; Cgs, Cgd: REAL; Vt, Vgst, Vgdt, VdSAT, Vsbphi2, Vdx, SqrtV: REAL; t1, t2: REAL; reverse: BOOL_ FALSE; Vg_ args[VgX]; Vb_ args[VbX]; Vd_ args[VdX]; Vs_ args[VsX]; t1_ Vb - Vs; IF t1 > 0.0 THEN { t1_ t1/parms[kTq]; IF t1 >= parms[expMax] THEN SIGNAL ThymeGlobals.Retreat["NFET -- Source."]; results[4]_ parms[Io]*(RealFns.Exp[t1] - 1.0); } ELSE results[4]_ -parms[Io]; t2_ Vb - Vd; IF t2 > 0.0 THEN { t2_ t2/parms[kTq]; IF t2 >= parms[expMax] THEN SIGNAL ThymeGlobals.Retreat["NFET -- Drain."]; results[5]_ parms[Io]*(RealFns.Exp[t2] - 1.0); } ELSE results[5]_ -parms[Io]; IF Vs > Vd THEN { reverse_ TRUE; t1_ Vs; Vs_ Vd; Vd_ t1; }; Vsbphi2_ MAX[Vs - Vb + parms[Phi2], 0.0]; SqrtV_ RealFns.SqRt[MAX[0.0, parms[qKbsq] + Vg - parms[Vfb] - Vb]]; Vt_ IF Vs= Vb THEN parms[VtX] ELSE parms[Phi2fb] + parms[Kb]*RealFns.SqRt[Vsbphi2]; Vgst_ Vg - Vs - Vt; IF Vgst > 0 THEN { 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*RealFns.SqRt[Vsbphi2]; t2_ Vdx - Vb + parms[Phi2]; t2_ t2*RealFns.SqRt[t2]; Id_ parms[hKp]*((2.0*(Vg - parms[Phi2fb]) - Vs - Vdx)* (Vdx - Vs) + parms[ftKb]*(t1 - t2)); } 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 { results[IdX] _ - Id; results[CgsX]_ Cgd; results[CgdX]_ Cgs; } ELSE { results[IdX] _ Id; results[CgsX]_ Cgs; results[CgdX]_ Cgd; }; }; -- NFET PFET: ThymeGlobals.model= { VgX: NAT= 0; VsX: NAT= 1; VdX: NAT= 2; VbX: NAT= 3; VtX: NAT= 0; hKp: NAT= 1; Phi2: NAT= 2; Phi2fb: NAT= 3; Kb: NAT= 4; ftKb: NAT= 5; hKbsq: NAT= 6; qKbsq: NAT= 7; Vfb: NAT= 8; Cox: NAT= 9; Cgsd0: NAT= 10; Cgsdp: NAT= 11; Ioff: NAT= 12; Io: NAT= 13; kTq: NAT= 14; expMax: NAT= 15; IdX: NAT= 0; CgbX: NAT= 1; CgsX: NAT= 2; CgdX: NAT= 3; Vg, Vs, Vd, Vb, Id: REAL; Cgs, Cgd: REAL; Vt, Vgst, Vgdt, VdSAT, Vsbphi2, Vdx, SqrtV: REAL; t1, t2: REAL; reverse: BOOL_ FALSE; Vg_ args[VgX]; Vb_ args[VbX]; Vd_ args[VdX]; Vs_ args[VsX]; t1_ Vs - Vb; IF t1 > 0.0 THEN { t1_ t1/parms[kTq]; IF t1 >= parms[expMax] THEN SIGNAL ThymeGlobals.Retreat["PFET -- Source."]; results[4]_ parms[Io]*(RealFns.Exp[t1] - 1.0); } ELSE results[4]_ -parms[Io]; t2_ Vd - Vb; IF t2 > 0.0 THEN { t2_ t2/parms[kTq]; IF t2 >= parms[expMax] THEN SIGNAL ThymeGlobals.Retreat["PFET -- Drain."]; results[5]_ parms[Io]*(RealFns.Exp[t2] - 1.0); } ELSE results[5]_ -parms[Io]; IF Vs < Vd THEN { reverse_ TRUE; t1_ Vs; Vs_ Vd; Vd_ t1; }; Vsbphi2_ MIN[Vs - Vb + parms[Phi2], 0.0]; SqrtV_ RealFns.SqRt[-MIN[0.0, -parms[qKbsq] + Vg - parms[Vfb] - Vb]]; Vt_ IF Vs= Vb THEN parms[VtX] ELSE parms[Phi2fb] - parms[Kb]*RealFns.SqRt[-Vsbphi2]; Vgst_ Vg - Vs - Vt; IF Vgst < 0 THEN { 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*RealFns.SqRt[-Vsbphi2]; t2_ Vdx - Vb + parms[Phi2]; t2_ t2*RealFns.SqRt[-t2]; Id_ parms[hKp]*((2.0*(Vg - parms[Phi2fb]) - Vs - Vdx)*(Vdx - Vs) - parms[ftKb]*(t1 - t2)); } 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 { results[IdX] _ -Id; results[CgsX]_ Cgd; results[CgdX]_ Cgs; } ELSE { results[IdX] _ Id; results[CgsX]_ Cgs; results[CgdX]_ Cgd; }; }; -- PFET DCDiode: ThymeGlobals.model= { Vd, e: REAL; Va: NAT= 0; Vc: NAT= 1; Io: NAT= 0; kTq: NAT= 1; expMax: NAT= 2; Vd_ args[Va] - args[Vc]; IF Vd + parms[kTq] <= 0.0 THEN results[0]_ -parms[Io] ELSE { e_ Vd/parms[kTq]; IF e >= parms[expMax] THEN SIGNAL ThymeGlobals.Retreat["DCDiode."]; results[0]_ parms[Io]*(RealFns.Exp[e] - 1.0); }; }; -- DCDiode CSIM: ThymeGlobals.model= { <> VgX: NAT= 0; VsX: NAT= 1; VdX: NAT= 2; VbX: NAT= 3; <> vfb: NAT= 0; twoPhiF: NAT= 1; k1: NAT= 2; k2: NAT= 3; eta: NAT= 4; beta0: NAT= 5; u0: NAT= 6; u1: NAT= 7; <> MCgbo: NAT= 8; Cgbo23rds: NAT= 9; Cov: NAT= 10; Cbso: NAT= 11; Cbdo: NAT= 12; phiB: NAT= 13; <> Ios: NAT= 14; Iod: NAT= 15; kTq: NAT= 16; expMax: NAT= 17; NoCap: NAT= 18; nChannel: NAT= 19; -- -1: pType; else nType; <> IdX : NAT= 0; CgbX: NAT= 1; CgsX: NAT= 2; CgdX: NAT= 3; CbsX: NAT= 4; CbdX: NAT= 5; Ibs: NAT= 6; Ibd: NAT= 7; Vg, Vs, Vd, Vb, Vds, Vgs, Vbs, Vbd: REAL; Id, Cgs, Cgd, Cbs, Cbd: REAL; reverse: BOOL_ FALSE; t1, TwoPhiFMVbs, Sqrt2PhiFMVbs, EtaVds, VgsMVth, VgdMVth, Vth: REAL; ArgRope: PROC [ix: NAT] RETURNS [r: Rope.ROPE] = { voltage: Rope.ROPE = IO.PutR[IO.real[args[ix]]]; r _ IO.PutFR["%g (%g V)", IO.rope[ThymeGlobals.MakeStringNB[ handle: parms.handle, n: parms.modFunc.arguments[ix], b: NIL]], IO.rope[Rope.Substr[base: voltage, len: MIN[voltage.Length, 5]]]]; }; -- ArgRope 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]; }; <> IF Vb > Vs THEN { t1_ (Vb-Vs)/parms[kTq]; IF t1 > parms[expMax] THEN SIGNAL ThymeGlobals.Retreat[ IO.PutFR["CSIM -> Vbs forward biased too much: b = %g, s = %g", IO.rope[ArgRope[VbX]], IO.rope[ArgRope[VsX]]]]; <= parms[twoPhiF] THEN {>> <> <> <<};>> results[Ibs]_ parms[nChannel]*parms[Ios]*(RealFns.Exp[t1]- 1.0); } ELSE results[Ibs]_ -parms[nChannel]*parms[Ios]; <> IF Vb > Vd THEN { t1_ (Vb-Vd)/parms[kTq]; IF t1 > parms[expMax] THEN SIGNAL ThymeGlobals.Retreat[ IO.PutFR["CSIM -> Vbd forward biased too much: b = %g, d = %g", IO.rope[ArgRope[VbX]], IO.rope[ArgRope[VdX]]]]; results[Ibd]_ parms[nChannel]*parms[Iod]*(RealFns.Exp[t1]- 1.0); } 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; <> 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 { -- 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; <> results[CgbX]_ IF VgsMVth <= 0 THEN parms[MCgbo] ELSE 0; <> 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); <2phif, the following should never blow up.>> Cbs_ parms[Cbso]/RealFns.SqRt[1.0 - Vbs/parms[phiB]]; Cbd_ parms[Cbdo]/RealFns.SqRt[1.0 - Vbd/parms[phiB]]; IF reverse THEN { results[IdX]_ -Id; results[CgsX]_ Cgd; results[CgdX]_ Cgs; results[CbsX]_ Cbd; results[CbdX]_ Cbs; } ELSE { results[IdX]_ Id; results[CgsX]_ Cgs; results[CgdX]_ Cgd; results[CbsX]_ Cbs; results[CbdX]_ Cbd; }; }; -- CSIM ACDiode: ThymeGlobals.model= { Vc: NAT= 0; -- cathode voltage index Va: NAT= 1; -- anode voltage index Co: NAT= 0; Pb: NAT= 1; Vt: NAT= 2; Io: NAT= 3; expMax: NAT= 4; C: NAT= 0; I: NAT= 1; t1: REAL; V: REAL_ args[Va] - args[Vc]; IF V > 0 THEN { -- forward biased t1_ V/parms[Vt]; IF t1 >= parms[expMax] THEN SIGNAL ThymeGlobals.Retreat[ "ACDiode forward biased too much"]; results[I]_ -parms[Io]*(RealFns.Exp[t1]- 1.0); } ELSE results[I]_ parms[Io]; results[C]_ parms[Co]/RealFns.SqRt[1.0 - V/parms[Pb]]; }; -- ACDiode ACDiodeIsUseful: PROC [parms: ThymeGlobals.argList] RETURNS [isUseful: BOOL] = { Co: NAT= 0; Pb: NAT= 1; Vt: NAT= 2; Io: NAT= 3; expMax: NAT= 4; isUseful _ parms[Co]#0 OR parms[Io]#0; }; -- ACDiodeIsUseful ACDiodeCombineInstances: PROC [parmsA, parmsB: ThymeGlobals.argList] RETURNS [ success: BOOL ] = { Co: NAT= 0; Pb: NAT= 1; Vt: NAT= 2; Io: NAT= 3; expMax: NAT= 4; IF (success _ (parmsA[Pb] = parmsB[Pb] AND parmsA[Vt] = parmsB[Vt] AND parmsA[expMax] = parmsB[expMax])) THEN { parmsA[Co] _ parmsA[Co]+parmsB[Co]; parmsA[Io] _ parmsA[Io]+parmsB[Io]; }; }; -- ACDiodeCombineInstances ThymeGlobals.EnterModels[["CSIM", CSIM, 4, 20, 8]]; ThymeGlobals.EnterModels[["ACDiode", ACDiode, 2, 5, 2, Atom.PutPropOnList[ Atom.PutPropOnList[NIL, $IsUsefulProc, NEW[ThymeGlobalsExtras.IsUsefulProc _ ACDiodeIsUseful]], $CombineInstancesProc, NEW[ThymeGlobalsExtras.CombineInstancesProc _ ACDiodeCombineInstances]]]]; ThymeGlobals.EnterModels[["DCDiode", DCDiode, 2, 3, 1]]; ThymeGlobals.EnterModels[["NFET", NFET, 4, 16, 6]]; ThymeGlobals.EnterModels[["PFET", PFET, 4, 16, 6]]; END. CHANGE LOG Wilhelm, April 12, 1982 9:28 AM Barth, 7-May-82 10:43:16 PDT Chen, April 29, 1983 12:03 PM, added and "enter"ed CSIM and ACDiode model. Chen, June 7, 1984 8:14:49 pm PDT, cedarized. McCreight, April 2, 1985 5:04:05 pm PST, 1. added ACDiodeIsUseful, ACDiodeCombineInstances, and related stuff. 2. added more information for the user when bs or bd junctions are forward biased too much. Chen, May 9, 1985 6:21:28 pm PDT, RealOps.SqRt => RealFns.SqRt . Chen, July 22, 1985 8:09:51 pm PDT, => Cedar6.0.