mos3load.c

来自「ngspice又一个电子CAD仿真软件代码.功能更全」· C语言 代码 · 共 1,286 行 · 第 1/3 页

C
1,286
字号
/**********Copyright 1990 Regents of the University of California.  All rights reserved.Author: 1985 Thomas L. QuarlesModified: 2000 AlansFixes**********/#include "ngspice.h"#include "cktdefs.h"#include "devdefs.h"#include "mos3defs.h"#include "trandefs.h"#include "const.h"#include "sperror.h"#include "suffix.h"/* actually load the current value into the sparse matrix previously * provided */intMOS3load(GENmodel *inModel, CKTcircuit *ckt){    MOS3model *model = (MOS3model *)inModel;    MOS3instance *here;    double Beta;    double DrainSatCur;    double EffectiveLength;    double EffectiveWidth;    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 = 0.0;    int xnrm;    int xrev;    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 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;            /* 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 */            EffectiveWidth=here->MOS3w-2*model->MOS3widthNarrow+		model->MOS3widthAdjust;            EffectiveLength=here->MOS3l - 2*model->MOS3latDiff+		model->MOS3lengthAdjust;           	    if( (here->MOS3tSatCurDens == 0) || 		(here->MOS3drainArea == 0) ||		(here->MOS3sourceArea == 0)) {                DrainSatCur = here->MOS3m * here->MOS3tSatCur;                SourceSatCur = here->MOS3m * here->MOS3tSatCur;            } else {                DrainSatCur = here->MOS3m * here->MOS3tSatCurDens * 		    here->MOS3drainArea;                SourceSatCur = here->MOS3m * here->MOS3tSatCurDens * 		    here->MOS3sourceArea;            }            GateSourceOverlapCap = model->MOS3gateSourceOverlapCapFactor * 		here->MOS3m * EffectiveWidth;            GateDrainOverlapCap = model->MOS3gateDrainOverlapCapFactor * 		here->MOS3m * EffectiveWidth;            GateBulkOverlapCap = model->MOS3gateBulkOverlapCapFactor * 		here->MOS3m * EffectiveLength;            Beta = here->MOS3tTransconductance *		here->MOS3m * EffectiveWidth/EffectiveLength;            OxideCap = model->MOS3oxideCapFactor * EffectiveLength * 		here->MOS3m * EffectiveWidth;                        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;            }            /*              * 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 */                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 ;#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*/                /* 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 {                /* 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;                }             }            /*             * 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 <= -3*vt) {                arg=3*vt/(vbs*CONSTe);                arg = arg * arg * arg;                here->MOS3cbs = -SourceSatCur*(1+arg)+ckt->CKTgmin*vbs;                here->MOS3gbs = SourceSatCur*3*arg/vbs+ckt->CKTgmin;            } else {                evbs = exp(MIN(MAX_EXP_ARG,vbs/vt));                here->MOS3gbs = SourceSatCur*evbs/vt + ckt->CKTgmin;                here->MOS3cbs = SourceSatCur*(evbs-1) + ckt->CKTgmin*vbs;            }            if(vbd <= -3*vt) {                arg=3*vt/(vbd*CONSTe);                arg = arg * arg * arg;                here->MOS3cbd = -DrainSatCur*(1+arg)+ckt->CKTgmin*vbd;                here->MOS3gbd = DrainSatCur*3*arg/vbd+ckt->CKTgmin;            } else {                evbd = exp(MIN(MAX_EXP_ARG,vbd/vt));

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?