From b4ecedc616fb372432764a2c3dded6d2307896eb Mon Sep 17 00:00:00 2001 From: dwarning Date: Sat, 9 May 2026 15:55:27 +0200 Subject: [PATCH] vdmos bulk diode with smart recovery model --- src/spicelib/devices/vdmos/vdmos.c | 3 + src/spicelib/devices/vdmos/vdmosacld.c | 14 +++ src/spicelib/devices/vdmos/vdmosask.c | 7 ++ src/spicelib/devices/vdmos/vdmosbindCSC.c | 24 +++++ src/spicelib/devices/vdmos/vdmosdefs.h | 31 +++++- src/spicelib/devices/vdmos/vdmosload.c | 115 +++++++++++++++++++--- src/spicelib/devices/vdmos/vdmosmask.c | 3 + src/spicelib/devices/vdmos/vdmosmpar.c | 4 + src/spicelib/devices/vdmos/vdmosset.c | 29 +++++- src/spicelib/devices/vdmos/vdmostrun.c | 2 + 10 files changed, 216 insertions(+), 16 deletions(-) diff --git a/src/spicelib/devices/vdmos/vdmos.c b/src/spicelib/devices/vdmos/vdmos.c index 3fc352631..e2243c8a8 100644 --- a/src/spicelib/devices/vdmos/vdmos.c +++ b/src/spicelib/devices/vdmos/vdmos.c @@ -31,6 +31,7 @@ IFparm VDMOSpTable[] = { /* parameters */ OP( "cgd", VDMOS_CAPGD, IF_REAL, "Gate-Drain capacitance"), OP( "cds", VDMOS_CAPDS, IF_REAL, "Drain-Source capacitance"), OP( "idio", VDMOS_CDIO, IF_REAL, "Body diode current"), + OP( "qdio", VDMOS_QDIO, IF_REAL, "Body diode charge"), OPU( "dnode", VDMOS_DNODE, IF_INTEGER, "Number of the drain node "), OPU( "gnode", VDMOS_GNODE, IF_INTEGER, "Number of the gate node "), @@ -115,6 +116,8 @@ IFparm VDMOSmPTable[] = { /* model parameters */ IOP("xti", VDIO_MOD_XTI, IF_REAL, "Body diode saturation current temperature exponent"), IOP("is", VDIO_MOD_IS, IF_REAL, "Body diode saturation current"), IOP("vj", VDIO_MOD_VJ, IF_REAL, "Body diode junction potential"), + IOP("vp", VDIO_MOD_VP, IF_REAL, "Soft reverse recovery parameter"), + /* body diode capacitance (e.g. source-drain capacitance) */ IOPA("cjo", VDIO_MOD_CJ, IF_REAL, "Zero-bias body diode junction capacitance"), diff --git a/src/spicelib/devices/vdmos/vdmosacld.c b/src/spicelib/devices/vdmos/vdmosacld.c index fd90caa66..fb6348c21 100644 --- a/src/spicelib/devices/vdmos/vdmosacld.c +++ b/src/spicelib/devices/vdmos/vdmosacld.c @@ -156,6 +156,20 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt) *(here->VDMOSSPtempPtr + 1) += xcsT; *(here->VDMOSGPtempPtr + 1) += xcgT; } + if ((here->VDIOqpNode > 0) && (model->VDIOsoftRevRecParam!=0) && (here->VDIOtTransitTime!=0)) { + /* QP subcircuit */ + double gdres= *(ckt->CKTstate0 + here->VDIOresConduct); + double fac = here->VDIOtTransitTime / model->VDIOsoftRevRecParam; + double dcrrdvd = fac * gdres; + *(here->VDIOqpQpPtr) += 1/model->VDIOsoftRevRecParam; + *(here->VDIOqpQpPtr + 1) += here->VDIOtTransitTime * ckt->CKTomega; + *(here->VDIOqpPosPrimePtr) += -dcrrdvd; + *(here->VDIOqpNegPtr) += dcrrdvd; + /* Gain of VCVS (1-vp)/tau * j*omega*tau = (1-vp) * j*omega */ + double xgain = (1 - model->VDIOsoftRevRecParam) * ckt->CKTomega; + *(here->VDIOposPrimeQpPtr + 1) += xgain; + *(here->VDIOnegQpPtr + 1) += -xgain; + } } } return(OK); diff --git a/src/spicelib/devices/vdmos/vdmosask.c b/src/spicelib/devices/vdmos/vdmosask.c index f29ee0d03..32fcb4286 100644 --- a/src/spicelib/devices/vdmos/vdmosask.c +++ b/src/spicelib/devices/vdmos/vdmosask.c @@ -118,6 +118,13 @@ VDMOSask(CKTcircuit *ckt, GENinstance *inst, int which, IFvalue *value, return(OK); case VDMOS_CDIO: value->rValue = *(ckt->CKTstate0 + here->VDIOcurrent); + if ((here->VDIOqpNode > 0) && (here->VDIOtTransitTime!=0)) + value->rValue += here->VDIOqpGain * *(ckt->CKTstate0 + here->VDIOcqcsr); + return(OK); + case VDMOS_QDIO: + value->rValue = *(ckt->CKTstate0+here->VDIOcapCharge); + if ((here->VDIOqpNode > 0) && (here->VDIOtTransitTime!=0)) + value->rValue += here->VDIOqpGain * *(ckt->CKTstate0 + here->VDIOsrcapCharge); return(OK); case VDMOS_CG : if (ckt->CKTcurrentAnalysis & DOING_AC) { diff --git a/src/spicelib/devices/vdmos/vdmosbindCSC.c b/src/spicelib/devices/vdmos/vdmosbindCSC.c index bd24b856d..43fd9727e 100644 --- a/src/spicelib/devices/vdmos/vdmosbindCSC.c +++ b/src/spicelib/devices/vdmos/vdmosbindCSC.c @@ -80,6 +80,14 @@ VDMOSbindCSC (GENmodel *inModel, CKTcircuit *ckt) CREATE_KLU_BINDING_TABLE(VDMOSDevTtpPtr, VDMOSDevTtpBinding, VDMOSvdevTbranch, VDMOStNodePrime); CREATE_KLU_BINDING_TABLE(VDMOSTpdevTPtr, VDMOSTpdevTBinding, VDMOStNodePrime, VDMOSvdevTbranch); } + /* rev-rec */ + if (model->VDIOsoftRevRecParamGiven && model->VDIOsoftRevRecParam!=0 && model->VDIOtransitTime!=0) { + CREATE_KLU_BINDING_TABLE(VDIOqpQpPtr , VDIOqpQpBinding , VDIOqpNode, VDIOqpNode); + CREATE_KLU_BINDING_TABLE(VDIOqpPosPrimePtr, VDIOqpPosPrimeBinding, VDIOqpNode, VDIOposPrimeNode); + CREATE_KLU_BINDING_TABLE(VDIOqpNegPtr , VDIOqpNegBinding , VDIOqpNode, VDMOSdNode); + CREATE_KLU_BINDING_TABLE(VDIOposPrimeQpPtr, VDIOposPrimeQpBinding, VDIOposPrimeNode, VDIOqpNode); + CREATE_KLU_BINDING_TABLE(VDIOnegQpPtr , VDIOnegQpBinding , VDMOSdNode, VDIOqpNode); + } } } @@ -155,6 +163,14 @@ VDMOSbindCSCComplex (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSDevTtpPtr, VDMOSDevTtpBinding, VDMOSvdevTbranch, VDMOStNodePrime); CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTpdevTPtr, VDMOSTpdevTBinding, VDMOStNodePrime, VDMOSvdevTbranch); } + /* rev-rec */ + if (model->VDIOsoftRevRecParamGiven && model->VDIOsoftRevRecParam!=0 && model->VDIOtransitTime!=0) { + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDIOqpQpPtr , VDIOqpQpBinding , VDIOqpNode, VDIOqpNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDIOqpPosPrimePtr, VDIOqpPosPrimeBinding, VDIOqpNode, VDIOposPrimeNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDIOqpNegPtr , VDIOqpNegBinding , VDIOqpNode, VDMOSdNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDIOposPrimeQpPtr, VDIOposPrimeQpBinding, VDIOposPrimeNode, VDIOqpNode); + CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDIOnegQpPtr , VDIOnegQpBinding , VDMOSdNode, VDIOqpNode); + } } } @@ -230,6 +246,14 @@ VDMOSbindCSCComplexToReal (GENmodel *inModel, CKTcircuit *ckt) CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSDevTtpPtr, VDMOSDevTtpBinding, VDMOSvdevTbranch, VDMOStNodePrime); CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTpdevTPtr, VDMOSTpdevTBinding, VDMOStNodePrime, VDMOSvdevTbranch); } + /* rev-rec */ + if (model->VDIOsoftRevRecParamGiven && model->VDIOsoftRevRecParam!=0 && model->VDIOtransitTime!=0) { + CONVERT_KLU_BINDING_TABLE_TO_REAL(VDIOqpQpPtr , VDIOqpQpBinding , VDIOqpNode, VDIOqpNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(VDIOqpPosPrimePtr, VDIOqpPosPrimeBinding, VDIOqpNode, VDIOposPrimeNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(VDIOqpNegPtr , VDIOqpNegBinding , VDIOqpNode, VDMOSdNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(VDIOposPrimeQpPtr, VDIOposPrimeQpBinding, VDIOposPrimeNode, VDIOqpNode); + CONVERT_KLU_BINDING_TABLE_TO_REAL(VDIOnegQpPtr , VDIOnegQpBinding , VDMOSdNode, VDIOqpNode); + } } } diff --git a/src/spicelib/devices/vdmos/vdmosdefs.h b/src/spicelib/devices/vdmos/vdmosdefs.h index 5409a520f..bd283e12d 100644 --- a/src/spicelib/devices/vdmos/vdmosdefs.h +++ b/src/spicelib/devices/vdmos/vdmosdefs.h @@ -49,6 +49,7 @@ typedef struct sVDMOSinstance { int VDMOSgNodePrime; /* number of the internal gate node of the mosfet */ int VDMOStNodePrime; /* number of the internal temp node between voltage source and Rthca */ int VDIOposPrimeNode; /* number of the internal node of the body diode */ + int VDIOqpNode; /* number of soft recovery charge node */ int VDMOSvdevTbranch; /* equation number of branch equation added for cktTemp source */ @@ -97,6 +98,9 @@ typedef struct sVDMOSinstance { double VDIOtF2; double VDIOtF3; + /* rev-rec */ + double VDIOqpGain;/* converts iterated diffcharge current */ + double VDMOSTempSH; /* for portability of SH temp to noise analysis */ double VDMOSgmT; @@ -216,6 +220,13 @@ typedef struct sVDMOSinstance { (source node, diode prime node) */ double *VDIORPsPtr; /* pointer to sparse matrix element at (diode prime node, source node) */ + /* rev-rec */ + double *VDIOqpQpPtr; + double *VDIOqpPosPrimePtr; + double *VDIOqpNegPtr; + double *VDIOposPrimeQpPtr; + double *VDIOnegQpPtr; + /* self heating */ double *VDMOSTemptempPtr; /* Transistor thermal contribution */ double *VDMOSTempdpPtr; @@ -290,6 +301,12 @@ typedef struct sVDMOSinstance { BindElement *VDMOSDevTdevTBinding ; BindElement *VDMOSDevTtpBinding ; BindElement *VDMOSTpdevTBinding ; + /* rev-rec */ + BindElement *VDIOqpQpBinding; + BindElement *VDIOqpPosPrimeBinding; + BindElement *VDIOqpNegBinding; + BindElement *VDIOposPrimeQpBinding; + BindElement *VDIOnegQpBinding; #endif } VDMOSinstance ; @@ -319,8 +336,16 @@ typedef struct sVDMOSinstance { #define VDIOdIdio_dT VDMOSstates+ 17 -#define VDMOSnumStates 18 +/* rev-rec */ +#define VDIOsrcapCharge VDMOSstates+18 +#define VDIOsrcapCurrent VDMOSstates+19 +#define VDIOqp VDMOSstates+20 +#define VDIOresCurrent VDMOSstates+21 +#define VDIOresConduct VDMOSstates+22 +#define VDIOcqcsr VDMOSstates+23 +#define VDIOgqcsr VDMOSstates+24 +#define VDMOSnumStates 25 /* per model data */ @@ -385,6 +410,7 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */ double VDIOgradCoeffTemp2; double VDIOtrb1; double VDIOtrb2; + double VDIOsoftRevRecParam; /* Soft reverse recovery parameter VP */ double VDMOStcvth; double VDMOSrthjc; @@ -482,6 +508,7 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */ unsigned VDMOSid_maxGiven :1; unsigned VDMOSidr_maxGiven :1; unsigned VDMOSderatingGiven :1; + unsigned VDIOsoftRevRecParamGiven : 1; } VDMOSmodel; #ifndef NMOS @@ -546,6 +573,7 @@ enum { VDIO_MOD_XTI, VDIO_MOD_TRB1, VDIO_MOD_TRB2, + VDIO_MOD_VP, VDMOS_MOD_TCVTH, VDMOS_MOD_RTHJC, VDMOS_MOD_RTHCA, @@ -599,6 +627,7 @@ enum { VDMOS_QGD, VDMOS_CQGD, VDMOS_CDIO, + VDMOS_QDIO, VDMOS_SOURCERESIST, VDMOS_DRAINRESIST, }; diff --git a/src/spicelib/devices/vdmos/vdmosload.c b/src/spicelib/devices/vdmos/vdmosload.c index f5c0d4e8d..12f39be0c 100644 --- a/src/spicelib/devices/vdmos/vdmosload.c +++ b/src/spicelib/devices/vdmos/vdmosload.c @@ -710,11 +710,17 @@ bypass: double Ith=0.0, dIth_dT=0.0; double dIdio_dT=0.0, dIth_dVdio=0.0; double vrb=0.0, dIrb_dT=0.0, dIth_dVrb=0.0; + /* rev-rec */ + double cdres, gdres; + double vqp; + double capsr, gqcsr, cqcsr; #ifndef NOBYPASS double tol; /* temporary for tolerance calculations */ #endif + int revrec = ((here->VDIOqpNode > 0) && (model->VDIOsoftRevRecParam!=0) && (here->VDIOtTransitTime!=0)); + gbpr = here->VDIOtConductance; vt = CONSTKoverQ * Temp; @@ -725,13 +731,17 @@ bypass: Check_dio = 1; if (ckt->CKTmode & MODEINITSMSIG) { vd = *(ckt->CKTstate0 + here->VDIOvoltage); + vqp = *(ckt->CKTstate0 + here->VDIOqp); } else if (ckt->CKTmode & MODEINITTRAN) { vd = *(ckt->CKTstate1 + here->VDIOvoltage); + vqp = *(ckt->CKTstate1 + here->VDIOqp); } else if ((ckt->CKTmode & MODEINITJCT) && (ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) { vd = here->VDIOinitCond; + vqp=0; } else if (ckt->CKTmode & MODEINITJCT) { vd = here->VDIOtVcrit; + vqp=0; } else { #ifndef PREDICTOR if (ckt->CKTmode & MODEINITPRED) { @@ -744,10 +754,20 @@ bypass: *(ckt->CKTstate1 + here->VDIOconduct); *(ckt->CKTstate0 + here->VDIOdIdio_dT) = *(ckt->CKTstate1 + here->VDIOdIdio_dT); + vqp = DEVpred(ckt,here->VDIOqp); + *(ckt->CKTstate0 + here->VDIOresCurrent) = + *(ckt->CKTstate1 + here->VDIOresCurrent); + *(ckt->CKTstate0 + here->VDIOresConduct) = + *(ckt->CKTstate1 + here->VDIOresConduct); + *(ckt->CKTstate0 + here->VDIOcqcsr) = + *(ckt->CKTstate1 + here->VDIOcqcsr); + *(ckt->CKTstate0 + here->VDIOgqcsr) = + *(ckt->CKTstate1 + here->VDIOgqcsr); } else { #endif /* PREDICTOR */ vd = model->VDMOStype * (*(ckt->CKTrhsOld + here->VDIOposPrimeNode) - *(ckt->CKTrhsOld + here->VDMOSdNode)); + vqp = model->VDMOStype * *(ckt->CKTrhsOld+here->VDIOqpNode); #ifndef PREDICTOR } #endif /* PREDICTOR */ @@ -776,6 +796,11 @@ bypass: cd = *(ckt->CKTstate0 + here->VDIOcurrent); gd = *(ckt->CKTstate0 + here->VDIOconduct); dIdio_dT= *(ckt->CKTstate0 + here->VDIOdIdio_dT); + vqp= *(ckt->CKTstate0 + here->VDIOqp); + cdres= *(ckt->CKTstate0 + here->VDIOresCurrent); + gdres= *(ckt->CKTstate0 + here->VDIOresConduct); + cqcsr= *(ckt->CKTstate0 + here->VDIOcqcsr); + gqcsr= *(ckt->CKTstate0 + here->VDIOgqcsr); goto load; } } @@ -833,6 +858,10 @@ bypass: cd = cdb + ckt->CKTgmin*vd; gd = gdb + ckt->CKTgmin; + cdres = cd; + gdres = gd; + cqcsr = 0; + gqcsr = 0; if ((ckt->CKTmode & (MODEDCTRANCURVE | MODETRAN | MODEAC | MODEINITSMSIG)) || ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC))) { @@ -853,14 +882,35 @@ bypass: (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; + if (revrec) { + /* + soft recovery with TT!=0 - add only depletion capacitance. + */ + *(ckt->CKTstate0 + here->VDIOcapCharge) = deplcharge; - here->VDIOcap = capd; + capd = deplcap; + here->VDIOcap = capd; + /* + DIOcap is now equal only to depletion capacitance + overlap capacitance. + Diffusion capacitance is modelled via Qp so there is no clear way to define it here. + Now prepare the charge for the capacitor connected to the QP node + */ + *(ckt->CKTstate0 + here->VDIOsrcapCharge) = here->VDIOtTransitTime * vqp; + capsr = here->VDIOtTransitTime; + } else { + /* + no soft recovery due to TT=0 + */ + diffcharge = here->VDIOtTransitTime*cdb; + diffcap = here->VDIOtTransitTime*gdb; + *(ckt->CKTstate0 + here->VDIOcapCharge) = diffcharge + deplcharge; + capd = diffcap + deplcap; + here->VDIOcap = capd; + + *(ckt->CKTstate0 + here->VDIOsrcapCharge) = 0; + capsr = 0; + } /* * store small-signal parameters @@ -869,6 +919,7 @@ bypass: (!(ckt->CKTmode & MODEUIC))) { if (ckt->CKTmode & MODEINITSMSIG) { *(ckt->CKTstate0 + here->VDIOcapCurrent) = capd; + *(ckt->CKTstate0 + here->VDIOresConduct) = gdres; continue; } @@ -889,6 +940,21 @@ bypass: *(ckt->CKTstate1 + here->VDIOcapCurrent) = *(ckt->CKTstate0 + here->VDIOcapCurrent); } + if (revrec) { + /* soft recovery subcircuit */ + if (ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->VDIOsrcapCharge) = + *(ckt->CKTstate0 + here->VDIOsrcapCharge); + } + error = NIintegrate(ckt,&geq,&ceq,capsr,here->VDIOsrcapCharge); + if(error) return(error); + gqcsr = geq; + cqcsr = *(ckt->CKTstate0 + here->VDIOsrcapCurrent); + if (ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->VDIOsrcapCurrent) = + *(ckt->CKTstate0 + here->VDIOsrcapCurrent); + } + } } } @@ -905,6 +971,11 @@ bypass: *(ckt->CKTstate0 + here->VDIOcurrent) = cd; *(ckt->CKTstate0 + here->VDIOconduct) = gd; *(ckt->CKTstate0 + here->VDIOdIdio_dT) = dIdio_dT; + *(ckt->CKTstate0 + here->VDIOqp) = vqp; + *(ckt->CKTstate0 + here->VDIOresCurrent) = cdres; + *(ckt->CKTstate0 + here->VDIOresConduct) = gdres; + *(ckt->CKTstate0 + here->VDIOcqcsr) = cqcsr; + *(ckt->CKTstate0 + here->VDIOgqcsr) = gqcsr; #ifndef NOBYPASS load: @@ -926,14 +997,10 @@ load: /* * 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; - } + cdeq = model->VDMOStype * (cd - gd*vd); + *(ckt->CKTrhs + here->VDMOSdNode) += cdeq; + *(ckt->CKTrhs + here->VDIOposPrimeNode) -= cdeq; + if (selfheat) { *(ckt->CKTrhs + here->VDIOposPrimeNode) += dIdio_dT*delTemp - dIrb_dT*delTemp; *(ckt->CKTrhs + here->VDMOSdNode) += -dIdio_dT*delTemp; @@ -959,6 +1026,26 @@ load: (*(here->VDMOSStempPtr) += dIrb_dT); (*(here->VDMOSDtempPtr) += -dIdio_dT); } + if (revrec) { + /* QP subcircuit */ + double fac = here->VDIOtTransitTime / model->VDIOsoftRevRecParam; + double dcrrdvd = fac*gdres; + double ceqrr = -fac*cdres + cqcsr + dcrrdvd*vd - gqcsr*vqp; + double grr = 1/model->VDIOsoftRevRecParam; + *(ckt->CKTrhs + here->VDIOqpNode) -= model->VDMOStype * ceqrr; + *(here->VDIOqpQpPtr) += grr + gqcsr; + *(here->VDIOqpPosPrimePtr) += -dcrrdvd; + *(here->VDIOqpNegPtr) += dcrrdvd; + /* Contribution to diode current */ + here->VDIOqpGain = (1 - model->VDIOsoftRevRecParam) / here->VDIOtTransitTime; + /* Linear contribution -(1-vp)/tau*ddt(Qp) */ + double geqrrd = here->VDIOqpGain*gqcsr; + double ceqrrd = model->VDMOStype * (here->VDIOqpGain*cqcsr - geqrrd*vqp); + *(ckt->CKTrhs + here->VDIOposPrimeNode) += -ceqrrd; + *(ckt->CKTrhs + here->VDMOSdNode) += ceqrrd; + *(here->VDIOposPrimeQpPtr) += geqrrd; + *(here->VDIOnegQpPtr) += -geqrrd; + } } } return(OK); diff --git a/src/spicelib/devices/vdmos/vdmosmask.c b/src/spicelib/devices/vdmos/vdmosmask.c index f1c79ec04..94c1bde04 100644 --- a/src/spicelib/devices/vdmos/vdmosmask.c +++ b/src/spicelib/devices/vdmos/vdmosmask.c @@ -182,6 +182,9 @@ VDMOSmAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value) case VDMOS_MOD_TKSUBTHRES2: value->rValue = model->VDMOStksubthres2; return(OK); + case VDIO_MOD_VP: + value->rValue = model->VDIOsoftRevRecParam; + return(OK); /* SOA */ case VDMOS_MOD_VGS_MAX: value->rValue = model->VDMOSvgsMax; diff --git a/src/spicelib/devices/vdmos/vdmosmpar.c b/src/spicelib/devices/vdmos/vdmosmpar.c index 20ad96aa6..e26a3adc8 100644 --- a/src/spicelib/devices/vdmos/vdmosmpar.c +++ b/src/spicelib/devices/vdmos/vdmosmpar.c @@ -166,6 +166,10 @@ VDMOSmParam(int param, IFvalue *value, GENmodel *inModel) model->VDIOtranTimeTemp1 = 0; model->VDIOtranTimeTemp2 = 0; break; + case VDIO_MOD_VP: + model->VDIOsoftRevRecParam = value->rValue; + model->VDIOsoftRevRecParamGiven = TRUE; + break; case VDIO_MOD_EG: model->VDIOeg = value->rValue; model->VDIOegGiven = TRUE; diff --git a/src/spicelib/devices/vdmos/vdmosset.c b/src/spicelib/devices/vdmos/vdmosset.c index 0adfce318..863ae61d2 100644 --- a/src/spicelib/devices/vdmos/vdmosset.c +++ b/src/spicelib/devices/vdmos/vdmosset.c @@ -251,6 +251,10 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, if (model->VDIOjctSatCur < ckt->CKTepsmin) model->VDIOjctSatCur = ckt->CKTepsmin; + if (!model->VDIOsoftRevRecParamGiven) { + model->VDIOsoftRevRecParam = 0.0; + } + /* loop through all the instances of the model */ for (here = VDMOSinstances(model); here != NULL; here = VDMOSnextInstance(here)) { @@ -431,6 +435,16 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, here->VDMOStcaseNode = 0; } + /* rev-rec */ + if (model->VDIOsoftRevRecParamGiven && model->VDIOsoftRevRecParam!=0 && model->VDIOtransitTime!=0) { + if(here->VDIOqpNode == 0) { + error = CKTmkVolt(ckt, &tmp, here->VDMOSname, "qp"); + if(error) return(error); + here->VDIOqpNode = tmp->number; + } + } else { + here->VDIOqpNode = 0; + } /* macro to make elements with built in test for out of memory */ #define TSTALLOC(ptr,first,second) \ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\ @@ -487,11 +501,20 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\ TSTALLOC(VDMOSTemptcasePtr, VDMOStempNode, VDMOStcaseNode); TSTALLOC(VDMOSTptpPtr, VDMOStNodePrime, VDMOStNodePrime); /* Rthca between tcase and Vsrc */ TSTALLOC(VDMOSTptcasePtr, VDMOStNodePrime, VDMOStcaseNode); - TSTALLOC(VDMOSTcasetpPtr, VDMOStcaseNode, VDMOStNodePrime); + TSTALLOC(VDMOSTcasetpPtr, VDMOStcaseNode, VDMOStNodePrime); TSTALLOC(VDMOSDevTdevTPtr, VDMOSvdevTbranch, VDMOSvdevTbranch); /* Vsrc=cktTemp to gnd */ TSTALLOC(VDMOSDevTtpPtr, VDMOSvdevTbranch, VDMOStNodePrime); TSTALLOC(VDMOSTpdevTPtr, VDMOStNodePrime, VDMOSvdevTbranch); } + + /* rev-rec */ + if (model->VDIOsoftRevRecParamGiven && model->VDIOsoftRevRecParam!=0 && model->VDIOtransitTime!=0) { + TSTALLOC(VDIOqpQpPtr , VDIOqpNode, VDIOqpNode); + TSTALLOC(VDIOqpPosPrimePtr, VDIOqpNode, VDIOposPrimeNode); + TSTALLOC(VDIOqpNegPtr , VDIOqpNode, VDMOSdNode); + TSTALLOC(VDIOposPrimeQpPtr, VDIOposPrimeNode, VDIOqpNode); + TSTALLOC(VDIOnegQpPtr, VDMOSdNode, VDIOqpNode); + } } } return(OK); @@ -538,6 +561,10 @@ VDMOSunsetup(GENmodel *inModel, CKTcircuit *ckt) here->VDMOSvdevTbranch = 0; } + /* rev-rec */ + if (here->VDIOqpNode > 0) + CKTdltNNum(ckt, here->VDIOqpNode); + here->VDIOqpNode = 0; } } return OK; diff --git a/src/spicelib/devices/vdmos/vdmostrun.c b/src/spicelib/devices/vdmos/vdmostrun.c index 1b35dfffe..9d8a3e56f 100644 --- a/src/spicelib/devices/vdmos/vdmostrun.c +++ b/src/spicelib/devices/vdmos/vdmostrun.c @@ -24,6 +24,8 @@ VDMOStrunc(GENmodel *inModel, CKTcircuit *ckt, double *timeStep) CKTterr(here->VDMOSqgs,ckt,timeStep); CKTterr(here->VDMOSqgd,ckt,timeStep); CKTterr(here->VDIOcapCharge,ckt,timeStep); + if (model->VDIOsoftRevRecParam!=0 && here->VDIOtTransitTime!=0) + CKTterr(here->VDIOsrcapCharge,ckt,timeStep); } } return(OK);