You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1406 lines
46 KiB

/**********
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1988 Jaijeet S Roychowdhury
Modified: 2000 AlansFixes
**********/
#include "ngspice/ngspice.h"
#include "ngspice/distodef.h"
#include "ngspice/devdefs.h"
#include "ngspice/cktdefs.h"
#include "mos2defs.h"
#include "ngspice/trandefs.h"
#include "ngspice/const.h"
#include "ngspice/sperror.h"
#include "ngspice/suffix.h"
/* assuming silicon - make definition for epsilon of silicon */
#define EPSSIL (11.7 * 8.854214871e-12)
static double sig1[4] = {1.0, -1.0, 1.0, -1.0};
static double sig2[4] = {1.0, 1.0,-1.0, -1.0};
int
MOS2dSetup(GENmodel *inModel, CKTcircuit *ckt)
/* actually load the current value into the
* sparse matrix previously provided
*/
{
MOS2model *model = (MOS2model *)inModel;
MOS2instance *here;
double Beta;
double DrainSatCur;
double EffectiveLength;
double GateBulkOverlapCap;
double GateDrainOverlapCap;
double GateSourceOverlapCap;
double OxideCap;
double SourceSatCur;
double arg;
double cdrain;
double ebd;
double evbs;
double sarg;
double sargsw;
double vbd;
double vbs;
double vds;
double vdsat;
double vgb;
double vgd;
double vgs;
double von;
double vt; /* K * T / Q */
double lcapgs2;
double lcapgd2;
double lcapgb2;
double lcapgs3;
double lcapgd3;
double lcapgb3;
double lgbs, lgbs2, lgbs3;
double lgbd, lgbd2, lgbd3;
double vgst;
double lcapbs, lcapbs2, lcapbs3;
double lcapbd, lcapbd2, lcapbd3;
double gm2, gb2, gds2;
double gmb, gmds, gbds;
double gm3, gb3, gds3;
double gm2b, gm2ds, gmb2, gmds2, gbds2, gb2ds;
double gmbds;
Dderivs d_cdrain;
/* loop through all the MOS2 device models */
for( ; model != NULL; model = model->MOS2nextModel ) {
/* loop through all the instances of the model */
for (here = model->MOS2instances; here != NULL ;
here=here->MOS2nextInstance) {
vt = CONSTKoverQ * here->MOS2temp;
EffectiveLength=here->MOS2l - 2*model->MOS2latDiff;
if( (here->MOS2tSatCurDens == 0) ||
(here->MOS2drainArea == 0) ||
(here->MOS2sourceArea == 0)) {
DrainSatCur = here->MOS2m * here->MOS2tSatCur;
SourceSatCur = here->MOS2m * here->MOS2tSatCur;
} else {
DrainSatCur = here->MOS2tSatCurDens *
here->MOS2m * here->MOS2drainArea;
SourceSatCur = here->MOS2tSatCurDens *
here->MOS2m * here->MOS2sourceArea;
}
GateSourceOverlapCap = model->MOS2gateSourceOverlapCapFactor *
here->MOS2m * here->MOS2w;
GateDrainOverlapCap = model->MOS2gateDrainOverlapCapFactor *
here->MOS2m * here->MOS2w;
GateBulkOverlapCap = model->MOS2gateBulkOverlapCapFactor *
here->MOS2m * EffectiveLength;
Beta = here->MOS2tTransconductance * here->MOS2m *
here->MOS2w/EffectiveLength;
OxideCap = model->MOS2oxideCapFactor * EffectiveLength *
here->MOS2m * here->MOS2w;
/* general iteration */
vbs = model->MOS2type * (
*(ckt->CKTrhsOld+here->MOS2bNode) -
*(ckt->CKTrhsOld+here->MOS2sNodePrime));
vgs = model->MOS2type * (
*(ckt->CKTrhsOld+here->MOS2gNode) -
*(ckt->CKTrhsOld+here->MOS2sNodePrime));
vds = model->MOS2type * (
*(ckt->CKTrhsOld+here->MOS2dNodePrime) -
*(ckt->CKTrhsOld+here->MOS2sNodePrime));
/* now some common crunching for some more useful quantities */
vbd=vbs-vds;
vgd=vgs-vds;
/* now all the preliminaries are over - we can start doing the * real work
*/
vgb = vgs - vbs;
/* bulk-source and bulk-drain doides here we just evaluate
* the ideal diode current and the correspoinding
* derivative (conductance). */
if(vbs <= 0) {
lgbs = SourceSatCur/vt;
lgbs += ckt->CKTgmin;
lgbs2 = lgbs3 = 0;
} else {
evbs = exp(MIN(MAX_EXP_ARG,vbs/vt));
lgbs = SourceSatCur*evbs/vt + ckt->CKTgmin;
lgbs2 = model->MOS2type *0.5 * (lgbs - ckt->CKTgmin)/vt;
lgbs3 = model->MOS2type *lgbs2/(vt*3);
}
if(vbd <= 0) {
lgbd = DrainSatCur/vt;
lgbd += ckt->CKTgmin;
lgbd2 = lgbd3 = 0;
} else {
ebd = exp(MIN(MAX_EXP_ARG,vbd/vt));
lgbd = DrainSatCur*ebd/vt +ckt->CKTgmin;
lgbd2 = model->MOS2type *0.5 * (lgbd - ckt->CKTgmin)/vt;
lgbd3 = model->MOS2type *lgbd2/(vt*3);
}
if(vds >= 0) {
/* normal mode */
here->MOS2mode = 1;
} else {
/* inverse mode */
here->MOS2mode = -1;
}
{
/* moseq2(vds,vbs,vgs,gm,gds,gmbs,qg,qc,qb,
* cggb,cgdb,cgsb,cbgb,cbdb,cbsb)
*/
/* note: cgdb, cgsb, cbdb, cbsb never used */
/*
* this routine evaluates the drain current, its derivatives and * the charges associated with the gate, channel and bulk * for mosfets *
*/
double arg;
double sarg;
double a4[4],b4[4],x4[8],poly4[8];
double beta1;
double sphi = 0.0; /* square root of phi */
double sphi3 = 0.0; /* square root of phi cubed */
double barg;
double factor;
double eta;
double vbin;
double argd = 0.0;
double args = 0.0;
double argss;
double argsd;
double argxs;
double argxd;
double gamasd;
double xwd;
double xws;
double gammad;
double cfs;
double cdonco;
double xn;
double argg = 0.0;
double sarg3;
double sbiarg;
double body;
double udenom;
double gammd2;
double argv;
double vgsx;
double ufact;
double ueff;
double a1;
double a3;
double a;
double b1;
double b3;
double b;
double c1;
double c;
double d1;
double fi;
double p0;
double p2;
double p3;
double p4;
double p;
double r3;
double r;
double ro;
double s2;
double s;
double v1;
double v2;
double xv;
double y3;
double delta4;
double xvalid = 0.0;
double bsarg;
double bodys;
double sargv;
double xlfact;
double xdv;
double xlv;
double xls;
double clfact;
double xleff;
double deltal;
double xwb;
double vdson;
double cdson;
double expg;
double xld;
double xlamda = model->MOS2lambda;
Dderivs d_xleff, d_delta1;
Dderivs d_xlfact;
Dderivs d_xlv, d_xls;
Dderivs d_bsarg, d_bodys, d_vdsat, d_sargv;
Dderivs d_delta4, d_a4[3], d_b4[3], d_x4[3], d_poly4[3];
Dderivs d_xvalid;
Dderivs d_ro, d_fi, d_y3, d_p3, d_p4, d_a3, d_b3;
Dderivs d_r3, d_s2, d_pee, d_p0, d_p2;
Dderivs d_b1, d_c1, d_d1, d_a, d_b, d_c, d_arr, d_s;
Dderivs d_xv, d_a1;
Dderivs d_v1, d_v2;
Dderivs d_argv,d_gammd2;
Dderivs d_ufact;
Dderivs d_udenom;
Dderivs d_sarg3, d_body;
Dderivs d_vgst;
Dderivs d_argg;
Dderivs d_cdonco,d_tmp,d_xn;
Dderivs d_dbargs,d_dbargd,d_dgddvb;
Dderivs d_dbxwd,d_dbxws;
Dderivs d_dsrgdb, d_dbrgdb;
Dderivs d_gamasd, d_gammad, d_args, d_argd;
Dderivs d_argxs, d_argxd;
Dderivs d_argss, d_argsd;
Dderivs d_xwd, d_xws;
Dderivs d_zero;
Dderivs d_vbin;
Dderivs d_barg;
Dderivs d_sarg;
Dderivs d_phiMinVbs;
Dderivs d_p, d_q, d_r;
Dderivs d_von, d_dummy, d_vgsx, d_arg, d_dumarg;
Dderivs d_ueff, d_beta1, d_clfact, d_xlamda,d_mos2gds;
Dderivs d_vdson, d_cdson, d_expg;
double dsrgdb, dbrgdb, dbxwd, dbxws, dbargs = 0.0, dbargd = 0.0;
double dgddvb;
/* from now on, p=vgs, q=vbs, r=vds */
/*
* 'local' variables - these switch d & s around appropriately
* so that we don't have to worry about vds < 0
*/
double lvbs = here->MOS2mode==1?vbs:vbd;
double lvds = here->MOS2mode*vds;
double lvgs = here->MOS2mode==1?vgs:vgd;
double phiMinVbs = here->MOS2tPhi - lvbs;
double tmp; /* a temporary variable, not used for more than */
/* about 10 lines at a time */
int iknt;
int jknt;
int i;
int j;
/*
* compute some useful quantities
*/
d_p.value = 0.0;
d_p.d1_p = 1.0;
d_p.d1_q = 0.0;
d_p.d1_r = 0.0;
d_p.d2_p2 = 0.0;
d_p.d2_q2 = 0.0;
d_p.d2_r2 = 0.0;
d_p.d2_pq = 0.0;
d_p.d2_qr = 0.0;
d_p.d2_pr = 0.0;
d_p.d3_p3 = 0.0;
d_p.d3_q3 = 0.0;
d_p.d3_r3 = 0.0;
d_p.d3_p2r = 0.0;
d_p.d3_p2q = 0.0;
d_p.d3_q2r = 0.0;
d_p.d3_pq2 = 0.0;
d_p.d3_pr2 = 0.0;
d_p.d3_qr2 = 0.0;
d_p.d3_pqr = 0.0;
EqualDeriv(&d_q,&d_p);
EqualDeriv(&d_r,&d_p);
EqualDeriv(&d_zero,&d_p);
d_q.d1_p = d_r.d1_p = d_zero.d1_p = 0.0;
d_q.d1_q = d_r.d1_r = 1.0;
EqualDeriv(&d_phiMinVbs,&d_q);
d_phiMinVbs.value = phiMinVbs;
d_phiMinVbs.d1_q = - d_phiMinVbs.d1_q;
if (lvbs <= 0.0) {
sarg = sqrt(phiMinVbs);
SqrtDeriv(&d_sarg, &d_phiMinVbs);
dsrgdb = -0.5/sarg;
InvDeriv(&d_dsrgdb,&d_sarg);
TimesDeriv(&d_dsrgdb,&d_dsrgdb,-0.5);
} else {
sphi = sqrt(here->MOS2tPhi); /*const*/
sphi3 = here->MOS2tPhi*sphi; /*const*/
sarg = sphi/(1.0+0.5*lvbs/here->MOS2tPhi);
EqualDeriv(&d_sarg,&d_q); d_sarg.value = lvbs;
TimesDeriv(&d_sarg,&d_sarg,0.5/here->MOS2tPhi);
d_sarg.value += 1.0;
InvDeriv(&d_sarg,&d_sarg);
TimesDeriv(&d_sarg,&d_sarg,sphi);
dsrgdb = -0.5*sarg*sarg/sphi3;
MultDeriv(&d_dsrgdb,&d_sarg,&d_sarg);
TimesDeriv(&d_dsrgdb,&d_dsrgdb,-0.5/sphi3);
/* tmp = sarg/sphi3; */
}
if ((lvds-lvbs) >= 0) {
barg = sqrt(phiMinVbs+lvds);
EqualDeriv(&d_barg,&d_phiMinVbs);
d_barg.value += lvds; d_barg.d1_r += 1.0;
SqrtDeriv(&d_barg,&d_barg);
dbrgdb = -0.5/barg;
InvDeriv(&d_dbrgdb,&d_barg);
TimesDeriv(&d_dbrgdb,&d_dbrgdb,-0.5);
} else {
sphi = sqrt(here->MOS2tPhi); /* added by HT 050523 */
sphi3 = here->MOS2tPhi*sphi; /* added by HT 050523 */
barg = sphi/(1.0+0.5*(lvbs-lvds)/here->MOS2tPhi);
EqualDeriv(&d_barg,&d_q); d_barg.value = lvbs - lvds;
d_barg.d1_r -= 1.0;
TimesDeriv(&d_barg,&d_barg,0.5/here->MOS2tPhi);
d_barg.value += 1.0;
InvDeriv(&d_barg,&d_barg);
TimesDeriv(&d_barg,&d_barg,sphi);
dbrgdb = -0.5*barg*barg/sphi3;
MultDeriv(&d_dbrgdb,&d_barg,&d_barg);
TimesDeriv(&d_dbrgdb,&d_dbrgdb,-0.5/sphi3);
/* tmp = barg/sphi3; */
}
/*
* calculate threshold voltage (von)
* narrow-channel effect
*/
/*XXX constant per device */
factor = 0.125*model->MOS2narrowFactor*2.0*M_PI*EPSSIL/
OxideCap*EffectiveLength;
/*XXX constant per device */
eta = 1.0+factor;
vbin = here->MOS2tVbi*model->MOS2type+factor*phiMinVbs;
/* mistake! fixed Dec 7 '89
TimesDeriv(&d_vbin,&d_phiMinVbs,here->MOS2tVbi*
model->MOS2type+factor);
*/
TimesDeriv(&d_vbin,&d_phiMinVbs,factor);
d_vbin.value += here->MOS2tVbi*model->MOS2type;
if ((model->MOS2gamma > 0.0) ||
(model->MOS2substrateDoping > 0.0)) {
xwd = model->MOS2xd*barg;
xws = model->MOS2xd*sarg;
TimesDeriv(&d_xwd,&d_barg,model->MOS2xd);
TimesDeriv(&d_xws,&d_sarg,model->MOS2xd);
/*
* short-channel effect with vds .ne. 0.0 */
argss = 0.0;
argsd = 0.0;
EqualDeriv(&d_argss,&d_zero);
EqualDeriv(&d_argsd,&d_zero);
if (model->MOS2junctionDepth > 0) {
tmp = 2.0/model->MOS2junctionDepth; /*const*/
argxs = 1.0+xws*tmp;
TimesDeriv(&d_argxs,&d_xws,tmp);
d_argxs.value += 1.0;
argxd = 1.0+xwd*tmp;
TimesDeriv(&d_argxd,&d_xwd,tmp);
d_argxd.value += 1.0;
args = sqrt(argxs);
SqrtDeriv(&d_args,&d_argxs);
argd = sqrt(argxd);
SqrtDeriv(&d_argd,&d_argxd);
tmp = .5*model->MOS2junctionDepth/EffectiveLength;
argss = tmp * (args-1.0);
TimesDeriv(&d_argss,&d_args,tmp);
d_argss.value -= tmp;
argsd = tmp * (argd-1.0);
TimesDeriv(&d_argsd,&d_argd,tmp);
d_argsd.value -= tmp;
}
gamasd = model->MOS2gamma*(1.0-argss-argsd);
PlusDeriv(&d_gamasd,&d_argss,&d_argsd);
d_gamasd.value -= 1.0;
TimesDeriv(&d_gamasd,&d_gamasd,-model->MOS2gamma);
dbxwd = model->MOS2xd*dbrgdb;
dbxws = model->MOS2xd*dsrgdb;
TimesDeriv(&d_dbxwd,&d_dbrgdb,model->MOS2xd);
TimesDeriv(&d_dbxws,&d_dsrgdb,model->MOS2xd);
if (model->MOS2junctionDepth > 0) {
tmp = 0.5/EffectiveLength;
dbargs = tmp*dbxws/args;
dbargd = tmp*dbxwd/argd;
DivDeriv(&d_dbargs,&d_dbxws,&d_args);
DivDeriv(&d_dbargd,&d_dbxwd,&d_argd);
TimesDeriv(&d_dbargs,&d_dbargs,tmp);
TimesDeriv(&d_dbargd,&d_dbargd,tmp);
}
dgddvb = -model->MOS2gamma*(dbargs+dbargd);
PlusDeriv(&d_dgddvb,&d_dbargs,&d_dbargd);
TimesDeriv(&d_dgddvb,&d_dgddvb,-model->MOS2gamma);
if (model->MOS2junctionDepth > 0) {
}
} else {
gamasd = model->MOS2gamma;
gammad = model->MOS2gamma;
EqualDeriv(&d_gamasd,&d_zero);
EqualDeriv(&d_gammad,&d_zero);
d_gamasd.value = d_gammad.value = model->MOS2gamma;
dgddvb = 0.0;
EqualDeriv(&d_dgddvb,&d_zero);
}
von = vbin+gamasd*sarg;
MultDeriv(&d_von,&d_gamasd,&d_sarg);
PlusDeriv(&d_von,&d_von,&d_vbin);
/*
vth = von;
EqualDeriv(&d_vth,&d_von);
*/
vdsat = 0.0;
EqualDeriv(&d_vdsat,&d_zero);
if (model->MOS2fastSurfaceStateDensity != 0.0 && OxideCap != 0.0) {
/* XXX constant per model */
cfs = CHARGE*model->MOS2fastSurfaceStateDensity*
1e4 /*(cm**2/m**2)*/;
cdonco = -(gamasd*dsrgdb + dgddvb*sarg) + factor;
MultDeriv(&d_dummy,&d_dgddvb,&d_sarg);
MultDeriv(&d_cdonco,&d_gamasd,&d_dsrgdb);
PlusDeriv(&d_cdonco,&d_cdonco,&d_dummy);
TimesDeriv(&d_cdonco,&d_cdonco,-1.0);
d_cdonco.value += factor;
xn = 1.0+cfs/OxideCap*here->MOS2m*here->MOS2w*EffectiveLength+cdonco;
EqualDeriv(&d_xn,&d_cdonco);
d_xn.value = xn;
tmp = vt*xn;
TimesDeriv(&d_tmp,&d_xn,vt);
von = von+tmp;
PlusDeriv(&d_von,&d_von,&d_tmp);
argg = 1.0/tmp;
InvDeriv(&d_argg,&d_tmp);
vgst = lvgs-von;
TimesDeriv(&d_vgst,&d_von,-1.0);
PlusDeriv(&d_vgst,&d_vgst,&d_p);
d_vgst.value += lvgs;
} else {
vgst = lvgs-von;
TimesDeriv(&d_vgst,&d_von,-1.0);
PlusDeriv(&d_vgst,&d_vgst,&d_p);
d_vgst.value += lvgs;
if (lvgs <= von) {
/*
* cutoff region */
here->MOS2gds = 0.0; /* look at this later */
goto line1050;
}
}
/*
* compute some more useful quantities */
sarg3 = sarg*sarg*sarg;
CubeDeriv(&d_sarg3,&d_sarg);
/* XXX constant per model */
sbiarg = sqrt(here->MOS2tBulkPot); /*const*/
gammad = gamasd;
EqualDeriv(&d_gammad,&d_gamasd);
body = barg*barg*barg-sarg3;
TimesDeriv(&d_body,&d_sarg3,-1.0);
CubeDeriv(&d_dummy,&d_barg);
PlusDeriv(&d_body,&d_body,&d_dummy);
if (model->MOS2fastSurfaceStateDensity == 0.0) goto line400;
if (OxideCap == 0.0) goto line410;
/*
* evaluate effective mobility and its derivatives */
line400:
if (OxideCap <= 0.0) goto line410;
udenom = vgst;
EqualDeriv(&d_udenom,&d_vgst);
tmp = model->MOS2critField * 100 /* cm/m */ * EPSSIL/
model->MOS2oxideCapFactor;
if (udenom <= tmp) goto line410;
ufact = exp(model->MOS2critFieldExp*log(tmp/udenom));
/* dummy = tmp/udenom */
InvDeriv(&d_dummy,&d_udenom);
TimesDeriv(&d_dummy,&d_dummy,tmp);
PowDeriv(&d_ufact,&d_dummy,model->MOS2critFieldExp);
ueff = model->MOS2surfaceMobility * 1e-4 /*(m**2/cm**2) */ *ufact;
TimesDeriv(&d_ueff,&d_ufact,model->MOS2surfaceMobility * 1e-4);
goto line500;
line410:
ufact = 0.0;
EqualDeriv(&d_ufact,&d_zero);
ueff = model->MOS2surfaceMobility * 1e-4 /*(m**2/cm**2) */ ;
EqualDeriv(&d_ueff,&d_zero);
d_ueff.value = ueff;
/*
* evaluate saturation voltage and its derivatives according to
* grove-frohman equation */
line500:
vgsx = lvgs;
EqualDeriv(&d_vgsx,&d_p); d_vgsx.value = lvgs;
gammad = gamasd/eta; /* eta is a constant */
TimesDeriv(&d_gammad,&d_gamasd,1/eta);
if (model->MOS2fastSurfaceStateDensity != 0 && OxideCap != 0) {
vgsx = MAX(lvgs,von);
/* mistake! fixed Dec 8 '89 if (vgsx < von) { } */
if (lvgs > von) {
EqualDeriv(&d_vgsx,&d_p);d_vgsx.value = lvgs;
} else {
EqualDeriv(&d_vgsx,&d_von);
}
}
if (gammad > 0) {
gammd2 = gammad*gammad;
MultDeriv(&d_gammd2,&d_gammad,&d_gammad);
argv = (vgsx-vbin)/eta+phiMinVbs;
TimesDeriv(&d_argv,&d_vbin,-1.0);
PlusDeriv(&d_argv,&d_vgsx,&d_vgsx);
TimesDeriv(&d_argv,&d_argv,1/eta);
PlusDeriv(&d_argv,&d_argv,&d_phiMinVbs);
if (argv <= 0.0) {
vdsat = 0.0;
EqualDeriv(&d_vdsat,&d_zero);
} else {
arg = sqrt(1.0+4.0*argv/gammd2);
DivDeriv(&d_arg,&d_argv,&d_gammd2);
TimesDeriv(&d_arg,&d_arg,4.0);d_arg.value += 1.0;
SqrtDeriv(&d_arg,&d_arg);
#if 0
dumarg= sqrt(gammd2*gammd2 +4*argv*gammd2);
TimesDeriv(&d_dumarg,&d_argv,4.0);
PlusDeriv(&d_dumarg,&d_dumarg,&d_gammd2);
MultDeriv(&d_dumarg,&d_dumarg,&d_gammd2);
SqrtDeriv(&d_dumarg,&d_dumarg);
vdsat = (vgsx-vbin)/eta+gammd2*(1.0-arg)/2.0;
/* distortion vdsat=(vgsx-vbin)/eta + (gammd2 - dumarg)/2.0
= argv - phiMinVbs + (gammd2 - dumarg)/2 */
#endif
TimesDeriv(&d_dummy,&d_dumarg,-1.0);
PlusDeriv(&d_dummy,&d_dummy,&d_gammd2);
TimesDeriv(&d_dummy,&d_dummy,0.5);
TimesDeriv(&d_vdsat,&d_phiMinVbs,-1.0);
PlusDeriv(&d_vdsat,&d_vdsat,&d_argv);
PlusDeriv(&d_vdsat,&d_dummy,&d_vdsat);
vdsat = MAX(vdsat,0.0);
if (vdsat < 0.0) {
EqualDeriv(&d_vdsat,&d_zero);
}
}
} else {
vdsat = (vgsx-vbin)/eta;
TimesDeriv(&d_vdsat,&d_vbin,-1.0);
PlusDeriv(&d_vdsat,&d_vgsx,&d_vdsat);
TimesDeriv(&d_vdsat,&d_vdsat,1/eta);
vdsat = MAX(vdsat,0.0);
if (vdsat < 0.0) {
EqualDeriv(&d_vdsat,&d_zero);
}
}
if (model->MOS2maxDriftVel > 0) {
/*
* evaluate saturation voltage and its derivatives
* according to baum's theory of scattering velocity
* saturation
*/
gammd2 = gammad*gammad;
MultDeriv(&d_gammd2,&d_gammad,&d_gammad);
v1 = (vgsx-vbin)/eta+phiMinVbs;
TimesDeriv(&d_v1,&d_vbin,-1.0);
#if 0
/* mistake ! (fixed Dec 7 '89) thanks to Jean Hsu */
PlusDeriv(&d_v1,&d_vgsx,&d_vgsx);
#endif
PlusDeriv(&d_v1,&d_v1,&d_vgsx);
TimesDeriv(&d_v1,&d_v1,1/eta);
PlusDeriv(&d_v1,&d_v1,&d_phiMinVbs);
v2 = phiMinVbs;
EqualDeriv(&d_v2,&d_phiMinVbs);
xv = model->MOS2maxDriftVel*EffectiveLength/ueff;
InvDeriv(&d_xv,&d_ueff);
TimesDeriv(&d_xv,&d_xv,model->MOS2maxDriftVel*EffectiveLength);
a1 = gammad/0.75;
TimesDeriv(&d_a1,&d_gammad,4.0/3.0);
/* dummy1 = a1 */
b1 = -2.0*(v1+xv);
PlusDeriv(&d_b1,&d_v1,&d_xv);
TimesDeriv(&d_b1,&d_b1,-2.0);
/* dummy2 = b1 */
c1 = -2.0*gammad*xv;
MultDeriv(&d_c1,&d_gammad,&d_xv);
TimesDeriv(&d_c1,&d_c1,-2.0);
/* dummy3 = c1 */
d1 = 2.0*v1*(v2+xv)-v2*v2-4.0/3.0*gammad*sarg3;
MultDeriv(&d_d1,&d_gammad,&d_sarg3);
TimesDeriv(&d_d1,&d_d1,4.0/3.0);
MultDeriv(&d_dummy,&d_v2,&d_v2);
PlusDeriv(&d_d1,&d_d1,&d_dummy);
TimesDeriv(&d_d1,&d_d1,-1.0);
PlusDeriv(&d_dummy,&d_v2,&d_xv);
MultDeriv(&d_dummy,&d_dummy,&d_v1);
TimesDeriv(&d_dummy,&d_dummy,2.0);
PlusDeriv(&d_d1,&d_d1,&d_dummy);
a = -b1;
TimesDeriv(&d_a,&d_b1,-1.0);
b = a1*c1-4.0*d1;
TimesDeriv(&d_b,&d_d1,-4.0);
MultDeriv(&d_dummy,&d_a1,&d_c1);
/* mistake! - fixed Dec 8 '89
PlusDeriv(&d_d1,&d_d1,&d_dummy);
*/
PlusDeriv(&d_b,&d_b,&d_dummy);
c = -d1*(a1*a1-4.0*b1)-c1*c1;
TimesDeriv(&d_dummy,&d_b1,-4.0);
MultDeriv(&d_c,&d_a1,&d_a1);
PlusDeriv(&d_dummy,&d_dummy,&d_c);
MultDeriv(&d_c,&d_dummy,&d_d1);
MultDeriv(&d_dummy,&d_c1,&d_c1);
PlusDeriv(&d_c,&d_c,&d_dummy);
TimesDeriv(&d_c,&d_c,-1.0);
r = -a*a/3.0+b;
MultDeriv(&d_arr,&d_a,&d_a);
TimesDeriv(&d_arr,&d_arr,-1.0/3.0);
PlusDeriv(&d_arr,&d_arr,&d_b);
s = 2.0*a*a*a/27.0-a*b/3.0+c;
CubeDeriv(&d_s,&d_a);
TimesDeriv(&d_s,&d_s,2.0/27.0);
PlusDeriv(&d_s,&d_s,&d_c);
MultDeriv(&d_dummy,&d_a,&d_b);
TimesDeriv(&d_dummy,&d_dummy,-1.0/3.0);
PlusDeriv(&d_s,&d_s,&d_dummy);
r3 = r*r*r;
CubeDeriv(&d_r3,&d_arr);
s2 = s*s;
MultDeriv(&d_s2,&d_s,&d_s);
p = s2/4.0+r3/27.0;
TimesDeriv(&d_dummy,&d_r3,1.0/27.0);
TimesDeriv(&d_pee,&d_s2,0.25);
PlusDeriv(&d_pee,&d_pee,&d_dummy);
p0 = fabs(p);
if (p < 0.0)
/* mistake! fixed Dec 8 '89
TimesDeriv(&d_pee,&d_pee, -1.0);
*/
TimesDeriv(&d_p0,&d_pee, -1.0);
p2 = sqrt(p0);
SqrtDeriv(&d_p2,&d_p0);
if (p < 0) {
ro = sqrt(s2/4.0+p0);
ro = log(ro)/3.0;
ro = exp(ro);
/* the above is eqvt. to
ro = (s2/4.0 + p0)^1/6; */
TimesDeriv(&d_ro,&d_s2,0.25);
PlusDeriv(&d_ro,&d_ro,&d_p0);
PowDeriv(&d_ro,&d_ro,1.0/6.0);
fi = atan(-2.0*p2/s);
DivDeriv(&d_fi,&d_p2,&d_s);
TimesDeriv(&d_fi,&d_fi,-2.0);
AtanDeriv(&d_fi,&d_fi);
y3 = 2.0*ro*cos(fi/3.0)-a/3.0;
TimesDeriv(&d_dummy,&d_fi,1.0/3.0);
CosDeriv(&d_dummy,&d_dummy);
MultDeriv(&d_y3,&d_ro,&d_dummy);
TimesDeriv(&d_y3,&d_y3,2.0);
/* mistake! fixed Dec 8 '89
TimesDeriv(&d_dummy,&d_a,-3.0);
*/
TimesDeriv(&d_dummy,&d_a,-1/3.0);
PlusDeriv(&d_y3,&d_y3,&d_dummy);
} else {
p3 = (-s/2.0+p2);
TimesDeriv(&d_p3,&d_s,-0.5);
PlusDeriv(&d_p3,&d_p3,&d_p2);
p3 = exp(log(fabs(p3))/3.0);
/* eqvt. to (fabs(p3)) ^ 1/3 */
if (p3 < 0.0)
TimesDeriv(&d_p3,&d_p3,-1.0);
PowDeriv(&d_p3,&d_p3,1.0/3.0);
p4 = (-s/2.0-p2);
TimesDeriv(&d_p4,&d_s,0.5);
PlusDeriv(&d_p4,&d_p4,&d_p2);
if (p4 < 0.0)
TimesDeriv(&d_p4,&d_p4,-1.0); /* this is fabs(p4) */
p4 = exp(log(fabs(p4))/3.0);
PowDeriv(&d_p4,&d_p4,1.0/3.0);
y3 = p3+p4-a/3.0;
TimesDeriv(&d_y3,&d_a,-1.0/3.0);
PlusDeriv(&d_y3,&d_y3,&d_p4);
PlusDeriv(&d_y3,&d_y3,&d_p3);
}
iknt = 0;
a3 = sqrt(a1*a1/4.0-b1+y3);
MultDeriv(&d_a3,&d_a1,&d_a1);
TimesDeriv(&d_a3,&d_a3,0.25);
PlusDeriv(&d_a3,&d_a3,&d_y3);
TimesDeriv(&d_dummy,&d_b1,-1.0);
PlusDeriv(&d_a3,&d_a3,&d_dummy);
SqrtDeriv(&d_a3,&d_a3);
b3 = sqrt(y3*y3/4.0-d1);
MultDeriv(&d_b3,&d_y3,&d_y3);
TimesDeriv(&d_b3,&d_b3,0.25);
TimesDeriv(&d_dummy,&d_d1,-1.0);
PlusDeriv(&d_b3,&d_b3,&d_dummy);
SqrtDeriv(&d_b3,&d_b3);
for(i = 1;i<=4;i++) {
a4[i-1] = a1/2.0+sig1[i-1]*a3;
TimesDeriv(&d_a4[i-1],&d_a1,0.5);
TimesDeriv(&d_dummy,&d_a3,sig1[i-1]);
PlusDeriv(&d_a4[i-1],&d_a4[i-1],&d_dummy);
b4[i-1] = y3/2.0+sig2[i-1]*b3;
TimesDeriv(&d_b4[i-1],&d_y3,0.5);
TimesDeriv(&d_dummy,&d_b3,sig2[i-1]);
PlusDeriv(&d_b4[i-1],&d_b4[i-1],&d_dummy);
delta4 = a4[i-1]*a4[i-1]/4.0-b4[i-1];
MultDeriv(&d_delta4,&d_a4[i-1],&d_a4[i-1]);
TimesDeriv(&d_delta4,&d_delta4,0.25);
TimesDeriv(&d_dummy,&d_b4[i-1],-1.0);
PlusDeriv(&d_delta4,&d_delta4,&d_dummy);
if (delta4 < 0) continue;
iknt = iknt+1;
tmp = sqrt(delta4);
SqrtDeriv(&d_tmp,&d_delta4);
x4[iknt-1] = -a4[i-1]/2.0+tmp;
TimesDeriv(&d_x4[iknt-1],&d_a4[i-1],-0.5);
PlusDeriv(&d_x4[iknt-1],&d_x4[iknt-1],&d_tmp);
iknt = iknt+1;
x4[iknt-1] = -a4[i-1]/2.0-tmp;
TimesDeriv(&d_x4[iknt-1],&d_a4[i-1],-0.5);
PlusDeriv(&d_x4[iknt-1],&d_x4[iknt-1],&d_tmp);
}
jknt = 0;
for(j = 1;j<=iknt;j++) {
if (x4[j-1] <= 0) continue;
/* XXX implement this sanely */
poly4[j-1] = x4[j-1]*x4[j-1]*x4[j-1]*x4[j-1]+a1*x4[j-1]*
x4[j-1]*x4[j-1];
CubeDeriv(&d_dummy,&d_x4[j-1]);
PlusDeriv(&d_poly4[j-1],&d_x4[j-1],&d_a1);
MultDeriv(&d_poly4[j-1],&d_poly4[j-1],&d_dummy);
poly4[j-1] = poly4[j-1]+b1*x4[j-1]*x4[j-1]+c1*x4[j-1]+d1;
PlusDeriv(&d_poly4[j-1],&d_poly4[j-1],&d_d1);
MultDeriv(&d_dummy,&d_b1,&d_x4[j-1]);
PlusDeriv(&d_dummy,&d_dummy,&d_c1);
MultDeriv(&d_dummy,&d_dummy,&d_x4[j-1]);
PlusDeriv(&d_poly4[j-1],&d_poly4[j-1],&d_dummy);
if (fabs(poly4[j-1]) > 1.0e-6) continue;
jknt = jknt+1;
if (jknt <= 1) {
xvalid = x4[j-1];
EqualDeriv(&d_xvalid,&d_x4[j-1]);
}
if (x4[j-1] > xvalid) continue;
xvalid = x4[j-1];
EqualDeriv(&d_xvalid,&d_x4[j-1]);
}
if (jknt > 0) {
vdsat = xvalid*xvalid-phiMinVbs;
MultDeriv(&d_vdsat,&d_xvalid,&d_xvalid);
TimesDeriv(&d_dummy,&d_phiMinVbs,-1.0);
PlusDeriv(&d_vdsat,&d_vdsat,&d_dummy);
}
}
/*
* evaluate effective channel length and its derivatives */
if (lvds != 0.0) {
gammad = gamasd;
EqualDeriv(&d_gammad,&d_gamasd);
if ((lvbs-vdsat) <= 0) {
bsarg = sqrt(vdsat+phiMinVbs);
PlusDeriv(&d_bsarg,&d_vdsat,&d_phiMinVbs);
SqrtDeriv(&d_bsarg,&d_bsarg);
} else {
bsarg = sphi/(1.0+0.5*(lvbs-vdsat)/here->MOS2tPhi);
TimesDeriv(&d_bsarg,&d_vdsat,-1.0);
d_bsarg.value += lvbs; d_bsarg.d1_r += 1.0;
TimesDeriv(&d_bsarg,&d_bsarg,0.5/here->MOS2tPhi);
d_bsarg.value += 1.0;
InvDeriv(&d_bsarg,&d_bsarg);
TimesDeriv(&d_bsarg,&d_bsarg,sphi);
}
bodys = bsarg*bsarg*bsarg-sarg3;
CubeDeriv(&d_bodys,&d_bsarg);
TimesDeriv(&d_dummy,&d_sarg3,-1.0);
PlusDeriv(&d_bodys,&d_bodys,&d_dummy);
if (model->MOS2maxDriftVel <= 0) {
if (model->MOS2substrateDoping == 0.0) goto line610;
if (xlamda > 0.0) goto line610;
argv = (lvds-vdsat)/4.0;
TimesDeriv(&d_argv,&d_vdsat,-1.0);
d_argv.value += lvds; d_argv.d1_r += 1.0;
TimesDeriv(&d_argv,&d_argv,0.25);
sargv = sqrt(1.0+argv*argv);
MultDeriv(&d_sargv,&d_argv,&d_argv);
d_sargv.value += 1.0;
SqrtDeriv(&d_sargv,&d_sargv);
arg = sqrt(argv+sargv);
PlusDeriv(&d_arg,&d_sargv,&d_argv);
SqrtDeriv(&d_arg,&d_arg);
xlfact = model->MOS2xd/(EffectiveLength*lvds);
EqualDeriv(&d_xlfact,&d_r); d_xlfact.value = lvds;
InvDeriv(&d_xlfact,&d_xlfact);
TimesDeriv(&d_xlfact,&d_xlfact,model->MOS2xd/EffectiveLength);
xlamda = xlfact*arg;
MultDeriv(&d_xlamda,&d_xlfact,&d_arg);
} else {
argv = (vgsx-vbin)/eta-vdsat;
TimesDeriv(&d_argv,&d_vbin,-1.0);
PlusDeriv(&d_argv,&d_argv,&d_vgsx);
TimesDeriv(&d_argv,&d_argv,1/eta);
TimesDeriv(&d_dummy,&d_vdsat,-1.0);
PlusDeriv(&d_argv,&d_argv,&d_dummy);
xdv = model->MOS2xd/sqrt(model->MOS2channelCharge); /*const*/
xlv = model->MOS2maxDriftVel*xdv/(2.0*ueff);
InvDeriv(&d_xlv,&d_ueff);
TimesDeriv(&d_xlv,&d_xlv,model->MOS2maxDriftVel*xdv*0.5);
/* retained for historical interest
vqchan = argv-gammad*bsarg;
MultDeriv(&d_vqchan,&d_gammad,&d_bsarg);
TimesDeriv(&d_vqchan,&d_vqchan,-1);
PlusDeriv(&d_vqchan,&d_vqchan,&d_argv);
*/
/* gammad = gamasd
vl = model->MOS2maxDriftVel*EffectiveLength;const*/
if (model->MOS2substrateDoping == 0.0) goto line610;
if (xlamda > 0.0) goto line610;
argv = lvds-vdsat;
TimesDeriv(&d_argv,&d_vdsat,-1.0);
d_argv.value += lvds;
d_argv.d1_r += 1.0;
if (argv < 0.0)
EqualDeriv(&d_argv,&d_zero);
argv = MAX(argv,0.0);
xls = sqrt(xlv*xlv+argv);
MultDeriv(&d_xls,&d_xlv,&d_xlv);
PlusDeriv(&d_xls,&d_xls,&d_argv);
SqrtDeriv(&d_xls,&d_xls);
/* dummy9 = xlv*xlv + argv */
xlfact = xdv/(EffectiveLength*lvds);
EqualDeriv(&d_xlfact,&d_r);
d_xlfact.value += lvds;
InvDeriv(&d_xlfact,&d_xlfact);
TimesDeriv(&d_xlfact,&d_xlfact,xdv/EffectiveLength);
xlamda = xlfact*(xls-xlv);
TimesDeriv(&d_xlamda,&d_xlv,-1.0);
PlusDeriv(&d_xlamda,&d_xlamda,&d_xls);
MultDeriv(&d_xlamda,&d_xlamda,&d_xlfact);
}
}
line610:
/*
* limit channel shortening at punch-through */
xwb = model->MOS2xd*sbiarg; /*const*/
xld = EffectiveLength-xwb; /*const*/
clfact = 1.0-xlamda*lvds;
EqualDeriv(&d_clfact,&d_r); d_clfact.value = lvds;
d_clfact.d1_r = -1;
MultDeriv(&d_clfact,&d_clfact,&d_xlamda);
d_clfact.value += 1.0;
xleff = EffectiveLength*clfact;
TimesDeriv(&d_xleff,&d_clfact,EffectiveLength);
deltal = xlamda*lvds*EffectiveLength;
EqualDeriv(&d_delta1,&d_r);
d_delta1.value = EffectiveLength*lvds;
d_delta1.d1_r = EffectiveLength;
MultDeriv(&d_delta1,&d_delta1,&d_xlamda);
if (model->MOS2substrateDoping == 0.0) xwb = 0.25e-6;
if (xleff < xwb) {
xleff = xwb/(1.0+(deltal-xld)/xwb);
EqualDeriv(&d_xleff,&d_delta1);d_xleff.value -= xld;
TimesDeriv(&d_xleff,&d_xleff,1/xwb);d_xleff.value += 1.0;
InvDeriv(&d_xleff,&d_xleff);
TimesDeriv(&d_xleff,&d_xleff,xwb);
clfact = xleff/EffectiveLength;
TimesDeriv(&d_clfact,&d_xleff,1/EffectiveLength);
/* dfact = xleff*xleff/(xwb*xwb); */
}
/*
* evaluate effective beta (effective kp)
*/
beta1 = Beta*ufact/clfact;
DivDeriv(&d_beta1,&d_ufact,&d_clfact);
TimesDeriv(&d_beta1,&d_beta1,Beta);
/*
* test for mode of operation and branch appropriately */
gammad = gamasd;
EqualDeriv(&d_gammad,&d_gamasd);
if (lvds <= 1.0e-10) {
if (lvgs <= von) {
if ((model->MOS2fastSurfaceStateDensity == 0.0) ||
(OxideCap == 0.0)) {
here->MOS2gds = 0.0;
d_cdrain.d1_q = 0.0;
d_cdrain.d2_q2 = 0.0;
d_cdrain.d3_q3 = 0.0;
goto line1050;
}
here->MOS2gds = beta1*(von-vbin-gammad*sarg)*exp(argg*
(lvgs-von));
MultDeriv(&d_dummy,&d_gammad,&d_sarg);
PlusDeriv(&d_dummy,&d_dummy,&d_vbin);
TimesDeriv(&d_dummy,&d_dummy,-1.0);
PlusDeriv(&d_dummy,&d_dummy,&d_von);
MultDeriv(&d_mos2gds,&d_beta1,&d_dummy);
TimesDeriv(&d_dummy,&d_von,-1.0);
PlusDeriv(&d_dummy,&d_dummy,&d_p);
d_dummy.value += lvgs;
MultDeriv(&d_dummy,&d_dummy,&d_argg);
ExpDeriv(&d_dummy,&d_dummy);
MultDeriv(&d_mos2gds,&d_mos2gds,&d_dummy);
d_cdrain.d1_r = d_mos2gds.value;
d_cdrain.d2_r2 = d_mos2gds.d1_r;
d_cdrain.d3_r3 = d_mos2gds.d2_r2;
/* dummy1 = von - vbin - gamasd*sarg */
goto line1050;
}
here->MOS2gds = beta1*(lvgs-vbin-gammad*sarg);
MultDeriv(&d_mos2gds,&d_gammad,&d_sarg);
PlusDeriv(&d_mos2gds,&d_mos2gds,&d_vbin);
TimesDeriv(&d_mos2gds,&d_mos2gds,-1.0);
MultDeriv(&d_mos2gds,&d_mos2gds,&d_beta1);
d_cdrain.d1_r = d_mos2gds.value;
d_cdrain.d2_r2 = d_mos2gds.d1_r;
d_cdrain.d3_r3 = d_mos2gds.d2_r2;
goto line1050;
}
if (lvgs > von) goto line900;
/*
* subthreshold region */
if (vdsat <= 0) {
here->MOS2gds = 0.0;
d_cdrain.d1_r = 0.0;
d_cdrain.d2_r2 = 0.0;
d_cdrain.d3_r3 = 0.0;
/* if (lvgs > vth) goto doneval; */
goto line1050;
}
vdson = MIN(vdsat,lvds);
if (vdsat <= lvds) {
EqualDeriv(&d_vdson,&d_vdsat);
} else {
EqualDeriv(&d_vdson,&d_r);
d_vdson.value = lvds;
}
if (lvds > vdsat) {
barg = bsarg;
EqualDeriv(&d_barg,&d_bsarg);
body = bodys;
EqualDeriv(&d_body,&d_bodys);
}
cdson = beta1*((von-vbin-eta*vdson*0.5)*vdson-gammad*body/1.5);
MultDeriv(&d_dummy,&d_gammad,&d_body);
TimesDeriv(&d_cdson,&d_dummy,-1/1.5);
TimesDeriv(&d_dummy,&d_vdson,0.5*eta);
PlusDeriv(&d_dummy,&d_dummy,&d_vbin);
TimesDeriv(&d_dummy,&d_dummy,-1.0);
PlusDeriv(&d_dummy,&d_dummy,&d_von);
MultDeriv(&d_dummy,&d_dummy,&d_vdson);
PlusDeriv(&d_dummy,&d_dummy,&d_cdson);
MultDeriv(&d_cdson,&d_dummy,&d_beta1);
expg = exp(argg*(lvgs-von));
TimesDeriv(&d_expg,&d_von,-1.0);
d_expg.value += lvgs;
d_expg.d1_p += 1.0;
MultDeriv(&d_expg,&d_expg,&d_argg);
ExpDeriv(&d_expg,&d_expg);
cdrain = cdson*expg;
MultDeriv(&d_cdrain,&d_cdson,&d_expg);
/*
gmw = cdrain*argg;
here->MOS2gm = gmw;
tmp = gmw*(lvgs-von)/xn;
*/
goto doneval;
line900:
if (lvds <= vdsat) {
/*
* linear region */
cdrain = beta1*((lvgs-vbin-eta*lvds/2.0)*lvds-gammad*body/1.5);
MultDeriv(&d_dummy,&d_gammad,&d_body);
TimesDeriv(&d_dummy,&d_dummy,-1/1.5);
EqualDeriv(&d_cdrain,&d_r);
d_cdrain.value = eta*lvds*0.5;
d_cdrain.d1_r = 0.5*eta;
PlusDeriv(&d_cdrain,&d_cdrain,&d_vbin);
TimesDeriv(&d_cdrain,&d_cdrain,-1.0);
d_cdrain.value += lvgs;
d_cdrain.d1_p += 1.0;
EqualDeriv(&d_dummy,&d_r);
d_dummy.value = lvds;
MultDeriv(&d_cdrain,&d_cdrain,&d_dummy);
MultDeriv(&d_dummy,&d_gammad,&d_body);
TimesDeriv(&d_dummy,&d_dummy,-1/1.5);
PlusDeriv(&d_cdrain,&d_cdrain,&d_dummy);
MultDeriv(&d_cdrain,&d_cdrain,&d_beta1);
} else {
/*
* saturation region */
cdrain = beta1*((lvgs-vbin-eta*
vdsat/2.0)*vdsat-gammad*bodys/1.5);
TimesDeriv(&d_cdrain,&d_vdsat,0.5*eta);
PlusDeriv(&d_cdrain,&d_cdrain,&d_vbin);
TimesDeriv(&d_cdrain,&d_cdrain,-1.0);
d_cdrain.value += lvgs;
d_cdrain.d1_p += 1.0;
MultDeriv(&d_cdrain,&d_cdrain,&d_vdsat);
MultDeriv(&d_dummy,&d_gammad,&d_bodys);
TimesDeriv(&d_dummy,&d_dummy,-1/1.5);
PlusDeriv(&d_cdrain,&d_cdrain,&d_dummy);
MultDeriv(&d_cdrain,&d_cdrain,&d_beta1);
}
/*
* compute charges for "on" region */
goto doneval;
/*
* finish special cases */
line1050:
cdrain = 0.0;
here->MOS2gm = 0.0;
here->MOS2gmbs = 0.0;
d_cdrain.value = 0.0;
d_cdrain.d1_p = 0.0;
d_cdrain.d1_q = 0.0;
d_cdrain.d2_p2 = 0.0;
d_cdrain.d2_q2 = 0.0;
d_cdrain.d2_pq = 0.0;
d_cdrain.d2_qr = 0.0;
d_cdrain.d2_pr = 0.0;
d_cdrain.d3_p3 = 0.0;
d_cdrain.d3_q3 = 0.0;
d_cdrain.d3_p2r = 0.0;
d_cdrain.d3_p2q = 0.0;
d_cdrain.d3_q2r = 0.0;
d_cdrain.d3_pq2 = 0.0;
d_cdrain.d3_pr2 = 0.0;
d_cdrain.d3_qr2 = 0.0;
d_cdrain.d3_pqr = 0.0;
}
/*
* finished
*/
/*================HERE=================*/
doneval:
/*
* COMPUTE EQUIVALENT DRAIN CURRENT SOURCE
*/
/*
* now we do the hard part of the bulk-drain and bulk-source
* diode - we evaluate the non-linear capacitance and
* charge
* the basic equations are not hard, but the implementation
* is somewhat long in an attempt to avoid log/exponential
* evaluations
*/
/*
* charge storage elements *
*.. bulk-drain and bulk-source depletion capacitances
*/
if (vbs < here->MOS2tDepCap){
arg=1-vbs/here->MOS2tBulkPot;
/*
* the following block looks somewhat long and messy,
* but since most users use the default grading
* coefficients of .5, and sqrt is MUCH faster than an
* exp(log()) we use this special case code to buy time.
* (as much as 10% of total job time!)
*/
if(model->MOS2bulkJctBotGradingCoeff ==
model->MOS2bulkJctSideGradingCoeff) {
if(model->MOS2bulkJctBotGradingCoeff == .5) {
sarg = sargsw = 1/sqrt(arg);
} else {
sarg = sargsw =
exp(-model->MOS2bulkJctBotGradingCoeff*
log(arg));
}
} else {
if(model->MOS2bulkJctBotGradingCoeff == .5) {
sarg = 1/sqrt(arg);
} else {
sarg = exp(-model->MOS2bulkJctBotGradingCoeff*
log(arg));
}
if(model->MOS2bulkJctSideGradingCoeff == .5) {
sargsw = 1/sqrt(arg);
} else {
sargsw =exp(-model->MOS2bulkJctSideGradingCoeff*
log(arg));
}
}
lcapbs=here->MOS2Cbs*sarg+
here->MOS2Cbssw*sargsw;
lcapbs2 = model->MOS2type*0.5/here->MOS2tBulkPot*(
here->MOS2Cbs*model->MOS2bulkJctBotGradingCoeff*
sarg/arg + here->MOS2Cbssw*
model->MOS2bulkJctSideGradingCoeff*sargsw/arg);
lcapbs3 = here->MOS2Cbs*sarg*
model->MOS2bulkJctBotGradingCoeff*
(model->MOS2bulkJctBotGradingCoeff+1);
lcapbs3 += here->MOS2Cbssw*sargsw*
model->MOS2bulkJctSideGradingCoeff*
(model->MOS2bulkJctSideGradingCoeff+1);
lcapbs3 = lcapbs3/(6*here->MOS2tBulkPot*
here->MOS2tBulkPot*arg*arg);
} else {
/* *(ckt->CKTstate0 + here->MOS2qbs)= here->MOS2f4s +
vbs*(here->MOS2f2s+vbs*(here->MOS2f3s/2));*/
lcapbs=here->MOS2f2s+here->MOS2f3s*vbs;
lcapbs2 = 0.5*here->MOS2f3s;
lcapbs3 = 0;
}
if (vbd < here->MOS2tDepCap) {
arg=1-vbd/here->MOS2tBulkPot;
/*
* the following block looks somewhat long and messy,
* but since most users use the default grading
* coefficients of .5, and sqrt is MUCH faster than an
* exp(log()) we use this special case code to buy time.
* (as much as 10% of total job time!)
*/
if(model->MOS2bulkJctBotGradingCoeff == .5 &&
model->MOS2bulkJctSideGradingCoeff == .5) {
sarg = sargsw = 1/sqrt(arg);
} else {
if(model->MOS2bulkJctBotGradingCoeff == .5) {
sarg = 1/sqrt(arg);
} else {
sarg = exp(-model->MOS2bulkJctBotGradingCoeff*
log(arg));
}
if(model->MOS2bulkJctSideGradingCoeff == .5) {
sargsw = 1/sqrt(arg);
} else {
sargsw =exp(-model->MOS2bulkJctSideGradingCoeff*
log(arg));
}
}
lcapbd=here->MOS2Cbd*sarg+
here->MOS2Cbdsw*sargsw;
lcapbd2 = model->MOS2type*0.5/here->MOS2tBulkPot*(
here->MOS2Cbd*model->MOS2bulkJctBotGradingCoeff*
sarg/arg + here->MOS2Cbdsw*
model->MOS2bulkJctSideGradingCoeff*sargsw/arg);
lcapbd3 = here->MOS2Cbd*sarg*
model->MOS2bulkJctBotGradingCoeff*
(model->MOS2bulkJctBotGradingCoeff+1);
lcapbd3 += here->MOS2Cbdsw*sargsw*
model->MOS2bulkJctSideGradingCoeff*
(model->MOS2bulkJctSideGradingCoeff+1);
lcapbd3 = lcapbd3/(6*here->MOS2tBulkPot*
here->MOS2tBulkPot*arg*arg);
} else {
lcapbd=here->MOS2f2d + vbd * here->MOS2f3d;
lcapbd2=0.5*here->MOS2f3d;
lcapbd3=0;
}
/*
* meyer's capacitor model */
/*
* the meyer capacitance equations are in DEVqmeyer
* these expressions are derived from those equations.
* these expressions are incorrect; they assume just one
* controlling variable for each charge storage element
* while actually there are several; the MOS2 small
* signal ac linear model is also wrong because it
* ignores controlled capacitive elements. these can be
* corrected (as can the linear ss ac model) if the
* expressions for the charge are available
*/
{
double phi;
double cox;
double vddif;
double vddif1;
double vddif2;
/* von, vgst and vdsat have already been adjusted for
possible source-drain interchange */
phi = here->MOS2tPhi;
cox = OxideCap;
if (vgst <= -phi) {
lcapgb2=lcapgb3=lcapgs2=lcapgs3=lcapgd2=lcapgd3=0;
} else if (vgst <= -phi/2) {
lcapgb2= -cox/(4*phi);
lcapgb3=lcapgs2=lcapgs3=lcapgd2=lcapgd3=0;
} else if (vgst <= 0) {
lcapgb2= -cox/(4*phi);
lcapgb3=lcapgs3=lcapgd2=lcapgd3=0;
lcapgs2 = cox/(3*phi);
} else { /* the MOS2modes are around because
vds has not been adjusted */
if (vdsat <= here->MOS2mode*vds) {
lcapgb2=lcapgb3=lcapgs2=lcapgs3=lcapgd2=lcapgd3=0;
} else {
vddif = 2.0*vdsat-here->MOS2mode*vds;
vddif1 = vdsat-here->MOS2mode*vds/*-1.0e-12*/;
vddif2 = vddif*vddif;
lcapgd2 = -vdsat*here->MOS2mode*vds*cox/(3*vddif*vddif2);
lcapgd3 = - here->MOS2mode*vds*cox*(vddif - 6*vdsat)/(9*vddif2*vddif2);
lcapgs2 = -vddif1*here->MOS2mode*vds*cox/(3*vddif*vddif2);
lcapgs3 = - here->MOS2mode*vds*cox*(vddif - 6*vddif1)/(9*vddif2*vddif2);
lcapgb2=lcapgb3=0;
}
}
}
/* the b-s and b-d diodes need no processing ... */
here->capbs2 = lcapbs2;
here->capbs3 = lcapbs3;
here->capbd2 = lcapbd2;
here->capbd3 = lcapbd3;
here->gbs2 = lgbs2;
here->gbs3 = lgbs3;
here->gbd2 = lgbd2;
here->gbd3 = lgbd3;
here->capgb2 = model->MOS2type*lcapgb2;
here->capgb3 = lcapgb3;
/*
* process to get Taylor coefficients, taking into * account type and mode.
*/
gm2 = d_cdrain.d2_p2;
gb2 = d_cdrain.d2_q2;
gds2 = d_cdrain.d2_r2;
gmb = d_cdrain.d2_pq;
gbds = d_cdrain.d2_qr;
gmds = d_cdrain.d2_pr;
gm3 = d_cdrain.d3_p3;
gb3 = d_cdrain.d3_q3;
gds3 = d_cdrain.d3_r3;
gm2ds = d_cdrain.d3_p2r;
gm2b = d_cdrain.d3_p2q;
gb2ds = d_cdrain.d3_q2r;
gmb2 = d_cdrain.d3_pq2;
gmds2 = d_cdrain.d3_pr2;
gbds2 = d_cdrain.d3_qr2;
gmbds = d_cdrain.d3_pqr;
if (here->MOS2mode == 1)
{
/* normal mode - no source-drain interchange */
here->cdr_x2 = gm2;
here->cdr_y2 = gb2;
here->cdr_z2 = gds2;
here->cdr_xy = gmb;
here->cdr_yz = gbds;
here->cdr_xz = gmds;
here->cdr_x3 = gm3;
here->cdr_y3 = gb3;
here->cdr_z3 = gds3;
here->cdr_x2z = gm2ds;
here->cdr_x2y = gm2b;
here->cdr_y2z = gb2ds;
here->cdr_xy2 = gmb2;
here->cdr_xz2 = gmds2;
here->cdr_yz2 = gbds2;
here->cdr_xyz = gmbds;
/* the gate caps have been divided and made into Taylor coeffs., but not adjusted for type */
here->capgs2 = model->MOS2type*lcapgs2;
here->capgs3 = lcapgs3;
here->capgd2 = model->MOS2type*lcapgd2;
here->capgd3 = lcapgd3;
} else {
/*
* inverse mode - source and drain interchanged */
here->cdr_x2 = -gm2;
here->cdr_y2 = -gb2;
here->cdr_z2 = -(gm2 + gb2 + gds2 + 2*(gmb + gmds + gbds));
here->cdr_xy = -gmb;
here->cdr_yz = gmb + gb2 + gbds;
here->cdr_xz = gm2 + gmb + gmds;
here->cdr_x3 = -gm3;
here->cdr_y3 = -gb3;
here->cdr_z3 = gm3 + gb3 + gds3 +
3*(gm2b + gm2ds + gmb2 + gb2ds + gmds2 + gbds2) + 6*gmbds ;
here->cdr_x2z = gm3 + gm2b + gm2ds;
here->cdr_x2y = -gm2b;
here->cdr_y2z = gmb2 + gb3 + gb2ds;
here->cdr_xy2 = -gmb2;
here->cdr_xz2 = -(gm3 + 2*(gm2b + gm2ds + gmbds) +
gmb2 + gmds2);
here->cdr_yz2 = -(gb3 + 2*(gmb2 + gb2ds + gmbds) +
gm2b + gbds2);
here->cdr_xyz = gm2b + gmb2 + gmbds;
here->capgs2 = model->MOS2type*lcapgd2;
here->capgs3 = lcapgd3;
here->capgd2 = model->MOS2type*lcapgs2;
here->capgd3 = lcapgs3;
}
/* now to adjust for type and multiply by factors to convert to Taylor coeffs. */
here->cdr_x2 = 0.5*model->MOS2type*here->cdr_x2;
here->cdr_y2 = 0.5*model->MOS2type*here->cdr_y2;
here->cdr_z2 = 0.5*model->MOS2type*here->cdr_z2;
here->cdr_xy = model->MOS2type*here->cdr_xy;
here->cdr_yz = model->MOS2type*here->cdr_yz;
here->cdr_xz = model->MOS2type*here->cdr_xz;
here->cdr_x3 = here->cdr_x3/6.;
here->cdr_y3 = here->cdr_y3/6.;
here->cdr_z3 = here->cdr_z3/6.;
here->cdr_x2z = 0.5*here->cdr_x2z;
here->cdr_x2y = 0.5*here->cdr_x2y;
here->cdr_y2z = 0.5*here->cdr_y2z;
here->cdr_xy2 = 0.5*here->cdr_xy2;
here->cdr_xz2 = 0.5*here->cdr_xz2;
here->cdr_yz2 = 0.5*here->cdr_yz2;
}
}
return(OK);
}