ngspice/src/spicelib/devices/mos3/mos3load.c

1343 lines
52 KiB
C

/**********
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Thomas L. Quarles
**********/
#include "ngspice.h"
#include <stdio.h>
#include "cktdefs.h"
#include "devdefs.h"
#include "mos3defs.h"
#include "trandefs.h"
#include "const.h"
#include "sperror.h"
#include "suffix.h"
int
MOS3load(inModel,ckt)
GENmodel *inModel;
register CKTcircuit *ckt;
/* actually load the current value into the
* sparse matrix previously provided
*/
{
register MOS3model *model = (MOS3model *)inModel;
register MOS3instance *here;
double Beta;
double DrainSatCur;
double EffectiveLength;
double GateBulkOverlapCap;
double GateDrainOverlapCap;
double GateSourceOverlapCap;
double OxideCap;
double SourceSatCur;
double arg;
double cbhat;
double cdhat;
double cdrain;
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 xfact;
int xnrm;
int xrev;
double capgs; /* total gate-source capacitance */
double capgd; /* total gate-drain capacitance */
double capgb; /* total gate-bulk capacitance */
int Check;
#ifndef NOBYPASS
double tempv;
#endif /*NOBYPASS*/
int error;
#ifdef CAPBYPASS
int senflag;
#endif /* CAPBYPASS */
int SenCond;
double vt; /* vt at instance temperature */
#ifdef CAPBYPASS
senflag = 0;
#endif /* CAPBYPASS */
if(ckt->CKTsenInfo){
if(ckt->CKTsenInfo->SENstatus == PERTURBATION) {
if((ckt->CKTsenInfo->SENmode == ACSEN)||
(ckt->CKTsenInfo->SENmode == TRANSEN)){
#ifdef CAPBYPASS
senflag = 1;
#endif /* CAPBYPASS */
}
goto next;
}
}
/* loop through all the MOS3 device models */
next:
for( ; model != NULL; model = model->MOS3nextModel ) {
/* loop through all the instances of the model */
for (here = model->MOS3instances; here != NULL ;
here=here->MOS3nextInstance) {
if (here->MOS3owner != ARCHme) continue;
vt = CONSTKoverQ * here->MOS3temp;
Check=1;
if(ckt->CKTsenInfo){
#ifdef SENSDEBUG
printf("MOS3load \n");
#endif /* SENSDEBUG */
if(ckt->CKTsenInfo->SENstatus == PERTURBATION)
if(here->MOS3senPertFlag == OFF)continue;
}
SenCond = ckt->CKTsenInfo && here->MOS3senPertFlag;
#ifdef DETAILPROF
asm(" .globl mos3pta");
asm("mos3pta:");
#endif /* DETAILPROF */
/* first, we compute a few useful values - these could be
* pre-computed, but for historical reasons are still done
* here. They may be moved at the expense of instance size
*/
EffectiveLength=here->MOS3l - 2*model->MOS3latDiff;
if( (here->MOS3tSatCurDens == 0) ||
(here->MOS3drainArea == 0) ||
(here->MOS3sourceArea == 0)) {
DrainSatCur = here->MOS3tSatCur;
SourceSatCur = here->MOS3tSatCur;
} else {
DrainSatCur = here->MOS3tSatCurDens *
here->MOS3drainArea;
SourceSatCur = here->MOS3tSatCurDens *
here->MOS3sourceArea;
}
GateSourceOverlapCap = model->MOS3gateSourceOverlapCapFactor *
here->MOS3w;
GateDrainOverlapCap = model->MOS3gateDrainOverlapCapFactor *
here->MOS3w;
GateBulkOverlapCap = model->MOS3gateBulkOverlapCapFactor *
EffectiveLength;
Beta = here->MOS3tTransconductance * here->MOS3w/EffectiveLength;
OxideCap = model->MOS3oxideCapFactor * EffectiveLength *
here->MOS3w;
if(SenCond){
#ifdef SENSDEBUG
printf("MOS3senPertFlag = ON \n");
#endif /* SENSDEBUG */
if((ckt->CKTsenInfo->SENmode == TRANSEN) &&
(ckt->CKTmode & MODEINITTRAN)) {
vgs = *(ckt->CKTstate1 + here->MOS3vgs);
vds = *(ckt->CKTstate1 + here->MOS3vds);
vbs = *(ckt->CKTstate1 + here->MOS3vbs);
vbd = *(ckt->CKTstate1 + here->MOS3vbd);
vgb = vgs - vbs;
vgd = vgs - vds;
}
else if (ckt->CKTsenInfo->SENmode == ACSEN){
vgb = model->MOS3type * (
*(ckt->CKTrhsOp+here->MOS3gNode) -
*(ckt->CKTrhsOp+here->MOS3bNode));
vbs = *(ckt->CKTstate0 + here->MOS3vbs);
vbd = *(ckt->CKTstate0 + here->MOS3vbd);
vgd = vgb + vbd ;
vgs = vgb + vbs ;
vds = vbs - vbd ;
}
else{
vgs = *(ckt->CKTstate0 + here->MOS3vgs);
vds = *(ckt->CKTstate0 + here->MOS3vds);
vbs = *(ckt->CKTstate0 + here->MOS3vbs);
vbd = *(ckt->CKTstate0 + here->MOS3vbd);
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;
}
#ifdef DETAILPROF
asm(" .globl mos3ptax");
asm("mos3ptax:");
#endif /* DETAILPROF */
/*
* ok - now to do the start-up operations
*
* we must get values for vbs, vds, and vgs from somewhere
* so we either predict them or recover them from last iteration
* These are the two most common cases - either a prediction
* step or the general iteration step and they
* share some code, so we put them first - others later on
*/
if((ckt->CKTmode & (MODEINITFLOAT | MODEINITPRED | MODEINITSMSIG |
MODEINITTRAN)) ||
( (ckt->CKTmode & MODEINITFIX) && (!here->MOS3off) ) ) {
#ifndef PREDICTOR
if(ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) {
/* predictor step */
xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1];
*(ckt->CKTstate0 + here->MOS3vbs) =
*(ckt->CKTstate1 + here->MOS3vbs);
vbs = (1+xfact)* (*(ckt->CKTstate1 + here->MOS3vbs))
-(xfact * (*(ckt->CKTstate2 + here->MOS3vbs)));
*(ckt->CKTstate0 + here->MOS3vgs) =
*(ckt->CKTstate1 + here->MOS3vgs);
vgs = (1+xfact)* (*(ckt->CKTstate1 + here->MOS3vgs))
-(xfact * (*(ckt->CKTstate2 + here->MOS3vgs)));
*(ckt->CKTstate0 + here->MOS3vds) =
*(ckt->CKTstate1 + here->MOS3vds);
vds = (1+xfact)* (*(ckt->CKTstate1 + here->MOS3vds))
-(xfact * (*(ckt->CKTstate2 + here->MOS3vds)));
*(ckt->CKTstate0 + here->MOS3vbd) =
*(ckt->CKTstate0 + here->MOS3vbs)-
*(ckt->CKTstate0 + here->MOS3vds);
} else {
#endif /*PREDICTOR*/
/* general iteration */
vbs = model->MOS3type * (
*(ckt->CKTrhsOld+here->MOS3bNode) -
*(ckt->CKTrhsOld+here->MOS3sNodePrime));
vgs = model->MOS3type * (
*(ckt->CKTrhsOld+here->MOS3gNode) -
*(ckt->CKTrhsOld+here->MOS3sNodePrime));
vds = model->MOS3type * (
*(ckt->CKTrhsOld+here->MOS3dNodePrime) -
*(ckt->CKTrhsOld+here->MOS3sNodePrime));
#ifndef PREDICTOR
}
#endif /*PREDICTOR*/
/* now some common crunching for some more useful quantities */
#ifdef DETAILPROF
asm(" .globl mos3ptay");
asm("mos3ptay:");
#endif /* DETAILPROF */
vbd=vbs-vds;
vgd=vgs-vds;
vgdo = *(ckt->CKTstate0 + here->MOS3vgs) -
*(ckt->CKTstate0 + here->MOS3vds);
delvbs = vbs - *(ckt->CKTstate0 + here->MOS3vbs);
delvbd = vbd - *(ckt->CKTstate0 + here->MOS3vbd);
delvgs = vgs - *(ckt->CKTstate0 + here->MOS3vgs);
delvds = vds - *(ckt->CKTstate0 + here->MOS3vds);
delvgd = vgd-vgdo;
/* these are needed for convergence testing */
if (here->MOS3mode >= 0) {
cdhat=
here->MOS3cd-
here->MOS3gbd * delvbd +
here->MOS3gmbs * delvbs +
here->MOS3gm * delvgs +
here->MOS3gds * delvds ;
} else {
cdhat=
here->MOS3cd -
( here->MOS3gbd -
here->MOS3gmbs) * delvbd -
here->MOS3gm * delvgd +
here->MOS3gds * delvds ;
}
cbhat=
here->MOS3cbs +
here->MOS3cbd +
here->MOS3gbd * delvbd +
here->MOS3gbs * delvbs ;
#ifdef DETAILPROF
asm(" .globl mos3ptb");
asm("mos3ptb:");
#endif /* DETAILPROF */
#ifndef NOBYPASS
/* now lets see if we can bypass (ugh) */
/* the following mess should be one if statement, but
* many compilers can't handle it all at once, so it
* is split into several successive if statements
*/
tempv = MAX(fabs(cbhat),fabs(here->MOS3cbs
+ here->MOS3cbd))+ckt->CKTabstol;
if((!(ckt->CKTmode & (MODEINITPRED|MODEINITTRAN|MODEINITSMSIG)
)) && (ckt->CKTbypass) )
if ( (fabs(cbhat-(here->MOS3cbs +
here->MOS3cbd)) < ckt->CKTreltol *
tempv))
if( (fabs(delvbs) < (ckt->CKTreltol * MAX(fabs(vbs),
fabs(*(ckt->CKTstate0+here->MOS3vbs)))+
ckt->CKTvoltTol)))
if ( (fabs(delvbd) < (ckt->CKTreltol * MAX(fabs(vbd),
fabs(*(ckt->CKTstate0+here->MOS3vbd)))+
ckt->CKTvoltTol)) )
if( (fabs(delvgs) < (ckt->CKTreltol * MAX(fabs(vgs),
fabs(*(ckt->CKTstate0+here->MOS3vgs)))+
ckt->CKTvoltTol)))
if ( (fabs(delvds) < (ckt->CKTreltol * MAX(fabs(vds),
fabs(*(ckt->CKTstate0+here->MOS3vds)))+
ckt->CKTvoltTol)) )
if( (fabs(cdhat- here->MOS3cd) <
ckt->CKTreltol * MAX(fabs(cdhat),fabs(
here->MOS3cd)) + 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->MOS3vbs);
vbd = *(ckt->CKTstate0 + here->MOS3vbd);
vgs = *(ckt->CKTstate0 + here->MOS3vgs);
vds = *(ckt->CKTstate0 + here->MOS3vds);
vgd = vgs - vds;
vgb = vgs - vbs;
cdrain = here->MOS3mode * (here->MOS3cd + here->MOS3cbd);
if(ckt->CKTmode & (MODETRAN | MODETRANOP)) {
capgs = ( *(ckt->CKTstate0+here->MOS3capgs)+
*(ckt->CKTstate1+here->MOS3capgs) +
GateSourceOverlapCap );
capgd = ( *(ckt->CKTstate0+here->MOS3capgd)+
*(ckt->CKTstate1+here->MOS3capgd) +
GateDrainOverlapCap );
capgb = ( *(ckt->CKTstate0+here->MOS3capgb)+
*(ckt->CKTstate1+here->MOS3capgb) +
GateBulkOverlapCap );
}
goto bypass;
}
#endif /*NOBYPASS*/
#ifdef DETAILPROF
asm(" .globl mos3ptc");
asm("mos3ptc:");
#endif /* DETAILPROF */
/* ok - bypass is out, do it the hard way */
von = model->MOS3type * here->MOS3von;
#ifndef NODELIMITING
/*
* limiting
* we want to keep device voltages from changing
* so fast that the exponentials churn out overflows
* and similar rudeness
*/
if(*(ckt->CKTstate0 + here->MOS3vds) >=0) {
vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->MOS3vgs)
,von);
vds = vgs - vgd;
vds = DEVlimvds(vds,*(ckt->CKTstate0 + here->MOS3vds));
vgd = vgs - vds;
} else {
vgd = DEVfetlim(vgd,vgdo,von);
vds = vgs - vgd;
if(!(ckt->CKTfixLimit)) {
vds = -DEVlimvds(-vds,-(*(ckt->CKTstate0 +
here->MOS3vds)));
}
vgs = vgd + vds;
}
if(vds >= 0) {
vbs = DEVpnjlim(vbs,*(ckt->CKTstate0 + here->MOS3vbs),
vt,here->MOS3sourceVcrit,&Check);
vbd = vbs-vds;
} else {
vbd = DEVpnjlim(vbd,*(ckt->CKTstate0 + here->MOS3vbd),
vt,here->MOS3drainVcrit,&Check);
vbs = vbd + vds;
}
#endif /*NODELIMITING*/
} else {
#ifdef DETAILPROF
asm(" .globl mos3ptd");
asm("mos3ptd:");
#endif /* DETAILPROF */
/* ok - not one of the simple cases, so we have to
* look at all of the possibilities for why we were
* called. We still just initialize the three voltages
*/
if((ckt->CKTmode & MODEINITJCT) && !here->MOS3off) {
vds= model->MOS3type * here->MOS3icVDS;
vgs= model->MOS3type * here->MOS3icVGS;
vbs= model->MOS3type * here->MOS3icVBS;
if((vds==0) && (vgs==0) && (vbs==0) &&
((ckt->CKTmode &
(MODETRAN|MODEDCOP|MODEDCTRANCURVE)) ||
(!(ckt->CKTmode & MODEUIC)))) {
vbs = -1;
vgs = model->MOS3type * here->MOS3tVto;
vds = 0;
}
} else {
vbs=vgs=vds=0;
}
}
#ifdef DETAILPROF
asm(" .globl mos3pte");
asm("mos3pte:");
#endif /* DETAILPROF */
/*
* 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 diodes
* here we just evaluate the ideal diode current and the
* corresponding derivative (conductance).
*/
next1: if(vbs <= 0) {
here->MOS3gbs = SourceSatCur/vt;
here->MOS3cbs = here->MOS3gbs*vbs;
here->MOS3gbs += ckt->CKTgmin;
} else {
evbs = exp(MIN(MAX_EXP_ARG,vbs/vt));
here->MOS3gbs = SourceSatCur*evbs/vt + ckt->CKTgmin;
here->MOS3cbs = SourceSatCur * (evbs-1);
}
if(vbd <= 0) {
here->MOS3gbd = DrainSatCur/vt;
here->MOS3cbd = here->MOS3gbd *vbd;
here->MOS3gbd += ckt->CKTgmin;
} else {
evbd = exp(MIN(MAX_EXP_ARG,vbd/vt));
here->MOS3gbd = DrainSatCur*evbd/vt +ckt->CKTgmin;
here->MOS3cbd = DrainSatCur *(evbd-1);
}
/* now to determine whether the user was able to correctly
* identify the source and drain of his device
*/
if(vds >= 0) {
/* normal mode */
here->MOS3mode = 1;
} else {
/* inverse mode */
here->MOS3mode = -1;
}
#ifdef DETAILPROF
asm(" .globl mos3ptf");
asm("mos3ptf:");
#endif /* DETAILPROF */
{
/*
* subroutine moseq3(vds,vbs,vgs,gm,gds,gmbs,
* qg,qc,qb,cggb,cgdb,cgsb,cbgb,cbdb,cbsb)
*/
/*
* this routine evaluates the drain current, its derivatives and
* the charges associated with the gate, channel and bulk
* for mosfets based on semi-empirical equations
*/
/*
common /mosarg/ vto,beta,gamma,phi,phib,cox,xnsub,xnfs,xd,xj,xld,
1 xlamda,uo,uexp,vbp,utra,vmax,xneff,xl,xw,vbi,von,vdsat,qspof,
2 beta0,beta1,cdrain,xqco,xqc,fnarrw,fshort,lev
common /status/ omega,time,delta,delold(7),ag(7),vt,xni,egfet,
1 xmu,sfactr,mode,modedc,icalc,initf,method,iord,maxord,noncon,
2 iterno,itemno,nosolv,modac,ipiv,ivmflg,ipostp,iscrch,iofile
common /knstnt/ twopi,xlog2,xlog10,root2,rad,boltz,charge,ctok,
1 gmin,reltol,abstol,vntol,trtol,chgtol,eps0,epssil,epsox,
2 pivtol,pivrel
*/
/* equivalence (xlamda,alpha),(vbp,theta),(uexp,eta),(utra,xkappa)*/
double coeff0 = 0.0631353e0;
double coeff1 = 0.8013292e0;
double coeff2 = -0.01110777e0;
double oneoverxl; /* 1/effective length */
double eta; /* eta from model after length factor */
double phibs; /* phi - vbs */
double sqphbs; /* square root of phibs */
double dsqdvb; /* */
double sqphis; /* square root of phi */
double sqphs3; /* square root of phi cubed */
double wps;
double oneoverxj; /* 1/junction depth */
double xjonxl; /* junction depth/effective length */
double djonxj;
double wponxj;
double arga;
double argb;
double argc;
double dwpdvb;
double dadvb;
double dbdvb;
double gammas;
double fbodys;
double fbody;
double onfbdy;
double qbonco;
double vbix;
double wconxj;
double dfsdvb;
double dfbdvb;
double dqbdvb;
double vth;
double dvtdvb;
double csonco;
double cdonco;
double dxndvb;
double dvodvb;
double dvodvd;
double vgsx;
double dvtdvd;
double onfg;
double fgate;
double us;
double dfgdvg;
double dfgdvd;
double dfgdvb;
double dvsdvg;
double dvsdvb;
double dvsdvd;
double xn;
double vdsc;
double onvdsc;
double dvsdga;
double vdsx;
double dcodvb;
double cdnorm;
double cdo;
double cd1;
double fdrain;
double fd2;
double dfddvg;
double dfddvb;
double dfddvd;
double gdsat;
double cdsat;
double gdoncd;
double gdonfd;
double gdonfg;
double dgdvg;
double dgdvd;
double dgdvb;
double emax;
double emongd;
double demdvg;
double demdvd;
double demdvb;
double delxl;
double dldvd;
double dldem;
double ddldvg;
double ddldvd;
double ddldvb;
double dlonxl;
double xlfact;
double diddl;
double gds0;
double emoncd;
double ondvt;
double onxn;
double wfact;
double gms;
double gmw;
double fshort;
/*
* bypasses the computation of charges
*/
/*
* reference cdrain equations to source and
* charge equations to bulk
*/
vdsat = 0.0;
oneoverxl = 1.0/EffectiveLength;
eta = model->MOS3eta * 8.15e-22/(model->MOS3oxideCapFactor*
EffectiveLength*EffectiveLength*EffectiveLength);
/*
*.....square root term
*/
if ( (here->MOS3mode==1?vbs:vbd) <= 0.0 ) {
phibs = here->MOS3tPhi-(here->MOS3mode==1?vbs:vbd);
sqphbs = sqrt(phibs);
dsqdvb = -0.5/sqphbs;
} else {
sqphis = sqrt(here->MOS3tPhi);
sqphs3 = here->MOS3tPhi*sqphis;
sqphbs = sqphis/(1.0+(here->MOS3mode==1?vbs:vbd)/
(here->MOS3tPhi+here->MOS3tPhi));
phibs = sqphbs*sqphbs;
dsqdvb = -phibs/(sqphs3+sqphs3);
}
/*
*.....short channel effect factor
*/
if ( (model->MOS3junctionDepth != 0.0) &&
(model->MOS3coeffDepLayWidth != 0.0) ) {
wps = model->MOS3coeffDepLayWidth*sqphbs;
oneoverxj = 1.0/model->MOS3junctionDepth;
xjonxl = model->MOS3junctionDepth*oneoverxl;
djonxj = model->MOS3latDiff*oneoverxj;
wponxj = wps*oneoverxj;
wconxj = coeff0+coeff1*wponxj+coeff2*wponxj*wponxj;
arga = wconxj+djonxj;
argc = wponxj/(1.0+wponxj);
argb = sqrt(1.0-argc*argc);
fshort = 1.0-xjonxl*(arga*argb-djonxj);
dwpdvb = model->MOS3coeffDepLayWidth*dsqdvb;
dadvb = (coeff1+coeff2*(wponxj+wponxj))*dwpdvb*oneoverxj;
dbdvb = -argc*argc*(1.0-argc)*dwpdvb/(argb*wps);
dfsdvb = -xjonxl*(dadvb*argb+arga*dbdvb);
} else {
fshort = 1.0;
dfsdvb = 0.0;
}
/*
*.....body effect
*/
gammas = model->MOS3gamma*fshort;
fbodys = 0.5*gammas/(sqphbs+sqphbs);
fbody = fbodys+model->MOS3narrowFactor/here->MOS3w;
onfbdy = 1.0/(1.0+fbody);
dfbdvb = -fbodys*dsqdvb/sqphbs+fbodys*dfsdvb/fshort;
qbonco =gammas*sqphbs+model->MOS3narrowFactor*phibs/here->MOS3w;
dqbdvb = gammas*dsqdvb+model->MOS3gamma*dfsdvb*sqphbs-
model->MOS3narrowFactor/here->MOS3w;
/*
*.....static feedback effect
*/
vbix = here->MOS3tVbi*model->MOS3type-eta*(here->MOS3mode*vds);
/*
*.....threshold voltage
*/
vth = vbix+qbonco;
dvtdvd = -eta;
dvtdvb = dqbdvb;
/*
*.....joint weak inversion and strong inversion
*/
von = vth;
if ( model->MOS3fastSurfaceStateDensity != 0.0 ) {
csonco = CHARGE*model->MOS3fastSurfaceStateDensity *
1e4 /*(cm**2/m**2)*/ *EffectiveLength*here->MOS3w/OxideCap;
cdonco = qbonco/(phibs+phibs);
xn = 1.0+csonco+cdonco;
von = vth+vt*xn;
dxndvb = dqbdvb/(phibs+phibs)-qbonco*dsqdvb/(phibs*sqphbs);
dvodvd = dvtdvd;
dvodvb = dvtdvb+vt*dxndvb;
} else {
/*
*.....cutoff region
*/
if ( (here->MOS3mode==1?vgs:vgd) <= von ) {
cdrain = 0.0;
here->MOS3gm = 0.0;
here->MOS3gds = 0.0;
here->MOS3gmbs = 0.0;
goto innerline1000;
}
}
/*
*.....device is on
*/
vgsx = MAX((here->MOS3mode==1?vgs:vgd),von);
/*
*.....mobility modulation by gate voltage
*/
onfg = 1.0+model->MOS3theta*(vgsx-vth);
fgate = 1.0/onfg;
us = here->MOS3tSurfMob * 1e-4 /*(m**2/cm**2)*/ *fgate;
dfgdvg = -model->MOS3theta*fgate*fgate;
dfgdvd = -dfgdvg*dvtdvd;
dfgdvb = -dfgdvg*dvtdvb;
/*
*.....saturation voltage
*/
vdsat = (vgsx-vth)*onfbdy;
if ( model->MOS3maxDriftVel <= 0.0 ) {
dvsdvg = onfbdy;
dvsdvd = -dvsdvg*dvtdvd;
dvsdvb = -dvsdvg*dvtdvb-vdsat*dfbdvb*onfbdy;
} else {
vdsc = EffectiveLength*model->MOS3maxDriftVel/us;
onvdsc = 1.0/vdsc;
arga = (vgsx-vth)*onfbdy;
argb = sqrt(arga*arga+vdsc*vdsc);
vdsat = arga+vdsc-argb;
dvsdga = (1.0-arga/argb)*onfbdy;
dvsdvg = dvsdga-(1.0-vdsc/argb)*vdsc*dfgdvg*onfg;
dvsdvd = -dvsdvg*dvtdvd;
dvsdvb = -dvsdvg*dvtdvb-arga*dvsdga*dfbdvb;
}
/*
*.....current factors in linear region
*/
vdsx = MIN((here->MOS3mode*vds),vdsat);
if ( vdsx == 0.0 ) goto line900;
cdo = vgsx-vth-0.5*(1.0+fbody)*vdsx;
dcodvb = -dvtdvb-0.5*dfbdvb*vdsx;
/*
*.....normalized drain current
*/
cdnorm = cdo*vdsx;
here->MOS3gm = vdsx;
here->MOS3gds = vgsx-vth-(1.0+fbody+dvtdvd)*vdsx;
here->MOS3gmbs = dcodvb*vdsx;
/*
*.....drain current without velocity saturation effect
*/
cd1 = Beta*cdnorm;
Beta = Beta*fgate;
cdrain = Beta*cdnorm;
here->MOS3gm = Beta*here->MOS3gm+dfgdvg*cd1;
here->MOS3gds = Beta*here->MOS3gds+dfgdvd*cd1;
here->MOS3gmbs = Beta*here->MOS3gmbs;
/*
*.....velocity saturation factor
*/
if ( model->MOS3maxDriftVel != 0.0 ) {
fdrain = 1.0/(1.0+vdsx*onvdsc);
fd2 = fdrain*fdrain;
arga = fd2*vdsx*onvdsc*onfg;
dfddvg = -dfgdvg*arga;
dfddvd = -dfgdvd*arga-fd2*onvdsc;
dfddvb = -dfgdvb*arga;
/*
*.....drain current
*/
here->MOS3gm = fdrain*here->MOS3gm+dfddvg*cdrain;
here->MOS3gds = fdrain*here->MOS3gds+dfddvd*cdrain;
here->MOS3gmbs = fdrain*here->MOS3gmbs+dfddvb*cdrain;
cdrain = fdrain*cdrain;
Beta = Beta*fdrain;
}
/*
*.....channel length modulation
*/
if ( (here->MOS3mode*vds) <= vdsat ) goto line700;
if ( model->MOS3maxDriftVel <= 0.0 ) goto line510;
if (model->MOS3alpha == 0.0) goto line700;
cdsat = cdrain;
gdsat = cdsat*(1.0-fdrain)*onvdsc;
gdsat = MAX(1.0e-12,gdsat);
gdoncd = gdsat/cdsat;
gdonfd = gdsat/(1.0-fdrain);
gdonfg = gdsat*onfg;
dgdvg = gdoncd*here->MOS3gm-gdonfd*dfddvg+gdonfg*dfgdvg;
dgdvd = gdoncd*here->MOS3gds-gdonfd*dfddvd+gdonfg*dfgdvd;
dgdvb = gdoncd*here->MOS3gmbs-gdonfd*dfddvb+gdonfg*dfgdvb;
if (ckt->CKTbadMos3)
emax = cdsat*oneoverxl/gdsat;
else
emax = model->MOS3kappa * cdsat*oneoverxl/gdsat;
emoncd = emax/cdsat;
emongd = emax/gdsat;
demdvg = emoncd*here->MOS3gm-emongd*dgdvg;
demdvd = emoncd*here->MOS3gds-emongd*dgdvd;
demdvb = emoncd*here->MOS3gmbs-emongd*dgdvb;
arga = 0.5*emax*model->MOS3alpha;
argc = model->MOS3kappa*model->MOS3alpha;
argb = sqrt(arga*arga+argc*((here->MOS3mode*vds)-vdsat));
delxl = argb-arga;
if (argb != 0.0) {
dldvd = argc/(argb+argb);
dldem = 0.5*(arga/argb-1.0)*model->MOS3alpha;
} else {
dldvd = 0.0;
dldem = 0.0;
}
ddldvg = dldem*demdvg;
ddldvd = dldem*demdvd-dldvd;
ddldvb = dldem*demdvb;
goto line520;
line510:
delxl = sqrt(model->MOS3kappa*((here->MOS3mode*vds)-vdsat)*
model->MOS3alpha);
dldvd = 0.5*delxl/((here->MOS3mode*vds)-vdsat);
ddldvg = 0.0;
ddldvd = -dldvd;
ddldvb = 0.0;
/*
*.....punch through approximation
*/
line520:
if ( delxl > (0.5*EffectiveLength) ) {
delxl = EffectiveLength-(EffectiveLength*EffectiveLength/
(4.0*delxl));
arga = 4.0*(EffectiveLength-delxl)*(EffectiveLength-delxl)/
(EffectiveLength*EffectiveLength);
ddldvg = ddldvg*arga;
ddldvd = ddldvd*arga;
ddldvb = ddldvb*arga;
dldvd = dldvd*arga;
}
/*
*.....saturation region
*/
dlonxl = delxl*oneoverxl;
xlfact = 1.0/(1.0-dlonxl);
cdrain = cdrain*xlfact;
diddl = cdrain/(EffectiveLength-delxl);
here->MOS3gm = here->MOS3gm*xlfact+diddl*ddldvg;
gds0 = here->MOS3gds*xlfact+diddl*ddldvd;
here->MOS3gmbs = here->MOS3gmbs*xlfact+diddl*ddldvb;
here->MOS3gm = here->MOS3gm+gds0*dvsdvg;
here->MOS3gmbs = here->MOS3gmbs+gds0*dvsdvb;
here->MOS3gds = gds0*dvsdvd+diddl*dldvd;
/*
*.....finish strong inversion case
*/
line700:
if ( (here->MOS3mode==1?vgs:vgd) < von ) {
/*
*.....weak inversion
*/
onxn = 1.0/xn;
ondvt = onxn/vt;
wfact = exp( ((here->MOS3mode==1?vgs:vgd)-von)*ondvt );
cdrain = cdrain*wfact;
gms = here->MOS3gm*wfact;
gmw = cdrain*ondvt;
here->MOS3gm = gmw;
if ((here->MOS3mode*vds) > vdsat) {
here->MOS3gm = here->MOS3gm+gds0*dvsdvg*wfact;
}
here->MOS3gds = here->MOS3gds*wfact+(gms-gmw)*dvodvd;
here->MOS3gmbs = here->MOS3gmbs*wfact+(gms-gmw)*dvodvb-gmw*
((here->MOS3mode==1?vgs:vgd)-von)*onxn*dxndvb;
}
/*
*.....charge computation
*/
goto innerline1000;
/*
*.....special case of vds = 0.0d0
*/
line900:
Beta = Beta*fgate;
cdrain = 0.0;
here->MOS3gm = 0.0;
here->MOS3gds = Beta*(vgsx-vth);
here->MOS3gmbs = 0.0;
if ( (model->MOS3fastSurfaceStateDensity != 0.0) &&
((here->MOS3mode==1?vgs:vgd) < von) ) {
here->MOS3gds *=exp(((here->MOS3mode==1?vgs:vgd)-von)/(vt*xn));
}
innerline1000:;
/*
*.....done
*/
}
#ifdef DETAILPROF
asm(" .globl mos3ptg");
asm("mos3ptg:");
#endif /* DETAILPROF */
/* now deal with n vs p polarity */
here->MOS3von = model->MOS3type * von;
here->MOS3vdsat = model->MOS3type * vdsat;
/* line 490 */
/*
* COMPUTE EQUIVALENT DRAIN CURRENT SOURCE
*/
here->MOS3cd=here->MOS3mode * cdrain - here->MOS3cbd;
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->MOS3vbs)))+
ckt->CKTvoltTol)|| senflag )
#endif /*CAPBYPASS*/
{
/* can't bypass the diode capacitance calculations */
#ifdef CAPZEROBYPASS
if(here->MOS3Cbs != 0 || here->MOS3Cbssw != 0 ) {
#endif /*CAPZEROBYPASS*/
if (vbs < here->MOS3tDepCap){
arg=1-vbs/here->MOS3tBulkPot;
/*
* 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!)
*/
#ifndef NOSQRT
if(model->MOS3bulkJctBotGradingCoeff ==
model->MOS3bulkJctSideGradingCoeff) {
if(model->MOS3bulkJctBotGradingCoeff == .5) {
sarg = sargsw = 1/sqrt(arg);
} else {
sarg = sargsw =
exp(-model->MOS3bulkJctBotGradingCoeff*
log(arg));
}
} else {
if(model->MOS3bulkJctBotGradingCoeff == .5) {
sarg = 1/sqrt(arg);
} else {
#endif /*NOSQRT*/
sarg = exp(-model->MOS3bulkJctBotGradingCoeff*
log(arg));
#ifndef NOSQRT
}
if(model->MOS3bulkJctSideGradingCoeff == .5) {
sargsw = 1/sqrt(arg);
} else {
#endif /*NOSQRT*/
sargsw =exp(-model->MOS3bulkJctSideGradingCoeff*
log(arg));
#ifndef NOSQRT
}
}
#endif /*NOSQRT*/
*(ckt->CKTstate0 + here->MOS3qbs) =
here->MOS3tBulkPot*(here->MOS3Cbs*
(1-arg*sarg)/(1-model->MOS3bulkJctBotGradingCoeff)
+here->MOS3Cbssw*
(1-arg*sargsw)/
(1-model->MOS3bulkJctSideGradingCoeff));
here->MOS3capbs=here->MOS3Cbs*sarg+
here->MOS3Cbssw*sargsw;
} else {
*(ckt->CKTstate0 + here->MOS3qbs) = here->MOS3f4s +
vbs*(here->MOS3f2s+vbs*(here->MOS3f3s/2));
here->MOS3capbs=here->MOS3f2s+here->MOS3f3s*vbs;
}
#ifdef CAPZEROBYPASS
} else {
*(ckt->CKTstate0 + here->MOS3qbs) = 0;
here->MOS3capbs=0;
}
#endif /*CAPZEROBYPASS*/
}
#ifdef CAPBYPASS
if(((ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) ||
fabs(delvbd) >= ckt->CKTreltol * MAX(fabs(vbd),
fabs(*(ckt->CKTstate0+here->MOS3vbd)))+
ckt->CKTvoltTol)|| senflag )
#endif /*CAPBYPASS*/
/* can't bypass the diode capacitance calculations */
{
#ifdef CAPZEROBYPASS
if(here->MOS3Cbd != 0 || here->MOS3Cbdsw != 0 ) {
#endif /*CAPZEROBYPASS*/
if (vbd < here->MOS3tDepCap) {
arg=1-vbd/here->MOS3tBulkPot;
/*
* 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!)
*/
#ifndef NOSQRT
if(model->MOS3bulkJctBotGradingCoeff == .5 &&
model->MOS3bulkJctSideGradingCoeff == .5) {
sarg = sargsw = 1/sqrt(arg);
} else {
if(model->MOS3bulkJctBotGradingCoeff == .5) {
sarg = 1/sqrt(arg);
} else {
#endif /*NOSQRT*/
sarg = exp(-model->MOS3bulkJctBotGradingCoeff*
log(arg));
#ifndef NOSQRT
}
if(model->MOS3bulkJctSideGradingCoeff == .5) {
sargsw = 1/sqrt(arg);
} else {
#endif /*NOSQRT*/
sargsw =exp(-model->MOS3bulkJctSideGradingCoeff*
log(arg));
#ifndef NOSQRT
}
}
#endif /*NOSQRT*/
*(ckt->CKTstate0 + here->MOS3qbd) =
here->MOS3tBulkPot*(here->MOS3Cbd*
(1-arg*sarg)
/(1-model->MOS3bulkJctBotGradingCoeff)
+here->MOS3Cbdsw*
(1-arg*sargsw)
/(1-model->MOS3bulkJctSideGradingCoeff));
here->MOS3capbd=here->MOS3Cbd*sarg+
here->MOS3Cbdsw*sargsw;
} else {
*(ckt->CKTstate0 + here->MOS3qbd) = here->MOS3f4d +
vbd * (here->MOS3f2d + vbd * here->MOS3f3d/2);
here->MOS3capbd=here->MOS3f2d + vbd * here->MOS3f3d;
}
#ifdef CAPZEROBYPASS
} else {
*(ckt->CKTstate0 + here->MOS3qbd) = 0;
here->MOS3capbd = 0;
}
#endif /*CAPZEROBYPASS*/
}
#ifdef DETAILPROF
asm(" .globl mos3pth");
asm("mos3pth:");
#endif /* DETAILPROF */
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->MOS3capbd,
here->MOS3qbd);
if(error) return(error);
here->MOS3gbd += geq;
here->MOS3cbd += *(ckt->CKTstate0 + here->MOS3cqbd);
here->MOS3cd -= *(ckt->CKTstate0 + here->MOS3cqbd);
error = NIintegrate(ckt,&geq,&ceq,here->MOS3capbs,
here->MOS3qbs);
if(error) return(error);
here->MOS3gbs += geq;
here->MOS3cbs += *(ckt->CKTstate0 + here->MOS3cqbs);
}
}
#ifdef DETAILPROF
asm(" .globl mos3pti");
asm("mos3pti:");
#endif /* DETAILPROF */
if(SenCond) goto next2;
/*
* check convergence
*/
if ( (here->MOS3off == 0) ||
(!(ckt->CKTmode & (MODEINITFIX|MODEINITSMSIG))) ){
if (Check == 1) {
ckt->CKTnoncon++;
ckt->CKTtroubleElt = (GENinstance *) here;
#ifndef NEWCONV
} else {
tol=ckt->CKTreltol*MAX(fabs(cdhat),
fabs(here->MOS3cd))+ckt->CKTabstol;
if (fabs(cdhat-here->MOS3cd) >= tol) {
ckt->CKTnoncon++;
ckt->CKTtroubleElt = (GENinstance *) here;
} else {
tol=ckt->CKTreltol*MAX(fabs(cbhat),
fabs(here->MOS3cbs+here->MOS3cbd))+
ckt->CKTabstol;
if (fabs(cbhat-(here->MOS3cbs+here->MOS3cbd)) > tol) {
ckt->CKTnoncon++;
ckt->CKTtroubleElt = (GENinstance *) here;
}
}
#endif /* NEWCONV */
}
}
#ifdef DETAILPROF
asm(" .globl mos3ptj");
asm("mos3ptj:");
#endif /* DETAILPROF */
/* save things away for next time */
next2: *(ckt->CKTstate0 + here->MOS3vbs) = vbs;
*(ckt->CKTstate0 + here->MOS3vbd) = vbd;
*(ckt->CKTstate0 + here->MOS3vgs) = vgs;
*(ckt->CKTstate0 + here->MOS3vds) = vds;
#ifdef DETAILPROF
asm(" .globl mos3ptk");
asm("mos3ptk:");
#endif /* DETAILPROF */
/*
* meyer's capacitor model
*/
if ( ckt->CKTmode & (MODETRAN | MODETRANOP | MODEINITSMSIG) ) {
/*
* calculate meyer's capacitors
*/
/*
* new cmeyer - this just evaluates at the current time,
* expects you to remember values from previous time
* returns 1/2 of non-constant portion of capacitance
* you must add in the other half from previous time
* and the constant part
*/
if (here->MOS3mode > 0){
DEVqmeyer (vgs,vgd,vgb,von,vdsat,
(ckt->CKTstate0 + here->MOS3capgs),
(ckt->CKTstate0 + here->MOS3capgd),
(ckt->CKTstate0 + here->MOS3capgb),
here->MOS3tPhi,OxideCap);
} else {
DEVqmeyer (vgd,vgs,vgb,von,vdsat,
(ckt->CKTstate0 + here->MOS3capgd),
(ckt->CKTstate0 + here->MOS3capgs),
(ckt->CKTstate0 + here->MOS3capgb),
here->MOS3tPhi,OxideCap);
}
vgs1 = *(ckt->CKTstate1 + here->MOS3vgs);
vgd1 = vgs1 - *(ckt->CKTstate1 + here->MOS3vds);
vgb1 = vgs1 - *(ckt->CKTstate1 + here->MOS3vbs);
if(ckt->CKTmode & MODETRANOP) {
capgs = 2 * *(ckt->CKTstate0+here->MOS3capgs)+
GateSourceOverlapCap ;
capgd = 2 * *(ckt->CKTstate0+here->MOS3capgd)+
GateDrainOverlapCap ;
capgb = 2 * *(ckt->CKTstate0+here->MOS3capgb)+
GateBulkOverlapCap ;
} else {
capgs = ( *(ckt->CKTstate0+here->MOS3capgs)+
*(ckt->CKTstate1+here->MOS3capgs) +
GateSourceOverlapCap );
capgd = ( *(ckt->CKTstate0+here->MOS3capgd)+
*(ckt->CKTstate1+here->MOS3capgd) +
GateDrainOverlapCap );
capgb = ( *(ckt->CKTstate0+here->MOS3capgb)+
*(ckt->CKTstate1+here->MOS3capgb) +
GateBulkOverlapCap );
}
if(ckt->CKTsenInfo){
here->MOS3cgs = capgs;
here->MOS3cgd = capgd;
here->MOS3cgb = capgb;
}
#ifdef DETAILPROF
asm(" .globl mos3ptl");
asm("mos3ptl:");
#endif /* DETAILPROF */
/*
* 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->MOS3qgs) =
(1+xfact) * *(ckt->CKTstate1 + here->MOS3qgs)
- xfact * *(ckt->CKTstate2 + here->MOS3qgs);
*(ckt->CKTstate0 + here->MOS3qgd) =
(1+xfact) * *(ckt->CKTstate1 + here->MOS3qgd)
- xfact * *(ckt->CKTstate2 + here->MOS3qgd);
*(ckt->CKTstate0 + here->MOS3qgb) =
(1+xfact) * *(ckt->CKTstate1 + here->MOS3qgb)
- xfact * *(ckt->CKTstate2 + here->MOS3qgb);
} else {
#endif /*PREDICTOR*/
if(ckt->CKTmode & MODETRAN) {
*(ckt->CKTstate0 + here->MOS3qgs) = (vgs-vgs1)*capgs +
*(ckt->CKTstate1 + here->MOS3qgs) ;
*(ckt->CKTstate0 + here->MOS3qgd) = (vgd-vgd1)*capgd +
*(ckt->CKTstate1 + here->MOS3qgd) ;
*(ckt->CKTstate0 + here->MOS3qgb) = (vgb-vgb1)*capgb +
*(ckt->CKTstate1 + here->MOS3qgb) ;
} else {
/* TRANOP only */
*(ckt->CKTstate0 + here->MOS3qgs) = vgs*capgs;
*(ckt->CKTstate0 + here->MOS3qgd) = vgd*capgd;
*(ckt->CKTstate0 + here->MOS3qgb) = vgb*capgb;
}
#ifndef PREDICTOR
}
#endif /*PREDICTOR*/
}
bypass:
if(SenCond) continue;
#ifdef DETAILPROF
asm(" .globl mos3ptm");
asm("mos3ptm:");
#endif /* DETAILPROF */
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->MOS3cqgs) =0;
if(capgd == 0) *(ckt->CKTstate0 + here->MOS3cqgd) =0;
if(capgb == 0) *(ckt->CKTstate0 + here->MOS3cqgb) =0;
/*
* calculate equivalent conductances and currents for
* meyer"s capacitors
*/
error = NIintegrate(ckt,&gcgs,&ceqgs,capgs,here->MOS3qgs);
if(error) return(error);
error = NIintegrate(ckt,&gcgd,&ceqgd,capgd,here->MOS3qgd);
if(error) return(error);
error = NIintegrate(ckt,&gcgb,&ceqgb,capgb,here->MOS3qgb);
if(error) return(error);
ceqgs=ceqgs-gcgs*vgs+ckt->CKTag[0]*
*(ckt->CKTstate0 + here->MOS3qgs);
ceqgd=ceqgd-gcgd*vgd+ckt->CKTag[0]*
*(ckt->CKTstate0 + here->MOS3qgd);
ceqgb=ceqgb-gcgb*vgb+ckt->CKTag[0]*
*(ckt->CKTstate0 + here->MOS3qgb);
}
/*
* store charge storage info for meyer's cap in lx table
*/
#ifdef DETAILPROF
asm(" .globl mos3ptn");
asm("mos3ptn:");
#endif /* DETAILPROF */
/*
* load current vector
*/
ceqbs = model->MOS3type *
(here->MOS3cbs-(here->MOS3gbs-ckt->CKTgmin)*vbs);
ceqbd = model->MOS3type *
(here->MOS3cbd-(here->MOS3gbd-ckt->CKTgmin)*vbd);
if (here->MOS3mode >= 0) {
xnrm=1;
xrev=0;
cdreq=model->MOS3type*(cdrain-here->MOS3gds*vds-
here->MOS3gm*vgs-here->MOS3gmbs*vbs);
} else {
xnrm=0;
xrev=1;
cdreq = -(model->MOS3type)*(cdrain-here->MOS3gds*(-vds)-
here->MOS3gm*vgd-here->MOS3gmbs*vbd);
}
*(ckt->CKTrhs + here->MOS3gNode) -=
(model->MOS3type * (ceqgs + ceqgb + ceqgd));
*(ckt->CKTrhs + here->MOS3bNode) -=
(ceqbs + ceqbd - model->MOS3type * ceqgb);
*(ckt->CKTrhs + here->MOS3dNodePrime) +=
(ceqbd - cdreq + model->MOS3type * ceqgd);
*(ckt->CKTrhs + here->MOS3sNodePrime) +=
cdreq + ceqbs + model->MOS3type * ceqgs;
/*
* load y matrix
*/
/*printf(" loading %s at time %g\n",here->MOS3name,ckt->CKTtime);*/
/*printf("%g %g %g %g %g\n", here->MOS3drainConductance,gcgd+gcgs+gcgb,
here->MOS3sourceConductance,here->MOS3gbd,here->MOS3gbs);*/
/*printf("%g %g %g %g %g\n",-gcgb,0.0,0.0,here->MOS3gds,here->MOS3gm);*/
/*printf("%g %g %g %g %g\n", here->MOS3gds,here->MOS3gmbs,gcgd,-gcgs,-gcgd);*/
/*printf("%g %g %g %g %g\n", -gcgs,-gcgd,0.0,-gcgs,0.0);*/
*(here->MOS3DdPtr) += (here->MOS3drainConductance);
*(here->MOS3GgPtr) += ((gcgd+gcgs+gcgb));
*(here->MOS3SsPtr) += (here->MOS3sourceConductance);
*(here->MOS3BbPtr) += (here->MOS3gbd+here->MOS3gbs+gcgb);
*(here->MOS3DPdpPtr) +=
(here->MOS3drainConductance+here->MOS3gds+
here->MOS3gbd+xrev*(here->MOS3gm+here->MOS3gmbs)+gcgd);
*(here->MOS3SPspPtr) +=
(here->MOS3sourceConductance+here->MOS3gds+
here->MOS3gbs+xnrm*(here->MOS3gm+here->MOS3gmbs)+gcgs);
*(here->MOS3DdpPtr) += (-here->MOS3drainConductance);
*(here->MOS3GbPtr) -= gcgb;
*(here->MOS3GdpPtr) -= gcgd;
*(here->MOS3GspPtr) -= gcgs;
*(here->MOS3SspPtr) += (-here->MOS3sourceConductance);
*(here->MOS3BgPtr) -= gcgb;
*(here->MOS3BdpPtr) -= here->MOS3gbd;
*(here->MOS3BspPtr) -= here->MOS3gbs;
*(here->MOS3DPdPtr) += (-here->MOS3drainConductance);
*(here->MOS3DPgPtr) += ((xnrm-xrev)*here->MOS3gm-gcgd);
*(here->MOS3DPbPtr) += (-here->MOS3gbd+(xnrm-xrev)*here->MOS3gmbs);
*(here->MOS3DPspPtr) += (-here->MOS3gds-
xnrm*(here->MOS3gm+here->MOS3gmbs));
*(here->MOS3SPgPtr) += (-(xnrm-xrev)*here->MOS3gm-gcgs);
*(here->MOS3SPsPtr) += (-here->MOS3sourceConductance);
*(here->MOS3SPbPtr) += (-here->MOS3gbs-(xnrm-xrev)*here->MOS3gmbs);
*(here->MOS3SPdpPtr) += (-here->MOS3gds-
xrev*(here->MOS3gm+here->MOS3gmbs));
}
}
return(OK);
}