File: [Cherry]<Thyme>Cedar5.1>System>spModels.mesa
Last editted: Chen June 7, 1984 8:14:41 pm PDT
Last Edited by: SChen, June 11, 1984 7:41:49 pm PDT
DIRECTORY
Rope USING [ROPE],
RealFns USING [Exp],
RealOps USING [SqRt],
spGlobals USING [EnterModels, model, Retreat];
spModels: CEDAR PROGRAM
IMPORTS RealFns, RealOps, spGlobals
EXPORTS spGlobals=
BEGIN
modelError: SIGNAL[s: Rope.ROPE]= CODE;
NFET: spGlobals.model= {
VgX: NAT= 0;
VsX: NAT= 1;
VdX: NAT= 2;
VbX: NAT= 3;

VtX: NAT= 0;
hKp: NAT= 1;
Phi2: NAT= 2;
Phi2fb: NAT= 3;
Kb: NAT= 4;
ftKb: NAT= 5;
hKbsq: NAT= 6;
qKbsq: NAT= 7;
Vfb: NAT= 8;
Cox: NAT= 9;
Cgsd0: NAT= 10;
Cgsdp: NAT= 11;
Ioff: NAT= 12;
Io: NAT= 13;
kTq: NAT= 14;
expMax: NAT= 15;

IdX: NAT= 0;
CgbX: NAT= 1;
CgsX: NAT= 2;
CgdX: NAT= 3;

Vg, Vs, Vd, Vb, Id: REAL;
Cgs, Cgd: REAL;
Vt, Vgst, Vgdt, VdSAT, Vsbphi2, Vdx, SqrtV: REAL;
t1, t2: REAL;
reverse: BOOL← FALSE;

Vg← args[VgX];
Vb← args[VbX];
Vd← args[VdX];
Vs← args[VsX];

t1← Vb - Vs;
IF t1 > 0.0 THEN {
t1← t1/parms[kTq];
IF t1 >= parms[expMax] THEN SIGNAL spGlobals.Retreat["NFET -- Source."];
results[4]← parms[Io]*(RealFns.Exp[t1] - 1.0); }
ELSE results[4]← -parms[Io];

t2← Vb - Vd;
IF t2 > 0.0 THEN {
t2← t2/parms[kTq];
IF t2 >= parms[expMax] THEN SIGNAL spGlobals.Retreat["NFET -- Drain."];
results[5]← parms[Io]*(RealFns.Exp[t2] - 1.0); }
ELSE results[5]← -parms[Io];

IF Vs > Vd THEN {
reverse← TRUE;
t1← Vs;
Vs← Vd;
Vd← t1; };

Vsbphi2← MAX[Vs - Vb + parms[Phi2], 0.0];
SqrtV← RealOps.SqRt[MAX[0.0, parms[qKbsq] + Vg - parms[Vfb] - Vb]];
Vt← IF Vs= Vb THEN parms[VtX]
ELSE parms[Phi2fb] + parms[Kb]*RealOps.SqRt[Vsbphi2];
Vgst← Vg - Vs - Vt;
IF Vgst > 0 THEN {
VdSAT← Vg - parms[Phi2fb] + parms[hKbsq] - parms[Kb]*SqrtV;
IF VdSAT < Vs THEN SIGNAL modelError["Negative VdSAT"];
Vdx← IF Vd > VdSAT THEN VdSAT ELSE Vd;
t1← Vsbphi2*RealOps.SqRt[Vsbphi2];
t2← Vdx - Vb + parms[Phi2];
t2← t2*RealOps.SqRt[t2];
Id← parms[hKp]*((2.0*(Vg - parms[Phi2fb]) - Vs - Vdx)*
(Vdx - Vs) + parms[ftKb]*(t1 - t2)); }
ELSE Id← parms[Ioff];

IF Id < 0.0 THEN
IF Id < -parms[Ioff] THEN SIGNAL modelError["Negative drain current"]
ELSE Id← parms[Ioff];

t1← Vg - Vb - parms[Vfb];
IF t1 <= 0.0 THEN results[CgbX]← parms[Cox]
ELSE results[CgbX]← 0.5*parms[Kb]*parms[Cox]/SqrtV;

Vgdt← Vg - Vd - Vt;
t1← Vgst + Vgdt;
t1← t1*t1;
IF Vgst <= 0.0 THEN Cgs← parms[Cgsdp]
ELSE IF Vgdt < 0.0 THEN Cgs← parms[Cgsd0] + parms[Cgsdp]
ELSE Cgs← parms[Cgsdp] + parms[Cgsd0]*(1.0 - Vgdt*Vgdt/t1);
IF Vgdt <= 0.0 THEN Cgd← parms[Cgsdp]
ELSE Cgd← parms[Cgsdp] + parms[Cgsd0]*(1.0 - Vgst*Vgst/t1);

IF reverse THEN {
results[IdX] ← -Id;
results[CgsX]← Cgd;
results[CgdX]← Cgs; }
ELSE {
results[IdX] ← Id;
results[CgsX]← Cgs;
results[CgdX]← Cgd; };
};
-- NFET
PFET: spGlobals.model= {
VgX: NAT= 0;
VsX: NAT= 1;
VdX: NAT= 2;
VbX: NAT= 3;

VtX: NAT= 0;
hKp: NAT= 1;
Phi2: NAT= 2;
Phi2fb: NAT= 3;
Kb: NAT= 4;
ftKb: NAT= 5;
hKbsq: NAT= 6;
qKbsq: NAT= 7;
Vfb: NAT= 8;
Cox: NAT= 9;
Cgsd0: NAT= 10;
Cgsdp: NAT= 11;
Ioff: NAT= 12;
Io: NAT= 13;
kTq: NAT= 14;
expMax: NAT= 15;

IdX: NAT= 0;
CgbX: NAT= 1;
CgsX: NAT= 2;
CgdX: NAT= 3;

Vg, Vs, Vd, Vb, Id: REAL;
Cgs, Cgd: REAL;
Vt, Vgst, Vgdt, VdSAT, Vsbphi2, Vdx, SqrtV: REAL;
t1, t2: REAL;
reverse: BOOL← FALSE;

Vg← args[VgX];
Vb← args[VbX];
Vd← args[VdX];
Vs← args[VsX];

t1← Vs - Vb;
IF t1 > 0.0 THEN {
t1← t1/parms[kTq];
IF t1 >= parms[expMax] THEN SIGNAL spGlobals.Retreat["PFET -- Source."];
results[4]← parms[Io]*(RealFns.Exp[t1] - 1.0); }
ELSE results[4]← -parms[Io];

t2← Vd - Vb;
IF t2 > 0.0 THEN {
t2← t2/parms[kTq];
IF t2 >= parms[expMax] THEN SIGNAL spGlobals.Retreat["PFET -- Drain."];
results[5]← parms[Io]*(RealFns.Exp[t2] - 1.0); }
ELSE results[5]← -parms[Io];

IF Vs < Vd THEN {
reverse← TRUE;
t1← Vs;
Vs← Vd;
Vd← t1; };

Vsbphi2← MIN[Vs - Vb + parms[Phi2], 0.0];
SqrtV← RealOps.SqRt[-MIN[0.0, -parms[qKbsq] + Vg - parms[Vfb] - Vb]];
Vt← IF Vs= Vb THEN parms[VtX]
ELSE parms[Phi2fb] - parms[Kb]*RealOps.SqRt[-Vsbphi2];
Vgst← Vg - Vs - Vt;
IF Vgst < 0 THEN {
VdSAT← Vg - parms[Phi2fb] - parms[hKbsq] + parms[Kb]*SqrtV;
IF VdSAT > Vs THEN SIGNAL modelError["Positive VdSAT"];
Vdx← IF Vd < VdSAT THEN VdSAT ELSE Vd;
t1← Vsbphi2*RealOps.SqRt[-Vsbphi2];
t2← Vdx - Vb + parms[Phi2];
t2← t2*RealOps.SqRt[-t2];
Id← parms[hKp]*((2.0*(Vg - parms[Phi2fb]) - Vs - Vdx)*
(Vdx - Vs) - parms[ftKb]*(t1 - t2)); }
ELSE Id← parms[Ioff];

IF Id < 0.0 THEN
IF Id < -parms[Ioff]THEN SIGNAL modelError["Negative drain current"]
ELSE Id← parms[Ioff];

t1← Vg - Vb - parms[Vfb];
IF t1 >= 0.0 THEN results[CgbX]← parms[Cox]
ELSE results[CgbX]← 0.5*parms[Kb]*parms[Cox]/SqrtV;

Vgdt← Vg - Vd - Vt;
t1← Vgst + Vgdt;
t1← t1*t1;
IF Vgst >= 0.0 THEN Cgs← parms[Cgsdp]
ELSE IF Vgdt > 0.0 THEN Cgs← parms[Cgsd0] + parms[Cgsdp]
ELSE Cgs← parms[Cgsdp] + parms[Cgsd0]*(1.0 - Vgdt*Vgdt/t1);
IF Vgdt >= 0.0 THEN Cgd← parms[Cgsdp]
ELSE Cgd← parms[Cgsdp] + parms[Cgsd0]*(1.0 - Vgst*Vgst/t1);

IF reverse THEN {
results[IdX] ← -Id;
results[CgsX]← Cgd;
results[CgdX]← Cgs; }
ELSE {
results[IdX] ← Id;
results[CgsX]← Cgs;
results[CgdX]← Cgd; };

};
-- PFET
dcDiode: spGlobals.model= {
Vd, e: REAL;

Va: NAT= 0;
Vc: NAT= 1;

Io: NAT= 0;
kTq: NAT= 1;
expMax: NAT= 2;

Vd← args[Va] - args[Vc];
IF Vd + parms[kTq] <= 0.0 THEN results[0]← -parms[Io]
ELSE {
e← Vd/parms[kTq];
IF e >= parms[expMax] THEN SIGNAL spGlobals.Retreat["dcDiode."];
results[0]← parms[Io]*(RealFns.Exp[e] - 1.0); };

};
-- dcDiode
CSIM: spGlobals.model= {
args:
VgX: NAT= 0;
VsX: NAT= 1;
VdX: NAT= 2;
VbX: NAT= 3;
The 8 electrical parameters of CSIM model. cf. Scharfetter's memo of 12/30/82.
vfb: NAT= 0;
twoPhiF: NAT= 1;
k1: NAT= 2;
k2: NAT= 3;
eta: NAT= 4;
beta0: NAT= 5;
u0: NAT= 6;
u1: NAT= 7;
The 6 capacitance parameters for MOSAID model. cf. MOSAID documentation by Dick Foss.
MCgbo: NAT= 8;
Cgbo23rds: NAT= 9;
Cov: NAT= 10;
Cbso: NAT= 11;
Cbdo: NAT= 12;
phiB: NAT= 13;
other parameters:
Ios: NAT= 14;
Iod: NAT= 15;
kTq: NAT= 16;
expMax: NAT= 17;
NoCap: NAT= 18;
nChannel: NAT= 19;
-- -1: pType; else nType;
results:
IdX : NAT= 0;
CgbX: NAT= 1;
CgsX: NAT= 2;
CgdX: NAT= 3;
CbsX: NAT= 4;
CbdX: NAT= 5;
Ibs: NAT= 6;
Ibd: NAT= 7;

Vg, Vs, Vd, Vb, Vds, Vgs, Vbs, Vbd: REAL;
Id, Cgs, Cgd, Cbs, Cbd: REAL;
reverse: BOOL← FALSE;
t1, TwoPhiFMVbs, Sqrt2PhiFMVbs, EtaVds,
VgsMVth, VgdMVth, Vth: REAL;

IF parms[nChannel]= -1 THEN {
Vg← -args[VgX]; Vb← -args[VbX];
Vd← -args[VdX]; Vs← -args[VsX]; }
ELSE {
parms[nChannel]← 1;
Vg← args[VgX]; Vb← args[VbX]; Vd← args[VdX]; Vs← args[VsX]; };
get Ibs:
IF Vb > Vs THEN {
t1← (Vb-Vs)/parms[kTq];
IF t1 >= parms[expMax] THEN SIGNAL spGlobals.Retreat[
"CSIM -> Vbs forward biased too much"];
results[Ibs]← parms[nChannel]*parms[Ios]*(RealFns.Exp[t1]- 1.0); }
ELSE results[Ibs]← -parms[nChannel]*parms[Ios];
get Ibd:
IF Vb > Vd THEN {
t1← (Vb-Vd)/parms[kTq];
IF t1 >= parms[expMax] THEN SIGNAL spGlobals.Retreat[
"CSIM -> Vbd forward biased too much"];
results[Ibd]← parms[nChannel]*parms[Iod]*(RealFns.Exp[t1]- 1.0); }
ELSE results[Ibd]← -parms[nChannel]*parms[Iod];

IF Vs > Vd THEN {reverse← TRUE; t1← Vs; Vs← Vd; Vd← t1; };

Vds← Vd - Vs; Vgs← Vg - Vs; Vbs← Vb - Vs; Vbd← Vb - Vd;
If it ever gets here, Vbs must be less than 2phif.
cf. expMax calculation in ThymeBasics.thy
TwoPhiFMVbs← parms[twoPhiF]-Vbs;
Sqrt2PhiFMVbs← RealOps.SqRt[TwoPhiFMVbs];
EtaVds← parms[eta]*Vds;

Vth← parms[vfb]+parms[twoPhiF]+parms[k1]*Sqrt2PhiFMVbs-EtaVds
-parms[k2]*TwoPhiFMVbs;
VgsMVth← Vgs - Vth;

IF VgsMVth <= 0.0 THEN Id← 0
ELSE {
-- Vgs>Vth:
g: REAL← 1.0-1.0/(1.744+0.8364*TwoPhiFMVbs);
a: REAL← 1.0 + 0.5*g*parms[k1]/Sqrt2PhiFMVbs;
alpha: REAL← a*(1.0 + parms[u1]*VgsMVth); -- a(1+u1*(Vgs-Vth))
VdSat: REAL← VgsMVth/alpha;
BetaP: REAL← parms[nChannel]*parms[beta0]
/(1.0+parms[u0]*VgsMVth); -- beta0/(1+u0(Vgs-Vth))

Id← IF Vds<VdSat THEN BetaP*Vds*(VgsMVth - 0.5*alpha*Vds)
ELSE BetaP*VgsMVth*VgsMVth/(2.0*alpha);

};
-- end of Vgs>Vth

IF parms[NoCap]#0 THEN {
results[CgbX]← results[CgsX]← results[CgdX]←
results[CbsX]← results[CbdX]← 0;
results[IdX]← IF reverse THEN -Id ELSE Id;
RETURN; };

VgdMVth← Vg - Vd - Vth;
Cgb:
results[CgbX]← IF VgsMVth <= 0 THEN parms[MCgbo] ELSE 0;
  
Cgs and Cgd:
t1← VgsMVth+VgdMVth;
t1← t1*t1;
-- (Vgs + Vgd - 2Vth)^2
Cgs← IF VgsMVth <= 0.0 THEN parms[Cov]
ELSE IF VgdMVth <= 0.0 THEN parms[Cgbo23rds] + parms[Cov]
ELSE parms[Cov] + parms[Cgbo23rds]*(1.0 - VgdMVth*VgdMVth/t1);
Cgd← IF VgdMVth <= 0.0 THEN parms[Cov]
ELSE parms[Cov] + parms[Cgbo23rds]*(1.0 - VgsMVth*VgsMVth/t1);
Cbs and Cbd: Since phiB>2phif, the following should never blow up.
Cbs← parms[Cbso]/RealOps.SqRt[1.0 - Vbs/parms[phiB]];
Cbd← parms[Cbdo]/RealOps.SqRt[1.0 - Vbd/parms[phiB]];

IF reverse THEN {
results[IdX]← -Id;
results[CgsX]← Cgd;
results[CgdX]← Cgs;
results[CbsX]← Cbd;
results[CbdX]← Cbs; }
ELSE {
results[IdX]← Id;
results[CgsX]← Cgs;
results[CgdX]← Cgd;
results[CbsX]← Cbs;
results[CbdX]← Cbd; };

};
-- CSIM
acDiode: spGlobals.model= {
Vc: NAT= 0; -- cathode voltage index
Va: NAT= 1; -- anode voltage index
Co: NAT= 0;
Pb: NAT= 1;
Vt: NAT= 2;
Io: NAT= 3;
expMax: NAT= 4;
C: NAT= 0;
I: NAT= 1;
t1: REAL;
V: REAL← args[Va] - args[Vc];
IF V > 0 THEN { -- forward biased
t1← V/parms[Vt];
IF t1 >= parms[expMax] THEN SIGNAL spGlobals.Retreat[
"acDiode forward biased too much"];
results[I]← -parms[Io]*(RealFns.Exp[t1]- 1.0); }
ELSE results[I]← parms[Io];
results[C]← parms[Co]/RealOps.SqRt[1.0 - V/parms[Pb]];

};
-- acDiode
spGlobals.EnterModels["CSIM", CSIM, 4, 20, 8];
spGlobals.EnterModels["acDiode", acDiode, 2, 5, 2];
spGlobals.EnterModels["dcDiode", dcDiode, 2, 3, 1];
spGlobals.EnterModels["NFET", NFET, 4, 16, 6];
spGlobals.EnterModels["PFET", PFET, 4, 16, 6];
END.
CHANGE LOG
Wilhelm, April 12, 1982 9:28 AM
Barth, 7-May-82 10:43:16 PDT
Chen, April 29, 1983 12:03 PM, added and "enter"ed CSIM and acDiode model.
Chen, June 7, 1984 8:14:49 pm PDT, cedarized.