DIRECTORY Atom USING [GetProp, PutProp, PutPropOnList], BSimModel, IO USING [int, PutR, PutF, PutFR, real, rope, STREAM], Process USING [Yield], Real USING [RoundLI], RealFns USING [Exp, SqRt], Rope USING [Length, ROPE, Substr], spGlobals USING [argList, EnterModels, makeStringNB, RefModBody, ModelBody, Retreat], spGlobalsExtras USING [CombineInstancesProc, IsUsefulProc]; BSimModelImplEval: CEDAR PROGRAM IMPORTS Atom, BSimModel, IO, Process, Real, RealFns, Rope, spGlobals = BEGIN MCgbo: NAT= 22; Cgbo23rds: NAT= 23; maxFwdBias: NAT=24; NoCap: NAT= 25; nChannel: NAT= 26; -- -1: pType; else nType; BSim: PROC [args, oldArgs, parms, results: spGlobals.argList] -- spGlobals.model -- = { VgX: NAT= 0; -- arguments VsX: NAT= 1; VdX: NAT= 2; VbX: NAT= 3; IdX : NAT= 0; CgbX: NAT= 1; CgsX: NAT= 2; CgdX: NAT= 3; Vg, Vs, Vd, Vb, Vds, Vgs, Vbs, Vbd: REAL; Vth, VgsMVth, Id: REAL; Cgs, Cgd: REAL _ 0.0; Vdd: REAL = parms[BSimModel.vdd]; reverse: BOOL_ FALSE; realTwoPhiFMVbs, sqrt2PhiFMVbs, TwoPhiFMVbs: REAL; IF parms[nChannel]= -1 THEN { Vg_ -args[VgX]; Vb_ -args[VbX]; Vd_ -args[VdX]; Vs_ -args[VsX]} ELSE { Vg_ args[VgX]; Vb_ args[VbX]; Vd_ args[VdX]; Vs_ args[VsX]}; IF Vs > Vd THEN {t1: REAL = Vs; Vs_ Vd; Vd_ t1; reverse_ TRUE}; Vds_ Vd - Vs; Vgs_ Vg - Vs; Vbs_ Vb - Vs; Vbd_ Vb - Vd; realTwoPhiFMVbs _ parms[BSimModel.phif2]-Vbs; IF Vbs <= 0 THEN {TwoPhiFMVbs _ realTwoPhiFMVbs; sqrt2PhiFMVbs _ RealFns.SqRt[TwoPhiFMVbs]} ELSE {sqrt2PhiFMVbs _ RealFns.SqRt[parms[BSimModel.phif2]]/(1.0+0.5*Vbs/parms[BSimModel.phif2]); TwoPhiFMVbs _ sqrt2PhiFMVbs*sqrt2PhiFMVbs}; { VdsMVdd: REAL = Vds-Vdd; Eta: REAL = MAX[0.0, parms[BSimModel.eta]+parms[BSimModel.x2eta]*TwoPhiFMVbs+parms[BSimModel.x3eta]*VdsMVdd]; IF realTwoPhiFMVbs < 0.0 THEN WITH parms.modFunc.body SELECT FROM rm: spGlobals.RefModBody => { prevVbs: REAL = parms[nChannel]*(rm.oldArgVector[VbX]-rm.oldArgVector[(IF reverse THEN VdX ELSE VsX)]); IF Vbs > prevVbs+0.1 THEN SIGNAL spGlobals.Retreat[NIL]; }; ENDCASE => ERROR; IF realTwoPhiFMVbs < parms[maxFwdBias] THEN { parms[maxFwdBias] _ realTwoPhiFMVbs+0.1; -- don't complain again for another 100 mV parms.handle.msgStream.PutF["\nBSIM inaccurate because source(%g)-body(%g) diode is forward-biased to %d volts.\n", IO.rope[ArgRope[args, parms, IF reverse THEN VdX ELSE VsX]], IO.rope[ArgRope[args, parms, VbX]], IO.real[Vbs]]; Process.Yield[]; }; Vth _ parms[BSimModel.vfb]+parms[BSimModel.phif2]+parms[BSimModel.k1]*sqrt2PhiFMVbs -parms[BSimModel.k2]*TwoPhiFMVbs-Eta*Vds; -- calculate threshold voltage IF (VgsMVth _ MAX[0, Vgs - Vth]) <= 0.0 THEN Id _ 0.0 ELSE { -- Vgs>Vth: u: REAL = 1.0+MAX[0.0, parms[BSimModel.u0]+parms[BSimModel.x2u0]*Vbs]*VgsMVth; u1Sum: REAL = MAX[0.0, parms[BSimModel.u1]+parms[BSimModel.x2u1]*Vbs+parms[BSimModel.x3u1]*VdsMVdd]; temp: REAL = parms[BSimModel.beta0]+parms[BSimModel.x2beta0]*Vbs; -- calculate beta tempA: REAL = (parms[BSimModel.beta0sat]+parms[BSimModel.x2beta0sat]*Vbs)/temp-1.0; x3vddvdd: REAL = parms[BSimModel.x3beta0sat]*Vdd/temp - tempA; vRatio: REAL = Vds/Vdd; beta: REAL = temp*(1.0+(tempA-x3vddvdd*(1.0-vRatio))*vRatio); g: REAL = 1.0-1.0/(1.744+0.8364*TwoPhiFMVbs); -- calculate alpha alpha -- also known as a -- : REAL = 1.0+0.5*g*parms[BSimModel.k1]/sqrt2PhiFMVbs; VgsMVthOverAlpha: REAL = VgsMVth/alpha; vc: REAL = u1Sum*VgsMVthOverAlpha; k: REAL = 0.5*(1.0+vc+RealFns.SqRt[1.0+2.0*vc]); VdsSat: REAL = VgsMVthOverAlpha/RealFns.SqRt[k]; IdsDiff: REAL _ 0.0; -- subthreshold current IF parms[BSimModel.n0]#0 OR parms[BSimModel.x2nb]#0 OR parms[BSimModel.x3nd]#0 THEN { nSubThPar: REAL = parms[BSimModel.n0]+parms[BSimModel.x3nd]*Vds+parms[BSimModel.x2nb]*Vbs; Vtm: REAL = 0.0258512*parms[BSimModel.tempK]/300.0; VtmSq: REAL = Vtm*Vtm; IdsSubTh: REAL = VtmSq*RealFns.Exp[(1.0-RealFns.Exp[-Vds-Vtm])*(Vgs-Vth)/(Vtm*nSubThPar)+1.8]; IdsDiffLim: REAL = 4.5*VtmSq; IdsDiff _ IdsSubTh*IdsSubTh/(IdsSubTh+IdsDiffLim); }; Id _ parms[nChannel]*beta*((IF Vds < VdsSat THEN Vds*(VgsMVth - 0.5*alpha*Vds)/(u*(1.0+u1Sum*Vds)) ELSE VgsMVth*VgsMVth/(2.0*u*alpha*k))+IdsDiff); Id _ Id; -- for breakpoints }; -- end of Vgs>Vth }; --end of calculating Ids { VgdMVth: REAL; SELECT TRUE FROM parms[NoCap] # 0 => results[CgbX] _ 0.0; VgsMVth <= 0.0 => -- no channel results[CgbX]_ parms[MCgbo]; (VgdMVth _ Vg - Vd - Vth) <= 0.0 => -- partial channel (source inverted, drain not) BEGIN results[CgbX]_ 0.0; Cgs _ parms[Cgbo23rds]; Cgd _ 0; END; ENDCASE => -- channel complete (both source and drain inverted) BEGIN t1: REAL = VgsMVth+VgdMVth; t2: REAL = t1*t1; -- (Vgs + Vgd - 2Vth)^2 results[CgbX]_ 0.0; Cgs _ parms[Cgbo23rds]*(1.0 - VgdMVth*VgdMVth/t2); Cgd _ parms[Cgbo23rds]*(1.0 - VgsMVth*VgsMVth/t2); END; }; IF reverse THEN { results[IdX]_ -Id; results[CgsX]_ Cgd; results[CgdX]_ Cgs} ELSE { results[IdX]_ Id; results[CgsX]_ Cgs; results[CgdX]_ Cgd}; }; -- BSim oldBSimModelBody: spGlobals.RefModBody _ NIL; newBSimModelBody: spGlobals.RefModBody _ NIL; distinguishedBSimModelBody: spGlobals.RefModBody _ NIL; nFavorites: NAT = 50; Favorites: TYPE = RECORD [ p: SEQUENCE size: NAT OF REF BSimModel.ProcessParams]; BSimInit: PROC [args, oldArgs, parms, results: spGlobals.argList] -- spGlobals.model -- = { L: NAT = 0; -- parameter indices W: NAT = 1; DUTZRatio: NAT = 2; channelType: INT = Real.RoundLI[parms[nChannel]]; doTrap: BOOL _ FALSE; IF ~ channelType IN [-1..1] THEN { lMicrons, wMicrons, dutZRatio: REAL; lEff, wEff, cox, zRatio -- w/l -- : REAL; bsimpp: REF BSimModel.ProcessParams; processIndex: INT = ABS[channelType]; f: REF ANY; favorites: REF Favorites; IF (f _ Atom.GetProp[$BSimModel, $Favorites]) = NIL THEN Atom.PutProp[$BSimModel, $Favorites, (f _ NEW[Favorites[nFavorites]])]; favorites _ NARROW[f]; IF processIndex >= favorites.size OR (bsimpp _ favorites[processIndex]) = NIL THEN { bsimpp _ BSimModel.ReadProcessFile[IO.PutFR["/DATools/DATools6.1/Thyme/BSimProcess-%d.process", IO.int[ABS[channelType]]]]; IF processIndex IN [2..favorites.size) THEN favorites[processIndex] _ bsimpp; }; parms[nChannel] _ IF channelType<0 THEN -1 ELSE 1; lMicrons _ parms[L]; wMicrons _ parms[W]; doTrap _ parms[DUTZRatio]<0; dutZRatio _ (IF parms[DUTZRatio]>0 THEN parms[DUTZRatio] ELSE bsimpp.dutW/bsimpp.dutL); lEff _ lMicrons+bsimpp.params[BSimModel.beta0][2]; wEff _ wMicrons+bsimpp.params[BSimModel.beta0][3]; zRatio _ bsimpp.betaFudgeFactor*wEff/lEff; cox _ 3.9*8.854E-10/bsimpp.toxMicrons; -- farads/sq cm FOR i: INT IN [0..BSimModel.nBasicBSimParams) DO t: REAL = bsimpp.params[i][1]+(bsimpp.params[i][2]/lEff)+(bsimpp.params[i][3]/wEff); SELECT i FROM BSimModel.beta0 => parms[BSimModel.beta0] _ bsimpp.params[i][1]*zRatio*(IF bsimpp.params[BSimModel.beta0][1]<1.0 THEN 1.0/dutZRatio ELSE cox); BSimModel.x2beta0, BSimModel.beta0sat, BSimModel.x2beta0sat, BSimModel.x3beta0sat => parms[i] _ t*cox*zRatio; BSimModel.u1, BSimModel.x2u1, BSimModel.x3u1 => parms[i] _ t/lEff; BSimModel.n0, BSimModel.x2nb, BSimModel.x3nd => parms[i] _ (IF Atom.GetProp[$BSimModel, $TurnOffSubThresh] # NIL THEN 0 ELSE t); ENDCASE => parms[i] _ t; ENDLOOP; parms[BSimModel.tempK] _ bsimpp.tempC+273.15; parms[BSimModel.vdd] _ bsimpp.vddVolts; }; IF parms.modFunc.body # oldBSimModelBody THEN { oldBSimModelBody _ NARROW[parms.modFunc.body]; newBSimModelBody _ NEW[spGlobals.ModelBody _ NARROW[parms.modFunc.body, spGlobals.RefModBody]^]; distinguishedBSimModelBody _ NEW[spGlobals.ModelBody _ NARROW[parms.modFunc.body, spGlobals.RefModBody]^]; newBSimModelBody.modelProc _ BSim; distinguishedBSimModelBody.modelProc _ BSim -- or DistinguishedBSim -- ; }; IF doTrap THEN {parms.modFunc.body _ distinguishedBSimModelBody; BSim[args, oldArgs, parms, results]; } ELSE {parms.modFunc.body _ newBSimModelBody; BSim[args, oldArgs, parms, results]; }; }; Co: NAT= 0; -- zero-bias capacitance (farads) OneOverPhi0: NAT= 1; -- 1/built-in potential (=kT/2*ln[Na*Nd/(Ni*Ni)]) (1/volts) OneOverVT: NAT= 2; -- (1/volts) Io: NAT= 3; -- reverse current (amps, should be negative) VMax: NAT= 4; -- maximum forward bias (volts) SDDiode: PROC [args, oldArgs, parms, results: spGlobals.argList] -- spGlobals.model -- = { Vc: NAT= 0; -- cathode voltage arg index Va: NAT= 1; -- anode voltage arg index C: NAT= 0; -- results index I: NAT= 1; V: REAL _ args[Va] - args[Vc]; phiRatio: REAL = V*parms[OneOverPhi0]; IF V > 0 THEN { -- forward bias WITH parms.modFunc.body SELECT FROM rm: spGlobals.RefModBody => { IF V > rm.oldArgVector[Va]-rm.oldArgVector[Vc]+0.1 THEN SIGNAL spGlobals.Retreat[NIL]; }; ENDCASE => ERROR; IF V >= parms[VMax] THEN { parms[VMax] _ V+0.1; -- don't complain again for 100 mV parms.handle.msgStream.PutF["\nSource-drain diode (anode(%g), cathode(%g)) forward biased to %d volts.\n", IO.rope[ArgRope[args, parms, Va]], IO.rope[ArgRope[args, parms, Vc]], IO.real[V]]; Process.Yield[]; }; results[I] _ -parms[Io]*(RealFns.Exp[V*parms[OneOverVT]] - 1.0); results[C] _ parms[Co]*(IF phiRatio < 0.5 THEN 1.0/RealFns.SqRt[1.0 - phiRatio] ELSE 1.4142*(0.5+phiRatio) -- extrapolate linearly from V=Phi0/2 -- ) } ELSE { -- reverse bias results[I] _ parms[Io]; results[C] _ parms[Co]/RealFns.SqRt[1.0 - phiRatio]; }; }; -- SDDiode SDDiodeIsUseful: PROC [parms: spGlobals.argList] RETURNS [isUseful: BOOL] -- spGlobalsExtras.IsUsefulProc -- = { isUseful _ parms[Co]#0 OR parms[Io]#0; }; -- SDDiodeIsUseful SDDiodeCombineInstances: PROC [parmsA, parmsB: spGlobals.argList] RETURNS [success: BOOL] -- spGlobalsExtras.CombineInstancesProc -- = { IF (success _ (parmsA[OneOverPhi0] = parmsB[OneOverPhi0] AND parmsA[OneOverVT] = parmsB[OneOverVT] AND parmsA[VMax] = parmsB[VMax])) THEN { parmsA[Co] _ parmsA[Co] + parmsB[Co]; parmsA[Io] _ parmsA[Io] + parmsB[Io]; }; }; -- SDDiodeCombineInstances ArgRope: PROC [args, parms: spGlobals.argList, ix: NAT] RETURNS [r: Rope.ROPE] = { voltage: Rope.ROPE = IO.PutR[IO.real[args[ix]]]; r _ IO.PutFR["%g (%g V)", IO.rope[spGlobals.makeStringNB[ handle: parms.handle, n: parms.modFunc.arguments[ix], b: NIL]], IO.rope[Rope.Substr[base: voltage, len: MIN[voltage.Length, 5]]]]; Process.Yield[]; }; spGlobals.EnterModels[[name: "BSimFromFile", proc: BSimInit, numArgs: 4, numParms: 27, numResults: 4]]; spGlobals.EnterModels[[name: "BSim", proc: BSim, numArgs: 4, numParms: 27, numResults: 4]]; spGlobals.EnterModels[[ name: "SDDiode", proc: SDDiode, numArgs: 2, numParms: 5, numResults: 2, data: Atom.PutPropOnList[ propList: Atom.PutPropOnList[ propList: NIL, prop: $IsUsefulProc, val: NEW[spGlobalsExtras.IsUsefulProc _ SDDiodeIsUseful]], prop: $CombineInstancesProc, val: NEW[spGlobalsExtras.CombineInstancesProc _ SDDiodeCombineInstances]] ]]; END. CHANGE LOG. McCreight, May 13, 1985 4:22:00 pm PDT, created Chen, May 17, 1985 2:54:28 pm PDT, Real.SqRt -> RealFns.SqRt Chen, July 17, 1985 11:12:00 am PDT, recompiled in Cedar6.0. Christian Jacobi, June 10, 1986 7:16:09 pm PDT, Yield to avoid monopolizing cpu. ΆFile: BSimModelImplEval.mesa Copyright (C) 1985 by Xerox Corporation. All rights reserved. Last Edited by: Last Edited by: Jacobi June 10, 1986 7:17:27 pm PDT Curry, September 23, 1986 5:17:25 pm PDT Pradeep Sindhu March 19, 1986 9:44:46 pm PST McCreight, May 31, 1985 2:44:17 pm PDT Sweetsun Chen, July 22, 1985 8:14:02 pm PDT Christian Jacobi, June 10, 1986 7:15:54 pm PDT CSIM2 Parameters -- in addition to the ones in BSimModel capacitance parameters for MOSAID model. cf. MOSAID documentation by Dick Foss. other parameters: results: Invert voltages if transistor is p-type. Switch source and drain if biases are reversed Calculate Ids .. otherwise retreating won't do much good.. Calculate capacitances From this point on, refill the parms vector with calculated parameters as a function of lMicrons and wMicrons Don't call this procedure any more, go directly to BSim SDDiode parameters .. otherwise retreating won't do much good.. Κ θ˜JšΟcœ™J™>™Icode™3K™(K™,J™&K™+K™.—J˜šΟk ˜ Jšœžœ#˜-Jšœ ˜ Jšžœžœ&žœ˜6Jšœžœ ˜Jšœžœ ˜Jšœžœ ˜Jšœžœ žœ ˜"Jšœ žœF˜UJšœžœ&˜;J˜—š œžœžœžœžœ+˜gJ˜—Jšž˜J˜JšΠct8™8J™JšœO™OJšœžœ˜Jšœ žœ˜J˜Jšœ™Jšœ žœ˜Jšœžœ˜Jšœ žœ˜,J˜J˜šΟnœžœ4œ˜WJ˜Jšœžœ ˜Jšœžœ˜ Jšœžœ˜ Jšœžœ˜ J™Jšœ™Jšœžœ˜ Jšœžœ˜ Jšœžœ˜ Jšœžœ˜ J˜J˜Jšœ$žœ˜)Jšœžœ˜Jšœ žœ˜Jšœžœ˜!Jšœ žœžœ˜šœ-žœ˜2J˜—Jšœ(™(šžœžœ˜J˜ J˜—šžœ˜J˜J˜J˜—Jšœ.™.Jšžœ žœžœ žœ˜?J˜˜7J˜—Jšœ-˜-šžœ ž˜Jšœ˜Jšœ*˜*—šž˜Jšœ[˜[Jšœ+˜+J™—šœ ™ Jšœ˜Jšœ žœ ˜Jšœžœžœ^˜mJ˜šžœž˜šžœžœž˜#šœ˜Jš œ žœ:žœ žœžœ˜gšžœž˜Jšžœžœ˜Jšœ,™,—Jšœ˜—Jšžœžœ˜—J˜—šžœ%žœ˜-Jšœ)*˜Sšœs˜sšžœžœ žœžœ˜Jšœžœ ˜Jšœžœ3˜=J˜Jšœžœ'˜@J˜JšœΠbcœžœ/˜Qšœžœ˜'J˜—Jšœžœ˜"Jšœžœ)˜0Jšœžœ$˜0J˜Jšœ žœ˜,šžœžœžœžœ˜UJšœ žœK˜ZJšœžœ*˜3Jšœžœ ˜Jšœ žœP˜^Jšœ žœ ˜Jšœ2˜2Jšœ˜—J˜šœžœ ˜+Jšžœ2˜6Jšžœ+˜/J˜—šœ ˜J˜—Jšœ˜—Jšžœ˜—J˜šœ™Jšœ˜Jšœ žœ˜J˜šžœžœž˜Jšœ(˜(šœ ˜Jšœ˜—šœ$/˜SJšž˜Jšœ˜Jšœ˜Jšœ˜Jšžœ˜—šžœ4˜?Jšž˜Jšœžœ˜Jšœžœ ˜*Jšœ˜Jšœ2˜2Jšœ2˜2Jšžœ˜—J˜—J˜—šžœ žœ˜J˜J˜J˜—šžœ˜J˜J˜J˜J˜—Jšœ˜ J˜J˜—J˜Jšœ)žœ˜-Jšœ)žœ˜-Jšœ3žœ˜7J˜Jšœ žœ˜šœ žœžœ˜Jš œžœžœžœžœ˜6J˜—J˜Jš œžœ4œ˜[˜Jšžœžœ˜ Jšžœžœ˜ Jšœ žœ˜J˜Jšœ žœ!˜1Jšœžœžœ˜J˜šžœžœ žœ˜"Jšœžœ˜$Jšœ œžœ˜)J˜Jšœžœ˜$Jšœžœžœ˜%Jšœžœžœ˜ Jšœ žœ ˜J˜šžœ.žœž˜8Jšœ*žœ˜G—Jšœ žœ˜šžœ žœ&žœžœ˜TJšœ#žœ;žœžœ˜{Jšžœžœžœ"˜MJ˜J˜—Jšœžœžœžœ˜2J˜Jšœm™mJ˜Jšœžœ˜Jšœžœ˜Jšœ˜Jšœ žœžœžœ˜WJ˜Jšœ2˜2Jšœ2˜2Jšœ*˜*Jšœ'˜6J˜šžœžœžœ!ž˜0JšœžœM˜Tšžœž˜ šœ˜Jšœ5žœ'žœžœ˜{—Jšœm˜mJšœB˜Bšœ:˜:Jš œžœ/žœžœžœ˜E—Jšžœ˜—Jšžœ˜—Jšœ-˜-Jšœ'˜'J˜—J˜Jšœ7™7J˜šžœ'žœ˜/Jšœžœ˜.šœžœ˜-Jšžœ-˜3—šœžœ˜7Jšžœ-˜3—Jšœ"˜"Jšœ,œ˜HJ˜—šžœž˜Jšœ1˜1Jšœ$˜$Jšœ˜—šž˜Jšœ'˜'Jšœ$˜$J˜—Jšœ˜J˜J˜—Jšœ™J˜Jšœžœ!˜-Jšœ žœ;˜PJšœ žœ ˜Jšœžœ-˜9Jšœžœ˜-J˜š œžœ4œ˜ZJšœžœ˜(Jšœžœ˜&J˜Jšžœžœ˜Jšžœžœ˜ J˜Jšžœžœ˜Jšœ žœžœ˜&šžœžœžœ˜šžœžœž˜#šœ˜šžœžœ/ž˜7Jšžœžœ˜Jšœ,™,—Jšœ˜—Jšžœžœ˜J˜—šžœžœžœ˜Jšœžœ"˜8šœj˜jšžœ ˜"Jšžœ ˜"Jšžœžœ˜ ——Jšœ˜Jšœ˜—Jšœžœžœ˜@šœžœžœ˜)Jšžœ!˜%Jšžœ(œ˜G——šžœ˜Jšœžœ˜Jšœžœ+˜4J˜—Jšœ ˜ J˜J˜—š  œžœžœ žœ"œ˜pJšœžœ ˜&šœ˜J˜—J˜—š  œžœ%žœ žœ*œ˜ˆšžœ6˜8Jšžœ&˜)Jšžœ˜!šžœ˜Jšœ%˜%Jšœ%˜%Jšœ˜——Jšœ˜J˜J˜J˜J˜—š  œžœ&žœžœ žœ˜RJšœžœžœžœ˜0šœžœ˜šžœ˜J˜J˜Jšœžœ˜ —Jšžœ&žœ˜B—Jšœ˜Jšœ˜J˜J˜J˜—J˜gJ˜[šœ˜Jšœ˜Jšœ˜Jšœ'˜'šœ˜šœ˜Jšœ žœ˜Jšœ˜Jšœžœ2˜:—Jšœ˜JšœžœA˜I—Jšœ˜—J˜Jšžœ˜J˜šžœžœ˜ J˜/J˜