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.
 
 
 
 
 
 

835 lines
34 KiB

/**********
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Thomas L. Quarles
Modified: 2000 AlansFixes
VDMOS: 2018 Holger Vogt
**********/
#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
#include "ngspice/devdefs.h"
#include "vdmosdefs.h"
#include "ngspice/trandefs.h"
#include "ngspice/const.h"
#include "ngspice/sperror.h"
#include "ngspice/suffix.h"
static double
cweakinv2(double sl, double shift, double vgst, double vds, double lambda, double beta, double vt, double mtr, double theta);
int
VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
/* actually load the current value into the
* sparse matrix previously provided
*/
{
VDMOSmodel *model = (VDMOSmodel *)inModel;
VDMOSinstance *here;
double Beta;
double DrainSatCur;
double SourceSatCur;
double arg;
double cdhat;
double cdrain;
double cdreq;
double ceq;
double ceqgd;
double ceqgs;
double delvds;
double delvgd;
double delvgs;
double gcgd;
double gcgs;
double geq;
double sarg;
double vds;
double vdsat;
double vgd1;
double vgd;
double vgdo;
double vgs1;
double vgs;
double von;
double vt;
#ifndef PREDICTOR
double xfact = 0.0;
#endif
int xnrm;
int xrev;
double capgs = 0.0; /* total gate-source capacitance */
double capgd = 0.0; /* total gate-drain capacitance */
int Check;
int error;
double CGBdummy;
/* loop through all the VDMOS device models */
for (; model != NULL; model = VDMOSnextModel(model)) {
/* VDMOS capacitance parameters */
const double cgdmin = model->VDMOScgdmin;
const double cgdmax = model->VDMOScgdmax;
const double a = model->VDMOSa;
const double cgs = model->VDMOScgs;
/* loop through all the instances of the model */
for (here = VDMOSinstances(model); here != NULL;
here = VDMOSnextInstance(here)) {
vt = CONSTKoverQ * here->VDMOStemp;
Check = 1;
/* 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
*/
DrainSatCur = here->VDMOSm * here->VDMOStSatCur;
SourceSatCur = here->VDMOSm * here->VDMOStSatCur;
Beta = here->VDMOStTransconductance * here->VDMOSm *
here->VDMOSw / here->VDMOSl;
/*
* 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->VDMOSoff))) {
#ifndef PREDICTOR
if (ckt->CKTmode & (MODEINITPRED | MODEINITTRAN)) {
/* predictor step */
xfact = ckt->CKTdelta / ckt->CKTdeltaOld[1];
*(ckt->CKTstate0 + here->VDMOSvgs) =
*(ckt->CKTstate1 + here->VDMOSvgs);
vgs = (1 + xfact)* (*(ckt->CKTstate1 + here->VDMOSvgs))
- (xfact * (*(ckt->CKTstate2 + here->VDMOSvgs)));
*(ckt->CKTstate0 + here->VDMOSvds) =
*(ckt->CKTstate1 + here->VDMOSvds);
vds = (1 + xfact)* (*(ckt->CKTstate1 + here->VDMOSvds))
- (xfact * (*(ckt->CKTstate2 + here->VDMOSvds)));
} else {
#endif /* PREDICTOR */
/* general iteration */
vgs = model->VDMOStype * (
*(ckt->CKTrhsOld + here->VDMOSgNodePrime) -
*(ckt->CKTrhsOld + here->VDMOSsNodePrime));
vds = model->VDMOStype * (
*(ckt->CKTrhsOld + here->VDMOSdNodePrime) -
*(ckt->CKTrhsOld + here->VDMOSsNodePrime));
#ifndef PREDICTOR
}
#endif /* PREDICTOR */
/* now some common crunching for some more useful quantities */
vgd = vgs - vds;
vgdo = *(ckt->CKTstate0 + here->VDMOSvgs) -
*(ckt->CKTstate0 + here->VDMOSvds);
delvgs = vgs - *(ckt->CKTstate0 + here->VDMOSvgs);
delvds = vds - *(ckt->CKTstate0 + here->VDMOSvds);
delvgd = vgd - vgdo;
/* these are needed for convergence testing */
if (here->VDMOSmode >= 0) {
cdhat =
here->VDMOScd
+ here->VDMOSgm * delvgs
+ here->VDMOSgds * delvds;
} else {
cdhat =
here->VDMOScd
- here->VDMOSgm * delvgd
+ here->VDMOSgds * delvds;
}
#ifndef NOBYPASS
/* now lets see if we can bypass (ugh) */
if ((!(ckt->CKTmode &
(MODEINITPRED | MODEINITTRAN | MODEINITSMSIG))) &&
(ckt->CKTbypass) &&
(fabs(delvgs) < (ckt->CKTreltol *
MAX(fabs(vgs),
fabs(*(ckt->CKTstate0 +
here->VDMOSvgs))) +
ckt->CKTvoltTol)) &&
(fabs(delvds) < (ckt->CKTreltol *
MAX(fabs(vds),
fabs(*(ckt->CKTstate0 +
here->VDMOSvds))) +
ckt->CKTvoltTol)) &&
(fabs(cdhat - here->VDMOScd) < (ckt->CKTreltol *
MAX(fabs(cdhat),
fabs(here->VDMOScd)) +
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
*/
vgs = *(ckt->CKTstate0 + here->VDMOSvgs);
vds = *(ckt->CKTstate0 + here->VDMOSvds);
vgd = vgs - vds;
cdrain = here->VDMOSmode * (here->VDMOScd);
if (ckt->CKTmode & (MODETRAN | MODETRANOP)) {
capgs = (*(ckt->CKTstate0 + here->VDMOScapgs) +
*(ckt->CKTstate1 + here->VDMOScapgs));
capgd = (*(ckt->CKTstate0 + here->VDMOScapgd) +
*(ckt->CKTstate1 + here->VDMOScapgd));
}
goto bypass;
}
#endif /*NOBYPASS*/
/* ok - bypass is out, do it the hard way */
von = model->VDMOStype * here->VDMOSvon;
#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->VDMOSvds) >= 0) {
vgs = DEVfetlim(vgs, *(ckt->CKTstate0 + here->VDMOSvgs)
, von);
vds = vgs - vgd;
vds = DEVlimvds(vds, *(ckt->CKTstate0 + here->VDMOSvds));
vgd = vgs - vds;
} else {
vgd = DEVfetlim(vgd, vgdo, von);
vds = vgs - vgd;
if (!(ckt->CKTfixLimit)) {
vds = -DEVlimvds(-vds, -(*(ckt->CKTstate0 +
here->VDMOSvds)));
}
vgs = vgd + vds;
}
#endif /*NODELIMITING*/
} else {
/* 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->VDMOSoff) {
vds = model->VDMOStype * here->VDMOSicVDS;
vgs = model->VDMOStype * here->VDMOSicVGS;
if ((vds == 0) && (vgs == 0) &&
((ckt->CKTmode &
(MODETRAN | MODEDCOP | MODEDCTRANCURVE)) ||
(!(ckt->CKTmode & MODEUIC)))) {
vgs = model->VDMOStype * here->VDMOStVto;
vds = 0;
}
} else {
vgs = vds = 0;
}
}
/*
* now all the preliminaries are over - we can start doing the
* real work
*/
vgd = vgs - vds;
/* now to determine whether the user was able to correctly
* identify the source and drain of his device
*/
if (vds >= 0) {
/* normal mode */
here->VDMOSmode = 1;
} else {
/* inverse mode */
here->VDMOSmode = -1;
}
{
/*
* this block of code evaluates the drain current and its
* derivatives using the shichman-hodges model and the
* charges associated with the gate, channel and bulk for
* mosfets
*
*/
/* the following 2 variables are local to this code block until
* it is obvious that they can be made global
*/
double betap;
double vgst;
von = (model->VDMOSvt0*model->VDMOStype);
vgst = (here->VDMOSmode == 1 ? vgs : vgd) - von;
vdsat = MAX(vgst, 0);
if (model->VDMOSksubthresGiven) {
/* Alternative simple weak inversion model, according to https://www.anasoft.co.uk/MOS1Model.htm
* Scale the voltage overdrive vgst logarithmically in weak inversion.
* Best fits LTSPICE curves with shift=0
* Drain current including subthreshold current */
double slope = model->VDMOSksubthres;
double lambda = model->VDMOSlambda;
double theta = model->VDMOStheta;
double shift = model->VDMOSsubshift;
double mtr = model->VDMOSmtr;
/* scale vds with mtr (except with lambda) */
double vdss = vds*mtr*here->VDMOSmode;
double t0 = 1 + lambda*vds;
double t1 = 1 + theta*vgs;
betap = Beta*t0/t1;
double dbetapdvgs = -Beta*theta*t0/(t1*t1);
double dbetapdvds = Beta*lambda/t1;
double t2 = exp((vgst-shift)/slope);
vgst = slope * log(1 + t2);
double dvgstdvgs = t2/(t2+1);
if (vgst <= vdss) {
/* saturation region */
cdrain = betap*vgst*vgst*.5;
here->VDMOSgm = betap*vgst*dvgstdvgs + 0.5*dbetapdvgs*vgst*vgst;
here->VDMOSgds = .5*dbetapdvds*vgst*vgst;
}
else {
/* linear region */
cdrain = betap * vdss * (vgst - .5 * vdss);
here->VDMOSgm = betap*vdss*dvgstdvgs + vdss*dbetapdvgs*(vgst-.5*vdss);
here->VDMOSgds = vdss*dbetapdvds*(vgst-.5*vdss) + betap*mtr*(vgst-.5*vdss) - .5*vdss*betap*mtr;
}
}
else if (model->VDMOSsubslGiven) {
/* numerical differentiation for gd and gm with a delta of 2 mV */
double vdsm = vds * here->VDMOSmode;
double delta = 0.001;
cdrain = cweakinv2(model->VDMOSsubsl, model->VDMOSsubshift, vgst, vdsm, model->VDMOSlambda,
Beta, vt, model->VDMOSmtr, model->VDMOStheta);
/* gd */
double vds1 = vdsm + delta;
double cdrp = cweakinv2(model->VDMOSsubsl, model->VDMOSsubshift, vgst, vds1, model->VDMOSlambda,
Beta, vt, model->VDMOSmtr, model->VDMOStheta);
vds1 = vdsm - delta;
double cdrm = cweakinv2(model->VDMOSsubsl, model->VDMOSsubshift, vgst, vds1, model->VDMOSlambda,
Beta, vt, model->VDMOSmtr, model->VDMOStheta);
here->VDMOSgds = (cdrp - cdrm) / (2. * delta);
/* gm */
double vgst1 = vgst + delta;
cdrp = cweakinv2(model->VDMOSsubsl, model->VDMOSsubshift, vgst1, vdsm, model->VDMOSlambda,
Beta, vt, model->VDMOSmtr, model->VDMOStheta);
vgst1 = vgst - delta;
cdrm = cweakinv2(model->VDMOSsubsl, model->VDMOSsubshift, vgst1, vdsm, model->VDMOSlambda,
Beta, vt, model->VDMOSmtr, model->VDMOStheta);
here->VDMOSgm = (cdrp - cdrm) / (2. * delta);
} else {
double onfg, fgate, Betam, dfgdvg;
onfg = 1.0+model->VDMOStheta*vgst;
fgate = 1.0/onfg;
Betam = Beta * fgate;
dfgdvg = -model->VDMOStheta*fgate*fgate;
if (vgst <= 0) {
/*
* cutoff region
*/
cdrain = 0;
here->VDMOSgm = 0;
here->VDMOSgds = 0;
} else {
/* scale vds with mtr */
double mtr = model->VDMOSmtr;
betap = Betam*(1 + model->VDMOSlambda*(vds*here->VDMOSmode));
if (vgst <= (vds * here->VDMOSmode) * mtr) {
/*
* saturation region
*/
cdrain = betap*vgst*vgst*.5;
here->VDMOSgm = betap*vgst * fgate + dfgdvg * cdrain;
here->VDMOSgds = model->VDMOSlambda*Betam*vgst*vgst*.5;
} else {
/*
* linear region
*/
cdrain = betap * (vds * here->VDMOSmode) * mtr *
(vgst - .5 * (vds*here->VDMOSmode) * mtr);
here->VDMOSgm = betap * (vds * here->VDMOSmode) * mtr * fgate + dfgdvg * cdrain;
here->VDMOSgds = betap * (vgst - (vds * here->VDMOSmode) * mtr) +
model->VDMOSlambda * Betam *
(vds * here->VDMOSmode) * mtr *
(vgst - .5 * (vds * here->VDMOSmode) * mtr);
}
}
}
}
/* now deal with n vs p polarity */
here->VDMOSvon = model->VDMOStype * von;
here->VDMOSvdsat = model->VDMOStype * vdsat;
/*
* COMPUTE EQUIVALENT DRAIN CURRENT SOURCE
*/
here->VDMOScd = here->VDMOSmode * cdrain;
/* save things away for next time */
*(ckt->CKTstate0 + here->VDMOSvgs) = vgs;
*(ckt->CKTstate0 + here->VDMOSvds) = vds;
/*
* vdmos capacitor model
*/
if (ckt->CKTmode & (MODETRAN | MODETRANOP | MODEINITSMSIG)) {
/*
* calculate gate - drain, gate - source capacitors
* drain-source capacitor is evaluated with the bulk diode below
*/
/*
* 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
*/
DevCapVDMOS(vgd, cgdmin, cgdmax, a, cgs,
(ckt->CKTstate0 + here->VDMOScapgs),
(ckt->CKTstate0 + here->VDMOScapgd),
&CGBdummy);
vgs1 = *(ckt->CKTstate1 + here->VDMOSvgs);
vgd1 = vgs1 - *(ckt->CKTstate1 + here->VDMOSvds);
if (ckt->CKTmode & (MODETRANOP | MODEINITSMSIG)) {
capgs = 2 * *(ckt->CKTstate0 + here->VDMOScapgs);
capgd = 2 * *(ckt->CKTstate0 + here->VDMOScapgd);
} else {
capgs = (*(ckt->CKTstate0 + here->VDMOScapgs) +
*(ckt->CKTstate1 + here->VDMOScapgs));
capgd = (*(ckt->CKTstate0 + here->VDMOScapgd) +
*(ckt->CKTstate1 + here->VDMOScapgd));
}
/*
*/
#ifndef PREDICTOR
if (ckt->CKTmode & (MODEINITPRED | MODEINITTRAN)) {
*(ckt->CKTstate0 + here->VDMOSqgs) =
(1 + xfact) * *(ckt->CKTstate1 + here->VDMOSqgs)
- xfact * *(ckt->CKTstate2 + here->VDMOSqgs);
*(ckt->CKTstate0 + here->VDMOSqgd) =
(1 + xfact) * *(ckt->CKTstate1 + here->VDMOSqgd)
- xfact * *(ckt->CKTstate2 + here->VDMOSqgd);
} else {
#endif /*PREDICTOR*/
if (ckt->CKTmode & MODETRAN) {
*(ckt->CKTstate0 + here->VDMOSqgs) = (vgs - vgs1)*capgs +
*(ckt->CKTstate1 + here->VDMOSqgs);
*(ckt->CKTstate0 + here->VDMOSqgd) = (vgd - vgd1)*capgd +
*(ckt->CKTstate1 + here->VDMOSqgd);
} else {
/* TRANOP only */
*(ckt->CKTstate0 + here->VDMOSqgs) = vgs*capgs;
*(ckt->CKTstate0 + here->VDMOSqgd) = vgd*capgd;
}
#ifndef PREDICTOR
}
#endif /*PREDICTOR*/
}
#ifndef NOBYPASS
bypass :
#endif
if ((ckt->CKTmode & (MODEINITTRAN)) ||
(!(ckt->CKTmode & (MODETRAN)))) {
/*
* initialize to zero charge conductances
* and current
*/
gcgs = 0;
ceqgs = 0;
gcgd = 0;
ceqgd = 0;
} else {
if (capgs == 0) *(ckt->CKTstate0 + here->VDMOScqgs) = 0;
if (capgd == 0) *(ckt->CKTstate0 + here->VDMOScqgd) = 0;
/*
* calculate equivalent conductances and currents for
* meyer"s capacitors
*/
error = NIintegrate(ckt, &gcgs, &ceqgs, capgs, here->VDMOSqgs);
if (error) return(error);
error = NIintegrate(ckt, &gcgd, &ceqgd, capgd, here->VDMOSqgd);
if (error) return(error);
ceqgs = ceqgs - gcgs*vgs + ckt->CKTag[0] *
*(ckt->CKTstate0 + here->VDMOSqgs);
ceqgd = ceqgd - gcgd*vgd + ckt->CKTag[0] *
*(ckt->CKTstate0 + here->VDMOSqgd);
}
/*
* load current vector
*/
if (here->VDMOSmode >= 0) {
xnrm = 1;
xrev = 0;
cdreq = model->VDMOStype*(cdrain - here->VDMOSgds*vds -
here->VDMOSgm*vgs);
} else {
xnrm = 0;
xrev = 1;
cdreq = -(model->VDMOStype)*(cdrain - here->VDMOSgds*(-vds) -
here->VDMOSgm*vgd);
}
*(ckt->CKTrhs + here->VDMOSgNodePrime) -=
(model->VDMOStype * (ceqgs + ceqgd));
*(ckt->CKTrhs + here->VDMOSdNodePrime) +=
(-cdreq + model->VDMOStype * ceqgd);
*(ckt->CKTrhs + here->VDMOSsNodePrime) +=
cdreq + model->VDMOStype * ceqgs;
/* quasi saturation
* according to Vincenzo d'Alessandro's Quasi-Saturation Model, simplified:
V. D'Alessandro, F. Frisina, N. Rinaldi: A New SPICE Model of VDMOS Transistors
Including Thermal and Quasi-saturation Effects, 9th European Conference on Power
Electronics and applications (EPE), Graz, Austria, August 2001, pp. P.1 − P.10.
*/
if (model->VDMOSqsGiven && (here->VDMOSmode == 1)) {
double vdsn = model->VDMOStype * (
*(ckt->CKTrhsOld + here->VDMOSdNode) -
*(ckt->CKTrhsOld + here->VDMOSsNode));
double rd = model->VDMOSdrainResistance + model->VDMOSqsResistance *
(vdsn / (vdsn + fabs(model->VDMOSqsVoltage)));
here->VDMOSdrainConductance = 1 / rd;
}
/*
* load y matrix
*/
*(here->VDMOSDdPtr) += (here->VDMOSdrainConductance + here->VDMOSdsConductance);
*(here->VDMOSGgPtr) += (here->VDMOSgateConductance); //((gcgd + gcgs + gcgb));
*(here->VDMOSSsPtr) += (here->VDMOSsourceConductance + here->VDMOSdsConductance);
*(here->VDMOSDPdpPtr) +=
(here->VDMOSdrainConductance + here->VDMOSgds +
xrev*(here->VDMOSgm) + gcgd);
*(here->VDMOSSPspPtr) +=
(here->VDMOSsourceConductance + here->VDMOSgds +
xnrm*(here->VDMOSgm) + gcgs);
*(here->VDMOSGPgpPtr) +=
(here->VDMOSgateConductance) + (gcgd + gcgs);
*(here->VDMOSGgpPtr) += (-here->VDMOSgateConductance);
*(here->VDMOSDdpPtr) += (-here->VDMOSdrainConductance);
*(here->VDMOSGPgPtr) += (-here->VDMOSgateConductance);
*(here->VDMOSGPdpPtr) -= gcgd;
*(here->VDMOSGPspPtr) -= gcgs;
*(here->VDMOSSspPtr) += (-here->VDMOSsourceConductance);
*(here->VDMOSDPdPtr) += (-here->VDMOSdrainConductance);
*(here->VDMOSDPgpPtr) += ((xnrm - xrev)*here->VDMOSgm - gcgd);
*(here->VDMOSDPspPtr) += (-here->VDMOSgds - xnrm*
(here->VDMOSgm));
*(here->VDMOSSPgpPtr) += (-(xnrm - xrev)*here->VDMOSgm - gcgs);
*(here->VDMOSSPsPtr) += (-here->VDMOSsourceConductance);
*(here->VDMOSSPdpPtr) += (-here->VDMOSgds - xrev*
(here->VDMOSgm));
*(here->VDMOSDsPtr) += (-here->VDMOSdsConductance);
*(here->VDMOSSdPtr) += (-here->VDMOSdsConductance);
/* bulk diode model
* Delivers reverse conduction and forward breakdown
* of VDMOS transistor
*/
double vd; /* current diode voltage */
double vdtemp;
double vte;
double vtebrk, vbrknp;
double cd, cdb, csat, cdeq;
double czero;
double czof2;
double capd;
double gd, gdb, gspr;
double delvd; /* change in diode voltage temporary */
double diffcharge, deplcharge, diffcap, deplcap;
double evd, evrev;
#ifndef NOBYPASS
double tol; /* temporary for tolerence calculations */
#endif
cd = 0.0;
cdb = 0.0;
gd = 0.0;
gdb = 0.0;
csat = here->VDIOtSatCur;
gspr = here->VDIOtConductance;
vte = model->VDMOSDn * vt;
vtebrk = model->VDIObrkdEmissionCoeff * vt;
vbrknp = here->VDIOtBrkdwnV;
Check = 1;
if (ckt->CKTmode & MODEINITSMSIG) {
vd = *(ckt->CKTstate0 + here->VDIOvoltage);
} else if (ckt->CKTmode & MODEINITTRAN) {
vd = *(ckt->CKTstate1 + here->VDIOvoltage);
} else if ((ckt->CKTmode & MODEINITJCT) &&
(ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) {
vd = here->VDIOinitCond;
} else if (ckt->CKTmode & MODEINITJCT) {
vd = here->VDIOtVcrit;
} else {
#ifndef PREDICTOR
if (ckt->CKTmode & MODEINITPRED) {
*(ckt->CKTstate0 + here->VDIOvoltage) =
*(ckt->CKTstate1 + here->VDIOvoltage);
vd = DEVpred(ckt, here->VDIOvoltage);
*(ckt->CKTstate0 + here->VDIOcurrent) =
*(ckt->CKTstate1 + here->VDIOcurrent);
*(ckt->CKTstate0 + here->VDIOconduct) =
*(ckt->CKTstate1 + here->VDIOconduct);
} else {
#endif /* PREDICTOR */
vd = model->VDMOStype * (*(ckt->CKTrhsOld + here->VDIOposPrimeNode) -
*(ckt->CKTrhsOld + here->VDMOSdNode));
#ifndef PREDICTOR
}
#endif /* PREDICTOR */
delvd = vd - *(ckt->CKTstate0 + here->VDIOvoltage);
cdhat = *(ckt->CKTstate0 + here->VDIOcurrent) +
*(ckt->CKTstate0 + here->VDIOconduct) * delvd;
/*
* bypass if solution has not changed
*/
#ifndef NOBYPASS
if ((!(ckt->CKTmode & MODEINITPRED)) && (ckt->CKTbypass)) {
tol = ckt->CKTvoltTol + ckt->CKTreltol*
MAX(fabs(vd), fabs(*(ckt->CKTstate0 + here->VDIOvoltage)));
if (fabs(delvd) < tol) {
tol = ckt->CKTreltol* MAX(fabs(cdhat),
fabs(*(ckt->CKTstate0 + here->VDIOcurrent))) +
ckt->CKTabstol;
if (fabs(cdhat - *(ckt->CKTstate0 + here->VDIOcurrent))
< tol) {
vd = *(ckt->CKTstate0 + here->VDIOvoltage);
cd = *(ckt->CKTstate0 + here->VDIOcurrent);
gd = *(ckt->CKTstate0 + here->VDIOconduct);
goto load;
}
}
}
#endif /* NOBYPASS */
/*
* limit new junction voltage
*/
if ((model->VDMOSDbvGiven) &&
(vd < MIN(0, -vbrknp + 10 * vtebrk))) {
vdtemp = -(vd + vbrknp);
vdtemp = DEVpnjlim(vdtemp,
-(*(ckt->CKTstate0 + here->VDIOvoltage) +
vbrknp), vtebrk,
here->VDIOtVcrit, &Check);
vd = -(vdtemp + vbrknp);
} else {
vd = DEVpnjlim(vd, *(ckt->CKTstate0 + here->VDIOvoltage),
vte, here->VDIOtVcrit, &Check);
}
}
/*
* compute dc current and derivatives
*/
if (vd >= -3 * vte) { /* bottom current forward */
evd = exp(vd / vte);
cdb = csat*(evd - 1);
gdb = csat*evd / vte;
} else if ((!(model->VDMOSDbvGiven)) ||
vd >= -vbrknp) { /* reverse */
arg = 3 * vte / (vd*CONSTe);
arg = arg * arg * arg;
cdb = -csat*(1 + arg);
gdb = csat * 3 * arg / vd;
} else { /* breakdown */
evrev = exp(-(vbrknp + vd) / vtebrk);
cdb = -csat*evrev;
gdb = csat*evrev / vtebrk;
}
cd = cdb;
gd = gdb;
gd = gd + ckt->CKTgmin;
cd = cd + ckt->CKTgmin*vd;
if ((ckt->CKTmode & (MODEDCTRANCURVE | MODETRAN | MODEAC | MODEINITSMSIG)) ||
((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC))) {
/*
* charge storage elements
*/
czero = here->VDIOtJctCap;
if (vd < here->VDIOtDepCap) {
arg = 1 - vd / here->VDIOtJctPot;
sarg = exp(-here->VDIOtGradingCoeff*log(arg));
deplcharge = here->VDIOtJctPot*czero*(1 - arg*sarg) / (1 - here->VDIOtGradingCoeff);
deplcap = czero*sarg;
} else {
czof2 = czero / here->VDIOtF2;
deplcharge = czero*here->VDIOtF1 + czof2*(here->VDIOtF3*(vd - here->VDIOtDepCap) +
(here->VDIOtGradingCoeff / (here->VDIOtJctPot + here->VDIOtJctPot))*(vd*vd - here->VDIOtDepCap*here->VDIOtDepCap));
deplcap = czof2*(here->VDIOtF3 + here->VDIOtGradingCoeff*vd / here->VDIOtJctPot);
}
diffcharge = here->VDIOtTransitTime*cdb;
*(ckt->CKTstate0 + here->VDIOcapCharge) =
diffcharge + deplcharge;
diffcap = here->VDIOtTransitTime*gdb;
capd = diffcap + deplcap;
here->VDIOcap = capd;
/*
* store small-signal parameters
*/
if ((!(ckt->CKTmode & MODETRANOP)) ||
(!(ckt->CKTmode & MODEUIC))) {
if (ckt->CKTmode & MODEINITSMSIG) {
*(ckt->CKTstate0 + here->VDIOcapCurrent) = capd;
continue;
}
/*
* transient analysis
*/
if (ckt->CKTmode & MODEINITTRAN) {
*(ckt->CKTstate1 + here->VDIOcapCharge) =
*(ckt->CKTstate0 + here->VDIOcapCharge);
}
error = NIintegrate(ckt, &geq, &ceq, capd, here->VDIOcapCharge);
if (error) return(error);
gd = gd + geq;
cd = cd + *(ckt->CKTstate0 + here->VDIOcapCurrent);
if (ckt->CKTmode & MODEINITTRAN) {
*(ckt->CKTstate1 + here->VDIOcapCurrent) =
*(ckt->CKTstate0 + here->VDIOcapCurrent);
}
}
}
/*
* check convergence
*/
if (Check == 1) {
ckt->CKTnoncon++;
ckt->CKTtroubleElt = (GENinstance *)here;
}
*(ckt->CKTstate0 + here->VDIOvoltage) = vd;
*(ckt->CKTstate0 + here->VDIOcurrent) = cd;
*(ckt->CKTstate0 + here->VDIOconduct) = gd;
#ifndef NOBYPASS
load :
#endif
/*
* load current vector
*/
cdeq = cd - gd*vd;
if (model->VDMOStype == 1) {
*(ckt->CKTrhs + here->VDMOSdNode) += cdeq;
*(ckt->CKTrhs + here->VDIOposPrimeNode) -= cdeq;
} else {
*(ckt->CKTrhs + here->VDMOSdNode) -= cdeq;
*(ckt->CKTrhs + here->VDIOposPrimeNode) += cdeq;
}
/*
* load matrix
*/
*(here->VDMOSSsPtr) += gspr;
*(here->VDMOSDdPtr) += gd;
*(here->VDIORPrpPtr) += (gd + gspr);
*(here->VDIOSrpPtr) -= gspr;
*(here->VDIODrpPtr) -= gd;
*(here->VDIORPsPtr) -= gspr;
*(here->VDIORPdPtr) -= gd;
}
}
return(OK);
}
/* scaling function, sine function interpolating between 0 and 1
* nf2: empirical setting of sine 'speed'
*/
static double
scalef(double nf2, double vgst)
{
double vgstsin = vgst / nf2;
if (vgstsin > 1)
return 1;
else if (vgstsin < -1)
return 0;
else
return 0.5 * sin(vgstsin * M_PI / 2) + 0.5;
}
/* Calculate D/S current including weak inversion.
* Uses a single function covering weak-moderate-stong inversion, as well
* as linear and saturation regions, with an interpolation method according to
* Tvividis, McAndrew: "Operation and Modeling of the MOS Transistor", Oxford, 2011, p. 209.
* A single parameter n sets the slope of the weak inversion current. The weak inversion
* current is independent from vds, as in long channel devices.
* The following modification has been added for VDMOS compatibility:
* n and lambda are depending on vgst with a sine function interpolating between 0 and 1.
*/
static double
cweakinv2(double slope, double shift, double vgst, double vds, double lambda, double beta, double vt, double mtr, double theta)
{
double betam = beta / (1.0+theta*vgst);
vgst += shift * (1 - scalef(0.5, vgst));
double n = slope / 2.3 / 0.0256; /* Tsividis, p. 208 */
double n1 = n + (1 - n) * scalef(0.7, vgst); /* n < n1 < 1 */
double first = log(1 + exp(vgst / (2 * n1 * vt)));
double second = log(1 + exp((vgst - vds * mtr * n1) / (2 * n1 * vt)));
double cds =
betam * n1 * 2 * vt * vt * (1 + scalef(1, vgst) * lambda * vds) *
(first * first - second * second);
return cds;
}