int B1load(GENmodel *inModel, CKTcircuit *ckt) /* actually load the current value into the * sparse matrix previously provided */ { B1model *model = (B1model*)inModel; B1instance *here; double DrainSatCurrent = 0.0; double EffectiveLength = 0.0; double GateBulkOverlapCap = 0.0; double GateDrainOverlapCap = 0.0; double GateSourceOverlapCap = 0.0; double SourceSatCurrent = 0.0; double DrainArea = 0.0; double SourceArea = 0.0; double DrainPerimeter = 0.0; double SourcePerimeter = 0.0; double arg = 0.0; double capbd = 0.0; double capbs = 0.0; double cbd = 0.0; double cbhat = 0.0; double cbs = 0.0; double cd = 0.0; double cdrain = 0.0; double cdhat = 0.0; double cdreq = 0.0; double ceq = 0.0; double ceqbd = 0.0; double ceqbs = 0.0; double ceqqb = 0.0; double ceqqd = 0.0; double ceqqg = 0.0; double czbd = 0.0; double czbdsw = 0.0; double czbs = 0.0; double czbssw = 0.0; double delvbd = 0.0; double delvbs = 0.0; double delvds = 0.0; double delvgd = 0.0; double delvgs = 0.0; double evbd = 0.0; double evbs = 0.0; double gbd = 0.0; double gbs = 0.0; double gcbdb = 0.0; double gcbgb = 0.0; double gcbsb = 0.0; double gcddb = 0.0; double gcdgb = 0.0; double gcdsb = 0.0; double gcgdb = 0.0; double gcggb = 0.0; double gcgsb = 0.0; double gcsdb = 0.0; double gcsgb = 0.0; double gcssb = 0.0; double gds = 0.0; double geq = 0.0; double gm = 0.0; double gmbs = 0.0; double sarg = 0.0; double sargsw = 0.0; double vbd = 0.0; double vbs = 0.0; double vcrit = 0.0; double vds = 0.0; double vdsat = 0.0; double vgb = 0.0; double vgd = 0.0; double vgdo = 0.0; double vgs = 0.0; double von = 0.0; double xfact = 0.0; double xnrm = 0.0; double xrev = 0.0; int Check = 0; double cgdb = 0.0; double cgsb = 0.0; double cbdb = 0.0; double cdgb = 0.0; double cddb = 0.0; double cdsb = 0.0; double cggb = 0.0; double cbgb = 0.0; double cbsb = 0.0; double csgb = 0.0; double cssb = 0.0; double csdb = 0.0; double PhiB = 0.0; double PhiBSW = 0.0; double MJ = 0.0; double MJSW = 0.0; double argsw = 0.0; double qgate = 0.0; double qbulk = 0.0; double qdrn = 0.0; double qsrc = 0.0; double cqgate = 0.0; double cqbulk = 0.0; double cqdrn = 0.0; double vt0 = 0.0; double args[8]; int ByPass = 0; #ifndef NOBYPASS double tempv = 0.0; #endif /*NOBYPASS*/ int error = 0; double m; /* parallel multiplier */ /* loop through all the B1 device models */ for( ; model != NULL; model = model->B1nextModel ) { /* loop through all the instances of the model */ for (here = model->B1instances; here != NULL ; here=here->B1nextInstance) { if (here->B1owner != ARCHme) continue; EffectiveLength=here->B1l - model->B1deltaL * 1.e-6;/* m */ DrainArea = here->B1drainArea; SourceArea = here->B1sourceArea; DrainPerimeter = here->B1drainPerimeter; SourcePerimeter = here->B1sourcePerimeter; if( (DrainSatCurrent=DrainArea*model->B1jctSatCurDensity) < 1e-15){ DrainSatCurrent = 1.0e-15; } if( (SourceSatCurrent=SourceArea*model->B1jctSatCurDensity) <1.0e-15){ SourceSatCurrent = 1.0e-15; } GateSourceOverlapCap = model->B1gateSourceOverlapCap *here->B1w; GateDrainOverlapCap = model->B1gateDrainOverlapCap * here->B1w; GateBulkOverlapCap = model->B1gateBulkOverlapCap *EffectiveLength; von = model->B1type * here->B1von; vdsat = model->B1type * here->B1vdsat; vt0 = model->B1type * here->B1vt0; Check=1; ByPass = 0; if((ckt->CKTmode & MODEINITSMSIG)) { vbs= *(ckt->CKTstate0 + here->B1vbs); vgs= *(ckt->CKTstate0 + here->B1vgs); vds= *(ckt->CKTstate0 + here->B1vds); } else if ((ckt->CKTmode & MODEINITTRAN)) { vbs= *(ckt->CKTstate1 + here->B1vbs); vgs= *(ckt->CKTstate1 + here->B1vgs); vds= *(ckt->CKTstate1 + here->B1vds); } else if((ckt->CKTmode & MODEINITJCT) && !here->B1off) { vds= model->B1type * here->B1icVDS; vgs= model->B1type * here->B1icVGS; vbs= model->B1type * here->B1icVBS; if((vds==0) && (vgs==0) && (vbs==0) && ((ckt->CKTmode & (MODETRAN|MODEAC|MODEDCOP|MODEDCTRANCURVE)) || (!(ckt->CKTmode & MODEUIC)))) { vbs = -1; vgs = vt0; vds = 0; } } else if((ckt->CKTmode & (MODEINITJCT | MODEINITFIX) ) && (here->B1off)) { vbs=vgs=vds=0; } else { #ifndef PREDICTOR if((ckt->CKTmode & MODEINITPRED)) { xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1]; *(ckt->CKTstate0 + here->B1vbs) = *(ckt->CKTstate1 + here->B1vbs); vbs = (1+xfact)* (*(ckt->CKTstate1 + here->B1vbs)) -(xfact * (*(ckt->CKTstate2 + here->B1vbs))); *(ckt->CKTstate0 + here->B1vgs) = *(ckt->CKTstate1 + here->B1vgs); vgs = (1+xfact)* (*(ckt->CKTstate1 + here->B1vgs)) -(xfact * (*(ckt->CKTstate2 + here->B1vgs))); *(ckt->CKTstate0 + here->B1vds) = *(ckt->CKTstate1 + here->B1vds); vds = (1+xfact)* (*(ckt->CKTstate1 + here->B1vds)) -(xfact * (*(ckt->CKTstate2 + here->B1vds))); *(ckt->CKTstate0 + here->B1vbd) = *(ckt->CKTstate0 + here->B1vbs)- *(ckt->CKTstate0 + here->B1vds); *(ckt->CKTstate0 + here->B1cd) = *(ckt->CKTstate1 + here->B1cd); *(ckt->CKTstate0 + here->B1cbs) = *(ckt->CKTstate1 + here->B1cbs); *(ckt->CKTstate0 + here->B1cbd) = *(ckt->CKTstate1 + here->B1cbd); *(ckt->CKTstate0 + here->B1gm) = *(ckt->CKTstate1 + here->B1gm); *(ckt->CKTstate0 + here->B1gds) = *(ckt->CKTstate1 + here->B1gds); *(ckt->CKTstate0 + here->B1gmbs) = *(ckt->CKTstate1 + here->B1gmbs); *(ckt->CKTstate0 + here->B1gbd) = *(ckt->CKTstate1 + here->B1gbd); *(ckt->CKTstate0 + here->B1gbs) = *(ckt->CKTstate1 + here->B1gbs); *(ckt->CKTstate0 + here->B1cggb) = *(ckt->CKTstate1 + here->B1cggb); *(ckt->CKTstate0 + here->B1cbgb) = *(ckt->CKTstate1 + here->B1cbgb); *(ckt->CKTstate0 + here->B1cbsb) = *(ckt->CKTstate1 + here->B1cbsb); *(ckt->CKTstate0 + here->B1cgdb) = *(ckt->CKTstate1 + here->B1cgdb); *(ckt->CKTstate0 + here->B1cgsb) = *(ckt->CKTstate1 + here->B1cgsb); *(ckt->CKTstate0 + here->B1cbdb) = *(ckt->CKTstate1 + here->B1cbdb); *(ckt->CKTstate0 + here->B1cdgb) = *(ckt->CKTstate1 + here->B1cdgb); *(ckt->CKTstate0 + here->B1cddb) = *(ckt->CKTstate1 + here->B1cddb); *(ckt->CKTstate0 + here->B1cdsb) = *(ckt->CKTstate1 + here->B1cdsb); } else { #endif /* PREDICTOR */ vbs = model->B1type * ( *(ckt->CKTrhsOld+here->B1bNode) - *(ckt->CKTrhsOld+here->B1sNodePrime)); vgs = model->B1type * ( *(ckt->CKTrhsOld+here->B1gNode) - *(ckt->CKTrhsOld+here->B1sNodePrime)); vds = model->B1type * ( *(ckt->CKTrhsOld+here->B1dNodePrime) - *(ckt->CKTrhsOld+here->B1sNodePrime)); #ifndef PREDICTOR } #endif /* PREDICTOR */ vbd=vbs-vds; vgd=vgs-vds; vgdo = *(ckt->CKTstate0 + here->B1vgs) - *(ckt->CKTstate0 + here->B1vds); delvbs = vbs - *(ckt->CKTstate0 + here->B1vbs); delvbd = vbd - *(ckt->CKTstate0 + here->B1vbd); delvgs = vgs - *(ckt->CKTstate0 + here->B1vgs); delvds = vds - *(ckt->CKTstate0 + here->B1vds); delvgd = vgd-vgdo; if (here->B1mode >= 0) { cdhat= *(ckt->CKTstate0 + here->B1cd) - *(ckt->CKTstate0 + here->B1gbd) * delvbd + *(ckt->CKTstate0 + here->B1gmbs) * delvbs + *(ckt->CKTstate0 + here->B1gm) * delvgs + *(ckt->CKTstate0 + here->B1gds) * delvds ; } else { cdhat= *(ckt->CKTstate0 + here->B1cd) - ( *(ckt->CKTstate0 + here->B1gbd) - *(ckt->CKTstate0 + here->B1gmbs)) * delvbd - *(ckt->CKTstate0 + here->B1gm) * delvgd + *(ckt->CKTstate0 + here->B1gds) * delvds; } cbhat= *(ckt->CKTstate0 + here->B1cbs) + *(ckt->CKTstate0 + here->B1cbd) + *(ckt->CKTstate0 + here->B1gbd) * delvbd + *(ckt->CKTstate0 + here->B1gbs) * delvbs ; #ifndef NOBYPASS /* now lets see if we can bypass (ugh) */ /* following should be one big if connected by && all over * the place, but some C compilers can't handle that, so * we split it up here to let them digest it in stages */ tempv = MAX(fabs(cbhat),fabs(*(ckt->CKTstate0 + here->B1cbs) + *(ckt->CKTstate0 + here->B1cbd)))+ckt->CKTabstol; if((!(ckt->CKTmode & MODEINITPRED)) && (ckt->CKTbypass) ) if( (fabs(delvbs) < (ckt->CKTreltol * MAX(fabs(vbs), fabs(*(ckt->CKTstate0+here->B1vbs)))+ ckt->CKTvoltTol)) ) if ( (fabs(delvbd) < (ckt->CKTreltol * MAX(fabs(vbd), fabs(*(ckt->CKTstate0+here->B1vbd)))+ ckt->CKTvoltTol)) ) if( (fabs(delvgs) < (ckt->CKTreltol * MAX(fabs(vgs), fabs(*(ckt->CKTstate0+here->B1vgs)))+ ckt->CKTvoltTol))) if ( (fabs(delvds) < (ckt->CKTreltol * MAX(fabs(vds), fabs(*(ckt->CKTstate0+here->B1vds)))+ ckt->CKTvoltTol)) ) if( (fabs(cdhat- *(ckt->CKTstate0 + here->B1cd)) < ckt->CKTreltol * MAX(fabs(cdhat),fabs(*(ckt->CKTstate0 + here->B1cd))) + ckt->CKTabstol) ) if ( (fabs(cbhat-(*(ckt->CKTstate0 + here->B1cbs) + *(ckt->CKTstate0 + here->B1cbd))) < ckt->CKTreltol * tempv)) { /* bypass code */ vbs = *(ckt->CKTstate0 + here->B1vbs); vbd = *(ckt->CKTstate0 + here->B1vbd); vgs = *(ckt->CKTstate0 + here->B1vgs); vds = *(ckt->CKTstate0 + here->B1vds); vgd = vgs - vds; vgb = vgs - vbs; cd = *(ckt->CKTstate0 + here->B1cd); cbs = *(ckt->CKTstate0 + here->B1cbs); cbd = *(ckt->CKTstate0 + here->B1cbd); cdrain = here->B1mode * (cd + cbd); gm = *(ckt->CKTstate0 + here->B1gm); gds = *(ckt->CKTstate0 + here->B1gds); gmbs = *(ckt->CKTstate0 + here->B1gmbs); gbd = *(ckt->CKTstate0 + here->B1gbd); gbs = *(ckt->CKTstate0 + here->B1gbs); if((ckt->CKTmode & (MODETRAN | MODEAC)) || ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC))) { cggb = *(ckt->CKTstate0 + here->B1cggb); cgdb = *(ckt->CKTstate0 + here->B1cgdb); cgsb = *(ckt->CKTstate0 + here->B1cgsb); cbgb = *(ckt->CKTstate0 + here->B1cbgb); cbdb = *(ckt->CKTstate0 + here->B1cbdb); cbsb = *(ckt->CKTstate0 + here->B1cbsb); cdgb = *(ckt->CKTstate0 + here->B1cdgb); cddb = *(ckt->CKTstate0 + here->B1cddb); cdsb = *(ckt->CKTstate0 + here->B1cdsb); capbs = *(ckt->CKTstate0 + here->B1capbs); capbd = *(ckt->CKTstate0 + here->B1capbd); ByPass = 1; goto line755; } else { goto line850; } } #endif /*NOBYPASS*/ von = model->B1type * here->B1von; if(*(ckt->CKTstate0 + here->B1vds) >=0) { vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->B1vgs) ,von); vds = vgs - vgd; vds = DEVlimvds(vds,*(ckt->CKTstate0 + here->B1vds)); vgd = vgs - vds; } else { vgd = DEVfetlim(vgd,vgdo,von); vds = vgs - vgd; vds = -DEVlimvds(-vds,-(*(ckt->CKTstate0 + here->B1vds))); vgs = vgd + vds; } if(vds >= 0) { vcrit =CONSTvt0*log(CONSTvt0/(CONSTroot2*SourceSatCurrent)); vbs = DEVpnjlim(vbs,*(ckt->CKTstate0 + here->B1vbs), CONSTvt0,vcrit,&Check); /* B1 test */ vbd = vbs-vds; } else { vcrit = CONSTvt0*log(CONSTvt0/(CONSTroot2*DrainSatCurrent)); vbd = DEVpnjlim(vbd,*(ckt->CKTstate0 + here->B1vbd), CONSTvt0,vcrit,&Check); /* B1 test*/ vbs = vbd + vds; } } /* determine DC current and derivatives */ vbd = vbs - vds; vgd = vgs - vds; vgb = vgs - vbs; if(vbs <= 0.0 ) { gbs = SourceSatCurrent / CONSTvt0 + ckt->CKTgmin; cbs = gbs * vbs ; } else { evbs = exp(vbs/CONSTvt0); gbs = SourceSatCurrent*evbs/CONSTvt0 + ckt->CKTgmin; cbs = SourceSatCurrent * (evbs-1) + ckt->CKTgmin * vbs ; } if(vbd <= 0.0) { gbd = DrainSatCurrent / CONSTvt0 + ckt->CKTgmin; cbd = gbd * vbd ; } else { evbd = exp(vbd/CONSTvt0); gbd = DrainSatCurrent*evbd/CONSTvt0 +ckt->CKTgmin; cbd = DrainSatCurrent *(evbd-1)+ckt->CKTgmin*vbd; } /* line 400 */ if(vds >= 0) { /* normal mode */ here->B1mode = 1; } else { /* inverse mode */ here->B1mode = -1; } /* call B1evaluate to calculate drain current and its * derivatives and charge and capacitances related to gate * drain, and bulk */ if( vds >= 0 ) { B1evaluate(vds,vbs,vgs,here,model,&gm,&gds,&gmbs,&qgate, &qbulk,&qdrn,&cggb,&cgdb,&cgsb,&cbgb,&cbdb,&cbsb,&cdgb, &cddb,&cdsb,&cdrain,&von,&vdsat,ckt); } else { B1evaluate(-vds,vbd,vgd,here,model,&gm,&gds,&gmbs,&qgate, &qbulk,&qsrc,&cggb,&cgsb,&cgdb,&cbgb,&cbsb,&cbdb,&csgb, &cssb,&csdb,&cdrain,&von,&vdsat,ckt); } here->B1von = model->B1type * von; here->B1vdsat = model->B1type * vdsat; /* * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE */ cd=here->B1mode * cdrain - cbd; if ((ckt->CKTmode & (MODETRAN | MODEAC | MODEINITSMSIG)) || ((ckt->CKTmode & MODETRANOP ) && (ckt->CKTmode & MODEUIC))) { /* * charge storage elements * * bulk-drain and bulk-source depletion capacitances * czbd : zero bias drain junction capacitance * czbs : zero bias source junction capacitance * czbdsw:zero bias drain junction sidewall capacitance * czbssw:zero bias source junction sidewall capacitance */ czbd = model->B1unitAreaJctCap * DrainArea; czbs = model->B1unitAreaJctCap * SourceArea; czbdsw= model->B1unitLengthSidewallJctCap * DrainPerimeter; czbssw= model->B1unitLengthSidewallJctCap * SourcePerimeter; PhiB = model->B1bulkJctPotential; PhiBSW = model->B1sidewallJctPotential; MJ = model->B1bulkJctBotGradingCoeff; MJSW = model->B1bulkJctSideGradingCoeff; /* Source Bulk Junction */ if( vbs < 0 ) { arg = 1 - vbs / PhiB; argsw = 1 - vbs / PhiBSW; sarg = exp(-MJ*log(arg)); sargsw = exp(-MJSW*log(argsw)); *(ckt->CKTstate0 + here->B1qbs) = PhiB * czbs * (1-arg*sarg)/(1-MJ) + PhiBSW * czbssw * (1-argsw*sargsw)/(1-MJSW); capbs = czbs * sarg + czbssw * sargsw ; } else { *(ckt->CKTstate0+here->B1qbs) = vbs*(czbs+czbssw)+ vbs*vbs*(czbs*MJ*0.5/PhiB + czbssw * MJSW * 0.5/PhiBSW); capbs = czbs + czbssw + vbs *(czbs*MJ/PhiB+ czbssw * MJSW / PhiBSW ); } /* Drain Bulk Junction */ if( vbd < 0 ) { arg = 1 - vbd / PhiB; argsw = 1 - vbd / PhiBSW; sarg = exp(-MJ*log(arg)); sargsw = exp(-MJSW*log(argsw)); *(ckt->CKTstate0 + here->B1qbd) = PhiB * czbd * (1-arg*sarg)/(1-MJ) + PhiBSW * czbdsw * (1-argsw*sargsw)/(1-MJSW); capbd = czbd * sarg + czbdsw * sargsw ; } else { *(ckt->CKTstate0+here->B1qbd) = vbd*(czbd+czbdsw)+ vbd*vbd*(czbd*MJ*0.5/PhiB + czbdsw * MJSW * 0.5/PhiBSW); capbd = czbd + czbdsw + vbd *(czbd*MJ/PhiB+ czbdsw * MJSW / PhiBSW ); } } /* * check convergence */ if ( (here->B1off == 0) || (!(ckt->CKTmode & MODEINITFIX)) ){ if (Check == 1) { ckt->CKTnoncon++; ckt->CKTtroubleElt = (GENinstance *) here; } } *(ckt->CKTstate0 + here->B1vbs) = vbs; *(ckt->CKTstate0 + here->B1vbd) = vbd; *(ckt->CKTstate0 + here->B1vgs) = vgs; *(ckt->CKTstate0 + here->B1vds) = vds; *(ckt->CKTstate0 + here->B1cd) = cd; *(ckt->CKTstate0 + here->B1cbs) = cbs; *(ckt->CKTstate0 + here->B1cbd) = cbd; *(ckt->CKTstate0 + here->B1gm) = gm; *(ckt->CKTstate0 + here->B1gds) = gds; *(ckt->CKTstate0 + here->B1gmbs) = gmbs; *(ckt->CKTstate0 + here->B1gbd) = gbd; *(ckt->CKTstate0 + here->B1gbs) = gbs; *(ckt->CKTstate0 + here->B1cggb) = cggb; *(ckt->CKTstate0 + here->B1cgdb) = cgdb; *(ckt->CKTstate0 + here->B1cgsb) = cgsb; *(ckt->CKTstate0 + here->B1cbgb) = cbgb; *(ckt->CKTstate0 + here->B1cbdb) = cbdb; *(ckt->CKTstate0 + here->B1cbsb) = cbsb; *(ckt->CKTstate0 + here->B1cdgb) = cdgb; *(ckt->CKTstate0 + here->B1cddb) = cddb; *(ckt->CKTstate0 + here->B1cdsb) = cdsb; *(ckt->CKTstate0 + here->B1capbs) = capbs; *(ckt->CKTstate0 + here->B1capbd) = capbd; /* bulk and channel charge plus overlaps */ if((!(ckt->CKTmode & (MODETRAN | MODEAC))) && ((!(ckt->CKTmode & MODETRANOP)) || (!(ckt->CKTmode & MODEUIC))) && (!(ckt->CKTmode & MODEINITSMSIG))) goto line850; line755: if( here->B1mode > 0 ) { args[0] = GateDrainOverlapCap; args[1] = GateSourceOverlapCap; args[2] = GateBulkOverlapCap; args[3] = capbd; args[4] = capbs; args[5] = cggb; args[6] = cgdb; args[7] = cgsb; B1mosCap(ckt,vgd,vgs,vgb, args, /* GateDrainOverlapCap, GateSourceOverlapCap,GateBulkOverlapCap, capbd,capbs, cggb,cgdb,cgsb, */ cbgb,cbdb,cbsb, cdgb,cddb,cdsb, &gcggb,&gcgdb,&gcgsb, &gcbgb,&gcbdb,&gcbsb, &gcdgb,&gcddb,&gcdsb,&gcsgb,&gcsdb,&gcssb, &qgate,&qbulk, &qdrn,&qsrc); } else { args[0] = GateSourceOverlapCap; args[1] = GateDrainOverlapCap; args[2] = GateBulkOverlapCap; args[3] = capbs; args[4] = capbd; args[5] = cggb; args[6] = cgsb; args[7] = cgdb; B1mosCap(ckt,vgs,vgd,vgb, args, /* GateSourceOverlapCap, GateDrainOverlapCap,GateBulkOverlapCap, capbs,capbd, cggb,cgsb,cgdb, */ cbgb,cbsb,cbdb, csgb,cssb,csdb, &gcggb,&gcgsb,&gcgdb, &gcbgb,&gcbsb,&gcbdb, &gcsgb,&gcssb,&gcsdb,&gcdgb,&gcdsb,&gcddb, &qgate,&qbulk, &qsrc,&qdrn); } if(ByPass) goto line860; *(ckt->CKTstate0 + here->B1qg) = qgate; *(ckt->CKTstate0 + here->B1qd) = qdrn - *(ckt->CKTstate0 + here->B1qbd); *(ckt->CKTstate0 + here->B1qb) = qbulk + *(ckt->CKTstate0 + here->B1qbd) + *(ckt->CKTstate0 + here->B1qbs); /* store small signal parameters */ if((!(ckt->CKTmode & (MODEAC | MODETRAN))) && (ckt->CKTmode & MODETRANOP ) && (ckt->CKTmode & MODEUIC )) goto line850; if(ckt->CKTmode & MODEINITSMSIG ) { *(ckt->CKTstate0+here->B1cggb) = cggb; *(ckt->CKTstate0+here->B1cgdb) = cgdb; *(ckt->CKTstate0+here->B1cgsb) = cgsb; *(ckt->CKTstate0+here->B1cbgb) = cbgb; *(ckt->CKTstate0+here->B1cbdb) = cbdb; *(ckt->CKTstate0+here->B1cbsb) = cbsb; *(ckt->CKTstate0+here->B1cdgb) = cdgb; *(ckt->CKTstate0+here->B1cddb) = cddb; *(ckt->CKTstate0+here->B1cdsb) = cdsb; *(ckt->CKTstate0+here->B1capbd) = capbd; *(ckt->CKTstate0+here->B1capbs) = capbs; goto line1000; } if(ckt->CKTmode & MODEINITTRAN ) { *(ckt->CKTstate1+here->B1qb) = *(ckt->CKTstate0+here->B1qb) ; *(ckt->CKTstate1+here->B1qg) = *(ckt->CKTstate0+here->B1qg) ; *(ckt->CKTstate1+here->B1qd) = *(ckt->CKTstate0+here->B1qd) ; } error = NIintegrate(ckt,&geq,&ceq,0.0,here->B1qb); if(error) return(error); error = NIintegrate(ckt,&geq,&ceq,0.0,here->B1qg); if(error) return(error); error = NIintegrate(ckt,&geq,&ceq,0.0,here->B1qd); if(error) return(error); goto line860; line850: /* initialize to zero charge conductance and current */ ceqqg = ceqqb = ceqqd = 0.0; gcdgb = gcddb = gcdsb = 0.0; gcsgb = gcsdb = gcssb = 0.0; gcggb = gcgdb = gcgsb = 0.0; gcbgb = gcbdb = gcbsb = 0.0; goto line900; line860: /* evaluate equivalent charge current */ cqgate = *(ckt->CKTstate0 + here->B1iqg); cqbulk = *(ckt->CKTstate0 + here->B1iqb); cqdrn = *(ckt->CKTstate0 + here->B1iqd); ceqqg = cqgate - gcggb * vgb + gcgdb * vbd + gcgsb * vbs; ceqqb = cqbulk - gcbgb * vgb + gcbdb * vbd + gcbsb * vbs; ceqqd = cqdrn - gcdgb * vgb + gcddb * vbd + gcdsb * vbs; if(ckt->CKTmode & MODEINITTRAN ) { *(ckt->CKTstate1 + here->B1iqb) = *(ckt->CKTstate0 + here->B1iqb); *(ckt->CKTstate1 + here->B1iqg) = *(ckt->CKTstate0 + here->B1iqg); *(ckt->CKTstate1 + here->B1iqd) = *(ckt->CKTstate0 + here->B1iqd); } /* * load current vector */ line900: m = here->B1m; ceqbs = model->B1type * (cbs-(gbs-ckt->CKTgmin)*vbs); ceqbd = model->B1type * (cbd-(gbd-ckt->CKTgmin)*vbd); ceqqg = model->B1type * ceqqg; ceqqb = model->B1type * ceqqb; ceqqd = model->B1type * ceqqd; if (here->B1mode >= 0) { xnrm=1; xrev=0; cdreq=model->B1type*(cdrain-gds*vds-gm*vgs-gmbs*vbs); } else { xnrm=0; xrev=1; cdreq = -(model->B1type)*(cdrain+gds*vds-gm*vgd-gmbs*vbd); } *(ckt->CKTrhs + here->B1gNode) -= m * ceqqg; *(ckt->CKTrhs + here->B1bNode) -= m * (ceqbs+ceqbd+ceqqb); *(ckt->CKTrhs + here->B1dNodePrime) += m * (ceqbd-cdreq-ceqqd); *(ckt->CKTrhs + here->B1sNodePrime) += m * (cdreq+ceqbs+ceqqg+ceqqb+ceqqd); /* * load y matrix */ *(here->B1DdPtr) += m * (here->B1drainConductance); *(here->B1GgPtr) += m * (gcggb); *(here->B1SsPtr) += m * (here->B1sourceConductance); *(here->B1BbPtr) += m * (gbd+gbs-gcbgb-gcbdb-gcbsb); *(here->B1DPdpPtr) += m * (here->B1drainConductance+gds+gbd+xrev*(gm+gmbs)+gcddb); *(here->B1SPspPtr) += m * (here->B1sourceConductance+gds+gbs+xnrm*(gm+gmbs)+gcssb); *(here->B1DdpPtr) += m * (-here->B1drainConductance); *(here->B1GbPtr) += m * (-gcggb-gcgdb-gcgsb); *(here->B1GdpPtr) += m * (gcgdb); *(here->B1GspPtr) += m * (gcgsb); *(here->B1SspPtr) += m * (-here->B1sourceConductance); *(here->B1BgPtr) += m * (gcbgb); *(here->B1BdpPtr) += m * (-gbd+gcbdb); *(here->B1BspPtr) += m * (-gbs+gcbsb); *(here->B1DPdPtr) += m * (-here->B1drainConductance); *(here->B1DPgPtr) += m * ((xnrm-xrev)*gm+gcdgb); *(here->B1DPbPtr) += m * (-gbd+(xnrm-xrev)*gmbs-gcdgb-gcddb-gcdsb); *(here->B1DPspPtr) += m * (-gds-xnrm*(gm+gmbs)+gcdsb); *(here->B1SPgPtr) += m * (-(xnrm-xrev)*gm+gcsgb); *(here->B1SPsPtr) += m * (-here->B1sourceConductance); *(here->B1SPbPtr) += m * (-gbs-(xnrm-xrev)*gmbs-gcsgb-gcsdb-gcssb); *(here->B1SPdpPtr) += m * (-gds-xrev*(gm+gmbs)+gcsdb); line1000: ; } /* End of Mosfet Instance */ } /* End of Model Instance */ return(OK); }
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); }
int JFETload(GENmodel *inModel, CKTcircuit *ckt) /* actually load the current resistance value into the * sparse matrix previously provided */ { JFETmodel *model = (JFETmodel*)inModel; JFETinstance *here; double beta; double betap; double capgd; double capgs; double cd; double cdhat = 0.0; double cdrain; double cdreq; double ceq; double ceqgd; double ceqgs; double cg; double cgd; double cghat = 0.0; double csat; double czgd; double czgdf2; double czgs; double czgsf2; double delvds; double delvgd; double delvgs; double evgd; double evgs; double fcpb2; double gdpr; double gds; double geq; double ggd; double ggs; double gm; double gspr; double sarg; double twop; double vds; double vgd; double vgdt; double vgs; double vgst; #ifndef PREDICTOR double xfact; #endif /* Modification for Sydney University JFET model */ double vto; double apart,cpart; double Bfac; /* end Sydney University mod. */ int icheck; int ichk1; int error; double arg, vt_temp; double m; /* loop through all the models */ for( ; model != NULL; model = JFETnextModel(model)) { /* loop through all the instances of the model */ for (here = JFETinstances(model); here != NULL ; here=JFETnextInstance(here)) { /* * dc model parameters */ beta = here->JFETtBeta * here->JFETarea; gdpr=model->JFETdrainConduct*here->JFETarea; gspr=model->JFETsourceConduct*here->JFETarea; csat=here->JFETtSatCur*here->JFETarea; /* * initialization */ icheck=1; if( ckt->CKTmode & MODEINITSMSIG) { vgs= *(ckt->CKTstate0 + here->JFETvgs); vgd= *(ckt->CKTstate0 + here->JFETvgd); } else if (ckt->CKTmode & MODEINITTRAN) { vgs= *(ckt->CKTstate1 + here->JFETvgs); vgd= *(ckt->CKTstate1 + here->JFETvgd); } else if ( (ckt->CKTmode & MODEINITJCT) && (ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC) ) { vds=model->JFETtype*here->JFETicVDS; vgs=model->JFETtype*here->JFETicVGS; vgd=vgs-vds; } else if ( (ckt->CKTmode & MODEINITJCT) && (here->JFEToff == 0) ) { vgs = -1; vgd = -1; } else if( (ckt->CKTmode & MODEINITJCT) || ((ckt->CKTmode & MODEINITFIX) && (here->JFEToff))) { vgs = 0; vgd = 0; } else { #ifndef PREDICTOR if(ckt->CKTmode & MODEINITPRED) { xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1]; *(ckt->CKTstate0 + here->JFETvgs)= *(ckt->CKTstate1 + here->JFETvgs); vgs=(1+xfact)* *(ckt->CKTstate1 + here->JFETvgs)-xfact* *(ckt->CKTstate2 + here->JFETvgs); *(ckt->CKTstate0 + here->JFETvgd)= *(ckt->CKTstate1 + here->JFETvgd); vgd=(1+xfact)* *(ckt->CKTstate1 + here->JFETvgd)-xfact* *(ckt->CKTstate2 + here->JFETvgd); *(ckt->CKTstate0 + here->JFETcg)= *(ckt->CKTstate1 + here->JFETcg); *(ckt->CKTstate0 + here->JFETcd)= *(ckt->CKTstate1 + here->JFETcd); *(ckt->CKTstate0 + here->JFETcgd)= *(ckt->CKTstate1 + here->JFETcgd); *(ckt->CKTstate0 + here->JFETgm)= *(ckt->CKTstate1 + here->JFETgm); *(ckt->CKTstate0 + here->JFETgds)= *(ckt->CKTstate1 + here->JFETgds); *(ckt->CKTstate0 + here->JFETggs)= *(ckt->CKTstate1 + here->JFETggs); *(ckt->CKTstate0 + here->JFETggd)= *(ckt->CKTstate1 + here->JFETggd); } else { #endif /*PREDICTOR*/ /* * compute new nonlinear branch voltages */ vgs=model->JFETtype* (*(ckt->CKTrhsOld+ here->JFETgateNode)- *(ckt->CKTrhsOld+ here->JFETsourcePrimeNode)); vgd=model->JFETtype* (*(ckt->CKTrhsOld+here->JFETgateNode)- *(ckt->CKTrhsOld+ here->JFETdrainPrimeNode)); #ifndef PREDICTOR } #endif /*PREDICTOR*/ delvgs=vgs- *(ckt->CKTstate0 + here->JFETvgs); delvgd=vgd- *(ckt->CKTstate0 + here->JFETvgd); delvds=delvgs-delvgd; cghat= *(ckt->CKTstate0 + here->JFETcg)+ *(ckt->CKTstate0 + here->JFETggd)*delvgd+ *(ckt->CKTstate0 + here->JFETggs)*delvgs; cdhat= *(ckt->CKTstate0 + here->JFETcd)+ *(ckt->CKTstate0 + here->JFETgm)*delvgs+ *(ckt->CKTstate0 + here->JFETgds)*delvds- *(ckt->CKTstate0 + here->JFETggd)*delvgd; /* * bypass if solution has not changed */ if((ckt->CKTbypass) && (!(ckt->CKTmode & MODEINITPRED)) && (fabs(delvgs) < ckt->CKTreltol*MAX(fabs(vgs), fabs(*(ckt->CKTstate0 + here->JFETvgs)))+ ckt->CKTvoltTol) ) if ( (fabs(delvgd) < ckt->CKTreltol*MAX(fabs(vgd), fabs(*(ckt->CKTstate0 + here->JFETvgd)))+ ckt->CKTvoltTol)) if ( (fabs(cghat-*(ckt->CKTstate0 + here->JFETcg)) < ckt->CKTreltol*MAX(fabs(cghat), fabs(*(ckt->CKTstate0 + here->JFETcg)))+ ckt->CKTabstol) ) if ( /* hack - expression too big */ (fabs(cdhat-*(ckt->CKTstate0 + here->JFETcd)) < ckt->CKTreltol*MAX(fabs(cdhat), fabs(*(ckt->CKTstate0 + here->JFETcd)))+ ckt->CKTabstol) ) { /* we can do a bypass */ vgs= *(ckt->CKTstate0 + here->JFETvgs); vgd= *(ckt->CKTstate0 + here->JFETvgd); vds= vgs-vgd; cg= *(ckt->CKTstate0 + here->JFETcg); cd= *(ckt->CKTstate0 + here->JFETcd); cgd= *(ckt->CKTstate0 + here->JFETcgd); gm= *(ckt->CKTstate0 + here->JFETgm); gds= *(ckt->CKTstate0 + here->JFETgds); ggs= *(ckt->CKTstate0 + here->JFETggs); ggd= *(ckt->CKTstate0 + here->JFETggd); goto load; } /* * limit nonlinear branch voltages */ ichk1=1; vgs = DEVpnjlim(vgs,*(ckt->CKTstate0 + here->JFETvgs), (here->JFETtemp*CONSTKoverQ), here->JFETvcrit, &icheck); vgd = DEVpnjlim(vgd,*(ckt->CKTstate0 + here->JFETvgd), (here->JFETtemp*CONSTKoverQ), here->JFETvcrit,&ichk1); if (ichk1 == 1) { icheck=1; } vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->JFETvgs), here->JFETtThreshold); vgd = DEVfetlim(vgd,*(ckt->CKTstate0 + here->JFETvgd), here->JFETtThreshold); } /* * determine dc current and derivatives */ vds=vgs-vgd; vt_temp=here->JFETtemp*CONSTKoverQ; if (vgs < -3*vt_temp) { arg=3*vt_temp/(vgs*CONSTe); arg = arg * arg * arg; cg = -csat*(1+arg)+ckt->CKTgmin*vgs; ggs = csat*3*arg/vgs+ckt->CKTgmin; } else { evgs = exp(vgs/vt_temp); ggs = csat*evgs/vt_temp+ckt->CKTgmin; cg = csat*(evgs-1)+ckt->CKTgmin*vgs; } if (vgd < -3*vt_temp) { arg=3*vt_temp/(vgd*CONSTe); arg = arg * arg * arg; cgd = -csat*(1+arg)+ckt->CKTgmin*vgd; ggd = csat*3*arg/vgd+ckt->CKTgmin; } else { evgd = exp(vgd/vt_temp); ggd = csat*evgd/vt_temp+ckt->CKTgmin; cgd = csat*(evgd-1)+ckt->CKTgmin*vgd; } cg = cg+cgd; /* Modification for Sydney University JFET model */ vto = here->JFETtThreshold; if (vds >= 0) { vgst = vgs - vto; /* * compute drain current and derivatives for normal mode */ if (vgst <= 0) { /* * normal mode, cutoff region */ cdrain = 0; gm = 0; gds = 0; } else { betap = beta*(1 + model->JFETlModulation*vds); Bfac = model->JFETbFac; if (vgst >= vds) { /* * normal mode, linear region */ apart = 2*model->JFETb + 3*Bfac*(vgst - vds); cpart = vds*(vds*(Bfac*vds - model->JFETb)+vgst*apart); cdrain = betap*cpart; gm = betap*vds*(apart + 3*Bfac*vgst); gds = betap*(vgst - vds)*apart + beta*model->JFETlModulation*cpart; } else { Bfac = vgst*Bfac; gm = betap*vgst*(2*model->JFETb+3*Bfac); /* * normal mode, saturation region */ cpart=vgst*vgst*(model->JFETb+Bfac); cdrain = betap*cpart; gds = model->JFETlModulation*beta*cpart; } } } else { vgdt = vgd - vto; /* * compute drain current and derivatives for inverse mode */ if (vgdt <= 0) { /* * inverse mode, cutoff region */ cdrain = 0; gm = 0; gds = 0; } else { betap = beta*(1 - model->JFETlModulation*vds); Bfac = model->JFETbFac; if (vgdt + vds >= 0) { /* * inverse mode, linear region */ apart = 2*model->JFETb + 3*Bfac*(vgdt + vds); cpart = vds*(-vds*(-Bfac*vds-model->JFETb)+vgdt*apart); cdrain = betap*cpart; gm = betap*vds*(apart + 3*Bfac*vgdt); gds = betap*(vgdt + vds)*apart - beta*model->JFETlModulation*cpart - gm; } else { Bfac = vgdt*Bfac; gm = -betap*vgdt*(2*model->JFETb+3*Bfac); /* * inverse mode, saturation region */ cpart=vgdt*vgdt*(model->JFETb+Bfac); cdrain = - betap*cpart; gds = model->JFETlModulation*beta*cpart-gm; } } } #ifdef notdef /* The original section is now commented out */ /* end Sydney University mod */ /* * compute drain current and derivitives for normal mode */ if (vds >= 0) { vgst=vgs-here->JFETtThreshold; /* * normal mode, cutoff region */ if (vgst <= 0) { cdrain=0; gm=0; gds=0; } else { betap=beta*(1+model->JFETlModulation*vds); twob=betap+betap; if (vgst <= vds) { /* * normal mode, saturation region */ cdrain=betap*vgst*vgst; gm=twob*vgst; gds=model->JFETlModulation*beta*vgst*vgst; } else { /* * normal mode, linear region */ cdrain=betap*vds*(vgst+vgst-vds); gm=twob*vds; gds=twob*(vgst-vds)+model->JFETlModulation*beta* vds*(vgst+vgst-vds); } } } else { /* * compute drain current and derivitives for inverse mode */ vgdt=vgd-here->JFETtThreshold; if (vgdt <= 0) { /* * inverse mode, cutoff region */ cdrain=0; gm=0; gds=0; } else { /* * inverse mode, saturation region */ betap=beta*(1-model->JFETlModulation*vds); twob=betap+betap; if (vgdt <= -vds) { cdrain = -betap*vgdt*vgdt; gm = -twob*vgdt; gds = model->JFETlModulation*beta*vgdt*vgdt-gm; } else { /* * inverse mode, linear region */ cdrain=betap*vds*(vgdt+vgdt+vds); gm=twob*vds; gds=twob*vgdt-model->JFETlModulation*beta*vds* (vgdt+vgdt+vds); } } } /* end of original section, now deleted (replaced w/SU mod */ #endif /* * compute equivalent drain current source */ cd=cdrain-cgd; if ( (ckt->CKTmode & (MODEDCTRANCURVE | MODETRAN | MODEAC | MODEINITSMSIG) ) || ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) ){ /* * charge storage elements */ czgs=here->JFETtCGS*here->JFETarea; czgd=here->JFETtCGD*here->JFETarea; twop=here->JFETtGatePot+here->JFETtGatePot; fcpb2=here->JFETcorDepCap*here->JFETcorDepCap; czgsf2=czgs/model->JFETf2; czgdf2=czgd/model->JFETf2; if (vgs < here->JFETcorDepCap) { sarg=sqrt(1-vgs/here->JFETtGatePot); *(ckt->CKTstate0 + here->JFETqgs) = twop*czgs*(1-sarg); capgs=czgs/sarg; } else { *(ckt->CKTstate0 + here->JFETqgs) = czgs*here->JFETf1 + czgsf2*(model->JFETf3 *(vgs- here->JFETcorDepCap)+(vgs*vgs-fcpb2)/ (twop+twop)); capgs=czgsf2*(model->JFETf3+vgs/twop); } if (vgd < here->JFETcorDepCap) { sarg=sqrt(1-vgd/here->JFETtGatePot); *(ckt->CKTstate0 + here->JFETqgd) = twop*czgd*(1-sarg); capgd=czgd/sarg; } else { *(ckt->CKTstate0 + here->JFETqgd) = czgd*here->JFETf1+ czgdf2*(model->JFETf3* (vgd- here->JFETcorDepCap)+(vgd*vgd-fcpb2)/ (twop+twop)); capgd=czgdf2*(model->JFETf3+vgd/twop); } /* * store small-signal parameters */ if( (!(ckt->CKTmode & MODETRANOP)) || (!(ckt->CKTmode & MODEUIC)) ) { if(ckt->CKTmode & MODEINITSMSIG) { *(ckt->CKTstate0 + here->JFETqgs) = capgs; *(ckt->CKTstate0 + here->JFETqgd) = capgd; continue; /*go to 1000*/ } /* * transient analysis */ if(ckt->CKTmode & MODEINITTRAN) { *(ckt->CKTstate1 + here->JFETqgs) = *(ckt->CKTstate0 + here->JFETqgs); *(ckt->CKTstate1 + here->JFETqgd) = *(ckt->CKTstate0 + here->JFETqgd); } error = NIintegrate(ckt,&geq,&ceq,capgs,here->JFETqgs); if(error) return(error); ggs = ggs + geq; cg = cg + *(ckt->CKTstate0 + here->JFETcqgs); error = NIintegrate(ckt,&geq,&ceq,capgd,here->JFETqgd); if(error) return(error); ggd = ggd + geq; cg = cg + *(ckt->CKTstate0 + here->JFETcqgd); cd = cd - *(ckt->CKTstate0 + here->JFETcqgd); cgd = cgd + *(ckt->CKTstate0 + here->JFETcqgd); if (ckt->CKTmode & MODEINITTRAN) { *(ckt->CKTstate1 + here->JFETcqgs) = *(ckt->CKTstate0 + here->JFETcqgs); *(ckt->CKTstate1 + here->JFETcqgd) = *(ckt->CKTstate0 + here->JFETcqgd); } } } /* * 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->JFETvgs) = vgs; *(ckt->CKTstate0 + here->JFETvgd) = vgd; *(ckt->CKTstate0 + here->JFETcg) = cg; *(ckt->CKTstate0 + here->JFETcd) = cd; *(ckt->CKTstate0 + here->JFETcgd) = cgd; *(ckt->CKTstate0 + here->JFETgm) = gm; *(ckt->CKTstate0 + here->JFETgds) = gds; *(ckt->CKTstate0 + here->JFETggs) = ggs; *(ckt->CKTstate0 + here->JFETggd) = ggd; /* * load current vector */ load: m = here->JFETm; ceqgd=model->JFETtype*(cgd-ggd*vgd); ceqgs=model->JFETtype*((cg-cgd)-ggs*vgs); cdreq=model->JFETtype*((cd+cgd)-gds*vds-gm*vgs); *(ckt->CKTrhs + here->JFETgateNode) += m * (-ceqgs-ceqgd); *(ckt->CKTrhs + here->JFETdrainPrimeNode) += m * (-cdreq+ceqgd); *(ckt->CKTrhs + here->JFETsourcePrimeNode) += m * (cdreq+ceqgs); /* * load y matrix */ *(here->JFETdrainDrainPrimePtr) += m * (-gdpr); *(here->JFETgateDrainPrimePtr) += m * (-ggd); *(here->JFETgateSourcePrimePtr) += m * (-ggs); *(here->JFETsourceSourcePrimePtr) += m * (-gspr); *(here->JFETdrainPrimeDrainPtr) += m * (-gdpr); *(here->JFETdrainPrimeGatePtr) += m * (gm-ggd); *(here->JFETdrainPrimeSourcePrimePtr) += m * (-gds-gm); *(here->JFETsourcePrimeGatePtr) += m * (-ggs-gm); *(here->JFETsourcePrimeSourcePtr) += m * (-gspr); *(here->JFETsourcePrimeDrainPrimePtr) += m * (-gds); *(here->JFETdrainDrainPtr) += m * (gdpr); *(here->JFETgateGatePtr) += m * (ggd+ggs); *(here->JFETsourceSourcePtr) += m * (gspr); *(here->JFETdrainPrimeDrainPrimePtr) += m * (gdpr+gds+ggd); *(here->JFETsourcePrimeSourcePrimePtr) += m * (gspr+gds+gm+ggs); } } return(OK); }
int JFET2load(GENmodel *inModel, CKTcircuit *ckt) /* actually load the current resistance value into the * sparse matrix previously provided */ { JFET2model *model = (JFET2model*)inModel; JFET2instance *here; double capgd; double capgs; double cd; double cdhat = 0.0; double cdreq; double ceq; double ceqgd; double ceqgs; double cg; double cgd; double cghat = 0.0; double delvds; double delvgd; double delvgs; double gdpr; double gds; double geq; double ggd; double ggs; double gm; double gspr; double vds; double vgd; double vgs; double xfact; int icheck; int ichk1; int error; double m; /* loop through all the models */ for( ; model != NULL; model = model->JFET2nextModel ) { /* loop through all the instances of the model */ for (here = model->JFET2instances; here != NULL ; here=here->JFET2nextInstance) { if (here->JFET2owner != ARCHme) continue; /* * dc model parameters */ gdpr=model->JFET2drainConduct*here->JFET2area; gspr=model->JFET2sourceConduct*here->JFET2area; /* * initialization */ icheck=1; if( ckt->CKTmode & MODEINITSMSIG) { vgs= *(ckt->CKTstate0 + here->JFET2vgs); vgd= *(ckt->CKTstate0 + here->JFET2vgd); } else if (ckt->CKTmode & MODEINITTRAN) { vgs= *(ckt->CKTstate1 + here->JFET2vgs); vgd= *(ckt->CKTstate1 + here->JFET2vgd); } else if ( (ckt->CKTmode & MODEINITJCT) && (ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC) ) { vds=model->JFET2type*here->JFET2icVDS; vgs=model->JFET2type*here->JFET2icVGS; vgd=vgs-vds; } else if ( (ckt->CKTmode & MODEINITJCT) && (here->JFET2off == 0) ) { vgs = -1; vgd = -1; } else if( (ckt->CKTmode & MODEINITJCT) || ((ckt->CKTmode & MODEINITFIX) && (here->JFET2off))) { vgs = 0; vgd = 0; } else { #ifndef PREDICTOR if(ckt->CKTmode & MODEINITPRED) { xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1]; *(ckt->CKTstate0 + here->JFET2vgs)= *(ckt->CKTstate1 + here->JFET2vgs); vgs=(1+xfact)* *(ckt->CKTstate1 + here->JFET2vgs)-xfact* *(ckt->CKTstate2 + here->JFET2vgs); *(ckt->CKTstate0 + here->JFET2vgd)= *(ckt->CKTstate1 + here->JFET2vgd); vgd=(1+xfact)* *(ckt->CKTstate1 + here->JFET2vgd)-xfact* *(ckt->CKTstate2 + here->JFET2vgd); *(ckt->CKTstate0 + here->JFET2cg)= *(ckt->CKTstate1 + here->JFET2cg); *(ckt->CKTstate0 + here->JFET2cd)= *(ckt->CKTstate1 + here->JFET2cd); *(ckt->CKTstate0 + here->JFET2cgd)= *(ckt->CKTstate1 + here->JFET2cgd); *(ckt->CKTstate0 + here->JFET2gm)= *(ckt->CKTstate1 + here->JFET2gm); *(ckt->CKTstate0 + here->JFET2gds)= *(ckt->CKTstate1 + here->JFET2gds); *(ckt->CKTstate0 + here->JFET2ggs)= *(ckt->CKTstate1 + here->JFET2ggs); *(ckt->CKTstate0 + here->JFET2ggd)= *(ckt->CKTstate1 + here->JFET2ggd); } else { #endif /*PREDICTOR*/ /* * compute new nonlinear branch voltages */ vgs=model->JFET2type* (*(ckt->CKTrhsOld+ here->JFET2gateNode)- *(ckt->CKTrhsOld+ here->JFET2sourcePrimeNode)); vgd=model->JFET2type* (*(ckt->CKTrhsOld+here->JFET2gateNode)- *(ckt->CKTrhsOld+ here->JFET2drainPrimeNode)); #ifndef PREDICTOR } #endif /*PREDICTOR*/ delvgs=vgs- *(ckt->CKTstate0 + here->JFET2vgs); delvgd=vgd- *(ckt->CKTstate0 + here->JFET2vgd); delvds=delvgs-delvgd; cghat= *(ckt->CKTstate0 + here->JFET2cg)+ *(ckt->CKTstate0 + here->JFET2ggd)*delvgd+ *(ckt->CKTstate0 + here->JFET2ggs)*delvgs; cdhat= *(ckt->CKTstate0 + here->JFET2cd)+ *(ckt->CKTstate0 + here->JFET2gm)*delvgs+ *(ckt->CKTstate0 + here->JFET2gds)*delvds- *(ckt->CKTstate0 + here->JFET2ggd)*delvgd; /* * bypass if solution has not changed */ if((ckt->CKTbypass) && (!(ckt->CKTmode & MODEINITPRED)) && (fabs(delvgs) < ckt->CKTreltol*MAX(fabs(vgs), fabs(*(ckt->CKTstate0 + here->JFET2vgs)))+ ckt->CKTvoltTol) ) if ( (fabs(delvgd) < ckt->CKTreltol*MAX(fabs(vgd), fabs(*(ckt->CKTstate0 + here->JFET2vgd)))+ ckt->CKTvoltTol)) if ( (fabs(cghat-*(ckt->CKTstate0 + here->JFET2cg)) < ckt->CKTreltol*MAX(fabs(cghat), fabs(*(ckt->CKTstate0 + here->JFET2cg)))+ ckt->CKTabstol) ) if ( /* hack - expression too big */ (fabs(cdhat-*(ckt->CKTstate0 + here->JFET2cd)) < ckt->CKTreltol*MAX(fabs(cdhat), fabs(*(ckt->CKTstate0 + here->JFET2cd)))+ ckt->CKTabstol) ) { /* we can do a bypass */ vgs= *(ckt->CKTstate0 + here->JFET2vgs); vgd= *(ckt->CKTstate0 + here->JFET2vgd); vds= vgs-vgd; cg= *(ckt->CKTstate0 + here->JFET2cg); cd= *(ckt->CKTstate0 + here->JFET2cd); cgd= *(ckt->CKTstate0 + here->JFET2cgd); gm= *(ckt->CKTstate0 + here->JFET2gm); gds= *(ckt->CKTstate0 + here->JFET2gds); ggs= *(ckt->CKTstate0 + here->JFET2ggs); ggd= *(ckt->CKTstate0 + here->JFET2ggd); goto load; } /* * limit nonlinear branch voltages */ ichk1=1; vgs = DEVpnjlim(vgs,*(ckt->CKTstate0 + here->JFET2vgs), (here->JFET2temp*CONSTKoverQ), here->JFET2vcrit, &icheck); vgd = DEVpnjlim(vgd,*(ckt->CKTstate0 + here->JFET2vgd), (here->JFET2temp*CONSTKoverQ), here->JFET2vcrit,&ichk1); if (ichk1 == 1) { icheck=1; } vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->JFET2vgs), model->JFET2vto); vgd = DEVfetlim(vgd,*(ckt->CKTstate0 + here->JFET2vgd), model->JFET2vto); } /* * determine dc current and derivatives */ vds=vgs-vgd; if (vds < 0.0) { cd = -PSids(ckt, model, here, vgd, vgs, &cgd, &cg, &ggd, &ggs, &gm, &gds); gds += gm; gm = -gm; } else { cd = PSids(ckt, model, here, vgs, vgd, &cg, &cgd, &ggs, &ggd, &gm, &gds); } cg = cg + cgd; cd = cd - cgd; if ( (ckt->CKTmode & (MODETRAN | MODEAC | MODEINITSMSIG) ) || ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) ){ /* * charge storage elements */ double capds = model->JFET2capds*here->JFET2area; PScharge(ckt, model, here, vgs, vgd, &capgs, &capgd); *(ckt->CKTstate0 + here->JFET2qds) = capds * vds; /* * store small-signal parameters */ if( (!(ckt->CKTmode & MODETRANOP)) || (!(ckt->CKTmode & MODEUIC)) ) { if(ckt->CKTmode & MODEINITSMSIG) { *(ckt->CKTstate0 + here->JFET2qgs) = capgs; *(ckt->CKTstate0 + here->JFET2qgd) = capgd; *(ckt->CKTstate0 + here->JFET2qds) = capds; continue; /*go to 1000*/ } /* * transient analysis */ if(ckt->CKTmode & MODEINITTRAN) { *(ckt->CKTstate1 + here->JFET2qgs) = *(ckt->CKTstate0 + here->JFET2qgs); *(ckt->CKTstate1 + here->JFET2qgd) = *(ckt->CKTstate0 + here->JFET2qgd); *(ckt->CKTstate1 + here->JFET2qds) = *(ckt->CKTstate0 + here->JFET2qds); } error = NIintegrate(ckt,&geq,&ceq,capgs,here->JFET2qgs); if(error) return(error); ggs = ggs + geq; cg = cg + *(ckt->CKTstate0 + here->JFET2cqgs); error = NIintegrate(ckt,&geq,&ceq,capgd,here->JFET2qgd); if(error) return(error); ggd = ggd + geq; cg = cg + *(ckt->CKTstate0 + here->JFET2cqgd); cd = cd - *(ckt->CKTstate0 + here->JFET2cqgd); cgd = cgd + *(ckt->CKTstate0 + here->JFET2cqgd); error = NIintegrate(ckt,&geq,&ceq,capds,here->JFET2qds); cd = cd + *(ckt->CKTstate0 + here->JFET2cqds); if(error) return(error); if (ckt->CKTmode & MODEINITTRAN) { *(ckt->CKTstate1 + here->JFET2cqgs) = *(ckt->CKTstate0 + here->JFET2cqgs); *(ckt->CKTstate1 + here->JFET2cqgd) = *(ckt->CKTstate0 + here->JFET2cqgd); *(ckt->CKTstate1 + here->JFET2cqds) = *(ckt->CKTstate0 + here->JFET2cqds); } } } /* * 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->JFET2vgs) = vgs; *(ckt->CKTstate0 + here->JFET2vgd) = vgd; *(ckt->CKTstate0 + here->JFET2cg) = cg; *(ckt->CKTstate0 + here->JFET2cd) = cd; *(ckt->CKTstate0 + here->JFET2cgd) = cgd; *(ckt->CKTstate0 + here->JFET2gm) = gm; *(ckt->CKTstate0 + here->JFET2gds) = gds; *(ckt->CKTstate0 + here->JFET2ggs) = ggs; *(ckt->CKTstate0 + here->JFET2ggd) = ggd; /* * load current vector */ load: m = here->JFET2m; ceqgd=model->JFET2type*(cgd-ggd*vgd); ceqgs=model->JFET2type*((cg-cgd)-ggs*vgs); cdreq=model->JFET2type*((cd+cgd)-gds*vds-gm*vgs); *(ckt->CKTrhs + here->JFET2gateNode) += m * (-ceqgs-ceqgd); *(ckt->CKTrhs + here->JFET2drainPrimeNode) += m * (-cdreq+ceqgd); *(ckt->CKTrhs + here->JFET2sourcePrimeNode) += m * (cdreq+ceqgs); /* * load y matrix */ *(here->JFET2drainDrainPrimePtr) += m * (-gdpr); *(here->JFET2gateDrainPrimePtr) += m * (-ggd); *(here->JFET2gateSourcePrimePtr) += m * (-ggs); *(here->JFET2sourceSourcePrimePtr) += m * (-gspr); *(here->JFET2drainPrimeDrainPtr) += m * (-gdpr); *(here->JFET2drainPrimeGatePtr) += m * (gm-ggd); *(here->JFET2drainPrimeSourcePrimePtr) += m * (-gds-gm); *(here->JFET2sourcePrimeGatePtr) += m * (-ggs-gm); *(here->JFET2sourcePrimeSourcePtr) += m * (-gspr); *(here->JFET2sourcePrimeDrainPrimePtr) += m * (-gds); *(here->JFET2drainDrainPtr) += m * (gdpr); *(here->JFET2gateGatePtr) += m * (ggd+ggs); *(here->JFET2sourceSourcePtr) += m * (gspr); *(here->JFET2drainPrimeDrainPrimePtr) += m * (gdpr+gds+ggd); *(here->JFET2sourcePrimeSourcePrimePtr) += m * (gspr+gds+gm+ggs); } } return(OK); }
int MOS1load(GENmodel *inModel, CKTcircuit *ckt) /* actually load the current value into the * sparse matrix previously provided */ { MOS1model *model = (MOS1model *) inModel; MOS1instance *here; double Beta; double DrainSatCur; double EffectiveLength; 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 vt; 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; #ifdef CAPBYPASS senflag = 0; if(ckt->CKTsenInfo && ckt->CKTsenInfo->SENstatus == PERTURBATION && (ckt->CKTsenInfo->SENmode & (ACSEN | TRANSEN))) { senflag = 1; } #endif /* CAPBYPASS */ /* loop through all the MOS1 device models */ for( ; model != NULL; model = model->MOS1nextModel ) { /* loop through all the instances of the model */ for (here = model->MOS1instances; here != NULL ; here=here->MOS1nextInstance) { if (here->MOS1owner != ARCHme) continue; vt = CONSTKoverQ * here->MOS1temp; Check=1; if(ckt->CKTsenInfo){ #ifdef SENSDEBUG printf("MOS1load \n"); #endif /* SENSDEBUG */ if((ckt->CKTsenInfo->SENstatus == PERTURBATION)&& (here->MOS1senPertFlag == OFF))continue; } SenCond = ckt->CKTsenInfo && here->MOS1senPertFlag; /* */ /* 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 */ EffectiveLength=here->MOS1l - 2*model->MOS1latDiff; if( (here->MOS1tSatCurDens == 0) || (here->MOS1drainArea == 0) || (here->MOS1sourceArea == 0)) { DrainSatCur = here->MOS1m * here->MOS1tSatCur; SourceSatCur = here->MOS1m * here->MOS1tSatCur; } else { DrainSatCur = here->MOS1tSatCurDens * here->MOS1m * here->MOS1drainArea; SourceSatCur = here->MOS1tSatCurDens * here->MOS1m * here->MOS1sourceArea; } GateSourceOverlapCap = model->MOS1gateSourceOverlapCapFactor * here->MOS1m * here->MOS1w; GateDrainOverlapCap = model->MOS1gateDrainOverlapCapFactor * here->MOS1m * here->MOS1w; GateBulkOverlapCap = model->MOS1gateBulkOverlapCapFactor * here->MOS1m * EffectiveLength; Beta = here->MOS1tTransconductance * here->MOS1m * here->MOS1w/EffectiveLength; OxideCap = model->MOS1oxideCapFactor * EffectiveLength * here->MOS1m * here->MOS1w; /* * 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(SenCond){ #ifdef SENSDEBUG printf("MOS1senPertFlag = ON \n"); #endif /* SENSDEBUG */ if((ckt->CKTsenInfo->SENmode == TRANSEN) && (ckt->CKTmode & MODEINITTRAN)) { vgs = *(ckt->CKTstate1 + here->MOS1vgs); vds = *(ckt->CKTstate1 + here->MOS1vds); vbs = *(ckt->CKTstate1 + here->MOS1vbs); vbd = *(ckt->CKTstate1 + here->MOS1vbd); vgb = vgs - vbs; vgd = vgs - vds; } else if (ckt->CKTsenInfo->SENmode == ACSEN){ vgb = model->MOS1type * ( *(ckt->CKTrhsOp+here->MOS1gNode) - *(ckt->CKTrhsOp+here->MOS1bNode)); vbs = *(ckt->CKTstate0 + here->MOS1vbs); vbd = *(ckt->CKTstate0 + here->MOS1vbd); vgd = vgb + vbd ; vgs = vgb + vbs ; vds = vbs - vbd ; } else{ vgs = *(ckt->CKTstate0 + here->MOS1vgs); vds = *(ckt->CKTstate0 + here->MOS1vds); vbs = *(ckt->CKTstate0 + here->MOS1vbs); vbd = *(ckt->CKTstate0 + here->MOS1vbd); 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; } if((ckt->CKTmode & (MODEINITFLOAT | MODEINITPRED | MODEINITSMSIG | MODEINITTRAN)) || ( (ckt->CKTmode & MODEINITFIX) && (!here->MOS1off) ) ) { #ifndef PREDICTOR if(ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) { /* predictor step */ xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1]; *(ckt->CKTstate0 + here->MOS1vbs) = *(ckt->CKTstate1 + here->MOS1vbs); vbs = (1+xfact)* (*(ckt->CKTstate1 + here->MOS1vbs)) -(xfact * (*(ckt->CKTstate2 + here->MOS1vbs))); *(ckt->CKTstate0 + here->MOS1vgs) = *(ckt->CKTstate1 + here->MOS1vgs); vgs = (1+xfact)* (*(ckt->CKTstate1 + here->MOS1vgs)) -(xfact * (*(ckt->CKTstate2 + here->MOS1vgs))); *(ckt->CKTstate0 + here->MOS1vds) = *(ckt->CKTstate1 + here->MOS1vds); vds = (1+xfact)* (*(ckt->CKTstate1 + here->MOS1vds)) -(xfact * (*(ckt->CKTstate2 + here->MOS1vds))); *(ckt->CKTstate0 + here->MOS1vbd) = *(ckt->CKTstate0 + here->MOS1vbs)- *(ckt->CKTstate0 + here->MOS1vds); } else { #endif /* PREDICTOR */ /* general iteration */ vbs = model->MOS1type * ( *(ckt->CKTrhsOld+here->MOS1bNode) - *(ckt->CKTrhsOld+here->MOS1sNodePrime)); vgs = model->MOS1type * ( *(ckt->CKTrhsOld+here->MOS1gNode) - *(ckt->CKTrhsOld+here->MOS1sNodePrime)); vds = model->MOS1type * ( *(ckt->CKTrhsOld+here->MOS1dNodePrime) - *(ckt->CKTrhsOld+here->MOS1sNodePrime)); #ifndef PREDICTOR } #endif /* PREDICTOR */ /* now some common crunching for some more useful quantities */ vbd=vbs-vds; vgd=vgs-vds; vgdo = *(ckt->CKTstate0 + here->MOS1vgs) - *(ckt->CKTstate0 + here->MOS1vds); delvbs = vbs - *(ckt->CKTstate0 + here->MOS1vbs); delvbd = vbd - *(ckt->CKTstate0 + here->MOS1vbd); delvgs = vgs - *(ckt->CKTstate0 + here->MOS1vgs); delvds = vds - *(ckt->CKTstate0 + here->MOS1vds); delvgd = vgd-vgdo; /* these are needed for convergence testing */ if (here->MOS1mode >= 0) { cdhat= here->MOS1cd- here->MOS1gbd * delvbd + here->MOS1gmbs * delvbs + here->MOS1gm * delvgs + here->MOS1gds * delvds ; } else { cdhat= here->MOS1cd - ( here->MOS1gbd - here->MOS1gmbs) * delvbd - here->MOS1gm * delvgd + here->MOS1gds * delvds ; } cbhat= here->MOS1cbs + here->MOS1cbd + here->MOS1gbd * delvbd + here->MOS1gbs * delvbs ; /* */ #ifndef NOBYPASS /* now lets see if we can bypass (ugh) */ tempv = (MAX(fabs(cbhat), fabs(here->MOS1cbs + here->MOS1cbd)) + ckt->CKTabstol); if ((!(ckt->CKTmode & (MODEINITPRED|MODEINITTRAN|MODEINITSMSIG))) && (ckt->CKTbypass) && (fabs(cbhat-(here->MOS1cbs + here->MOS1cbd)) < ckt->CKTreltol * tempv) && (fabs(delvbs) < (ckt->CKTreltol * MAX(fabs(vbs), fabs( *(ckt->CKTstate0 + here->MOS1vbs))) + ckt->CKTvoltTol)) && (fabs(delvbd) < (ckt->CKTreltol * MAX(fabs(vbd), fabs(*(ckt->CKTstate0 + here->MOS1vbd))) + ckt->CKTvoltTol)) && (fabs(delvgs) < (ckt->CKTreltol * MAX(fabs(vgs), fabs(*(ckt->CKTstate0 + here->MOS1vgs)))+ ckt->CKTvoltTol)) && (fabs(delvds) < (ckt->CKTreltol * MAX(fabs(vds), fabs(*(ckt->CKTstate0 + here->MOS1vds))) + ckt->CKTvoltTol)) && (fabs(cdhat- here->MOS1cd) < (ckt->CKTreltol * MAX(fabs(cdhat), fabs(here->MOS1cd)) + 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->MOS1vbs); vbd = *(ckt->CKTstate0 + here->MOS1vbd); vgs = *(ckt->CKTstate0 + here->MOS1vgs); vds = *(ckt->CKTstate0 + here->MOS1vds); vgd = vgs - vds; vgb = vgs - vbs; cdrain = here->MOS1mode * (here->MOS1cd + here->MOS1cbd); if(ckt->CKTmode & (MODETRAN | MODETRANOP)) { capgs = ( *(ckt->CKTstate0+here->MOS1capgs)+ *(ckt->CKTstate1+here->MOS1capgs) + GateSourceOverlapCap ); capgd = ( *(ckt->CKTstate0+here->MOS1capgd)+ *(ckt->CKTstate1+here->MOS1capgd) + GateDrainOverlapCap ); capgb = ( *(ckt->CKTstate0+here->MOS1capgb)+ *(ckt->CKTstate1+here->MOS1capgb) + GateBulkOverlapCap ); if(ckt->CKTsenInfo){ here->MOS1cgs = capgs; here->MOS1cgd = capgd; here->MOS1cgb = capgb; } } goto bypass; } #endif /*NOBYPASS*/ /* */ /* ok - bypass is out, do it the hard way */ von = model->MOS1type * here->MOS1von; #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->MOS1vds) >=0) { vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->MOS1vgs) ,von); vds = vgs - vgd; vds = DEVlimvds(vds,*(ckt->CKTstate0 + here->MOS1vds)); vgd = vgs - vds; } else { vgd = DEVfetlim(vgd,vgdo,von); vds = vgs - vgd; if(!(ckt->CKTfixLimit)) { vds = -DEVlimvds(-vds,-(*(ckt->CKTstate0 + here->MOS1vds))); } vgs = vgd + vds; } if(vds >= 0) { vbs = DEVpnjlim(vbs,*(ckt->CKTstate0 + here->MOS1vbs), vt,here->MOS1sourceVcrit,&Check); vbd = vbs-vds; } else { vbd = DEVpnjlim(vbd,*(ckt->CKTstate0 + here->MOS1vbd), vt,here->MOS1drainVcrit,&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->MOS1off) { vds= model->MOS1type * here->MOS1icVDS; vgs= model->MOS1type * here->MOS1icVGS; vbs= model->MOS1type * here->MOS1icVBS; if((vds==0) && (vgs==0) && (vbs==0) && ((ckt->CKTmode & (MODETRAN|MODEDCOP|MODEDCTRANCURVE)) || (!(ckt->CKTmode & MODEUIC)))) { vbs = -1; vgs = model->MOS1type * here->MOS1tVto; 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) { here->MOS1gbs = ckt->CKTgmin; here->MOS1cbs = here->MOS1gbs*vbs-SourceSatCur; } else { evbs = exp(MIN(MAX_EXP_ARG,vbs/vt)); here->MOS1gbs = SourceSatCur*evbs/vt + ckt->CKTgmin; here->MOS1cbs = SourceSatCur*(evbs-1) + ckt->CKTgmin*vbs; } if(vbd <= -3*vt) { here->MOS1gbd = ckt->CKTgmin; here->MOS1cbd = here->MOS1gbd*vbd-DrainSatCur; } else { evbd = exp(MIN(MAX_EXP_ARG,vbd/vt)); here->MOS1gbd = DrainSatCur*evbd/vt + ckt->CKTgmin; here->MOS1cbd = DrainSatCur*(evbd-1) + ckt->CKTgmin*vbd; } /* now to determine whether the user was able to correctly * identify the source and drain of his device */ if(vds >= 0) { /* normal mode */ here->MOS1mode = 1; } else { /* inverse mode */ here->MOS1mode = -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 4 variables are local to this code block until * it is obvious that they can be made global */ double arg; double betap; double sarg; double vgst; if ((here->MOS1mode==1?vbs:vbd) <= 0 ) { sarg=sqrt(here->MOS1tPhi-(here->MOS1mode==1?vbs:vbd)); } else { sarg=sqrt(here->MOS1tPhi); sarg=sarg-(here->MOS1mode==1?vbs:vbd)/(sarg+sarg); sarg=MAX(0,sarg); } von=(here->MOS1tVbi*model->MOS1type)+model->MOS1gamma*sarg; vgst=(here->MOS1mode==1?vgs:vgd)-von; vdsat=MAX(vgst,0); if (sarg <= 0) { arg=0; } else { arg=model->MOS1gamma/(sarg+sarg); } if (vgst <= 0) { /* * cutoff region */ cdrain=0; here->MOS1gm=0; here->MOS1gds=0; here->MOS1gmbs=0; } else{ /* * saturation region */ betap=Beta*(1+model->MOS1lambda*(vds*here->MOS1mode)); if (vgst <= (vds*here->MOS1mode)){ cdrain=betap*vgst*vgst*.5; here->MOS1gm=betap*vgst; here->MOS1gds=model->MOS1lambda*Beta*vgst*vgst*.5; here->MOS1gmbs=here->MOS1gm*arg; } else { /* * linear region */ cdrain=betap*(vds*here->MOS1mode)* (vgst-.5*(vds*here->MOS1mode)); here->MOS1gm=betap*(vds*here->MOS1mode); here->MOS1gds=betap*(vgst-(vds*here->MOS1mode))+ model->MOS1lambda*Beta* (vds*here->MOS1mode)* (vgst-.5*(vds*here->MOS1mode)); here->MOS1gmbs=here->MOS1gm*arg; } } /* * finished */ } /* */ /* now deal with n vs p polarity */ here->MOS1von = model->MOS1type * von; here->MOS1vdsat = model->MOS1type * vdsat; /* line 490 */ /* * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE */ here->MOS1cd=here->MOS1mode * cdrain - here->MOS1cbd; 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->MOS1vbs)))+ ckt->CKTvoltTol)|| senflag) #endif /*CAPBYPASS*/ { /* can't bypass the diode capacitance calculations */ #ifdef CAPZEROBYPASS if(here->MOS1Cbs != 0 || here->MOS1Cbssw != 0 ) { #endif /*CAPZEROBYPASS*/ if (vbs < here->MOS1tDepCap){ arg=1-vbs/here->MOS1tBulkPot; /* * 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->MOS1bulkJctBotGradingCoeff == model->MOS1bulkJctSideGradingCoeff) { if(model->MOS1bulkJctBotGradingCoeff == .5) { sarg = sargsw = 1/sqrt(arg); } else { sarg = sargsw = exp(-model->MOS1bulkJctBotGradingCoeff* log(arg)); } } else { if(model->MOS1bulkJctBotGradingCoeff == .5) { sarg = 1/sqrt(arg); } else { #endif /*NOSQRT*/ sarg = exp(-model->MOS1bulkJctBotGradingCoeff* log(arg)); #ifndef NOSQRT } if(model->MOS1bulkJctSideGradingCoeff == .5) { sargsw = 1/sqrt(arg); } else { #endif /*NOSQRT*/ sargsw =exp(-model->MOS1bulkJctSideGradingCoeff* log(arg)); #ifndef NOSQRT } } #endif /*NOSQRT*/ *(ckt->CKTstate0 + here->MOS1qbs) = here->MOS1tBulkPot*(here->MOS1Cbs* (1-arg*sarg)/(1-model->MOS1bulkJctBotGradingCoeff) +here->MOS1Cbssw* (1-arg*sargsw)/ (1-model->MOS1bulkJctSideGradingCoeff)); here->MOS1capbs=here->MOS1Cbs*sarg+ here->MOS1Cbssw*sargsw; } else { *(ckt->CKTstate0 + here->MOS1qbs) = here->MOS1f4s + vbs*(here->MOS1f2s+vbs*(here->MOS1f3s/2)); here->MOS1capbs=here->MOS1f2s+here->MOS1f3s*vbs; } #ifdef CAPZEROBYPASS } else { *(ckt->CKTstate0 + here->MOS1qbs) = 0; here->MOS1capbs=0; } #endif /*CAPZEROBYPASS*/ } #ifdef CAPBYPASS if(((ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) || fabs(delvbd) >= ckt->CKTreltol * MAX(fabs(vbd), fabs(*(ckt->CKTstate0+here->MOS1vbd)))+ ckt->CKTvoltTol)|| senflag) #endif /*CAPBYPASS*/ /* can't bypass the diode capacitance calculations */ { #ifdef CAPZEROBYPASS if(here->MOS1Cbd != 0 || here->MOS1Cbdsw != 0 ) { #endif /*CAPZEROBYPASS*/ if (vbd < here->MOS1tDepCap) { arg=1-vbd/here->MOS1tBulkPot; /* * 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->MOS1bulkJctBotGradingCoeff == .5 && model->MOS1bulkJctSideGradingCoeff == .5) { sarg = sargsw = 1/sqrt(arg); } else { if(model->MOS1bulkJctBotGradingCoeff == .5) { sarg = 1/sqrt(arg); } else { #endif /*NOSQRT*/ sarg = exp(-model->MOS1bulkJctBotGradingCoeff* log(arg)); #ifndef NOSQRT } if(model->MOS1bulkJctSideGradingCoeff == .5) { sargsw = 1/sqrt(arg); } else { #endif /*NOSQRT*/ sargsw =exp(-model->MOS1bulkJctSideGradingCoeff* log(arg)); #ifndef NOSQRT } } #endif /*NOSQRT*/ *(ckt->CKTstate0 + here->MOS1qbd) = here->MOS1tBulkPot*(here->MOS1Cbd* (1-arg*sarg) /(1-model->MOS1bulkJctBotGradingCoeff) +here->MOS1Cbdsw* (1-arg*sargsw) /(1-model->MOS1bulkJctSideGradingCoeff)); here->MOS1capbd=here->MOS1Cbd*sarg+ here->MOS1Cbdsw*sargsw; } else { *(ckt->CKTstate0 + here->MOS1qbd) = here->MOS1f4d + vbd * (here->MOS1f2d + vbd * here->MOS1f3d/2); here->MOS1capbd=here->MOS1f2d + vbd * here->MOS1f3d; } #ifdef CAPZEROBYPASS } else { *(ckt->CKTstate0 + here->MOS1qbd) = 0; here->MOS1capbd = 0; } #endif /*CAPZEROBYPASS*/ } /* */ if(SenCond && (ckt->CKTsenInfo->SENmode==TRANSEN)) goto next2; if ( (ckt->CKTmode & MODETRAN) || ( (ckt->CKTmode&MODEINITTRAN) && !(ckt->CKTmode&MODEUIC)) ) { /* (above only excludes tranop, since we're only at this * point if tran or tranop ) */ /* * calculate equivalent conductances and currents for * depletion capacitors */ /* integrate the capacitors and save results */ error = NIintegrate(ckt,&geq,&ceq,here->MOS1capbd, here->MOS1qbd); if(error) return(error); here->MOS1gbd += geq; here->MOS1cbd += *(ckt->CKTstate0 + here->MOS1cqbd); here->MOS1cd -= *(ckt->CKTstate0 + here->MOS1cqbd); error = NIintegrate(ckt,&geq,&ceq,here->MOS1capbs, here->MOS1qbs); if(error) return(error); here->MOS1gbs += geq; here->MOS1cbs += *(ckt->CKTstate0 + here->MOS1cqbs); } } /* */ if(SenCond) goto next2; /* * check convergence */ if ( (here->MOS1off == 0) || (!(ckt->CKTmode & (MODEINITFIX|MODEINITSMSIG))) ){ if (Check == 1) { ckt->CKTnoncon++; ckt->CKTtroubleElt = (GENinstance *) here; } } /* */ /* save things away for next time */ next2: *(ckt->CKTstate0 + here->MOS1vbs) = vbs; *(ckt->CKTstate0 + here->MOS1vbd) = vbd; *(ckt->CKTstate0 + here->MOS1vgs) = vgs; *(ckt->CKTstate0 + here->MOS1vds) = vds; /* */ /* * meyer's capacitor model */ if ( ckt->CKTmode & (MODETRAN | MODETRANOP | MODEINITSMSIG) ) { /* * calculate meyer's capacitors */ /* * new cmeyer - 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 */ if (here->MOS1mode > 0){ DEVqmeyer (vgs,vgd,vgb,von,vdsat, (ckt->CKTstate0 + here->MOS1capgs), (ckt->CKTstate0 + here->MOS1capgd), (ckt->CKTstate0 + here->MOS1capgb), here->MOS1tPhi,OxideCap); } else { DEVqmeyer (vgd,vgs,vgb,von,vdsat, (ckt->CKTstate0 + here->MOS1capgd), (ckt->CKTstate0 + here->MOS1capgs), (ckt->CKTstate0 + here->MOS1capgb), here->MOS1tPhi,OxideCap); } vgs1 = *(ckt->CKTstate1 + here->MOS1vgs); vgd1 = vgs1 - *(ckt->CKTstate1 + here->MOS1vds); vgb1 = vgs1 - *(ckt->CKTstate1 + here->MOS1vbs); if(ckt->CKTmode & (MODETRANOP|MODEINITSMSIG)) { capgs = 2 * *(ckt->CKTstate0+here->MOS1capgs)+ GateSourceOverlapCap ; capgd = 2 * *(ckt->CKTstate0+here->MOS1capgd)+ GateDrainOverlapCap ; capgb = 2 * *(ckt->CKTstate0+here->MOS1capgb)+ GateBulkOverlapCap ; } else { capgs = ( *(ckt->CKTstate0+here->MOS1capgs)+ *(ckt->CKTstate1+here->MOS1capgs) + GateSourceOverlapCap ); capgd = ( *(ckt->CKTstate0+here->MOS1capgd)+ *(ckt->CKTstate1+here->MOS1capgd) + GateDrainOverlapCap ); capgb = ( *(ckt->CKTstate0+here->MOS1capgb)+ *(ckt->CKTstate1+here->MOS1capgb) + GateBulkOverlapCap ); } if(ckt->CKTsenInfo){ here->MOS1cgs = capgs; here->MOS1cgd = capgd; here->MOS1cgb = capgb; } /* */ /* * store small-signal parameters (for meyer's model) * all parameters already stored, so done... */ if(SenCond){ if((ckt->CKTsenInfo->SENmode == DCSEN)|| (ckt->CKTsenInfo->SENmode == ACSEN)){ continue; } } #ifndef PREDICTOR if (ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) { *(ckt->CKTstate0 + here->MOS1qgs) = (1+xfact) * *(ckt->CKTstate1 + here->MOS1qgs) - xfact * *(ckt->CKTstate2 + here->MOS1qgs); *(ckt->CKTstate0 + here->MOS1qgd) = (1+xfact) * *(ckt->CKTstate1 + here->MOS1qgd) - xfact * *(ckt->CKTstate2 + here->MOS1qgd); *(ckt->CKTstate0 + here->MOS1qgb) = (1+xfact) * *(ckt->CKTstate1 + here->MOS1qgb) - xfact * *(ckt->CKTstate2 + here->MOS1qgb); } else { #endif /*PREDICTOR*/ if(ckt->CKTmode & MODETRAN) { *(ckt->CKTstate0 + here->MOS1qgs) = (vgs-vgs1)*capgs + *(ckt->CKTstate1 + here->MOS1qgs) ; *(ckt->CKTstate0 + here->MOS1qgd) = (vgd-vgd1)*capgd + *(ckt->CKTstate1 + here->MOS1qgd) ; *(ckt->CKTstate0 + here->MOS1qgb) = (vgb-vgb1)*capgb + *(ckt->CKTstate1 + here->MOS1qgb) ; } else { /* TRANOP only */ *(ckt->CKTstate0 + here->MOS1qgs) = vgs*capgs; *(ckt->CKTstate0 + here->MOS1qgd) = vgd*capgd; *(ckt->CKTstate0 + here->MOS1qgb) = vgb*capgb; } #ifndef PREDICTOR } #endif /*PREDICTOR*/ } bypass: if(SenCond) continue; if ( (ckt->CKTmode & (MODEINITTRAN)) || (! (ckt->CKTmode & (MODETRAN)) ) ) { /* * initialize to zero charge conductances * and current */ gcgs=0; ceqgs=0; gcgd=0; ceqgd=0; gcgb=0; ceqgb=0; } else { if(capgs == 0) *(ckt->CKTstate0 + here->MOS1cqgs) =0; if(capgd == 0) *(ckt->CKTstate0 + here->MOS1cqgd) =0; if(capgb == 0) *(ckt->CKTstate0 + here->MOS1cqgb) =0; /* * calculate equivalent conductances and currents for * meyer"s capacitors */ error = NIintegrate(ckt,&gcgs,&ceqgs,capgs,here->MOS1qgs); if(error) return(error); error = NIintegrate(ckt,&gcgd,&ceqgd,capgd,here->MOS1qgd); if(error) return(error); error = NIintegrate(ckt,&gcgb,&ceqgb,capgb,here->MOS1qgb); if(error) return(error); ceqgs=ceqgs-gcgs*vgs+ckt->CKTag[0]* *(ckt->CKTstate0 + here->MOS1qgs); ceqgd=ceqgd-gcgd*vgd+ckt->CKTag[0]* *(ckt->CKTstate0 + here->MOS1qgd); ceqgb=ceqgb-gcgb*vgb+ckt->CKTag[0]* *(ckt->CKTstate0 + here->MOS1qgb); } /* * store charge storage info for meyer's cap in lx table */ /* * load current vector */ ceqbs = model->MOS1type * (here->MOS1cbs-(here->MOS1gbs)*vbs); ceqbd = model->MOS1type * (here->MOS1cbd-(here->MOS1gbd)*vbd); if (here->MOS1mode >= 0) { xnrm=1; xrev=0; cdreq=model->MOS1type*(cdrain-here->MOS1gds*vds- here->MOS1gm*vgs-here->MOS1gmbs*vbs); } else { xnrm=0; xrev=1; cdreq = -(model->MOS1type)*(cdrain-here->MOS1gds*(-vds)- here->MOS1gm*vgd-here->MOS1gmbs*vbd); } *(ckt->CKTrhs + here->MOS1gNode) -= (model->MOS1type * (ceqgs + ceqgb + ceqgd)); *(ckt->CKTrhs + here->MOS1bNode) -= (ceqbs + ceqbd - model->MOS1type * ceqgb); *(ckt->CKTrhs + here->MOS1dNodePrime) += (ceqbd - cdreq + model->MOS1type * ceqgd); *(ckt->CKTrhs + here->MOS1sNodePrime) += cdreq + ceqbs + model->MOS1type * ceqgs; /* * load y matrix */ *(here->MOS1DdPtr) += (here->MOS1drainConductance); *(here->MOS1GgPtr) += ((gcgd+gcgs+gcgb)); *(here->MOS1SsPtr) += (here->MOS1sourceConductance); *(here->MOS1BbPtr) += (here->MOS1gbd+here->MOS1gbs+gcgb); *(here->MOS1DPdpPtr) += (here->MOS1drainConductance+here->MOS1gds+ here->MOS1gbd+xrev*(here->MOS1gm+here->MOS1gmbs)+gcgd); *(here->MOS1SPspPtr) += (here->MOS1sourceConductance+here->MOS1gds+ here->MOS1gbs+xnrm*(here->MOS1gm+here->MOS1gmbs)+gcgs); *(here->MOS1DdpPtr) += (-here->MOS1drainConductance); *(here->MOS1GbPtr) -= gcgb; *(here->MOS1GdpPtr) -= gcgd; *(here->MOS1GspPtr) -= gcgs; *(here->MOS1SspPtr) += (-here->MOS1sourceConductance); *(here->MOS1BgPtr) -= gcgb; *(here->MOS1BdpPtr) -= here->MOS1gbd; *(here->MOS1BspPtr) -= here->MOS1gbs; *(here->MOS1DPdPtr) += (-here->MOS1drainConductance); *(here->MOS1DPgPtr) += ((xnrm-xrev)*here->MOS1gm-gcgd); *(here->MOS1DPbPtr) += (-here->MOS1gbd+(xnrm-xrev)*here->MOS1gmbs); *(here->MOS1DPspPtr) += (-here->MOS1gds-xnrm* (here->MOS1gm+here->MOS1gmbs)); *(here->MOS1SPgPtr) += (-(xnrm-xrev)*here->MOS1gm-gcgs); *(here->MOS1SPsPtr) += (-here->MOS1sourceConductance); *(here->MOS1SPbPtr) += (-here->MOS1gbs-(xnrm-xrev)*here->MOS1gmbs); *(here->MOS1SPdpPtr) += (-here->MOS1gds-xrev* (here->MOS1gm+here->MOS1gmbs)); } } return(OK); }
int MESAload(GENmodel *inModel, CKTcircuit *ckt) { MESAmodel *model = (MESAmodel*)inModel; MESAinstance *here; double capgd; double capgs; double cd; double cdhat = 0.0; double cdrain; double cdreq; double ceq; double ceqgd; double ceqgs; double cg; double cgd; double cgs; double cghat = 0.0; double arg; double earg; double delvds; double delvgd; double delvgs; double delvgspp=0; double delvgdpp=0; double evgd; double evgs; double gds; double geq; double ggd; double ggs; double gm; double ggspp=0; double cgspp=0; double ggdpp=0; double cgdpp=0; double vcrits; double vcritd; double vds=0; double vgd=0; double vgs=0; double vgspp=0; double vgdpp=0; double vgs1=0; double vgd1=0; double xfact; double temp; double vted; double vtes; double vtd; double vts; double von; double ccorr; int inverse=FALSE; int icheck; int ichk1; int error; double m; /* loop through all the models */ for( ; model != NULL; model = model->MESAnextModel ) { /* loop through all the instances of the model */ for (here = model->MESAinstances; here != NULL ; here=here->MESAnextInstance) { if (here->MESAowner != ARCHme) continue; /* * dc model parameters */ vcrits = here->MESAvcrits; vcritd = here->MESAvcritd; vtd = CONSTKoverQ * here->MESAtd; vts = CONSTKoverQ * here->MESAts; vted = model->MESAn*vtd; vtes = model->MESAn*vts; /* * initialization */ icheck = 1; if( ckt->CKTmode & MODEINITSMSIG) { vgs = *(ckt->CKTstate0 + here->MESAvgs); vgd = *(ckt->CKTstate0 + here->MESAvgd); vgspp = *(ckt->CKTstate0 + here->MESAvgspp); vgdpp = *(ckt->CKTstate0 + here->MESAvgdpp); } else if (ckt->CKTmode & MODEINITTRAN) { vgs = *(ckt->CKTstate1 + here->MESAvgs); vgd = *(ckt->CKTstate1 + here->MESAvgd); vgspp = *(ckt->CKTstate1 + here->MESAvgspp); vgdpp = *(ckt->CKTstate1 + here->MESAvgdpp); } else if ( (ckt->CKTmode & MODEINITJCT) && (ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC) ) { vds = here->MESAicVDS; vgs = here->MESAicVGS; vgd = vgs-vds; vgspp = vgs; vgdpp = vgd; } else if ( (ckt->CKTmode & MODEINITJCT) && (here->MESAoff == 0) ) { vgs = -1; vgd = -1; vgspp = 0; vgdpp = 0; } else if( (ckt->CKTmode & MODEINITJCT) || ((ckt->CKTmode & MODEINITFIX) && (here->MESAoff))) { vgs = 0; vgd = 0; vgspp = 0; vgdpp = 0; } else { #ifndef PREDICTOR if(ckt->CKTmode & MODEINITPRED) { xfact = ckt->CKTdelta/ckt->CKTdeltaOld[2]; *(ckt->CKTstate0 + here->MESAvgs) = *(ckt->CKTstate1 + here->MESAvgs); vgs = (1+xfact) * *(ckt->CKTstate1 + here->MESAvgs) - xfact * *(ckt->CKTstate2 + here->MESAvgs); *(ckt->CKTstate0 + here->MESAvgspp) = *(ckt->CKTstate1 + here->MESAvgspp); vgspp = (1+xfact) * *(ckt->CKTstate1 + here->MESAvgspp) - xfact * *(ckt->CKTstate2 + here->MESAvgspp); *(ckt->CKTstate0 + here->MESAvgd) = *(ckt->CKTstate1 + here->MESAvgd); vgd = (1+xfact)* *(ckt->CKTstate1 + here->MESAvgd) - xfact * *(ckt->CKTstate2 + here->MESAvgd); *(ckt->CKTstate0 + here->MESAvgdpp) = *(ckt->CKTstate1 + here->MESAvgdpp); vgdpp = (1+xfact) * *(ckt->CKTstate1 + here->MESAvgdpp) - xfact * *(ckt->CKTstate2 + here->MESAvgdpp); *(ckt->CKTstate0 + here->MESAcg) = *(ckt->CKTstate1 + here->MESAcg); *(ckt->CKTstate0 + here->MESAcd) = *(ckt->CKTstate1 + here->MESAcd); *(ckt->CKTstate0 + here->MESAcgd) = *(ckt->CKTstate1 + here->MESAcgd); *(ckt->CKTstate0 + here->MESAcgs) = *(ckt->CKTstate1 + here->MESAcgs); *(ckt->CKTstate0 + here->MESAgm) = *(ckt->CKTstate1 + here->MESAgm); *(ckt->CKTstate0 + here->MESAgds) = *(ckt->CKTstate1 + here->MESAgds); *(ckt->CKTstate0 + here->MESAggs) = *(ckt->CKTstate1 + here->MESAggs); *(ckt->CKTstate0 + here->MESAggd) = *(ckt->CKTstate1 + here->MESAggd); *(ckt->CKTstate0 + here->MESAggspp) = *(ckt->CKTstate1 + here->MESAggspp); *(ckt->CKTstate0 + here->MESAcgspp) = *(ckt->CKTstate1 + here->MESAcgspp); *(ckt->CKTstate0 + here->MESAggdpp) = *(ckt->CKTstate1 + here->MESAggdpp); *(ckt->CKTstate0 + here->MESAcgdpp) = *(ckt->CKTstate1 + here->MESAcgdpp); } else { #endif /* PREDICTOR */ /* * compute new nonlinear branch voltages */ vgs = (*(ckt->CKTrhsOld+ here->MESAgatePrimeNode)- *(ckt->CKTrhsOld+here->MESAsourcePrimeNode)); vgd = (*(ckt->CKTrhsOld+here->MESAgatePrimeNode)- *(ckt->CKTrhsOld+here->MESAdrainPrimeNode)); vgspp = (*(ckt->CKTrhsOld+here->MESAgatePrimeNode)- *(ckt->CKTrhsOld+here->MESAsourcePrmPrmNode)); vgdpp = (*(ckt->CKTrhsOld+here->MESAgatePrimeNode)- *(ckt->CKTrhsOld+here->MESAdrainPrmPrmNode)); #ifndef PREDICTOR } #endif /* PREDICTOR */ delvgs=vgs - *(ckt->CKTstate0 + here->MESAvgs); delvgd=vgd - *(ckt->CKTstate0 + here->MESAvgd); delvds=delvgs - delvgd; delvgspp = vgspp - *(ckt->CKTstate0 + here->MESAvgspp); delvgdpp = vgdpp - *(ckt->CKTstate0 + here->MESAvgdpp); cghat= *(ckt->CKTstate0 + here->MESAcg) + *(ckt->CKTstate0 + here->MESAggd)*delvgd + *(ckt->CKTstate0 + here->MESAggs)*delvgs + *(ckt->CKTstate0 + here->MESAggspp)*delvgspp+ *(ckt->CKTstate0 + here->MESAggdpp)*delvgdpp; cdhat= *(ckt->CKTstate0 + here->MESAcd) + *(ckt->CKTstate0 + here->MESAgm)*delvgs + *(ckt->CKTstate0 + here->MESAgds)*delvds - *(ckt->CKTstate0 + here->MESAggd)*delvgd; /* * bypass if solution has not changed */ if((ckt->CKTbypass) && (!(ckt->CKTmode & MODEINITPRED)) && (fabs(delvgs) < ckt->CKTreltol*MAX(fabs(vgs), fabs(*(ckt->CKTstate0 + here->MESAvgs)))+ ckt->CKTvoltTol) ) if((fabs(delvgd) < ckt->CKTreltol*MAX(fabs(vgd), fabs(*(ckt->CKTstate0 + here->MESAvgd)))+ ckt->CKTvoltTol)) if((fabs(delvgspp) < ckt->CKTreltol*MAX(fabs(vgspp), fabs(*(ckt->CKTstate0 + here->MESAvgspp)))+ ckt->CKTvoltTol)) if((fabs(delvgdpp) < ckt->CKTreltol*MAX(fabs(vgdpp), fabs(*(ckt->CKTstate0 + here->MESAvgdpp)))+ ckt->CKTvoltTol)) if((fabs(cghat-*(ckt->CKTstate0 + here->MESAcg)) < ckt->CKTreltol*MAX(fabs(cghat), fabs(*(ckt->CKTstate0 + here->MESAcg)))+ ckt->CKTabstol)) if((fabs(cdhat-*(ckt->CKTstate0 + here->MESAcd)) < ckt->CKTreltol*MAX(fabs(cdhat), fabs(*(ckt->CKTstate0 + here->MESAcd)))+ ckt->CKTabstol)) { /* we can do a bypass */ vgs= *(ckt->CKTstate0 + here->MESAvgs); vgd= *(ckt->CKTstate0 + here->MESAvgd); vds= vgs-vgd; vgspp = *(ckt->CKTstate0 + here->MESAvgspp); vgdpp = *(ckt->CKTstate0 + here->MESAvgdpp); cg= *(ckt->CKTstate0 + here->MESAcg); cd= *(ckt->CKTstate0 + here->MESAcd); cgs= *(ckt->CKTstate0 + here->MESAcgs); cgd= *(ckt->CKTstate0 + here->MESAcgd); gm= *(ckt->CKTstate0 + here->MESAgm); gds= *(ckt->CKTstate0 + here->MESAgds); ggs= *(ckt->CKTstate0 + here->MESAggs); ggd= *(ckt->CKTstate0 + here->MESAggd); ggspp = *(ckt->CKTstate0 + here->MESAggspp); cgspp = *(ckt->CKTstate0 + here->MESAcgspp); ggdpp = *(ckt->CKTstate0 + here->MESAggdpp); cgdpp = *(ckt->CKTstate0 + here->MESAcgdpp); goto load; } /* * limit nonlinear branch voltages */ ichk1=1; vgs = DEVpnjlim(vgs,*(ckt->CKTstate0 + here->MESAvgs),vtes, vcrits, &icheck); vgd = DEVpnjlim(vgd,*(ckt->CKTstate0 + here->MESAvgd),vted, vcritd,&ichk1); if (ichk1 == 1) { icheck=1; } vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->MESAvgs), here->MESAtVto); vgd = DEVfetlim(vgd,*(ckt->CKTstate0 + here->MESAvgd), here->MESAtVto); if(here->MESAsourcePrmPrmNode == here->MESAsourcePrimeNode) vgspp = vgs; if(here->MESAdrainPrmPrmNode == here->MESAdrainPrimeNode) vgdpp = vgd; } /* * determine dc current and derivatives */ vds = vgs-vgd; arg = -vgs*model->MESAdel/vts; earg = exp(arg); evgs = exp(vgs/vtes); ggs = here->MESAcsatfs*evgs/vtes+here->MESAggrwl*earg*(1-arg)+ckt->CKTgmin; cgs = here->MESAcsatfs*(evgs-1)+here->MESAggrwl*vgs*earg+ ckt->CKTgmin*vgs; cg = cgs; arg = -vgd*model->MESAdel/vtd; earg = exp(arg); evgd = exp(vgd/vted); ggd = here->MESAcsatfd*evgd/vted+here->MESAggrwl*earg*(1-arg)+ckt->CKTgmin; cgd = here->MESAcsatfd*(evgd-1)+here->MESAggrwl*vgd*earg+ ckt->CKTgmin*vgd; cg = cg+cgd; if(vds < 0) { vds = -vds; inverse = TRUE; } von = here->MESAtVto+model->MESAks*(*(ckt->CKTrhsOld+here->MESAsourcePrimeNode)-model->MESAvsg); if(model->MESAlevel == 2) mesa1(model,here,inverse?vgd:vgs,vds,von,&cdrain,&gm,&gds,&capgs,&capgd); else if(model->MESAlevel == 3) mesa2(model,here,inverse?vgd:vgs,vds,von,&cdrain,&gm,&gds,&capgs,&capgd); else if(model->MESAlevel == 4) mesa3(model,here,inverse?vgd:vgs,vds,von,&cdrain,&gm,&gds,&capgs,&capgd); if(inverse) { cdrain = -cdrain; vds = -vds; temp = capgs; capgs = capgd; capgd = temp; } /* * compute equivalent drain current source */ cd = cdrain - cgd; if ( (ckt->CKTmode & (MODETRAN|MODEINITSMSIG)) || ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) ){ /* * charge storage elements */ vgs1 = *(ckt->CKTstate1 + here->MESAvgspp); vgd1 = *(ckt->CKTstate1 + here->MESAvgdpp); if(ckt->CKTmode & MODEINITTRAN) { *(ckt->CKTstate1 + here->MESAqgs) = capgs*vgspp; *(ckt->CKTstate1 + here->MESAqgd) = capgd*vgdpp; } *(ckt->CKTstate0+here->MESAqgs) = *(ckt->CKTstate1 + here->MESAqgs) + capgs*(vgspp-vgs1); *(ckt->CKTstate0+here->MESAqgd) = *(ckt->CKTstate1 + here->MESAqgd) + capgd*(vgdpp-vgd1); /* * store small-signal parameters */ if( (!(ckt->CKTmode & MODETRANOP)) || (!(ckt->CKTmode & MODEUIC)) ) { if(ckt->CKTmode & MODEINITSMSIG) { *(ckt->CKTstate0 + here->MESAqgs) = capgs; *(ckt->CKTstate0 + here->MESAqgd) = capgd; continue; /*go to 1000*/ } /* * transient analysis */ if(ckt->CKTmode & MODEINITTRAN) { *(ckt->CKTstate1 + here->MESAqgs) = *(ckt->CKTstate0 + here->MESAqgs); *(ckt->CKTstate1 + here->MESAqgd) = *(ckt->CKTstate0 + here->MESAqgd); } error = NIintegrate(ckt,&geq,&ceq,capgs,here->MESAqgs); if(error) return(error); ggspp = geq; cgspp = *(ckt->CKTstate0 + here->MESAcqgs); cg = cg + cgspp; error = NIintegrate(ckt,&geq,&ceq,capgd,here->MESAqgd); if(error) return(error); ggdpp = geq; cgdpp = *(ckt->CKTstate0 + here->MESAcqgd); cg = cg + cgdpp; cd = cd - cgdpp; if (ckt->CKTmode & MODEINITTRAN) { *(ckt->CKTstate1 + here->MESAcqgs) = *(ckt->CKTstate0 + here->MESAcqgs); *(ckt->CKTstate1 + here->MESAcqgd) = *(ckt->CKTstate0 + here->MESAcqgd); } } } /* * 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->CKTstate0 + here->MESAvgs) = vgs; *(ckt->CKTstate0 + here->MESAvgspp) = vgspp; *(ckt->CKTstate0 + here->MESAvgd) = vgd; *(ckt->CKTstate0 + here->MESAvgdpp) = vgdpp; *(ckt->CKTstate0 + here->MESAcg) = cg; *(ckt->CKTstate0 + here->MESAcd) = cd; *(ckt->CKTstate0 + here->MESAcgd) = cgd; *(ckt->CKTstate0 + here->MESAcgs) = cgs; *(ckt->CKTstate0 + here->MESAgm) = gm; *(ckt->CKTstate0 + here->MESAgds) = gds; *(ckt->CKTstate0 + here->MESAggs) = ggs; *(ckt->CKTstate0 + here->MESAggd) = ggd; *(ckt->CKTstate0 + here->MESAggspp) = ggspp; *(ckt->CKTstate0 + here->MESAcgspp) = cgspp; *(ckt->CKTstate0 + here->MESAggdpp) = ggdpp; *(ckt->CKTstate0 + here->MESAcgdpp) = cgdpp; /* * load current vector */ load: m = here->MESAm; ccorr = model->MESAag*(cgs-cgd); ceqgd = cgd + cgdpp - ggd*vgd - ggdpp*vgdpp; ceqgs = cgs + cgspp - ggs*vgs - ggspp*vgspp; cdreq=((cd+cgd+cgdpp)-gds*vds-gm*vgs); *(ckt->CKTrhs + here->MESAgatePrimeNode) += m * (-ceqgs-ceqgd); ceqgd = (cgd-ggd*vgd); *(ckt->CKTrhs + here->MESAdrainPrimeNode) += m * (-cdreq+ceqgd+ccorr); ceqgd = (cgdpp-ggdpp*vgdpp); *(ckt->CKTrhs + here->MESAdrainPrmPrmNode) += ceqgd; ceqgs = (cgs-ggs*vgs); *(ckt->CKTrhs + here->MESAsourcePrimeNode) += m * (cdreq+ceqgs-ccorr); ceqgs = (cgspp-ggspp*vgspp); *(ckt->CKTrhs + here->MESAsourcePrmPrmNode) += ceqgs; /* * load y matrix */ *(here->MESAdrainDrainPtr) += m * (here->MESAdrainConduct); *(here->MESAsourceSourcePtr) += m * (here->MESAsourceConduct); *(here->MESAgateGatePtr) += m * (here->MESAgateConduct); *(here->MESAsourcePrmPrmSourcePrmPrmPtr) += m * (here->MESAtGi+ggspp); *(here->MESAdrainPrmPrmDrainPrmPrmPtr) += m * (here->MESAtGf+ggdpp); *(here->MESAgatePrimeGatePrimePtr) += m * (ggd+ggs+here->MESAgateConduct+ggspp+ggdpp); *(here->MESAdrainPrimeDrainPrimePtr) += m * (gds+ggd+here->MESAdrainConduct+here->MESAtGf); *(here->MESAsourcePrimeSourcePrimePtr) += m * (gds+gm+ggs+here->MESAsourceConduct+here->MESAtGi); *(here->MESAdrainDrainPrimePtr) -= m * (here->MESAdrainConduct); *(here->MESAdrainPrimeDrainPtr) -= m * (here->MESAdrainConduct); *(here->MESAsourceSourcePrimePtr) -= m * (here->MESAsourceConduct); *(here->MESAsourcePrimeSourcePtr) -= m * (here->MESAsourceConduct); *(here->MESAgateGatePrimePtr) -= m * (here->MESAgateConduct); *(here->MESAgatePrimeGatePtr) -= m * (here->MESAgateConduct); *(here->MESAgatePrimeDrainPrimePtr) -= m * (ggd); *(here->MESAgatePrimeSourcePrimePtr) -= m * (ggs); *(here->MESAdrainPrimeGatePrimePtr) += m * (gm-ggd); *(here->MESAdrainPrimeSourcePrimePtr) += m * (-gds-gm); *(here->MESAsourcePrimeGatePrimePtr) += m * (-ggs-gm); *(here->MESAsourcePrimeDrainPrimePtr) -= m * (gds); *(here->MESAsourcePrimeSourcePrmPrmPtr) -= m * (here->MESAtGi); *(here->MESAsourcePrmPrmSourcePrimePtr) -= m * (here->MESAtGi); *(here->MESAgatePrimeSourcePrmPrmPtr) -= m * (ggspp); *(here->MESAsourcePrmPrmGatePrimePtr) -= m * (ggspp); *(here->MESAdrainPrimeDrainPrmPrmPtr) -= m * (here->MESAtGf); *(here->MESAdrainPrmPrmDrainPrimePtr) -= m * (here->MESAtGf); *(here->MESAgatePrimeDrainPrmPrmPtr) -= m * (ggdpp); *(here->MESAdrainPrmPrmGatePrimePtr) -= m * (ggdpp); } } return(OK); }