From 4ac7a641ece53912c44003ffb8468e179fd7e80a Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 9 Apr 2018 20:11:45 +0200 Subject: [PATCH] diode model for bulk diode added code taken from dio.c etc. capacitance calculation for vdmos bulk cap removed, is now completely with the diode. An internal node added for series diode resistance RB matrix entries not yet done! --- src/spicelib/devices/vdmos/vdmos.c | 2 + src/spicelib/devices/vdmos/vdmosask.c | 3 + src/spicelib/devices/vdmos/vdmosdefs.h | 53 +++- src/spicelib/devices/vdmos/vdmosload.c | 359 ++++++++++++++++--------- src/spicelib/devices/vdmos/vdmosmask.c | 9 +- src/spicelib/devices/vdmos/vdmosmpar.c | 20 +- src/spicelib/devices/vdmos/vdmosset.c | 40 ++- src/spicelib/devices/vdmos/vdmostemp.c | 157 +++++++++++ 8 files changed, 490 insertions(+), 153 deletions(-) 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);