📄 mos6load.c
字号:
*/#ifdef DETAILPROFasm(" .globl mosptc");asm("mosptc:");#endif /*DETAILPROF*/ /* ok - bypass is out, do it the hard way */ von = model->MOS6type * here->MOS6von;#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->MOS6vds) >=0) { vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->MOS6vgs) ,von); vds = vgs - vgd; vds = DEVlimvds(vds,*(ckt->CKTstate0 + here->MOS6vds)); vgd = vgs - vds; } else { vgd = DEVfetlim(vgd,vgdo,von); vds = vgs - vgd; if(!(ckt->CKTfixLimit)) { vds = -DEVlimvds(-vds,-(*(ckt->CKTstate0 + here->MOS6vds))); } vgs = vgd + vds; } if(vds >= 0) { vbs = DEVpnjlim(vbs,*(ckt->CKTstate0 + here->MOS6vbs), vt,here->MOS6sourceVcrit,&Check); vbd = vbs-vds; } else { vbd = DEVpnjlim(vbd,*(ckt->CKTstate0 + here->MOS6vbd), vt,here->MOS6drainVcrit,&Check); vbs = vbd + vds; }#endif /*NODELIMITING*//**/#ifdef DETAILPROFasm(" .globl mosptd");asm("mosptd:");#endif /*DETAILPROF*/ } 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->MOS6off) { vds= model->MOS6type * here->MOS6icVDS; vgs= model->MOS6type * here->MOS6icVGS; vbs= model->MOS6type * here->MOS6icVBS; if((vds==0) && (vgs==0) && (vbs==0) && ((ckt->CKTmode & (MODETRAN|MODEDCOP|MODEDCTRANCURVE)) || (!(ckt->CKTmode & MODEUIC)))) { vbs = -1; vgs = model->MOS6type * here->MOS6tVto; vds = 0; } } else { vbs=vgs=vds=0; } }/**/#ifdef DETAILPROFasm(" .globl mospte");asm("mospte:");#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->MOS6gbs = SourceSatCur/vt; here->MOS6cbs = here->MOS6gbs*vbs; here->MOS6gbs += ckt->CKTgmin; } else { evbs = exp(MIN(MAX_EXP_ARG,vbs/vt)); here->MOS6gbs = SourceSatCur*evbs/vt + ckt->CKTgmin; here->MOS6cbs = SourceSatCur * (evbs-1); } if(vbd <= 0) { here->MOS6gbd = DrainSatCur/vt; here->MOS6cbd = here->MOS6gbd *vbd; here->MOS6gbd += ckt->CKTgmin; } else { evbd = exp(MIN(MAX_EXP_ARG,vbd/vt)); here->MOS6gbd = DrainSatCur*evbd/vt +ckt->CKTgmin; here->MOS6cbd = 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->MOS6mode = 1; } else { /* inverse mode */ here->MOS6mode = -1; }/**/#ifdef DETAILPROFasm(" .globl mosptf");asm("mosptf:");#endif /*DETAILPROF*/ { /* * this block of code evaluates the drain current and its * derivatives using the n-th power MOS model and the * charges associated with the gate, channel and bulk for * mosfets * */ /* the following 14 variables are local to this code block until * it is obvious that they can be made global */ double arg; double sarg; double vgon; double vdshere, vbsvbd; double idsat, lambda, vonbm; double vdst, vdst1, vdst2, ivdst1, vdstg; vbsvbd = (here->MOS6mode==1?vbs:vbd); if (vbsvbd <= 0 ) { sarg = sqrt(here->MOS6tPhi - vbsvbd); } else { sarg = sqrt(here->MOS6tPhi); sarg = sarg - vbsvbd / (sarg+sarg); sarg = MAX(0,sarg); } vdshere = vds * here->MOS6mode; von=(here->MOS6tVbi*model->MOS6type)+model->MOS6gamma*sarg - model->MOS6gamma1 * vbsvbd; - model->MOS6sigma * vdshere; vgon = (here->MOS6mode==1?vgs:vgd) - von; if (vgon <= 0) { /* * cutoff region */ vdsat = 0; cdrain=0; here->MOS6gm=0; here->MOS6gds=0; here->MOS6gmbs=0; } else { if (sarg <= 0) { arg=0; } else { if ((here->MOS6mode==1?vbs:vbd) <= 0 ) { vonbm = model->MOS6gamma1 + model->MOS6gamma / (sarg + sarg); } else { vonbm = model->MOS6gamma1 + model->MOS6gamma / 2 / sqrt(here->MOS6tPhi); } } sarg = log(vgon); vdsat = model->MOS6kv * exp(sarg * model->MOS6nv); idsat = betac * exp(sarg * model->MOS6nc); lambda = model->MOS6lamda0 - model->MOS6lamda1 * vbsvbd; /* * saturation region */ cdrain = idsat * (1 + lambda * vdshere); here->MOS6gm = cdrain * model->MOS6nc / vgon; here->MOS6gds = here->MOS6gm * model->MOS6sigma + idsat * lambda; here->MOS6gmbs = here->MOS6gm * vonbm - idsat * model->MOS6lamda1 * vdshere; if (vdsat > vdshere){ /* * linear region */ vdst = vdshere / vdsat; vdst2 = (2 - vdst) * vdst; vdstg = - vdst * model->MOS6nv / vgon; ivdst1 = cdrain * (2 - vdst - vdst); cdrain = cdrain * vdst2; here->MOS6gm = here->MOS6gm * vdst2 + ivdst1 * vdstg; here->MOS6gds = here->MOS6gds * vdst2 + ivdst1 * (1 / vdsat + vdstg * model->MOS6sigma); here->MOS6gmbs = here->MOS6gmbs * vdst2 + ivdst1 * vdstg * vonbm; } } /* * finished */ }/**/#ifdef DETAILPROFasm(" .globl mosptg");asm("mosptg:");#endif /*DETAILPROF*/ /* now deal with n vs p polarity */ here->MOS6von = model->MOS6type * von; here->MOS6vdsat = model->MOS6type * vdsat; /* line 490 */ /* * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE */ here->MOS6cd=here->MOS6mode * cdrain - here->MOS6cbd; 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->MOS6vbs)))+ ckt->CKTvoltTol)|| senflag)#endif /*CAPBYPASS*/ { /* can't bypass the diode capacitance calculations */#ifdef CAPZEROBYPASS if(here->MOS6Cbs != 0 || here->MOS6Cbssw != 0 ) {#endif /*CAPZEROBYPASS*/ if (vbs < here->MOS6tDepCap){ arg=1-vbs/here->MOS6tBulkPot; /* * 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->MOS6bulkJctBotGradingCoeff == model->MOS6bulkJctSideGradingCoeff) { if(model->MOS6bulkJctBotGradingCoeff == .5) { sarg = sargsw = 1/sqrt(arg); } else { sarg = sargsw = exp(-model->MOS6bulkJctBotGradingCoeff* log(arg)); } } else { if(model->MOS6bulkJctBotGradingCoeff == .5) { sarg = 1/sqrt(arg); } else {#endif /*NOSQRT*/ sarg = exp(-model->MOS6bulkJctBotGradingCoeff* log(arg));#ifndef NOSQRT } if(model->MOS6bulkJctSideGradingCoeff == .5) { sargsw = 1/sqrt(arg); } else {#endif /*NOSQRT*/ sargsw =exp(-model->MOS6bulkJctSideGradingCoeff* log(arg));#ifndef NOSQRT } }#endif /*NOSQRT*/ *(ckt->CKTstate0 + here->MOS6qbs) = here->MOS6tBulkPot*(here->MOS6Cbs* (1-arg*sarg)/(1-model->MOS6bulkJctBotGradingCoeff) +here->MOS6Cbssw* (1-arg*sargsw)/ (1-model->MOS6bulkJctSideGradingCoeff)); here->MOS6capbs=here->MOS6Cbs*sarg+ here->MOS6Cbssw*sargsw; } else { *(ckt->CKTstate0 + here->MOS6qbs) = here->MOS6f4s + vbs*(here->MOS6f2s+vbs*(here->MOS6f3s/2)); here->MOS6capbs=here->MOS6f2s+here->MOS6f3s*vbs; }#ifdef CAPZEROBYPASS } else { *(ckt->CKTstate0 + here->MOS6qbs) = 0; here->MOS6capbs=0; }#endif /*CAPZEROBYPASS*/ }#ifdef CAPBYPASS if(((ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) || FABS(delvbd) >= ckt->CKTreltol * MAX(FABS(vbd), FABS(*(ckt->CKTstate0+here->MOS6vbd)))+ ckt->CKTvoltTol)|| senflag)#endif /*CAPBYPASS*/ /* can't bypass the diode capacitance calculations */ {#ifdef CAPZEROBYPASS if(here->MOS6Cbd != 0 || here->MOS6Cbdsw != 0 ) {#endif /*CAPZEROBYPASS*/ if (vbd < here->MOS6tDepCap) { arg=1-vbd/here->MOS6tBulkPot; /* * 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->MOS6bulkJctBotGradingCoeff == .5 &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -