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.
 
 
 
 
 
 

496 lines
19 KiB

/**********
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 S. Hwang
Modified: 2000 AlansFixes
**********/
#include "ngspice.h"
#include <stdio.h>
#include "devdefs.h"
#include "cktdefs.h"
#include "mesdefs.h"
#include "const.h"
#include "trandefs.h"
#include "sperror.h"
#include "suffix.h"
/* forward declaraction of our helper function */
#ifdef __STDC__
static double qggnew(double,double,double,double,double,double,double,
double*,double*);
#else /* stdc */
static double qggnew();
#endif /* stdc */
int
MESload(inModel,ckt)
GENmodel *inModel;
CKTcircuit *ckt;
/* actually load the current resistance value into the
* sparse matrix previously provided
*/
{
MESmodel *model = (MESmodel*)inModel;
MESinstance *here;
double afact;
double beta;
double betap;
double capgd;
double capgs;
double cd;
double cdhat;
double cdrain;
double cdreq;
double ceq;
double ceqgd;
double ceqgs;
double cg;
double cgd;
double cgdna,cgdnb,cgdnc,cgdnd;
double cghat;
double cgsna,cgsnb,cgsnc,cgsnd;
double csat;
double czgd;
double czgs;
double delvds;
double delvgd;
double delvgs;
double denom;
double evgd;
double evgs;
double gdpr;
double gds;
double geq;
double ggd;
double ggs;
double gm;
double gspr;
double invdenom;
double lfact;
double phib;
double prod;
double qgga,qggb,qggc,qggd;
double vcap;
double vcrit;
double vds;
double vgd;
double vgd1;
double vgdt;
double vgs;
double vgs1;
double vgst;
double vto;
double xfact;
double arg;
int icheck;
int ichk1;
int error;
/* loop through all the models */
for( ; model != NULL; model = model->MESnextModel ) {
/* loop through all the instances of the model */
for (here = model->MESinstances; here != NULL ;
here=here->MESnextInstance) {
if (here->MESowner != ARCHme) continue;
/*
* dc model parameters
*/
beta = model->MESbeta * here->MESarea;
gdpr = model->MESdrainConduct * here->MESarea;
gspr = model->MESsourceConduct * here->MESarea;
csat = model->MESgateSatCurrent * here->MESarea;
vcrit = model->MESvcrit;
vto = model->MESthreshold;
/*
* initialization
*/
icheck = 1;
if( ckt->CKTmode & MODEINITSMSIG) {
vgs = *(ckt->CKTstate0 + here->MESvgs);
vgd = *(ckt->CKTstate0 + here->MESvgd);
} else if (ckt->CKTmode & MODEINITTRAN) {
vgs = *(ckt->CKTstate1 + here->MESvgs);
vgd = *(ckt->CKTstate1 + here->MESvgd);
} else if ( (ckt->CKTmode & MODEINITJCT) &&
(ckt->CKTmode & MODETRANOP) &&
(ckt->CKTmode & MODEUIC) ) {
vds = model->MEStype*here->MESicVDS;
vgs = model->MEStype*here->MESicVGS;
vgd = vgs-vds;
} else if ( (ckt->CKTmode & MODEINITJCT) &&
(here->MESoff == 0) ) {
vgs = -1;
vgd = -1;
} else if( (ckt->CKTmode & MODEINITJCT) ||
((ckt->CKTmode & MODEINITFIX) && (here->MESoff))) {
vgs = 0;
vgd = 0;
} else {
#ifndef PREDICTOR
if(ckt->CKTmode & MODEINITPRED) {
xfact = ckt->CKTdelta/ckt->CKTdeltaOld[1];
*(ckt->CKTstate0 + here->MESvgs) =
*(ckt->CKTstate1 + here->MESvgs);
vgs = (1+xfact) * *(ckt->CKTstate1 + here->MESvgs) -
xfact * *(ckt->CKTstate2 + here->MESvgs);
*(ckt->CKTstate0 + here->MESvgd) =
*(ckt->CKTstate1 + here->MESvgd);
vgd = (1+xfact)* *(ckt->CKTstate1 + here->MESvgd) -
xfact * *(ckt->CKTstate2 + here->MESvgd);
*(ckt->CKTstate0 + here->MEScg) =
*(ckt->CKTstate1 + here->MEScg);
*(ckt->CKTstate0 + here->MEScd) =
*(ckt->CKTstate1 + here->MEScd);
*(ckt->CKTstate0 + here->MEScgd) =
*(ckt->CKTstate1 + here->MEScgd);
*(ckt->CKTstate0 + here->MESgm) =
*(ckt->CKTstate1 + here->MESgm);
*(ckt->CKTstate0 + here->MESgds) =
*(ckt->CKTstate1 + here->MESgds);
*(ckt->CKTstate0 + here->MESggs) =
*(ckt->CKTstate1 + here->MESggs);
*(ckt->CKTstate0 + here->MESggd) =
*(ckt->CKTstate1 + here->MESggd);
} else {
#endif /* PREDICTOR */
/*
* compute new nonlinear branch voltages
*/
vgs = model->MEStype*
(*(ckt->CKTrhsOld+ here->MESgateNode)-
*(ckt->CKTrhsOld+
here->MESsourcePrimeNode));
vgd = model->MEStype*
(*(ckt->CKTrhsOld+here->MESgateNode)-
*(ckt->CKTrhsOld+
here->MESdrainPrimeNode));
#ifndef PREDICTOR
}
#endif /* PREDICTOR */
delvgs=vgs - *(ckt->CKTstate0 + here->MESvgs);
delvgd=vgd - *(ckt->CKTstate0 + here->MESvgd);
delvds=delvgs - delvgd;
cghat= *(ckt->CKTstate0 + here->MEScg) +
*(ckt->CKTstate0 + here->MESggd)*delvgd +
*(ckt->CKTstate0 + here->MESggs)*delvgs;
cdhat= *(ckt->CKTstate0 + here->MEScd) +
*(ckt->CKTstate0 + here->MESgm)*delvgs +
*(ckt->CKTstate0 + here->MESgds)*delvds -
*(ckt->CKTstate0 + here->MESggd)*delvgd;
/*
* bypass if solution has not changed
*/
if((ckt->CKTbypass) &&
(!(ckt->CKTmode & MODEINITPRED)) &&
(fabs(delvgs) < ckt->CKTreltol*MAX(fabs(vgs),
fabs(*(ckt->CKTstate0 + here->MESvgs)))+
ckt->CKTvoltTol) )
if ( (fabs(delvgd) < ckt->CKTreltol*MAX(fabs(vgd),
fabs(*(ckt->CKTstate0 + here->MESvgd)))+
ckt->CKTvoltTol))
if ( (fabs(cghat-*(ckt->CKTstate0 + here->MEScg))
< ckt->CKTreltol*MAX(fabs(cghat),
fabs(*(ckt->CKTstate0 + here->MEScg)))+
ckt->CKTabstol) ) if ( /* hack - expression too big */
(fabs(cdhat-*(ckt->CKTstate0 + here->MEScd))
< ckt->CKTreltol*MAX(fabs(cdhat),
fabs(*(ckt->CKTstate0 + here->MEScd)))+
ckt->CKTabstol) ) {
/* we can do a bypass */
vgs= *(ckt->CKTstate0 + here->MESvgs);
vgd= *(ckt->CKTstate0 + here->MESvgd);
vds= vgs-vgd;
cg= *(ckt->CKTstate0 + here->MEScg);
cd= *(ckt->CKTstate0 + here->MEScd);
cgd= *(ckt->CKTstate0 + here->MEScgd);
gm= *(ckt->CKTstate0 + here->MESgm);
gds= *(ckt->CKTstate0 + here->MESgds);
ggs= *(ckt->CKTstate0 + here->MESggs);
ggd= *(ckt->CKTstate0 + here->MESggd);
goto load;
}
/*
* limit nonlinear branch voltages
*/
ichk1=1;
vgs = DEVpnjlim(vgs,*(ckt->CKTstate0 + here->MESvgs),CONSTvt0,
vcrit, &icheck);
vgd = DEVpnjlim(vgd,*(ckt->CKTstate0 + here->MESvgd),CONSTvt0,
vcrit,&ichk1);
if (ichk1 == 1) {
icheck=1;
}
vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->MESvgs),
model->MESthreshold);
vgd = DEVfetlim(vgd,*(ckt->CKTstate0 + here->MESvgd),
model->MESthreshold);
}
/*
* determine dc current and derivatives
*/
vds = vgs-vgd;
if (vgs <= -3*CONSTvt0) {
arg=3*CONSTvt0/(vgs*CONSTe);
arg = arg * arg * arg;
cg = -csat*(1+arg)+ckt->CKTgmin*vgs;
ggs = csat*3*arg/vgs+ckt->CKTgmin;
} else {
evgs = exp(vgs/CONSTvt0);
ggs = csat*evgs/CONSTvt0+ckt->CKTgmin;
cg = csat*(evgs-1)+ckt->CKTgmin*vgs;
}
if (vgd <= -3*CONSTvt0) {
arg=3*CONSTvt0/(vgd*CONSTe);
arg = arg * arg * arg;
cgd = -csat*(1+arg)+ckt->CKTgmin*vgd;
ggd = csat*3*arg/vgd+ckt->CKTgmin;
} else {
evgd = exp(vgd/CONSTvt0);
ggd = csat*evgd/CONSTvt0+ckt->CKTgmin;
cgd = csat*(evgd-1)+ckt->CKTgmin*vgd;
}
cg = cg+cgd;
/*
* compute drain current and derivitives for normal mode
*/
if (vds >= 0) {
vgst = vgs-model->MESthreshold;
/*
* normal mode, cutoff region
*/
if (vgst <= 0) {
cdrain = 0;
gm = 0;
gds = 0;
} else {
prod = 1 + model->MESlModulation * vds;
betap = beta * prod;
denom = 1 + model->MESb * vgst;
invdenom = 1 / denom;
if (vds >= ( 3 / model->MESalpha ) ) {
/*
* normal mode, saturation region
*/
cdrain = betap * vgst * vgst * invdenom;
gm = betap * vgst * (1 + denom) * invdenom * invdenom;
gds = model->MESlModulation * beta * vgst * vgst *
invdenom;
} else {
/*
* normal mode, linear region
*/
afact = 1 - model->MESalpha * vds / 3;
lfact = 1 - afact * afact * afact;
cdrain = betap * vgst * vgst * invdenom * lfact;
gm = betap * vgst * (1 + denom) * invdenom * invdenom *
lfact;
gds = beta * vgst * vgst * invdenom * (model->MESalpha *
afact * afact * prod + lfact *
model->MESlModulation);
}
}
} else {
/*
* compute drain current and derivitives for inverse mode
*/
vgdt = vgd - model->MESthreshold;
if (vgdt <= 0) {
/*
* inverse mode, cutoff region
*/
cdrain = 0;
gm = 0;
gds = 0;
} else {
/*
* inverse mode, saturation region
*/
prod = 1 - model->MESlModulation * vds;
betap = beta * prod;
denom = 1 + model->MESb * vgdt;
invdenom = 1 / denom;
if ( -vds >= ( 3 / model->MESalpha ) ) {
cdrain = -betap * vgdt * vgdt * invdenom;
gm = -betap * vgdt * (1 + denom) * invdenom * invdenom;
gds = model->MESlModulation * beta * vgdt * vgdt *
invdenom-gm;
} else {
/*
* inverse mode, linear region
*/
afact = 1 + model->MESalpha * vds / 3;
lfact = 1 - afact * afact * afact;
cdrain = -betap * vgdt * vgdt * invdenom * lfact;
gm = -betap * vgdt * (1 + denom) * invdenom *
invdenom * lfact;
gds = beta * vgdt * vgdt * invdenom * (model->MESalpha *
afact * afact * prod + lfact *
model->MESlModulation)-gm;
}
}
}
/*
* compute equivalent drain current source
*/
cd = cdrain - cgd;
if ( (ckt->CKTmode & (MODETRAN|MODEINITSMSIG)) ||
((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) ){
/*
* charge storage elements
*/
czgs = model->MEScapGS * here->MESarea;
czgd = model->MEScapGD * here->MESarea;
phib = model->MESgatePotential;
vgs1 = *(ckt->CKTstate1 + here->MESvgs);
vgd1 = *(ckt->CKTstate1 + here->MESvgd);
vcap = 1 / model->MESalpha;
qgga = qggnew(vgs,vgd,phib,vcap,vto,czgs,czgd,&cgsna,&cgdna);
qggb = qggnew(vgs1,vgd,phib,vcap,vto,czgs,czgd,&cgsnb,&cgdnb);
qggc = qggnew(vgs,vgd1,phib,vcap,vto,czgs,czgd,&cgsnc,&cgdnc);
qggd = qggnew(vgs1,vgd1,phib,vcap,vto,czgs,czgd,&cgsnd,&cgdnd);
if(ckt->CKTmode & MODEINITTRAN) {
*(ckt->CKTstate1 + here->MESqgs) = qgga;
*(ckt->CKTstate1 + here->MESqgd) = qgga;
}
*(ckt->CKTstate0+here->MESqgs) = *(ckt->CKTstate1+here->MESqgs)
+ 0.5 * (qgga-qggb + qggc-qggd);
*(ckt->CKTstate0+here->MESqgd) = *(ckt->CKTstate1+here->MESqgd)
+ 0.5 * (qgga-qggc + qggb-qggd);
capgs = cgsna;
capgd = cgdna;
/*
* store small-signal parameters
*/
if( (!(ckt->CKTmode & MODETRANOP)) ||
(!(ckt->CKTmode & MODEUIC)) ) {
if(ckt->CKTmode & MODEINITSMSIG) {
*(ckt->CKTstate0 + here->MESqgs) = capgs;
*(ckt->CKTstate0 + here->MESqgd) = capgd;
continue; /*go to 1000*/
}
/*
* transient analysis
*/
if(ckt->CKTmode & MODEINITTRAN) {
*(ckt->CKTstate1 + here->MESqgs) =
*(ckt->CKTstate0 + here->MESqgs);
*(ckt->CKTstate1 + here->MESqgd) =
*(ckt->CKTstate0 + here->MESqgd);
}
error = NIintegrate(ckt,&geq,&ceq,capgs,here->MESqgs);
if(error) return(error);
ggs = ggs + geq;
cg = cg + *(ckt->CKTstate0 + here->MEScqgs);
error = NIintegrate(ckt,&geq,&ceq,capgd,here->MESqgd);
if(error) return(error);
ggd = ggd + geq;
cg = cg + *(ckt->CKTstate0 + here->MEScqgd);
cd = cd - *(ckt->CKTstate0 + here->MEScqgd);
cgd = cgd + *(ckt->CKTstate0 + here->MEScqgd);
if (ckt->CKTmode & MODEINITTRAN) {
*(ckt->CKTstate1 + here->MEScqgs) =
*(ckt->CKTstate0 + here->MEScqgs);
*(ckt->CKTstate1 + here->MEScqgd) =
*(ckt->CKTstate0 + here->MEScqgd);
}
}
}
/*
* check convergence
*/
if( (!(ckt->CKTmode & MODEINITFIX)) | (!(ckt->CKTmode & MODEUIC))) {
if((icheck == 1) ||
(fabs(cghat-cg) >= ckt->CKTreltol *
MAX(fabs(cghat),fabs(cg))+ckt->CKTabstol) ||
(fabs(cdhat-cd) > ckt->CKTreltol*
MAX(fabs(cdhat),fabs(cd))+ckt->CKTabstol)) {
ckt->CKTnoncon++;
ckt->CKTtroubleElt = (GENinstance *) here;
}
}
*(ckt->CKTstate0 + here->MESvgs) = vgs;
*(ckt->CKTstate0 + here->MESvgd) = vgd;
*(ckt->CKTstate0 + here->MEScg) = cg;
*(ckt->CKTstate0 + here->MEScd) = cd;
*(ckt->CKTstate0 + here->MEScgd) = cgd;
*(ckt->CKTstate0 + here->MESgm) = gm;
*(ckt->CKTstate0 + here->MESgds) = gds;
*(ckt->CKTstate0 + here->MESggs) = ggs;
*(ckt->CKTstate0 + here->MESggd) = ggd;
/*
* load current vector
*/
load:
ceqgd=model->MEStype*(cgd-ggd*vgd);
ceqgs=model->MEStype*((cg-cgd)-ggs*vgs);
cdreq=model->MEStype*((cd+cgd)-gds*vds-gm*vgs);
*(ckt->CKTrhs + here->MESgateNode) += (-ceqgs-ceqgd);
*(ckt->CKTrhs + here->MESdrainPrimeNode) +=
(-cdreq+ceqgd);
*(ckt->CKTrhs + here->MESsourcePrimeNode) +=
(cdreq+ceqgs);
/*
* load y matrix
*/
*(here->MESdrainDrainPrimePtr) += (-gdpr);
*(here->MESgateDrainPrimePtr) += (-ggd);
*(here->MESgateSourcePrimePtr) += (-ggs);
*(here->MESsourceSourcePrimePtr) += (-gspr);
*(here->MESdrainPrimeDrainPtr) += (-gdpr);
*(here->MESdrainPrimeGatePtr) += (gm-ggd);
*(here->MESdrainPrimeSourcePrimePtr) += (-gds-gm);
*(here->MESsourcePrimeGatePtr) += (-ggs-gm);
*(here->MESsourcePrimeSourcePtr) += (-gspr);
*(here->MESsourcePrimeDrainPrimePtr) += (-gds);
*(here->MESdrainDrainPtr) += (gdpr);
*(here->MESgateGatePtr) += (ggd+ggs);
*(here->MESsourceSourcePtr) += (gspr);
*(here->MESdrainPrimeDrainPrimePtr) += (gdpr+gds+ggd);
*(here->MESsourcePrimeSourcePrimePtr) += (gspr+gds+gm+ggs);
}
}
return(OK);
}
/* function qggnew - private, used by MESload*/
static double
qggnew(vgs,vgd,phib,vcap,vto,cgs,cgd,cgsnew,cgdnew)
double vgs,vgd,phib,vcap,vto,cgs,cgd,*cgsnew,*cgdnew;
{
double veroot,veff1,veff2,del,vnroot,vnew1,vnew3,vmax,ext;
double qroot,qggval,par1,cfact,cplus,cminus;
veroot = sqrt( (vgs - vgd) * (vgs - vgd) + vcap*vcap );
veff1 = 0.5 * (vgs + vgd + veroot);
veff2 = veff1 - veroot;
del = 0.2;
vnroot = sqrt( (veff1 - vto)*(veff1 - vto) + del * del );
vnew1 = 0.5 * (veff1 + vto + vnroot);
vnew3 = vnew1;
vmax = 0.5;
if ( vnew1 < vmax ) {
ext=0;
} else {
vnew1 = vmax;
ext = (vnew3 - vmax)/sqrt(1 - vmax/phib);
}
qroot = sqrt(1 - vnew1/phib);
qggval = cgs * (2*phib*(1-qroot) + ext) + cgd*veff2;
par1 = 0.5 * ( 1 + (veff1-vto)/vnroot);
cfact = (vgs- vgd)/veroot;
cplus = 0.5 * (1 + cfact);
cminus = cplus - cfact;
*cgsnew = cgs/qroot*par1*cplus + cgd*cminus;
*cgdnew = cgs/qroot*par1*cminus + cgd*cplus;
return(qggval);
}