-- 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.