diff --git a/src/spicelib/devices/vdmos/vdmos.c b/src/spicelib/devices/vdmos/vdmos.c index e124e1135..a7b9b23c0 100644 --- a/src/spicelib/devices/vdmos/vdmos.c +++ b/src/spicelib/devices/vdmos/vdmos.c @@ -37,6 +37,7 @@ IFparm VDMOSpTable[] = { /* parameters */ OP( "cgs", VDMOS_CGS, IF_REAL, "Gate-Source capacitance"), OP( "cgd", VDMOS_CGD, IF_REAL, "Gate-Drain capacitance"), */ + OP( "cds", VDMOS_CDS, IF_REAL, "Drain-Source capacitance"), OPU( "dnode", VDMOS_DNODE, IF_INTEGER, "Number of the drain node "), OPU( "gnode", VDMOS_GNODE, IF_INTEGER, "Number of the gate node "), @@ -105,6 +106,7 @@ IFparm VDMOSmPTable[] = { /* model parameters */ /* body diode capacitance (e.g. source-drain capacitance) */ IOP("fc", VDMOS_MOD_FC, IF_REAL, "Body diode coefficient for forward-bias depletion capacitance formula"), + IOPA("cjo", VDMOS_MOD_CJ, IF_REAL, "Zero-bias body diode junction capacitance"), IOP("mj", VDMOS_MOD_MJ, IF_REAL, "Body diode grading coefficient"), /* gate-source and gate-drain capacitances */ diff --git a/src/spicelib/devices/vdmos/vdmosask.c b/src/spicelib/devices/vdmos/vdmosask.c index d4eabcfbc..4f37b3d9b 100644 --- a/src/spicelib/devices/vdmos/vdmosask.c +++ b/src/spicelib/devices/vdmos/vdmosask.c @@ -35,6 +35,9 @@ VDMOSask(CKTcircuit *ckt, GENinstance *inst, int which, IFvalue *value, case VDMOS_CGD: value->rValue = 2* *(ckt->CKTstate0 + here->VDMOScapgd); return(OK); + case VDMOS_CDS: + value->rValue = here->VDIOcap; + return(OK); case VDMOS_M: value->rValue = here->VDMOSm; return(OK); diff --git a/src/spicelib/devices/vdmos/vdmosdefs.h b/src/spicelib/devices/vdmos/vdmosdefs.h index 5492fd327..fc9e6348e 100644 --- a/src/spicelib/devices/vdmos/vdmosdefs.h +++ b/src/spicelib/devices/vdmos/vdmosdefs.h @@ -45,6 +45,7 @@ typedef struct sVDMOSinstance { int VDMOSdNodePrime; /* number of the internal drain node of the mosfet */ int VDMOSsNodePrime; /* number of the internal source node of the mosfet */ int VDMOSgNodePrime; /* number of the internal gate node of the mosfet */ + int VDIOposPrimeNode; /* number of the internal node of the bulk diode */ double VDMOSm; /* parallel device multiplier */ @@ -60,9 +61,6 @@ typedef struct sVDMOSinstance { double VDMOStPhi; /* temperature corrected Phi */ double VDMOStVto; /* temperature corrected Vto */ double VDMOStSatCur; /* temperature corrected saturation Cur. */ - double VDMOStBulkPot; /* temperature corrected Bulk potential */ - double VDMOStDepCap; /* temperature adjusted transition point in */ - /* the cureve matching Fc * Vj */ double VDMOSicVBS; /* initial condition B-S voltage */ double VDMOSicVDS; /* initial condition D-S voltage */ @@ -90,6 +88,23 @@ typedef struct sVDMOSinstance { double VDMOSf3s; double VDMOSf4s; + double VDIOcap; + double VDIOtSatCur; /* temperature corrected saturation Cur. density*/ + double VDIOinitCond; + double VDIOtVcrit; + double VDIOtConductance; + double VDIOtBrkdwnV; + double VDIOtJctCap; + double VDIOtDepCap; /* temperature adjusted transition point in */ + /* the cureve matching Fc * Vj */ + double VDIOtJctPot; /* temperature corrected Bulk potential */ + double VDIOtGradingCoeff; + + double VDIOtTransitTime; + double VDIOtF1; + double VDIOtF2; + double VDIOtF3; + /* * naming convention: * x = vgs @@ -256,7 +271,13 @@ typedef struct sVDMOSinstance { #define VDMOSqbs VDMOSstates+ 15 /* bulk-source capacitor charge */ #define VDMOScqbs VDMOSstates+ 16 /* bulk-source capacitor current */ -#define VDMOSnumStates 17 +#define VDIOvoltage VDMOSstates+ 17 +#define VDIOcurrent VDMOSstates+ 18 +#define VDIOconduct VDMOSstates+ 19 +#define VDIOcapCharge VDMOSstates+ 20 +#define VDIOcapCurrent VDMOSstates+ 21 + +#define VDMOSnumStates 22 /* per model data */ @@ -279,7 +300,6 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */ int VDMOStype; /* device type : 1 = nmos, -1 = pmos */ double VDMOStnom; /* temperature at which parameters measured */ - double VDMOSjctSatCur; /* input - use tSatCur */ double VDMOSdrainResistance; double VDMOSsourceResistance; double VDMOSgateResistance; @@ -287,9 +307,6 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */ double VDMOStransconductance; /* input - use tTransconductance */ double VDMOSoxideCapFactor; double VDMOSvt0; /* input - use tVto */ - double VDMOSbulkJctPotential; /* input - use tBulkPot */ - double VDMOSbulkJctBotGradingCoeff; - double VDMOSfwdCapDepCoeff; double VDMOSphi; /* input - use tPhi */ double VDMOSlambda; double VDMOSfNcoef; @@ -299,27 +316,37 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */ double VDMOSa; double VDMOScgs; + /* bulk diode */ + double VDIOjunctionCap; /* input - use tCj */ + double VDIOjunctionPot; /* input - use tBulkPot */ + double VDMOSbulkJctBotGradingCoeff; + double VDIOdepletionCapCoeff; + double VDIOjctSatCur; /* input - use tSatCur */ double VDMOSDbv; double VDMOSDibv; double VDIObrkdEmissionCoeff; double VDIOresistance; double VDIOresistTemp1; double VDIOresistTemp2; + double VDIOconductance; double VDMOSDn; double VDIOtransitTime; + double VDIOtranTimeTemp1; + double VDIOtranTimeTemp2; double VDMOSDeg; double VDMOSDxti; + double VDIOgradCoeffTemp1; + double VDIOgradCoeffTemp2; unsigned VDMOStypeGiven :1; - unsigned VDMOSjctSatCurGiven :1; + unsigned VDIOjctSatCurGiven :1; unsigned VDMOSdrainResistanceGiven :1; unsigned VDMOSsourceResistanceGiven :1; unsigned VDMOSgateResistanceGiven :1; unsigned VDMOStransconductanceGiven :1; unsigned VDMOSvt0Given :1; - unsigned VDMOSbulkJctPotentialGiven :1; unsigned VDMOSbulkJctBotGradingCoeffGiven :1; - unsigned VDMOSfwdCapDepCoeffGiven :1; + unsigned VDIOdepletionCapCoeffGiven :1; unsigned VDMOSphiGiven :1; unsigned VDMOSlambdaGiven :1; unsigned VDMOStnomGiven :1; @@ -333,6 +360,8 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */ unsigned VDMOSDbvGiven :1; unsigned VDMOSDibvGiven :1; + unsigned VDIOjunctionCapGiven :1; + unsigned VDIOjunctionPotGiven :1; unsigned VDIObrkdEmissionCoeffGiven :1; unsigned VDIOresistanceGiven :1; unsigned VDMOSDnGiven :1; @@ -376,6 +405,7 @@ enum { VDMOS_MOD_RG, VDMOS_MOD_IS, VDMOS_MOD_VJ, + VDMOS_MOD_CJ, VDMOS_MOD_MJ, VDMOS_MOD_FC, VDMOS_MOD_NMOS, @@ -403,6 +433,7 @@ enum { enum { VDMOS_CGS = 201, VDMOS_CGD, + VDMOS_CDS, VDMOS_DNODE, VDMOS_GNODE, VDMOS_SNODE, diff --git a/src/spicelib/devices/vdmos/vdmosload.c b/src/spicelib/devices/vdmos/vdmosload.c index 3799746e5..ec888178e 100644 --- a/src/spicelib/devices/vdmos/vdmosload.c +++ b/src/spicelib/devices/vdmos/vdmosload.c @@ -48,7 +48,6 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) double gcgs; double geq; double sarg; - double sargsw; double vbd; double vbs; double vds; @@ -454,144 +453,20 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) 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 + * capacitance evaluation for drain-source is done with the bulk diode */ - /* - * charge storage elements - * - *.. bulk-drain and bulk-source depletion capacitances - */ - { - /* can't bypass the diode capacitance calculations */ - if (here->VDMOSCbs != 0) { - if (vbs < here->VDMOStDepCap) { - arg = 1 - vbs / here->VDMOStBulkPot; - /* - * 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!) - */ - if (model->VDMOSbulkJctBotGradingCoeff == .5) { - sarg = sargsw = 1 / sqrt(arg); - } - else { - sarg = sargsw = - exp(-model->VDMOSbulkJctBotGradingCoeff* - log(arg)); - } - *(ckt->CKTstate0 + here->VDMOSqbs) = - here->VDMOStBulkPot*(here->VDMOSCbs* - (1 - arg*sarg) / (1 - model->VDMOSbulkJctBotGradingCoeff)); - here->VDMOScapbs = here->VDMOSCbs * sarg; - } - else { - *(ckt->CKTstate0 + here->VDMOSqbs) = here->VDMOSf4s + - vbs*(here->VDMOSf2s + vbs*(here->VDMOSf3s / 2)); - here->VDMOScapbs = here->VDMOSf2s + here->VDMOSf3s*vbs; - } - } - else { *(ckt->CKTstate0 + here->VDMOSqbs) = 0; here->VDMOScapbs = 0; - } - } - { - if (here->VDMOSCbd != 0) { - if (vbd < here->VDMOStDepCap) { - arg = 1 - vbd / here->VDMOStBulkPot; - /* - * 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!) - */ - if (model->VDMOSbulkJctBotGradingCoeff == .5) { - sarg = sargsw = 1 / sqrt(arg); - } - else { - if (model->VDMOSbulkJctBotGradingCoeff == .5) { - sarg = 1 / sqrt(arg); - } - else { - sarg = exp(-model->VDMOSbulkJctBotGradingCoeff* - log(arg)); - } - } - *(ckt->CKTstate0 + here->VDMOSqbd) = - here->VDMOStBulkPot*(here->VDMOSCbd* - (1 - arg*sarg) - / (1 - model->VDMOSbulkJctBotGradingCoeff)); - here->VDMOScapbd = here->VDMOSCbd * sarg; - } - else { - *(ckt->CKTstate0 + here->VDMOSqbd) = here->VDMOSf4d + - vbd * (here->VDMOSf2d + vbd * here->VDMOSf3d / 2); - here->VDMOScapbd = here->VDMOSf2d + vbd * here->VDMOSf3d; - } - } - else { + *(ckt->CKTstate0 + here->VDMOSqbd) = 0; here->VDMOScapbd = 0; - } - } /* */ - - 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->VDMOScapbd, - here->VDMOSqbd); - if (error) return(error); - here->VDMOSgbd += geq; - here->VDMOScbd += *(ckt->CKTstate0 + here->VDMOScqbd); - here->VDMOScd -= *(ckt->CKTstate0 + here->VDMOScqbd); - error = NIintegrate(ckt, &geq, &ceq, here->VDMOScapbs, - here->VDMOSqbs); - if (error) return(error); - here->VDMOSgbs += geq; - here->VDMOScbs += *(ckt->CKTstate0 + here->VDMOScqbs); - } } - /* - - */ - /* - * check convergence - */ - if ((here->VDMOSoff == 0) || - (!(ckt->CKTmode & (MODEINITFIX | MODEINITSMSIG)))) { - if (Check == 1) { - ckt->CKTnoncon++; - ckt->CKTtroubleElt = (GENinstance *)here; - } - } - /* - - */ /* save things away for next time */ @@ -781,6 +656,236 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) *(here->VDMOSSPbPtr) += (-here->VDMOSgbs - (xnrm - xrev)*here->VDMOSgmbs); *(here->VDMOSSPdpPtr) += (-here->VDMOSgds - xrev* (here->VDMOSgm + here->VDMOSgmbs)); + + + /* bulk diode model + * Delivers reverse conduction and forward breakdown + * of VDMOS transistor + */ + + double vd; /* current diode voltage */ + double vdtemp; + double vte; + double vtebrk; + 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; + + 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 = *(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, -here->VDIOtBrkdwnV + 10 * vtebrk))) { + vdtemp = -(vd + here->VDIOtBrkdwnV); + vdtemp = DEVpnjlim(vdtemp, + -(*(ckt->CKTstate0 + here->VDIOvoltage) + + here->VDIOtBrkdwnV), vtebrk, + here->VDIOtVcrit, &Check); + vd = -(vdtemp + here->VDIOtBrkdwnV); + } + else { + vd = DEVpnjlim(vd, *(ckt->CKTstate0 + here->VDIOvoltage), + vte, here->VDIOtVcrit, &Check); + } + } + /* + * compute dc current and derivitives + */ + if (vd >= -3 * vte) { /* bottom current forward */ + + evd = exp(vd / vte); + cdb = csat*(evd - 1); + gdb = csat*evd / vte; + + } + else if ((!(model->VDMOSDbvGiven)) || + vd >= -here->VDIOtBrkdwnV) { /* reverse */ + + arg = 3 * vte / (vd*CONSTe); + arg = arg * arg * arg; + cdb = -csat*(1 + arg); + gdb = csat * 3 * arg / vd; + + } + else { /* breakdown */ + + evrev = exp(-(here->VDIOtBrkdwnV + 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; + *(ckt->CKTrhs + here->VDMOSdNode) += cdeq; + *(ckt->CKTrhs + here->VDIOposPrimeNode) -= cdeq; + /* + * load matrix + */ + /* + *(here->DIOposPosPtr) += gspr; + *(here->DIOnegNegPtr) += gd; + *(here->DIOposPrimePosPrimePtr) += (gd + gspr); + *(here->DIOposPosPrimePtr) -= gspr; + *(here->DIOnegPosPrimePtr) -= gd; + *(here->DIOposPrimePosPtr) -= gspr; + *(here->DIOposPrimeNegPtr) -= gd; + */ } } return(OK); diff --git a/src/spicelib/devices/vdmos/vdmosmask.c b/src/spicelib/devices/vdmos/vdmosmask.c index f77ebece1..8589664bc 100644 --- a/src/spicelib/devices/vdmos/vdmosmask.c +++ b/src/spicelib/devices/vdmos/vdmosmask.c @@ -69,13 +69,16 @@ VDMOSmAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value) value->rValue = model->VDIOresistance; return(OK); case VDMOS_MOD_IS: - value->rValue = model->VDMOSjctSatCur; + value->rValue = model->VDIOjctSatCur; return(OK); case VDMOS_MOD_N: value->rValue = model->VDMOSDn; return(OK); case VDMOS_MOD_VJ: - value->rValue = model->VDMOSbulkJctPotential; + value->rValue = model->VDIOjunctionPot; + return(OK); + case VDMOS_MOD_CJ: + value->rValue = model->VDIOjunctionCap; return(OK); case VDMOS_MOD_MJ: value->rValue = model->VDMOSbulkJctBotGradingCoeff; @@ -90,7 +93,7 @@ VDMOSmAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value) value->rValue = model->VDIObrkdEmissionCoeff; return(OK); case VDMOS_MOD_FC: - value->rValue = model->VDMOSfwdCapDepCoeff; + value->rValue = model->VDIOdepletionCapCoeff; return(OK); case VDMOS_MOD_TT: value->rValue = model->VDIOtransitTime; diff --git a/src/spicelib/devices/vdmos/vdmosmpar.c b/src/spicelib/devices/vdmos/vdmosmpar.c index af65a0b7d..a0f9dcdd2 100644 --- a/src/spicelib/devices/vdmos/vdmosmpar.c +++ b/src/spicelib/devices/vdmos/vdmosmpar.c @@ -54,20 +54,26 @@ VDMOSmParam(int param, IFvalue *value, GENmodel *inModel) model->VDIOresistTemp2 = 0; break; case VDMOS_MOD_IS: - model->VDMOSjctSatCur = value->rValue; - model->VDMOSjctSatCurGiven = TRUE; + model->VDIOjctSatCur = value->rValue; + model->VDIOjctSatCurGiven = TRUE; break; case VDMOS_MOD_VJ: - model->VDMOSbulkJctPotential = value->rValue; - model->VDMOSbulkJctPotentialGiven = TRUE; + model->VDIOjunctionPot = value->rValue; + model->VDIOjunctionPotGiven = TRUE; + break; + case VDMOS_MOD_CJ: + model->VDIOjunctionCap = value->rValue; + model->VDIOjunctionCapGiven = TRUE; break; case VDMOS_MOD_MJ: model->VDMOSbulkJctBotGradingCoeff = value->rValue; model->VDMOSbulkJctBotGradingCoeffGiven = TRUE; + model->VDIOgradCoeffTemp1 = 0; + model->VDIOgradCoeffTemp2 = 0; break; case VDMOS_MOD_FC: - model->VDMOSfwdCapDepCoeff = value->rValue; - model->VDMOSfwdCapDepCoeffGiven = TRUE; + model->VDIOdepletionCapCoeff = value->rValue; + model->VDIOdepletionCapCoeffGiven = TRUE; break; case VDMOS_MOD_NMOS: if(value->iValue) { @@ -130,6 +136,8 @@ VDMOSmParam(int param, IFvalue *value, GENmodel *inModel) case VDMOS_MOD_TT: model->VDIOtransitTime = value->rValue; model->VDIOtransitTimeGiven = TRUE; + model->VDIOtranTimeTemp1 = 0; + model->VDIOtranTimeTemp2 = 0; break; case VDMOS_MOD_EG: model->VDMOSDeg = value->rValue; diff --git a/src/spicelib/devices/vdmos/vdmosset.c b/src/spicelib/devices/vdmos/vdmosset.c index fce93e1f0..e377f0b19 100644 --- a/src/spicelib/devices/vdmos/vdmosset.c +++ b/src/spicelib/devices/vdmos/vdmosset.c @@ -30,8 +30,8 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, if (!model->VDMOStypeGiven) { model->VDMOStype = NMOS; } - if (!model->VDMOSjctSatCurGiven) { - model->VDMOSjctSatCur = 1e-14; + if (!model->VDIOjctSatCurGiven) { + model->VDIOjctSatCur = 1e-14; } if (!model->VDMOStransconductanceGiven) { model->VDMOStransconductance = 1; @@ -39,14 +39,14 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, if (!model->VDMOSvt0Given) { model->VDMOSvt0 = 0; } - if (!model->VDMOSbulkJctPotentialGiven) { - model->VDMOSbulkJctPotential = .8; + if (!model->VDIOjunctionPotGiven) { + model->VDIOjunctionPot = .8; } if (!model->VDMOSbulkJctBotGradingCoeffGiven) { model->VDMOSbulkJctBotGradingCoeff = .5; } - if (!model->VDMOSfwdCapDepCoeffGiven) { - model->VDMOSfwdCapDepCoeff = .5; + if (!model->VDIOdepletionCapCoeffGiven) { + model->VDIOdepletionCapCoeff = .5; } if (!model->VDMOSphiGiven) { model->VDMOSphi = .6; @@ -185,6 +185,29 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, here->VDMOSgNodePrime = here->VDMOSgNode; } + if (model->VDIOresistance != 0 ) { + if (here->VDIOposPrimeNode == 0) { + error = CKTmkVolt(ckt, &tmp, here->VDMOSname, "bulk diode"); + if (error) return(error); + here->VDIOposPrimeNode = tmp->number; + + if (ckt->CKTcopyNodesets) { + CKTnode *tmpNode; + IFuid tmpName; + + if (CKTinst2Node(ckt, here, 3, &tmpNode, &tmpName) == OK) { + if (tmpNode->nsGiven) { + tmp->nodeset = tmpNode->nodeset; + tmp->nsGiven = tmpNode->nsGiven; + } + } + } + } + } + else { + here->VDIOposPrimeNode = here->VDMOSdNode; + } + /* macro to make elements with built in test for out of memory */ #define TSTALLOC(ptr,first,second) \ @@ -274,6 +297,11 @@ VDMOSunsetup(GENmodel *inModel, CKTcircuit *ckt) && here->VDMOSgNodePrime != here->VDMOSgNode) CKTdltNNum(ckt, here->VDMOSgNodePrime); here->VDMOSgNodePrime = 0; + + if (here->VDIOposPrimeNode > 0 + && here->VDIOposPrimeNode != here->VDMOSdNode) + CKTdltNNum(ckt, here->VDIOposPrimeNode); + here->VDIOposPrimeNode = 0; } } return OK; diff --git a/src/spicelib/devices/vdmos/vdmostemp.c b/src/spicelib/devices/vdmos/vdmostemp.c index e63080930..34a39d712 100644 --- a/src/spicelib/devices/vdmos/vdmostemp.c +++ b/src/spicelib/devices/vdmos/vdmostemp.c @@ -25,6 +25,8 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt) double phio; double pbfact1,pbfact; double vt,vtnom; + double xfc; + /* loop through all the resistor models */ for( ; model != NULL; model = VDMOSnextModel(model)) { @@ -52,6 +54,31 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt) model->VDMOSoxideCapFactor = 0; + /* bulk diode model */ + /* limit activation energy to min of .1 */ + if (model->VDMOSDeg<.1) { + SPfrontEnd->IFerrorf(ERR_WARNING, + "%s: bulk diode activation energy too small, limited to 0.1", + model->VDMOSmodName); + model->VDMOSDeg = .1; + } + /* limit depletion cap coeff to max of .95 */ + if (model->VDIOdepletionCapCoeff>.95) { + SPfrontEnd->IFerrorf(ERR_WARNING, + "%s: coefficient Fc too large, limited to 0.95", + model->VDMOSmodName); + model->VDIOdepletionCapCoeff = .95; + } + /* set lower limit of saturation current */ + if (model->VDIOjctSatCur < ckt->CKTepsmin) + model->VDIOjctSatCur = ckt->CKTepsmin; + if ((!model->VDIOresistanceGiven) || (model->VDIOresistance == 0)) { + model->VDIOconductance = 0.0; + } + else { + model->VDIOconductance = 1 / model->VDIOresistance; + } + xfc = log(1 - model->VDIOdepletionCapCoeff); /* loop through all instances of the model */ for(here = VDMOSinstances(model); here!= NULL; @@ -133,6 +160,136 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt) } else { here->VDMOSgateConductance = 0; } + + /* bulk diode model */ + double egfet1, arg1, fact1, pbfact1, pbo, gmaold; + double fact2, pbfact, arg2, egfet, gmanew, factor; + double tBreakdownVoltage, vte, cbv; + double xbv, xcbv, tol, iter, dt; + + /* loop through all the instances */ + + if (!here->VDMOSdtempGiven) here->VDMOStemp = 0.0; + + if (!here->VDMOStempGiven) + here->VDMOStemp = ckt->CKTtemp + here->VDMOStemp; + + dt = here->VDMOStemp - model->VDMOStnom; + + /* Junction grading temperature adjust */ + factor = 1.0 + (model->VDIOgradCoeffTemp1 * dt) + + (model->VDIOgradCoeffTemp2 * dt * dt); + here->VDIOtGradingCoeff = model->VDMOSbulkJctBotGradingCoeff * factor; + + vt = CONSTKoverQ * here->VDMOStemp; + /* this part gets really ugly - I won't even try to + * explain these equations */ + fact2 = here->VDMOStemp / REFTEMP; + egfet = 1.16 - (7.02e-4*here->VDMOStemp*here->VDMOStemp) / + (here->VDMOStemp + 1108); + arg2 = -egfet / (2 * CONSTboltz*here->VDMOStemp) + + 1.1150877 / (CONSTboltz*(REFTEMP + REFTEMP)); + pbfact = -2 * vt*(1.5*log(fact2) + CHARGE*arg2); + egfet1 = 1.16 - (7.02e-4*model->VDMOStnom*model->VDMOStnom) / + (model->VDMOStnom + 1108); + arg1 = -egfet1 / (CONSTboltz * 2 * model->VDMOStnom) + + 1.1150877 / (2 * CONSTboltz*REFTEMP); + fact1 = model->VDMOStnom / REFTEMP; + pbfact1 = -2 * vtnom*(1.5*log(fact1) + CHARGE*arg1); + + pbo = (model->VDIOjunctionPot - pbfact1) / fact1; + gmaold = (model->VDIOjunctionPot - pbo) / pbo; + here->VDIOtJctCap = model->VDIOjunctionCap / + (1 + here->VDIOtGradingCoeff* + (400e-6*(model->VDMOStnom - REFTEMP) - gmaold)); + here->VDIOtJctPot = pbfact + fact2*pbo; + gmanew = (here->VDIOtJctPot - pbo) / pbo; + here->VDIOtJctCap *= 1 + here->VDIOtGradingCoeff* + (400e-6*(here->VDMOStemp - REFTEMP) - gmanew); + + + here->VDIOtSatCur = model->VDIOjctSatCur * exp( + ((here->VDMOStemp / model->VDMOStnom) - 1) * + model->VDMOSDeg / (model->VDMOSDn*vt) + + model->VDMOSDxti / model->VDMOSDn * + log(here->VDMOStemp / model->VDMOStnom)); + + /* the defintion of f1, just recompute after temperature adjusting + * all the variables used in it */ + here->VDIOtF1 = here->VDIOtJctPot* + (1 - exp((1 - here->VDIOtGradingCoeff)*xfc)) / + (1 - here->VDIOtGradingCoeff); + /* same for Depletion Capacitance */ + here->VDIOtDepCap = model->VDIOdepletionCapCoeff* + here->VDIOtJctPot; + + /* and Vcrit */ + vte = model->VDMOSDn*vt; + + here->VDIOtVcrit = vte * log(vte / (CONSTroot2*here->VDIOtSatCur)); + + /* limit junction potential to max of 1/FC */ + if (here->VDIOtDepCap > 1.0) { + here->VDIOtJctPot = 1.0 / model->VDMOSDn; + here->VDIOtDepCap = model->VDMOSDn*here->VDIOtJctPot; + SPfrontEnd->IFerrorf(ERR_WARNING, + "%s: junction potential VJ too large, limited to %f", + model->VDMOSmodName, here->VDIOtJctPot); + } + + /* and now to compute the breakdown voltage, again, using + * temperature adjusted basic parameters */ + if (model->VDMOSDbvGiven) { + /* tlev == 0 */ + tBreakdownVoltage = model->VDMOSDbv; + + cbv = model->VDMOSDibv; + + if (cbv < here->VDIOtSatCur * tBreakdownVoltage / vt) { + cbv = here->VDIOtSatCur * tBreakdownVoltage / vt; +#ifdef TRACE + SPfrontEnd->IFerrorf(ERR_WARNING, "%s: breakdown current increased to %g to resolve", here->DIOname, cbv); + SPfrontEnd->IFerrorf(ERR_WARNING, + "incompatibility with specified saturation current"); +#endif + xbv = tBreakdownVoltage; + } + else { + tol = ckt->CKTreltol*cbv; + xbv = tBreakdownVoltage - model->VDIObrkdEmissionCoeff*vt*log(1 + cbv / + (here->VDIOtSatCur)); + iter = 0; + for (iter = 0; iter < 25; iter++) { + xbv = tBreakdownVoltage - model->VDIObrkdEmissionCoeff*vt*log(cbv / + (here->VDIOtSatCur) + 1 - xbv / vt); + xcbv = here->VDIOtSatCur * + (exp((tBreakdownVoltage - xbv) / (model->VDIObrkdEmissionCoeff*vt)) - 1 + xbv / vt); + if (fabs(xcbv - cbv) <= tol) goto matched; + } +#ifdef TRACE + SPfrontEnd->IFerrorf(ERR_WARNING, "%s: unable to match forward and reverse diode regions: bv = %g, ibv = %g", here->DIOname, xbv, xcbv); +#endif + } + matched: + here->VDIOtBrkdwnV = xbv; + } + + /* transit time temperature adjust */ + factor = 1.0 + (model->VDIOtranTimeTemp1 * dt) + + (model->VDIOtranTimeTemp2 * dt * dt); + here->VDIOtTransitTime = model->VDIOtransitTime * factor; + + /* Series resistance temperature adjust */ + here->VDIOtConductance = model->VDIOconductance; + if (model->VDIOresistanceGiven && model->VDIOresistance != 0.0) { + factor = 1.0 + (model->VDIOresistTemp1) * dt + + (model->VDIOresistTemp2 * dt * dt); + here->VDIOtConductance = model->VDIOconductance / factor; + } + + here->VDIOtF2 = exp((1 + here->VDIOtGradingCoeff)*xfc); + here->VDIOtF3 = 1 - model->VDIOdepletionCapCoeff* + (1 + here->VDIOtGradingCoeff); } } return(OK);