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.
 
 
 
 
 
 

1392 lines
55 KiB

/**********
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Thomas L. Quarles
Modified: 2000 alansFixes
**********/
#include "ngspice/ngspice.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
MOS2load(GENmodel *inModel, CKTcircuit *ckt)
/* actually load the current value into the
* sparse matrix previously provided
*/
{
MOS2model *model = (MOS2model *)inModel;
MOS2instance *here;
int error;
double Beta;
double DrainSatCur;
double EffectiveLength;
double GateBulkOverlapCap;
double GateDrainOverlapCap;
double GateSourceOverlapCap;
double OxideCap;
double SourceSatCur;
double arg;
double cbhat;
double cdhat;
double cdrain = 0.0;
double cdreq;
double ceq;
double ceqbd;
double ceqbs;
double ceqgb;
double ceqgd;
double ceqgs;
double delvbd;
double delvbs;
double delvds;
double delvgd;
double delvgs;
double evbd;
double evbs;
double gcgb;
double gcgd;
double gcgs;
double geq;
double sarg;
double sargsw;
double vbd;
double vbs;
double vds;
double vdsat;
double vgb1;
double vgb;
double vgd1;
double vgd;
double vgdo;
double vgs1;
double vgs;
double von;
double vt; /* K * T / Q */
#ifndef PREDICTOR
double xfact = 0.0;
#endif
double capgs = 0.0; /* total gate-source capacitance */
double capgd = 0.0; /* total gate-drain capacitance */
double capgb = 0.0; /* total gate-bulk capacitance */
int xnrm;
int xrev;
int Check;
#ifndef NOBYPASS
double tempv;
#endif /*NOBYPASS*/
#ifdef CAPBYPASS
int senflag;
#endif /* CAPBYPASS */
int SenCond=0;
#ifdef CAPBYPASS
senflag = 0;
if(ckt->CKTsenInfo){
if(ckt->CKTsenInfo->SENstatus == PERTURBATION){
if((ckt->CKTsenInfo->SENmode == ACSEN)||
(ckt->CKTsenInfo->SENmode == TRANSEN)){
senflag = 1;
}
}
}
#endif /* CAPBYPASS */
/* 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;
Check=1;
if(ckt->CKTsenInfo){
#ifdef SENSDEBUG
printf("MOS2load %s\n",here->MOS2name);
#endif /* SENSDEBUG */
if(ckt->CKTsenInfo->SENstatus == PERTURBATION) {
if(here->MOS2senPertFlag == OFF)continue;
}
SenCond = here->MOS2senPertFlag;
}
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->MOS2m * here->MOS2tSatCurDens *
here->MOS2drainArea;
SourceSatCur = here->MOS2m * here->MOS2tSatCurDens *
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->MOS2w *
here->MOS2m/EffectiveLength;
OxideCap = model->MOS2oxideCapFactor * EffectiveLength *
here->MOS2m * here->MOS2w;
if(SenCond){
#ifdef SENSDEBUG
printf("MOS2senPertFlag = ON \n");
#endif /* SENSDEBUG */
if((ckt->CKTsenInfo->SENmode == TRANSEN) &&
(ckt->CKTmode & MODEINITTRAN)) {
vgs = *(ckt->CKTstate1 + here->MOS2vgs);
vds = *(ckt->CKTstate1 + here->MOS2vds);
vbs = *(ckt->CKTstate1 + here->MOS2vbs);
vbd = *(ckt->CKTstate1 + here->MOS2vbd);
vgb = vgs - vbs;
vgd = vgs - vds;
}
else if (ckt->CKTsenInfo->SENmode == ACSEN){
vgb = model->MOS2type * (
*(ckt->CKTrhsOp+here->MOS2gNode) -
*(ckt->CKTrhsOp+here->MOS2bNode));
vbs = *(ckt->CKTstate0 + here->MOS2vbs);
vbd = *(ckt->CKTstate0 + here->MOS2vbd);
vgd = vgb + vbd ;
vgs = vgb + vbs ;
vds = vbs - vbd ;
}
else{
vgs = *(ckt->CKTstate0 + here->MOS2vgs);
vds = *(ckt->CKTstate0 + here->MOS2vds);
vbs = *(ckt->CKTstate0 + here->MOS2vbs);
vbd = *(ckt->CKTstate0 + here->MOS2vbd);
vgb = vgs - vbs;
vgd = vgs - vds;
}
#ifdef SENSDEBUG
printf(" vbs = %.7e ,vbd = %.7e,vgb = %.7e\n",vbs,vbd,vgb);
printf(" vgs = %.7e ,vds = %.7e,vgd = %.7e\n",vgs,vds,vgd);
#endif /* SENSDEBUG */
goto next1;
}
if((ckt->CKTmode & (MODEINITFLOAT | MODEINITPRED |MODEINITSMSIG
| MODEINITTRAN)) ||
( (ckt->CKTmode & MODEINITFIX) && (!here->MOS2off) ) ) {
#ifndef PREDICTOR
if(ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) {
/* predictor step */
xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1];
*(ckt->CKTstate0 + here->MOS2vbs) =
*(ckt->CKTstate1 + here->MOS2vbs);
vbs = (1+xfact)* (*(ckt->CKTstate1 + here->MOS2vbs))
-(xfact * (*(ckt->CKTstate2 + here->MOS2vbs)));
*(ckt->CKTstate0 + here->MOS2vgs) =
*(ckt->CKTstate1 + here->MOS2vgs);
vgs = (1+xfact)* (*(ckt->CKTstate1 + here->MOS2vgs))
-(xfact * (*(ckt->CKTstate2 + here->MOS2vgs)));
*(ckt->CKTstate0 + here->MOS2vds) =
*(ckt->CKTstate1 + here->MOS2vds);
vds = (1+xfact)* (*(ckt->CKTstate1 + here->MOS2vds))
-(xfact * (*(ckt->CKTstate2 + here->MOS2vds)));
*(ckt->CKTstate0 + here->MOS2vbd) =
*(ckt->CKTstate0 + here->MOS2vbs)-
*(ckt->CKTstate0 + here->MOS2vds);
} else {
#endif /* PREDICTOR */
/* 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));
#ifndef PREDICTOR
}
#endif /* PREDICTOR */
/* now some common crunching for some more useful quantities */
vbd=vbs-vds;
vgd=vgs-vds;
vgdo = *(ckt->CKTstate0 + here->MOS2vgs) -
*(ckt->CKTstate0 + here->MOS2vds);
delvbs = vbs - *(ckt->CKTstate0 + here->MOS2vbs);
delvbd = vbd - *(ckt->CKTstate0 + here->MOS2vbd);
delvgs = vgs - *(ckt->CKTstate0 + here->MOS2vgs);
delvds = vds - *(ckt->CKTstate0 + here->MOS2vds);
delvgd = vgd-vgdo;
/* these are needed for convergence testing */
if (here->MOS2mode >= 0) {
cdhat=
here->MOS2cd -
here->MOS2gbd * delvbd +
here->MOS2gmbs * delvbs +
here->MOS2gm * delvgs +
here->MOS2gds * delvds ;
} else {
cdhat=
here->MOS2cd +
( here->MOS2gmbs -
here->MOS2gbd) * delvbd -
here->MOS2gm * delvgd +
here->MOS2gds * delvds ;
}
cbhat=
here->MOS2cbs +
here->MOS2cbd +
here->MOS2gbd * delvbd +
here->MOS2gbs * delvbs ;
/* now lets see if we can bypass (ugh) */
/* the following massive if should all be one
* single compound if statement, but most compilers
* can't handle it in one piece, so it is broken up
* into several stages here
*/
#ifndef NOBYPASS
tempv = MAX(fabs(cbhat),fabs(here->MOS2cbs+here->MOS2cbd))+
ckt->CKTabstol;
if((!(ckt->CKTmode & (MODEINITPRED|MODEINITTRAN|MODEINITSMSIG)
)) && (ckt->CKTbypass) )
if ( (fabs(cbhat-(here->MOS2cbs + here->MOS2cbd))
< ckt->CKTreltol * tempv))
if( (fabs(delvbs) < (ckt->CKTreltol * MAX(fabs(vbs),
fabs(*(ckt->CKTstate0+here->MOS2vbs)))+
ckt->CKTvoltTol)))
if ( (fabs(delvbd) < (ckt->CKTreltol * MAX(fabs(vbd),
fabs(*(ckt->CKTstate0+here->MOS2vbd)))+
ckt->CKTvoltTol)) )
if( (fabs(delvgs) < (ckt->CKTreltol * MAX(fabs(vgs),
fabs(*(ckt->CKTstate0+here->MOS2vgs)))+
ckt->CKTvoltTol)) )
if ( (fabs(delvds) < (ckt->CKTreltol * MAX(fabs(vds),
fabs(*(ckt->CKTstate0+here->MOS2vds)))+
ckt->CKTvoltTol)) )
if( (fabs(cdhat- here->MOS2cd) <
ckt->CKTreltol * MAX(fabs(cdhat),fabs(
here->MOS2cd)) + ckt->CKTabstol) ) {
/* bypass code */
/* nothing interesting has changed since last
* iteration on this device, so we just
* copy all the values computed last iteration
* out and keep going
*/
vbs = *(ckt->CKTstate0 + here->MOS2vbs);
vbd = *(ckt->CKTstate0 + here->MOS2vbd);
vgs = *(ckt->CKTstate0 + here->MOS2vgs);
vds = *(ckt->CKTstate0 + here->MOS2vds);
vgd = vgs - vds;
vgb = vgs - vbs;
cdrain = here->MOS2mode * (here->MOS2cd + here->MOS2cbd);
if(ckt->CKTmode & (MODETRAN | MODETRANOP)) {
capgs = ( *(ckt->CKTstate0 + here->MOS2capgs)+
*(ckt->CKTstate1 + here->MOS2capgs)+
GateSourceOverlapCap );
capgd = ( *(ckt->CKTstate0 + here->MOS2capgd)+
*(ckt->CKTstate1 + here->MOS2capgd)+
GateDrainOverlapCap );
capgb = ( *(ckt->CKTstate0 + here->MOS2capgb)+
*(ckt->CKTstate1 + here->MOS2capgb)+
GateBulkOverlapCap );
if(ckt->CKTsenInfo){
here->MOS2cgs = capgs;
here->MOS2cgd = capgd;
here->MOS2cgb = capgb;
}
}
goto bypass;
}
#endif /*NOBYPASS*/
/* ok - bypass is out, do it the hard way */
von = model->MOS2type * here->MOS2von;
/*
* limiting
* We want to keep device voltages from changing
* so fast that the exponentials churn out overflows
* and similar rudeness
*/
if(*(ckt->CKTstate0 + here->MOS2vds) >=0) {
vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->MOS2vgs)
,von);
vds = vgs - vgd;
vds = DEVlimvds(vds,*(ckt->CKTstate0 + here->MOS2vds));
vgd = vgs - vds;
} else {
vgd = DEVfetlim(vgd,vgdo,von);
vds = vgs - vgd;
if(!(ckt->CKTfixLimit)) {
vds = -DEVlimvds(-vds,-(*(ckt->CKTstate0 +
here->MOS2vds)));
}
vgs = vgd + vds;
}
if(vds >= 0) {
vbs = DEVpnjlim(vbs,*(ckt->CKTstate0 + here->MOS2vbs),
vt,here->MOS2sourceVcrit,&Check);
vbd = vbs-vds;
} else {
vbd = DEVpnjlim(vbd,*(ckt->CKTstate0 + here->MOS2vbd),
vt,here->MOS2drainVcrit,&Check);
vbs = vbd + vds;
}
} else {
/* ok - not one of the simple cases, so we have to
* look at other possibilities
*/
if((ckt->CKTmode & MODEINITJCT) && !here->MOS2off) {
vds= model->MOS2type * here->MOS2icVDS;
vgs= model->MOS2type * here->MOS2icVGS;
vbs= model->MOS2type * here->MOS2icVBS;
if((vds==0) && (vgs==0) && (vbs==0) &&
((ckt->CKTmode &
(MODETRAN|MODEDCOP|MODEDCTRANCURVE)) ||
(!(ckt->CKTmode & MODEUIC)))) {
vbs = -1;
vgs = model->MOS2type * here->MOS2tVto;
vds = 0;
}
} else {
vbs=vgs=vds=0;
}
}
/* now all the preliminaries are over - we can start doing the
* real work
*/
vbd = vbs - vds;
vgd = vgs - vds;
vgb = vgs - vbs;
/* bulk-source and bulk-drain doides
* here we just evaluate the ideal diode current and the
* correspoinding derivative (conductance).
*/
next1: if(vbs <= -3*vt) {
here->MOS2gbs = ckt->CKTgmin;
here->MOS2cbs = here->MOS2gbs*vbs-SourceSatCur;
} else {
evbs = exp(MIN(MAX_EXP_ARG,vbs/vt));
here->MOS2gbs = SourceSatCur*evbs/vt + ckt->CKTgmin;
here->MOS2cbs = SourceSatCur*(evbs-1) + ckt->CKTgmin*vbs;
}
if(vbd <= -3*vt) {
here->MOS2gbd = ckt->CKTgmin;
here->MOS2cbd = here->MOS2gbd*vbd-DrainSatCur;
} else {
evbd = exp(MIN(MAX_EXP_ARG,vbd/vt));
here->MOS2gbd = DrainSatCur*evbd/vt + ckt->CKTgmin;
here->MOS2cbd = DrainSatCur*(evbd-1) + ckt->CKTgmin*vbd;
}
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 dsrgdb;
double d2sdb2;
double sphi = 0.0; /* square root of phi */
double sphi3 = 0.0; /* square root of phi cubed */
double barg;
double d2bdb2;
double factor;
double dbrgdb;
double eta;
double vbin;
double argd = 0.0;
double args = 0.0;
double argss;
double argsd;
double argxs = 0.0;
double argxd = 0.0;
double daddb2;
double dasdb2;
double dbargd;
double dbargs;
double dbxwd;
double dbxws;
double dgddb2;
double dgddvb;
double dgdvds;
double gamasd;
double xwd;
double xws;
double ddxwd;
double gammad;
double vth;
double cfs;
double cdonco;
double xn = 0.0;
double argg = 0.0;
double vgst;
double sarg3;
double sbiarg;
double dgdvbs;
double body;
double gdbdv;
double dodvbs;
double dodvds = 0.0;
double dxndvd = 0.0;
double dxndvb = 0.0;
double udenom;
double dudvgs;
double dudvds;
double dudvbs;
double gammd2;
double argv;
double vgsx;
double ufact;
double ueff;
double dsdvgs;
double dsdvbs;
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 = 0.0;
double dbsrdb;
double bodys = 0.0;
double gdbdvs = 0.0;
double sargv;
double xlfact;
double dldsat;
double xdv;
double xlv;
double vqchan;
double dqdsat;
double vl;
double dfundg;
double dfunds;
double dfundb;
double xls;
double dldvgs;
double dldvds;
double dldvbs;
double dfact;
double clfact;
double xleff;
double deltal;
double xwb;
double vdson;
double cdson;
double didvds;
double gdson;
double gmw;
double gbson;
double expg;
double xld;
double xlamda = model->MOS2lambda;
/* '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
*/
if (lvbs <= 0.0) {
sarg = sqrt(phiMinVbs);
dsrgdb = -0.5/sarg;
d2sdb2 = 0.5*dsrgdb/phiMinVbs;
} else {
sphi = sqrt(here->MOS2tPhi);
sphi3 = here->MOS2tPhi*sphi;
sarg = sphi/(1.0+0.5*lvbs/here->MOS2tPhi);
tmp = sarg/sphi3;
dsrgdb = -0.5*sarg*tmp;
d2sdb2 = -dsrgdb*tmp;
}
if ((lvbs-lvds) <= 0) {
barg = sqrt(phiMinVbs+lvds);
dbrgdb = -0.5/barg;
d2bdb2 = 0.5*dbrgdb/(phiMinVbs+lvds);
} 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);
tmp = barg/sphi3;
dbrgdb = -0.5*barg*tmp;
d2bdb2 = -dbrgdb*tmp;
}
/*
* 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;
if ((model->MOS2gamma > 0.0) ||
(model->MOS2substrateDoping > 0.0)) {
xwd = model->MOS2xd*barg;
xws = model->MOS2xd*sarg;
/*
* short-channel effect with vds .ne. 0.0
*/
argss = 0.0;
argsd = 0.0;
dbargs = 0.0;
dbargd = 0.0;
dgdvds = 0.0;
dgddb2 = 0.0;
if (model->MOS2junctionDepth > 0) {
tmp = 2.0/model->MOS2junctionDepth;
argxs = 1.0+xws*tmp;
argxd = 1.0+xwd*tmp;
args = sqrt(argxs);
argd = sqrt(argxd);
tmp = .5*model->MOS2junctionDepth/EffectiveLength;
argss = tmp * (args-1.0);
argsd = tmp * (argd-1.0);
}
gamasd = model->MOS2gamma*(1.0-argss-argsd);
dbxwd = model->MOS2xd*dbrgdb;
dbxws = model->MOS2xd*dsrgdb;
if (model->MOS2junctionDepth > 0) {
tmp = 0.5/EffectiveLength;
dbargs = tmp*dbxws/args;
dbargd = tmp*dbxwd/argd;
dasdb2 = -model->MOS2xd*( d2sdb2+dsrgdb*dsrgdb*
model->MOS2xd/(model->MOS2junctionDepth*argxs))/
(EffectiveLength*args);
daddb2 = -model->MOS2xd*( d2bdb2+dbrgdb*dbrgdb*
model->MOS2xd/(model->MOS2junctionDepth*argxd))/
(EffectiveLength*argd);
dgddb2 = -0.5*model->MOS2gamma*(dasdb2+daddb2);
}
dgddvb = -model->MOS2gamma*(dbargs+dbargd);
if (model->MOS2junctionDepth > 0) {
ddxwd = -dbxwd;
dgdvds = -model->MOS2gamma*0.5*ddxwd/(EffectiveLength*argd);
}
} else {
gamasd = model->MOS2gamma;
gammad = model->MOS2gamma;
dgddvb = 0.0;
dgdvds = 0.0;
dgddb2 = 0.0;
}
von = vbin+gamasd*sarg;
vth = von;
vdsat = 0.0;
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;
xn = 1.0+cfs/OxideCap*here->MOS2m*
here->MOS2w*EffectiveLength+cdonco;
tmp = vt*xn;
von = von+tmp;
argg = 1.0/tmp;
vgst = lvgs-von;
} else {
vgst = lvgs-von;
if (lvgs <= vbin) {
/*
* cutoff region
*/
here->MOS2gds = 0.0;
goto line1050;
}
}
/*
* compute some more useful quantities
*/
sarg3 = sarg*sarg*sarg;
/* XXX constant per model */
sbiarg = sqrt(here->MOS2tBulkPot);
gammad = gamasd;
dgdvbs = dgddvb;
body = barg*barg*barg-sarg3;
gdbdv = 2.0*gammad*(barg*barg*dbrgdb-sarg*sarg*dsrgdb);
dodvbs = -factor+dgdvbs*sarg+gammad*dsrgdb;
if (model->MOS2fastSurfaceStateDensity == 0.0) goto line400;
if (OxideCap == 0.0) goto line410;
dxndvb = 2.0*dgdvbs*dsrgdb+gammad*d2sdb2+dgddb2*sarg;
dodvbs = dodvbs+vt*dxndvb;
dxndvd = dgdvds*dsrgdb;
dodvds = dgdvds*sarg+vt*dxndvd;
/*
* evaluate effective mobility and its derivatives
*/
line400:
if (OxideCap <= 0.0) goto line410;
udenom = vgst;
tmp = model->MOS2critField * 100 /* cm/m */ * EPSSIL/
model->MOS2oxideCapFactor;
if (udenom <= tmp) goto line410;
ufact = exp(model->MOS2critFieldExp*log(tmp/udenom));
ueff = model->MOS2surfaceMobility * 1e-4 /*(m**2/cm**2) */ *ufact;
dudvgs = -ufact*model->MOS2critFieldExp/udenom;
dudvds = 0.0;
dudvbs = model->MOS2critFieldExp*ufact*dodvbs/vgst;
goto line500;
line410:
ufact = 1.0;
ueff = model->MOS2surfaceMobility * 1e-4 /*(m**2/cm**2) */ ;
dudvgs = 0.0;
dudvds = 0.0;
dudvbs = 0.0;
/*
* evaluate saturation voltage and its derivatives according to
* grove-frohman equation
*/
line500:
vgsx = lvgs;
gammad = gamasd/eta;
dgdvbs = dgddvb;
if (model->MOS2fastSurfaceStateDensity != 0 && OxideCap != 0) {
vgsx = MAX(lvgs,von);
}
if (gammad > 0) {
gammd2 = gammad*gammad;
argv = (vgsx-vbin)/eta+phiMinVbs;
if (argv <= 0.0) {
vdsat = 0.0;
dsdvgs = 0.0;
dsdvbs = 0.0;
} else {
arg = sqrt(1.0+4.0*argv/gammd2);
vdsat = (vgsx-vbin)/eta+gammd2*(1.0-arg)/2.0;
vdsat = MAX(vdsat,0.0);
dsdvgs = (1.0-1.0/arg)/eta;
dsdvbs = (gammad*(1.0-arg)+2.0*argv/(gammad*arg))/
eta*dgdvbs+1.0/arg+factor*dsdvgs;
}
} else {
vdsat = (vgsx-vbin)/eta;
vdsat = MAX(vdsat,0.0);
dsdvgs = 1.0;
dsdvbs = 0.0;
}
if (model->MOS2maxDriftVel > 0) {
/*
* evaluate saturation voltage and its derivatives
* according to baum's theory of scattering velocity
* saturation
*/
gammd2 = gammad*gammad;
v1 = (vgsx-vbin)/eta+phiMinVbs;
v2 = phiMinVbs;
xv = model->MOS2maxDriftVel*EffectiveLength/ueff;
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;
s = 2.0*a*a*a/27.0-a*b/3.0+c;
r3 = r*r*r;
s2 = s*s;
p = s2/4.0+r3/27.0;
p0 = fabs(p);
p2 = sqrt(p0);
if (p < 0) {
ro = sqrt(s2/4.0+p0);
ro = log(ro)/3.0;
ro = exp(ro);
fi = atan(-2.0*p2/s);
y3 = 2.0*ro*cos(fi/3.0)-a/3.0;
} else {
p3 = (-s/2.0+p2);
p3 = exp(log(fabs(p3))/3.0);
p4 = (-s/2.0-p2);
p4 = exp(log(fabs(p4))/3.0);
y3 = p3+p4-a/3.0;
}
iknt = 0;
a3 = sqrt(a1*a1/4.0-b1+y3);
b3 = sqrt(y3*y3/4.0-d1);
for(i = 1;i<=4;i++) {
a4[i-1] = a1/2.0+sig1[i-1]*a3;
b4[i-1] = y3/2.0+sig2[i-1]*b3;
delta4 = a4[i-1]*a4[i-1]/4.0-b4[i-1];
if (delta4 < 0) continue;
iknt = iknt+1;
tmp = sqrt(delta4);
x4[iknt-1] = -a4[i-1]/2.0+tmp;
iknt = iknt+1;
x4[iknt-1] = -a4[i-1]/2.0-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];
poly4[j-1] = poly4[j-1]+b1*x4[j-1]*x4[j-1]+c1*x4[j-1]+d1;
if (fabs(poly4[j-1]) > 1.0e-6) continue;
jknt = jknt+1;
if (jknt <= 1) {
xvalid = x4[j-1];
}
if (x4[j-1] > xvalid) continue;
xvalid = x4[j-1];
}
if (jknt > 0) {
vdsat = xvalid*xvalid-phiMinVbs;
}
}
/*
* evaluate effective channel length and its derivatives
*/
if (lvds != 0.0) {
gammad = gamasd;
if ((lvbs-vdsat) <= 0) {
bsarg = sqrt(vdsat+phiMinVbs);
dbsrdb = -0.5/bsarg;
} else {
sphi = sqrt(here->MOS2tPhi);/* added by HT 050523 */
sphi3 = here->MOS2tPhi*sphi;/* added by HT 050523 */
bsarg = sphi/(1.0+0.5*(lvbs-vdsat)/here->MOS2tPhi);
dbsrdb = -0.5*bsarg*bsarg/sphi3;
}
bodys = bsarg*bsarg*bsarg-sarg3;
gdbdvs = 2.0*gammad*(bsarg*bsarg*dbsrdb-sarg*sarg*dsrgdb);
if (model->MOS2maxDriftVel <= 0) {
if (model->MOS2substrateDoping == 0.0) goto line610;
if (xlamda > 0.0) goto line610;
argv = (lvds-vdsat)/4.0;
sargv = sqrt(1.0+argv*argv);
arg = sqrt(argv+sargv);
xlfact = model->MOS2xd/(EffectiveLength*lvds);
xlamda = xlfact*arg;
dldsat = lvds*xlamda/(8.0*sargv);
} else {
argv = (vgsx-vbin)/eta-vdsat;
xdv = model->MOS2xd/sqrt(model->MOS2channelCharge);
xlv = model->MOS2maxDriftVel*xdv/(2.0*ueff);
vqchan = argv-gammad*bsarg;
dqdsat = -1.0+gammad*dbsrdb;
vl = model->MOS2maxDriftVel*EffectiveLength;
dfunds = vl*dqdsat-ueff*vqchan;
dfundg = (vl-ueff*vdsat)/eta;
dfundb = -vl*(1.0+dqdsat-factor/eta)+ueff*
(gdbdvs-dgdvbs*bodys/1.5)/eta;
dsdvgs = -dfundg/dfunds;
dsdvbs = -dfundb/dfunds;
if (model->MOS2substrateDoping == 0.0) goto line610;
if (xlamda > 0.0) goto line610;
argv = lvds-vdsat;
argv = MAX(argv,0.0);
xls = sqrt(xlv*xlv+argv);
dldsat = xdv/(2.0*xls);
xlfact = xdv/(EffectiveLength*lvds);
xlamda = xlfact*(xls-xlv);
dldsat = dldsat/EffectiveLength;
}
dldvgs = dldsat*dsdvgs;
dldvds = -xlamda+dldsat;
dldvbs = dldsat*dsdvbs;
} else {
line610:
dldvgs = 0.0;
dldvds = 0.0;
dldvbs = 0.0;
}
/*
* limit channel shortening at punch-through
*/
xwb = model->MOS2xd*sbiarg;
xld = EffectiveLength-xwb;
clfact = 1.0-xlamda*lvds;
dldvds = -xlamda-dldvds;
xleff = EffectiveLength*clfact;
deltal = xlamda*lvds*EffectiveLength;
if (model->MOS2substrateDoping == 0.0) xwb = 0.25e-6;
if (xleff < xwb) {
xleff = xwb/(1.0+(deltal-xld)/xwb);
clfact = xleff/EffectiveLength;
dfact = xleff*xleff/(xwb*xwb);
dldvgs = dfact*dldvgs;
dldvds = dfact*dldvds;
dldvbs = dfact*dldvbs;
}
/*
* evaluate effective beta (effective kp)
*/
beta1 = Beta*ufact/clfact;
/*
* test for mode of operation and branch appropriately
*/
gammad = gamasd;
dgdvbs = dgddvb;
if (lvds <= 1.0e-10) {
if (lvgs <= von) {
if ((model->MOS2fastSurfaceStateDensity == 0.0) ||
(OxideCap == 0.0)) {
here->MOS2gds = 0.0;
goto line1050;
}
here->MOS2gds = beta1*(von-vbin-gammad*sarg)*exp(argg*
(lvgs-von));
goto line1050;
}
here->MOS2gds = beta1*(lvgs-vbin-gammad*sarg);
goto line1050;
}
if (model->MOS2fastSurfaceStateDensity != 0 && OxideCap != 0) {
if (lvgs > von) goto line900;
} else {
if (lvgs > vbin) goto line900;
goto doneval;
}
if (lvgs > von) goto line900;
/*
* subthreshold region
*/
if (vdsat <= 0) {
here->MOS2gds = 0.0;
if (lvgs > vth) goto doneval;
goto line1050;
}
vdson = MIN(vdsat,lvds);
if (lvds > vdsat) {
barg = bsarg;
dbrgdb = dbsrdb;
body = bodys;
gdbdv = gdbdvs;
}
cdson = beta1*((von-vbin-eta*vdson*0.5)*vdson-gammad*body/1.5);
didvds = beta1*(von-vbin-eta*vdson-gammad*barg);
gdson = -cdson*dldvds/clfact-beta1*dgdvds*body/1.5;
if (lvds < vdsat) gdson = gdson+didvds;
gbson = -cdson*dldvbs/clfact+beta1*
(dodvbs*vdson+factor*vdson-dgdvbs*body/1.5-gdbdv);
if (lvds > vdsat) gbson = gbson+didvds*dsdvbs;
expg = exp(argg*(lvgs-von));
cdrain = cdson*expg;
gmw = cdrain*argg;
here->MOS2gm = gmw;
if (lvds > vdsat) here->MOS2gm = gmw+didvds*dsdvgs*expg;
tmp = gmw*(lvgs-von)/xn;
here->MOS2gds = gdson*expg-here->MOS2gm*dodvds-tmp*dxndvd;
here->MOS2gmbs = gbson*expg-here->MOS2gm*dodvbs-tmp*dxndvb;
goto doneval;
line900:
if (lvds <= vdsat) {
/*
* linear region
*/
cdrain = beta1*((lvgs-vbin-eta*lvds/2.0)*lvds-gammad*body/1.5);
arg = cdrain*(dudvgs/ufact-dldvgs/clfact);
here->MOS2gm = arg+beta1*lvds;
arg = cdrain*(dudvds/ufact-dldvds/clfact);
here->MOS2gds = arg+beta1*(lvgs-vbin-eta*
lvds-gammad*barg-dgdvds*body/1.5);
arg = cdrain*(dudvbs/ufact-dldvbs/clfact);
here->MOS2gmbs = arg-beta1*(gdbdv+dgdvbs*body/1.5-factor*lvds);
} else {
/*
* saturation region
*/
cdrain = beta1*((lvgs-vbin-eta*
vdsat/2.0)*vdsat-gammad*bodys/1.5);
arg = cdrain*(dudvgs/ufact-dldvgs/clfact);
here->MOS2gm = arg+beta1*vdsat+beta1*(lvgs-
vbin-eta*vdsat-gammad*bsarg)*dsdvgs;
here->MOS2gds = -cdrain*dldvds/clfact-beta1*dgdvds*bodys/1.5;
arg = cdrain*(dudvbs/ufact-dldvbs/clfact);
here->MOS2gmbs = arg-beta1*(gdbdvs+dgdvbs*bodys/1.5-factor*
vdsat)+beta1* (lvgs-vbin-eta*vdsat-gammad*bsarg)*dsdvbs;
}
/*
* compute charges for "on" region
*/
goto doneval;
/*
* finish special cases
*/
line1050:
cdrain = 0.0;
here->MOS2gm = 0.0;
here->MOS2gmbs = 0.0;
/*
* finished
*/
}
doneval:
here->MOS2von = model->MOS2type * von;
here->MOS2vdsat = model->MOS2type * vdsat;
/*
* COMPUTE EQUIVALENT DRAIN CURRENT SOURCE
*/
here->MOS2cd=here->MOS2mode * cdrain - here->MOS2cbd;
if (ckt->CKTmode & (MODETRAN | MODETRANOP|MODEINITSMSIG)) {
/*
* 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
*/
#ifdef CAPBYPASS
if(((ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) ||
fabs(delvbs) >= ckt->CKTreltol * MAX(fabs(vbs),
fabs(*(ckt->CKTstate0+here->MOS2vbs)))+
ckt->CKTvoltTol)|| senflag)
#endif /*CAPBYPASS*/
{
/* can't bypass the diode capacitance calculations */
if(here->MOS2Cbs != 0 || here->MOS2Cbssw != 0) {
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));
}
}
*(ckt->CKTstate0 + here->MOS2qbs) =
here->MOS2tBulkPot*(here->MOS2Cbs*
(1-arg*sarg)/(1-model->MOS2bulkJctBotGradingCoeff)
+here->MOS2Cbssw*
(1-arg*sargsw)/
(1-model->MOS2bulkJctSideGradingCoeff));
here->MOS2capbs=here->MOS2Cbs*sarg+
here->MOS2Cbssw*sargsw;
} else {
*(ckt->CKTstate0 + here->MOS2qbs) = here->MOS2f4s +
vbs*(here->MOS2f2s+vbs*(here->MOS2f3s/2));
here->MOS2capbs=here->MOS2f2s+here->MOS2f3s*vbs;
}
} else {
*(ckt->CKTstate0 + here->MOS2qbs) = 0;
here->MOS2capbs=0;
}
}
#ifdef CAPBYPASS
if(((ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) ||
fabs(delvbd) >= ckt->CKTreltol * MAX(fabs(vbd),
fabs(*(ckt->CKTstate0+here->MOS2vbd)))+
ckt->CKTvoltTol)|| senflag)
#endif /*CAPBYPASS*/
/* can't bypass the diode capacitance calculations */
{
if(here->MOS2Cbd != 0 || here->MOS2Cbdsw != 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));
}
}
*(ckt->CKTstate0 + here->MOS2qbd) =
here->MOS2tBulkPot*(here->MOS2Cbd*
(1-arg*sarg)
/(1-model->MOS2bulkJctBotGradingCoeff)
+here->MOS2Cbdsw*
(1-arg*sargsw)
/(1-model->MOS2bulkJctSideGradingCoeff));
here->MOS2capbd=here->MOS2Cbd*sarg+
here->MOS2Cbdsw*sargsw;
} else {
*(ckt->CKTstate0 + here->MOS2qbd) = here->MOS2f4d +
vbd * (here->MOS2f2d + vbd * here->MOS2f3d/2);
here->MOS2capbd=here->MOS2f2d + vbd * here->MOS2f3d;
}
} else {
*(ckt->CKTstate0 + here->MOS2qbd) = 0;
here->MOS2capbd = 0;
}
}
if(SenCond && (ckt->CKTsenInfo->SENmode==TRANSEN)) goto next2;
if ( ckt->CKTmode & MODETRAN ) {
/* (above only excludes tranop, since we're only at this
* point if tran or tranop )
*/
/*
* calculate equivalent conductances and currents for
* depletion capacitors
*/
/* integrate the capacitors and save results */
error = NIintegrate(ckt,&geq,&ceq,here->MOS2capbd,
here->MOS2qbd);
if(error) return(error);
here->MOS2gbd += geq;
here->MOS2cbd += *(ckt->CKTstate0 + here->MOS2cqbd);
here->MOS2cd -= *(ckt->CKTstate0 + here->MOS2cqbd);
error = NIintegrate(ckt,&geq,&ceq,here->MOS2capbs,
here->MOS2qbs);
if(error) return(error);
here->MOS2gbs += geq;
here->MOS2cbs += *(ckt->CKTstate0 + here->MOS2cqbs);
}
}
if(SenCond) goto next2;
/*
* check convergence
*/
if ( (here->MOS2off == 0) ||
(!(ckt->CKTmode & (MODEINITFIX|MODEINITSMSIG))) ){
if (Check == 1) {
ckt->CKTnoncon++;
ckt->CKTtroubleElt = (GENinstance *) here;
}
}
next2: *(ckt->CKTstate0 + here->MOS2vbs) = vbs;
*(ckt->CKTstate0 + here->MOS2vbd) = vbd;
*(ckt->CKTstate0 + here->MOS2vgs) = vgs;
*(ckt->CKTstate0 + here->MOS2vds) = vds;
/*
* meyer's capacitor model
*/
if ( ckt->CKTmode & (MODETRAN|MODETRANOP|MODEINITSMSIG)) {
/*
* calculate meyer's capacitors
*/
if (here->MOS2mode > 0){
DEVqmeyer (vgs,vgd,vgb,von,vdsat,
(ckt->CKTstate0 + here->MOS2capgs),
(ckt->CKTstate0 + here->MOS2capgd),
(ckt->CKTstate0 + here->MOS2capgb),
here->MOS2tPhi,OxideCap);
} else {
DEVqmeyer (vgd,vgs,vgb,von,vdsat,
(ckt->CKTstate0 + here->MOS2capgd),
(ckt->CKTstate0 + here->MOS2capgs),
(ckt->CKTstate0 + here->MOS2capgb),
here->MOS2tPhi,OxideCap);
}
vgs1 = *(ckt->CKTstate1 + here->MOS2vgs);
vgd1 = vgs1 - *(ckt->CKTstate1 + here->MOS2vds);
vgb1 = vgs1 - *(ckt->CKTstate1 + here->MOS2vbs);
if(ckt->CKTmode & MODETRANOP) {
capgs = 2 * *(ckt->CKTstate0 + here->MOS2capgs)+
GateSourceOverlapCap;
capgd = 2 * *(ckt->CKTstate0 + here->MOS2capgd)+
GateDrainOverlapCap;
capgb = 2 * *(ckt->CKTstate0 + here->MOS2capgb)+
GateBulkOverlapCap;
} else {
capgs = *(ckt->CKTstate0 + here->MOS2capgs)+
*(ckt->CKTstate1 + here->MOS2capgs)+
GateSourceOverlapCap;
capgd = *(ckt->CKTstate0 + here->MOS2capgd)+
*(ckt->CKTstate1 + here->MOS2capgd)+
GateDrainOverlapCap;
capgb = *(ckt->CKTstate0 + here->MOS2capgb)+
*(ckt->CKTstate1 + here->MOS2capgb)+
GateBulkOverlapCap;
}
if(ckt->CKTsenInfo){
here->MOS2cgs = capgs;
here->MOS2cgd = capgd;
here->MOS2cgb = capgb;
}
/*
* store small-signal parameters (for meyer's model)
* all parameters already stored, so done...
*/
if(SenCond){
if(ckt->CKTsenInfo->SENmode & (DCSEN|ACSEN)){
continue;
}
}
#ifndef PREDICTOR
if(ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) {
*(ckt->CKTstate0 + here->MOS2qgs) =
(1+xfact) * *(ckt->CKTstate1 + here->MOS2qgs)
-xfact * *(ckt->CKTstate2 + here->MOS2qgs);
*(ckt->CKTstate0 + here->MOS2qgd) =
(1+xfact) * *(ckt->CKTstate1 + here->MOS2qgd)
-xfact * *(ckt->CKTstate2 + here->MOS2qgd);
*(ckt->CKTstate0 + here->MOS2qgb) =
(1+xfact) * *(ckt->CKTstate1 + here->MOS2qgb)
-xfact * *(ckt->CKTstate2 + here->MOS2qgb);
} else {
#endif /* PREDICTOR */
if(ckt->CKTmode & MODETRAN) {
*(ckt->CKTstate0 + here->MOS2qgs) = (vgs-vgs1)*capgs +
*(ckt->CKTstate1 + here->MOS2qgs) ;
*(ckt->CKTstate0 + here->MOS2qgd) = (vgd-vgd1)*capgd +
*(ckt->CKTstate1 + here->MOS2qgd) ;
*(ckt->CKTstate0 + here->MOS2qgb) = (vgb-vgb1)*capgb +
*(ckt->CKTstate1 + here->MOS2qgb) ;
} else {
/* TRANOP */
*(ckt->CKTstate0 + here->MOS2qgs) = capgs*vgs;
*(ckt->CKTstate0 + here->MOS2qgd) = capgd*vgd;
*(ckt->CKTstate0 + here->MOS2qgb) = capgb*vgb;
}
#ifndef PREDICTOR
}
#endif /* PREDICTOR */
}
#ifndef NOBYPASS
bypass:
#endif /* NOBYPASS */
if(SenCond) continue;
if((ckt->CKTmode & MODEINITTRAN) || (!(ckt->CKTmode & MODETRAN)) ) {
/* initialize to zero charge conductances and current */
gcgs=0;
ceqgs=0;
gcgd=0;
ceqgd=0;
gcgb=0;
ceqgb=0;
} else {
if(capgs == 0) *(ckt->CKTstate0 + here->MOS2cqgs) =0;
if(capgd == 0) *(ckt->CKTstate0 + here->MOS2cqgd) =0;
if(capgb == 0) *(ckt->CKTstate0 + here->MOS2cqgb) =0;
/*
* calculate equivalent conductances and currents for
* meyer"s capacitors
*/
error = NIintegrate(ckt,&gcgs,&ceqgs,capgs,here->MOS2qgs);
if(error) return(error);
error = NIintegrate(ckt,&gcgd,&ceqgd,capgd,here->MOS2qgd);
if(error) return(error);
error = NIintegrate(ckt,&gcgb,&ceqgb,capgb,here->MOS2qgb);
if(error) return(error);
ceqgs=ceqgs-gcgs*vgs+ckt->CKTag[0]*
*(ckt->CKTstate0 + here->MOS2qgs);
ceqgd=ceqgd-gcgd*vgd+ckt->CKTag[0]*
*(ckt->CKTstate0 + here->MOS2qgd);
ceqgb=ceqgb-gcgb*vgb+ckt->CKTag[0]*
*(ckt->CKTstate0 + here->MOS2qgb);
}
/*
* store charge storage info for meyer's cap in lx table
*/
/*
* load current vector
*/
ceqbs = model->MOS2type *
(here->MOS2cbs-(here->MOS2gbs)*vbs);
ceqbd = model->MOS2type *
(here->MOS2cbd-(here->MOS2gbd)*vbd);
if (here->MOS2mode >= 0) {
xnrm=1;
xrev=0;
cdreq=model->MOS2type*(cdrain-here->MOS2gds*vds-
here->MOS2gm*vgs-here->MOS2gmbs*vbs);
} else {
xnrm=0;
xrev=1;
cdreq = -(model->MOS2type)*(cdrain-here->MOS2gds*(-vds)-
here->MOS2gm*vgd-here->MOS2gmbs*vbd);
}
*(ckt->CKTrhs + here->MOS2gNode) -=
model->MOS2type * (ceqgs + ceqgb + ceqgd);
*(ckt->CKTrhs + here->MOS2bNode) -=
(ceqbs+ceqbd-model->MOS2type * ceqgb);
*(ckt->CKTrhs + here->MOS2dNodePrime) +=
ceqbd - cdreq + model->MOS2type * ceqgd;
*(ckt->CKTrhs + here->MOS2sNodePrime) +=
cdreq + ceqbs + model->MOS2type * ceqgs;
#if 0
printf(" loading %s at time %g\n", here->MOS2name, ckt->CKTtime);
printf("%g %g %g %g %g\n", here->MOS2drainConductance,
gcgd+gcgs+gcgb, here->MOS2sourceConductance,
here->MOS2gbd, here->MOS2gbs);
printf("%g %g %g %g %g\n", -gcgb, 0.0, 0.0,
here->MOS2gds, here->MOS2gm);
printf("%g %g %g %g %g\n", here->MOS2gds, here->MOS2gmbs,
gcgd, -gcgs, -gcgd);
printf("%g %g %g %g %g\n", -gcgs, -gcgd, 0.0, -gcgs, 0.0);
#endif
/*
* load y matrix
*/
*(here->MOS2DdPtr) += (here->MOS2drainConductance);
*(here->MOS2GgPtr) += gcgd+gcgs+gcgb;
*(here->MOS2SsPtr) += (here->MOS2sourceConductance);
*(here->MOS2BbPtr) += (here->MOS2gbd+here->MOS2gbs+gcgb);
*(here->MOS2DPdpPtr) += here->MOS2drainConductance+here->MOS2gds+
here->MOS2gbd+xrev*(here->MOS2gm+here->MOS2gmbs)+gcgd;
*(here->MOS2SPspPtr) += here->MOS2sourceConductance+here->MOS2gds+
here->MOS2gbs+xnrm*(here->MOS2gm+here->MOS2gmbs)+gcgs;
*(here->MOS2DdpPtr) -= here->MOS2drainConductance;
*(here->MOS2GbPtr) -= gcgb;
*(here->MOS2GdpPtr) -= gcgd;
*(here->MOS2GspPtr) -= gcgs;
*(here->MOS2SspPtr) -= here->MOS2sourceConductance;
*(here->MOS2BgPtr) -= gcgb;
*(here->MOS2BdpPtr) -= here->MOS2gbd;
*(here->MOS2BspPtr) -= here->MOS2gbs;
*(here->MOS2DPdPtr) -= here->MOS2drainConductance;
*(here->MOS2DPgPtr) += ((xnrm-xrev)*here->MOS2gm-gcgd);
*(here->MOS2DPbPtr) += (-here->MOS2gbd+(xnrm-xrev)*here->MOS2gmbs);
*(here->MOS2DPspPtr) -= here->MOS2gds+xnrm*(here->MOS2gm+
here->MOS2gmbs);
*(here->MOS2SPgPtr) -= (xnrm-xrev)*here->MOS2gm+gcgs;
*(here->MOS2SPsPtr) -= here->MOS2sourceConductance;
*(here->MOS2SPbPtr) -= here->MOS2gbs+(xnrm-xrev)*here->MOS2gmbs;
*(here->MOS2SPdpPtr) -= here->MOS2gds+xrev*(here->MOS2gm+
here->MOS2gmbs);
}
}
return(OK);
}