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