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 + -
显示快捷键?