diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c
index d0ec09b73..577ef2898 100644
--- a/src/frontend/inpcom.c
+++ b/src/frontend/inpcom.c
@@ -4009,7 +4009,7 @@ static int get_number_terminals(char *c)
char *inst = gettok_instance(&c);
strncpy(nam_buf, inst, sizeof(nam_buf) - 1);
txfree(inst);
- if (strstr(nam_buf, "off") || strchr(nam_buf, '='))
+ if (strstr(nam_buf, "off") || strchr(nam_buf, '=') || strstr(nam_buf, "tnodeout"))
break;
i++;
}
diff --git a/src/spicelib/devices/devsup.c b/src/spicelib/devices/devsup.c
index 4d36f8744..691009c95 100644
--- a/src/spicelib/devices/devsup.c
+++ b/src/spicelib/devices/devsup.c
@@ -620,7 +620,7 @@ http://ltwiki.org/index.php5?title=Undocumented_LTspice#VDMOS:_Breakdown_and_Sub
void
DevCapVDMOS(double vgd, double cgdmin,
double cgdmax, double a, double cgs,
- double *capgs, double *capgd, double *capgb)
+ double *capgs, double *capgd)
{
double s = (cgdmax - cgdmin) / (1 + M_PI / 2);
double y = cgdmax - s;
@@ -629,7 +629,6 @@ DevCapVDMOS(double vgd, double cgdmin,
else
*capgd = 0.5 * (s * atan(a * vgd) + y);
*capgs = 0.5 * cgs;
- *capgb = 0;
}
/* Compute the MOS overlap capacitances as functions of the device
diff --git a/src/spicelib/devices/vdmos/Makefile.am b/src/spicelib/devices/vdmos/Makefile.am
index 0a173abbf..0e8da3cfa 100644
--- a/src/spicelib/devices/vdmos/Makefile.am
+++ b/src/spicelib/devices/vdmos/Makefile.am
@@ -22,6 +22,7 @@ libvdmos_la_SOURCES = \
vdmospar.c \
vdmospzld.c \
vdmosset.c \
+ vdmossoachk.c \
vdmostemp.c \
vdmostrun.c
diff --git a/src/spicelib/devices/vdmos/vdmos.c b/src/spicelib/devices/vdmos/vdmos.c
index afe09e7ac..859d4501f 100644
--- a/src/spicelib/devices/vdmos/vdmos.c
+++ b/src/spicelib/devices/vdmos/vdmos.c
@@ -2,7 +2,7 @@
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1987 Thomas L. Quarles
Modified: 2000 AlansFixes
-VDMOS Model: 2018 Holger Vogt
+VDMOS: 2018 Holger Vogt, 2020 Dietmar Warning
**********/
#include "ngspice/ngspice.h"
@@ -12,35 +12,36 @@ VDMOS Model: 2018 Holger Vogt
#include "ngspice/suffix.h"
IFparm VDMOSpTable[] = { /* parameters */
- IOPU("mu", VDMOS_M, IF_REAL, "Multiplier"),
- IOPU("l", VDMOS_L, IF_REAL, "Length"),
- IOPU("w", VDMOS_W, IF_REAL, "Width"),
- IP("off", VDMOS_OFF, IF_FLAG, "Device initially off"),
- IOPU("icvds", VDMOS_IC_VDS, IF_REAL, "Initial D-S voltage"),
- IOPU("icvgs", VDMOS_IC_VGS, IF_REAL, "Initial G-S voltage"),
- IOPU("temp", VDMOS_TEMP, IF_REAL, "Instance temperature"),
- IOPU("dtemp", VDMOS_DTEMP, IF_REAL, "Instance temperature difference"),
- IP( "ic", VDMOS_IC, IF_REALVEC, "Vector of D-S, G-S voltages"),
+ IOPU("m", VDMOS_M, IF_REAL, "Multiplier"),
+ IOPU("l", VDMOS_L, IF_REAL, "Length"),
+ IOPU("w", VDMOS_W, IF_REAL, "Width"),
+ IP("off", VDMOS_OFF, IF_FLAG, "Device initially off"),
+ IOPU("icvds", VDMOS_IC_VDS, IF_REAL, "Initial D-S voltage"),
+ IOPU("icvgs", VDMOS_IC_VGS, IF_REAL, "Initial G-S voltage"),
+ IOPU("temp", VDMOS_TEMP, IF_REAL, "Instance temperature"),
+ IOPU("dtemp", VDMOS_DTEMP, IF_REAL, "Instance temperature difference"),
+ IP( "ic", VDMOS_IC, IF_REALVEC, "Vector of D-S, G-S voltages"),
- OP( "id", VDMOS_CD, IF_REAL, "Drain current"),
- OP( "is", VDMOS_CS, IF_REAL, "Source current"),
- OP( "ig", VDMOS_CG, IF_REAL, "Gate current "),
- OP( "vgs", VDMOS_VGS, IF_REAL, "Gate-Source voltage"),
- OP( "vds", VDMOS_VDS, IF_REAL, "Drain-Source voltage"),
- OP( "cgs", VDMOS_CAPGS, IF_REAL, "Gate-Source capacitance"),
- OP( "cgd", VDMOS_CAPGD, IF_REAL, "Gate-Drain capacitance"),
- OP( "cds", VDMOS_CAPDS, IF_REAL, "Drain-Source capacitance"),
+ IOP("tnodeout", VDMOS_TNODEOUT, IF_FLAG, "Thermal model switch on/off"),
+
+ OP( "id", VDMOS_CD, IF_REAL, "Drain current"),
+ OP( "is", VDMOS_CS, IF_REAL, "Source current"),
+ OP( "ig", VDMOS_CG, IF_REAL, "Gate current"),
+ OP( "vgs", VDMOS_VGS, IF_REAL, "Gate-Source voltage"),
+ OP( "vds", VDMOS_VDS, IF_REAL, "Drain-Source voltage"),
+ OP( "cgs", VDMOS_CAPGS, IF_REAL, "Gate-Source capacitance"),
+ OP( "cgd", VDMOS_CAPGD, IF_REAL, "Gate-Drain capacitance"),
+ OP( "cds", VDMOS_CAPDS, 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 "),
OPU( "snode", VDMOS_SNODE, IF_INTEGER, "Number of the source node "),
+ OPU( "tempnode", VDMOS_TNODE, IF_INTEGER, "Number of temperature node"),
+ OPU( "tcasenode", VDMOS_TCASE, IF_INTEGER, "Number of 2nd temperature node"),
OPU( "dnodeprime", VDMOS_DNODEPRIME, IF_INTEGER, "Number of int. drain node"),
OPU( "snodeprime", VDMOS_SNODEPRIME, IF_INTEGER, "Number of int. source node "),
- OP( "von", VDMOS_VON, IF_REAL, " "),
- OP( "vdsat", VDMOS_VDSAT, IF_REAL, "Saturation drain voltage"),
- OPU( "sourcevcrit", VDMOS_SOURCEVCRIT, IF_REAL, "Critical source voltage"),
- OPU( "drainvcrit", VDMOS_DRAINVCRIT, IF_REAL, "Critical drain voltage"),
+ OP( "von", VDMOS_VON, IF_REAL, "Device on state voltage"),
OP( "rs", VDMOS_SOURCERESIST, IF_REAL, "Source resistance"),
OPU("sourceconductance", VDMOS_SOURCECONDUCT, IF_REAL, "Conductance of source"),
OP( "rd", VDMOS_DRAINRESIST, IF_REAL, "Drain conductance"),
@@ -54,13 +55,14 @@ IFparm VDMOSpTable[] = { /* parameters */
OPU( "qgs", VDMOS_QGS, IF_REAL, "Gate-Source charge storage"),
OPU( "qgd", VDMOS_QGD, IF_REAL, "Gate-Drain charge storage"),
- OPU( "p", VDMOS_POWER, IF_REAL, "Instaneous power"),
+ OPU( "p", VDMOS_POWER, IF_REAL, "Instantaneous power"),
};
IFparm VDMOSmPTable[] = { /* model parameters */
/* basic device */
OP("type", VDMOS_MOD_TYPE, IF_STRING, "N-channel or P-channel MOS"),
- IOP("vto", VDMOS_MOD_VTO, IF_REAL, "Threshold voltage"),
+ IOP("vto", VDMOS_MOD_VTH, IF_REAL, "Threshold voltage"),
+ IOPR("vth0", VDMOS_MOD_VTH, IF_REAL, "Threshold voltage"),
IOP("kp", VDMOS_MOD_KP, IF_REAL, "Transconductance parameter"),
IOP("phi", VDMOS_MOD_PHI, IF_REAL, "Surface potential"),
IOP("lambda",VDMOS_MOD_LAMBDA,IF_REAL, "Channel length modulation"),
@@ -80,10 +82,17 @@ IFparm VDMOSmPTable[] = { /* model parameters */
IOP("vq", VDMOS_MOD_VQ, IF_REAL, "Quasi saturation voltage fitting parameter"),
IOP("mtriode", VDMOS_MOD_MTRIODE, IF_REAL, "Conductance multiplier in triode region"),
+ /* temperature dependency */
+ IOP( "tcvth", VDMOS_MOD_TCVTH, IF_REAL, "Linear Vth0 temperature coefficient"),
+ IOPR("vtotc", VDMOS_MOD_TCVTH, IF_REAL, "Linear Vth0 temperature coefficient"),
+ IOP( "mu", VDMOS_MOD_MU, IF_REAL, "Exponent of gain temperature dependency"),
+ IOPR("bex", VDMOS_MOD_MU, IF_REAL, "Exponent of gain temperature dependency"),
+ IOP( "texp0", VDMOS_MOD_TEXP0, IF_REAL, "Drain resistance rd0 temperature exponent"),
+ IOP( "texp1", VDMOS_MOD_TEXP1, IF_REAL, "Drain resistance rd1 temperature exponent"),
+
/* weak inversion */
- IOP("subslope", VDMOS_MOD_SUBSLOPE, IF_REAL, "Slope of weak inversion log current versus vgs - vth"),
IOP("subshift", VDMOS_MOD_SUBSHIFT, IF_REAL, "Shift of weak inversion plot on the vgs axis"),
- IOP("ksubthres", VDMOS_MOD_KSUBTHRES, IF_REAL, "Shift of weak inversion plot on the vgs axis"),
+ IOP("ksubthres", VDMOS_MOD_KSUBTHRES, IF_REAL, "Slope of weak inversion log current versus vgs"),
/* body diode */
IOP("bv", VDMOS_MOD_BV, IF_REAL, "Vds breakdown voltage"),
@@ -94,7 +103,7 @@ IFparm VDMOSmPTable[] = { /* model parameters */
IOP("n", VDMOS_MOD_N, IF_REAL, "Body diode emission coefficient"),
IOP("tt", VDMOS_MOD_TT, IF_REAL, "Body diode transit time"),
IOP("eg", VDMOS_MOD_EG, IF_REAL, "Body diode activation energy for temperature effect on Is"),
- IOP("Xti", VDMOS_MOD_XTI, IF_REAL, "Body diode saturation current temperature exponent"),
+ IOP("xti", VDMOS_MOD_XTI, IF_REAL, "Body diode saturation current temperature exponent"),
IOP("is", VDMOS_MOD_IS, IF_REAL, "Body diode saturation current"),
IOP("vj", VDMOS_MOD_VJ, IF_REAL, "Body diode junction potential"),
@@ -108,16 +117,30 @@ IFparm VDMOSmPTable[] = { /* model parameters */
IOPA("cgdmax", VDMOS_MOD_CGDMAX, IF_REAL, "Maximum non-linear G-D capacitance"),
IOPA("a", VDMOS_MOD_A, IF_REAL, "Non-linear Cgd capacitance parameter"),
IOPA("cgs", VDMOS_MOD_CGS, IF_REAL, "Gate-source capacitance"),
+
+/* self heating */
+ IOP("rthjc", VDMOS_MOD_RTHJC, IF_REAL, "Self-heating thermal resistance"),
+ IOP("rthca", VDMOS_MOD_RTHCA, IF_REAL, "Self-heating thermal resistance"),
+ IOP("cthj", VDMOS_MOD_CTHJ, IF_REAL, "Self-heating thermal capacitance"),
+
+/* soa check */
+ IOP("vgs_max", VDMOS_MOD_VGS_MAX, IF_REAL, "maximum voltage G-S branch"),
+ IOP("vgd_max", VDMOS_MOD_VGD_MAX, IF_REAL, "maximum voltage G-D branch"),
+ IOP("vds_max", VDMOS_MOD_VDS_MAX, IF_REAL, "maximum voltage D-S branch"),
+ IOP("vgsr_max", VDMOS_MOD_VGSR_MAX, IF_REAL, "maximum voltage G-S branch"),
+ IOP("vgdr_max", VDMOS_MOD_VGDR_MAX, IF_REAL, "maximum voltage G-D branch"),
};
char *VDMOSnames[] = {
"Drain",
"Gate",
- "Source"
+ "Source",
+ "Temp",
+ "Tcase"
};
-int VDMOSnSize = NUMELEMS(VDMOSnames);
-int VDMOSpTSize = NUMELEMS(VDMOSpTable);
-int VDMOSmPTSize = NUMELEMS(VDMOSmPTable);
-int VDMOSiSize = sizeof(VDMOSinstance);
-int VDMOSmSize = sizeof(VDMOSmodel);
+int VDMOSnSize = NUMELEMS(VDMOSnames);
+int VDMOSpTSize = NUMELEMS(VDMOSpTable);
+int VDMOSmPTSize = NUMELEMS(VDMOSmPTable);
+int VDMOSiSize = sizeof(VDMOSinstance);
+int VDMOSmSize = sizeof(VDMOSmodel);
diff --git a/src/spicelib/devices/vdmos/vdmosacld.c b/src/spicelib/devices/vdmos/vdmosacld.c
index 93a9f116c..6a5276372 100644
--- a/src/spicelib/devices/vdmos/vdmosacld.c
+++ b/src/spicelib/devices/vdmos/vdmosacld.c
@@ -2,6 +2,7 @@
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Thomas L. Quarles
Modified: 2000 AlansFixes
+VDMOS: 2018 Holger Vogt, 2020 Dietmar Warning
**********/
/*
*/
@@ -20,15 +21,21 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt)
VDMOSinstance *here;
int xnrm;
int xrev;
- double xgs;
- double xgd;
- double capgs;
- double capgd;
+ double xgs, xcgT;
+ double xgd, xcdT;
+ double capgs, cgT;
+ double capgd, cdT;
+ double cTt, gTtt, gTtg, gTtdp, gTtsp;
+ double GmT;
+ double xcsT, xcTt;
+
+ register int selfheat;
for( ; model != NULL; model = VDMOSnextModel(model)) {
for(here = VDMOSinstances(model); here!= NULL;
here = VDMOSnextInstance(here)) {
-
+
+ selfheat = (here->VDMOStnodeoutGiven) && (model->VDMOSrthjc != 0.0);
if (here->VDMOSmode < 0) {
xnrm=0;
xrev=1;
@@ -36,6 +43,27 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt)
xnrm=1;
xrev=0;
}
+
+ if (here->VDMOSmode >= 0) {
+ GmT = model->VDMOStype * here->VDMOSgmT;
+ cgT = model->VDMOStype * here->VDMOScgT;
+ cdT = model->VDMOStype * here->VDMOScdT;
+ cTt = model->VDMOScthj;
+ gTtg = here->VDMOSgtempg;
+ gTtdp = here->VDMOSgtempd;
+ gTtt = here->VDMOSgtempT;
+ gTtsp = - (gTtg + gTtdp);
+ } else {
+ GmT = -model->VDMOStype * here->VDMOSgmT;
+ cgT = -model->VDMOStype * here->VDMOScgT;
+ cdT = -model->VDMOStype * here->VDMOScdT;
+ cTt = -model->VDMOScthj;
+ gTtg = -here->VDMOSgtempg;
+ gTtdp = -here->VDMOSgtempd;
+ gTtt = -here->VDMOSgtempT;
+ gTtsp = gTtg + gTtdp;
+ }
+
/*
* VDMOS cap model parameters
*/
@@ -46,7 +74,12 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt)
xgs = capgs * ckt->CKTomega;
xgd = capgd * ckt->CKTomega;
- /* bulk diode */
+ xcgT = cgT * ckt->CKTomega;
+ xcdT = cdT * ckt->CKTomega;
+ xcsT = -(cgT + cdT) * ckt->CKTomega;
+ xcTt = cTt * ckt->CKTomega;
+
+ /* body diode */
double gspr, geq, xceq;
gspr = here->VDIOtConductance;
geq = *(ckt->CKTstate0 + here->VDIOconduct);
@@ -62,6 +95,7 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt)
*(here->VDMOSGPspPtr +1) -= xgs;
*(here->VDMOSDPgpPtr +1) -= xgd;
*(here->VDMOSSPgpPtr +1) -= xgs;
+
*(here->VDMOSDdPtr) += here->VDMOSdrainConductance;
*(here->VDMOSSsPtr) += here->VDMOSsourceConductance;
*(here->VDMOSDPdpPtr) += here->VDMOSdrainConductance+
@@ -78,10 +112,10 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt)
*(here->VDMOSSPdpPtr) -= here->VDMOSgds+xrev*(here->VDMOSgm);
/* gate resistor */
*(here->VDMOSGgPtr) += (here->VDMOSgateConductance);
- *(here->VDMOSGPgpPtr) += (here->VDMOSgateConductance)/* + ?? FIXME */;
+ *(here->VDMOSGPgpPtr) += (here->VDMOSgateConductance);
*(here->VDMOSGgpPtr) -= here->VDMOSgateConductance;
*(here->VDMOSGPgPtr) -= here->VDMOSgateConductance;
- /* bulk diode */
+ /* body diode */
*(here->VDMOSSsPtr) += gspr;
*(here->VDMOSDdPtr) += geq;
*(here->VDMOSDdPtr +1) += xceq;
@@ -93,6 +127,29 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt)
*(here->VDIORPsPtr) -= gspr;
*(here->VDIORPdPtr) -= geq;
*(here->VDIORPdPtr +1) -= xceq;
+ if (selfheat)
+ {
+ *(here->VDMOSDPtempPtr) += GmT;
+ *(here->VDMOSSPtempPtr) += -GmT;
+
+ *(here->VDMOSTemptempPtr) += gTtt + 1/model->VDMOSrthjc;
+ *(here->VDMOSTempgpPtr) += gTtg;
+ *(here->VDMOSTempdpPtr) += gTtdp;
+ *(here->VDMOSTempspPtr) += gTtsp;
+ *(here->VDMOSTemptcasePtr) += -1/model->VDMOSrthjc;
+ *(here->VDMOSTcasetempPtr) += -1/model->VDMOSrthjc;
+ *(here->VDMOSTcasetcasePtr) += 1/model->VDMOSrthjc + 1/model->VDMOSrthca;
+ *(here->VDMOSTptpPtr) += 1/model->VDMOSrthca;
+ *(here->VDMOSTptcasePtr) += -1/model->VDMOSrthca;
+ *(here->VDMOSTcasetpPtr) += -1/model->VDMOSrthca;
+ *(here->VDMOSCktTtpPtr) += 1.0;
+ *(here->VDMOSTpcktTPtr) += 1.0;
+
+ *(here->VDMOSTemptempPtr + 1) += xcTt;
+ *(here->VDMOSDPtempPtr + 1) += xcdT;
+ *(here->VDMOSSPtempPtr + 1) += xcsT;
+ *(here->VDMOSGPtempPtr + 1) += xcgT;
+ }
}
}
return(OK);
diff --git a/src/spicelib/devices/vdmos/vdmosask.c b/src/spicelib/devices/vdmos/vdmosask.c
index c7bc97b28..597192fc3 100644
--- a/src/spicelib/devices/vdmos/vdmosask.c
+++ b/src/spicelib/devices/vdmos/vdmosask.c
@@ -43,19 +43,22 @@ VDMOSask(CKTcircuit *ckt, GENinstance *inst, int which, IFvalue *value,
return(OK);
case VDMOS_L:
value->rValue = here->VDMOSl;
- return(OK);
+ return(OK);
case VDMOS_W:
value->rValue = here->VDMOSw;
- return(OK);
+ return(OK);
case VDMOS_OFF:
- value->rValue = here->VDMOSoff;
- return(OK);
+ value->iValue = here->VDMOSoff;
+ return(OK);
+ case VDMOS_TNODEOUT:
+ value->iValue = here->VDMOStnodeout;
+ return(OK);
case VDMOS_IC_VDS:
value->rValue = here->VDMOSicVDS;
- return(OK);
+ return(OK);
case VDMOS_IC_VGS:
value->rValue = here->VDMOSicVGS;
- return(OK);
+ return(OK);
case VDMOS_DNODE:
value->iValue = here->VDMOSdNode;
return(OK);
@@ -65,6 +68,9 @@ VDMOSask(CKTcircuit *ckt, GENinstance *inst, int which, IFvalue *value,
case VDMOS_SNODE:
value->iValue = here->VDMOSsNode;
return(OK);
+ case VDMOS_TNODE:
+ value->iValue = here->VDMOStempNode;
+ return(OK);
case VDMOS_SNODEPRIME:
value->iValue = here->VDMOSsNodePrime;
return(OK);
@@ -89,15 +95,6 @@ VDMOSask(CKTcircuit *ckt, GENinstance *inst, int which, IFvalue *value,
case VDMOS_VON:
value->rValue = here->VDMOSvon;
return(OK);
- case VDMOS_VDSAT:
- value->rValue = here->VDMOSvdsat;
- return(OK);
- case VDMOS_SOURCEVCRIT:
- value->rValue = here->VDMOSsourceVcrit;
- return(OK);
- case VDMOS_DRAINVCRIT:
- value->rValue = here->VDMOSdrainVcrit;
- return(OK);
case VDMOS_CD:
value->rValue = here->VDMOScd;
return(OK);
diff --git a/src/spicelib/devices/vdmos/vdmosdefs.h b/src/spicelib/devices/vdmos/vdmosdefs.h
index 87644bbb7..6aaee1645 100644
--- a/src/spicelib/devices/vdmos/vdmosdefs.h
+++ b/src/spicelib/devices/vdmos/vdmosdefs.h
@@ -2,6 +2,7 @@
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Thomas L. Quarles
Modified: 2000 AlansFixes
+VDMOS: 2018 Holger Vogt, 2020 Dietmar Warning
**********/
#ifndef VDMOS
@@ -41,10 +42,15 @@ typedef struct sVDMOSinstance {
const int VDMOSdNode; /* number of the gate node of the mosfet */
const int VDMOSgNode; /* number of the gate node of the mosfet */
const int VDMOSsNode; /* number of the source node of the mosfet */
+ const int VDMOStempNode; /* number of the temperature node of the mosfet */
+ const int VDMOStcaseNode; /* number of the 2nd temperature node of the mosfet */
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 */
+ 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 VDMOSvcktTbranch; /* equation number of branch equation added for cktTemp source */
double VDMOSm; /* parallel device multiplier */
@@ -52,42 +58,37 @@ typedef struct sVDMOSinstance {
double VDMOSw; /* the width of the channel region */
double VDMOSsourceConductance; /*conductance of source(or 0):set in setup*/
double VDMOSdrainConductance; /*conductance of drain(or 0):set in setup*/
+ double VDMOSdrainResistance; /*resistance of drain(or 0): set in temp*/
+ double VDMOSqsResistance; /*resistance of drain: set in temp*/
double VDMOSgateConductance; /*conductance of gate(or 0):set in setup*/
double VDMOSdsConductance; /*conductance of drain to source:set in setup*/
double VDMOStemp; /* operating temperature of this instance */
double VDMOSdtemp; /* operating temperature of the instance relative to circuit temperature*/
+ int VDMOStnodeout; /* flag indicate self heating on */
double VDMOStTransconductance; /* temperature corrected transconductance*/
double VDMOStPhi; /* temperature corrected Phi */
- double VDMOStVto; /* temperature corrected Vto */
- double VDMOStSatCur; /* temperature corrected saturation Cur. */
+ double VDMOStVth; /* temperature corrected Vth */
double VDMOSicVDS; /* initial condition D-S voltage */
double VDMOSicVGS; /* initial condition G-S voltage */
double VDMOSvon;
double VDMOSvdsat;
- double VDMOSsourceVcrit; /* Vcrit for pos. vds */
- double VDMOSdrainVcrit; /* Vcrit for pos. vds */
double VDMOScd;
double VDMOSgm;
double VDMOSgds;
- double VDMOSf2d;
- double VDMOSf3d;
- double VDMOSf4d;
- double VDMOSf2s;
- double VDMOSf3s;
- double VDMOSf4s;
double VDIOcap;
- double VDIOtSatCur; /* temperature corrected saturation Cur. density*/
+ double VDIOtSatCur; /* temperature corrected saturation Cur. density*/
double VDIOinitCond;
double VDIOtVcrit;
+ double VDIOconductance;
double VDIOtConductance;
double VDIOtBrkdwnV;
double VDIOtJctCap;
double VDIOtDepCap; /* temperature adjusted transition point in */
- /* the cureve matching Fc * Vj */
- double VDIOtJctPot; /* temperature corrected Bulk potential */
+ /* the curve matching Fc * Vj */
+ double VDIOtJctPot; /* temperature corrected junction potential */
double VDIOtGradingCoeff;
double VDIOtTransitTime;
@@ -95,6 +96,16 @@ typedef struct sVDMOSinstance {
double VDIOtF2;
double VDIOtF3;
+ double VDMOSTempSH; /* for portability of SH temp to noise analysis */
+
+ double VDMOSgmT;
+ double VDMOSgtempg;
+ double VDMOSgtempd;
+ double VDMOSgtempT;
+ double VDMOScgT;
+ double VDMOScdT;
+ double VDMOScth; /* current alias power */
+
/*
* naming convention:
* x = vgs
@@ -135,21 +146,20 @@ typedef struct sVDMOSinstance {
int VDMOSmode; /* device mode : 1 = normal, -1 = inverse */
-
unsigned VDMOSoff:1; /* non-zero to indicate device is off for dc analysis*/
unsigned VDMOStempGiven :1; /* instance temperature specified */
unsigned VDMOSdtempGiven :1; /* instance delta temperature specified */
unsigned VDMOSmGiven :1;
unsigned VDMOSlGiven :1;
unsigned VDMOSwGiven :1;
- unsigned VDMOSdNodePrimeSet :1;
- unsigned VDMOSsNodePrimeSet :1;
+ unsigned VDMOSdNodePrimeSet :1;
+ unsigned VDMOSsNodePrimeSet :1;
unsigned VDMOSicVDSGiven :1;
unsigned VDMOSicVGSGiven :1;
- unsigned VDMOSvonGiven :1;
+ unsigned VDMOStnodeoutGiven : 1; /* flag indicate self heating on */
+ unsigned VDMOSvonGiven : 1;
unsigned VDMOSvdsatGiven :1;
- unsigned VDMOSmodeGiven :1;
-
+ unsigned VDMOSmodeGiven :1;
double *VDMOSDdPtr; /* pointer to sparse matrix element at
* (Drain node,drain node) */
@@ -201,7 +211,7 @@ typedef struct sVDMOSinstance {
* (source node, drain node) */
double *VDMOSSdPtr; /* pointer to sparse matrix element at
* (drain node, source node) */
- /* bulk diode */
+ /* body diode */
double *VDIORPdPtr; /* pointer to sparse matrix element at
* (diode prime node, drain node) */
double *VDIODrpPtr; /* pointer to sparse matrix element at
@@ -212,32 +222,57 @@ typedef struct sVDMOSinstance {
* (source node, diode prime node) */
double *VDIORPsPtr; /* pointer to sparse matrix element at
* (diode prime node, source node) */
+ /* self heating */
+ double *VDMOSTemptempPtr;
+ double *VDMOSTempdpPtr;
+ double *VDMOSTempspPtr;
+ double *VDMOSTempgpPtr;
+ double *VDMOSGPtempPtr;
+ double *VDMOSDPtempPtr;
+ double *VDMOSSPtempPtr;
+
+ double *VDMOSTcasetcasePtr; /* for Rthjc */
+ double *VDMOSTcasetempPtr;
+ double *VDMOSTemptcasePtr;
+
+ double *VDMOSTptpPtr; /* for Rthca */
+ double *VDMOSTptcasePtr;
+ double *VDMOSTcasetpPtr;
+
+ double *VDMOSCktTcktTPtr; /* for VcktTemp */
+ double *VDMOSCktTtpPtr;
+ double *VDMOSTpcktTPtr;
} VDMOSinstance ;
#define VDMOSvgs VDMOSstates+ 0 /* gate-source voltage */
#define VDMOSvds VDMOSstates+ 1 /* drain-source voltage */
+#define VDMOSdeltemp VDMOSstates+ 2
-#define VDMOScapgs VDMOSstates+2 /* gate-source capacitor value */
-#define VDMOSqgs VDMOSstates+ 3 /* gate-source capacitor charge */
-#define VDMOScqgs VDMOSstates+ 4 /* gate-source capacitor current */
+#define VDMOScapgs VDMOSstates+3 /* gate-source capacitor value */
+#define VDMOSqgs VDMOSstates+ 4 /* gate-source capacitor charge */
+#define VDMOScqgs VDMOSstates+ 5 /* gate-source capacitor current */
-#define VDMOScapgd VDMOSstates+ 5 /* gate-drain capacitor value */
-#define VDMOSqgd VDMOSstates+ 6 /* gate-drain capacitor charge */
-#define VDMOScqgd VDMOSstates+ 7 /* gate-drain capacitor current */
+#define VDMOScapgd VDMOSstates+ 6 /* gate-drain capacitor value */
+#define VDMOSqgd VDMOSstates+ 7 /* gate-drain capacitor charge */
+#define VDMOScqgd VDMOSstates+ 8 /* gate-drain capacitor current */
-#define VDIOvoltage VDMOSstates+ 8
-#define VDIOcurrent VDMOSstates+ 9
-#define VDIOconduct VDMOSstates+ 10
-#define VDIOcapCharge VDMOSstates+ 11
-#define VDIOcapCurrent VDMOSstates+ 12
+#define VDIOvoltage VDMOSstates+ 9
+#define VDIOcurrent VDMOSstates+ 10
+#define VDIOconduct VDMOSstates+ 11
+#define VDIOcapCharge VDMOSstates+ 12
+#define VDIOcapCurrent VDMOSstates+ 13
-#define VDMOSnumStates 13
+#define VDMOScapth VDMOSstates+ 14 /* thermal capacitor value */
+#define VDMOSqth VDMOSstates+ 15 /* thermal capacitor charge */
+#define VDMOScqth VDMOSstates+ 16 /* thermal capacitor current */
+
+#define VDMOSnumStates 17
/* per model data */
- /* NOTE: parameters marked 'input - use xxxx' are paramters for
+ /* NOTE: parameters marked 'input - use xxxx' are parameters for
* which a temperature correction is applied in VDMOStemp, thus
* the VDMOSxxxx value in the per-instance structure should be used
* instead in all calculations
@@ -262,7 +297,7 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */
double VDMOSqsVoltage;
double VDMOStransconductance; /* input - use tTransconductance */
double VDMOSoxideCapFactor;
- double VDMOSvt0; /* input - use tVto */
+ double VDMOSvth0; /* input - use tVth */
double VDMOSphi; /* input - use tPhi */
double VDMOSlambda;
double VDMOStheta;
@@ -273,34 +308,44 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */
double VDMOScgdmax;
double VDMOSa;
double VDMOScgs;
- double VDMOSsubsl;
double VDMOSsubshift;
double VDMOSksubthres;
double VDMOSmtr;
- /* bulk diode */
+ /* body diode */
double VDIOjunctionCap; /* input - use tCj */
- double VDIOjunctionPot; /* input - use tBulkPot */
+ double VDIOjunctionPot; /* input - use tJctPot */
double VDIOdepletionCapCoeff;
double VDIOjctSatCur; /* input - use tSatCur */
- double VDMOSDbv;
- double VDMOSDibv;
+ double VDMOSbv;
+ double VDMOSibv;
double VDIObrkdEmissionCoeff;
double VDIOresistance;
- double VDIOresistTemp1;
- double VDIOresistTemp2;
- double VDIOconductance;
double VDMOSrds;
- double VDMOSDn;
+ double VDMOSn;
double VDIOtransitTime;
double VDIOtranTimeTemp1;
double VDIOtranTimeTemp2;
- double VDMOSDeg;
- double VDMOSDxti;
+ double VDMOSeg;
+ double VDMOSxti;
double VDIOgradCoeff;
double VDIOgradCoeffTemp1;
double VDIOgradCoeffTemp2;
+ double VDMOSrthjc;
+ double VDMOSrthca;
+ double VDMOScthj;
+ double VDMOSmu;
+ double VDMOStexp0;
+ double VDMOStexp1;
+ double VDMOStcvth;
+
+ double VDMOSvgsMax;
+ double VDMOSvgdMax;
+ double VDMOSvdsMax;
+ double VDMOSvgsrMax;
+ double VDMOSvgdrMax;
+
unsigned VDMOStypeGiven :1;
unsigned VDIOjctSatCurGiven :1;
unsigned VDMOSdrainResistanceGiven :1;
@@ -310,7 +355,7 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */
unsigned VDMOSqsVoltageGiven :1;
unsigned VDMOSqsGiven :1;
unsigned VDMOStransconductanceGiven :1;
- unsigned VDMOSvt0Given :1;
+ unsigned VDMOSvth0Given :1;
unsigned VDIOgradCoeffGiven :1;
unsigned VDIOdepletionCapCoeffGiven :1;
unsigned VDMOSphiGiven :1;
@@ -324,23 +369,35 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */
unsigned VDMOScgdmaxGiven :1;
unsigned VDMOScgsGiven :1;
unsigned VDMOSaGiven :1;
- unsigned VDMOSsubslGiven :1;
unsigned VDMOSsubshiftGiven :1;
unsigned VDMOSksubthresGiven :1;
unsigned VDMOSmtrGiven :1;
- unsigned VDMOSDbvGiven :1;
- unsigned VDMOSDibvGiven :1;
+ unsigned VDMOSbvGiven :1;
+ unsigned VDMOSibvGiven :1;
unsigned VDIOjunctionCapGiven :1;
unsigned VDIOjunctionPotGiven :1;
unsigned VDIObrkdEmissionCoeffGiven :1;
unsigned VDIOresistanceGiven :1;
unsigned VDMOSrdsGiven :1;
- unsigned VDMOSDnGiven :1;
+ unsigned VDMOSnGiven :1;
unsigned VDIOtransitTimeGiven :1;
- unsigned VDMOSDegGiven :1;
- unsigned VDMOSDxtiGiven :1;
+ unsigned VDMOSegGiven :1;
+ unsigned VDMOSxtiGiven :1;
+ unsigned VDMOSrthjcGiven :1;
+ unsigned VDMOSrthcaGiven :1;
+ unsigned VDMOScthjGiven :1;
+ unsigned VDMOSmuGiven :1;
+ unsigned VDMOStexp0Given :1;
+ unsigned VDMOStexp1Given :1;
+ unsigned VDMOStcvthGiven :1;
+
+ unsigned VDMOSvgsMaxGiven :1;
+ unsigned VDMOSvgdMaxGiven :1;
+ unsigned VDMOSvdsMaxGiven :1;
+ unsigned VDMOSvgsrMaxGiven :1;
+ unsigned VDMOSvgdrMaxGiven :1;
} VDMOSmodel;
#ifndef NMOS
@@ -362,11 +419,12 @@ enum {
VDMOS_TEMP,
VDMOS_M,
VDMOS_DTEMP,
+ VDMOS_TNODEOUT,
};
-/* model paramerers */
+/* model parameters */
enum {
- VDMOS_MOD_VTO = 101,
+ VDMOS_MOD_VTH = 101,
VDMOS_MOD_KP,
VDMOS_MOD_PHI,
VDMOS_MOD_LAMBDA,
@@ -394,7 +452,6 @@ enum {
VDMOS_MOD_CGS,
VDMOS_MOD_RB,
VDMOS_MOD_MTRIODE,
- VDMOS_MOD_SUBSLOPE,
VDMOS_MOD_SUBSHIFT,
VDMOS_MOD_KSUBTHRES,
VDMOS_MOD_BV,
@@ -405,6 +462,18 @@ enum {
VDMOS_MOD_TT,
VDMOS_MOD_EG,
VDMOS_MOD_XTI,
+ VDMOS_MOD_RTHJC,
+ VDMOS_MOD_RTHCA,
+ VDMOS_MOD_CTHJ,
+ VDMOS_MOD_MU,
+ VDMOS_MOD_TEXP0,
+ VDMOS_MOD_TEXP1,
+ VDMOS_MOD_TCVTH,
+ VDMOS_MOD_VGS_MAX,
+ VDMOS_MOD_VGD_MAX,
+ VDMOS_MOD_VDS_MAX,
+ VDMOS_MOD_VGSR_MAX,
+ VDMOS_MOD_VGDR_MAX,
};
/* device questions */
@@ -415,14 +484,13 @@ enum {
VDMOS_DNODE,
VDMOS_GNODE,
VDMOS_SNODE,
+ VDMOS_TNODE,
+ VDMOS_TCASE,
VDMOS_DNODEPRIME,
VDMOS_SNODEPRIME,
VDMOS_SOURCECONDUCT,
VDMOS_DRAINCONDUCT,
VDMOS_VON,
- VDMOS_VDSAT,
- VDMOS_SOURCEVCRIT,
- VDMOS_DRAINVCRIT,
VDMOS_CD,
VDMOS_GM,
VDMOS_GDS,
diff --git a/src/spicelib/devices/vdmos/vdmosdset.c b/src/spicelib/devices/vdmos/vdmosdset.c
index 555a41496..6ffa1b902 100644
--- a/src/spicelib/devices/vdmos/vdmosdset.c
+++ b/src/spicelib/devices/vdmos/vdmosdset.c
@@ -21,8 +21,7 @@ VDMOSdSetup(GENmodel *inModel, CKTcircuit *ckt)
VDMOSmodel *model = (VDMOSmodel *) inModel;
VDMOSinstance *here;
double Beta;
- double DrainSatCur;
- double SourceSatCur;
+ double OxideCap;
double gm;
double gds;
double vgst;
@@ -52,11 +51,10 @@ VDMOSdSetup(GENmodel *inModel, CKTcircuit *ckt)
vt = CONSTKoverQ * here->VDMOStemp;
- DrainSatCur = here->VDMOSm * here->VDMOStSatCur;
- SourceSatCur = here->VDMOSm * here->VDMOStSatCur;
+ Beta = here->VDMOStTransconductance;
- Beta = here->VDMOStTransconductance * here->VDMOSm *
- here->VDMOSw/here->VDMOSl;
+ OxideCap = model->VDMOSoxideCapFactor * here->VDMOSl *
+ here->VDMOSm * here->VDMOSw;
vgs = model->VDMOStype * (
*(ckt->CKTrhsOld+here->VDMOSgNode) -
@@ -84,7 +82,7 @@ VDMOSdSetup(GENmodel *inModel, CKTcircuit *ckt)
/*
* 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
+ * charges associated with the gate and channel for
* mosfets
*
*/
@@ -93,59 +91,50 @@ VDMOSdSetup(GENmodel *inModel, CKTcircuit *ckt)
* it is obvious that they can be made global
*/
{
- double betap;
+ double von = here->VDMOStVth * model->VDMOStype;
+ vgst = (here->VDMOSmode == 1 ? vgs : vgd) - von;
+ vdsat = MAX(vgst, 0);
+ double slope = model->VDMOSksubthres;
+ double lambda = model->VDMOSlambda;
+ double theta = model->VDMOStheta;
+ double shift = model->VDMOSsubshift;
+ double mtr = model->VDMOSmtr;
- vgst=(here->VDMOSmode==1?vgs:vgd);
- vdsat=MAX(vgst,0);
+ /* scale vds with mtr (except with lambda) */
+ double vdss = vds*mtr*here->VDMOSmode;
+ double t0 = 1 + lambda*vds;
+ double t1 = 1 + theta*vgs;
+ double betap = Beta*t0/t1;
+ double dbetapdvgs = -Beta*theta*t0/(t1*t1);
+ double dbetapdvds = Beta*lambda/t1;
- if (vgst <= 0) {
- /*
- * cutoff region
- */
- /* cdrain = 0 */
- gm=0;
- gds=0;
- gm2=gds2=0;
- gmds=0;
- gm3=gds3=0;
- gm2ds=gmds2=0;
- } else {
- /*
- * saturation region
- */
+ double t2 = exp((vgst-shift)/slope);
+ vgst = slope * log(1 + t2);
+ double dvgstdvgs = t2/(t2+1);
- betap=Beta*(1+model->VDMOSlambda*(vds*here->VDMOSmode));
- /* cdrain = betap * vgst * vgst * 0.5; */
- if (vgst <= (vds*here->VDMOSmode)){
- gm=betap*vgst;
- gds=model->VDMOSlambda*Beta*vgst*vgst*.5;
+ if (vgst <= vdss) {
+ /* saturation region */
+ gm = betap*vgst*dvgstdvgs + 0.5*dbetapdvgs*vgst*vgst;
+ gds = .5*dbetapdvds*vgst*vgst;
gm2 = betap;
gds2 = 0;
- gmds = vgst*model->VDMOSlambda*Beta;
+ gmds = Beta*lambda*vgst;
gm3 = 0;
gds3 = 0;
- gm2ds = Beta * model->VDMOSlambda;
+ gm2ds = Beta*lambda;
gmds2 = 0;
-
- } else {
- /*
- * linear region
- */
- /* cdrain = betap * vds * (vgst - vds/2); */
- gm=betap*(vds*here->VDMOSmode);
- gds= Beta * model->VDMOSlambda*(vgst*
- vds*here->VDMOSmode - vds*vds*0.5) +
- betap*(vgst - vds*here->VDMOSmode);
+ }
+ else {
+ /* linear region */
+ gm = betap*vdss*dvgstdvgs + vdss*dbetapdvgs*(vgst-.5*vdss);
+ gds = vdss*dbetapdvds*(vgst-.5*vdss) + betap*mtr*(vgst-.5*vdss) - .5*vdss*betap*mtr;
gm2 = 0;
- gds2 = 2*Beta * model->VDMOSlambda*(vgst -
- vds*here->VDMOSmode) - betap;
- gmds = Beta * model->VDMOSlambda* vds *
- here->VDMOSmode + betap;
+ gds2 = 2*Beta * lambda*(vgst - vds*here->VDMOSmode) - betap;
+ gmds = Beta * lambda * vds * here->VDMOSmode + betap;
gm3=0;
- gds3 = -Beta*model->VDMOSlambda*3.;
+ gds3 = -Beta*lambda*3.;
gm2ds=0;
- gmds2 = 2*model->VDMOSlambda*Beta;
- }
+ gmds2 = 2*lambda*Beta;
}
/*
* finished
@@ -156,15 +145,6 @@ VDMOSdSetup(GENmodel *inModel, CKTcircuit *ckt)
/*
* COMPUTE EQUIVALENT DRAIN CURRENT SOURCE
*/
- /*
- * 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
- */
/*
* meyer's capacitor model
*/
@@ -180,7 +160,6 @@ VDMOSdSetup(GENmodel *inModel, CKTcircuit *ckt)
* expressions for the charge are available
*/
-
{
double phi;
@@ -191,7 +170,7 @@ VDMOSdSetup(GENmodel *inModel, CKTcircuit *ckt)
/* von, vgst and vdsat have already been adjusted for
possible source-drain interchange */
phi = here->VDMOStPhi;
- cox = 0;/*FIXME: can we do disto without knowing the oxide thickness?*/
+ cox = OxideCap; /*FIXME: using a guess for the oxide thickness of 1e-07 in vdmostemp.c */
lcapgs2=lcapgs3=lcapgd2=lcapgd3=0;
if (vgst <= 0) {
lcapgs2 = cox/(3*phi);
diff --git a/src/spicelib/devices/vdmos/vdmosext.h b/src/spicelib/devices/vdmos/vdmosext.h
index c3c442adb..877768590 100644
--- a/src/spicelib/devices/vdmos/vdmosext.h
+++ b/src/spicelib/devices/vdmos/vdmosext.h
@@ -20,3 +20,4 @@ extern int VDMOSconvTest(GENmodel*,CKTcircuit*);
extern int VDMOSdisto(int,GENmodel*,CKTcircuit*);
extern int VDMOSnoise(int,int,GENmodel*,CKTcircuit*,Ndata*,double*);
extern int VDMOSdSetup(GENmodel*,CKTcircuit*);
+extern int VDMOSsoaCheck(CKTcircuit *, GENmodel *);
diff --git a/src/spicelib/devices/vdmos/vdmosinit.c b/src/spicelib/devices/vdmos/vdmosinit.c
index 4fa8665a3..e0499c659 100644
--- a/src/spicelib/devices/vdmos/vdmosinit.c
+++ b/src/spicelib/devices/vdmos/vdmosinit.c
@@ -58,7 +58,7 @@ SPICEdev VDMOSinfo = {
.DEVsenTrunc = NULL,
.DEVdisto = VDMOSdisto,
.DEVnoise = VDMOSnoise,
- .DEVsoaCheck = NULL,
+ .DEVsoaCheck = VDMOSsoaCheck,
.DEVinstSize = &VDMOSiSize,
.DEVmodSize = &VDMOSmSize,
diff --git a/src/spicelib/devices/vdmos/vdmosload.c b/src/spicelib/devices/vdmos/vdmosload.c
index 11c2a9ed1..55ff97a41 100644
--- a/src/spicelib/devices/vdmos/vdmosload.c
+++ b/src/spicelib/devices/vdmos/vdmosload.c
@@ -2,7 +2,7 @@
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Thomas L. Quarles
Modified: 2000 AlansFixes
-VDMOS: 2018 Holger Vogt
+VDMOS: 2018 Holger Vogt, 2020 Dietmar Warning
**********/
#include "ngspice/ngspice.h"
@@ -14,9 +14,35 @@ VDMOS: 2018 Holger Vogt
#include "ngspice/sperror.h"
#include "ngspice/suffix.h"
+/* VDMOSlimitlog(deltemp, deltemp_old, LIM_TOL, check)
+ * Logarithmic damping the per-iteration change of deltemp beyond LIM_TOL.
+ */
static double
-cweakinv2(double sl, double shift, double vgst, double vds, double lambda, double beta, double vt, double mtr, double theta);
-
+VDMOSlimitlog(
+ double deltemp,
+ double deltemp_old,
+ double LIM_TOL,
+ int *check)
+{
+ *check = 0;
+ if (isnan (deltemp) || isnan (deltemp_old))
+ {
+ fprintf(stderr, "Alberto says: YOU TURKEY! The limiting function received NaN.\n");
+ fprintf(stderr, "New prediction returns to 0.0!\n");
+ deltemp = 0.0;
+ *check = 1;
+ }
+ /* Logarithmic damping of deltemp beyond LIM_TOL */
+ if (deltemp > deltemp_old + LIM_TOL) {
+ deltemp = deltemp_old + LIM_TOL + log10((deltemp-deltemp_old)/LIM_TOL);
+ *check = 1;
+ }
+ else if (deltemp < deltemp_old - LIM_TOL) {
+ deltemp = deltemp_old - LIM_TOL - log10((deltemp_old-deltemp)/LIM_TOL);
+ *check = 1;
+ }
+ return deltemp;
+}
int
VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
@@ -27,8 +53,6 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
VDMOSmodel *model = (VDMOSmodel *)inModel;
VDMOSinstance *here;
double Beta;
- double DrainSatCur;
- double SourceSatCur;
double arg;
double cdhat;
double cdrain;
@@ -55,14 +79,18 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
#ifndef PREDICTOR
double xfact = 0.0;
#endif
- int xnrm;
- int xrev;
+ int xnrm, xrev;
double capgs = 0.0; /* total gate-source capacitance */
double capgd = 0.0; /* total gate-drain capacitance */
- int Check;
+ double capth = 0.0; /* total thermal capacitance */
+ int Check_mos, Check_diode;
int error;
- double CGBdummy;
+ register int selfheat;
+ double rd0T, rd1T, dBeta_dT, drd0T_dT, drd1T_dT, dIds_dT;
+ double deldelTemp, delTemp, delTemp1, Temp, Vds, Vgs;
+ double ceqqth=0.0;
+ double GmT, gTtg, gTtdp, gTtt, gTtsp, gcTt=0.0;
/* loop through all the VDMOS device models */
for (; model != NULL; model = VDMOSnextModel(model)) {
@@ -76,34 +104,60 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
for (here = VDMOSinstances(model); here != NULL;
here = VDMOSnextInstance(here)) {
+ selfheat = (here->VDMOStnodeoutGiven) && (model->VDMOSrthjc != 0.0);
+ if (selfheat)
+ Check_mos = 1;
+ else
+ Check_mos = 0;
+
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;
+ delTemp = 0.0;
+ if ((ckt->CKTmode & MODEINITSMSIG)) {
+ vgs = *(ckt->CKTstate0 + here->VDMOSvgs);
+ vds = *(ckt->CKTstate0 + here->VDMOSvds);
+ delTemp = *(ckt->CKTstate0 + here->VDMOSdeltemp);
+ } else if ((ckt->CKTmode & MODEINITTRAN)) {
+ vgs = *(ckt->CKTstate1 + here->VDMOSvgs);
+ vds = *(ckt->CKTstate1 + here->VDMOSvds);
+ delTemp = *(ckt->CKTstate1 + here->VDMOSdeltemp);
+ } else if ((ckt->CKTmode & MODEINITJCT) && !here->VDMOSoff) {
+ /* 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 two voltages
+ */
+ vds = model->VDMOStype * here->VDMOSicVDS;
+ vgs = model->VDMOStype * here->VDMOSicVGS;
+ delTemp = 0.0;
+ if ((vds == 0.0) && (vgs == 0.0) &&
+ ((ckt->CKTmode & (MODETRAN | MODEAC|MODEDCOP |
+ MODEDCTRANCURVE)) || (!(ckt->CKTmode & MODEUIC))))
+ {
+ vgs = model->VDMOStype * model->VDMOSvth0 + 0.1;
+ vds = 0.0;
+ }
+ } else if ((ckt->CKTmode & (MODEINITJCT | MODEINITFIX)) && (here->VDMOSoff)) {
+ delTemp = vgs = vds = 0.0;
/*
* ok - now to do the start-up operations
*
- * we must get values for vbs, vds, and vgs from somewhere
+ * we must get values for 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))) {
+ }
+ else
+ {
#ifndef PREDICTOR
- if (ckt->CKTmode & (MODEINITPRED | MODEINITTRAN)) {
+ if (ckt->CKTmode & MODEINITPRED) {
/* predictor step */
@@ -116,7 +170,13 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
*(ckt->CKTstate1 + here->VDMOSvds);
vds = (1 + xfact)* (*(ckt->CKTstate1 + here->VDMOSvds))
- (xfact * (*(ckt->CKTstate2 + here->VDMOSvds)));
- } else {
+ *(ckt->CKTstate0 + here->VDMOSdeltemp) =
+ *(ckt->CKTstate1 + here->VDMOSdeltemp);
+ delTemp = (1 + xfact)* (*(ckt->CKTstate1 + here->VDMOSdeltemp))
+ - (xfact * (*(ckt->CKTstate2 + here->VDMOSdeltemp)));
+ }
+ else
+ {
#endif /* PREDICTOR */
/* general iteration */
@@ -127,6 +187,10 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
vds = model->VDMOStype * (
*(ckt->CKTrhsOld + here->VDMOSdNodePrime) -
*(ckt->CKTrhsOld + here->VDMOSsNodePrime));
+ if (selfheat)
+ delTemp = *(ckt->CKTrhsOld + here->VDMOStempNode);
+ else
+ delTemp = 0.0;
#ifndef PREDICTOR
}
#endif /* PREDICTOR */
@@ -140,61 +204,73 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
delvds = vds - *(ckt->CKTstate0 + here->VDMOSvds);
delvgd = vgd - vgdo;
+ deldelTemp = delTemp - *(ckt->CKTstate0 + here->VDMOSdeltemp);
+
/* these are needed for convergence testing */
if (here->VDMOSmode >= 0) {
cdhat =
- here->VDMOScd
- + here->VDMOSgm * delvgs
- + here->VDMOSgds * delvds;
+ here->VDMOScd
+ + here->VDMOSgm * delvgs
+ + here->VDMOSgds * delvds
+ + here->VDMOSgmT * deldelTemp;
} else {
cdhat =
- here->VDMOScd
- - here->VDMOSgm * delvgd
- + here->VDMOSgds * delvds;
+ here->VDMOScd
+ - here->VDMOSgm * delvgd
+ + here->VDMOSgds * delvds
+ + here->VDMOSgmT * deldelTemp;
}
#ifndef NOBYPASS
/* now lets see if we can bypass (ugh) */
- if ((!(ckt->CKTmode &
- (MODEINITPRED | MODEINITTRAN | MODEINITSMSIG))) &&
+ if ((!(ckt->CKTmode & MODEINITPRED)) &&
(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;
- }
+ (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)) &&
+ ((here->VDMOStempNode == 0) ||
+ (fabs(deldelTemp) < (ckt->CKTreltol * MAX(fabs(delTemp),
+ fabs(*(ckt->CKTstate0+here->VDMOSdeltemp)))
+ + ckt->CKTvoltTol*1e4))))
+ {
+ /* 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;
+ delTemp = *(ckt->CKTstate0 + here->VDMOSdeltemp);
+ /* calculate Vds for temperature conductance calculation
+ in bypass (used later when filling Temp node matrix) */
+ Vds = here->VDMOSmode > 0 ? vds : -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));
+ capth = (*(ckt->CKTstate0 + here->VDMOScapth) +
+ *(ckt->CKTstate1 + here->VDMOScapth));
+ }
+ goto bypass;
+ }
#endif /*NOBYPASS*/
-
/* ok - bypass is out, do it the hard way */
von = model->VDMOStype * here->VDMOSvon;
@@ -202,7 +278,7 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
#ifndef NODELIMITING
/*
* limiting
- * we want to keep device voltages from changing
+ * we want to keep device voltages from changing
* so fast that the exponentials churn out overflows
* and similar rudeness
*/
@@ -222,31 +298,41 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
}
vgs = vgd + vds;
}
+ if (selfheat)
+ delTemp = VDMOSlimitlog(delTemp,
+ *(ckt->CKTstate0 + here->VDMOSdeltemp),100,&Check_mos);
+ else
+ delTemp = 0.0;
#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;
- }
}
+ Temp = delTemp + here->VDMOStemp;
+ here->VDMOSTempSH = Temp; /* added for portability of SH Temp for noise analysis */
+
+ /* Calculate temperature dependent values for self-heating effect */
+ if (selfheat) {
+ double TempRatio = Temp / here->VDMOStemp;
+ Beta = here->VDMOStTransconductance * pow(TempRatio,model->VDMOSmu);
+ dBeta_dT = here->VDMOStTransconductance * model->VDMOSmu / (here->VDMOStemp * pow(TempRatio,1-model->VDMOSmu));
+ rd0T = here->VDMOSdrainResistance * pow(TempRatio, model->VDMOStexp0);
+ drd0T_dT = rd0T * model->VDMOStexp0 / Temp;
+ rd1T = 0.0;
+ drd1T_dT = 0.0;
+ if (model->VDMOSqsGiven) {
+ rd1T = here->VDMOSqsResistance * pow(TempRatio, model->VDMOStexp1);
+ drd1T_dT = rd1T * model->VDMOStexp1 / Temp;
+ }
+ } else {
+ Beta = here->VDMOStTransconductance;
+ dBeta_dT = 0.0;
+ rd0T = here->VDMOSdrainResistance;
+ drd0T_dT = 0.0;
+ rd1T = 0.0;
+ if (model->VDMOSqsGiven)
+ rd1T = here->VDMOSqsResistance;
+ drd1T_dT = 0.0;
+ }
/*
* now all the preliminaries are over - we can start doing the
@@ -261,125 +347,63 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
if (vds >= 0) {
/* normal mode */
here->VDMOSmode = 1;
+ Vds = vds;
+ Vgs = vgs;
} else {
/* inverse mode */
here->VDMOSmode = -1;
+ Vds = -vds;
+ Vgs = vgd;
}
{
/*
* 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
+ * charges associated with the gate and channel 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;
+ von = here->VDMOStVth * model->VDMOStype;
+ double 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
+ /* 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;
- 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;
+ double betap = Beta*t0/t1;
+ double dbetapdvgs = -Beta*theta*t0/(t1*t1);
+ double dbetapdvds = Beta*lambda/t1;
+ double dbetapdT = dBeta_dT*t0/t1;
- /* 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);
- 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;
- }
+ 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;
+ dIds_dT = dbetapdT * vgst*vgst * .5;
}
- 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);
- }
- }
+ 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;
+ dIds_dT = dbetapdT * vdss * (vgst - .5 * vdss);
}
}
@@ -398,119 +422,7 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
*(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;
-
+ *(ckt->CKTstate0 + here->VDMOSdeltemp) = delTemp;
/* quasi saturation
* according to Vincenzo d'Alessandro's Quasi-Saturation Model, simplified:
@@ -522,17 +434,194 @@ bypass :
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;
+ double rd = rd0T + rd1T * (vdsn / (vdsn + fabs(model->VDMOSqsVoltage)));
+ if (rd > 0)
+ here->VDMOSdrainConductance = 1 / rd + ckt->CKTgmin;
+ else
+ here->VDMOSdrainConductance = 1 / rd0T;
+ } else {
+ if (rd0T > 0)
+ here->VDMOSdrainConductance = 1 / rd0T;
}
+ if (selfheat) {
+ GmT = dIds_dT;
+ here->VDMOSgmT = GmT;
+ } else {
+ GmT = 0.0;
+ here->VDMOSgmT = 0.0;
+ }
+
+ if (selfheat) {
+ /* note that sign is switched because power flows out
+ of device into the temperature node. */
+ here->VDMOSgtempg = -model->VDMOStype*here->VDMOSgm * Vds;
+ here->VDMOSgtempT = -GmT * Vds;
+ here->VDMOSgtempd = -model->VDMOStype* (here->VDMOSgds * Vds + cdrain);
+ here->VDMOScth = - cdrain * Vds
+ - 1/here->VDMOSdrainConductance * cdrain*cdrain
+ - model->VDMOStype * (here->VDMOSgtempg * Vgs + here->VDMOSgtempd * Vds)
+ - here->VDMOSgtempT * delTemp;
+ }
+
+ /*
+ * vdmos capacitor model
+ */
+ if (ckt->CKTmode & (MODETRAN | MODETRANOP | MODEINITSMSIG)) {
+ /*
+ * calculate gate - drain, gate - source capacitors
+ * drain-source capacitor is evaluated with the body 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));
+ *(ckt->CKTstate0 + here->VDMOScapth) = model->VDMOScthj; /* always constant */
+
+ vgs1 = *(ckt->CKTstate1 + here->VDMOSvgs);
+ vgd1 = vgs1 - *(ckt->CKTstate1 + here->VDMOSvds);
+ delTemp1 = *(ckt->CKTstate1 + here->VDMOSdeltemp);
+ if (ckt->CKTmode & (MODETRANOP | MODEINITSMSIG)) {
+ capgs = 2 * *(ckt->CKTstate0 + here->VDMOScapgs);
+ capgd = 2 * *(ckt->CKTstate0 + here->VDMOScapgd);
+ capth = 2 * *(ckt->CKTstate0 + here->VDMOScapth);
+ } else {
+ capgs = (*(ckt->CKTstate0 + here->VDMOScapgs) +
+ *(ckt->CKTstate1 + here->VDMOScapgs));
+ capgd = (*(ckt->CKTstate0 + here->VDMOScapgd) +
+ *(ckt->CKTstate1 + here->VDMOScapgd));
+ capth = (*(ckt->CKTstate0 + here->VDMOScapth) +
+ *(ckt->CKTstate1 + here->VDMOScapth));
+ }
+
+#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);
+ *(ckt->CKTstate0 + here->VDMOSqth) =
+ (1 + xfact) * *(ckt->CKTstate1 + here->VDMOSqth)
+ - xfact * *(ckt->CKTstate2 + here->VDMOSqth);
+ } 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);
+ *(ckt->CKTstate0 + here->VDMOSqth) = (delTemp-delTemp1)*capth +
+ *(ckt->CKTstate1 + here->VDMOSqth);
+ } else {
+ /* TRANOP only */
+ *(ckt->CKTstate0 + here->VDMOSqgs) = vgs*capgs;
+ *(ckt->CKTstate0 + here->VDMOSqgd) = vgd*capgd;
+ *(ckt->CKTstate0 + here->VDMOSqth) = delTemp*capth;
+ }
+#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;
+ gcTt = 0.0;
+ ceqqth = 0.0;
+ } else {
+ if (capgs == 0) *(ckt->CKTstate0 + here->VDMOScqgs) = 0;
+ if (capgd == 0) *(ckt->CKTstate0 + here->VDMOScqgd) = 0;
+ if (capth == 0) *(ckt->CKTstate0 + here->VDMOScqth) = 0;
+ /*
+ * calculate equivalent conductances and currents for
+ * vdmos 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);
+ if (selfheat)
+ {
+ error = NIintegrate(ckt, &gcTt, &ceqqth, 0.0, here->VDMOSqth);
+ gcTt = model->VDMOScthj * ckt->CKTag[0];
+ ceqqth = *(ckt->CKTstate0 + here->VDMOScqth) - gcTt * delTemp;
+ }
+ }
+
+ /*
+ * load current vector
+ */
+
+ if (selfheat) {
+ if (here->VDMOSmode >= 0) {
+ GmT = model->VDMOStype * here->VDMOSgmT;
+ gTtg = here->VDMOSgtempg;
+ gTtdp = here->VDMOSgtempd;
+ gTtt = here->VDMOSgtempT;
+ gTtsp = - (gTtg + gTtdp);
+ } else {
+ GmT = -model->VDMOStype * here->VDMOSgmT;
+ gTtg = here->VDMOSgtempg;
+ gTtsp = here->VDMOSgtempd;
+ gTtt = here->VDMOSgtempT;
+ gTtdp = - (gTtg + gTtsp);
+ }
+ } else {
+ GmT = 0.0;
+ gTtg = 0.0;
+ gTtdp = 0.0;
+ gTtt = 0.0;
+ gTtsp = 0.0;
+ }
+
+ if (here->VDMOSmode >= 0) {
+ xnrm = 1;
+ xrev = 0;
+ cdreq = model->VDMOStype*(cdrain - here->VDMOSgds*vds
+ - here->VDMOSgm*vgs)
+ - GmT * delTemp;
+ } else {
+ xnrm = 0;
+ xrev = 1;
+ cdreq = -(model->VDMOStype)*(cdrain - here->VDMOSgds*(-vds)
+ - here->VDMOSgm*vgd)
+ - GmT * delTemp;
+ }
+
+ *(ckt->CKTrhs + here->VDMOSgNodePrime) -= (model->VDMOStype * (ceqgs + ceqgd));
+ *(ckt->CKTrhs + here->VDMOSdNodePrime) += (-cdreq + model->VDMOStype * ceqgd);
+ *(ckt->CKTrhs + here->VDMOSsNodePrime) += cdreq + model->VDMOStype * ceqgs;
+ if (selfheat) {
+ *(ckt->CKTrhs + here->VDMOStempNode) -= here->VDMOScth + ceqqth; /* dissipated power + Cthj current */
+ *(ckt->CKTrhs + here->VDMOSvcktTbranch) = ckt->CKTtemp-CONSTCtoK; /* ckt temperature */
+ }
/*
* load y matrix
*/
*(here->VDMOSDdPtr) += (here->VDMOSdrainConductance + here->VDMOSdsConductance);
- *(here->VDMOSGgPtr) += (here->VDMOSgateConductance); //((gcgd + gcgs + gcgb));
+ *(here->VDMOSGgPtr) += (here->VDMOSgateConductance);
*(here->VDMOSSsPtr) += (here->VDMOSsourceConductance + here->VDMOSdsConductance);
*(here->VDMOSDPdpPtr) +=
(here->VDMOSdrainConductance + here->VDMOSgds +
@@ -560,26 +649,40 @@ bypass :
*(here->VDMOSDsPtr) += (-here->VDMOSdsConductance);
*(here->VDMOSSdPtr) += (-here->VDMOSdsConductance);
+ if (selfheat)
+ {
+ (*(here->VDMOSDPtempPtr) += GmT);
+ (*(here->VDMOSSPtempPtr) += -GmT);
+ (*(here->VDMOSGPtempPtr) += 0.0);
+ (*(here->VDMOSTemptempPtr) += gTtt + 1/model->VDMOSrthjc + gcTt);
+ (*(here->VDMOSTempgpPtr) += gTtg);
+ (*(here->VDMOSTempdpPtr) += gTtdp);
+ (*(here->VDMOSTempspPtr) += gTtsp);
+ (*(here->VDMOSTemptcasePtr) += -1/model->VDMOSrthjc);
+ (*(here->VDMOSTcasetempPtr) += -1/model->VDMOSrthjc);
+ (*(here->VDMOSTcasetcasePtr) += 1/model->VDMOSrthjc + 1/model->VDMOSrthca);
+ (*(here->VDMOSTptpPtr) += 1/model->VDMOSrthca);
+ (*(here->VDMOSTptcasePtr) += -1/model->VDMOSrthca);
+ (*(here->VDMOSTcasetpPtr) += -1/model->VDMOSrthca);
+ (*(here->VDMOSCktTtpPtr) += 1.0);
+ (*(here->VDMOSTpcktTPtr) += 1.0);
+ }
- /* bulk diode model
+ /* body 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;
+ double evrev;
#ifndef NOBYPASS
- double tol; /* temporary for tolerence calculations */
+ double tol; /* temporary for tolerance calculations */
#endif
cd = 0.0;
@@ -588,11 +691,11 @@ bypass :
gdb = 0.0;
csat = here->VDIOtSatCur;
gspr = here->VDIOtConductance;
- vte = model->VDMOSDn * vt;
+ vte = model->VDMOSn * vt;
vtebrk = model->VDIObrkdEmissionCoeff * vt;
vbrknp = here->VDIOtBrkdwnV;
- Check = 1;
+ Check_diode = 1;
if (ckt->CKTmode & MODEINITSMSIG) {
vd = *(ckt->CKTstate0 + here->VDIOvoltage);
} else if (ckt->CKTmode & MODEINITTRAN) {
@@ -646,29 +749,31 @@ bypass :
/*
* limit new junction voltage
*/
- if ((model->VDMOSDbvGiven) &&
+ if ((model->VDMOSbvGiven) &&
(vd < MIN(0, -vbrknp + 10 * vtebrk))) {
+ double vdtemp;
vdtemp = -(vd + vbrknp);
vdtemp = DEVpnjlim(vdtemp,
-(*(ckt->CKTstate0 + here->VDIOvoltage) +
vbrknp), vtebrk,
- here->VDIOtVcrit, &Check);
+ here->VDIOtVcrit, &Check_diode);
vd = -(vdtemp + vbrknp);
} else {
vd = DEVpnjlim(vd, *(ckt->CKTstate0 + here->VDIOvoltage),
- vte, here->VDIOtVcrit, &Check);
+ vte, here->VDIOtVcrit, &Check_diode);
}
}
/*
* compute dc current and derivatives
*/
if (vd >= -3 * vte) { /* bottom current forward */
+ double evd;
evd = exp(vd / vte);
cdb = csat*(evd - 1);
gdb = csat*evd / vte;
- } else if ((!(model->VDMOSDbvGiven)) ||
+ } else if ((!(model->VDMOSbvGiven)) ||
vd >= -vbrknp) { /* reverse */
arg = 3 * vte / (vd*CONSTe);
@@ -696,6 +801,7 @@ bypass :
/*
* charge storage elements
*/
+ double czero, czof2, diffcharge, deplcharge, diffcap, deplcap;
czero = here->VDIOtJctCap;
if (vd < here->VDIOtDepCap) {
arg = 1 - vd / here->VDIOtJctPot;
@@ -751,7 +857,7 @@ bypass :
* check convergence
*/
- if (Check == 1) {
+ if ((Check_mos == 1) || (Check_diode == 1)) {
ckt->CKTnoncon++;
ckt->CKTtroubleElt = (GENinstance *)here;
}
@@ -761,7 +867,7 @@ bypass :
*(ckt->CKTstate0 + here->VDIOconduct) = gd;
#ifndef NOBYPASS
-load :
+load:
#endif
/*
* load current vector
@@ -789,47 +895,3 @@ load :
}
return(OK);
}
-
-
-/* scaling function, sine function interpolating between 0 and 1
- * nf2: empirical setting of sine 'speed'
- */
-
-static double
-scalef(double nf2, double vgst)
-{
- double vgstsin = vgst / nf2;
- if (vgstsin > 1)
- return 1;
- else if (vgstsin < -1)
- return 0;
- else
- return 0.5 * sin(vgstsin * M_PI / 2) + 0.5;
-}
-
-
-/* Calculate D/S current including weak inversion.
- * Uses a single function covering weak-moderate-stong inversion, as well
- * as linear and saturation regions, with an interpolation method according to
- * Tvividis, McAndrew: "Operation and Modeling of the MOS Transistor", Oxford, 2011, p. 209.
- * A single parameter n sets the slope of the weak inversion current. The weak inversion
- * current is independent from vds, as in long channel devices.
- * The following modification has been added for VDMOS compatibility:
- * n and lambda are depending on vgst with a sine function interpolating between 0 and 1.
- */
-
-static double
-cweakinv2(double slope, double shift, double vgst, double vds, double lambda, double beta, double vt, double mtr, double theta)
-{
- double betam = beta / (1.0+theta*vgst);
- vgst += shift * (1 - scalef(0.5, vgst));
- double n = slope / 2.3 / 0.0256; /* Tsividis, p. 208 */
- double n1 = n + (1 - n) * scalef(0.7, vgst); /* n < n1 < 1 */
- double first = log(1 + exp(vgst / (2 * n1 * vt)));
- double second = log(1 + exp((vgst - vds * mtr * n1) / (2 * n1 * vt)));
- double cds =
- betam * n1 * 2 * vt * vt * (1 + scalef(1, vgst) * lambda * vds) *
- (first * first - second * second);
- return cds;
-}
-
diff --git a/src/spicelib/devices/vdmos/vdmosmask.c b/src/spicelib/devices/vdmos/vdmosmask.c
index c5fe055c4..de8f9437d 100644
--- a/src/spicelib/devices/vdmos/vdmosmask.c
+++ b/src/spicelib/devices/vdmos/vdmosmask.c
@@ -24,8 +24,8 @@ VDMOSmAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value)
case VDMOS_MOD_TNOM:
value->rValue = model->VDMOStnom-CONSTCtoK;
return(OK);
- case VDMOS_MOD_VTO:
- value->rValue = model->VDMOSvt0;
+ case VDMOS_MOD_VTH:
+ value->rValue = model->VDMOSvth0;
return(OK);
case VDMOS_MOD_KP:
value->rValue = model->VDMOStransconductance;
@@ -57,9 +57,6 @@ VDMOSmAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value)
case VDMOS_MOD_MTRIODE:
value->rValue = model->VDMOSmtr;
return(OK);
- case VDMOS_MOD_SUBSLOPE:
- value->rValue = model->VDMOSsubsl;
- return(OK);
case VDMOS_MOD_SUBSHIFT:
value->rValue = model->VDMOSsubshift;
return(OK);
@@ -93,7 +90,7 @@ VDMOSmAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value)
value->rValue = model->VDIOjctSatCur;
return(OK);
case VDMOS_MOD_N:
- value->rValue = model->VDMOSDn;
+ value->rValue = model->VDMOSn;
return(OK);
case VDMOS_MOD_VJ:
value->rValue = model->VDIOjunctionPot;
@@ -105,10 +102,10 @@ VDMOSmAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value)
value->rValue = model->VDIOgradCoeff;
return(OK);
case VDMOS_MOD_BV:
- value->rValue = model->VDMOSDbv;
+ value->rValue = model->VDMOSbv;
return(OK);
case VDMOS_MOD_IBV:
- value->rValue = model->VDMOSDibv;
+ value->rValue = model->VDMOSibv;
return(OK);
case VDMOS_MOD_NBV:
value->rValue = model->VDIObrkdEmissionCoeff;
@@ -123,10 +120,46 @@ VDMOSmAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value)
value->rValue = model->VDIOtransitTime;
return(OK);
case VDMOS_MOD_EG:
- value->rValue = model->VDMOSDeg;
+ value->rValue = model->VDMOSeg;
return(OK);
case VDMOS_MOD_XTI:
- value->rValue = model->VDMOSDxti;
+ value->rValue = model->VDMOSxti;
+ return(OK);
+ case VDMOS_MOD_RTHJC:
+ value->rValue = model->VDMOSrthjc;
+ return(OK);
+ case VDMOS_MOD_RTHCA:
+ value->rValue = model->VDMOSrthca;
+ return(OK);
+ case VDMOS_MOD_CTHJ:
+ value->rValue = model->VDMOScthj;
+ return(OK);
+ case VDMOS_MOD_MU:
+ value->rValue = model->VDMOSmu;
+ return(OK);
+ case VDMOS_MOD_TEXP0:
+ value->rValue = model->VDMOStexp0;
+ return(OK);
+ case VDMOS_MOD_TEXP1:
+ value->rValue = model->VDMOStexp1;
+ return(OK);
+ case VDMOS_MOD_TCVTH:
+ value->rValue = model->VDMOStcvth;
+ return(OK);
+ case VDMOS_MOD_VGS_MAX:
+ value->rValue = model->VDMOSvgsMax;
+ return(OK);
+ case VDMOS_MOD_VGD_MAX:
+ value->rValue = model->VDMOSvgdMax;
+ return(OK);
+ case VDMOS_MOD_VDS_MAX:
+ value->rValue = model->VDMOSvdsMax;
+ return(OK);
+ case VDMOS_MOD_VGSR_MAX:
+ value->rValue = model->VDMOSvgsrMax;
+ return(OK);
+ case VDMOS_MOD_VGDR_MAX:
+ value->rValue = model->VDMOSvgdrMax;
return(OK);
default:
return(E_BADPARM);
diff --git a/src/spicelib/devices/vdmos/vdmosmpar.c b/src/spicelib/devices/vdmos/vdmosmpar.c
index 14ef1fb1c..615cc6948 100644
--- a/src/spicelib/devices/vdmos/vdmosmpar.c
+++ b/src/spicelib/devices/vdmos/vdmosmpar.c
@@ -1,6 +1,7 @@
/**********
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Thomas L. Quarles
+VDMOS: 2018 Holger Vogt, 2020 Dietmar Warning
**********/
#include "ngspice/ngspice.h"
@@ -19,9 +20,9 @@ VDMOSmParam(int param, IFvalue *value, GENmodel *inModel)
model->VDMOStnom = value->rValue + CONSTCtoK;
model->VDMOStnomGiven = TRUE;
break;
- case VDMOS_MOD_VTO:
- model->VDMOSvt0 = value->rValue;
- model->VDMOSvt0Given = TRUE;
+ case VDMOS_MOD_VTH:
+ model->VDMOSvth0 = value->rValue;
+ model->VDMOSvth0Given = TRUE;
break;
case VDMOS_MOD_KP:
model->VDMOStransconductance = value->rValue;
@@ -54,20 +55,14 @@ VDMOSmParam(int param, IFvalue *value, GENmodel *inModel)
case VDMOS_MOD_RQ:
model->VDMOSqsResistance = value->rValue;
model->VDMOSqsResistanceGiven = TRUE;
- if (model->VDMOSqsVoltageGiven)
- model->VDMOSqsGiven = TRUE;
break;
case VDMOS_MOD_VQ:
model->VDMOSqsVoltage = value->rValue;
model->VDMOSqsVoltageGiven = TRUE;
- if (model->VDMOSqsResistanceGiven)
- model->VDMOSqsGiven = TRUE;
break;
case VDMOS_MOD_RB:
model->VDIOresistance = value->rValue;
model->VDIOresistanceGiven = TRUE;
- model->VDIOresistTemp1 = 0;
- model->VDIOresistTemp2 = 0;
break;
case VDMOS_MOD_IS:
model->VDIOjctSatCur = value->rValue;
@@ -137,10 +132,6 @@ VDMOSmParam(int param, IFvalue *value, GENmodel *inModel)
model->VDMOSmtr = value->rValue;
model->VDMOSmtrGiven = TRUE;
break;
- case VDMOS_MOD_SUBSLOPE:
- model->VDMOSsubsl = value->rValue;
- model->VDMOSsubslGiven = TRUE;
- break;
case VDMOS_MOD_SUBSHIFT:
model->VDMOSsubshift = value->rValue;
model->VDMOSsubshiftGiven = TRUE;
@@ -150,12 +141,12 @@ VDMOSmParam(int param, IFvalue *value, GENmodel *inModel)
model->VDMOSksubthresGiven = TRUE;
break;
case VDMOS_MOD_BV:
- model->VDMOSDbv = value->rValue;
- model->VDMOSDbvGiven = TRUE;
+ model->VDMOSbv = value->rValue;
+ model->VDMOSbvGiven = TRUE;
break;
case VDMOS_MOD_IBV:
- model->VDMOSDibv = value->rValue;
- model->VDMOSDibvGiven = TRUE;
+ model->VDMOSibv = value->rValue;
+ model->VDMOSibvGiven = TRUE;
break;
case VDMOS_MOD_NBV:
model->VDIObrkdEmissionCoeff = value->rValue;
@@ -166,8 +157,8 @@ VDMOSmParam(int param, IFvalue *value, GENmodel *inModel)
model->VDMOSrdsGiven = TRUE;
break;
case VDMOS_MOD_N:
- model->VDMOSDn = value->rValue;
- model->VDMOSDnGiven = TRUE;
+ model->VDMOSn = value->rValue;
+ model->VDMOSnGiven = TRUE;
break;
case VDMOS_MOD_TT:
model->VDIOtransitTime = value->rValue;
@@ -176,12 +167,60 @@ VDMOSmParam(int param, IFvalue *value, GENmodel *inModel)
model->VDIOtranTimeTemp2 = 0;
break;
case VDMOS_MOD_EG:
- model->VDMOSDeg = value->rValue;
- model->VDMOSDegGiven = TRUE;
+ model->VDMOSeg = value->rValue;
+ model->VDMOSegGiven = TRUE;
break;
case VDMOS_MOD_XTI:
- model->VDMOSDxti = value->rValue;
- model->VDMOSDxtiGiven = TRUE;
+ model->VDMOSxti = value->rValue;
+ model->VDMOSxtiGiven = TRUE;
+ break;
+ case VDMOS_MOD_RTHJC:
+ model->VDMOSrthjc = value->rValue;
+ model->VDMOSrthjcGiven = TRUE;
+ break;
+ case VDMOS_MOD_RTHCA:
+ model->VDMOSrthca = value->rValue;
+ model->VDMOSrthcaGiven = TRUE;
+ break;
+ case VDMOS_MOD_CTHJ:
+ model->VDMOScthj = value->rValue;
+ model->VDMOScthjGiven = TRUE;
+ break;
+ case VDMOS_MOD_MU:
+ model->VDMOSmu = value->rValue;
+ model->VDMOSmuGiven = TRUE;
+ break;
+ case VDMOS_MOD_TEXP0:
+ model->VDMOStexp0 = value->rValue;
+ model->VDMOStexp0Given = TRUE;
+ break;
+ case VDMOS_MOD_TEXP1:
+ model->VDMOStexp1 = value->rValue;
+ model->VDMOStexp1Given = TRUE;
+ break;
+ case VDMOS_MOD_TCVTH:
+ model->VDMOStcvth = value->rValue;
+ model->VDMOStcvthGiven = TRUE;
+ break;
+ case VDMOS_MOD_VGS_MAX:
+ model->VDMOSvgsMax = value->rValue;
+ model->VDMOSvgsMaxGiven = TRUE;
+ break;
+ case VDMOS_MOD_VGD_MAX:
+ model->VDMOSvgdMax = value->rValue;
+ model->VDMOSvgdMaxGiven = TRUE;
+ break;
+ case VDMOS_MOD_VDS_MAX:
+ model->VDMOSvdsMax = value->rValue;
+ model->VDMOSvdsMaxGiven = TRUE;
+ break;
+ case VDMOS_MOD_VGSR_MAX:
+ model->VDMOSvgsrMax = value->rValue;
+ model->VDMOSvgsrMaxGiven = TRUE;
+ break;
+ case VDMOS_MOD_VGDR_MAX:
+ model->VDMOSvgdrMax = value->rValue;
+ model->VDMOSvgdrMaxGiven = TRUE;
break;
default:
return(E_BADPARM);
diff --git a/src/spicelib/devices/vdmos/vdmosnoi.c b/src/spicelib/devices/vdmos/vdmosnoi.c
index ca8dbdfdd..222f686be 100644
--- a/src/spicelib/devices/vdmos/vdmosnoi.c
+++ b/src/spicelib/devices/vdmos/vdmosnoi.c
@@ -36,6 +36,7 @@ VDMOSnoise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt,
double noizDens[VDMOSNSRCS];
double lnNdens[VDMOSNSRCS];
int i;
+ double tempRatioSH;
/* define the names of the noise sources */
@@ -90,17 +91,21 @@ VDMOSnoise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt,
switch (mode) {
case N_DENS:
+ if ((inst->VDMOStnodeoutGiven) && (model->VDMOSrthjc != 0.0))
+ tempRatioSH = inst->VDMOSTempSH / ckt->CKTtemp;
+ else
+ tempRatioSH = 1.0;
NevalSrc(&noizDens[VDMOSRDNOIZ],&lnNdens[VDMOSRDNOIZ],
ckt,THERMNOISE,inst->VDMOSdNodePrime,inst->VDMOSdNode,
- inst->VDMOSdrainConductance);
+ inst->VDMOSdrainConductance * tempRatioSH);
NevalSrc(&noizDens[VDMOSRSNOIZ],&lnNdens[VDMOSRSNOIZ],
ckt,THERMNOISE,inst->VDMOSsNodePrime,inst->VDMOSsNode,
- inst->VDMOSsourceConductance);
+ inst->VDMOSsourceConductance * tempRatioSH);
NevalSrc(&noizDens[VDMOSIDNOIZ],&lnNdens[VDMOSIDNOIZ],
ckt,THERMNOISE,inst->VDMOSdNodePrime,inst->VDMOSsNodePrime,
- (2.0/3.0 * fabs(inst->VDMOSgm)));
+ (2.0/3.0 * fabs(inst->VDMOSgm)) * tempRatioSH);
NevalSrc(&noizDens[VDMOSFLNOIZ], NULL, ckt,
N_GAIN,inst->VDMOSdNodePrime, inst->VDMOSsNodePrime,
diff --git a/src/spicelib/devices/vdmos/vdmospar.c b/src/spicelib/devices/vdmos/vdmospar.c
index 428beb90d..ad57b8c09 100644
--- a/src/spicelib/devices/vdmos/vdmospar.c
+++ b/src/spicelib/devices/vdmos/vdmospar.c
@@ -2,6 +2,7 @@
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Thomas L. Quarles
Modified: 2000 AlansFixes
+VDMOS: 2018 Holger Vogt, 2020 Dietmar Warning
**********/
/*
*/
@@ -60,6 +61,10 @@ VDMOSparam(int param, IFvalue *value, GENinstance *inst, IFvalue *select)
here->VDMOSicVGS = value->rValue;
here->VDMOSicVGSGiven = TRUE;
break;
+ case VDMOS_TNODEOUT:
+ here->VDMOStnodeout = (value->iValue != 0);
+ here->VDMOStnodeoutGiven = TRUE;
+ break;
case VDMOS_IC:
switch(value->v.numValue){
case 2:
diff --git a/src/spicelib/devices/vdmos/vdmospzld.c b/src/spicelib/devices/vdmos/vdmospzld.c
index 65bd2ce9e..674ad4ae7 100644
--- a/src/spicelib/devices/vdmos/vdmospzld.c
+++ b/src/spicelib/devices/vdmos/vdmospzld.c
@@ -44,8 +44,13 @@ VDMOSpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s)
capgd = ( 2* *(ckt->CKTstate0+here->VDMOScapgd));
xgs = capgs;
xgd = capgd;
- /*printf("vdmos: xgs=%g, xgd=%g\n",
- xgs,xgd);*/
+
+ /* body diode */
+ double gspr, geq, xceq;
+ gspr = here->VDIOtConductance;
+ geq = *(ckt->CKTstate0 + here->VDIOconduct);
+ xceq = *(ckt->CKTstate0 + here->VDIOcapCurrent);
+
/*
* load matrix
*/
@@ -67,21 +72,34 @@ VDMOSpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s)
*(here->VDMOSDdPtr) += here->VDMOSdrainConductance;
*(here->VDMOSSsPtr) += here->VDMOSsourceConductance;
*(here->VDMOSDPdpPtr) += here->VDMOSdrainConductance+
- here->VDMOSgds+
- xrev*(here->VDMOSgm);
+ here->VDMOSgds+xrev*(here->VDMOSgm);
*(here->VDMOSSPspPtr) += here->VDMOSsourceConductance+
- here->VDMOSgds+
- xnrm*(here->VDMOSgm);
+ here->VDMOSgds+xnrm*(here->VDMOSgm);
*(here->VDMOSDdpPtr) -= here->VDMOSdrainConductance;
*(here->VDMOSSspPtr) -= here->VDMOSsourceConductance;
*(here->VDMOSDPdPtr) -= here->VDMOSdrainConductance;
- *(here->VDMOSDPgPtr) += (xnrm-xrev)*here->VDMOSgm;
- *(here->VDMOSDPspPtr) -= here->VDMOSgds+
- xnrm*(here->VDMOSgm);
- *(here->VDMOSSPgPtr) -= (xnrm-xrev)*here->VDMOSgm;
+ *(here->VDMOSDPgpPtr) += (xnrm-xrev)*here->VDMOSgm;
+ *(here->VDMOSDPspPtr) -= here->VDMOSgds+xnrm*(here->VDMOSgm);
+ *(here->VDMOSSPgpPtr) -= (xnrm-xrev)*here->VDMOSgm;
*(here->VDMOSSPsPtr) -= here->VDMOSsourceConductance;
- *(here->VDMOSSPdpPtr) -= here->VDMOSgds+
- xrev*(here->VDMOSgm);
+ *(here->VDMOSSPdpPtr) -= here->VDMOSgds+xrev*(here->VDMOSgm);
+ /* gate resistor */
+ *(here->VDMOSGgPtr) += (here->VDMOSgateConductance);
+ *(here->VDMOSGPgpPtr) += (here->VDMOSgateConductance);
+ *(here->VDMOSGgpPtr) -= here->VDMOSgateConductance;
+ *(here->VDMOSGPgPtr) -= here->VDMOSgateConductance;
+ /* body diode */
+ *(here->VDMOSSsPtr) += gspr;
+ *(here->VDMOSDdPtr) += geq + xceq * s->real;
+ *(here->VDMOSDdPtr +1 ) += xceq * s->imag;
+ *(here->VDIORPrpPtr) += geq + gspr + xceq * s->real;
+ *(here->VDIORPrpPtr +1) += xceq * s->imag;
+ *(here->VDIOSrpPtr) -= gspr;
+ *(here->VDIODrpPtr) -= geq + xceq * s->real;
+ *(here->VDIODrpPtr +1) -= xceq * s->imag;
+ *(here->VDIORPsPtr) -= gspr;
+ *(here->VDIORPdPtr) -= geq + xceq * s->real;
+ *(here->VDIORPdPtr +1 ) -= xceq * s->imag;
}
}
diff --git a/src/spicelib/devices/vdmos/vdmosset.c b/src/spicelib/devices/vdmos/vdmosset.c
index 4fb7a2017..e8aa30fdf 100644
--- a/src/spicelib/devices/vdmos/vdmosset.c
+++ b/src/spicelib/devices/vdmos/vdmosset.c
@@ -2,6 +2,7 @@
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Thomas L. Quarles
Modified: 2000 AlansFixes
+VDMOS: 2018 Holger Vogt, 2020 Dietmar Warning
**********/
/* load the VDMOS device structure with those pointers needed later
@@ -27,87 +28,136 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt,
/* loop through all the VDMOS device models */
for (; model != NULL; model = VDMOSnextModel(model)) {
- if (!model->VDMOStypeGiven) {
+ if (!model->VDMOStypeGiven)
model->VDMOStype = NMOS;
- }
- if (!model->VDIOjctSatCurGiven) {
+
+ if (!model->VDIOjctSatCurGiven)
model->VDIOjctSatCur = 1e-14;
- }
- if (!model->VDMOStransconductanceGiven) {
+
+ if (!model->VDMOStransconductanceGiven)
model->VDMOStransconductance = 1;
- }
- if (!model->VDMOSvt0Given) {
- model->VDMOSvt0 = 0;
- }
- if (!model->VDIOjunctionPotGiven) {
+
+ if (!model->VDMOSvth0Given)
+ model->VDMOSvth0 = 0;
+
+ if (!model->VDIOjunctionPotGiven)
model->VDIOjunctionPot = .8;
- }
- if (!model->VDIOgradCoeffGiven) {
+
+ if (!model->VDIOgradCoeffGiven)
model->VDIOgradCoeff = .5;
- }
- if (!model->VDIOdepletionCapCoeffGiven) {
+
+ if (!model->VDIOdepletionCapCoeffGiven)
model->VDIOdepletionCapCoeff = .5;
- }
- if (!model->VDMOSphiGiven) {
+
+ if (!model->VDMOSphiGiven)
model->VDMOSphi = .6;
- }
- if (!model->VDMOSlambdaGiven) {
+
+ if (!model->VDMOSlambdaGiven)
model->VDMOSlambda = 0;
- }
- if (!model->VDMOSthetaGiven) {
+
+ if (!model->VDMOSthetaGiven)
model->VDMOStheta = 0;
- }
- if (!model->VDMOSfNcoefGiven) {
+
+ if (!model->VDMOSfNcoefGiven)
model->VDMOSfNcoef = 0;
- }
- if (!model->VDMOSfNexpGiven) {
+
+ if (!model->VDMOSfNexpGiven)
model->VDMOSfNexp = 1;
- }
- if (!model->VDMOScgdminGiven) {
+
+ if (!model->VDMOScgdminGiven)
model->VDMOScgdmin = 0;
- }
- if (!model->VDMOScgdmaxGiven) {
+
+ if (!model->VDMOScgdmaxGiven)
model->VDMOScgdmax = 0;
- }
- if (!model->VDMOScgsGiven) {
+
+ if (!model->VDMOScgsGiven)
model->VDMOScgs = 0;
- }
- if (!model->VDMOSaGiven) {
+
+ if (!model->VDMOSaGiven)
model->VDMOSa = 1.;
- }
- if (!model->VDMOSsubslGiven) {
- model->VDMOSsubsl = 0;
- }
- if (!model->VDMOSsubshiftGiven) {
+
+ if (!model->VDMOSsubshiftGiven)
model->VDMOSsubshift = 0;
- }
- if (!model->VDMOSksubthresGiven) {
- model->VDMOSksubthres = 0;
- }
- if (!model->VDMOSmtrGiven) {
+
+ if (!model->VDMOSksubthresGiven)
+ model->VDMOSksubthres = 0.1;
+
+ if (!model->VDMOSmtrGiven)
model->VDMOSmtr = 1.;
- }
- if (!model->VDMOSDbvGiven) {
- model->VDMOSDbv = 1.0e30;
- }
- if (!model->VDMOSDibvGiven) {
- model->VDMOSDibv = 1.0e-10;
- }
- if (!model->VDIObrkdEmissionCoeffGiven) {
+
+ if (!model->VDMOSbvGiven)
+ model->VDMOSbv = 1.0e30;
+
+ if (!model->VDMOSibvGiven)
+ model->VDMOSibv = 1.0e-10;
+
+ if (!model->VDIObrkdEmissionCoeffGiven)
model->VDIObrkdEmissionCoeff = 1.;
- }
- if (!model->VDMOSrdsGiven) {
- model->VDMOSrds = 1.0e30;
- }
- if (!model->VDMOSDnGiven) {
- model->VDMOSDn = 1.;
- }
- if (!model->VDIOtransitTimeGiven) {
+
+ if (!model->VDMOSdrainResistanceGiven)
+ model->VDMOSdrainResistance = 1.0e-03;
+
+ if (!model->VDMOSsourceResistanceGiven)
+ model->VDMOSsourceResistance = 1.0e-03;
+
+ if (!model->VDMOSgateResistanceGiven)
+ model->VDMOSgateResistance = 1.0e-03;
+
+ if (!model->VDMOSrdsGiven)
+ model->VDMOSrds = 1.0e+15;
+
+ if (!model->VDIOresistanceGiven)
+ model->VDIOresistance = 1.0e-03;
+
+ if (!model->VDMOSnGiven)
+ model->VDMOSn = 1.;
+
+ if (!model->VDIOtransitTimeGiven)
model->VDIOtransitTime = 0.;
- }
- if (!model->VDMOSDegGiven) {
- model->VDMOSDeg = 1.11;
- }
+
+ if (!model->VDMOSegGiven)
+ model->VDMOSeg = 1.11;
+
+ if (!model->VDMOSrthjcGiven)
+ model->VDMOSrthjc = 0;
+
+ if (!model->VDMOSrthcaGiven)
+ model->VDMOSrthca = 100;
+
+ if (!model->VDMOScthjGiven)
+ model->VDMOScthj = 10e-06;
+
+ if (!model->VDMOSmuGiven)
+ model->VDMOSmu = -1.5;
+
+ if (!model->VDMOStcvthGiven)
+ model->VDMOStcvth = 0.0;
+
+ if (!model->VDMOStexp0Given)
+ model->VDMOStexp0 = 1.5;
+
+ if (!model->VDMOStexp1Given)
+ model->VDMOStexp1 = 0.3;
+
+ if (!model->VDMOSvgsMaxGiven)
+ model->VDMOSvgsMax = 1e99;
+
+ if (!model->VDMOSvgdMaxGiven)
+ model->VDMOSvgdMax = 1e99;
+
+ if (!model->VDMOSvdsMaxGiven)
+ model->VDMOSvdsMax = 1e99;
+
+ if (!model->VDMOSvgsrMaxGiven)
+ model->VDMOSvgsrMax = 1e99;
+
+ if (!model->VDMOSvgdrMaxGiven)
+ model->VDMOSvgdrMax = 1e99;
+
+ if ((model->VDMOSqsResistanceGiven) && (model->VDMOSqsVoltageGiven))
+ model->VDMOSqsGiven = 1;
+ else
+ model->VDMOSqsGiven = 0;
/* loop through all the instances of the model */
for (here = VDMOSinstances(model); here != NULL;
@@ -129,6 +179,45 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt,
if (!here->VDMOSvonGiven) {
here->VDMOSvon = 0;
}
+ if(!here->VDMOSmGiven) {
+ here->VDMOSm = 1;
+ }
+ if(!here->VDMOSlGiven) {
+ here->VDMOSl = 1;
+ }
+ if(!here->VDMOSwGiven) {
+ here->VDMOSw = 1;
+ }
+ if (model->VDMOSdrainResistance != 0) {
+ here->VDMOSdrainConductance = here->VDMOSm / model->VDMOSdrainResistance;
+ } else {
+ here->VDMOSdrainConductance = here->VDMOSm / 1.0e-03;
+ }
+ if (model->VDMOSsourceResistance != 0) {
+ here->VDMOSsourceConductance = here->VDMOSm / model->VDMOSsourceResistance;
+ } else {
+ here->VDMOSsourceConductance = here->VDMOSm / 1.0e-03;
+ }
+ if (model->VDMOSgateResistance != 0) {
+ here->VDMOSgateConductance = here->VDMOSm / model->VDMOSgateResistance;
+ } else {
+ here->VDMOSgateConductance = here->VDMOSm / 1.0e-03;
+ }
+ if (model->VDMOSrdsGiven) {
+ if (model->VDMOSrds != 0) {
+ here->VDMOSdsConductance = here->VDMOSm / model->VDMOSrds;
+ } else {
+ here->VDMOSdsConductance = 1e-15;
+ }
+ } else {
+ here->VDMOSdsConductance = 1e-15;
+ }
+ if (model->VDIOresistance != 0) {
+ here->VDIOconductance = here->VDMOSm / model->VDIOresistance;
+ } else {
+ here->VDIOconductance = here->VDMOSm / 1.0e-03;
+ }
+
if (model->VDMOSdrainResistance != 0) {
if (here->VDMOSdNodePrime == 0) {
error = CKTmkVolt(ckt, &tmp, here->VDMOSname, "drain");
@@ -153,6 +242,29 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt,
here->VDMOSdNodePrime = here->VDMOSdNode;
}
+ if (model->VDMOSgateResistance != 0 ) {
+ if (here->VDMOSgNodePrime == 0) {
+ error = CKTmkVolt(ckt, &tmp, here->VDMOSname, "gate");
+ if (error) return(error);
+ here->VDMOSgNodePrime = tmp->number;
+
+ if (ckt->CKTcopyNodesets) {
+ CKTnode *tmpNode;
+ IFuid tmpName;
+
+ if (CKTinst2Node(ckt, here, 2, &tmpNode, &tmpName) == OK) {
+ if (tmpNode->nsGiven) {
+ tmp->nodeset = tmpNode->nodeset;
+ tmp->nsGiven = tmpNode->nsGiven;
+ }
+ }
+ }
+ }
+ }
+ else {
+ here->VDMOSgNodePrime = here->VDMOSgNode;
+ }
+
if (model->VDMOSsourceResistance != 0) {
if (here->VDMOSsNodePrime == 0) {
error = CKTmkVolt(ckt, &tmp, here->VDMOSname, "source");
@@ -177,32 +289,9 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt,
here->VDMOSsNodePrime = here->VDMOSsNode;
}
- if (model->VDMOSgateResistance != 0 ) {
- if (here->VDMOSgNodePrime == 0) {
- error = CKTmkVolt(ckt, &tmp, here->VDMOSname, "gate");
- if (error) return(error);
- here->VDMOSgNodePrime = 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->VDMOSgNodePrime = here->VDMOSgNode;
- }
-
if (model->VDIOresistance != 0 ) {
if (here->VDIOposPrimeNode == 0) {
- error = CKTmkVolt(ckt, &tmp, here->VDMOSname, "bulk diode");
+ error = CKTmkVolt(ckt, &tmp, here->VDMOSname, "body diode");
if (error) return(error);
here->VDIOposPrimeNode = tmp->number;
@@ -223,6 +312,18 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt,
here->VDIOposPrimeNode = here->VDMOSsNode;
}
+ if ((here->VDMOStnodeoutGiven) && (model->VDMOSrthjc!=0.0)) {
+ if(here->VDMOSvcktTbranch == 0) {
+ error = CKTmkCur(ckt,&tmp,here->VDMOSname,"VcktTemp");
+ if(error) return(error);
+ here->VDMOSvcktTbranch = tmp->number;
+ }
+ if (here->VDMOStNodePrime == 0) {
+ error = CKTmkVolt(ckt, &tmp, here->VDMOSname, "thermal node");
+ if (error) return(error);
+ here->VDMOStNodePrime = tmp->number;
+ }
+ }
/* macro to make elements with built in test for out of memory */
#define TSTALLOC(ptr,first,second) \
@@ -230,6 +331,25 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\
return(E_NOMEM);\
} } while(0)
+ if ((here->VDMOStnodeoutGiven) && (model->VDMOSrthjc!=0.0)) {
+ TSTALLOC(VDMOSTemptempPtr, VDMOStempNode, VDMOStempNode);
+ TSTALLOC(VDMOSTempdpPtr, VDMOStempNode, VDMOSdNodePrime);
+ TSTALLOC(VDMOSTempspPtr, VDMOStempNode, VDMOSsNodePrime);
+ TSTALLOC(VDMOSTempgpPtr, VDMOStempNode, VDMOSgNodePrime);
+ TSTALLOC(VDMOSGPtempPtr, VDMOSgNodePrime, VDMOStempNode);
+ TSTALLOC(VDMOSDPtempPtr, VDMOSdNodePrime, VDMOStempNode);
+ TSTALLOC(VDMOSSPtempPtr, VDMOSsNodePrime, VDMOStempNode);
+
+ TSTALLOC(VDMOSTcasetcasePtr, VDMOStcaseNode, VDMOStcaseNode); /* Rthjc between tj and tcase*/
+ TSTALLOC(VDMOSTcasetempPtr, VDMOStcaseNode, VDMOStempNode);
+ TSTALLOC(VDMOSTemptcasePtr, VDMOStempNode, VDMOStcaseNode);
+ TSTALLOC(VDMOSTptpPtr, VDMOStNodePrime, VDMOStNodePrime); /* Rthca between tcase and Vsrc */
+ TSTALLOC(VDMOSTptcasePtr, VDMOStNodePrime, VDMOStempNode);
+ TSTALLOC(VDMOSTcasetpPtr, VDMOStempNode, VDMOStNodePrime);
+ TSTALLOC(VDMOSCktTcktTPtr, VDMOSvcktTbranch, VDMOSvcktTbranch); /* Vsrc=cktTemp to gnd */
+ TSTALLOC(VDMOSCktTtpPtr, VDMOSvcktTbranch, VDMOStNodePrime);
+ TSTALLOC(VDMOSTpcktTPtr, VDMOStNodePrime, VDMOSvcktTbranch);
+ }
TSTALLOC(VDMOSDdPtr, VDMOSdNode, VDMOSdNode);
TSTALLOC(VDMOSGgPtr, VDMOSgNode, VDMOSgNode);
TSTALLOC(VDMOSSsPtr, VDMOSsNode, VDMOSsNode);
@@ -294,6 +414,16 @@ VDMOSunsetup(GENmodel *inModel, CKTcircuit *ckt)
&& here->VDIOposPrimeNode != here->VDMOSsNode)
CKTdltNNum(ckt, here->VDIOposPrimeNode);
here->VDIOposPrimeNode = 0;
+
+ if ((here->VDMOStnodeoutGiven) && (model->VDMOSrthjc!=0.0)) {
+ if (here->VDMOStNodePrime > 0)
+ CKTdltNNum(ckt, here->VDMOStNodePrime);
+ here->VDMOStNodePrime = 0;
+ if (here->VDMOSvcktTbranch > 0)
+ CKTdltNNum(ckt, here->VDMOSvcktTbranch);
+ here->VDMOSvcktTbranch = 0;
+ }
+
}
}
return OK;
diff --git a/src/spicelib/devices/vdmos/vdmossoachk.c b/src/spicelib/devices/vdmos/vdmossoachk.c
new file mode 100644
index 000000000..d47164965
--- /dev/null
+++ b/src/spicelib/devices/vdmos/vdmossoachk.c
@@ -0,0 +1,142 @@
+/**********
+Copyright 2013 Dietmar Warning. All rights reserved.
+Author: 2013 Dietmar Warning
+**********/
+
+#include "ngspice/ngspice.h"
+#include "ngspice/cktdefs.h"
+#include "vdmosdefs.h"
+#include "ngspice/trandefs.h"
+#include "ngspice/sperror.h"
+#include "ngspice/suffix.h"
+#include "ngspice/cpdefs.h"
+
+
+int
+VDMOSsoaCheck(CKTcircuit *ckt, GENmodel *inModel)
+{
+ VDMOSmodel *model = (VDMOSmodel *) inModel;
+ VDMOSinstance *here;
+ double vgs, vgd, vds; /* actual mos voltages */
+ int maxwarns;
+ static int warns_vgs = 0, warns_vgd = 0, warns_vds = 0;
+
+ if (!ckt) {
+ warns_vgs = 0;
+ warns_vgd = 0;
+ warns_vds = 0;
+ return OK;
+ }
+
+ maxwarns = ckt->CKTsoaMaxWarns;
+
+ for (; model; model = VDMOSnextModel(model)) {
+
+ for (here = VDMOSinstances(model); here; here = VDMOSnextInstance(here)) {
+
+ vgs = ckt->CKTrhsOld [here->VDMOSgNode] -
+ ckt->CKTrhsOld [here->VDMOSsNodePrime];
+
+ vgd = ckt->CKTrhsOld [here->VDMOSgNode] -
+ ckt->CKTrhsOld [here->VDMOSdNodePrime];
+
+ vds = ckt->CKTrhsOld [here->VDMOSdNodePrime] -
+ ckt->CKTrhsOld [here->VDMOSsNodePrime];
+
+ if (!model->VDMOSvgsrMaxGiven) {
+ if (fabs(vgs) > model->VDMOSvgsMax)
+ if (warns_vgs < maxwarns) {
+ soa_printf(ckt, (GENinstance*) here,
+ "Vgs=%g has exceeded Vgs_max=%g\n",
+ vgs, model->VDMOSvgsMax);
+ warns_vgs++;
+ }
+ } else {
+ if (model->VDMOStype > 0) {
+ if (vgs > model->VDMOSvgsMax)
+ if (warns_vgs < maxwarns) {
+ soa_printf(ckt, (GENinstance*) here,
+ "Vgs=%g has exceeded Vgs_max=%g\n",
+ vgs, model->VDMOSvgsMax);
+ warns_vgs++;
+ }
+ if (-1*vgs > model->VDMOSvgsrMax)
+ if (warns_vgs < maxwarns) {
+ soa_printf(ckt, (GENinstance*) here,
+ "Vgs=%g has exceeded Vgsr_max=%g\n",
+ vgs, model->VDMOSvgsrMax);
+ warns_vgs++;
+ }
+ } else {
+ if (vgs > model->VDMOSvgsrMax)
+ if (warns_vgs < maxwarns) {
+ soa_printf(ckt, (GENinstance*) here,
+ "Vgs=%g has exceeded Vgsr_max=%g\n",
+ vgs, model->VDMOSvgsrMax);
+ warns_vgs++;
+ }
+ if (-1*vgs > model->VDMOSvgsMax)
+ if (warns_vgs < maxwarns) {
+ soa_printf(ckt, (GENinstance*) here,
+ "Vgs=%g has exceeded Vgs_max=%g\n",
+ vgs, model->VDMOSvgsMax);
+ warns_vgs++;
+ }
+ }
+ }
+
+ if (!model->VDMOSvgdrMaxGiven) {
+ if (fabs(vgd) > model->VDMOSvgdMax)
+ if (warns_vgd < maxwarns) {
+ soa_printf(ckt, (GENinstance*) here,
+ "Vgd=%g has exceeded Vgd_max=%g\n",
+ vgd, model->VDMOSvgdMax);
+ warns_vgd++;
+ }
+ } else {
+ if (model->VDMOStype > 0) {
+ if (vgd > model->VDMOSvgdMax)
+ if (warns_vgd < maxwarns) {
+ soa_printf(ckt, (GENinstance*) here,
+ "Vgd=%g has exceeded Vgd_max=%g\n",
+ vgd, model->VDMOSvgdMax);
+ warns_vgd++;
+ }
+ if (-1*vgd > model->VDMOSvgdrMax)
+ if (warns_vgd < maxwarns) {
+ soa_printf(ckt, (GENinstance*) here,
+ "Vgd=%g has exceeded Vgdr_max=%g\n",
+ vgd, model->VDMOSvgdrMax);
+ warns_vgd++;
+ }
+ } else {
+ if (vgd > model->VDMOSvgdrMax)
+ if (warns_vgd < maxwarns) {
+ soa_printf(ckt, (GENinstance*) here,
+ "Vgd=%g has exceeded Vgdr_max=%g\n",
+ vgd, model->VDMOSvgdrMax);
+ warns_vgd++;
+ }
+ if (-1*vgd > model->VDMOSvgdMax)
+ if (warns_vgd < maxwarns) {
+ soa_printf(ckt, (GENinstance*) here,
+ "Vgd=%g has exceeded Vgd_max=%g\n",
+ vgd, model->VDMOSvgdMax);
+ warns_vgd++;
+ }
+ }
+ }
+
+ if (fabs(vds) > model->VDMOSvdsMax)
+ if (warns_vds < maxwarns) {
+ soa_printf(ckt, (GENinstance*) here,
+ "Vds=%g has exceeded Vds_max=%g\n",
+ vds, model->VDMOSvdsMax);
+ warns_vds++;
+ }
+
+ }
+ }
+
+ return OK;
+}
diff --git a/src/spicelib/devices/vdmos/vdmostemp.c b/src/spicelib/devices/vdmos/vdmostemp.c
index 530a720c0..4b9fda07b 100644
--- a/src/spicelib/devices/vdmos/vdmostemp.c
+++ b/src/spicelib/devices/vdmos/vdmostemp.c
@@ -2,6 +2,7 @@
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Thomas L. Quarles
Modified: 2000 AlansFixes
+VDMOS: 2018 Holger Vogt, 2020 Dietmar Warning
**********/
#include "ngspice/ngspice.h"
@@ -21,7 +22,7 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt)
double fact1,fact2;
double kt,kt1;
double arg1;
- double ratio,ratio4;
+ double ratio;
double phio;
double pbfact1,pbfact;
double vt,vtnom;
@@ -45,22 +46,21 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt)
pbfact1 = -2*vtnom *(1.5*log(fact1)+CHARGE*arg1);
/* now model parameter preprocessing */
-
if (model->VDMOSphi <= 0.0) {
SPfrontEnd->IFerrorf(ERR_FATAL,
"%s: Phi is not positive.", model->VDMOSmodName);
return(E_BADPARM);
}
- model->VDMOSoxideCapFactor = 0;
+ model->VDMOSoxideCapFactor = 3.9 * 8.854214871e-12 / 1e-07; /* use default Tox of 100nm */
- /* bulk diode model */
+ /* body diode model */
/* limit activation energy to min of .1 */
- if (model->VDMOSDeg<.1) {
+ if (model->VDMOSeg<.1) {
SPfrontEnd->IFerrorf(ERR_WARNING,
- "%s: bulk diode activation energy too small, limited to 0.1",
+ "%s: body diode activation energy too small, limited to 0.1",
model->VDMOSmodName);
- model->VDMOSDeg = .1;
+ model->VDMOSeg = .1;
}
/* limit depletion cap coeff to max of .95 */
if (model->VDIOdepletionCapCoeff>.95) {
@@ -72,12 +72,7 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt)
/* 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 */
@@ -86,15 +81,29 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt)
double arg; /* 1 - fc */
/* perform the parameter defaulting */
-
if(!here->VDMOSdtempGiven) {
here->VDMOSdtemp = 0.0;
}
if(!here->VDMOStempGiven) {
here->VDMOStemp = ckt->CKTtemp + here->VDMOSdtemp;
}
- vt = here->VDMOStemp * CONSTKoverQ;
+
+ double dt = here->VDMOStemp - model->VDMOStnom;
+
+ /* vdmos temperature model */
ratio = here->VDMOStemp/model->VDMOStnom;
+ here->VDMOStTransconductance = model->VDMOStransconductance
+ * here->VDMOSm * here->VDMOSw / here->VDMOSl
+ * pow(ratio, model->VDMOSmu);
+
+ here->VDMOStVth = model->VDMOSvth0 - model->VDMOStype * model->VDMOStcvth * dt;
+
+ here->VDMOSdrainResistance = model->VDMOSdrainResistance / here->VDMOSm * pow(ratio, model->VDMOStexp0);
+
+ if (model->VDMOSqsGiven)
+ here->VDMOSqsResistance = model->VDMOSqsResistance / here->VDMOSm * pow(ratio, model->VDMOStexp1);
+
+ vt = here->VDMOStemp * CONSTKoverQ;
fact2 = here->VDMOStemp/REFTEMP;
kt = here->VDMOStemp * CONSTboltz;
egfet = 1.16-(7.02e-4*here->VDMOStemp*here->VDMOStemp)/
@@ -102,82 +111,15 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt)
arg = -egfet/(kt+kt)+1.1150877/(CONSTboltz*(REFTEMP+REFTEMP));
pbfact = -2*vt *(1.5*log(fact2)+CHARGE*arg);
- if(!here->VDMOSmGiven) {
- here->VDMOSm = 1;
- }
- if(!here->VDMOSlGiven) {
- here->VDMOSl = 1;
- }
- if(!here->VDMOSwGiven) {
- here->VDMOSw = 1;
- }
-
- ratio4 = ratio * sqrt(ratio);
- here->VDMOStTransconductance = model->VDMOStransconductance / ratio4;
phio = (model->VDMOSphi - pbfact1) / fact1;
- here->VDMOStPhi = fact2 * phio + pbfact;
- here->VDMOStVto = model->VDMOSvt0;
+ here->VDMOStPhi = fact2 * phio + pbfact; /* needed for distortion analysis */
- here->VDMOSf2d = 0;
- here->VDMOSf3d = 0;
- here->VDMOSf4d = 0;
-
- here->VDMOSf2s = 0;
- here->VDMOSf3s = 0;
- here->VDMOSf4s = 0;
-
-
- if (model->VDMOSdrainResistanceGiven) {
- if (model->VDMOSdrainResistance != 0) {
- here->VDMOSdrainConductance = here->VDMOSm /
- model->VDMOSdrainResistance;
- }
- else {
- here->VDMOSdrainConductance = 0;
- }
- } else {
- here->VDMOSdrainConductance = 0;
- }
- if(model->VDMOSsourceResistanceGiven) {
- if(model->VDMOSsourceResistance != 0) {
- here->VDMOSsourceConductance = here->VDMOSm /
- model->VDMOSsourceResistance;
- } else {
- here->VDMOSsourceConductance = 0;
- }
- } else {
- here->VDMOSsourceConductance = 0;
- }
- if (model->VDMOSgateResistanceGiven) {
- if (model->VDMOSgateResistance != 0) {
- here->VDMOSgateConductance = here->VDMOSm /
- model->VDMOSgateResistance;
- } else {
- here->VDMOSgateConductance = 0;
- }
- } else {
- here->VDMOSgateConductance = 0;
- }
- if (model->VDMOSrdsGiven) {
- if (model->VDMOSrds != 0) {
- here->VDMOSdsConductance = here->VDMOSm /
- model->VDMOSrds;
- }
- else {
- here->VDMOSdsConductance = 0;
- }
- }
- else {
- here->VDMOSdsConductance = 0;
- }
-
- /* bulk diode model */
+ /* body diode temperature model */
double pbo, gmaold;
double gmanew, factor;
double tBreakdownVoltage, vte, cbv;
- double xbv, xcbv, tol, iter, dt;
+ double xbv, xcbv, tol, iter;
- dt = here->VDMOStemp - model->VDMOStnom;
/* Junction grading temperature adjust */
factor = 1.0 + (model->VDIOgradCoeffTemp1 * dt)
+ (model->VDIOgradCoeffTemp2 * dt * dt);
@@ -185,7 +127,7 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt)
pbo = (model->VDIOjunctionPot - pbfact1) / fact1;
gmaold = (model->VDIOjunctionPot - pbo) / pbo;
- here->VDIOtJctCap = model->VDIOjunctionCap /
+ here->VDIOtJctCap = here->VDMOSm * model->VDIOjunctionCap /
(1 + here->VDIOtGradingCoeff*
(400e-6*(model->VDMOStnom - REFTEMP) - gmaold));
here->VDIOtJctPot = pbfact + fact2*pbo;
@@ -193,10 +135,10 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt)
here->VDIOtJctCap *= 1 + here->VDIOtGradingCoeff*
(400e-6*(here->VDMOStemp - REFTEMP) - gmanew);
- here->VDIOtSatCur = model->VDIOjctSatCur * exp(
+ here->VDIOtSatCur = here->VDMOSm * model->VDIOjctSatCur * exp(
((here->VDMOStemp / model->VDMOStnom) - 1) *
- model->VDMOSDeg / (model->VDMOSDn*vt) +
- model->VDMOSDxti / model->VDMOSDn *
+ model->VDMOSeg / (model->VDMOSn*vt) +
+ model->VDMOSxti / model->VDMOSn *
log(here->VDMOStemp / model->VDMOStnom));
/* the defintion of f1, just recompute after temperature adjusting
@@ -209,14 +151,14 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt)
here->VDIOtJctPot;
/* and Vcrit */
- vte = model->VDMOSDn*vt;
+ vte = model->VDMOSn*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;
+ if (here->VDIOtDepCap > 2.5) {
+ here->VDIOtJctPot = 2.5 / model->VDMOSn;
+ here->VDIOtDepCap = model->VDMOSn*here->VDIOtJctPot;
SPfrontEnd->IFerrorf(ERR_WARNING,
"%s: junction potential VJ too large, limited to %f",
model->VDMOSmodName, here->VDIOtJctPot);
@@ -224,16 +166,16 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt)
/* and now to compute the breakdown voltage, again, using
* temperature adjusted basic parameters */
- if (model->VDMOSDbvGiven) {
+ if (model->VDMOSbvGiven) {
/* tlev == 0 */
- tBreakdownVoltage = fabs(model->VDMOSDbv);
+ tBreakdownVoltage = fabs(model->VDMOSbv);
- cbv = model->VDMOSDibv;
+ cbv = model->VDMOSibv;
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, "%s: breakdown current increased to %g to resolve", here->VDMOSname, cbv);
SPfrontEnd->IFerrorf(ERR_WARNING,
"incompatibility with specified saturation current");
#endif
@@ -252,7 +194,7 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt)
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);
+ SPfrontEnd->IFerrorf(ERR_WARNING, "%s: unable to match forward and reverse diode regions: bv = %g, ibv = %g", here->VDMOSname, xbv, xcbv);
#endif
}
matched:
@@ -264,13 +206,8 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt)
+ (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;
- }
+ /* Series resistance temperature adjust (not implemented yet) */
+ here->VDIOtConductance = here->VDIOconductance;
here->VDIOtF2 = exp((1 + here->VDIOtGradingCoeff)*xfc);
here->VDIOtF3 = 1 - model->VDIOdepletionCapCoeff*
diff --git a/src/spicelib/parser/inp2m.c b/src/spicelib/parser/inp2m.c
index a91f36527..488f28b83 100644
--- a/src/spicelib/parser/inp2m.c
+++ b/src/spicelib/parser/inp2m.c
@@ -33,7 +33,7 @@ model_numnodes(int type)
if (type == INPtypelook("VDMOS")) /* 3 ; VDMOSnames */
{
- return 3;
+ return 5;
}
return 4;
diff --git a/visualc/sharedspice.vcxproj b/visualc/sharedspice.vcxproj
index a4dc57acb..212541ec4 100644
--- a/visualc/sharedspice.vcxproj
+++ b/visualc/sharedspice.vcxproj
@@ -2106,6 +2106,7 @@
+
diff --git a/visualc/vngspice-fftw.vcxproj b/visualc/vngspice-fftw.vcxproj
index f7c941462..b60c10eef 100644
--- a/visualc/vngspice-fftw.vcxproj
+++ b/visualc/vngspice-fftw.vcxproj
@@ -2547,6 +2547,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3
+
diff --git a/visualc/vngspice.vcxproj b/visualc/vngspice.vcxproj
index efd8222af..ba0762697 100644
--- a/visualc/vngspice.vcxproj
+++ b/visualc/vngspice.vcxproj
@@ -2555,6 +2555,7 @@
+