-- File: [Thyme]<Thyme>System>Spice>Level2Model.mesa -- Last editted by SChen 8-Feb-84 20:21:27 DIRECTORY AltoDefs, Real, RealFns, spModelDefs; Level2Model: 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 SpiceLevel2: spModelDefs.model= BEGIN -- args Vd: REAL← args[0]; Vg: REAL← args[1]; Vs: REAL← args[2]; Vb: REAL← args[3]; -- parms l: REAL= parms[0]; w: REAL= parms[1]; xd: REAL= parms[2]; xj: REAL= parms[3]; Issat: REAL= parms[4]; Idsat: REAL= parms[5]; beta: REAL= parms[6]; phi: REAL= parms[7]; phiB: REAL= parms[8]; vbp: REAL= parms[9]; vbi: REAL= parms[10]; gamma: REAL= parms[11]; lambda: REAL← parms[12]; vt: REAL= parms[13]; uo: REAL= parms[14]; vmax: REAL= parms[15]; QNfs: REAL= parms[16]; nsub: REAL= parms[17]; uexp: REAL= parms[18]; neff: REAL= parms[19]; eta: REAL= parms[20]; factor: REAL= parms[21]; Cox: REAL= parms[22]; CovGS: REAL= parms[23]; CovDS: REAL= parms[24]; CgbM: REAL= parms[25]; Cgb23rds: REAL= parms[26]; CbsBottom: REAL= parms[27]; CbdBottom: REAL= parms[28]; CbsSW: REAL= parms[29]; CbdSW: REAL= parms[30]; CbsFwd1: REAL= parms[31]; CbsFwd2: REAL= parms[32]; CbdFwd1: REAL= parms[33]; CbdFwd2: REAL= parms[34]; FcByPb: REAL= parms[35]; sign: REAL= parms[36]; Vds, Vgs, Vbs, Vbd, Id, Ibs, Ibd, Cgb, Cgs, Cgd, Cbs, Cbd, t1: REAL← 0.0; reverse: BOOLEAN← FALSE; SArg, DsargDb, SqrtPhi, SqrtPhi3, BArg, DbargDb, Vbin, XdBarg, XdSarg, ArgSS, ArgSD, DBArgS, DBArgD, ArgD, ArgS, ArgXS, ArgXD, gamaSD, DBXWD, DBXWS, gammaD, DgdDvb, CdOnCo, Xn, VgsT, ArgG, SArg3, SqrtPhib, body, UFactor, UEffective, VgsX, ArgV, Arg, BSArg, DbsargDb, bodyS, clFactor, von, vdsat, beta1: REAL← 0.0; IF sign= -1 THEN {Vd← -Vd; Vg← -Vg; Vs← -Vs; Vb← -Vb}; IF Vs > Vd THEN {reverse← TRUE; t1← Vs; Vs← Vd; Vd← t1}; Vds← Vd - Vs; Vgs← Vg - Vs; Vbs← Vb - Vs; Vbd← Vb - Vd; -- get Ibs t1← Vbs/vt; IF Vbs > 0 THEN BEGIN t1← MIN[t1, 85.0]; Ibs← sign*Issat*(RealFns.Exp[t1]- 1.0); END ELSE Ibs← sign*Issat*t1; -- get Ibd t1← Vbd/vt; IF Vbd > 0 THEN BEGIN t1← MIN[t1, 85.0]; Ibd← sign*Idsat*(RealFns.Exp[t1]- 1.0); END ELSE Ibd← sign*Idsat*t1; -- 100 IF Vbs <= 0.0 THEN BEGIN SArg← SqRt[phi-Vbs]; DsargDb← -0.5/SArg; END ELSE BEGIN -- ( 110 ) SqrtPhi← SqRt[phi]; SqrtPhi3← phi*SqrtPhi; SArg← SqrtPhi/(1.0+0.5*Vbs/phi); DsargDb← -0.5*SArg*SArg/SqrtPhi3; END; -- 120 IF Vds >= Vbs THEN BEGIN BArg← SqRt[phi+Vds-Vbs]; DbargDb← -0.5/BArg; END ELSE BEGIN -- 130 BArg← SqrtPhi/(1.0+0.5*(Vbs-Vds)/phi); DbargDb← -0.5*BArg*BArg/SqrtPhi3; END; -- 200, Calculate von, narrow channel effect Vbin← vbi+factor*(phi-Vbs); IF (gamma<=0.0) OR (nsub<=0.0) THEN BEGIN -- 215 gamaSD← gammaD← gamma; DgdDvb← 0.0; END ELSE BEGIN XdBarg← xd*BArg; XdSarg← xd*SArg; -- short channel effect with Vds # 0 ArgSS← ArgSD← DBArgS← DBArgD← 0.0; IF xj > 0.0 THEN BEGIN ArgXS← 1.0+2.0*XdSarg/xj; ArgS← SqRt[ArgXS]; ArgSS← 0.5*xj/l*(ArgS-1.0); ArgXD← 1.0+2.0*XdBarg/xj; ArgD← SqRt[ArgXD]; ArgSD← 0.5*xj/l*(ArgD-1.0); END; --(205) gamaSD← gamma*(1.0-ArgSS-ArgSD); DBXWD← xd*DbargDb; DBXWS← xd*DsargDb; IF xj>0.0 THEN BEGIN DBArgS← 0.5/l*DBXWS/ArgS; DBArgD← 0.5/l*DBXWD/ArgD; END; DgdDvb← -gamma*(DBArgS+DBArgD); END; --220 von← Vbin+gamaSD*SArg; vdsat← 0.0; --225 BEGIN IF QNfs = 0.0 THEN BEGIN -- 230 VgsT← Vgs-von; IF VgsT<=0.0 THEN GOTO done; -- (Id=0) 1050 END ELSE BEGIN CdOnCo← -(gamaSD*DsargDb+DgdDvb*SArg)+factor; Xn← 1.0+QNfs/Cox+CdOnCo; von← von+vt*Xn; ArgG← 1.0/(vt*Xn); VgsT← Vgs-von; END; -- 300 SArg3← SArg*SArg*SArg; SqrtPhib← SqRt[phiB]; gammaD← gamaSD; body← BArg*BArg*BArg-SArg3; -- 400, EVALUATE EFFECTIVE MOBILITY AND ITS DERIVATIVES IF VgsT > vbp THEN BEGIN UFactor← RealFns.Exp[ uexp*RealFns.Ln[vbp/VgsT] ]; UEffective← uo*UFactor; END ELSE BEGIN -- 410 UFactor← 1.0; UEffective← uo; END; -- 500 EVALUATE SATURATION VOLTAGE AND ITS DERIVATIVES ACCORDING TO -- GROVE-FROHMAN EQUATION VgsX← Vgs; gammaD← gamaSD/eta; IF QNfs#0.0 THEN VgsX← MAX[Vgs, von]; IF gammaD<=0.0 THEN vdsat← MAX[0.0, (VgsX-Vbin)/eta] ELSE BEGIN gammaD2: REAL← gammaD*gammaD; ArgV← (VgsX-Vbin)/eta+phi-Vbs; IF ArgV<=0.0 THEN vdsat← 0.0 ELSE BEGIN 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; -- vdsat← DMAX1(vdsat,0.0); END; END; -- 545 IF vmax > 0.0 THEN BEGIN -- EVALUATE SATURATION VOLTAGE AND ITS DERIVATIVES ACCORDING TO -- BAUM'S THEORY OF SCATTERING VELOCITY SATURATION v1, v2, xv, a1, b1, c1, d1, a3, b3, A, B, C, R, S, r3, s2, P, p0, p2, fi, y3, delta4, xValid: REAL; x4, poly4, a4, b4, Sig1, Sig2: ARRAY[1..4] OF REAL; Icount, Jcount: CARDINAL← 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← SqRt[s2/4.0+p0]; ro← RealFns.Ln[ro]/3.0; ro← RealFns.Exp[ro]; fi← RealFns.ArcTan[-2.0*p2, S]; -- arcTan(-2.0*p2/S); y3← 2.0*ro*RealFns.Cos[fi/3.0]-A/3.0; END ELSE BEGIN -- 550 p3: REAL← RealFns.Exp[ RealFns.Ln[ABS[-S/2.0+p2]]/3.0 ]; p4: REAL← 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 Icount← Icount+1; x4[Icount]← -a4[I]/2.0+SqRt[delta4]; Icount← Icount+1; x4[Icount]← -a4[I]/2.0-SqRt[delta4]; END; ENDLOOP; FOR J:CARDINAL IN [1..Icount] DO IF x4[J]<=0.0 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 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; -- Block 545 -- 600, EVALUATE EFFECTIVE CHANNEL LENGTH AND ITS DERIVATIVES IF Vds # 0.0 THEN BEGIN lFactor, ArgV, xdv, lv, ls, SArgV: REAL; gammaD← gamaSD; BSArg← IF Vbs <= vdsat THEN SqRt[vdsat-Vbs+phi]; ELSE SqrtPhi/(1.0+0.5*(Vbs-vdsat)/phi); bodyS← BSArg*BSArg*BSArg-SArg3; IF vmax<=0.0 THEN BEGIN IF nsub # 0.0 AND lambda <= 0.0 THEN BEGIN ArgV← (Vds-vdsat)/4.0; SArgV← SqRt[1.0+ArgV*ArgV]; Arg← SqRt[ArgV+SArgV]; lFactor← xd/(l*Vds); lambda← lFactor*Arg; END; END ELSE BEGIN -- 603 ArgV← (VgsX-Vbin)/eta-vdsat; xdv← xd/SqRt[neff]; lv← vmax*xdv/(2.0*UEffective); IF nsub # 0.0 AND lambda <= 0.0 THEN BEGIN ArgV← MAX[Vds-vdsat, 0.0]; ls← SqRt[lv*lv+ArgV]; lFactor← xdv/(l*Vds); lambda← lFactor*(ls-lv); END; END; END; -- block 600 -- 620, LIMIT CHANNEL SHORTENING AT PUNCH-THROUGH BEGIN leffective, deltaL: REAL; xwb: REAL← xd*SqrtPhib; ld: REAL← l-xwb; clFactor← 1.0-lambda*Vds; leffective← l*clFactor; deltaL← lambda*Vds*l; IF nsub=0.0 THEN xwb← 0.25E-6; IF leffective<xwb THEN BEGIN leffective← xwb/(1.0+(deltaL-ld)/xwb); clFactor← leffective/l; END; END; -- 700 EVALUATE EFFECTIVE beta (EFFECTIVE KP) beta1← beta*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-eta*VdsOn*0.5)*VdsOn-gammaD*body/1.5); Id← sign*IdsOn*RealFns.Exp[ArgG*VgsT]; END; END ELSE Id← IF Vds <= vdsat THEN -- 900 LINEAR REGION sign*beta1*((Vgs-Vbin-eta*Vds/2.0)*Vds-gammaD*body/1.5) ELSE -- 1000 SATURATION REGION sign*beta1*((Vgs-Vbin-eta*vdsat/2.0)*vdsat-gammaD*bodyS/1.5); EXITS done=> NULL; END; -- capacitances, and results VgdT: REAL← Vg - Vd - von; -- Cgb: Cgb← IF VgsT <= 0 THEN CgbM ELSE 0; -- Cgs and Cgd: t1← VgsT+VgdT; t1← t1*t1; -- (Vgs + Vgd - 2von)↑2 Cgs← IF VgsT <= 0.0 THEN CovGS ELSE IF VgdT <= 0.0 THEN Cgb23rds + CovGS ELSE CovGS + Cgb23rds*(1.0 - VgdT*VgdT/t1); Cgd← IF VgdT <= 0.0 THEN CovDS ELSE CovDS + Cgb23rds*(1.0 - VgsT*VgsT/t1); -- Cbs and Cbd IF Vbs >= FcByPb THEN -- 520 Cbs← CbsFwd1 + Vbs*CbsFwd2 ELSE BEGIN t1← RealFns.Ln[1.0-Vbs/PhiB]; Cbs← CbsBottom*RealFns.Exp[-Mj*t1] + CbsSW*RealFns.Exp[-Mjsw*t1] END; IF Vbd >= FcByPb THEN -- 520 Cbd← CbdFwd1 + Vbd*CbdFwd2 ELSE BEGIN t1← RealFns.Ln[1.0-Vbd/PhiB]; Cbd← CbdBottom*RealFns.Exp[-Mj*t1] + CbdSW*RealFns.Exp[-Mjsw*t1] END; -- results order: Id, Cgb, Cgs, Cgd, Cbs, Cbd, Ibs, Ibd. results← IF reverse THEN [-Id, Cgb, Cgd, Cgs, Cbd, Cbs, Ibd, Ibs] ELSE [ Id, Cgb, Cgs, Cgd, Cbs, Cbd, Ibs, Ibd]; END; END; -- SpiceLevel2 initSqRt[]; spModelDefs.EnterModels["SpiceLevel2", SpiceLevel2, 4, 37, 8]; END.