-- File: [Thyme]<Thyme>System>Spice>spModels.mesa -- Last editted by SChen 8-Feb-84 20:21:27 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; -- SqRt 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; -- initSqRt 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; -- dcDiode 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 Baum: PROC[VgsX, Vbin, Eta, Phi, Vbs, Vmax, L, UEffective, gammaD, SArg3: REAL] RETURNS[vdsat: REAL]= BEGIN v1, v2, xv, a1, b1, c1, d1, a3, b3, A, B, C, R, S, r3, s2, P, p0, p2, fi, y3, delta4, xValid: REAL← 0.0; x4, poly4: ARRAY[1..8] OF REAL; a4, b4, Sig1, Sig2: ARRAY[1..4] OF REAL; Icount, Jcount: CARDINAL← 0; Icount← Jcount← 0; x4← poly4← ALL[0.0]; a4← b4← ALL[0.0]; Sig1← [1.0, -1.0, 1.0, -1.0]; Sig2← [1.0, 1.0, -1.0, -1.0]; v1← (VgsX-Vbin)/Eta+Phi-Vbs; v2← Phi-Vbs; xv← Vmax*L/UEffective; a1← gammaD/0.75; b1← -2.0*(v1+xv); c1← -2.0*gammaD*xv; d1← 2.0*v1*(v2+xv)-v2*v2-4.0/3.0*gammaD*SArg3; A← -b1; B← a1*c1-4.0*d1; C← -d1*(a1*a1-4.0*b1)-c1*c1; R← -A*A/3.0+B; r3← R*R*R; S← 2.0*A*A*A/27.0-A*B/3.0+C; s2← S*S; P← s2/4.0+r3/27.0; p0← ABS[P]; p2← SqRt[p0]; -- get y3 value. IF P<0.0 THEN BEGIN ro: REAL; ro← SqRt[s2/4.0+p0]; ro← RealFns.Ln[ro]/3.0; ro← RealFns.Exp[ro]; fi← RealFns.ArcTan[-2.0*p2/S, 1]; -- arcTan(-2.0*p2/S); y3← 2.0*ro*RealFns.Cos[fi/3.0]-A/3.0; END ELSE BEGIN -- 550 p3, p4: REAL; p3← RealFns.Exp[ RealFns.Ln[ABS[-S/2.0+p2]]/3.0 ]; p4← RealFns.Exp[ RealFns.Ln[ABS[-S/2.0-p2]]/3.0 ]; y3← p3+p4-A/3.0; END; a3← SqRt[a1*a1/4.0-b1+y3]; b3← SqRt[y3*y3/4.0-d1]; -- from a3, b3, Sig1, Sig2, y3 -> a4, b4 -> delta4 -> x4 FOR I:CARDINAL IN[1..4] DO a4[I]← a1/2.0+Sig1[I]*a3; b4[I]← y3/2.0+Sig2[I]*b3; delta4← a4[I]*a4[I]/4.0-b4[I]; IF delta4>=0.0 THEN BEGIN sqrtd4: REAL; sqrtd4← SqRt[delta4]; Icount← Icount+1; x4[Icount]← a4[I]/(-2.0)+sqrtd4; Icount← Icount+1; x4[Icount]← a4[I]/(-2.0)-sqrtd4; END; ENDLOOP; FOR J:CARDINAL IN [1..Icount] DO IF x4[J]<=0.0 AND J<Icount THEN LOOP; poly4[J]← x4[J]*x4[J]*x4[J]*x4[J] + a1*x4[J]*x4[J]*x4[J]; poly4[J]← poly4[J]+b1*x4[J]*x4[J]+c1*x4[J]+d1; IF ABS[poly4[J]]>1.0E-6 AND J<Icount THEN LOOP; Jcount← Jcount+1; IF Jcount<=1 THEN xValid← x4[J]; IF x4[J]<=xValid THEN xValid← x4[J]; ENDLOOP; IF Jcount>0 THEN vdsat← xValid*xValid+Vbs-Phi ELSE SIGNAL spModelDefs.Retreat[ "Error in immediate velocity saturation model"]; END; -- Baum Grove: PROC[gammaD, VgsX, Vbin, Eta, Phi, Vbs: REAL] RETURNS[vdsat: REAL]= BEGIN gammaD2, ArgV: REAL; gammaD2← gammaD*gammaD; ArgV← (VgsX-Vbin)/Eta+Phi-Vbs; IF ArgV<=0.0 THEN vdsat← 0.0 ELSE BEGIN Arg: REAL; Arg← SqRt[1.0+4.0*ArgV/gammaD2]; vdsat← (VgsX-Vbin)/Eta+gammaD2*(1.0-Arg)/2.0; IF vdsat<0.0 THEN vdsat←0.0; END; END; -- Grove SpiceLevel2: spModelDefs.model= BEGIN -- args VdX: CARDINAL= 0; VgX: CARDINAL= 1; VsX: CARDINAL= 2; VbX: CARDINAL= 3; -- parms LX: CARDINAL= 0; WX: CARDINAL= 1; XdX: CARDINAL= 2; XjX: CARDINAL= 3; IssatX: CARDINAL= 4; IdsatX: CARDINAL= 5; BetaX: CARDINAL= 6; PhiX: CARDINAL= 7; SqRtPhiX: CARDINAL= 8; SqRtPhi3X: CARDINAL= 9; PbX: CARDINAL= 10; SqRtPbX: CARDINAL= 11; VbpX: CARDINAL= 12; VbiX: CARDINAL= 13; GammaX: CARDINAL= 14; LambdaX: CARDINAL= 15; VtX: CARDINAL= 16; UoX: CARDINAL= 17; VmaxX: CARDINAL= 18; QNfsX: CARDINAL= 19; NsubX: CARDINAL= 20; UexpX: CARDINAL= 21; NeffX: CARDINAL= 22; EtaX: CARDINAL= 23; FactorX: CARDINAL= 24; CoxX: CARDINAL= 25; CovGSX: CARDINAL= 26; CovDSX: CARDINAL= 27; CgbMX: CARDINAL= 28; Cgb23rdsX: CARDINAL= 29; CbsBottomX: CARDINAL= 30; CbdBottomX: CARDINAL= 31; CbsSWX: CARDINAL= 32; CbdSWX: CARDINAL= 33; CbsFwd1X: CARDINAL= 34; CbsFwd2X: CARDINAL= 35; CbdFwd1X: CARDINAL= 36; CbdFwd2X: CARDINAL= 37; MjX: CARDINAL= 38; MjswX: CARDINAL= 39; FcPbX: CARDINAL= 40; SignX: CARDINAL= 41; reverse: BOOLEAN; Vd, Vg, Vs, Vb, Vds, Vgs, Vbs, Vbd, Id, Ibs, Ibd, Cgb, Cgs, Cgd, Cbs, Cbd, t1, SArg, DsargDb, BArg, DbargDb, Vbin, XdBarg, XdSarg, ArgSS, ArgSD, DBArgS, DBArgD, ArgD, ArgS, gamaSD, DBXWD, DBXWS, gammaD, DgdDvb, VgsT, VgdT, SArg3, body, UFactor, UEffective, VgsX, bodyS, clFactor, von, vdsat, ArgG, beta1: REAL; Vd← MAX[-5.0, MIN[10.0, args[VdX]]]; Vg← MAX[-5.0, MIN[10.0, args[VgX]]]; Vs← MAX[-5.0, MIN[10.0, args[VsX]]]; Vb← MAX[-5.0, MIN[10.0, args[VbX]]]; IF parms[SignX]= -1 THEN {Vd← -Vd; Vg← -Vg; Vs← -Vs; Vb← -Vb}; IF Vs < Vd THEN reverse← FALSE ELSE {reverse← TRUE; t1← Vs; Vs← Vd; Vd← t1}; Vds← Vd - Vs; Vgs← Vg - Vs; Vbs← Vb - Vs; Vbd← Vb - Vd; Id← 0; -- get Ibs t1← Vbs/parms[VtX]; IF Vbs > 0 THEN BEGIN t1← MIN[t1, 85.0]; Ibs← parms[SignX]*parms[IssatX]*(RealFns.Exp[t1]- 1.0); END ELSE Ibs← parms[SignX]*parms[IssatX]*t1; -- get Ibd t1← Vbd/parms[VtX]; IF Vbd > 0 THEN BEGIN t1← MIN[t1, 85.0]; Ibd← parms[SignX]*parms[IdsatX]*(RealFns.Exp[t1]- 1.0); END ELSE Ibd← parms[SignX]*parms[IdsatX]*t1; -- 100 IF Vbs <= 0.0 THEN BEGIN SArg← SqRt[parms[PhiX]-Vbs]; DsargDb← -0.5/SArg; END ELSE BEGIN -- ( 110 ) SArg← parms[SqRtPhiX]/(1.0+0.5*Vbs/parms[PhiX]); DsargDb← -0.5*SArg*SArg/parms[SqRtPhi3X]; END; -- 120 IF Vbd <= 0 THEN BEGIN BArg← SqRt[parms[PhiX]+Vds-Vbs]; DbargDb← -0.5/BArg; END ELSE BEGIN -- 130 BArg← parms[SqRtPhiX]/(1.0+0.5*(Vbs-Vds)/parms[PhiX]); DbargDb← -0.5*BArg*BArg/parms[SqRtPhi3X]; END; -- 200, Calculate von, narrow channel effect Vbin← parms[VbiX]+parms[FactorX]*(parms[PhiX]-Vbs); XdBarg← parms[XdX]*BArg; XdSarg← parms[XdX]*SArg; -- short channel effect with Vds # 0 ArgSS← ArgSD← DBArgS← DBArgD← 0.0; IF parms[XjX] > 0.0 THEN BEGIN ArgXS, ArgXD: REAL; ArgXS← 1.0+2.0*XdSarg/parms[XjX]; ArgS← SqRt[ArgXS]; ArgSS← 0.5*parms[XjX]/parms[LX]*(ArgS-1.0); ArgXD← 1.0+2.0*XdBarg/parms[XjX]; ArgD← SqRt[ArgXD]; ArgSD← 0.5*parms[XjX]/parms[LX]*(ArgD-1.0); END; --(205) gamaSD← parms[GammaX]*(1.0-ArgSS-ArgSD); DBXWD← parms[XdX]*DbargDb; DBXWS← parms[XdX]*DsargDb; IF parms[XjX] > 0.0 THEN BEGIN DBArgS← 0.5/parms[LX]*DBXWS/ArgS; DBArgD← 0.5/parms[LX]*DBXWD/ArgD; END; DgdDvb← -parms[GammaX]*(DBArgS+DBArgD); --220 von← Vbin+gamaSD*SArg; vdsat← 0.0; --225 BEGIN IF parms[QNfsX] = 0.0 THEN BEGIN -- 230 VgsT← Vgs-von; IF VgsT<=0.0 THEN GOTO done; -- (Id=0) 1050 END ELSE BEGIN CdOnCo, Xn: REAL; CdOnCo← -(gamaSD*DsargDb+DgdDvb*SArg)+parms[FactorX]; Xn← 1.0+parms[QNfsX]/parms[CoxX]+CdOnCo; von← von+parms[VtX]*Xn; ArgG← 1.0/(parms[VtX]*Xn); VgsT← Vgs-von; END; -- 300 SArg3← SArg*SArg*SArg; gammaD← gamaSD; body← BArg*BArg*BArg-SArg3; -- 400, EVALUATE EFFECTIVE MOBILITY AND ITS DERIVATIVES IF VgsT > parms[VbpX] THEN BEGIN UFactor← RealFns.Exp[ parms[UexpX]*RealFns.Ln[parms[VbpX]/VgsT] ]; UEffective← parms[UoX]*UFactor; END ELSE BEGIN -- 410 UFactor← 1.0; UEffective← parms[UoX]; END; -- 500 EVALUATE SATURATION VOLTAGE AND ITS DERIVATIVES -- ACCORDING TO GROVE-FROHMAN EQUATION VgsX← Vgs; gammaD← gamaSD/parms[EtaX]; IF parms[QNfsX]#0.0 THEN VgsX← MAX[Vgs, von]; vdsat← IF gammaD <= 0.0 THEN MAX[0.0, (VgsX-Vbin)/parms[EtaX]] ELSE Grove[gammaD, VgsX, Vbin, parms[EtaX], parms[PhiX], Vbs]; -- 545 IF parms[VmaxX] > 0.0 THEN vdsat← Baum[ VgsX, Vbin, parms[EtaX], parms[PhiX], Vbs, parms[VmaxX], parms[LX], UEffective, gammaD, SArg3]; -- 600, EVALUATE EFFECTIVE CHANNEL LENGTH AND ITS DERIVATIVES IF Vds # 0.0 THEN BEGIN lFactor, ArgV, xdv, lv, ls, SArgV, BSArg: REAL; gammaD← gamaSD; BSArg← IF Vbs <= vdsat THEN SqRt[vdsat-Vbs+parms[PhiX]] ELSE parms[SqRtPhiX]/(1.0+0.5*(Vbs-vdsat)/parms[PhiX]); bodyS← BSArg*BSArg*BSArg-SArg3; IF parms[VmaxX] <=0.0 THEN BEGIN IF parms[NsubX] # 0.0 AND parms[LambdaX] <= 0.0 THEN BEGIN Arg: REAL; ArgV← (Vds-vdsat)/4.0; SArgV← SqRt[1.0+ArgV*ArgV]; Arg← SqRt[ArgV+SArgV]; lFactor← parms[XdX]/(parms[LX]*Vds); parms[LambdaX]← lFactor*Arg; END; END ELSE BEGIN -- 603 ArgV← (VgsX-Vbin)/parms[EtaX]-vdsat; xdv← parms[XdX]/SqRt[parms[NeffX]]; lv← parms[VmaxX]*xdv/(2.0*UEffective); IF parms[NsubX] # 0.0 AND parms[LambdaX] <= 0.0 THEN BEGIN ArgV← MAX[Vds-vdsat, 0.0]; ls← SqRt[lv*lv+ArgV]; lFactor← xdv/(parms[LX]*Vds); parms[LambdaX]← lFactor*(ls-lv); END; END; END; -- block 600 -- 620, LIMIT CHANNEL SHORTENING AT PUNCH-THROUGH BEGIN leffective, deltaL, xwb, ld: REAL; xwb← parms[XdX]*parms[SqRtPbX]; ld← parms[LX]-xwb; clFactor← 1.0-parms[LambdaX]*Vds; leffective← parms[LX]*clFactor; deltaL← parms[LambdaX]*Vds*parms[LX]; IF parms[NsubX]=0.0 THEN xwb← 0.25E-6; IF leffective<xwb THEN BEGIN leffective← xwb/(1.0+(deltaL-ld)/xwb); clFactor← leffective/parms[LX]; END; END; -- 700 EVALUATE EFFECTIVE beta (EFFECTIVE KP) beta1← parms[BetaX]*UFactor/clFactor; -- TEST FOR MODE OF OPERATION AND BRANCH APPROPRIATELY gammaD← gamaSD; IF Vds <= 1.0E-8 THEN GOTO done; -- (Id=0) 1050 -- 730 IF VgsT <= 0.0 THEN BEGIN -- else goto 900 VdsOn, IdsOn: REAL; -- SUBTHRESHOLD REGION, IF vdsat<=0.0 THEN Id← 0.0 IF vdsat > 0.0 THEN BEGIN -- 830 VdsOn← MIN[vdsat,Vds]; IF Vds > vdsat THEN body← bodyS; -- 850 IdsOn← beta1*((von-Vbin-parms[EtaX]*VdsOn*0.5)*VdsOn-gammaD*body/1.5); Id← parms[SignX]*IdsOn*RealFns.Exp[ArgG*VgsT]; END; END ELSE Id← IF Vds <= vdsat THEN -- 900 LINEAR REGION parms[SignX]*beta1*((Vgs-Vbin-parms[EtaX]*Vds/2.0)*Vds-gammaD*body/1.5) ELSE -- 1000 SATURATION REGION parms[SignX]*beta1*((Vgs-Vbin-parms[EtaX]*vdsat/2.0)*vdsat-gammaD*bodyS/1.5); EXITS done=> NULL; END; -- capacitances, and results VgdT← Vg - Vd - von; -- Cgb: Cgb← IF VgsT <= 0 THEN parms[CgbMX] ELSE 0; -- Cgs and Cgd: t1← VgsT+VgdT; t1← t1*t1; -- (Vgs + Vgd - 2von)↑2 Cgs← IF VgsT <= 0.0 THEN parms[CovGSX] ELSE IF VgdT <= 0.0 THEN parms[Cgb23rdsX] + parms[CovGSX] ELSE parms[CovGSX] + parms[Cgb23rdsX]*(1.0 - VgdT*VgdT/t1); Cgd← IF VgdT <= 0.0 THEN parms[CovDSX] ELSE parms[CovDSX] + parms[Cgb23rdsX]*(1.0 - VgsT*VgsT/t1); -- Cbs and Cbd IF Vbs >= parms[FcPbX] THEN -- 520 Cbs← parms[CbsFwd1X] + Vbs*parms[CbsFwd2X] ELSE BEGIN t1← RealFns.Ln[1.0-Vbs/parms[PbX]]; Cbs← parms[CbsBottomX]*RealFns.Exp[-parms[MjX]*t1] + parms[CbsSWX]*RealFns.Exp[-parms[MjswX]*t1] END; IF Vbd >= parms[FcPbX] THEN -- 520 Cbd← parms[CbdFwd1X] + Vbd*parms[CbdFwd2X] ELSE BEGIN t1← RealFns.Ln[1.0-Vbd/parms[PbX]]; Cbd← parms[CbdBottomX]*RealFns.Exp[-parms[MjX]*t1] + parms[CbdSWX]*RealFns.Exp[-parms[MjswX]*t1] END; -- results order: Id, Cgb, Cgs, Cgd, Cbs, Cbd, Ibs, Ibd. IF reverse THEN BEGIN results[0]← -Id; results[1]← Cgb; results[2]← Cgd; results[3]← Cgs; results[4]← Cbd; results[5]← Cbs; results[6]← Ibd; results[7]← Ibs; END ELSE BEGIN results[0]← Id; results[1]← Cgb; results[2]← Cgs; results[3]← Cgd; results[4]← Cbs; results[5]← Cbd; results[6]← Ibs; results[7]← Ibd; END; END; -- SpiceLevel2 initSqRt[]; spModelDefs.EnterModels["SpiceLevel2", SpiceLevel2, 4, 42, 8]; spModelDefs.EnterModels["acDiode", acDiode, 2, 5, 2]; spModelDefs.EnterModels["dcDiode", dcDiode, 2, 3, 1]; END.