28 changed files with 7503 additions and 0 deletions
-
38src/spicelib/devices/vdmos/Makefile.am
-
165src/spicelib/devices/vdmos/vdmos.c
-
118src/spicelib/devices/vdmos/vdmosacld.c
-
437src/spicelib/devices/vdmos/vdmosask.c
-
99src/spicelib/devices/vdmos/vdmosconv.c
-
532src/spicelib/devices/vdmos/vdmosdefs.h
-
18src/spicelib/devices/vdmos/vdmosdel.c
-
1379src/spicelib/devices/vdmos/vdmosdist.c
-
578src/spicelib/devices/vdmos/vdmosdset.c
-
28src/spicelib/devices/vdmos/vdmosext.h
-
46src/spicelib/devices/vdmos/vdmosic.c
-
76src/spicelib/devices/vdmos/vdmosinit.c
-
13src/spicelib/devices/vdmos/vdmosinit.h
-
9src/spicelib/devices/vdmos/vdmositf.h
-
940src/spicelib/devices/vdmos/vdmosload.c
-
119src/spicelib/devices/vdmos/vdmosmask.c
-
154src/spicelib/devices/vdmos/vdmosmpar.c
-
190src/spicelib/devices/vdmos/vdmosnoi.c
-
123src/spicelib/devices/vdmos/vdmospar.c
-
132src/spicelib/devices/vdmos/vdmospzld.c
-
785src/spicelib/devices/vdmos/vdmossacl.c
-
238src/spicelib/devices/vdmos/vdmosset.c
-
623src/spicelib/devices/vdmos/vdmossld.c
-
68src/spicelib/devices/vdmos/vdmossprt.c
-
50src/spicelib/devices/vdmos/vdmossset.c
-
183src/spicelib/devices/vdmos/vdmossupd.c
-
332src/spicelib/devices/vdmos/vdmostemp.c
-
30src/spicelib/devices/vdmos/vdmostrun.c
@ -0,0 +1,38 @@ |
|||
## Process this file with automake to produce Makefile.in
|
|||
|
|||
noinst_LTLIBRARIES = libvdmos.la |
|||
|
|||
libvdmos_la_SOURCES = \
|
|||
vdmos.c \
|
|||
vdmosacld.c \
|
|||
vdmosask.c \
|
|||
vdmosconv.c \
|
|||
vdmosdefs.h \
|
|||
vdmosdel.c \
|
|||
vdmosdist.c \
|
|||
vdmosdset.c \
|
|||
vdmosext.h \
|
|||
vdmosic.c \
|
|||
vdmosinit.c \
|
|||
vdmosinit.h \
|
|||
vdmositf.h \
|
|||
vdmosload.c \
|
|||
vdmosmask.c \
|
|||
vdmosmpar.c \
|
|||
vdmosnoi.c \
|
|||
vdmospar.c \
|
|||
vdmospzld.c \
|
|||
vdmossacl.c \
|
|||
vdmosset.c \
|
|||
vdmossld.c \
|
|||
vdmossprt.c \
|
|||
vdmossset.c \
|
|||
vdmossupd.c \
|
|||
vdmostemp.c \
|
|||
vdmostrun.c |
|||
|
|||
|
|||
|
|||
AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include |
|||
AM_CFLAGS = $(STATIC) |
|||
MAINTAINERCLEANFILES = Makefile.in |
|||
@ -0,0 +1,165 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1987 Thomas L. Quarles |
|||
Modified: 2000 AlansFixes |
|||
**********/ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "ngspice/devdefs.h" |
|||
#include "ngspice/ifsim.h" |
|||
#include "vdmosdefs.h" |
|||
#include "ngspice/suffix.h" |
|||
|
|||
IFparm VDMOSpTable[] = { /* parameters */ |
|||
IOPU("m", VDMOS_M, IF_REAL , "Multiplier"), |
|||
IOPU("l", VDMOS_L, IF_REAL , "Length"), |
|||
IOPU("w", VDMOS_W, IF_REAL , "Width"), |
|||
IOPU("ad", VDMOS_AD, IF_REAL , "Drain area"), |
|||
IOPU("as", VDMOS_AS, IF_REAL , "Source area"), |
|||
IOPU("pd", VDMOS_PD, IF_REAL , "Drain perimeter"), |
|||
IOPU("ps", VDMOS_PS, IF_REAL , "Source perimeter"), |
|||
IOPU("nrd", VDMOS_NRD, IF_REAL , "Drain squares"), |
|||
IOPU("nrs", VDMOS_NRS, IF_REAL , "Source squares"), |
|||
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("icvbs", VDMOS_IC_VBS, IF_REAL , "Initial B-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, B-S voltages"), |
|||
IP( "sens_l", VDMOS_L_SENS, IF_FLAG, "flag to request sensitivity WRT length"), |
|||
IP( "sens_w", VDMOS_W_SENS, IF_FLAG, "flag to request sensitivity WRT width"), |
|||
|
|||
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( "ib", VDMOS_CB, IF_REAL, "Bulk current "), |
|||
OPU( "ibd", VDMOS_CBD, IF_REAL, "B-D junction current"), |
|||
OPU( "ibs", VDMOS_CBS, IF_REAL, "B-S junction current"), |
|||
OP( "vgs", VDMOS_VGS, IF_REAL, "Gate-Source voltage"), |
|||
OP( "vds", VDMOS_VDS, IF_REAL, "Drain-Source voltage"), |
|||
OP( "vbs", VDMOS_VBS, IF_REAL, "Bulk-Source voltage"), |
|||
OPU( "vbd", VDMOS_VBD, IF_REAL, "Bulk-Drain voltage"), |
|||
/* |
|||
OP( "cgs", VDMOS_CGS, IF_REAL , "Gate-Source capacitance"), |
|||
OP( "cgd", VDMOS_CGD, IF_REAL , "Gate-Drain 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( "bnode", VDMOS_BNODE, IF_INTEGER, "Number of the 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( "rs", VDMOS_SOURCERESIST, IF_REAL, "Source resistance"), |
|||
OPU("sourceconductance", VDMOS_SOURCECONDUCT, IF_REAL, "Conductance of source"), |
|||
OP( "rd", VDMOS_DRAINRESIST, IF_REAL, "Drain conductance"), |
|||
OPU("drainconductance", VDMOS_DRAINCONDUCT, IF_REAL, "Conductance of drain"), |
|||
|
|||
OP( "gm", VDMOS_GM, IF_REAL, "Transconductance"), |
|||
OP( "gds", VDMOS_GDS, IF_REAL, "Drain-Source conductance"), |
|||
OP( "gmb", VDMOS_GMBS, IF_REAL, "Bulk-Source transconductance"), |
|||
OPR( "gmbs", VDMOS_GMBS, IF_REAL, ""), |
|||
OPU( "gbd", VDMOS_GBD, IF_REAL, "Bulk-Drain conductance"), |
|||
OPU( "gbs", VDMOS_GBS, IF_REAL, "Bulk-Source conductance"), |
|||
|
|||
OP( "cbd", VDMOS_CAPBD, IF_REAL, "Bulk-Drain capacitance"), |
|||
OP( "cbs", VDMOS_CAPBS, IF_REAL, "Bulk-Source capacitance"), |
|||
OP( "cgs", VDMOS_CAPGS, IF_REAL, "Gate-Source capacitance"), |
|||
OP( "cgd", VDMOS_CAPGD, IF_REAL, "Gate-Drain capacitance"), |
|||
OP( "cgb", VDMOS_CAPGB, IF_REAL, "Gate-Bulk capacitance"), |
|||
|
|||
OPU( "cqgs",VDMOS_CQGS,IF_REAL,"Capacitance due to gate-source charge storage"), |
|||
OPU( "cqgd",VDMOS_CQGD,IF_REAL,"Capacitance due to gate-drain charge storage"), |
|||
OPU( "cqgb",VDMOS_CQGB,IF_REAL,"Capacitance due to gate-bulk charge storage"), |
|||
OPU( "cqbd",VDMOS_CQBD,IF_REAL,"Capacitance due to bulk-drain charge storage"), |
|||
OPU( "cqbs",VDMOS_CQBS,IF_REAL,"Capacitance due to bulk-source charge storage"), |
|||
|
|||
OP( "cbd0", VDMOS_CAPZEROBIASBD, IF_REAL, "Zero-Bias B-D junction capacitance"), |
|||
OP( "cbdsw0", VDMOS_CAPZEROBIASBDSW, IF_REAL, " "), |
|||
OP( "cbs0", VDMOS_CAPZEROBIASBS, IF_REAL, "Zero-Bias B-S junction capacitance"), |
|||
OP( "cbssw0", VDMOS_CAPZEROBIASBSSW, IF_REAL, " "), |
|||
|
|||
OPU( "qgs", VDMOS_QGS, IF_REAL, "Gate-Source charge storage"), |
|||
OPU( "qgd", VDMOS_QGD, IF_REAL, "Gate-Drain charge storage"), |
|||
OPU( "qgb", VDMOS_QGB, IF_REAL, "Gate-Bulk charge storage"), |
|||
OPU( "qbd", VDMOS_QBD, IF_REAL, "Bulk-Drain charge storage"), |
|||
OPU( "qbs", VDMOS_QBS, IF_REAL, "Bulk-Source charge storage"), |
|||
OPU( "p", VDMOS_POWER, IF_REAL, "Instaneous power"), |
|||
OPU( "sens_l_dc", VDMOS_L_SENS_DC, IF_REAL, "dc sensitivity wrt length"), |
|||
OPU( "sens_l_real", VDMOS_L_SENS_REAL,IF_REAL, |
|||
"real part of ac sensitivity wrt length"), |
|||
OPU( "sens_l_imag", VDMOS_L_SENS_IMAG,IF_REAL, |
|||
"imag part of ac sensitivity wrt length"), |
|||
OPU( "sens_l_mag", VDMOS_L_SENS_MAG, IF_REAL, |
|||
"sensitivity wrt l of ac magnitude"), |
|||
OPU( "sens_l_ph", VDMOS_L_SENS_PH, IF_REAL, |
|||
"sensitivity wrt l of ac phase"), |
|||
OPU( "sens_l_cplx", VDMOS_L_SENS_CPLX,IF_COMPLEX, "ac sensitivity wrt length"), |
|||
OPU( "sens_w_dc", VDMOS_W_SENS_DC, IF_REAL, "dc sensitivity wrt width"), |
|||
OPU( "sens_w_real", VDMOS_W_SENS_REAL,IF_REAL, |
|||
"real part of ac sensitivity wrt width"), |
|||
OPU( "sens_w_imag", VDMOS_W_SENS_IMAG,IF_REAL, |
|||
"imag part of ac sensitivity wrt width"), |
|||
OPU( "sens_w_mag", VDMOS_W_SENS_MAG, IF_REAL, |
|||
"sensitivity wrt w of ac magnitude"), |
|||
OPU( "sens_w_ph", VDMOS_W_SENS_PH, IF_REAL, |
|||
"sensitivity wrt w of ac phase"), |
|||
OPU( "sens_w_cplx", VDMOS_W_SENS_CPLX,IF_COMPLEX, "ac sensitivity wrt width") |
|||
}; |
|||
|
|||
IFparm VDMOSmPTable[] = { /* model parameters */ |
|||
OP("type", VDMOS_MOD_TYPE, IF_STRING, "N-channel or P-channel MOS"), |
|||
IOP("vto", VDMOS_MOD_VTO, IF_REAL ,"Threshold voltage"), |
|||
IOPR("vt0", VDMOS_MOD_VTO, IF_REAL ,"Threshold voltage"), |
|||
IOP("kp", VDMOS_MOD_KP, IF_REAL ,"Transconductance parameter"), |
|||
IOP("gamma", VDMOS_MOD_GAMMA, IF_REAL ,"Bulk threshold parameter"), |
|||
IOP("phi", VDMOS_MOD_PHI, IF_REAL ,"Surface potential"), |
|||
IOP("lambda",VDMOS_MOD_LAMBDA,IF_REAL ,"Channel length modulation"), |
|||
IOP("rd", VDMOS_MOD_RD, IF_REAL ,"Drain ohmic resistance"), |
|||
IOP("rs", VDMOS_MOD_RS, IF_REAL ,"Source ohmic resistance"), |
|||
IOPA("cbd", VDMOS_MOD_CBD, IF_REAL ,"B-D junction capacitance"), |
|||
IOPA("cbs", VDMOS_MOD_CBS, IF_REAL ,"B-S junction capacitance"), |
|||
IOP("is", VDMOS_MOD_IS, IF_REAL ,"Bulk junction sat. current"), |
|||
IOP("pb", VDMOS_MOD_PB, IF_REAL ,"Bulk junction potential"), |
|||
IOPA("cgso", VDMOS_MOD_CGSO, IF_REAL ,"Gate-source overlap cap."), |
|||
IOPA("cgdo", VDMOS_MOD_CGDO, IF_REAL ,"Gate-drain overlap cap."), |
|||
IOPA("cgbo", VDMOS_MOD_CGBO, IF_REAL ,"Gate-bulk overlap cap."), |
|||
IOP("rsh", VDMOS_MOD_RSH, IF_REAL ,"Sheet resistance"), |
|||
IOPA("cj", VDMOS_MOD_CJ, IF_REAL ,"Bottom junction cap per area"), |
|||
IOP("mj", VDMOS_MOD_MJ, IF_REAL ,"Bottom grading coefficient"), |
|||
IOPA("cjsw", VDMOS_MOD_CJSW, IF_REAL ,"Side junction cap per area"), |
|||
IOP("mjsw", VDMOS_MOD_MJSW, IF_REAL ,"Side grading coefficient"), |
|||
IOP("js", VDMOS_MOD_JS, IF_REAL ,"Bulk jct. sat. current density"), |
|||
IOP("tox", VDMOS_MOD_TOX, IF_REAL ,"Oxide thickness"), |
|||
IOP("ld", VDMOS_MOD_LD, IF_REAL ,"Lateral diffusion"), |
|||
IOP("u0", VDMOS_MOD_U0, IF_REAL ,"Surface mobility"), |
|||
IOPR("uo", VDMOS_MOD_U0, IF_REAL ,"Surface mobility"), |
|||
IOP("fc", VDMOS_MOD_FC, IF_REAL ,"Forward bias jct. fit parm."), |
|||
IP("nmos", VDMOS_MOD_NMOS, IF_FLAG ,"N type MOSfet model"), |
|||
IP("pmos", VDMOS_MOD_PMOS, IF_FLAG ,"P type MOSfet model"), |
|||
IOP("nsub", VDMOS_MOD_NSUB, IF_REAL ,"Substrate doping"), |
|||
IOP("tpg", VDMOS_MOD_TPG, IF_INTEGER,"Gate type"), |
|||
IOP("nss", VDMOS_MOD_NSS, IF_REAL ,"Surface state density"), |
|||
IOP("tnom", VDMOS_MOD_TNOM, IF_REAL ,"Parameter measurement temperature"), |
|||
IOP("kf", VDMOS_MOD_KF, IF_REAL ,"Flicker noise coefficient"), |
|||
IOP("af", VDMOS_MOD_AF, IF_REAL ,"Flicker noise exponent") |
|||
}; |
|||
|
|||
char *VDMOSnames[] = { |
|||
"Drain", |
|||
"Gate", |
|||
"Source", |
|||
"Bulk" |
|||
}; |
|||
|
|||
int VDMOSnSize = NUMELEMS(VDMOSnames); |
|||
int VDMOSpTSize = NUMELEMS(VDMOSpTable); |
|||
int VDMOSmPTSize = NUMELEMS(VDMOSmPTable); |
|||
int VDMOSiSize = sizeof(VDMOSinstance); |
|||
int VDMOSmSize = sizeof(VDMOSmodel); |
|||
@ -0,0 +1,118 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1985 Thomas L. Quarles |
|||
Modified: 2000 AlansFixes |
|||
**********/ |
|||
/* |
|||
*/ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "ngspice/cktdefs.h" |
|||
#include "vdmosdefs.h" |
|||
#include "ngspice/sperror.h" |
|||
#include "ngspice/suffix.h" |
|||
|
|||
|
|||
int |
|||
VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt) |
|||
{ |
|||
VDMOSmodel *model = (VDMOSmodel*)inModel; |
|||
VDMOSinstance *here; |
|||
int xnrm; |
|||
int xrev; |
|||
double xgs; |
|||
double xgd; |
|||
double xgb; |
|||
double xbd; |
|||
double xbs; |
|||
double capgs; |
|||
double capgd; |
|||
double capgb; |
|||
double GateBulkOverlapCap; |
|||
double GateDrainOverlapCap; |
|||
double GateSourceOverlapCap; |
|||
double EffectiveLength; |
|||
|
|||
for( ; model != NULL; model = VDMOSnextModel(model)) { |
|||
for(here = VDMOSinstances(model); here!= NULL; |
|||
here = VDMOSnextInstance(here)) { |
|||
|
|||
if (here->VDMOSmode < 0) { |
|||
xnrm=0; |
|||
xrev=1; |
|||
} else { |
|||
xnrm=1; |
|||
xrev=0; |
|||
} |
|||
/* |
|||
* meyer's model parameters |
|||
*/ |
|||
EffectiveLength=here->VDMOSl - 2*model->VDMOSlatDiff; |
|||
|
|||
GateSourceOverlapCap = model->VDMOSgateSourceOverlapCapFactor * |
|||
here->VDMOSm * here->VDMOSw; |
|||
GateDrainOverlapCap = model->VDMOSgateDrainOverlapCapFactor * |
|||
here->VDMOSm * here->VDMOSw; |
|||
GateBulkOverlapCap = model->VDMOSgateBulkOverlapCapFactor * |
|||
here->VDMOSm * EffectiveLength; |
|||
|
|||
capgs = ( *(ckt->CKTstate0+here->VDMOScapgs)+ |
|||
*(ckt->CKTstate0+here->VDMOScapgs) + |
|||
GateSourceOverlapCap ); |
|||
capgd = ( *(ckt->CKTstate0+here->VDMOScapgd)+ |
|||
*(ckt->CKTstate0+here->VDMOScapgd) + |
|||
GateDrainOverlapCap ); |
|||
capgb = ( *(ckt->CKTstate0+here->VDMOScapgb)+ |
|||
*(ckt->CKTstate0+here->VDMOScapgb) + |
|||
GateBulkOverlapCap ); |
|||
xgs = capgs * ckt->CKTomega; |
|||
xgd = capgd * ckt->CKTomega; |
|||
xgb = capgb * ckt->CKTomega; |
|||
xbd = here->VDMOScapbd * ckt->CKTomega; |
|||
xbs = here->VDMOScapbs * ckt->CKTomega; |
|||
/* |
|||
* load matrix |
|||
*/ |
|||
|
|||
*(here->VDMOSGgPtr +1) += xgd+xgs+xgb; |
|||
*(here->VDMOSBbPtr +1) += xgb+xbd+xbs; |
|||
*(here->VDMOSDPdpPtr +1) += xgd+xbd; |
|||
*(here->VDMOSSPspPtr +1) += xgs+xbs; |
|||
*(here->VDMOSGbPtr +1) -= xgb; |
|||
*(here->VDMOSGdpPtr +1) -= xgd; |
|||
*(here->VDMOSGspPtr +1) -= xgs; |
|||
*(here->VDMOSBgPtr +1) -= xgb; |
|||
*(here->VDMOSBdpPtr +1) -= xbd; |
|||
*(here->VDMOSBspPtr +1) -= xbs; |
|||
*(here->VDMOSDPgPtr +1) -= xgd; |
|||
*(here->VDMOSDPbPtr +1) -= xbd; |
|||
*(here->VDMOSSPgPtr +1) -= xgs; |
|||
*(here->VDMOSSPbPtr +1) -= xbs; |
|||
*(here->VDMOSDdPtr) += here->VDMOSdrainConductance; |
|||
*(here->VDMOSSsPtr) += here->VDMOSsourceConductance; |
|||
*(here->VDMOSBbPtr) += here->VDMOSgbd+here->VDMOSgbs; |
|||
*(here->VDMOSDPdpPtr) += here->VDMOSdrainConductance+ |
|||
here->VDMOSgds+here->VDMOSgbd+ |
|||
xrev*(here->VDMOSgm+here->VDMOSgmbs); |
|||
*(here->VDMOSSPspPtr) += here->VDMOSsourceConductance+ |
|||
here->VDMOSgds+here->VDMOSgbs+ |
|||
xnrm*(here->VDMOSgm+here->VDMOSgmbs); |
|||
*(here->VDMOSDdpPtr) -= here->VDMOSdrainConductance; |
|||
*(here->VDMOSSspPtr) -= here->VDMOSsourceConductance; |
|||
*(here->VDMOSBdpPtr) -= here->VDMOSgbd; |
|||
*(here->VDMOSBspPtr) -= here->VDMOSgbs; |
|||
*(here->VDMOSDPdPtr) -= here->VDMOSdrainConductance; |
|||
*(here->VDMOSDPgPtr) += (xnrm-xrev)*here->VDMOSgm; |
|||
*(here->VDMOSDPbPtr) += -here->VDMOSgbd+(xnrm-xrev)*here->VDMOSgmbs; |
|||
*(here->VDMOSDPspPtr) -= here->VDMOSgds+ |
|||
xnrm*(here->VDMOSgm+here->VDMOSgmbs); |
|||
*(here->VDMOSSPgPtr) -= (xnrm-xrev)*here->VDMOSgm; |
|||
*(here->VDMOSSPsPtr) -= here->VDMOSsourceConductance; |
|||
*(here->VDMOSSPbPtr) -= here->VDMOSgbs+(xnrm-xrev)*here->VDMOSgmbs; |
|||
*(here->VDMOSSPdpPtr) -= here->VDMOSgds+ |
|||
xrev*(here->VDMOSgm+here->VDMOSgmbs); |
|||
|
|||
} |
|||
} |
|||
return(OK); |
|||
} |
|||
@ -0,0 +1,437 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1987 Thomas L. Quarles |
|||
Modified: 2000 AlansFixes |
|||
**********/ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "ngspice/const.h" |
|||
#include "ngspice/ifsim.h" |
|||
#include "ngspice/cktdefs.h" |
|||
#include "ngspice/devdefs.h" |
|||
#include "vdmosdefs.h" |
|||
#include "ngspice/sperror.h" |
|||
#include "ngspice/suffix.h" |
|||
|
|||
/*ARGSUSED*/ |
|||
int |
|||
VDMOSask(CKTcircuit *ckt, GENinstance *inst, int which, IFvalue *value, |
|||
IFvalue *select) |
|||
{ |
|||
VDMOSinstance *here = (VDMOSinstance*)inst; |
|||
double vr; |
|||
double vi; |
|||
double sr; |
|||
double si; |
|||
double vm; |
|||
static char *msg = "Current and power not available for ac analysis"; |
|||
switch(which) { |
|||
case VDMOS_TEMP: |
|||
value->rValue = here->VDMOStemp - CONSTCtoK; |
|||
return(OK); |
|||
case VDMOS_DTEMP: |
|||
value->rValue = here->VDMOSdtemp; |
|||
return(OK); |
|||
case VDMOS_CGS: |
|||
value->rValue = 2* *(ckt->CKTstate0 + here->VDMOScapgs); |
|||
return(OK); |
|||
case VDMOS_CGD: |
|||
value->rValue = 2* *(ckt->CKTstate0 + here->VDMOScapgd); |
|||
return(OK); |
|||
case VDMOS_M: |
|||
value->rValue = here->VDMOSm; |
|||
return(OK); |
|||
case VDMOS_L: |
|||
value->rValue = here->VDMOSl; |
|||
return(OK); |
|||
case VDMOS_W: |
|||
value->rValue = here->VDMOSw; |
|||
return(OK); |
|||
case VDMOS_AS: |
|||
value->rValue = here->VDMOSsourceArea; |
|||
return(OK); |
|||
case VDMOS_AD: |
|||
value->rValue = here->VDMOSdrainArea; |
|||
return(OK); |
|||
case VDMOS_PS: |
|||
value->rValue = here->VDMOSsourcePerimiter; |
|||
return(OK); |
|||
case VDMOS_PD: |
|||
value->rValue = here->VDMOSdrainPerimiter; |
|||
return(OK); |
|||
case VDMOS_NRS: |
|||
value->rValue = here->VDMOSsourceSquares; |
|||
return(OK); |
|||
case VDMOS_NRD: |
|||
value->rValue = here->VDMOSdrainSquares; |
|||
return(OK); |
|||
case VDMOS_OFF: |
|||
value->rValue = here->VDMOSoff; |
|||
return(OK); |
|||
case VDMOS_IC_VBS: |
|||
value->rValue = here->VDMOSicVBS; |
|||
return(OK); |
|||
case VDMOS_IC_VDS: |
|||
value->rValue = here->VDMOSicVDS; |
|||
return(OK); |
|||
case VDMOS_IC_VGS: |
|||
value->rValue = here->VDMOSicVGS; |
|||
return(OK); |
|||
case VDMOS_DNODE: |
|||
value->iValue = here->VDMOSdNode; |
|||
return(OK); |
|||
case VDMOS_GNODE: |
|||
value->iValue = here->VDMOSgNode; |
|||
return(OK); |
|||
case VDMOS_SNODE: |
|||
value->iValue = here->VDMOSsNode; |
|||
return(OK); |
|||
case VDMOS_BNODE: |
|||
value->iValue = here->VDMOSbNode; |
|||
return(OK); |
|||
case VDMOS_DNODEPRIME: |
|||
value->iValue = here->VDMOSdNodePrime; |
|||
return(OK); |
|||
case VDMOS_SNODEPRIME: |
|||
value->iValue = here->VDMOSsNodePrime; |
|||
return(OK); |
|||
case VDMOS_SOURCECONDUCT: |
|||
value->rValue = here->VDMOSsourceConductance; |
|||
return(OK); |
|||
case VDMOS_SOURCERESIST: |
|||
if (here->VDMOSsNodePrime != here->VDMOSsNode) |
|||
value->rValue = 1.0 / here->VDMOSsourceConductance; |
|||
else |
|||
value->rValue = 0.0; |
|||
return(OK); |
|||
case VDMOS_DRAINCONDUCT: |
|||
value->rValue = here->VDMOSdrainConductance; |
|||
return(OK); |
|||
case VDMOS_DRAINRESIST: |
|||
if (here->VDMOSdNodePrime != here->VDMOSdNode) |
|||
value->rValue = 1.0 / here->VDMOSdrainConductance; |
|||
else |
|||
value->rValue = 0.0; |
|||
return(OK); |
|||
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); |
|||
case VDMOS_CBS: |
|||
value->rValue = here->VDMOScbs; |
|||
return(OK); |
|||
case VDMOS_CBD: |
|||
value->rValue = here->VDMOScbd; |
|||
return(OK); |
|||
case VDMOS_GMBS: |
|||
value->rValue = here->VDMOSgmbs; |
|||
return(OK); |
|||
case VDMOS_GM: |
|||
value->rValue = here->VDMOSgm; |
|||
return(OK); |
|||
case VDMOS_GDS: |
|||
value->rValue = here->VDMOSgds; |
|||
return(OK); |
|||
case VDMOS_GBD: |
|||
value->rValue = here->VDMOSgbd; |
|||
return(OK); |
|||
case VDMOS_GBS: |
|||
value->rValue = here->VDMOSgbs; |
|||
return(OK); |
|||
case VDMOS_CAPBD: |
|||
value->rValue = here->VDMOScapbd; |
|||
return(OK); |
|||
case VDMOS_CAPBS: |
|||
value->rValue = here->VDMOScapbs; |
|||
return(OK); |
|||
case VDMOS_CAPZEROBIASBD: |
|||
value->rValue = here->VDMOSCbd; |
|||
return(OK); |
|||
case VDMOS_CAPZEROBIASBDSW: |
|||
value->rValue = here->VDMOSCbdsw; |
|||
return(OK); |
|||
case VDMOS_CAPZEROBIASBS: |
|||
value->rValue = here->VDMOSCbs; |
|||
return(OK); |
|||
case VDMOS_CAPZEROBIASBSSW: |
|||
value->rValue = here->VDMOSCbssw; |
|||
return(OK); |
|||
case VDMOS_VBD: |
|||
value->rValue = *(ckt->CKTstate0 + here->VDMOSvbd); |
|||
return(OK); |
|||
case VDMOS_VBS: |
|||
value->rValue = *(ckt->CKTstate0 + here->VDMOSvbs); |
|||
return(OK); |
|||
case VDMOS_VGS: |
|||
value->rValue = *(ckt->CKTstate0 + here->VDMOSvgs); |
|||
return(OK); |
|||
case VDMOS_VDS: |
|||
value->rValue = *(ckt->CKTstate0 + here->VDMOSvds); |
|||
return(OK); |
|||
case VDMOS_CAPGS: |
|||
value->rValue = 2* *(ckt->CKTstate0 + here->VDMOScapgs); |
|||
/* add overlap capacitance */ |
|||
value->rValue += (VDMOSmodPtr(here)->VDMOSgateSourceOverlapCapFactor) |
|||
* here->VDMOSm |
|||
* (here->VDMOSw); |
|||
return(OK); |
|||
case VDMOS_QGS: |
|||
value->rValue = *(ckt->CKTstate0 + here->VDMOSqgs); |
|||
return(OK); |
|||
case VDMOS_CQGS: |
|||
value->rValue = *(ckt->CKTstate0 + here->VDMOScqgs); |
|||
return(OK); |
|||
case VDMOS_CAPGD: |
|||
value->rValue = 2* *(ckt->CKTstate0 + here->VDMOScapgd); |
|||
/* add overlap capacitance */ |
|||
value->rValue += (VDMOSmodPtr(here)->VDMOSgateDrainOverlapCapFactor) |
|||
* here->VDMOSm |
|||
* (here->VDMOSw); |
|||
return(OK); |
|||
case VDMOS_QGD: |
|||
value->rValue = *(ckt->CKTstate0 + here->VDMOSqgd); |
|||
return(OK); |
|||
case VDMOS_CQGD: |
|||
value->rValue = *(ckt->CKTstate0 + here->VDMOScqgd); |
|||
return(OK); |
|||
case VDMOS_CAPGB: |
|||
value->rValue = 2* *(ckt->CKTstate0 + here->VDMOScapgb); |
|||
/* add overlap capacitance */ |
|||
value->rValue += (VDMOSmodPtr(here)->VDMOSgateBulkOverlapCapFactor) |
|||
* here->VDMOSm |
|||
* (here->VDMOSl |
|||
-2*(VDMOSmodPtr(here)->VDMOSlatDiff)); |
|||
return(OK); |
|||
case VDMOS_QGB: |
|||
value->rValue = *(ckt->CKTstate0 + here->VDMOSqgb); |
|||
return(OK); |
|||
case VDMOS_CQGB: |
|||
value->rValue = *(ckt->CKTstate0 + here->VDMOScqgb); |
|||
return(OK); |
|||
case VDMOS_QBD: |
|||
value->rValue = *(ckt->CKTstate0 + here->VDMOSqbd); |
|||
return(OK); |
|||
case VDMOS_CQBD: |
|||
value->rValue = *(ckt->CKTstate0 + here->VDMOScqbd); |
|||
return(OK); |
|||
case VDMOS_QBS: |
|||
value->rValue = *(ckt->CKTstate0 + here->VDMOSqbs); |
|||
return(OK); |
|||
case VDMOS_CQBS: |
|||
value->rValue = *(ckt->CKTstate0 + here->VDMOScqbs); |
|||
return(OK); |
|||
case VDMOS_L_SENS_DC: |
|||
if(ckt->CKTsenInfo && here->VDMOSsens_l){ |
|||
value->rValue = *(ckt->CKTsenInfo->SEN_Sap[select->iValue + 1]+ |
|||
here->VDMOSsenParmNo); |
|||
} |
|||
return(OK); |
|||
case VDMOS_L_SENS_REAL: |
|||
if(ckt->CKTsenInfo && here->VDMOSsens_l){ |
|||
value->rValue = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ |
|||
here->VDMOSsenParmNo); |
|||
} |
|||
return(OK); |
|||
case VDMOS_L_SENS_IMAG: |
|||
if(ckt->CKTsenInfo && here->VDMOSsens_l){ |
|||
value->rValue = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ |
|||
here->VDMOSsenParmNo); |
|||
} |
|||
return(OK); |
|||
case VDMOS_L_SENS_MAG: |
|||
if(ckt->CKTsenInfo && here->VDMOSsens_l){ |
|||
vr = *(ckt->CKTrhsOld + select->iValue + 1); |
|||
vi = *(ckt->CKTirhsOld + select->iValue + 1); |
|||
vm = sqrt(vr*vr + vi*vi); |
|||
if(vm == 0){ |
|||
value->rValue = 0; |
|||
return(OK); |
|||
} |
|||
sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ |
|||
here->VDMOSsenParmNo); |
|||
si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ |
|||
here->VDMOSsenParmNo); |
|||
value->rValue = (vr * sr + vi * si)/vm; |
|||
} |
|||
return(OK); |
|||
case VDMOS_L_SENS_PH: |
|||
if(ckt->CKTsenInfo && here->VDMOSsens_l){ |
|||
vr = *(ckt->CKTrhsOld + select->iValue + 1); |
|||
vi = *(ckt->CKTirhsOld + select->iValue + 1); |
|||
vm = vr*vr + vi*vi; |
|||
if(vm == 0){ |
|||
value->rValue = 0; |
|||
return(OK); |
|||
} |
|||
sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ |
|||
here->VDMOSsenParmNo); |
|||
si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ |
|||
here->VDMOSsenParmNo); |
|||
value->rValue = (vr * si - vi * sr)/vm; |
|||
} |
|||
return(OK); |
|||
case VDMOS_L_SENS_CPLX: |
|||
if(ckt->CKTsenInfo && here->VDMOSsens_l){ |
|||
value->cValue.real= |
|||
*(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ |
|||
here->VDMOSsenParmNo); |
|||
value->cValue.imag= |
|||
*(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ |
|||
here->VDMOSsenParmNo); |
|||
} |
|||
return(OK); |
|||
case VDMOS_W_SENS_DC: |
|||
if(ckt->CKTsenInfo && here->VDMOSsens_w){ |
|||
value->rValue = *(ckt->CKTsenInfo->SEN_Sap[select->iValue + 1]+ |
|||
here->VDMOSsenParmNo + here->VDMOSsens_l); |
|||
} |
|||
return(OK); |
|||
case VDMOS_W_SENS_REAL: |
|||
if(ckt->CKTsenInfo && here->VDMOSsens_w){ |
|||
value->rValue = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ |
|||
here->VDMOSsenParmNo + here->VDMOSsens_l); |
|||
} |
|||
return(OK); |
|||
case VDMOS_W_SENS_IMAG: |
|||
if(ckt->CKTsenInfo && here->VDMOSsens_w){ |
|||
value->rValue = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ |
|||
here->VDMOSsenParmNo + here->VDMOSsens_l); |
|||
} |
|||
return(OK); |
|||
case VDMOS_W_SENS_MAG: |
|||
if(ckt->CKTsenInfo && here->VDMOSsens_w){ |
|||
vr = *(ckt->CKTrhsOld + select->iValue + 1); |
|||
vi = *(ckt->CKTirhsOld + select->iValue + 1); |
|||
vm = sqrt(vr*vr + vi*vi); |
|||
if(vm == 0){ |
|||
value->rValue = 0; |
|||
return(OK); |
|||
} |
|||
sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ |
|||
here->VDMOSsenParmNo + here->VDMOSsens_l); |
|||
si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ |
|||
here->VDMOSsenParmNo + here->VDMOSsens_l); |
|||
value->rValue = (vr * sr + vi * si)/vm; |
|||
} |
|||
return(OK); |
|||
case VDMOS_W_SENS_PH: |
|||
if(ckt->CKTsenInfo && here->VDMOSsens_w){ |
|||
vr = *(ckt->CKTrhsOld + select->iValue + 1); |
|||
vi = *(ckt->CKTirhsOld + select->iValue + 1); |
|||
vm = vr*vr + vi*vi; |
|||
if(vm == 0){ |
|||
value->rValue = 0; |
|||
return(OK); |
|||
} |
|||
sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ |
|||
here->VDMOSsenParmNo + here->VDMOSsens_l); |
|||
si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ |
|||
here->VDMOSsenParmNo + here->VDMOSsens_l); |
|||
value->rValue = (vr * si - vi * sr)/vm; |
|||
} |
|||
return(OK); |
|||
case VDMOS_W_SENS_CPLX: |
|||
if(ckt->CKTsenInfo && here->VDMOSsens_w){ |
|||
value->cValue.real= |
|||
*(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ |
|||
here->VDMOSsenParmNo + here->VDMOSsens_l); |
|||
value->cValue.imag= |
|||
*(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ |
|||
here->VDMOSsenParmNo + here->VDMOSsens_l); |
|||
} |
|||
return(OK); |
|||
case VDMOS_CB : |
|||
if (ckt->CKTcurrentAnalysis & DOING_AC) { |
|||
errMsg = TMALLOC(char, strlen(msg) + 1); |
|||
errRtn = "VDMOSask.c"; |
|||
strcpy(errMsg,msg); |
|||
return(E_ASKCURRENT); |
|||
} else { |
|||
value->rValue = here->VDMOScbd + here->VDMOScbs - *(ckt->CKTstate0 |
|||
+ here->VDMOScqgb); |
|||
} |
|||
return(OK); |
|||
case VDMOS_CG : |
|||
if (ckt->CKTcurrentAnalysis & DOING_AC) { |
|||
errMsg = TMALLOC(char, strlen(msg) + 1); |
|||
errRtn = "VDMOSask.c"; |
|||
strcpy(errMsg,msg); |
|||
return(E_ASKCURRENT); |
|||
} else if (ckt->CKTcurrentAnalysis & (DOING_DCOP | DOING_TRCV)) { |
|||
value->rValue = 0; |
|||
} else if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && |
|||
(ckt->CKTmode & MODETRANOP)) { |
|||
value->rValue = 0; |
|||
} else { |
|||
value->rValue = *(ckt->CKTstate0 + here->VDMOScqgb) + |
|||
*(ckt->CKTstate0 + here->VDMOScqgd) + *(ckt->CKTstate0 + |
|||
here->VDMOScqgs); |
|||
} |
|||
return(OK); |
|||
case VDMOS_CS : |
|||
if (ckt->CKTcurrentAnalysis & DOING_AC) { |
|||
errMsg = TMALLOC(char, strlen(msg) + 1); |
|||
errRtn = "VDMOSask.c"; |
|||
strcpy(errMsg,msg); |
|||
return(E_ASKCURRENT); |
|||
} else { |
|||
value->rValue = -here->VDMOScd; |
|||
value->rValue -= here->VDMOScbd + here->VDMOScbs - |
|||
*(ckt->CKTstate0 + here->VDMOScqgb); |
|||
if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && |
|||
!(ckt->CKTmode & MODETRANOP)) { |
|||
value->rValue -= *(ckt->CKTstate0 + here->VDMOScqgb) + |
|||
*(ckt->CKTstate0 + here->VDMOScqgd) + |
|||
*(ckt->CKTstate0 + here->VDMOScqgs); |
|||
} |
|||
} |
|||
return(OK); |
|||
case VDMOS_POWER : |
|||
if (ckt->CKTcurrentAnalysis & DOING_AC) { |
|||
errMsg = TMALLOC(char, strlen(msg) + 1); |
|||
errRtn = "VDMOSask.c"; |
|||
strcpy(errMsg,msg); |
|||
return(E_ASKPOWER); |
|||
} else { |
|||
double temp; |
|||
|
|||
value->rValue = here->VDMOScd * |
|||
*(ckt->CKTrhsOld + here->VDMOSdNode); |
|||
value->rValue += (here->VDMOScbd + here->VDMOScbs - |
|||
*(ckt->CKTstate0 + here->VDMOScqgb)) * |
|||
*(ckt->CKTrhsOld + here->VDMOSbNode); |
|||
if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && |
|||
!(ckt->CKTmode & MODETRANOP)) { |
|||
value->rValue += (*(ckt->CKTstate0 + here->VDMOScqgb) + |
|||
*(ckt->CKTstate0 + here->VDMOScqgd) + |
|||
*(ckt->CKTstate0 + here->VDMOScqgs)) * |
|||
*(ckt->CKTrhsOld + here->VDMOSgNode); |
|||
} |
|||
temp = -here->VDMOScd; |
|||
temp -= here->VDMOScbd + here->VDMOScbs ; |
|||
if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && |
|||
!(ckt->CKTmode & MODETRANOP)) { |
|||
temp -= *(ckt->CKTstate0 + here->VDMOScqgb) + |
|||
*(ckt->CKTstate0 + here->VDMOScqgd) + |
|||
*(ckt->CKTstate0 + here->VDMOScqgs); |
|||
} |
|||
value->rValue += temp * *(ckt->CKTrhsOld + here->VDMOSsNode); |
|||
} |
|||
return(OK); |
|||
default: |
|||
return(E_BADPARM); |
|||
} |
|||
/* NOTREACHED */ |
|||
} |
|||
|
|||
@ -0,0 +1,99 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1985 Thomas L. Quarles |
|||
**********/ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "ngspice/cktdefs.h" |
|||
#include "vdmosdefs.h" |
|||
#include "ngspice/sperror.h" |
|||
#include "ngspice/suffix.h" |
|||
|
|||
int |
|||
VDMOSconvTest(GENmodel *inModel, CKTcircuit *ckt) |
|||
{ |
|||
VDMOSmodel *model = (VDMOSmodel*)inModel; |
|||
VDMOSinstance *here; |
|||
double delvbs; |
|||
double delvbd; |
|||
double delvgs; |
|||
double delvds; |
|||
double delvgd; |
|||
double cbhat; |
|||
double cdhat; |
|||
double vbs; |
|||
double vbd; |
|||
double vgs; |
|||
double vds; |
|||
double vgd; |
|||
double vgdo; |
|||
double tol; |
|||
|
|||
for( ; model != NULL; model = VDMOSnextModel(model)) { |
|||
for(here = VDMOSinstances(model); here!= NULL; |
|||
here = VDMOSnextInstance(here)) { |
|||
|
|||
vbs = model->VDMOStype * ( |
|||
*(ckt->CKTrhs+here->VDMOSbNode) - |
|||
*(ckt->CKTrhs+here->VDMOSsNodePrime)); |
|||
vgs = model->VDMOStype * ( |
|||
*(ckt->CKTrhs+here->VDMOSgNode) - |
|||
*(ckt->CKTrhs+here->VDMOSsNodePrime)); |
|||
vds = model->VDMOStype * ( |
|||
*(ckt->CKTrhs+here->VDMOSdNodePrime) - |
|||
*(ckt->CKTrhs+here->VDMOSsNodePrime)); |
|||
vbd=vbs-vds; |
|||
vgd=vgs-vds; |
|||
vgdo = *(ckt->CKTstate0 + here->VDMOSvgs) - |
|||
*(ckt->CKTstate0 + here->VDMOSvds); |
|||
delvbs = vbs - *(ckt->CKTstate0 + here->VDMOSvbs); |
|||
delvbd = vbd - *(ckt->CKTstate0 + here->VDMOSvbd); |
|||
delvgs = vgs - *(ckt->CKTstate0 + here->VDMOSvgs); |
|||
delvds = vds - *(ckt->CKTstate0 + here->VDMOSvds); |
|||
delvgd = vgd-vgdo; |
|||
|
|||
/* these are needed for convergence testing */ |
|||
|
|||
if (here->VDMOSmode >= 0) { |
|||
cdhat= |
|||
here->VDMOScd- |
|||
here->VDMOSgbd * delvbd + |
|||
here->VDMOSgmbs * delvbs + |
|||
here->VDMOSgm * delvgs + |
|||
here->VDMOSgds * delvds ; |
|||
} else { |
|||
cdhat= |
|||
here->VDMOScd - |
|||
( here->VDMOSgbd - |
|||
here->VDMOSgmbs) * delvbd - |
|||
here->VDMOSgm * delvgd + |
|||
here->VDMOSgds * delvds ; |
|||
} |
|||
cbhat= |
|||
here->VDMOScbs + |
|||
here->VDMOScbd + |
|||
here->VDMOSgbd * delvbd + |
|||
here->VDMOSgbs * delvbs ; |
|||
/* |
|||
* check convergence |
|||
*/ |
|||
tol=ckt->CKTreltol*MAX(fabs(cdhat),fabs(here->VDMOScd))+ |
|||
ckt->CKTabstol; |
|||
if (fabs(cdhat-here->VDMOScd) >= tol) { |
|||
ckt->CKTnoncon++; |
|||
ckt->CKTtroubleElt = (GENinstance *) here; |
|||
return(OK); /* no reason to continue, we haven't converged */ |
|||
} else { |
|||
tol=ckt->CKTreltol* |
|||
MAX(fabs(cbhat),fabs(here->VDMOScbs+here->VDMOScbd))+ |
|||
ckt->CKTabstol; |
|||
if (fabs(cbhat-(here->VDMOScbs+here->VDMOScbd)) > tol) { |
|||
ckt->CKTnoncon++; |
|||
ckt->CKTtroubleElt = (GENinstance *) here; |
|||
return(OK); /* no reason to continue, we haven't converged*/ |
|||
} |
|||
} |
|||
} |
|||
} |
|||
return(OK); |
|||
} |
|||
@ -0,0 +1,532 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1985 Thomas L. Quarles |
|||
Modified: 2000 AlansFixes |
|||
**********/ |
|||
|
|||
#ifndef VDMOS |
|||
#define VDMOS |
|||
|
|||
#include "ngspice/ifsim.h" |
|||
#include "ngspice/cktdefs.h" |
|||
#include "ngspice/gendefs.h" |
|||
#include "ngspice/complex.h" |
|||
#include "ngspice/noisedef.h" |
|||
|
|||
/* declarations for level 1 MOSFETs */ |
|||
|
|||
/* indices to the array of MOSFET(1) noise sources */ |
|||
|
|||
enum { |
|||
VDMOSRDNOIZ = 0, |
|||
VDMOSRSNOIZ, |
|||
VDMOSIDNOIZ, |
|||
VDMOSFLNOIZ, |
|||
VDMOSTOTNOIZ, |
|||
/* finally, the number of noise sources */ |
|||
VDMOSNSRCS |
|||
}; |
|||
|
|||
/* information needed for each instance */ |
|||
|
|||
typedef struct sVDMOSinstance { |
|||
|
|||
struct GENinstance gen; |
|||
|
|||
#define VDMOSmodPtr(inst) ((struct sVDMOSmodel *)((inst)->gen.GENmodPtr)) |
|||
#define VDMOSnextInstance(inst) ((struct sVDMOSinstance *)((inst)->gen.GENnextInstance)) |
|||
#define VDMOSname gen.GENname |
|||
#define VDMOSstates gen.GENstate |
|||
|
|||
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 VDMOSbNode; /* number of the bulk 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 */ |
|||
|
|||
double VDMOSm; /* parallel device multiplier */ |
|||
|
|||
double VDMOSl; /* the length of the channel region */ |
|||
double VDMOSw; /* the width of the channel region */ |
|||
double VDMOSdrainArea; /* the area of the drain diffusion */ |
|||
double VDMOSsourceArea; /* the area of the source diffusion */ |
|||
double VDMOSdrainSquares; /* the length of the drain in squares */ |
|||
double VDMOSsourceSquares; /* the length of the source in squares */ |
|||
double VDMOSdrainPerimiter; |
|||
double VDMOSsourcePerimiter; |
|||
double VDMOSsourceConductance; /*conductance of source(or 0):set in setup*/ |
|||
double VDMOSdrainConductance; /*conductance of drain(or 0):set in setup*/ |
|||
double VDMOStemp; /* operating temperature of this instance */ |
|||
double VDMOSdtemp; /* operating temperature of the instance relative to circuit temperature*/ |
|||
|
|||
double VDMOStTransconductance; /* temperature corrected transconductance*/ |
|||
double VDMOStSurfMob; /* temperature corrected surface mobility */ |
|||
double VDMOStPhi; /* temperature corrected Phi */ |
|||
double VDMOStVto; /* temperature corrected Vto */ |
|||
double VDMOStSatCur; /* temperature corrected saturation Cur. */ |
|||
double VDMOStSatCurDens; /* temperature corrected saturation Cur. density*/ |
|||
double VDMOStCbd; /* temperature corrected B-D Capacitance */ |
|||
double VDMOStCbs; /* temperature corrected B-S Capacitance */ |
|||
double VDMOStCj; /* temperature corrected Bulk bottom Capacitance */ |
|||
double VDMOStCjsw; /* temperature corrected Bulk side Capacitance */ |
|||
double VDMOStBulkPot; /* temperature corrected Bulk potential */ |
|||
double VDMOStDepCap; /* temperature adjusted transition point in */ |
|||
/* the cureve matching Fc * Vj */ |
|||
double VDMOStVbi; /* temperature adjusted Vbi */ |
|||
|
|||
double VDMOSicVBS; /* initial condition B-S voltage */ |
|||
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 VDMOScbs; |
|||
double VDMOScbd; |
|||
double VDMOSgmbs; |
|||
double VDMOSgm; |
|||
double VDMOSgds; |
|||
double VDMOSgbd; |
|||
double VDMOSgbs; |
|||
double VDMOScapbd; |
|||
double VDMOScapbs; |
|||
double VDMOSCbd; |
|||
double VDMOSCbdsw; |
|||
double VDMOSCbs; |
|||
double VDMOSCbssw; |
|||
double VDMOSf2d; |
|||
double VDMOSf3d; |
|||
double VDMOSf4d; |
|||
double VDMOSf2s; |
|||
double VDMOSf3s; |
|||
double VDMOSf4s; |
|||
|
|||
/* |
|||
* naming convention: |
|||
* x = vgs |
|||
* y = vbs |
|||
* z = vds |
|||
* cdr = cdrain |
|||
*/ |
|||
|
|||
#define VDMOSNDCOEFFS 30 |
|||
|
|||
#ifndef NODISTO |
|||
double VDMOSdCoeffs[VDMOSNDCOEFFS]; |
|||
#else /* NODISTO */ |
|||
double *VDMOSdCoeffs; |
|||
#endif /* NODISTO */ |
|||
|
|||
#ifndef CONFIG |
|||
|
|||
#define capbs2 VDMOSdCoeffs[0] |
|||
#define capbs3 VDMOSdCoeffs[1] |
|||
#define capbd2 VDMOSdCoeffs[2] |
|||
#define capbd3 VDMOSdCoeffs[3] |
|||
#define gbs2 VDMOSdCoeffs[4] |
|||
#define gbs3 VDMOSdCoeffs[5] |
|||
#define gbd2 VDMOSdCoeffs[6] |
|||
#define gbd3 VDMOSdCoeffs[7] |
|||
#define capgb2 VDMOSdCoeffs[8] |
|||
#define capgb3 VDMOSdCoeffs[9] |
|||
#define cdr_x2 VDMOSdCoeffs[10] |
|||
#define cdr_y2 VDMOSdCoeffs[11] |
|||
#define cdr_z2 VDMOSdCoeffs[12] |
|||
#define cdr_xy VDMOSdCoeffs[13] |
|||
#define cdr_yz VDMOSdCoeffs[14] |
|||
#define cdr_xz VDMOSdCoeffs[15] |
|||
#define cdr_x3 VDMOSdCoeffs[16] |
|||
#define cdr_y3 VDMOSdCoeffs[17] |
|||
#define cdr_z3 VDMOSdCoeffs[18] |
|||
#define cdr_x2z VDMOSdCoeffs[19] |
|||
#define cdr_x2y VDMOSdCoeffs[20] |
|||
#define cdr_y2z VDMOSdCoeffs[21] |
|||
#define cdr_xy2 VDMOSdCoeffs[22] |
|||
#define cdr_xz2 VDMOSdCoeffs[23] |
|||
#define cdr_yz2 VDMOSdCoeffs[24] |
|||
#define cdr_xyz VDMOSdCoeffs[25] |
|||
#define capgs2 VDMOSdCoeffs[26] |
|||
#define capgs3 VDMOSdCoeffs[27] |
|||
#define capgd2 VDMOSdCoeffs[28] |
|||
#define capgd3 VDMOSdCoeffs[29] |
|||
|
|||
#endif |
|||
|
|||
#ifndef NONOISE |
|||
double VDMOSnVar[NSTATVARS][VDMOSNSRCS]; |
|||
#else /* NONOISE */ |
|||
double **VDMOSnVar; |
|||
#endif /* NONOISE */ |
|||
|
|||
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 VDMOSdrainAreaGiven :1; |
|||
unsigned VDMOSsourceAreaGiven :1; |
|||
unsigned VDMOSdrainSquaresGiven :1; |
|||
unsigned VDMOSsourceSquaresGiven :1; |
|||
unsigned VDMOSdrainPerimiterGiven :1; |
|||
unsigned VDMOSsourcePerimiterGiven :1; |
|||
unsigned VDMOSdNodePrimeSet :1; |
|||
unsigned VDMOSsNodePrimeSet :1; |
|||
unsigned VDMOSicVBSGiven :1; |
|||
unsigned VDMOSicVDSGiven :1; |
|||
unsigned VDMOSicVGSGiven :1; |
|||
unsigned VDMOSvonGiven :1; |
|||
unsigned VDMOSvdsatGiven :1; |
|||
unsigned VDMOSmodeGiven :1; |
|||
|
|||
|
|||
double *VDMOSDdPtr; /* pointer to sparse matrix element at |
|||
* (Drain node,drain node) */ |
|||
double *VDMOSGgPtr; /* pointer to sparse matrix element at |
|||
* (gate node,gate node) */ |
|||
double *VDMOSSsPtr; /* pointer to sparse matrix element at |
|||
* (source node,source node) */ |
|||
double *VDMOSBbPtr; /* pointer to sparse matrix element at |
|||
* (bulk node,bulk node) */ |
|||
double *VDMOSDPdpPtr; /* pointer to sparse matrix element at |
|||
* (drain prime node,drain prime node) */ |
|||
double *VDMOSSPspPtr; /* pointer to sparse matrix element at |
|||
* (source prime node,source prime node) */ |
|||
double *VDMOSDdpPtr; /* pointer to sparse matrix element at |
|||
* (drain node,drain prime node) */ |
|||
double *VDMOSGbPtr; /* pointer to sparse matrix element at |
|||
* (gate node,bulk node) */ |
|||
double *VDMOSGdpPtr; /* pointer to sparse matrix element at |
|||
* (gate node,drain prime node) */ |
|||
double *VDMOSGspPtr; /* pointer to sparse matrix element at |
|||
* (gate node,source prime node) */ |
|||
double *VDMOSSspPtr; /* pointer to sparse matrix element at |
|||
* (source node,source prime node) */ |
|||
double *VDMOSBdpPtr; /* pointer to sparse matrix element at |
|||
* (bulk node,drain prime node) */ |
|||
double *VDMOSBspPtr; /* pointer to sparse matrix element at |
|||
* (bulk node,source prime node) */ |
|||
double *VDMOSDPspPtr; /* pointer to sparse matrix element at |
|||
* (drain prime node,source prime node) */ |
|||
double *VDMOSDPdPtr; /* pointer to sparse matrix element at |
|||
* (drain prime node,drain node) */ |
|||
double *VDMOSBgPtr; /* pointer to sparse matrix element at |
|||
* (bulk node,gate node) */ |
|||
double *VDMOSDPgPtr; /* pointer to sparse matrix element at |
|||
* (drain prime node,gate node) */ |
|||
|
|||
double *VDMOSSPgPtr; /* pointer to sparse matrix element at |
|||
* (source prime node,gate node) */ |
|||
double *VDMOSSPsPtr; /* pointer to sparse matrix element at |
|||
* (source prime node,source node) */ |
|||
double *VDMOSDPbPtr; /* pointer to sparse matrix element at |
|||
* (drain prime node,bulk node) */ |
|||
double *VDMOSSPbPtr; /* pointer to sparse matrix element at |
|||
* (source prime node,bulk node) */ |
|||
double *VDMOSSPdpPtr; /* pointer to sparse matrix element at |
|||
* (source prime node,drain prime node) */ |
|||
|
|||
int VDMOSsenParmNo; /* parameter # for sensitivity use; |
|||
set equal to 0 if neither length |
|||
nor width of the mosfet is a design |
|||
parameter */ |
|||
unsigned VDMOSsens_l :1; /* field which indicates whether |
|||
length of the mosfet is a design |
|||
parameter or not */ |
|||
unsigned VDMOSsens_w :1; /* field which indicates whether |
|||
width of the mosfet is a design |
|||
parameter or not */ |
|||
unsigned VDMOSsenPertFlag :1; /* indictes whether the the |
|||
parameter of the particular instance is |
|||
to be perturbed */ |
|||
double VDMOScgs; |
|||
double VDMOScgd; |
|||
double VDMOScgb; |
|||
double *VDMOSsens; |
|||
|
|||
#define VDMOSsenCgs VDMOSsens /* contains pertured values of cgs */ |
|||
#define VDMOSsenCgd VDMOSsens + 6 /* contains perturbed values of cgd*/ |
|||
#define VDMOSsenCgb VDMOSsens + 12 /* contains perturbed values of cgb*/ |
|||
#define VDMOSsenCbd VDMOSsens + 18 /* contains perturbed values of cbd*/ |
|||
#define VDMOSsenCbs VDMOSsens + 24 /* contains perturbed values of cbs*/ |
|||
#define VDMOSsenGds VDMOSsens + 30 /* contains perturbed values of gds*/ |
|||
#define VDMOSsenGbs VDMOSsens + 36 /* contains perturbed values of gbs*/ |
|||
#define VDMOSsenGbd VDMOSsens + 42 /* contains perturbed values of gbd*/ |
|||
#define VDMOSsenGm VDMOSsens + 48 /* contains perturbed values of gm*/ |
|||
#define VDMOSsenGmbs VDMOSsens + 54 /* contains perturbed values of gmbs*/ |
|||
#define VDMOSdphigs_dl VDMOSsens + 60 |
|||
#define VDMOSdphigd_dl VDMOSsens + 61 |
|||
#define VDMOSdphigb_dl VDMOSsens + 62 |
|||
#define VDMOSdphibs_dl VDMOSsens + 63 |
|||
#define VDMOSdphibd_dl VDMOSsens + 64 |
|||
#define VDMOSdphigs_dw VDMOSsens + 65 |
|||
#define VDMOSdphigd_dw VDMOSsens + 66 |
|||
#define VDMOSdphigb_dw VDMOSsens + 67 |
|||
#define VDMOSdphibs_dw VDMOSsens + 68 |
|||
#define VDMOSdphibd_dw VDMOSsens + 69 |
|||
|
|||
} VDMOSinstance ; |
|||
|
|||
#define VDMOSvbd VDMOSstates+ 0 /* bulk-drain voltage */ |
|||
#define VDMOSvbs VDMOSstates+ 1 /* bulk-source voltage */ |
|||
#define VDMOSvgs VDMOSstates+ 2 /* gate-source voltage */ |
|||
#define VDMOSvds VDMOSstates+ 3 /* drain-source voltage */ |
|||
|
|||
#define VDMOScapgs VDMOSstates+4 /* gate-source capacitor value */ |
|||
#define VDMOSqgs VDMOSstates+ 5 /* gate-source capacitor charge */ |
|||
#define VDMOScqgs VDMOSstates+ 6 /* gate-source capacitor current */ |
|||
|
|||
#define VDMOScapgd VDMOSstates+ 7 /* gate-drain capacitor value */ |
|||
#define VDMOSqgd VDMOSstates+ 8 /* gate-drain capacitor charge */ |
|||
#define VDMOScqgd VDMOSstates+ 9 /* gate-drain capacitor current */ |
|||
|
|||
#define VDMOScapgb VDMOSstates+10 /* gate-bulk capacitor value */ |
|||
#define VDMOSqgb VDMOSstates+ 11 /* gate-bulk capacitor charge */ |
|||
#define VDMOScqgb VDMOSstates+ 12 /* gate-bulk capacitor current */ |
|||
|
|||
#define VDMOSqbd VDMOSstates+ 13 /* bulk-drain capacitor charge */ |
|||
#define VDMOScqbd VDMOSstates+ 14 /* bulk-drain capacitor current */ |
|||
|
|||
#define VDMOSqbs VDMOSstates+ 15 /* bulk-source capacitor charge */ |
|||
#define VDMOScqbs VDMOSstates+ 16 /* bulk-source capacitor current */ |
|||
|
|||
#define VDMOSnumStates 17 |
|||
|
|||
#define VDMOSsensxpgs VDMOSstates+17 /* charge sensitivities and their derivatives. |
|||
* +18 for the derivatives |
|||
* pointer to the beginning of the array */ |
|||
#define VDMOSsensxpgd VDMOSstates+19 |
|||
#define VDMOSsensxpgb VDMOSstates+21 |
|||
#define VDMOSsensxpbs VDMOSstates+23 |
|||
#define VDMOSsensxpbd VDMOSstates+25 |
|||
|
|||
#define VDMOSnumSenStates 10 |
|||
|
|||
|
|||
/* per model data */ |
|||
|
|||
/* NOTE: parameters marked 'input - use xxxx' are paramters 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 |
|||
*/ |
|||
|
|||
|
|||
typedef struct sVDMOSmodel { /* model structure for a resistor */ |
|||
|
|||
struct GENmodel gen; |
|||
|
|||
#define VDMOSmodType gen.GENmodType |
|||
#define VDMOSnextModel(inst) ((struct sVDMOSmodel *)((inst)->gen.GENnextModel)) |
|||
#define VDMOSinstances(inst) ((VDMOSinstance *)((inst)->gen.GENinstances)) |
|||
#define VDMOSmodName gen.GENmodName |
|||
|
|||
int VDMOStype; /* device type : 1 = nmos, -1 = pmos */ |
|||
double VDMOStnom; /* temperature at which parameters measured */ |
|||
double VDMOSlatDiff; |
|||
double VDMOSjctSatCurDensity; /* input - use tSatCurDens */ |
|||
double VDMOSjctSatCur; /* input - use tSatCur */ |
|||
double VDMOSdrainResistance; |
|||
double VDMOSsourceResistance; |
|||
double VDMOSsheetResistance; |
|||
double VDMOStransconductance; /* input - use tTransconductance */ |
|||
double VDMOSgateSourceOverlapCapFactor; |
|||
double VDMOSgateDrainOverlapCapFactor; |
|||
double VDMOSgateBulkOverlapCapFactor; |
|||
double VDMOSoxideCapFactor; |
|||
double VDMOSvt0; /* input - use tVto */ |
|||
double VDMOScapBD; /* input - use tCbd */ |
|||
double VDMOScapBS; /* input - use tCbs */ |
|||
double VDMOSbulkCapFactor; /* input - use tCj */ |
|||
double VDMOSsideWallCapFactor; /* input - use tCjsw */ |
|||
double VDMOSbulkJctPotential; /* input - use tBulkPot */ |
|||
double VDMOSbulkJctBotGradingCoeff; |
|||
double VDMOSbulkJctSideGradingCoeff; |
|||
double VDMOSfwdCapDepCoeff; |
|||
double VDMOSphi; /* input - use tPhi */ |
|||
double VDMOSgamma; |
|||
double VDMOSlambda; |
|||
double VDMOSsubstrateDoping; |
|||
int VDMOSgateType; |
|||
double VDMOSsurfaceStateDensity; |
|||
double VDMOSoxideThickness; |
|||
double VDMOSsurfaceMobility; /* input - use tSurfMob */ |
|||
double VDMOSfNcoef; |
|||
double VDMOSfNexp; |
|||
|
|||
unsigned VDMOStypeGiven :1; |
|||
unsigned VDMOSlatDiffGiven :1; |
|||
unsigned VDMOSjctSatCurDensityGiven :1; |
|||
unsigned VDMOSjctSatCurGiven :1; |
|||
unsigned VDMOSdrainResistanceGiven :1; |
|||
unsigned VDMOSsourceResistanceGiven :1; |
|||
unsigned VDMOSsheetResistanceGiven :1; |
|||
unsigned VDMOStransconductanceGiven :1; |
|||
unsigned VDMOSgateSourceOverlapCapFactorGiven :1; |
|||
unsigned VDMOSgateDrainOverlapCapFactorGiven :1; |
|||
unsigned VDMOSgateBulkOverlapCapFactorGiven :1; |
|||
unsigned VDMOSvt0Given :1; |
|||
unsigned VDMOScapBDGiven :1; |
|||
unsigned VDMOScapBSGiven :1; |
|||
unsigned VDMOSbulkCapFactorGiven :1; |
|||
unsigned VDMOSsideWallCapFactorGiven :1; |
|||
unsigned VDMOSbulkJctPotentialGiven :1; |
|||
unsigned VDMOSbulkJctBotGradingCoeffGiven :1; |
|||
unsigned VDMOSbulkJctSideGradingCoeffGiven :1; |
|||
unsigned VDMOSfwdCapDepCoeffGiven :1; |
|||
unsigned VDMOSphiGiven :1; |
|||
unsigned VDMOSgammaGiven :1; |
|||
unsigned VDMOSlambdaGiven :1; |
|||
unsigned VDMOSsubstrateDopingGiven :1; |
|||
unsigned VDMOSgateTypeGiven :1; |
|||
unsigned VDMOSsurfaceStateDensityGiven :1; |
|||
unsigned VDMOSoxideThicknessGiven :1; |
|||
unsigned VDMOSsurfaceMobilityGiven :1; |
|||
unsigned VDMOStnomGiven :1; |
|||
unsigned VDMOSfNcoefGiven :1; |
|||
unsigned VDMOSfNexpGiven :1; |
|||
|
|||
} VDMOSmodel; |
|||
|
|||
#ifndef NMOS |
|||
#define NMOS 1 |
|||
#define PMOS -1 |
|||
#endif /*NMOS*/ |
|||
|
|||
/* device parameters */ |
|||
enum { |
|||
VDMOS_W = 1, |
|||
VDMOS_L, |
|||
VDMOS_AS, |
|||
VDMOS_AD, |
|||
VDMOS_PS, |
|||
VDMOS_PD, |
|||
VDMOS_NRS, |
|||
VDMOS_NRD, |
|||
VDMOS_OFF, |
|||
VDMOS_IC, |
|||
VDMOS_IC_VBS, |
|||
VDMOS_IC_VDS, |
|||
VDMOS_IC_VGS, |
|||
VDMOS_W_SENS, |
|||
VDMOS_L_SENS, |
|||
VDMOS_CB, |
|||
VDMOS_CG, |
|||
VDMOS_CS, |
|||
VDMOS_POWER, |
|||
VDMOS_TEMP, |
|||
VDMOS_M, |
|||
VDMOS_DTEMP, |
|||
}; |
|||
|
|||
/* model paramerers */ |
|||
enum { |
|||
VDMOS_MOD_VTO = 101, |
|||
VDMOS_MOD_KP, |
|||
VDMOS_MOD_GAMMA, |
|||
VDMOS_MOD_PHI, |
|||
VDMOS_MOD_LAMBDA, |
|||
VDMOS_MOD_RD, |
|||
VDMOS_MOD_RS, |
|||
VDMOS_MOD_CBD, |
|||
VDMOS_MOD_CBS, |
|||
VDMOS_MOD_IS, |
|||
VDMOS_MOD_PB, |
|||
VDMOS_MOD_CGSO, |
|||
VDMOS_MOD_CGDO, |
|||
VDMOS_MOD_CGBO, |
|||
VDMOS_MOD_CJ, |
|||
VDMOS_MOD_MJ, |
|||
VDMOS_MOD_CJSW, |
|||
VDMOS_MOD_MJSW, |
|||
VDMOS_MOD_JS, |
|||
VDMOS_MOD_TOX, |
|||
VDMOS_MOD_LD, |
|||
VDMOS_MOD_RSH, |
|||
VDMOS_MOD_U0, |
|||
VDMOS_MOD_FC, |
|||
VDMOS_MOD_NSUB, |
|||
VDMOS_MOD_TPG, |
|||
VDMOS_MOD_NSS, |
|||
VDMOS_MOD_NMOS, |
|||
VDMOS_MOD_PMOS, |
|||
VDMOS_MOD_TNOM, |
|||
VDMOS_MOD_KF, |
|||
VDMOS_MOD_AF, |
|||
VDMOS_MOD_TYPE, |
|||
}; |
|||
|
|||
/* device questions */ |
|||
enum { |
|||
VDMOS_CGS = 201, |
|||
VDMOS_CGD, |
|||
VDMOS_DNODE, |
|||
VDMOS_GNODE, |
|||
VDMOS_SNODE, |
|||
VDMOS_BNODE, |
|||
VDMOS_DNODEPRIME, |
|||
VDMOS_SNODEPRIME, |
|||
VDMOS_SOURCECONDUCT, |
|||
VDMOS_DRAINCONDUCT, |
|||
VDMOS_VON, |
|||
VDMOS_VDSAT, |
|||
VDMOS_SOURCEVCRIT, |
|||
VDMOS_DRAINVCRIT, |
|||
VDMOS_CD, |
|||
VDMOS_CBS, |
|||
VDMOS_CBD, |
|||
VDMOS_GMBS, |
|||
VDMOS_GM, |
|||
VDMOS_GDS, |
|||
VDMOS_GBD, |
|||
VDMOS_GBS, |
|||
VDMOS_CAPBD, |
|||
VDMOS_CAPBS, |
|||
VDMOS_CAPZEROBIASBD, |
|||
VDMOS_CAPZEROBIASBDSW, |
|||
VDMOS_CAPZEROBIASBS, |
|||
VDMOS_CAPZEROBIASBSSW, |
|||
VDMOS_VBD, |
|||
VDMOS_VBS, |
|||
VDMOS_VGS, |
|||
VDMOS_VDS, |
|||
VDMOS_CAPGS, |
|||
VDMOS_QGS, |
|||
VDMOS_CQGS, |
|||
VDMOS_CAPGD, |
|||
VDMOS_QGD, |
|||
VDMOS_CQGD, |
|||
VDMOS_CAPGB, |
|||
VDMOS_QGB, |
|||
VDMOS_CQGB, |
|||
VDMOS_QBD, |
|||
VDMOS_CQBD, |
|||
VDMOS_QBS, |
|||
VDMOS_CQBS, |
|||
VDMOS_L_SENS_REAL, |
|||
VDMOS_L_SENS_IMAG, |
|||
VDMOS_L_SENS_MAG, |
|||
VDMOS_L_SENS_PH, |
|||
VDMOS_L_SENS_CPLX, |
|||
VDMOS_W_SENS_REAL, |
|||
VDMOS_W_SENS_IMAG, |
|||
VDMOS_W_SENS_MAG, |
|||
VDMOS_W_SENS_PH, |
|||
VDMOS_W_SENS_CPLX, |
|||
VDMOS_L_SENS_DC, |
|||
VDMOS_W_SENS_DC, |
|||
VDMOS_SOURCERESIST, |
|||
VDMOS_DRAINRESIST, |
|||
}; |
|||
|
|||
/* model questions */ |
|||
|
|||
#include "vdmosext.h" |
|||
|
|||
#endif /*VDMOS*/ |
|||
|
|||
@ -0,0 +1,18 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1985 Thomas L. Quarles |
|||
**********/ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "vdmosdefs.h" |
|||
#include "ngspice/sperror.h" |
|||
#include "ngspice/suffix.h" |
|||
|
|||
|
|||
int |
|||
VDMOSdelete(GENinstance *gen_inst) |
|||
{ |
|||
VDMOSinstance *inst = (VDMOSinstance *) gen_inst; |
|||
FREE(inst->VDMOSsens); |
|||
return OK; |
|||
} |
|||
1379
src/spicelib/devices/vdmos/vdmosdist.c
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,578 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1988 Jaijeet S Roychowdhury |
|||
**********/ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "ngspice/cktdefs.h" |
|||
#include "ngspice/devdefs.h" |
|||
#include "vdmosdefs.h" |
|||
#include "ngspice/distodef.h" |
|||
#include "ngspice/const.h" |
|||
#include "ngspice/sperror.h" |
|||
#include "ngspice/suffix.h" |
|||
|
|||
int |
|||
VDMOSdSetup(GENmodel *inModel, CKTcircuit *ckt) |
|||
/* actually load the current value into the |
|||
* sparse matrix previously provided |
|||
*/ |
|||
{ |
|||
VDMOSmodel *model = (VDMOSmodel *) inModel; |
|||
VDMOSinstance *here; |
|||
double Beta; |
|||
double DrainSatCur; |
|||
double EffectiveLength; |
|||
double GateBulkOverlapCap; |
|||
double GateDrainOverlapCap; |
|||
double GateSourceOverlapCap; |
|||
double OxideCap; |
|||
double SourceSatCur; |
|||
double gm; |
|||
double gds; |
|||
double gb; |
|||
double ebd; |
|||
double vgst; |
|||
double evbs; |
|||
double sargsw; |
|||
double vbd; |
|||
double vbs; |
|||
double vds; |
|||
double arg; |
|||
double sarg; |
|||
double vdsat; |
|||
double vgd; |
|||
double vgs; |
|||
double von; |
|||
double vt; |
|||
double lgbs; |
|||
double lgbs2; |
|||
double lgbs3; |
|||
double lgbd; |
|||
double lgbd2; |
|||
double lgbd3; |
|||
double gm2; |
|||
double gds2; |
|||
double gb2; |
|||
double gmds; |
|||
double gmb; |
|||
double gbds; |
|||
double gm3; |
|||
double gds3; |
|||
double gb3; |
|||
double gm2ds; |
|||
double gmds2; |
|||
double gm2b; |
|||
double gmb2; |
|||
double gb2ds; |
|||
double gbds2; |
|||
double lcapgb2; |
|||
double lcapgb3; |
|||
double lcapgs2; |
|||
double lcapgs3; |
|||
double lcapgd2; |
|||
double lcapgd3; |
|||
double lcapbs2; |
|||
double lcapbs3; |
|||
double lcapbd2; |
|||
double lcapbd3; |
|||
double gmbds = 0.0; |
|||
|
|||
|
|||
/* loop through all the VDMOS device models */ |
|||
for( ; model != NULL; model = VDMOSnextModel(model)) { |
|||
/* loop through all the instances of the model */ |
|||
for (here = VDMOSinstances(model); here != NULL ; |
|||
here=VDMOSnextInstance(here)) { |
|||
|
|||
vt = CONSTKoverQ * here->VDMOStemp; |
|||
EffectiveLength=here->VDMOSl - 2*model->VDMOSlatDiff; |
|||
|
|||
if( (here->VDMOStSatCurDens == 0) || |
|||
(here->VDMOSdrainArea == 0) || |
|||
(here->VDMOSsourceArea == 0)) { |
|||
DrainSatCur = here->VDMOSm * here->VDMOStSatCur; |
|||
SourceSatCur = here->VDMOSm * here->VDMOStSatCur; |
|||
} else { |
|||
DrainSatCur = here->VDMOStSatCurDens * |
|||
here->VDMOSm * here->VDMOSdrainArea; |
|||
SourceSatCur = here->VDMOStSatCurDens * |
|||
here->VDMOSm * here->VDMOSsourceArea; |
|||
} |
|||
GateSourceOverlapCap = model->VDMOSgateSourceOverlapCapFactor * |
|||
here->VDMOSm * here->VDMOSw; |
|||
GateDrainOverlapCap = model->VDMOSgateDrainOverlapCapFactor * |
|||
here->VDMOSm * here->VDMOSw; |
|||
GateBulkOverlapCap = model->VDMOSgateBulkOverlapCapFactor * |
|||
here->VDMOSm * EffectiveLength; |
|||
Beta = here->VDMOStTransconductance * here->VDMOSm * |
|||
here->VDMOSw/EffectiveLength; |
|||
OxideCap = model->VDMOSoxideCapFactor * EffectiveLength * |
|||
here->VDMOSm * here->VDMOSw; |
|||
|
|||
vbs = model->VDMOStype * ( |
|||
*(ckt->CKTrhsOld+here->VDMOSbNode) - |
|||
*(ckt->CKTrhsOld+here->VDMOSsNodePrime)); |
|||
vgs = model->VDMOStype * ( |
|||
*(ckt->CKTrhsOld+here->VDMOSgNode) - |
|||
*(ckt->CKTrhsOld+here->VDMOSsNodePrime)); |
|||
vds = model->VDMOStype * ( |
|||
*(ckt->CKTrhsOld+here->VDMOSdNodePrime) - |
|||
*(ckt->CKTrhsOld+here->VDMOSsNodePrime)); |
|||
|
|||
/* now some common crunching for some more useful quantities */ |
|||
|
|||
vbd=vbs-vds; |
|||
vgd=vgs-vds; |
|||
|
|||
/* |
|||
* bulk-source and bulk-drain diodes |
|||
* here we just evaluate the ideal diode current and the |
|||
* corresponding derivative (conductance). |
|||
*/ |
|||
if(vbs <= 0) { |
|||
lgbs = SourceSatCur/vt; |
|||
lgbs += ckt->CKTgmin; |
|||
lgbs2 = lgbs3 = 0; |
|||
} else { |
|||
evbs = exp(MIN(MAX_EXP_ARG,vbs/vt)); |
|||
lgbs = SourceSatCur*evbs/vt + ckt->CKTgmin; |
|||
lgbs2 = model->VDMOStype *0.5 * (lgbs - ckt->CKTgmin)/vt; |
|||
lgbs3 = model->VDMOStype *lgbs2/(vt*3); |
|||
|
|||
} |
|||
if(vbd <= 0) { |
|||
lgbd = DrainSatCur/vt; |
|||
lgbd += ckt->CKTgmin; |
|||
lgbd2 = lgbd3 = 0; |
|||
} else { |
|||
ebd = exp(MIN(MAX_EXP_ARG,vbd/vt)); |
|||
lgbd = DrainSatCur*ebd/vt +ckt->CKTgmin; |
|||
lgbd2 = model->VDMOStype *0.5 * (lgbd - ckt->CKTgmin)/vt; |
|||
lgbd3 = model->VDMOStype *lgbd2/(vt*3); |
|||
} |
|||
|
|||
/* now to determine whether the user was able to correctly |
|||
* identify the source and drain of his device |
|||
*/ |
|||
if(vds >= 0) { |
|||
/* normal mode */ |
|||
here->VDMOSmode = 1; |
|||
} else { |
|||
/* inverse mode */ |
|||
here->VDMOSmode = -1; |
|||
} |
|||
|
|||
/* |
|||
* this block of code evaluates the drain current and its |
|||
* derivatives using the shichman-hodges model and the |
|||
* charges associated with the gate, channel and bulk for |
|||
* mosfets |
|||
* |
|||
*/ |
|||
|
|||
/* the following variables are local to this code block until |
|||
* it is obvious that they can be made global |
|||
*/ |
|||
{ |
|||
double betap; |
|||
double dvondvbs; |
|||
double d2vondvbs2; |
|||
double d3vondvbs3; |
|||
|
|||
if ((here->VDMOSmode==1?vbs:vbd) <= 0 ) { |
|||
sarg=sqrt(here->VDMOStPhi-(here->VDMOSmode==1?vbs:vbd)); |
|||
if (-model->VDMOSgamma != 0.0) { |
|||
dvondvbs = -model->VDMOSgamma*0.5/sarg; |
|||
d2vondvbs2 = - dvondvbs*0.5/(sarg*sarg); |
|||
d3vondvbs3 = 1.5*d2vondvbs2/(sarg*sarg); |
|||
} |
|||
else { |
|||
dvondvbs = d2vondvbs2 = d3vondvbs3 = 0.0; |
|||
} |
|||
} else { |
|||
sarg=sqrt(here->VDMOStPhi); |
|||
if (model->VDMOSgamma != 0.0) { |
|||
dvondvbs = -model->VDMOSgamma/(sarg+sarg); |
|||
} |
|||
else { |
|||
dvondvbs = 0.0; |
|||
} |
|||
d2vondvbs2 = d3vondvbs3 = 0; |
|||
sarg=sarg-(here->VDMOSmode==1?vbs:vbd)/(sarg+sarg); |
|||
sarg=MAX(0,sarg); |
|||
dvondvbs = (sarg<=0?0:dvondvbs); |
|||
} |
|||
von=(here->VDMOStVbi*model->VDMOStype)+model->VDMOSgamma*sarg; |
|||
vgst=(here->VDMOSmode==1?vgs:vgd)-von; |
|||
vdsat=MAX(vgst,0); |
|||
/* if (sarg <= 0) { |
|||
arg=0; |
|||
} else { |
|||
arg=model->VDMOSgamma/(sarg+sarg); |
|||
} */ |
|||
if (vgst <= 0) { |
|||
/* |
|||
* cutoff region |
|||
*/ |
|||
/* cdrain = 0 */ |
|||
gm=0; |
|||
gds=0; |
|||
gb=0; |
|||
gm2=gb2=gds2=0; |
|||
gmds=gbds=gmb=0; |
|||
gm3=gb3=gds3=0; |
|||
gm2ds=gmds2=gm2b=gmb2=gb2ds=gbds2=0; |
|||
} else{ |
|||
/* |
|||
* saturation region |
|||
*/ |
|||
|
|||
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; |
|||
/* gb=here->VDMOSgm*arg; */ |
|||
gb= -gm*dvondvbs; |
|||
gm2 = betap; |
|||
gds2 = 0; |
|||
gb2 = -(gm*d2vondvbs2 - betap*dvondvbs*dvondvbs); |
|||
gmds = vgst*model->VDMOSlambda*Beta; |
|||
gbds = - gmds*dvondvbs; |
|||
gmb = -betap*dvondvbs; |
|||
gm3 = 0; |
|||
gb3 = -(gmb*d2vondvbs2 + gm*d3vondvbs3 - |
|||
betap*2*dvondvbs*d2vondvbs2); |
|||
gds3 = 0; |
|||
gm2ds = Beta * model->VDMOSlambda; |
|||
gm2b = 0; |
|||
gmb2 = -betap*d2vondvbs2; |
|||
gb2ds = -(gmds*d2vondvbs2 - dvondvbs*dvondvbs* |
|||
Beta * model->VDMOSlambda); |
|||
gmds2 = 0; |
|||
gbds2 = 0; |
|||
gmbds = -Beta * model->VDMOSlambda*dvondvbs; |
|||
|
|||
|
|||
} 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); |
|||
/* gb=gm*arg; */ |
|||
gb = - gm*dvondvbs; |
|||
gm2 = 0; |
|||
gb2 = -(gm*d2vondvbs2); |
|||
gds2 = 2*Beta * model->VDMOSlambda*(vgst - |
|||
vds*here->VDMOSmode) - betap; |
|||
gmds = Beta * model->VDMOSlambda* vds * |
|||
here->VDMOSmode + betap; |
|||
gbds = - gmds*dvondvbs; |
|||
gmb=0; |
|||
gm3=0; |
|||
gb3 = -gm*d3vondvbs3; |
|||
gds3 = -Beta*model->VDMOSlambda*3.; |
|||
gm2ds=gm2b=gmb2=0; |
|||
gmds2 = 2*model->VDMOSlambda*Beta; |
|||
gb2ds = -(gmds*d2vondvbs2); |
|||
gbds2 = -gmds2*dvondvbs; |
|||
gmbds = 0; |
|||
} |
|||
} |
|||
/* |
|||
* finished |
|||
*/ |
|||
} /* code block */ |
|||
|
|||
|
|||
/* |
|||
* 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 |
|||
*/ |
|||
/* |
|||
* charge storage elements |
|||
* |
|||
*.. bulk-drain and bulk-source depletion capacitances |
|||
*/ |
|||
if (vbs < here->VDMOStDepCap){ |
|||
arg=1-vbs/here->VDMOStBulkPot; |
|||
/* |
|||
* the following block looks somewhat long and messy, |
|||
* but since most users use the default grading |
|||
* coefficients of .5, and sqrt is MUCH faster than an |
|||
* exp(log()) we use this special case code to buy time. |
|||
* (as much as 10% of total job time!) |
|||
*/ |
|||
if(model->VDMOSbulkJctBotGradingCoeff == |
|||
model->VDMOSbulkJctSideGradingCoeff) { |
|||
if(model->VDMOSbulkJctBotGradingCoeff == .5) { |
|||
sarg = sargsw = 1/sqrt(arg); |
|||
} else { |
|||
sarg = sargsw = |
|||
exp(-model->VDMOSbulkJctBotGradingCoeff* |
|||
log(arg)); |
|||
} |
|||
} else { |
|||
if(model->VDMOSbulkJctBotGradingCoeff == .5) { |
|||
sarg = 1/sqrt(arg); |
|||
} else { |
|||
sarg = exp(-model->VDMOSbulkJctBotGradingCoeff* |
|||
log(arg)); |
|||
} |
|||
if(model->VDMOSbulkJctSideGradingCoeff == .5) { |
|||
sargsw = 1/sqrt(arg); |
|||
} else { |
|||
sargsw =exp(-model->VDMOSbulkJctSideGradingCoeff* |
|||
log(arg)); |
|||
} |
|||
} |
|||
/* |
|||
lcapbs=here->VDMOSCbs*sarg+ |
|||
here->VDMOSCbssw*sargsw; |
|||
*/ |
|||
lcapbs2 = model->VDMOStype*0.5/here->VDMOStBulkPot*( |
|||
here->VDMOSCbs*model->VDMOSbulkJctBotGradingCoeff* |
|||
sarg/arg + here->VDMOSCbssw* |
|||
model->VDMOSbulkJctSideGradingCoeff*sargsw/arg); |
|||
lcapbs3 = here->VDMOSCbs*sarg* |
|||
model->VDMOSbulkJctBotGradingCoeff* |
|||
(model->VDMOSbulkJctBotGradingCoeff+1); |
|||
lcapbs3 += here->VDMOSCbssw*sargsw* |
|||
model->VDMOSbulkJctSideGradingCoeff* |
|||
(model->VDMOSbulkJctSideGradingCoeff+1); |
|||
lcapbs3 = lcapbs3/(6*here->VDMOStBulkPot* |
|||
here->VDMOStBulkPot*arg*arg); |
|||
} else { |
|||
/* *(ckt->CKTstate0 + here->VDMOSqbs)= here->VDMOSf4s + |
|||
vbs*(here->VDMOSf2s+vbs*(here->VDMOSf3s/2));*/ |
|||
/* |
|||
lcapbs=here->VDMOSf2s+here->VDMOSf3s*vbs; |
|||
*/ |
|||
lcapbs2 = 0.5*here->VDMOSf3s; |
|||
lcapbs3 = 0; |
|||
} |
|||
if (vbd < here->VDMOStDepCap) { |
|||
arg=1-vbd/here->VDMOStBulkPot; |
|||
/* |
|||
* the following block looks somewhat long and messy, |
|||
* but since most users use the default grading |
|||
* coefficients of .5, and sqrt is MUCH faster than an |
|||
* exp(log()) we use this special case code to buy time. |
|||
* (as much as 10% of total job time!) |
|||
*/ |
|||
#ifndef NOSQRT |
|||
if(model->VDMOSbulkJctBotGradingCoeff == .5 && |
|||
model->VDMOSbulkJctSideGradingCoeff == .5) { |
|||
sarg = sargsw = 1/sqrt(arg); |
|||
} else { |
|||
if(model->VDMOSbulkJctBotGradingCoeff == .5) { |
|||
sarg = 1/sqrt(arg); |
|||
} else { |
|||
#endif /*NOSQRT*/ |
|||
sarg = exp(-model->VDMOSbulkJctBotGradingCoeff* |
|||
log(arg)); |
|||
#ifndef NOSQRT |
|||
} |
|||
if(model->VDMOSbulkJctSideGradingCoeff == .5) { |
|||
sargsw = 1/sqrt(arg); |
|||
} else { |
|||
#endif /*NOSQRT*/ |
|||
sargsw =exp(-model->VDMOSbulkJctSideGradingCoeff* |
|||
log(arg)); |
|||
#ifndef NOSQRT |
|||
} |
|||
} |
|||
#endif /*NOSQRT*/ |
|||
/* |
|||
lcapbd=here->VDMOSCbd*sarg+ |
|||
here->VDMOSCbdsw*sargsw; |
|||
*/ |
|||
lcapbd2 = model->VDMOStype*0.5/here->VDMOStBulkPot*( |
|||
here->VDMOSCbd*model->VDMOSbulkJctBotGradingCoeff* |
|||
sarg/arg + here->VDMOSCbdsw* |
|||
model->VDMOSbulkJctSideGradingCoeff*sargsw/arg); |
|||
lcapbd3 = here->VDMOSCbd*sarg* |
|||
model->VDMOSbulkJctBotGradingCoeff* |
|||
(model->VDMOSbulkJctBotGradingCoeff+1); |
|||
lcapbd3 += here->VDMOSCbdsw*sargsw* |
|||
model->VDMOSbulkJctSideGradingCoeff* |
|||
(model->VDMOSbulkJctSideGradingCoeff+1); |
|||
lcapbd3 = lcapbd3/(6*here->VDMOStBulkPot* |
|||
here->VDMOStBulkPot*arg*arg); |
|||
} else { |
|||
/* |
|||
lcapbd=here->VDMOSf2d + vbd * here->VDMOSf3d; |
|||
*/ |
|||
lcapbd2=0.5*here->VDMOSf3d; |
|||
lcapbd3=0; |
|||
} |
|||
/* |
|||
* meyer's capacitor model |
|||
*/ |
|||
/* |
|||
* the meyer capacitance equations are in DEVqmeyer |
|||
* these expressions are derived from those equations. |
|||
* these expressions are incorrect; they assume just one |
|||
* controlling variable for each charge storage element |
|||
* while actually there are several; the VDMOS small |
|||
* signal ac linear model is also wrong because it |
|||
* ignores controlled capacitive elements. these can be |
|||
* corrected (as can the linear ss ac model) if the |
|||
* expressions for the charge are available |
|||
*/ |
|||
|
|||
|
|||
{ |
|||
|
|||
|
|||
double phi; |
|||
double cox; |
|||
double vddif; |
|||
double vddif1; |
|||
double vddif2; |
|||
/* von, vgst and vdsat have already been adjusted for |
|||
possible source-drain interchange */ |
|||
|
|||
|
|||
|
|||
phi = here->VDMOStPhi; |
|||
cox = OxideCap; |
|||
if (vgst <= -phi) { |
|||
lcapgb2=lcapgb3=lcapgs2=lcapgs3=lcapgd2=lcapgd3=0; |
|||
} else if (vgst <= -phi/2) { |
|||
lcapgb2= -cox/(4*phi); |
|||
lcapgb3=lcapgs2=lcapgs3=lcapgd2=lcapgd3=0; |
|||
} else if (vgst <= 0) { |
|||
lcapgb2= -cox/(4*phi); |
|||
lcapgb3=lcapgs3=lcapgd2=lcapgd3=0; |
|||
lcapgs2 = cox/(3*phi); |
|||
} else { /* the VDMOSmodes are around because |
|||
vds has not been adjusted */ |
|||
if (vdsat <= here->VDMOSmode*vds) { |
|||
lcapgb2=lcapgb3=lcapgs2=lcapgs3=lcapgd2=lcapgd3=0; |
|||
} else { |
|||
vddif = 2.0*vdsat-here->VDMOSmode*vds; |
|||
vddif1 = vdsat-here->VDMOSmode*vds/*-1.0e-12*/; |
|||
vddif2 = vddif*vddif; |
|||
lcapgd2 = -vdsat*here->VDMOSmode*vds*cox/(3*vddif*vddif2); |
|||
lcapgd3 = - here->VDMOSmode*vds*cox*(vddif - 6*vdsat)/(9*vddif2*vddif2); |
|||
lcapgs2 = -vddif1*here->VDMOSmode*vds*cox/(3*vddif*vddif2); |
|||
lcapgs3 = - here->VDMOSmode*vds*cox*(vddif - 6*vddif1)/(9*vddif2*vddif2); |
|||
lcapgb2=lcapgb3=0; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/* the b-s and b-d diodes need no processing ... */ |
|||
here->capbs2 = lcapbs2; |
|||
here->capbs3 = lcapbs3; |
|||
here->capbd2 = lcapbd2; |
|||
here->capbd3 = lcapbd3; |
|||
here->gbs2 = lgbs2; |
|||
here->gbs3 = lgbs3; |
|||
here->gbd2 = lgbd2; |
|||
here->gbd3 = lgbd3; |
|||
here->capgb2 = model->VDMOStype*lcapgb2; |
|||
here->capgb3 = lcapgb3; |
|||
/* |
|||
* process to get Taylor coefficients, taking into |
|||
* account type and mode. |
|||
*/ |
|||
|
|||
if (here->VDMOSmode == 1) |
|||
{ |
|||
/* normal mode - no source-drain interchange */ |
|||
|
|||
here->cdr_x2 = gm2; |
|||
here->cdr_y2 = gb2;; |
|||
here->cdr_z2 = gds2;; |
|||
here->cdr_xy = gmb; |
|||
here->cdr_yz = gbds; |
|||
here->cdr_xz = gmds; |
|||
here->cdr_x3 = gm3; |
|||
here->cdr_y3 = gb3; |
|||
here->cdr_z3 = gds3; |
|||
here->cdr_x2z = gm2ds; |
|||
here->cdr_x2y = gm2b; |
|||
here->cdr_y2z = gb2ds; |
|||
here->cdr_xy2 = gmb2; |
|||
here->cdr_xz2 = gmds2; |
|||
here->cdr_yz2 = gbds2; |
|||
here->cdr_xyz = gmbds; |
|||
|
|||
/* the gate caps have been divided and made into |
|||
Taylor coeffs., but not adjusted for type */ |
|||
|
|||
here->capgs2 = model->VDMOStype*lcapgs2; |
|||
here->capgs3 = lcapgs3; |
|||
here->capgd2 = model->VDMOStype*lcapgd2; |
|||
here->capgd3 = lcapgd3; |
|||
} else { |
|||
/* |
|||
* inverse mode - source and drain interchanged |
|||
*/ |
|||
|
|||
here->cdr_x2 = -gm2; |
|||
here->cdr_y2 = -gb2; |
|||
here->cdr_z2 = -(gm2 + gb2 + gds2 + 2*(gmb + gmds + gbds)); |
|||
here->cdr_xy = -gmb; |
|||
here->cdr_yz = gmb + gb2 + gbds; |
|||
here->cdr_xz = gm2 + gmb + gmds; |
|||
here->cdr_x3 = -gm3; |
|||
here->cdr_y3 = -gb3; |
|||
here->cdr_z3 = gm3 + gb3 + gds3 + |
|||
3*(gm2b + gm2ds + gmb2 + gb2ds + gmds2 + gbds2) + 6*gmbds ; |
|||
here->cdr_x2z = gm3 + gm2b + gm2ds; |
|||
here->cdr_x2y = -gm2b; |
|||
here->cdr_y2z = gmb2 + gb3 + gb2ds; |
|||
here->cdr_xy2 = -gmb2; |
|||
here->cdr_xz2 = -(gm3 + 2*(gm2b + gm2ds + gmbds) + |
|||
gmb2 + gmds2); |
|||
here->cdr_yz2 = -(gb3 + 2*(gmb2 + gb2ds + gmbds) + |
|||
gm2b + gbds2); |
|||
here->cdr_xyz = gm2b + gmb2 + gmbds; |
|||
|
|||
here->capgs2 = model->VDMOStype*lcapgd2; |
|||
here->capgs3 = lcapgd3; |
|||
|
|||
here->capgd2 = model->VDMOStype*lcapgs2; |
|||
here->capgd3 = lcapgs3; |
|||
|
|||
} |
|||
|
|||
/* now to adjust for type and multiply by factors to convert to Taylor coeffs. */ |
|||
|
|||
here->cdr_x2 = 0.5*model->VDMOStype*here->cdr_x2; |
|||
here->cdr_y2 = 0.5*model->VDMOStype*here->cdr_y2; |
|||
here->cdr_z2 = 0.5*model->VDMOStype*here->cdr_z2; |
|||
here->cdr_xy = model->VDMOStype*here->cdr_xy; |
|||
here->cdr_yz = model->VDMOStype*here->cdr_yz; |
|||
here->cdr_xz = model->VDMOStype*here->cdr_xz; |
|||
here->cdr_x3 = here->cdr_x3/6.; |
|||
here->cdr_y3 = here->cdr_y3/6.; |
|||
here->cdr_z3 = here->cdr_z3/6.; |
|||
here->cdr_x2z = 0.5*here->cdr_x2z; |
|||
here->cdr_x2y = 0.5*here->cdr_x2y; |
|||
here->cdr_y2z = 0.5*here->cdr_y2z; |
|||
here->cdr_xy2 = 0.5*here->cdr_xy2; |
|||
here->cdr_xz2 = 0.5*here->cdr_xz2; |
|||
here->cdr_yz2 = 0.5*here->cdr_yz2; |
|||
|
|||
|
|||
} |
|||
} |
|||
return(OK); |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1985 Thomas L. Quarles |
|||
Modified: 2000 AlansFixes |
|||
**********/ |
|||
|
|||
extern int VDMOSacLoad(GENmodel *,CKTcircuit*); |
|||
extern int VDMOSask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); |
|||
extern int VDMOSdelete(GENinstance*); |
|||
extern int VDMOSgetic(GENmodel*,CKTcircuit*); |
|||
extern int VDMOSload(GENmodel*,CKTcircuit*); |
|||
extern int VDMOSmAsk(CKTcircuit *,GENmodel *,int,IFvalue*); |
|||
extern int VDMOSmParam(int,IFvalue*,GENmodel*); |
|||
extern int VDMOSparam(int,IFvalue*,GENinstance*,IFvalue*); |
|||
extern int VDMOSpzLoad(GENmodel*,CKTcircuit*,SPcomplex*); |
|||
extern int VDMOSsAcLoad(GENmodel*,CKTcircuit*); |
|||
extern int VDMOSsLoad(GENmodel*,CKTcircuit*); |
|||
extern void VDMOSsPrint(GENmodel*,CKTcircuit*); |
|||
extern int VDMOSsSetup(SENstruct*,GENmodel*); |
|||
extern int VDMOSsUpdate(GENmodel*,CKTcircuit*); |
|||
extern int VDMOSsetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); |
|||
extern int VDMOSunsetup(GENmodel*,CKTcircuit*); |
|||
extern int VDMOStemp(GENmodel*,CKTcircuit*); |
|||
extern int VDMOStrunc(GENmodel*,CKTcircuit*,double*); |
|||
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*); |
|||
@ -0,0 +1,46 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1985 Thomas L. Quarles |
|||
**********/ |
|||
/* |
|||
*/ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "ngspice/cktdefs.h" |
|||
#include "vdmosdefs.h" |
|||
#include "ngspice/sperror.h" |
|||
#include "ngspice/suffix.h" |
|||
|
|||
|
|||
int |
|||
VDMOSgetic(GENmodel *inModel, CKTcircuit *ckt) |
|||
{ |
|||
VDMOSmodel *model = (VDMOSmodel *)inModel; |
|||
VDMOSinstance *here; |
|||
/* |
|||
* grab initial conditions out of rhs array. User specified, so use |
|||
* external nodes to get values |
|||
*/ |
|||
|
|||
for( ; model ; model = VDMOSnextModel(model)) { |
|||
for(here = VDMOSinstances(model); here ; here = VDMOSnextInstance(here)) { |
|||
|
|||
if(!here->VDMOSicVBSGiven) { |
|||
here->VDMOSicVBS = |
|||
*(ckt->CKTrhs + here->VDMOSbNode) - |
|||
*(ckt->CKTrhs + here->VDMOSsNode); |
|||
} |
|||
if(!here->VDMOSicVDSGiven) { |
|||
here->VDMOSicVDS = |
|||
*(ckt->CKTrhs + here->VDMOSdNode) - |
|||
*(ckt->CKTrhs + here->VDMOSsNode); |
|||
} |
|||
if(!here->VDMOSicVGSGiven) { |
|||
here->VDMOSicVGS = |
|||
*(ckt->CKTrhs + here->VDMOSgNode) - |
|||
*(ckt->CKTrhs + here->VDMOSsNode); |
|||
} |
|||
} |
|||
} |
|||
return(OK); |
|||
} |
|||
@ -0,0 +1,76 @@ |
|||
#include "ngspice/config.h" |
|||
|
|||
#include "ngspice/devdefs.h" |
|||
|
|||
#include "vdmositf.h" |
|||
#include "vdmosext.h" |
|||
#include "vdmosinit.h" |
|||
|
|||
|
|||
SPICEdev VDMOSinfo = { |
|||
.DEVpublic = { |
|||
.name = "Vdmos", |
|||
.description = "Level 1 MOSfet model with Meyer capacitance model", |
|||
.terms = &VDMOSnSize, |
|||
.numNames = &VDMOSnSize, |
|||
.termNames = VDMOSnames, |
|||
.numInstanceParms = &VDMOSpTSize, |
|||
.instanceParms = VDMOSpTable, |
|||
.numModelParms = &VDMOSmPTSize, |
|||
.modelParms = VDMOSmPTable, |
|||
.flags = DEV_DEFAULT, |
|||
|
|||
#ifdef XSPICE |
|||
.cm_func = NULL, |
|||
.num_conn = 0, |
|||
.conn = NULL, |
|||
.num_param = 0, |
|||
.param = NULL, |
|||
.num_inst_var = 0, |
|||
.inst_var = NULL, |
|||
#endif |
|||
}, |
|||
|
|||
.DEVparam = VDMOSparam, |
|||
.DEVmodParam = VDMOSmParam, |
|||
.DEVload = VDMOSload, |
|||
.DEVsetup = VDMOSsetup, |
|||
.DEVunsetup = VDMOSunsetup, |
|||
.DEVpzSetup = VDMOSsetup, |
|||
.DEVtemperature = VDMOStemp, |
|||
.DEVtrunc = VDMOStrunc, |
|||
.DEVfindBranch = NULL, |
|||
.DEVacLoad = VDMOSacLoad, |
|||
.DEVaccept = NULL, |
|||
.DEVdestroy = NULL, |
|||
.DEVmodDelete = NULL, |
|||
.DEVdelete = VDMOSdelete, |
|||
.DEVsetic = VDMOSgetic, |
|||
.DEVask = VDMOSask, |
|||
.DEVmodAsk = VDMOSmAsk, |
|||
.DEVpzLoad = VDMOSpzLoad, |
|||
.DEVconvTest = VDMOSconvTest, |
|||
.DEVsenSetup = VDMOSsSetup, |
|||
.DEVsenLoad = VDMOSsLoad, |
|||
.DEVsenUpdate = VDMOSsUpdate, |
|||
.DEVsenAcLoad = VDMOSsAcLoad, |
|||
.DEVsenPrint = VDMOSsPrint, |
|||
.DEVsenTrunc = NULL, |
|||
.DEVdisto = VDMOSdisto, |
|||
.DEVnoise = VDMOSnoise, |
|||
.DEVsoaCheck = NULL, |
|||
.DEVinstSize = &VDMOSiSize, |
|||
.DEVmodSize = &VDMOSmSize, |
|||
|
|||
#ifdef CIDER |
|||
.DEVdump = NULL, |
|||
.DEVacct = NULL, |
|||
#endif |
|||
}; |
|||
|
|||
|
|||
SPICEdev * |
|||
get_vdmos_info(void) |
|||
{ |
|||
return &VDMOSinfo; |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
#ifndef _VDMOSINIT_H |
|||
#define _VDMOSINIT_H |
|||
|
|||
extern IFparm VDMOSpTable[ ]; |
|||
extern IFparm VDMOSmPTable[ ]; |
|||
extern char *VDMOSnames[ ]; |
|||
extern int VDMOSpTSize; |
|||
extern int VDMOSmPTSize; |
|||
extern int VDMOSnSize; |
|||
extern int VDMOSiSize; |
|||
extern int VDMOSmSize; |
|||
|
|||
#endif |
|||
@ -0,0 +1,9 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
**********/ |
|||
#ifndef DEV_VDMOS |
|||
#define DEV_VDMOS |
|||
|
|||
extern SPICEdev *get_vdmos_info(void); |
|||
|
|||
#endif |
|||
@ -0,0 +1,940 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1985 Thomas L. Quarles |
|||
Modified: 2000 AlansFixes |
|||
**********/ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "ngspice/cktdefs.h" |
|||
#include "ngspice/devdefs.h" |
|||
#include "vdmosdefs.h" |
|||
#include "ngspice/trandefs.h" |
|||
#include "ngspice/const.h" |
|||
#include "ngspice/sperror.h" |
|||
#include "ngspice/suffix.h" |
|||
|
|||
int |
|||
VDMOSload(GENmodel *inModel, CKTcircuit *ckt) |
|||
/* actually load the current value into the |
|||
* sparse matrix previously provided |
|||
*/ |
|||
{ |
|||
VDMOSmodel *model = (VDMOSmodel *) inModel; |
|||
VDMOSinstance *here; |
|||
double Beta; |
|||
double DrainSatCur; |
|||
double EffectiveLength; |
|||
double GateBulkOverlapCap; |
|||
double GateDrainOverlapCap; |
|||
double GateSourceOverlapCap; |
|||
double OxideCap; |
|||
double SourceSatCur; |
|||
double arg; |
|||
double cbhat; |
|||
double cdhat; |
|||
double cdrain; |
|||
double cdreq; |
|||
double ceq; |
|||
double ceqbd; |
|||
double ceqbs; |
|||
double ceqgb; |
|||
double ceqgd; |
|||
double ceqgs; |
|||
double delvbd; |
|||
double delvbs; |
|||
double delvds; |
|||
double delvgd; |
|||
double delvgs; |
|||
double evbd; |
|||
double evbs; |
|||
double gcgb; |
|||
double gcgd; |
|||
double gcgs; |
|||
double geq; |
|||
double sarg; |
|||
double sargsw; |
|||
double vbd; |
|||
double vbs; |
|||
double vds; |
|||
double vdsat; |
|||
double vgb1; |
|||
double vgb; |
|||
double vgd1; |
|||
double vgd; |
|||
double vgdo; |
|||
double vgs1; |
|||
double vgs; |
|||
double von; |
|||
double vt; |
|||
#ifndef PREDICTOR |
|||
double xfact = 0.0; |
|||
#endif |
|||
int xnrm; |
|||
int xrev; |
|||
double capgs = 0.0; /* total gate-source capacitance */ |
|||
double capgd = 0.0; /* total gate-drain capacitance */ |
|||
double capgb = 0.0; /* total gate-bulk capacitance */ |
|||
int Check; |
|||
#ifndef NOBYPASS |
|||
double tempv; |
|||
#endif /*NOBYPASS*/ |
|||
int error; |
|||
#ifdef CAPBYPASS |
|||
int senflag; |
|||
#endif /*CAPBYPASS*/ |
|||
int SenCond; |
|||
|
|||
|
|||
|
|||
#ifdef CAPBYPASS |
|||
senflag = 0; |
|||
if(ckt->CKTsenInfo && ckt->CKTsenInfo->SENstatus == PERTURBATION && |
|||
(ckt->CKTsenInfo->SENmode & (ACSEN | TRANSEN))) { |
|||
senflag = 1; |
|||
} |
|||
#endif /* CAPBYPASS */ |
|||
|
|||
/* loop through all the VDMOS device models */ |
|||
for( ; model != NULL; model = VDMOSnextModel(model)) { |
|||
|
|||
/* loop through all the instances of the model */ |
|||
for (here = VDMOSinstances(model); here != NULL ; |
|||
here=VDMOSnextInstance(here)) { |
|||
|
|||
vt = CONSTKoverQ * here->VDMOStemp; |
|||
Check=1; |
|||
if(ckt->CKTsenInfo){ |
|||
#ifdef SENSDEBUG |
|||
printf("VDMOSload \n"); |
|||
#endif /* SENSDEBUG */ |
|||
|
|||
if((ckt->CKTsenInfo->SENstatus == PERTURBATION)&& |
|||
(here->VDMOSsenPertFlag == OFF))continue; |
|||
|
|||
} |
|||
SenCond = ckt->CKTsenInfo && here->VDMOSsenPertFlag; |
|||
|
|||
/* |
|||
|
|||
*/ |
|||
|
|||
/* first, we compute a few useful values - these could be |
|||
* pre-computed, but for historical reasons are still done |
|||
* here. They may be moved at the expense of instance size |
|||
*/ |
|||
|
|||
EffectiveLength=here->VDMOSl - 2*model->VDMOSlatDiff; |
|||
|
|||
if( (here->VDMOStSatCurDens == 0) || |
|||
(here->VDMOSdrainArea == 0) || |
|||
(here->VDMOSsourceArea == 0)) { |
|||
DrainSatCur = here->VDMOSm * here->VDMOStSatCur; |
|||
SourceSatCur = here->VDMOSm * here->VDMOStSatCur; |
|||
} else { |
|||
DrainSatCur = here->VDMOStSatCurDens * |
|||
here->VDMOSm * here->VDMOSdrainArea; |
|||
SourceSatCur = here->VDMOStSatCurDens * |
|||
here->VDMOSm * here->VDMOSsourceArea; |
|||
} |
|||
GateSourceOverlapCap = model->VDMOSgateSourceOverlapCapFactor * |
|||
here->VDMOSm * here->VDMOSw; |
|||
GateDrainOverlapCap = model->VDMOSgateDrainOverlapCapFactor * |
|||
here->VDMOSm * here->VDMOSw; |
|||
GateBulkOverlapCap = model->VDMOSgateBulkOverlapCapFactor * |
|||
here->VDMOSm * EffectiveLength; |
|||
Beta = here->VDMOStTransconductance * here->VDMOSm * |
|||
here->VDMOSw/EffectiveLength; |
|||
OxideCap = model->VDMOSoxideCapFactor * EffectiveLength * |
|||
here->VDMOSm * here->VDMOSw; |
|||
|
|||
/* |
|||
* ok - now to do the start-up operations |
|||
* |
|||
* we must get values for vbs, vds, and vgs from somewhere |
|||
* so we either predict them or recover them from last iteration |
|||
* These are the two most common cases - either a prediction |
|||
* step or the general iteration step and they |
|||
* share some code, so we put them first - others later on |
|||
*/ |
|||
|
|||
if(SenCond){ |
|||
#ifdef SENSDEBUG |
|||
printf("VDMOSsenPertFlag = ON \n"); |
|||
#endif /* SENSDEBUG */ |
|||
if((ckt->CKTsenInfo->SENmode == TRANSEN) && |
|||
(ckt->CKTmode & MODEINITTRAN)) { |
|||
vgs = *(ckt->CKTstate1 + here->VDMOSvgs); |
|||
vds = *(ckt->CKTstate1 + here->VDMOSvds); |
|||
vbs = *(ckt->CKTstate1 + here->VDMOSvbs); |
|||
vbd = *(ckt->CKTstate1 + here->VDMOSvbd); |
|||
vgb = vgs - vbs; |
|||
vgd = vgs - vds; |
|||
} |
|||
else if (ckt->CKTsenInfo->SENmode == ACSEN){ |
|||
vgb = model->VDMOStype * ( |
|||
*(ckt->CKTrhsOp+here->VDMOSgNode) - |
|||
*(ckt->CKTrhsOp+here->VDMOSbNode)); |
|||
vbs = *(ckt->CKTstate0 + here->VDMOSvbs); |
|||
vbd = *(ckt->CKTstate0 + here->VDMOSvbd); |
|||
vgd = vgb + vbd ; |
|||
vgs = vgb + vbs ; |
|||
vds = vbs - vbd ; |
|||
} |
|||
else{ |
|||
vgs = *(ckt->CKTstate0 + here->VDMOSvgs); |
|||
vds = *(ckt->CKTstate0 + here->VDMOSvds); |
|||
vbs = *(ckt->CKTstate0 + here->VDMOSvbs); |
|||
vbd = *(ckt->CKTstate0 + here->VDMOSvbd); |
|||
vgb = vgs - vbs; |
|||
vgd = vgs - vds; |
|||
} |
|||
#ifdef SENSDEBUG |
|||
printf(" vbs = %.7e ,vbd = %.7e,vgb = %.7e\n",vbs,vbd,vgb); |
|||
printf(" vgs = %.7e ,vds = %.7e,vgd = %.7e\n",vgs,vds,vgd); |
|||
#endif /* SENSDEBUG */ |
|||
goto next1; |
|||
} |
|||
|
|||
|
|||
if((ckt->CKTmode & (MODEINITFLOAT | MODEINITPRED | MODEINITSMSIG |
|||
| MODEINITTRAN)) || |
|||
( (ckt->CKTmode & MODEINITFIX) && (!here->VDMOSoff) ) ) { |
|||
#ifndef PREDICTOR |
|||
if(ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) { |
|||
|
|||
/* predictor step */ |
|||
|
|||
xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1]; |
|||
*(ckt->CKTstate0 + here->VDMOSvbs) = |
|||
*(ckt->CKTstate1 + here->VDMOSvbs); |
|||
vbs = (1+xfact)* (*(ckt->CKTstate1 + here->VDMOSvbs)) |
|||
-(xfact * (*(ckt->CKTstate2 + here->VDMOSvbs))); |
|||
*(ckt->CKTstate0 + here->VDMOSvgs) = |
|||
*(ckt->CKTstate1 + here->VDMOSvgs); |
|||
vgs = (1+xfact)* (*(ckt->CKTstate1 + here->VDMOSvgs)) |
|||
-(xfact * (*(ckt->CKTstate2 + here->VDMOSvgs))); |
|||
*(ckt->CKTstate0 + here->VDMOSvds) = |
|||
*(ckt->CKTstate1 + here->VDMOSvds); |
|||
vds = (1+xfact)* (*(ckt->CKTstate1 + here->VDMOSvds)) |
|||
-(xfact * (*(ckt->CKTstate2 + here->VDMOSvds))); |
|||
*(ckt->CKTstate0 + here->VDMOSvbd) = |
|||
*(ckt->CKTstate0 + here->VDMOSvbs)- |
|||
*(ckt->CKTstate0 + here->VDMOSvds); |
|||
} else { |
|||
#endif /* PREDICTOR */ |
|||
|
|||
/* general iteration */ |
|||
|
|||
vbs = model->VDMOStype * ( |
|||
*(ckt->CKTrhsOld+here->VDMOSbNode) - |
|||
*(ckt->CKTrhsOld+here->VDMOSsNodePrime)); |
|||
vgs = model->VDMOStype * ( |
|||
*(ckt->CKTrhsOld+here->VDMOSgNode) - |
|||
*(ckt->CKTrhsOld+here->VDMOSsNodePrime)); |
|||
vds = model->VDMOStype * ( |
|||
*(ckt->CKTrhsOld+here->VDMOSdNodePrime) - |
|||
*(ckt->CKTrhsOld+here->VDMOSsNodePrime)); |
|||
#ifndef PREDICTOR |
|||
} |
|||
#endif /* PREDICTOR */ |
|||
|
|||
/* now some common crunching for some more useful quantities */ |
|||
|
|||
vbd=vbs-vds; |
|||
vgd=vgs-vds; |
|||
vgdo = *(ckt->CKTstate0 + here->VDMOSvgs) - |
|||
*(ckt->CKTstate0 + here->VDMOSvds); |
|||
delvbs = vbs - *(ckt->CKTstate0 + here->VDMOSvbs); |
|||
delvbd = vbd - *(ckt->CKTstate0 + here->VDMOSvbd); |
|||
delvgs = vgs - *(ckt->CKTstate0 + here->VDMOSvgs); |
|||
delvds = vds - *(ckt->CKTstate0 + here->VDMOSvds); |
|||
delvgd = vgd-vgdo; |
|||
|
|||
/* these are needed for convergence testing */ |
|||
|
|||
if (here->VDMOSmode >= 0) { |
|||
cdhat= |
|||
here->VDMOScd- |
|||
here->VDMOSgbd * delvbd + |
|||
here->VDMOSgmbs * delvbs + |
|||
here->VDMOSgm * delvgs + |
|||
here->VDMOSgds * delvds ; |
|||
} else { |
|||
cdhat= |
|||
here->VDMOScd - |
|||
( here->VDMOSgbd - |
|||
here->VDMOSgmbs) * delvbd - |
|||
here->VDMOSgm * delvgd + |
|||
here->VDMOSgds * delvds ; |
|||
} |
|||
cbhat= |
|||
here->VDMOScbs + |
|||
here->VDMOScbd + |
|||
here->VDMOSgbd * delvbd + |
|||
here->VDMOSgbs * delvbs ; |
|||
/* |
|||
|
|||
*/ |
|||
|
|||
#ifndef NOBYPASS |
|||
/* now lets see if we can bypass (ugh) */ |
|||
tempv = (MAX(fabs(cbhat), |
|||
fabs(here->VDMOScbs + here->VDMOScbd)) + |
|||
ckt->CKTabstol); |
|||
if ((!(ckt->CKTmode & |
|||
(MODEINITPRED|MODEINITTRAN|MODEINITSMSIG))) && |
|||
(ckt->CKTbypass) && |
|||
(fabs(cbhat-(here->VDMOScbs + |
|||
here->VDMOScbd)) < ckt->CKTreltol * tempv) && |
|||
(fabs(delvbs) < (ckt->CKTreltol * |
|||
MAX(fabs(vbs), |
|||
fabs( *(ckt->CKTstate0 + |
|||
here->VDMOSvbs))) + |
|||
ckt->CKTvoltTol)) && |
|||
(fabs(delvbd) < (ckt->CKTreltol * |
|||
MAX(fabs(vbd), |
|||
fabs(*(ckt->CKTstate0 + |
|||
here->VDMOSvbd))) + |
|||
ckt->CKTvoltTol)) && |
|||
(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 |
|||
*/ |
|||
vbs = *(ckt->CKTstate0 + here->VDMOSvbs); |
|||
vbd = *(ckt->CKTstate0 + here->VDMOSvbd); |
|||
vgs = *(ckt->CKTstate0 + here->VDMOSvgs); |
|||
vds = *(ckt->CKTstate0 + here->VDMOSvds); |
|||
vgd = vgs - vds; |
|||
vgb = vgs - vbs; |
|||
cdrain = here->VDMOSmode * (here->VDMOScd + here->VDMOScbd); |
|||
if(ckt->CKTmode & (MODETRAN | MODETRANOP)) { |
|||
capgs = ( *(ckt->CKTstate0+here->VDMOScapgs)+ |
|||
*(ckt->CKTstate1+here->VDMOScapgs) + |
|||
GateSourceOverlapCap ); |
|||
capgd = ( *(ckt->CKTstate0+here->VDMOScapgd)+ |
|||
*(ckt->CKTstate1+here->VDMOScapgd) + |
|||
GateDrainOverlapCap ); |
|||
capgb = ( *(ckt->CKTstate0+here->VDMOScapgb)+ |
|||
*(ckt->CKTstate1+here->VDMOScapgb) + |
|||
GateBulkOverlapCap ); |
|||
|
|||
if(ckt->CKTsenInfo){ |
|||
here->VDMOScgs = capgs; |
|||
here->VDMOScgd = capgd; |
|||
here->VDMOScgb = capgb; |
|||
} |
|||
} |
|||
goto bypass; |
|||
} |
|||
#endif /*NOBYPASS*/ |
|||
|
|||
/* |
|||
|
|||
*/ |
|||
|
|||
/* ok - bypass is out, do it the hard way */ |
|||
|
|||
von = model->VDMOStype * here->VDMOSvon; |
|||
|
|||
#ifndef NODELIMITING |
|||
/* |
|||
* limiting |
|||
* we want to keep device voltages from changing |
|||
* so fast that the exponentials churn out overflows |
|||
* and similar rudeness |
|||
*/ |
|||
|
|||
if(*(ckt->CKTstate0 + here->VDMOSvds) >=0) { |
|||
vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->VDMOSvgs) |
|||
,von); |
|||
vds = vgs - vgd; |
|||
vds = DEVlimvds(vds,*(ckt->CKTstate0 + here->VDMOSvds)); |
|||
vgd = vgs - vds; |
|||
} else { |
|||
vgd = DEVfetlim(vgd,vgdo,von); |
|||
vds = vgs - vgd; |
|||
if(!(ckt->CKTfixLimit)) { |
|||
vds = -DEVlimvds(-vds,-(*(ckt->CKTstate0 + |
|||
here->VDMOSvds))); |
|||
} |
|||
vgs = vgd + vds; |
|||
} |
|||
if(vds >= 0) { |
|||
vbs = DEVpnjlim(vbs,*(ckt->CKTstate0 + here->VDMOSvbs), |
|||
vt,here->VDMOSsourceVcrit,&Check); |
|||
vbd = vbs-vds; |
|||
} else { |
|||
vbd = DEVpnjlim(vbd,*(ckt->CKTstate0 + here->VDMOSvbd), |
|||
vt,here->VDMOSdrainVcrit,&Check); |
|||
vbs = vbd + vds; |
|||
} |
|||
#endif /*NODELIMITING*/ |
|||
/* |
|||
|
|||
*/ |
|||
|
|||
} else { |
|||
|
|||
/* ok - not one of the simple cases, so we have to |
|||
* look at all of the possibilities for why we were |
|||
* called. We still just initialize the three voltages |
|||
*/ |
|||
|
|||
if((ckt->CKTmode & MODEINITJCT) && !here->VDMOSoff) { |
|||
vds= model->VDMOStype * here->VDMOSicVDS; |
|||
vgs= model->VDMOStype * here->VDMOSicVGS; |
|||
vbs= model->VDMOStype * here->VDMOSicVBS; |
|||
if((vds==0) && (vgs==0) && (vbs==0) && |
|||
((ckt->CKTmode & |
|||
(MODETRAN|MODEDCOP|MODEDCTRANCURVE)) || |
|||
(!(ckt->CKTmode & MODEUIC)))) { |
|||
vbs = -1; |
|||
vgs = model->VDMOStype * here->VDMOStVto; |
|||
vds = 0; |
|||
} |
|||
} else { |
|||
vbs=vgs=vds=0; |
|||
} |
|||
} |
|||
/* |
|||
|
|||
*/ |
|||
|
|||
/* |
|||
* now all the preliminaries are over - we can start doing the |
|||
* real work |
|||
*/ |
|||
vbd = vbs - vds; |
|||
vgd = vgs - vds; |
|||
vgb = vgs - vbs; |
|||
|
|||
|
|||
/* |
|||
* bulk-source and bulk-drain diodes |
|||
* here we just evaluate the ideal diode current and the |
|||
* corresponding derivative (conductance). |
|||
*/ |
|||
next1: if(vbs <= -3*vt) { |
|||
here->VDMOSgbs = ckt->CKTgmin; |
|||
here->VDMOScbs = here->VDMOSgbs*vbs-SourceSatCur; |
|||
} else { |
|||
evbs = exp(MIN(MAX_EXP_ARG,vbs/vt)); |
|||
here->VDMOSgbs = SourceSatCur*evbs/vt + ckt->CKTgmin; |
|||
here->VDMOScbs = SourceSatCur*(evbs-1) + ckt->CKTgmin*vbs; |
|||
} |
|||
if(vbd <= -3*vt) { |
|||
here->VDMOSgbd = ckt->CKTgmin; |
|||
here->VDMOScbd = here->VDMOSgbd*vbd-DrainSatCur; |
|||
} else { |
|||
evbd = exp(MIN(MAX_EXP_ARG,vbd/vt)); |
|||
here->VDMOSgbd = DrainSatCur*evbd/vt + ckt->CKTgmin; |
|||
here->VDMOScbd = DrainSatCur*(evbd-1) + ckt->CKTgmin*vbd; |
|||
} |
|||
/* now to determine whether the user was able to correctly |
|||
* identify the source and drain of his device |
|||
*/ |
|||
if(vds >= 0) { |
|||
/* normal mode */ |
|||
here->VDMOSmode = 1; |
|||
} else { |
|||
/* inverse mode */ |
|||
here->VDMOSmode = -1; |
|||
} |
|||
/* |
|||
|
|||
*/ |
|||
|
|||
{ |
|||
/* |
|||
* this block of code evaluates the drain current and its |
|||
* derivatives using the shichman-hodges model and the |
|||
* charges associated with the gate, channel and bulk for |
|||
* mosfets |
|||
* |
|||
*/ |
|||
|
|||
/* the following 4 variables are local to this code block until |
|||
* it is obvious that they can be made global |
|||
*/ |
|||
double arg; |
|||
double betap; |
|||
double sarg; |
|||
double vgst; |
|||
|
|||
if ((here->VDMOSmode==1?vbs:vbd) <= 0 ) { |
|||
sarg=sqrt(here->VDMOStPhi-(here->VDMOSmode==1?vbs:vbd)); |
|||
} else { |
|||
sarg=sqrt(here->VDMOStPhi); |
|||
sarg=sarg-(here->VDMOSmode==1?vbs:vbd)/(sarg+sarg); |
|||
sarg=MAX(0,sarg); |
|||
} |
|||
von=(here->VDMOStVbi*model->VDMOStype)+model->VDMOSgamma*sarg; |
|||
vgst=(here->VDMOSmode==1?vgs:vgd)-von; |
|||
vdsat=MAX(vgst,0); |
|||
if (sarg <= 0) { |
|||
arg=0; |
|||
} else { |
|||
arg=model->VDMOSgamma/(sarg+sarg); |
|||
} |
|||
if (vgst <= 0) { |
|||
/* |
|||
* cutoff region |
|||
*/ |
|||
cdrain=0; |
|||
here->VDMOSgm=0; |
|||
here->VDMOSgds=0; |
|||
here->VDMOSgmbs=0; |
|||
} else{ |
|||
/* |
|||
* saturation region |
|||
*/ |
|||
betap=Beta*(1+model->VDMOSlambda*(vds*here->VDMOSmode)); |
|||
if (vgst <= (vds*here->VDMOSmode)){ |
|||
cdrain=betap*vgst*vgst*.5; |
|||
here->VDMOSgm=betap*vgst; |
|||
here->VDMOSgds=model->VDMOSlambda*Beta*vgst*vgst*.5; |
|||
here->VDMOSgmbs=here->VDMOSgm*arg; |
|||
} else { |
|||
/* |
|||
* linear region |
|||
*/ |
|||
cdrain=betap*(vds*here->VDMOSmode)* |
|||
(vgst-.5*(vds*here->VDMOSmode)); |
|||
here->VDMOSgm=betap*(vds*here->VDMOSmode); |
|||
here->VDMOSgds=betap*(vgst-(vds*here->VDMOSmode))+ |
|||
model->VDMOSlambda*Beta* |
|||
(vds*here->VDMOSmode)* |
|||
(vgst-.5*(vds*here->VDMOSmode)); |
|||
here->VDMOSgmbs=here->VDMOSgm*arg; |
|||
} |
|||
} |
|||
/* |
|||
* finished |
|||
*/ |
|||
} |
|||
/* |
|||
|
|||
*/ |
|||
|
|||
/* now deal with n vs p polarity */ |
|||
|
|||
here->VDMOSvon = model->VDMOStype * von; |
|||
here->VDMOSvdsat = model->VDMOStype * vdsat; |
|||
/* line 490 */ |
|||
/* |
|||
* COMPUTE EQUIVALENT DRAIN CURRENT SOURCE |
|||
*/ |
|||
here->VDMOScd=here->VDMOSmode * cdrain - here->VDMOScbd; |
|||
|
|||
if (ckt->CKTmode & (MODETRAN | MODETRANOP | MODEINITSMSIG)) { |
|||
/* |
|||
* now we do the hard part of the bulk-drain and bulk-source |
|||
* diode - we evaluate the non-linear capacitance and |
|||
* charge |
|||
* |
|||
* the basic equations are not hard, but the implementation |
|||
* is somewhat long in an attempt to avoid log/exponential |
|||
* evaluations |
|||
*/ |
|||
/* |
|||
* charge storage elements |
|||
* |
|||
*.. bulk-drain and bulk-source depletion capacitances |
|||
*/ |
|||
#ifdef CAPBYPASS |
|||
if(((ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) || |
|||
fabs(delvbs) >= ckt->CKTreltol * MAX(fabs(vbs), |
|||
fabs(*(ckt->CKTstate0+here->VDMOSvbs)))+ |
|||
ckt->CKTvoltTol)|| senflag) |
|||
#endif /*CAPBYPASS*/ |
|||
|
|||
{ |
|||
/* can't bypass the diode capacitance calculations */ |
|||
if(here->VDMOSCbs != 0 || here->VDMOSCbssw != 0 ) { |
|||
if (vbs < here->VDMOStDepCap){ |
|||
arg=1-vbs/here->VDMOStBulkPot; |
|||
/* |
|||
* the following block looks somewhat long and messy, |
|||
* but since most users use the default grading |
|||
* coefficients of .5, and sqrt is MUCH faster than an |
|||
* exp(log()) we use this special case code to buy time. |
|||
* (as much as 10% of total job time!) |
|||
*/ |
|||
if(model->VDMOSbulkJctBotGradingCoeff == |
|||
model->VDMOSbulkJctSideGradingCoeff) { |
|||
if(model->VDMOSbulkJctBotGradingCoeff == .5) { |
|||
sarg = sargsw = 1/sqrt(arg); |
|||
} else { |
|||
sarg = sargsw = |
|||
exp(-model->VDMOSbulkJctBotGradingCoeff* |
|||
log(arg)); |
|||
} |
|||
} else { |
|||
if(model->VDMOSbulkJctBotGradingCoeff == .5) { |
|||
sarg = 1/sqrt(arg); |
|||
} else { |
|||
sarg = exp(-model->VDMOSbulkJctBotGradingCoeff* |
|||
log(arg)); |
|||
} |
|||
if(model->VDMOSbulkJctSideGradingCoeff == .5) { |
|||
sargsw = 1/sqrt(arg); |
|||
} else { |
|||
sargsw =exp(-model->VDMOSbulkJctSideGradingCoeff* |
|||
log(arg)); |
|||
} |
|||
} |
|||
*(ckt->CKTstate0 + here->VDMOSqbs) = |
|||
here->VDMOStBulkPot*(here->VDMOSCbs* |
|||
(1-arg*sarg)/(1-model->VDMOSbulkJctBotGradingCoeff) |
|||
+here->VDMOSCbssw* |
|||
(1-arg*sargsw)/ |
|||
(1-model->VDMOSbulkJctSideGradingCoeff)); |
|||
here->VDMOScapbs=here->VDMOSCbs*sarg+ |
|||
here->VDMOSCbssw*sargsw; |
|||
} else { |
|||
*(ckt->CKTstate0 + here->VDMOSqbs) = here->VDMOSf4s + |
|||
vbs*(here->VDMOSf2s+vbs*(here->VDMOSf3s/2)); |
|||
here->VDMOScapbs=here->VDMOSf2s+here->VDMOSf3s*vbs; |
|||
} |
|||
} else { |
|||
*(ckt->CKTstate0 + here->VDMOSqbs) = 0; |
|||
here->VDMOScapbs=0; |
|||
} |
|||
} |
|||
#ifdef CAPBYPASS |
|||
if(((ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) || |
|||
fabs(delvbd) >= ckt->CKTreltol * MAX(fabs(vbd), |
|||
fabs(*(ckt->CKTstate0+here->VDMOSvbd)))+ |
|||
ckt->CKTvoltTol)|| senflag) |
|||
#endif /*CAPBYPASS*/ |
|||
|
|||
/* can't bypass the diode capacitance calculations */ |
|||
{ |
|||
if(here->VDMOSCbd != 0 || here->VDMOSCbdsw != 0 ) { |
|||
if (vbd < here->VDMOStDepCap) { |
|||
arg=1-vbd/here->VDMOStBulkPot; |
|||
/* |
|||
* the following block looks somewhat long and messy, |
|||
* but since most users use the default grading |
|||
* coefficients of .5, and sqrt is MUCH faster than an |
|||
* exp(log()) we use this special case code to buy time. |
|||
* (as much as 10% of total job time!) |
|||
*/ |
|||
if(model->VDMOSbulkJctBotGradingCoeff == .5 && |
|||
model->VDMOSbulkJctSideGradingCoeff == .5) { |
|||
sarg = sargsw = 1/sqrt(arg); |
|||
} else { |
|||
if(model->VDMOSbulkJctBotGradingCoeff == .5) { |
|||
sarg = 1/sqrt(arg); |
|||
} else { |
|||
sarg = exp(-model->VDMOSbulkJctBotGradingCoeff* |
|||
log(arg)); |
|||
} |
|||
if(model->VDMOSbulkJctSideGradingCoeff == .5) { |
|||
sargsw = 1/sqrt(arg); |
|||
} else { |
|||
sargsw =exp(-model->VDMOSbulkJctSideGradingCoeff* |
|||
log(arg)); |
|||
} |
|||
} |
|||
*(ckt->CKTstate0 + here->VDMOSqbd) = |
|||
here->VDMOStBulkPot*(here->VDMOSCbd* |
|||
(1-arg*sarg) |
|||
/(1-model->VDMOSbulkJctBotGradingCoeff) |
|||
+here->VDMOSCbdsw* |
|||
(1-arg*sargsw) |
|||
/(1-model->VDMOSbulkJctSideGradingCoeff)); |
|||
here->VDMOScapbd=here->VDMOSCbd*sarg+ |
|||
here->VDMOSCbdsw*sargsw; |
|||
} else { |
|||
*(ckt->CKTstate0 + here->VDMOSqbd) = here->VDMOSf4d + |
|||
vbd * (here->VDMOSf2d + vbd * here->VDMOSf3d/2); |
|||
here->VDMOScapbd=here->VDMOSf2d + vbd * here->VDMOSf3d; |
|||
} |
|||
} else { |
|||
*(ckt->CKTstate0 + here->VDMOSqbd) = 0; |
|||
here->VDMOScapbd = 0; |
|||
} |
|||
} |
|||
/* |
|||
|
|||
*/ |
|||
|
|||
if(SenCond && (ckt->CKTsenInfo->SENmode==TRANSEN)) goto next2; |
|||
|
|||
if ( (ckt->CKTmode & MODETRAN) || ( (ckt->CKTmode&MODEINITTRAN) |
|||
&& !(ckt->CKTmode&MODEUIC)) ) { |
|||
/* (above only excludes tranop, since we're only at this |
|||
* point if tran or tranop ) |
|||
*/ |
|||
|
|||
/* |
|||
* calculate equivalent conductances and currents for |
|||
* depletion capacitors |
|||
*/ |
|||
|
|||
/* integrate the capacitors and save results */ |
|||
|
|||
error = NIintegrate(ckt,&geq,&ceq,here->VDMOScapbd, |
|||
here->VDMOSqbd); |
|||
if(error) return(error); |
|||
here->VDMOSgbd += geq; |
|||
here->VDMOScbd += *(ckt->CKTstate0 + here->VDMOScqbd); |
|||
here->VDMOScd -= *(ckt->CKTstate0 + here->VDMOScqbd); |
|||
error = NIintegrate(ckt,&geq,&ceq,here->VDMOScapbs, |
|||
here->VDMOSqbs); |
|||
if(error) return(error); |
|||
here->VDMOSgbs += geq; |
|||
here->VDMOScbs += *(ckt->CKTstate0 + here->VDMOScqbs); |
|||
} |
|||
} |
|||
/* |
|||
|
|||
*/ |
|||
|
|||
if(SenCond) goto next2; |
|||
|
|||
|
|||
/* |
|||
* check convergence |
|||
*/ |
|||
if ( (here->VDMOSoff == 0) || |
|||
(!(ckt->CKTmode & (MODEINITFIX|MODEINITSMSIG))) ){ |
|||
if (Check == 1) { |
|||
ckt->CKTnoncon++; |
|||
ckt->CKTtroubleElt = (GENinstance *) here; |
|||
} |
|||
} |
|||
/* |
|||
|
|||
*/ |
|||
|
|||
/* save things away for next time */ |
|||
|
|||
next2: *(ckt->CKTstate0 + here->VDMOSvbs) = vbs; |
|||
*(ckt->CKTstate0 + here->VDMOSvbd) = vbd; |
|||
*(ckt->CKTstate0 + here->VDMOSvgs) = vgs; |
|||
*(ckt->CKTstate0 + here->VDMOSvds) = vds; |
|||
|
|||
/* |
|||
|
|||
*/ |
|||
|
|||
/* |
|||
* meyer's capacitor model |
|||
*/ |
|||
if ( ckt->CKTmode & (MODETRAN | MODETRANOP | MODEINITSMSIG) ) { |
|||
/* |
|||
* calculate meyer's capacitors |
|||
*/ |
|||
/* |
|||
* new cmeyer - this just evaluates at the current time, |
|||
* expects you to remember values from previous time |
|||
* returns 1/2 of non-constant portion of capacitance |
|||
* you must add in the other half from previous time |
|||
* and the constant part |
|||
*/ |
|||
if (here->VDMOSmode > 0){ |
|||
DEVqmeyer (vgs,vgd,vgb,von,vdsat, |
|||
(ckt->CKTstate0 + here->VDMOScapgs), |
|||
(ckt->CKTstate0 + here->VDMOScapgd), |
|||
(ckt->CKTstate0 + here->VDMOScapgb), |
|||
here->VDMOStPhi,OxideCap); |
|||
} else { |
|||
DEVqmeyer (vgd,vgs,vgb,von,vdsat, |
|||
(ckt->CKTstate0 + here->VDMOScapgd), |
|||
(ckt->CKTstate0 + here->VDMOScapgs), |
|||
(ckt->CKTstate0 + here->VDMOScapgb), |
|||
here->VDMOStPhi,OxideCap); |
|||
} |
|||
vgs1 = *(ckt->CKTstate1 + here->VDMOSvgs); |
|||
vgd1 = vgs1 - *(ckt->CKTstate1 + here->VDMOSvds); |
|||
vgb1 = vgs1 - *(ckt->CKTstate1 + here->VDMOSvbs); |
|||
if(ckt->CKTmode & (MODETRANOP|MODEINITSMSIG)) { |
|||
capgs = 2 * *(ckt->CKTstate0+here->VDMOScapgs)+ |
|||
GateSourceOverlapCap ; |
|||
capgd = 2 * *(ckt->CKTstate0+here->VDMOScapgd)+ |
|||
GateDrainOverlapCap ; |
|||
capgb = 2 * *(ckt->CKTstate0+here->VDMOScapgb)+ |
|||
GateBulkOverlapCap ; |
|||
} else { |
|||
capgs = ( *(ckt->CKTstate0+here->VDMOScapgs)+ |
|||
*(ckt->CKTstate1+here->VDMOScapgs) + |
|||
GateSourceOverlapCap ); |
|||
capgd = ( *(ckt->CKTstate0+here->VDMOScapgd)+ |
|||
*(ckt->CKTstate1+here->VDMOScapgd) + |
|||
GateDrainOverlapCap ); |
|||
capgb = ( *(ckt->CKTstate0+here->VDMOScapgb)+ |
|||
*(ckt->CKTstate1+here->VDMOScapgb) + |
|||
GateBulkOverlapCap ); |
|||
} |
|||
if(ckt->CKTsenInfo){ |
|||
here->VDMOScgs = capgs; |
|||
here->VDMOScgd = capgd; |
|||
here->VDMOScgb = capgb; |
|||
} |
|||
/* |
|||
|
|||
*/ |
|||
|
|||
/* |
|||
* store small-signal parameters (for meyer's model) |
|||
* all parameters already stored, so done... |
|||
*/ |
|||
if(SenCond){ |
|||
if((ckt->CKTsenInfo->SENmode == DCSEN)|| |
|||
(ckt->CKTsenInfo->SENmode == ACSEN)){ |
|||
continue; |
|||
} |
|||
} |
|||
|
|||
#ifndef PREDICTOR |
|||
if (ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) { |
|||
*(ckt->CKTstate0 + here->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->VDMOSqgb) = |
|||
(1+xfact) * *(ckt->CKTstate1 + here->VDMOSqgb) |
|||
- xfact * *(ckt->CKTstate2 + here->VDMOSqgb); |
|||
} 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->VDMOSqgb) = (vgb-vgb1)*capgb + |
|||
*(ckt->CKTstate1 + here->VDMOSqgb) ; |
|||
} else { |
|||
/* TRANOP only */ |
|||
*(ckt->CKTstate0 + here->VDMOSqgs) = vgs*capgs; |
|||
*(ckt->CKTstate0 + here->VDMOSqgd) = vgd*capgd; |
|||
*(ckt->CKTstate0 + here->VDMOSqgb) = vgb*capgb; |
|||
} |
|||
#ifndef PREDICTOR |
|||
} |
|||
#endif /*PREDICTOR*/ |
|||
} |
|||
#ifndef NOBYPASS |
|||
bypass: |
|||
#endif |
|||
if(SenCond) continue; |
|||
|
|||
if ( (ckt->CKTmode & (MODEINITTRAN)) || |
|||
(! (ckt->CKTmode & (MODETRAN)) ) ) { |
|||
/* |
|||
* initialize to zero charge conductances |
|||
* and current |
|||
*/ |
|||
gcgs=0; |
|||
ceqgs=0; |
|||
gcgd=0; |
|||
ceqgd=0; |
|||
gcgb=0; |
|||
ceqgb=0; |
|||
} else { |
|||
if(capgs == 0) *(ckt->CKTstate0 + here->VDMOScqgs) =0; |
|||
if(capgd == 0) *(ckt->CKTstate0 + here->VDMOScqgd) =0; |
|||
if(capgb == 0) *(ckt->CKTstate0 + here->VDMOScqgb) =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); |
|||
error = NIintegrate(ckt,&gcgb,&ceqgb,capgb,here->VDMOSqgb); |
|||
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); |
|||
ceqgb=ceqgb-gcgb*vgb+ckt->CKTag[0]* |
|||
*(ckt->CKTstate0 + here->VDMOSqgb); |
|||
} |
|||
/* |
|||
* store charge storage info for meyer's cap in lx table |
|||
*/ |
|||
|
|||
/* |
|||
* load current vector |
|||
*/ |
|||
ceqbs = model->VDMOStype * |
|||
(here->VDMOScbs-(here->VDMOSgbs)*vbs); |
|||
ceqbd = model->VDMOStype * |
|||
(here->VDMOScbd-(here->VDMOSgbd)*vbd); |
|||
if (here->VDMOSmode >= 0) { |
|||
xnrm=1; |
|||
xrev=0; |
|||
cdreq=model->VDMOStype*(cdrain-here->VDMOSgds*vds- |
|||
here->VDMOSgm*vgs-here->VDMOSgmbs*vbs); |
|||
} else { |
|||
xnrm=0; |
|||
xrev=1; |
|||
cdreq = -(model->VDMOStype)*(cdrain-here->VDMOSgds*(-vds)- |
|||
here->VDMOSgm*vgd-here->VDMOSgmbs*vbd); |
|||
} |
|||
*(ckt->CKTrhs + here->VDMOSgNode) -= |
|||
(model->VDMOStype * (ceqgs + ceqgb + ceqgd)); |
|||
*(ckt->CKTrhs + here->VDMOSbNode) -= |
|||
(ceqbs + ceqbd - model->VDMOStype * ceqgb); |
|||
*(ckt->CKTrhs + here->VDMOSdNodePrime) += |
|||
(ceqbd - cdreq + model->VDMOStype * ceqgd); |
|||
*(ckt->CKTrhs + here->VDMOSsNodePrime) += |
|||
cdreq + ceqbs + model->VDMOStype * ceqgs; |
|||
/* |
|||
* load y matrix |
|||
*/ |
|||
|
|||
*(here->VDMOSDdPtr) += (here->VDMOSdrainConductance); |
|||
*(here->VDMOSGgPtr) += ((gcgd+gcgs+gcgb)); |
|||
*(here->VDMOSSsPtr) += (here->VDMOSsourceConductance); |
|||
*(here->VDMOSBbPtr) += (here->VDMOSgbd+here->VDMOSgbs+gcgb); |
|||
*(here->VDMOSDPdpPtr) += |
|||
(here->VDMOSdrainConductance+here->VDMOSgds+ |
|||
here->VDMOSgbd+xrev*(here->VDMOSgm+here->VDMOSgmbs)+gcgd); |
|||
*(here->VDMOSSPspPtr) += |
|||
(here->VDMOSsourceConductance+here->VDMOSgds+ |
|||
here->VDMOSgbs+xnrm*(here->VDMOSgm+here->VDMOSgmbs)+gcgs); |
|||
*(here->VDMOSDdpPtr) += (-here->VDMOSdrainConductance); |
|||
*(here->VDMOSGbPtr) -= gcgb; |
|||
*(here->VDMOSGdpPtr) -= gcgd; |
|||
*(here->VDMOSGspPtr) -= gcgs; |
|||
*(here->VDMOSSspPtr) += (-here->VDMOSsourceConductance); |
|||
*(here->VDMOSBgPtr) -= gcgb; |
|||
*(here->VDMOSBdpPtr) -= here->VDMOSgbd; |
|||
*(here->VDMOSBspPtr) -= here->VDMOSgbs; |
|||
*(here->VDMOSDPdPtr) += (-here->VDMOSdrainConductance); |
|||
*(here->VDMOSDPgPtr) += ((xnrm-xrev)*here->VDMOSgm-gcgd); |
|||
*(here->VDMOSDPbPtr) += (-here->VDMOSgbd+(xnrm-xrev)*here->VDMOSgmbs); |
|||
*(here->VDMOSDPspPtr) += (-here->VDMOSgds-xnrm* |
|||
(here->VDMOSgm+here->VDMOSgmbs)); |
|||
*(here->VDMOSSPgPtr) += (-(xnrm-xrev)*here->VDMOSgm-gcgs); |
|||
*(here->VDMOSSPsPtr) += (-here->VDMOSsourceConductance); |
|||
*(here->VDMOSSPbPtr) += (-here->VDMOSgbs-(xnrm-xrev)*here->VDMOSgmbs); |
|||
*(here->VDMOSSPdpPtr) += (-here->VDMOSgds-xrev* |
|||
(here->VDMOSgm+here->VDMOSgmbs)); |
|||
} |
|||
} |
|||
return(OK); |
|||
} |
|||
@ -0,0 +1,119 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1987 Thomas L. Quarles |
|||
**********/ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "ngspice/const.h" |
|||
#include "ngspice/ifsim.h" |
|||
#include "ngspice/cktdefs.h" |
|||
#include "ngspice/devdefs.h" |
|||
#include "vdmosdefs.h" |
|||
#include "ngspice/sperror.h" |
|||
#include "ngspice/suffix.h" |
|||
|
|||
/*ARGSUSED*/ |
|||
int |
|||
VDMOSmAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value) |
|||
{ |
|||
VDMOSmodel *model = (VDMOSmodel *)inst; |
|||
|
|||
NG_IGNORE(ckt); |
|||
|
|||
switch(which) { |
|||
case VDMOS_MOD_TNOM: |
|||
value->rValue = model->VDMOStnom-CONSTCtoK; |
|||
return(OK); |
|||
case VDMOS_MOD_VTO: |
|||
value->rValue = model->VDMOSvt0; |
|||
return(OK); |
|||
case VDMOS_MOD_KP: |
|||
value->rValue = model->VDMOStransconductance; |
|||
return(OK); |
|||
case VDMOS_MOD_GAMMA: |
|||
value->rValue = model->VDMOSgamma; |
|||
return(OK); |
|||
case VDMOS_MOD_PHI: |
|||
value->rValue = model->VDMOSphi; |
|||
return(OK); |
|||
case VDMOS_MOD_LAMBDA: |
|||
value->rValue = model->VDMOSlambda; |
|||
return(OK); |
|||
case VDMOS_MOD_RD: |
|||
value->rValue = model->VDMOSdrainResistance; |
|||
return(OK); |
|||
case VDMOS_MOD_RS: |
|||
value->rValue = model->VDMOSsourceResistance; |
|||
return(OK); |
|||
case VDMOS_MOD_CBD: |
|||
value->rValue = model->VDMOScapBD; |
|||
return(OK); |
|||
case VDMOS_MOD_CBS: |
|||
value->rValue = model->VDMOScapBS; |
|||
return(OK); |
|||
case VDMOS_MOD_IS: |
|||
value->rValue = model->VDMOSjctSatCur; |
|||
return(OK); |
|||
case VDMOS_MOD_PB: |
|||
value->rValue = model->VDMOSbulkJctPotential; |
|||
return(OK); |
|||
case VDMOS_MOD_CGSO: |
|||
value->rValue = model->VDMOSgateSourceOverlapCapFactor; |
|||
return(OK); |
|||
case VDMOS_MOD_CGDO: |
|||
value->rValue = model->VDMOSgateDrainOverlapCapFactor; |
|||
return(OK); |
|||
case VDMOS_MOD_CGBO: |
|||
value->rValue = model->VDMOSgateBulkOverlapCapFactor; |
|||
return(OK); |
|||
case VDMOS_MOD_CJ: |
|||
value->rValue = model->VDMOSbulkCapFactor; |
|||
return(OK); |
|||
case VDMOS_MOD_MJ: |
|||
value->rValue = model->VDMOSbulkJctBotGradingCoeff; |
|||
return(OK); |
|||
case VDMOS_MOD_CJSW: |
|||
value->rValue = model->VDMOSsideWallCapFactor; |
|||
return(OK); |
|||
case VDMOS_MOD_MJSW: |
|||
value->rValue = model->VDMOSbulkJctSideGradingCoeff; |
|||
return(OK); |
|||
case VDMOS_MOD_JS: |
|||
value->rValue = model->VDMOSjctSatCurDensity; |
|||
return(OK); |
|||
case VDMOS_MOD_TOX: |
|||
value->rValue = model->VDMOSoxideThickness; |
|||
return(OK); |
|||
case VDMOS_MOD_LD: |
|||
value->rValue = model->VDMOSlatDiff; |
|||
return(OK); |
|||
case VDMOS_MOD_RSH: |
|||
value->rValue = model->VDMOSsheetResistance; |
|||
return(OK); |
|||
case VDMOS_MOD_U0: |
|||
value->rValue = model->VDMOSsurfaceMobility; |
|||
return(OK); |
|||
case VDMOS_MOD_FC: |
|||
value->rValue = model->VDMOSfwdCapDepCoeff; |
|||
return(OK); |
|||
case VDMOS_MOD_NSUB: |
|||
value->rValue = model->VDMOSsubstrateDoping; |
|||
return(OK); |
|||
case VDMOS_MOD_TPG: |
|||
value->iValue = model->VDMOSgateType; |
|||
return(OK); |
|||
case VDMOS_MOD_NSS: |
|||
value->rValue = model->VDMOSsurfaceStateDensity; |
|||
return(OK); |
|||
case VDMOS_MOD_TYPE: |
|||
if (model->VDMOStype > 0) |
|||
value->sValue = "nmos"; |
|||
else |
|||
value->sValue = "pmos"; |
|||
return(OK); |
|||
default: |
|||
return(E_BADPARM); |
|||
} |
|||
/* NOTREACHED */ |
|||
} |
|||
|
|||
@ -0,0 +1,154 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1985 Thomas L. Quarles |
|||
**********/ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "ngspice/const.h" |
|||
#include "ngspice/ifsim.h" |
|||
#include "vdmosdefs.h" |
|||
#include "ngspice/sperror.h" |
|||
#include "ngspice/suffix.h" |
|||
|
|||
int |
|||
VDMOSmParam(int param, IFvalue *value, GENmodel *inModel) |
|||
{ |
|||
VDMOSmodel *model = (VDMOSmodel *)inModel; |
|||
switch(param) { |
|||
case VDMOS_MOD_TNOM: |
|||
model->VDMOStnom = value->rValue + CONSTCtoK; |
|||
model->VDMOStnomGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_VTO: |
|||
model->VDMOSvt0 = value->rValue; |
|||
model->VDMOSvt0Given = TRUE; |
|||
break; |
|||
case VDMOS_MOD_KP: |
|||
model->VDMOStransconductance = value->rValue; |
|||
model->VDMOStransconductanceGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_GAMMA: |
|||
model->VDMOSgamma = value->rValue; |
|||
model->VDMOSgammaGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_PHI: |
|||
model->VDMOSphi = value->rValue; |
|||
model->VDMOSphiGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_LAMBDA: |
|||
model->VDMOSlambda = value->rValue; |
|||
model->VDMOSlambdaGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_RD: |
|||
model->VDMOSdrainResistance = value->rValue; |
|||
model->VDMOSdrainResistanceGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_RS: |
|||
model->VDMOSsourceResistance = value->rValue; |
|||
model->VDMOSsourceResistanceGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_CBD: |
|||
model->VDMOScapBD = value->rValue; |
|||
model->VDMOScapBDGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_CBS: |
|||
model->VDMOScapBS = value->rValue; |
|||
model->VDMOScapBSGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_IS: |
|||
model->VDMOSjctSatCur = value->rValue; |
|||
model->VDMOSjctSatCurGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_PB: |
|||
model->VDMOSbulkJctPotential = value->rValue; |
|||
model->VDMOSbulkJctPotentialGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_CGSO: |
|||
model->VDMOSgateSourceOverlapCapFactor = value->rValue; |
|||
model->VDMOSgateSourceOverlapCapFactorGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_CGDO: |
|||
model->VDMOSgateDrainOverlapCapFactor = value->rValue; |
|||
model->VDMOSgateDrainOverlapCapFactorGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_CGBO: |
|||
model->VDMOSgateBulkOverlapCapFactor = value->rValue; |
|||
model->VDMOSgateBulkOverlapCapFactorGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_CJ: |
|||
model->VDMOSbulkCapFactor = value->rValue; |
|||
model->VDMOSbulkCapFactorGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_MJ: |
|||
model->VDMOSbulkJctBotGradingCoeff = value->rValue; |
|||
model->VDMOSbulkJctBotGradingCoeffGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_CJSW: |
|||
model->VDMOSsideWallCapFactor = value->rValue; |
|||
model->VDMOSsideWallCapFactorGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_MJSW: |
|||
model->VDMOSbulkJctSideGradingCoeff = value->rValue; |
|||
model->VDMOSbulkJctSideGradingCoeffGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_JS: |
|||
model->VDMOSjctSatCurDensity = value->rValue; |
|||
model->VDMOSjctSatCurDensityGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_TOX: |
|||
model->VDMOSoxideThickness = value->rValue; |
|||
model->VDMOSoxideThicknessGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_LD: |
|||
model->VDMOSlatDiff = value->rValue; |
|||
model->VDMOSlatDiffGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_RSH: |
|||
model->VDMOSsheetResistance = value->rValue; |
|||
model->VDMOSsheetResistanceGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_U0: |
|||
model->VDMOSsurfaceMobility = value->rValue; |
|||
model->VDMOSsurfaceMobilityGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_FC: |
|||
model->VDMOSfwdCapDepCoeff = value->rValue; |
|||
model->VDMOSfwdCapDepCoeffGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_NSS: |
|||
model->VDMOSsurfaceStateDensity = value->rValue; |
|||
model->VDMOSsurfaceStateDensityGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_NSUB: |
|||
model->VDMOSsubstrateDoping = value->rValue; |
|||
model->VDMOSsubstrateDopingGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_TPG: |
|||
model->VDMOSgateType = value->iValue; |
|||
model->VDMOSgateTypeGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_NMOS: |
|||
if(value->iValue) { |
|||
model->VDMOStype = 1; |
|||
model->VDMOStypeGiven = TRUE; |
|||
} |
|||
break; |
|||
case VDMOS_MOD_PMOS: |
|||
if(value->iValue) { |
|||
model->VDMOStype = -1; |
|||
model->VDMOStypeGiven = TRUE; |
|||
} |
|||
break; |
|||
case VDMOS_MOD_KF: |
|||
model->VDMOSfNcoef = value->rValue; |
|||
model->VDMOSfNcoefGiven = TRUE; |
|||
break; |
|||
case VDMOS_MOD_AF: |
|||
model->VDMOSfNexp = value->rValue; |
|||
model->VDMOSfNexpGiven = TRUE; |
|||
break; |
|||
default: |
|||
return(E_BADPARM); |
|||
} |
|||
return(OK); |
|||
} |
|||
@ -0,0 +1,190 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1987 Gary W. Ng |
|||
Modified: 2000 AlansFixes |
|||
**********/ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "vdmosdefs.h" |
|||
#include "ngspice/cktdefs.h" |
|||
#include "ngspice/iferrmsg.h" |
|||
#include "ngspice/noisedef.h" |
|||
#include "ngspice/suffix.h" |
|||
|
|||
/* |
|||
* VDMOSnoise (mode, operation, firstModel, ckt, data, OnDens) |
|||
* This routine names and evaluates all of the noise sources |
|||
* associated with MOSFET's. It starts with the model *firstModel and |
|||
* traverses all of its insts. It then proceeds to any other models |
|||
* on the linked list. The total output noise density generated by |
|||
* all of the MOSFET's is summed with the variable "OnDens". |
|||
*/ |
|||
|
|||
|
|||
int |
|||
VDMOSnoise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt, |
|||
Ndata *data, double *OnDens) |
|||
{ |
|||
NOISEAN *job = (NOISEAN *) ckt->CKTcurJob; |
|||
|
|||
VDMOSmodel *firstModel = (VDMOSmodel *) genmodel; |
|||
VDMOSmodel *model; |
|||
VDMOSinstance *inst; |
|||
double coxSquared; |
|||
double tempOnoise; |
|||
double tempInoise; |
|||
double noizDens[VDMOSNSRCS]; |
|||
double lnNdens[VDMOSNSRCS]; |
|||
int i; |
|||
|
|||
/* define the names of the noise sources */ |
|||
|
|||
static char *VDMOSnNames[VDMOSNSRCS] = { /* Note that we have to keep the order */ |
|||
"_rd", /* noise due to rd */ /* consistent with thestrchr definitions */ |
|||
"_rs", /* noise due to rs */ /* in VDMOSdefs.h */ |
|||
"_id", /* noise due to id */ |
|||
"_1overf", /* flicker (1/f) noise */ |
|||
"" /* total transistor noise */ |
|||
}; |
|||
|
|||
for (model=firstModel; model != NULL; model=VDMOSnextModel(model)) { |
|||
|
|||
/* Oxide capacitance can be zero in MOS level 1. Since this will give us problems in our 1/f */ |
|||
/* noise model, we ASSUME an actual "tox" of 1e-7 */ |
|||
|
|||
if (model->VDMOSoxideCapFactor == 0.0) { |
|||
coxSquared = 3.9 * 8.854214871e-12 / 1e-7; |
|||
} else { |
|||
coxSquared = model->VDMOSoxideCapFactor; |
|||
} |
|||
coxSquared *= coxSquared; |
|||
for (inst=VDMOSinstances(model); inst != NULL; inst=VDMOSnextInstance(inst)) { |
|||
|
|||
switch (operation) { |
|||
|
|||
case N_OPEN: |
|||
|
|||
/* see if we have to to produce a summary report */ |
|||
/* if so, name all the noise generators */ |
|||
|
|||
if (job->NStpsSm != 0) { |
|||
switch (mode) { |
|||
|
|||
case N_DENS: |
|||
for (i=0; i < VDMOSNSRCS; i++) { |
|||
NOISE_ADD_OUTVAR(ckt, data, "onoise_%s%s", inst->VDMOSname, VDMOSnNames[i]); |
|||
} |
|||
break; |
|||
|
|||
case INT_NOIZ: |
|||
for (i=0; i < VDMOSNSRCS; i++) { |
|||
NOISE_ADD_OUTVAR(ckt, data, "onoise_total_%s%s", inst->VDMOSname, VDMOSnNames[i]); |
|||
NOISE_ADD_OUTVAR(ckt, data, "inoise_total_%s%s", inst->VDMOSname, VDMOSnNames[i]); |
|||
} |
|||
break; |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case N_CALC: |
|||
switch (mode) { |
|||
|
|||
case N_DENS: |
|||
NevalSrc(&noizDens[VDMOSRDNOIZ],&lnNdens[VDMOSRDNOIZ], |
|||
ckt,THERMNOISE,inst->VDMOSdNodePrime,inst->VDMOSdNode, |
|||
inst->VDMOSdrainConductance); |
|||
|
|||
NevalSrc(&noizDens[VDMOSRSNOIZ],&lnNdens[VDMOSRSNOIZ], |
|||
ckt,THERMNOISE,inst->VDMOSsNodePrime,inst->VDMOSsNode, |
|||
inst->VDMOSsourceConductance); |
|||
|
|||
NevalSrc(&noizDens[VDMOSIDNOIZ],&lnNdens[VDMOSIDNOIZ], |
|||
ckt,THERMNOISE,inst->VDMOSdNodePrime,inst->VDMOSsNodePrime, |
|||
(2.0/3.0 * fabs(inst->VDMOSgm))); |
|||
|
|||
NevalSrc(&noizDens[VDMOSFLNOIZ], NULL, ckt, |
|||
N_GAIN,inst->VDMOSdNodePrime, inst->VDMOSsNodePrime, |
|||
(double)0.0); |
|||
noizDens[VDMOSFLNOIZ] *= model->VDMOSfNcoef * |
|||
exp(model->VDMOSfNexp * |
|||
log(MAX(fabs(inst->VDMOScd),N_MINLOG))) / |
|||
(data->freq * inst->VDMOSw * |
|||
inst->VDMOSm * |
|||
(inst->VDMOSl - 2*model->VDMOSlatDiff) * coxSquared); |
|||
lnNdens[VDMOSFLNOIZ] = |
|||
log(MAX(noizDens[VDMOSFLNOIZ],N_MINLOG)); |
|||
|
|||
noizDens[VDMOSTOTNOIZ] = noizDens[VDMOSRDNOIZ] + |
|||
noizDens[VDMOSRSNOIZ] + |
|||
noizDens[VDMOSIDNOIZ] + |
|||
noizDens[VDMOSFLNOIZ]; |
|||
lnNdens[VDMOSTOTNOIZ] = |
|||
log(MAX(noizDens[VDMOSTOTNOIZ], N_MINLOG)); |
|||
|
|||
*OnDens += noizDens[VDMOSTOTNOIZ]; |
|||
|
|||
if (data->delFreq == 0.0) { |
|||
|
|||
/* if we haven't done any previous integration, we need to */ |
|||
/* initialize our "history" variables */ |
|||
|
|||
for (i=0; i < VDMOSNSRCS; i++) { |
|||
inst->VDMOSnVar[LNLSTDENS][i] = lnNdens[i]; |
|||
} |
|||
|
|||
/* clear out our integration variables if it's the first pass */ |
|||
|
|||
if (data->freq == job->NstartFreq) { |
|||
for (i=0; i < VDMOSNSRCS; i++) { |
|||
inst->VDMOSnVar[OUTNOIZ][i] = 0.0; |
|||
inst->VDMOSnVar[INNOIZ][i] = 0.0; |
|||
} |
|||
} |
|||
} else { /* data->delFreq != 0.0 (we have to integrate) */ |
|||
for (i=0; i < VDMOSNSRCS; i++) { |
|||
if (i != VDMOSTOTNOIZ) { |
|||
tempOnoise = Nintegrate(noizDens[i], lnNdens[i], |
|||
inst->VDMOSnVar[LNLSTDENS][i], data); |
|||
tempInoise = Nintegrate(noizDens[i] * data->GainSqInv , |
|||
lnNdens[i] + data->lnGainInv, |
|||
inst->VDMOSnVar[LNLSTDENS][i] + data->lnGainInv, |
|||
data); |
|||
inst->VDMOSnVar[LNLSTDENS][i] = lnNdens[i]; |
|||
data->outNoiz += tempOnoise; |
|||
data->inNoise += tempInoise; |
|||
if (job->NStpsSm != 0) { |
|||
inst->VDMOSnVar[OUTNOIZ][i] += tempOnoise; |
|||
inst->VDMOSnVar[OUTNOIZ][VDMOSTOTNOIZ] += tempOnoise; |
|||
inst->VDMOSnVar[INNOIZ][i] += tempInoise; |
|||
inst->VDMOSnVar[INNOIZ][VDMOSTOTNOIZ] += tempInoise; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
if (data->prtSummary) { |
|||
for (i=0; i < VDMOSNSRCS; i++) { /* print a summary report */ |
|||
data->outpVector[data->outNumber++] = noizDens[i]; |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case INT_NOIZ: /* already calculated, just output */ |
|||
if (job->NStpsSm != 0) { |
|||
for (i=0; i < VDMOSNSRCS; i++) { |
|||
data->outpVector[data->outNumber++] = inst->VDMOSnVar[OUTNOIZ][i]; |
|||
data->outpVector[data->outNumber++] = inst->VDMOSnVar[INNOIZ][i]; |
|||
} |
|||
} /* if */ |
|||
break; |
|||
} /* switch (mode) */ |
|||
break; |
|||
|
|||
case N_CLOSE: |
|||
return (OK); /* do nothing, the main calling routine will close */ |
|||
break; /* the plots */ |
|||
} /* switch (operation) */ |
|||
} /* for inst */ |
|||
} /* for model */ |
|||
|
|||
return(OK); |
|||
} |
|||
@ -0,0 +1,123 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1985 Thomas L. Quarles |
|||
Modified: 2000 AlansFixes |
|||
**********/ |
|||
/* |
|||
*/ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "ngspice/const.h" |
|||
#include "ngspice/ifsim.h" |
|||
#include "vdmosdefs.h" |
|||
#include "ngspice/sperror.h" |
|||
#include "ngspice/suffix.h" |
|||
#include "ngspice/fteext.h" |
|||
|
|||
|
|||
/* ARGSUSED */ |
|||
int |
|||
VDMOSparam(int param, IFvalue *value, GENinstance *inst, IFvalue *select) |
|||
{ |
|||
double scale; |
|||
|
|||
VDMOSinstance *here = (VDMOSinstance *)inst; |
|||
|
|||
NG_IGNORE(select); |
|||
|
|||
if (!cp_getvar("scale", CP_REAL, &scale)) |
|||
scale = 1; |
|||
|
|||
switch(param) { |
|||
case VDMOS_TEMP: |
|||
here->VDMOStemp = value->rValue+CONSTCtoK; |
|||
here->VDMOStempGiven = TRUE; |
|||
break; |
|||
case VDMOS_DTEMP: |
|||
here->VDMOSdtemp = value->rValue; |
|||
here->VDMOSdtempGiven = TRUE; |
|||
break; |
|||
case VDMOS_M: |
|||
here->VDMOSm = value->rValue; |
|||
here->VDMOSmGiven = TRUE; |
|||
break; |
|||
case VDMOS_W: |
|||
here->VDMOSw = value->rValue * scale; |
|||
here->VDMOSwGiven = TRUE; |
|||
break; |
|||
case VDMOS_L: |
|||
here->VDMOSl = value->rValue * scale; |
|||
here->VDMOSlGiven = TRUE; |
|||
break; |
|||
case VDMOS_AS: |
|||
here->VDMOSsourceArea = value->rValue * scale * scale; |
|||
here->VDMOSsourceAreaGiven = TRUE; |
|||
break; |
|||
case VDMOS_AD: |
|||
here->VDMOSdrainArea = value->rValue * scale * scale; |
|||
here->VDMOSdrainAreaGiven = TRUE; |
|||
break; |
|||
case VDMOS_PS: |
|||
here->VDMOSsourcePerimiter = value->rValue * scale; |
|||
here->VDMOSsourcePerimiterGiven = TRUE; |
|||
break; |
|||
case VDMOS_PD: |
|||
here->VDMOSdrainPerimiter = value->rValue * scale; |
|||
here->VDMOSdrainPerimiterGiven = TRUE; |
|||
break; |
|||
case VDMOS_NRS: |
|||
here->VDMOSsourceSquares = value->rValue; |
|||
here->VDMOSsourceSquaresGiven = TRUE; |
|||
break; |
|||
case VDMOS_NRD: |
|||
here->VDMOSdrainSquares = value->rValue; |
|||
here->VDMOSdrainSquaresGiven = TRUE; |
|||
break; |
|||
case VDMOS_OFF: |
|||
here->VDMOSoff = (value->iValue != 0); |
|||
break; |
|||
case VDMOS_IC_VBS: |
|||
here->VDMOSicVBS = value->rValue; |
|||
here->VDMOSicVBSGiven = TRUE; |
|||
break; |
|||
case VDMOS_IC_VDS: |
|||
here->VDMOSicVDS = value->rValue; |
|||
here->VDMOSicVDSGiven = TRUE; |
|||
break; |
|||
case VDMOS_IC_VGS: |
|||
here->VDMOSicVGS = value->rValue; |
|||
here->VDMOSicVGSGiven = TRUE; |
|||
break; |
|||
case VDMOS_IC: |
|||
switch(value->v.numValue){ |
|||
case 3: |
|||
here->VDMOSicVBS = *(value->v.vec.rVec+2); |
|||
here->VDMOSicVBSGiven = TRUE; |
|||
case 2: |
|||
here->VDMOSicVGS = *(value->v.vec.rVec+1); |
|||
here->VDMOSicVGSGiven = TRUE; |
|||
case 1: |
|||
here->VDMOSicVDS = *(value->v.vec.rVec); |
|||
here->VDMOSicVDSGiven = TRUE; |
|||
break; |
|||
default: |
|||
return(E_BADPARM); |
|||
} |
|||
break; |
|||
case VDMOS_L_SENS: |
|||
if(value->iValue) { |
|||
here->VDMOSsenParmNo = 1; |
|||
here->VDMOSsens_l = 1; |
|||
} |
|||
break; |
|||
case VDMOS_W_SENS: |
|||
if(value->iValue) { |
|||
here->VDMOSsenParmNo = 1; |
|||
here->VDMOSsens_w = 1; |
|||
} |
|||
break; |
|||
default: |
|||
return(E_BADPARM); |
|||
} |
|||
return(OK); |
|||
} |
|||
@ -0,0 +1,132 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1985 Thomas L. Quarles |
|||
Modified: 2000 AlansFixes |
|||
**********/ |
|||
/* |
|||
*/ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "ngspice/cktdefs.h" |
|||
#include "ngspice/complex.h" |
|||
#include "vdmosdefs.h" |
|||
#include "ngspice/sperror.h" |
|||
#include "ngspice/suffix.h" |
|||
|
|||
|
|||
int |
|||
VDMOSpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s) |
|||
{ |
|||
VDMOSmodel *model = (VDMOSmodel*)inModel; |
|||
VDMOSinstance *here; |
|||
int xnrm; |
|||
int xrev; |
|||
double xgs; |
|||
double xgd; |
|||
double xgb; |
|||
double xbd; |
|||
double xbs; |
|||
double capgs; |
|||
double capgd; |
|||
double capgb; |
|||
double GateBulkOverlapCap; |
|||
double GateDrainOverlapCap; |
|||
double GateSourceOverlapCap; |
|||
double EffectiveLength; |
|||
|
|||
for( ; model != NULL; model = VDMOSnextModel(model)) { |
|||
for(here = VDMOSinstances(model); here!= NULL; |
|||
here = VDMOSnextInstance(here)) { |
|||
|
|||
if (here->VDMOSmode < 0) { |
|||
xnrm=0; |
|||
xrev=1; |
|||
} else { |
|||
xnrm=1; |
|||
xrev=0; |
|||
} |
|||
/* |
|||
* meyer's model parameters |
|||
*/ |
|||
EffectiveLength=here->VDMOSl - 2*model->VDMOSlatDiff; |
|||
|
|||
GateSourceOverlapCap = model->VDMOSgateSourceOverlapCapFactor * |
|||
here->VDMOSm * here->VDMOSw; |
|||
GateDrainOverlapCap = model->VDMOSgateDrainOverlapCapFactor * |
|||
here->VDMOSm * here->VDMOSw; |
|||
GateBulkOverlapCap = model->VDMOSgateBulkOverlapCapFactor * |
|||
here->VDMOSm * EffectiveLength; |
|||
|
|||
capgs = ( 2* *(ckt->CKTstate0+here->VDMOScapgs)+ |
|||
GateSourceOverlapCap ); |
|||
capgd = ( 2* *(ckt->CKTstate0+here->VDMOScapgd)+ |
|||
GateDrainOverlapCap ); |
|||
capgb = ( 2* *(ckt->CKTstate0+here->VDMOScapgb)+ |
|||
GateBulkOverlapCap ); |
|||
xgs = capgs; |
|||
xgd = capgd; |
|||
xgb = capgb; |
|||
xbd = here->VDMOScapbd; |
|||
xbs = here->VDMOScapbs; |
|||
/*printf("vdmos: xgs=%g, xgd=%g, xgb=%g, xbd=%g, xbs=%g\n", |
|||
xgs,xgd,xgb,xbd,xbs);*/ |
|||
/* |
|||
* load matrix |
|||
*/ |
|||
|
|||
*(here->VDMOSGgPtr ) += (xgd+xgs+xgb)*s->real; |
|||
*(here->VDMOSGgPtr +1) += (xgd+xgs+xgb)*s->imag; |
|||
*(here->VDMOSBbPtr ) += (xgb+xbd+xbs)*s->real; |
|||
*(here->VDMOSBbPtr +1) += (xgb+xbd+xbs)*s->imag; |
|||
*(here->VDMOSDPdpPtr ) += (xgd+xbd)*s->real; |
|||
*(here->VDMOSDPdpPtr +1) += (xgd+xbd)*s->imag; |
|||
*(here->VDMOSSPspPtr ) += (xgs+xbs)*s->real; |
|||
*(here->VDMOSSPspPtr +1) += (xgs+xbs)*s->imag; |
|||
*(here->VDMOSGbPtr ) -= xgb*s->real; |
|||
*(here->VDMOSGbPtr +1) -= xgb*s->imag; |
|||
*(here->VDMOSGdpPtr ) -= xgd*s->real; |
|||
*(here->VDMOSGdpPtr +1) -= xgd*s->imag; |
|||
*(here->VDMOSGspPtr ) -= xgs*s->real; |
|||
*(here->VDMOSGspPtr +1) -= xgs*s->imag; |
|||
*(here->VDMOSBgPtr ) -= xgb*s->real; |
|||
*(here->VDMOSBgPtr +1) -= xgb*s->imag; |
|||
*(here->VDMOSBdpPtr ) -= xbd*s->real; |
|||
*(here->VDMOSBdpPtr +1) -= xbd*s->imag; |
|||
*(here->VDMOSBspPtr ) -= xbs*s->real; |
|||
*(here->VDMOSBspPtr +1) -= xbs*s->imag; |
|||
*(here->VDMOSDPgPtr ) -= xgd*s->real; |
|||
*(here->VDMOSDPgPtr +1) -= xgd*s->imag; |
|||
*(here->VDMOSDPbPtr ) -= xbd*s->real; |
|||
*(here->VDMOSDPbPtr +1) -= xbd*s->imag; |
|||
*(here->VDMOSSPgPtr ) -= xgs*s->real; |
|||
*(here->VDMOSSPgPtr +1) -= xgs*s->imag; |
|||
*(here->VDMOSSPbPtr ) -= xbs*s->real; |
|||
*(here->VDMOSSPbPtr +1) -= xbs*s->imag; |
|||
*(here->VDMOSDdPtr) += here->VDMOSdrainConductance; |
|||
*(here->VDMOSSsPtr) += here->VDMOSsourceConductance; |
|||
*(here->VDMOSBbPtr) += here->VDMOSgbd+here->VDMOSgbs; |
|||
*(here->VDMOSDPdpPtr) += here->VDMOSdrainConductance+ |
|||
here->VDMOSgds+here->VDMOSgbd+ |
|||
xrev*(here->VDMOSgm+here->VDMOSgmbs); |
|||
*(here->VDMOSSPspPtr) += here->VDMOSsourceConductance+ |
|||
here->VDMOSgds+here->VDMOSgbs+ |
|||
xnrm*(here->VDMOSgm+here->VDMOSgmbs); |
|||
*(here->VDMOSDdpPtr) -= here->VDMOSdrainConductance; |
|||
*(here->VDMOSSspPtr) -= here->VDMOSsourceConductance; |
|||
*(here->VDMOSBdpPtr) -= here->VDMOSgbd; |
|||
*(here->VDMOSBspPtr) -= here->VDMOSgbs; |
|||
*(here->VDMOSDPdPtr) -= here->VDMOSdrainConductance; |
|||
*(here->VDMOSDPgPtr) += (xnrm-xrev)*here->VDMOSgm; |
|||
*(here->VDMOSDPbPtr) += -here->VDMOSgbd+(xnrm-xrev)*here->VDMOSgmbs; |
|||
*(here->VDMOSDPspPtr) -= here->VDMOSgds+ |
|||
xnrm*(here->VDMOSgm+here->VDMOSgmbs); |
|||
*(here->VDMOSSPgPtr) -= (xnrm-xrev)*here->VDMOSgm; |
|||
*(here->VDMOSSPsPtr) -= here->VDMOSsourceConductance; |
|||
*(here->VDMOSSPbPtr) -= here->VDMOSgbs+(xnrm-xrev)*here->VDMOSgmbs; |
|||
*(here->VDMOSSPdpPtr) -= here->VDMOSgds+ |
|||
xrev*(here->VDMOSgm+here->VDMOSgmbs); |
|||
|
|||
} |
|||
} |
|||
return(OK); |
|||
} |
|||
@ -0,0 +1,785 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1985 Thomas L. Quarles |
|||
|
|||
This function is obsolete (was used by an old sensitivity analysis) |
|||
**********/ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "ngspice/smpdefs.h" |
|||
#include "ngspice/cktdefs.h" |
|||
#include "ngspice/const.h" |
|||
#include "vdmosdefs.h" |
|||
#include "ngspice/sperror.h" |
|||
#include "ngspice/suffix.h" |
|||
|
|||
/* actually load the current ac sensitivity |
|||
* information into the array previously provided |
|||
*/ |
|||
|
|||
int |
|||
VDMOSsAcLoad(GENmodel *inModel, CKTcircuit *ckt) |
|||
{ |
|||
VDMOSmodel *model = (VDMOSmodel*)inModel; |
|||
VDMOSinstance *here; |
|||
int xnrm; |
|||
int xrev; |
|||
double A0; |
|||
double Apert = 0.0; |
|||
double DELA; |
|||
double DELAinv; |
|||
double gdpr0; |
|||
double gspr0; |
|||
double gds0; |
|||
double gbs0; |
|||
double gbd0; |
|||
double gm0; |
|||
double gmbs0; |
|||
double gdpr; |
|||
double gspr; |
|||
double gds; |
|||
double gbs; |
|||
double gbd; |
|||
double gm; |
|||
double gmbs; |
|||
double xcgs0; |
|||
double xcgd0; |
|||
double xcgb0; |
|||
double xbd0; |
|||
double xbs0; |
|||
double xcgs; |
|||
double xcgd; |
|||
double xcgb; |
|||
double xbd; |
|||
double xbs; |
|||
double vbsOp; |
|||
double vbdOp; |
|||
double vspr; |
|||
double vdpr; |
|||
double vgs; |
|||
double vgd; |
|||
double vgb; |
|||
double vbs; |
|||
double vbd; |
|||
double vds; |
|||
double ivspr; |
|||
double ivdpr; |
|||
double ivgs; |
|||
double ivgd; |
|||
double ivgb; |
|||
double ivbs; |
|||
double ivbd; |
|||
double ivds; |
|||
double cspr; |
|||
double cdpr; |
|||
double cgs; |
|||
double cgd; |
|||
double cgb; |
|||
double cbs; |
|||
double cbd; |
|||
double cds; |
|||
double cs0; |
|||
double csprm0; |
|||
double cd0; |
|||
double cdprm0; |
|||
double cg0; |
|||
double cb0; |
|||
double cs; |
|||
double csprm; |
|||
double cd; |
|||
double cdprm; |
|||
double cg; |
|||
double cb; |
|||
double icspr; |
|||
double icdpr; |
|||
double icgs; |
|||
double icgd; |
|||
double icgb; |
|||
double icbs; |
|||
double icbd; |
|||
double icds; |
|||
double ics0; |
|||
double icsprm0; |
|||
double icd0; |
|||
double icdprm0; |
|||
double icg0; |
|||
double icb0; |
|||
double ics; |
|||
double icsprm; |
|||
double icd; |
|||
double icdprm; |
|||
double icg; |
|||
double icb; |
|||
double DvDp = 0.0; |
|||
int i; |
|||
int flag; |
|||
int error; |
|||
int iparmno; |
|||
double arg; |
|||
double sarg; |
|||
double sargsw; |
|||
double SaveState[44]; |
|||
int save_mode; |
|||
SENstruct *info; |
|||
|
|||
#ifdef SENSDEBUG |
|||
printf("VDMOSsenacload\n"); |
|||
printf("CKTomega = %.5e\n",ckt->CKTomega); |
|||
#endif /* SENSDEBUG */ |
|||
info = ckt->CKTsenInfo; |
|||
info->SENstatus = PERTURBATION; |
|||
for( ; model != NULL; model = VDMOSnextModel(model)) { |
|||
for(here = VDMOSinstances(model); here!= NULL; |
|||
here = VDMOSnextInstance(here)) { |
|||
|
|||
/* save the unperturbed values in the state vector */ |
|||
for(i=0; i <= 16; i++) |
|||
*(SaveState + i) = *(ckt->CKTstate0 + here->VDMOSstates + i); |
|||
|
|||
*(SaveState + 17) = here->VDMOSsourceConductance; |
|||
*(SaveState + 18) = here->VDMOSdrainConductance; |
|||
*(SaveState + 19) = here->VDMOScd; |
|||
*(SaveState + 20) = here->VDMOScbs; |
|||
*(SaveState + 21) = here->VDMOScbd; |
|||
*(SaveState + 22) = here->VDMOSgmbs; |
|||
*(SaveState + 23) = here->VDMOSgm; |
|||
*(SaveState + 24) = here->VDMOSgds; |
|||
*(SaveState + 25) = here->VDMOSgbd; |
|||
*(SaveState + 26) = here->VDMOSgbs; |
|||
*(SaveState + 27) = here->VDMOScapbd; |
|||
*(SaveState + 28) = here->VDMOScapbs; |
|||
*(SaveState + 29) = here->VDMOSCbd; |
|||
*(SaveState + 30) = here->VDMOSCbdsw; |
|||
*(SaveState + 31) = here->VDMOSCbs; |
|||
*(SaveState + 32) = here->VDMOSCbssw; |
|||
*(SaveState + 33) = here->VDMOSf2d; |
|||
*(SaveState + 34) = here->VDMOSf3d; |
|||
*(SaveState + 35) = here->VDMOSf4d; |
|||
*(SaveState + 36) = here->VDMOSf2s; |
|||
*(SaveState + 37) = here->VDMOSf3s; |
|||
*(SaveState + 38) = here->VDMOSf4s; |
|||
*(SaveState + 39) = here->VDMOScgs; |
|||
*(SaveState + 40) = here->VDMOScgd; |
|||
*(SaveState + 41) = here->VDMOScgb; |
|||
*(SaveState + 42) = here->VDMOSvdsat; |
|||
*(SaveState + 43) = here->VDMOSvon; |
|||
save_mode = here->VDMOSmode; |
|||
|
|||
xnrm=1; |
|||
xrev=0; |
|||
if (here->VDMOSmode < 0) { |
|||
xnrm=0; |
|||
xrev=1; |
|||
} |
|||
|
|||
vbsOp = model->VDMOStype * ( |
|||
*(ckt->CKTrhsOp+here->VDMOSbNode) - |
|||
*(ckt->CKTrhsOp+here->VDMOSsNodePrime)); |
|||
vbdOp = model->VDMOStype * ( |
|||
*(ckt->CKTrhsOp+here->VDMOSbNode) - |
|||
*(ckt->CKTrhsOp+here->VDMOSdNodePrime)); |
|||
vspr = *(ckt->CKTrhsOld + here->VDMOSsNode) |
|||
- *(ckt->CKTrhsOld + |
|||
here->VDMOSsNodePrime) ; |
|||
ivspr = *(ckt->CKTirhsOld + here->VDMOSsNode) |
|||
- *(ckt->CKTirhsOld + |
|||
here->VDMOSsNodePrime) ; |
|||
vdpr = *(ckt->CKTrhsOld + here->VDMOSdNode) |
|||
- *(ckt->CKTrhsOld + |
|||
here->VDMOSdNodePrime) ; |
|||
ivdpr = *(ckt->CKTirhsOld + here->VDMOSdNode) |
|||
- *(ckt->CKTirhsOld + |
|||
here->VDMOSdNodePrime) ; |
|||
vgb = *(ckt->CKTrhsOld + here->VDMOSgNode) |
|||
- *(ckt->CKTrhsOld + |
|||
here->VDMOSbNode) ; |
|||
ivgb = *(ckt->CKTirhsOld + here->VDMOSgNode) |
|||
- *(ckt->CKTirhsOld + |
|||
here->VDMOSbNode) ; |
|||
vbs = *(ckt->CKTrhsOld + here->VDMOSbNode) |
|||
- *(ckt->CKTrhsOld + |
|||
here->VDMOSsNodePrime) ; |
|||
ivbs = *(ckt->CKTirhsOld + here->VDMOSbNode) |
|||
- *(ckt->CKTirhsOld + |
|||
here->VDMOSsNodePrime) ; |
|||
vbd = *(ckt->CKTrhsOld + here->VDMOSbNode) |
|||
- *(ckt->CKTrhsOld + |
|||
here->VDMOSdNodePrime) ; |
|||
ivbd = *(ckt->CKTirhsOld + here->VDMOSbNode) |
|||
- *(ckt->CKTirhsOld + |
|||
here->VDMOSdNodePrime) ; |
|||
vds = vbs - vbd ; |
|||
ivds = ivbs - ivbd ; |
|||
vgs = vgb + vbs ; |
|||
ivgs = ivgb + ivbs ; |
|||
vgd = vgb + vbd ; |
|||
ivgd = ivgb + ivbd ; |
|||
|
|||
#ifdef SENSDEBUG |
|||
printf("senacload instance name %s\n",here->VDMOSname); |
|||
printf("gate = %d ,drain = %d, drainprm = %d\n", |
|||
here->VDMOSgNode,here->VDMOSdNode,here->VDMOSdNodePrime); |
|||
printf("source = %d , sourceprm = %d ,body = %d, senparmno = %d\n", |
|||
here->VDMOSsNode ,here->VDMOSsNodePrime,here->VDMOSbNode, |
|||
here->VDMOSsenParmNo); |
|||
printf("\n without perturbation \n"); |
|||
#endif /* SENSDEBUG */ |
|||
/* without perturbation */ |
|||
*(ckt->CKTstate0 + here->VDMOSvbs) = vbsOp; |
|||
*(ckt->CKTstate0 + here->VDMOSvbd) = vbdOp; |
|||
|
|||
here->VDMOSsenPertFlag = ON ; |
|||
if(info->SENacpertflag == 1){ |
|||
/* store the unperturbed values of small signal parameters */ |
|||
if((error = VDMOSload((GENmodel*)model,ckt)) != 0) |
|||
return(error); |
|||
*(here->VDMOSsenCgs) = here->VDMOScgs; |
|||
*(here->VDMOSsenCgd) = here->VDMOScgd; |
|||
*(here->VDMOSsenCgb) = here->VDMOScgb; |
|||
*(here->VDMOSsenCbd) = here->VDMOScapbd; |
|||
*(here->VDMOSsenCbs) = here->VDMOScapbs; |
|||
*(here->VDMOSsenGds) = here->VDMOSgds; |
|||
*(here->VDMOSsenGbs) = here->VDMOSgbs; |
|||
*(here->VDMOSsenGbd) = here->VDMOSgbd; |
|||
*(here->VDMOSsenGm) = here->VDMOSgm; |
|||
*(here->VDMOSsenGmbs) = here->VDMOSgmbs; |
|||
|
|||
} |
|||
xcgs0= *(here->VDMOSsenCgs) * ckt->CKTomega; |
|||
xcgd0= *(here->VDMOSsenCgd) * ckt->CKTomega; |
|||
xcgb0= *(here->VDMOSsenCgb) * ckt->CKTomega; |
|||
xbd0= *(here->VDMOSsenCbd) * ckt->CKTomega; |
|||
xbs0= *(here->VDMOSsenCbs) * ckt->CKTomega; |
|||
gds0= *(here->VDMOSsenGds); |
|||
gbs0= *(here->VDMOSsenGbs); |
|||
gbd0= *(here->VDMOSsenGbd); |
|||
gm0= *(here->VDMOSsenGm); |
|||
gmbs0= *(here->VDMOSsenGmbs); |
|||
gdpr0 = here->VDMOSdrainConductance; |
|||
gspr0 = here->VDMOSsourceConductance; |
|||
|
|||
|
|||
cspr = gspr0 * vspr ; |
|||
icspr = gspr0 * ivspr ; |
|||
cdpr = gdpr0 * vdpr ; |
|||
icdpr = gdpr0 * ivdpr ; |
|||
cgs = ( - xcgs0 * ivgs ); |
|||
icgs = xcgs0 * vgs ; |
|||
cgd = ( - xcgd0 * ivgd ); |
|||
icgd = xcgd0 * vgd ; |
|||
cgb = ( - xcgb0 * ivgb ); |
|||
icgb = xcgb0 * vgb ; |
|||
cbs = ( gbs0 * vbs - xbs0 * ivbs ); |
|||
icbs = ( xbs0 * vbs + gbs0 * ivbs ); |
|||
cbd = ( gbd0 * vbd - xbd0 * ivbd ); |
|||
icbd = ( xbd0 * vbd + gbd0 * ivbd ); |
|||
cds = ( gds0 * vds + xnrm * (gm0 * vgs + gmbs0 * vbs) |
|||
- xrev * (gm0 * vgd + gmbs0 * vbd) ); |
|||
icds = ( gds0 * ivds + xnrm * (gm0 * ivgs + gmbs0 * ivbs) |
|||
- xrev * (gm0 * ivgd + gmbs0 * ivbd) ); |
|||
|
|||
cs0 = cspr; |
|||
ics0 = icspr; |
|||
csprm0 = ( -cspr - cgs - cbs - cds ) ; |
|||
icsprm0 = ( -icspr - icgs - icbs - icds ) ; |
|||
cd0 = cdpr; |
|||
icd0 = icdpr; |
|||
cdprm0 = ( -cdpr - cgd - cbd + cds ) ; |
|||
icdprm0 = ( -icdpr - icgd - icbd + icds ) ; |
|||
cg0 = cgs + cgd + cgb ; |
|||
icg0 = icgs + icgd + icgb ; |
|||
cb0 = cbs + cbd - cgb ; |
|||
icb0 = icbs + icbd - icgb ; |
|||
#ifdef SENSDEBUG |
|||
printf("gspr0 = %.7e , gdpr0 = %.7e , gds0 = %.7e, gbs0 = %.7e\n", |
|||
gspr0,gdpr0,gds0,gbs0); |
|||
printf("gbd0 = %.7e , gm0 = %.7e , gmbs0 = %.7e\n",gbd0,gm0,gmbs0); |
|||
printf("xcgs0 = %.7e , xcgd0 = %.7e , xcgb0 = %.7e,", |
|||
xcgs0,xcgd0,xcgb0); |
|||
printf("xbd0 = %.7e,xbs0 = %.7e\n",xbd0,xbs0); |
|||
printf("vbs = %.7e , vbd = %.7e , vgb = %.7e\n",vbs,vbd,vgb); |
|||
printf("ivbs = %.7e , ivbd = %.7e , ivgb = %.7e\n",ivbs,ivbd,ivgb); |
|||
printf("cbs0 = %.7e , cbd0 = %.7e , cgb0 = %.7e\n",cbs,cbd,cgb); |
|||
printf("cb0 = %.7e , cg0 = %.7e , cs0 = %.7e\n",cb0,cg0,cs0); |
|||
printf("csprm0 = %.7e, cd0 = %.7e, cdprm0 = %.7e\n", |
|||
csprm0,cd0,cdprm0); |
|||
printf("icb0 = %.7e , icg0 = %.7e , ics0 = %.7e\n",icb0,icg0,ics0); |
|||
printf("icsprm0 = %.7e, icd0 = %.7e, icdprm0 = %.7e\n", |
|||
icsprm0,icd0,icdprm0); |
|||
printf("\nPerturbation of vbs\n"); |
|||
#endif /* SENSDEBUG */ |
|||
|
|||
/* Perturbation of vbs */ |
|||
flag = 1; |
|||
A0 = vbsOp; |
|||
DELA = info->SENpertfac * here->VDMOStVto ; |
|||
DELAinv = 1.0/DELA; |
|||
|
|||
if(info->SENacpertflag == 1){ |
|||
/* store the values of small signal parameters |
|||
* corresponding to perturbed vbs */ |
|||
Apert = A0 + DELA; |
|||
*(ckt->CKTstate0 + here->VDMOSvbs) = Apert; |
|||
*(ckt->CKTstate0 + here->VDMOSvbd) = vbdOp; |
|||
|
|||
if((error = VDMOSload((GENmodel*)model,ckt)) != 0) |
|||
return(error); |
|||
|
|||
*(here->VDMOSsenCgs + 1) = here->VDMOScgs; |
|||
*(here->VDMOSsenCgd + 1) = here->VDMOScgd; |
|||
*(here->VDMOSsenCgb + 1) = here->VDMOScgb; |
|||
*(here->VDMOSsenCbd + 1) = here->VDMOScapbd; |
|||
*(here->VDMOSsenCbs + 1) = here->VDMOScapbs; |
|||
*(here->VDMOSsenGds + 1) = here->VDMOSgds; |
|||
*(here->VDMOSsenGbs + 1) = here->VDMOSgbs; |
|||
*(here->VDMOSsenGbd + 1) = here->VDMOSgbd; |
|||
*(here->VDMOSsenGm + 1) = here->VDMOSgm; |
|||
*(here->VDMOSsenGmbs + 1) = here->VDMOSgmbs; |
|||
|
|||
*(ckt->CKTstate0 + here->VDMOSvbs) = A0; |
|||
|
|||
|
|||
} |
|||
|
|||
goto load; |
|||
|
|||
|
|||
pertvbd: /* Perturbation of vbd */ |
|||
#ifdef SENSDEBUG |
|||
printf("\nPerturbation of vbd\n"); |
|||
#endif /* SENSDEBUG */ |
|||
|
|||
flag = 2; |
|||
A0 = vbdOp; |
|||
DELA = info->SENpertfac * here->VDMOStVto + 1e-8; |
|||
DELAinv = 1.0/DELA; |
|||
|
|||
if(info->SENacpertflag == 1){ |
|||
/* store the values of small signal parameters |
|||
* corresponding to perturbed vbd */ |
|||
Apert = A0 + DELA; |
|||
*(ckt->CKTstate0 + here->VDMOSvbs) = vbsOp; |
|||
*(ckt->CKTstate0 + here->VDMOSvbd) = Apert; |
|||
|
|||
if((error = VDMOSload((GENmodel*)model,ckt)) != 0) |
|||
return(error); |
|||
|
|||
*(here->VDMOSsenCgs + 2) = here->VDMOScgs; |
|||
*(here->VDMOSsenCgd + 2) = here->VDMOScgd; |
|||
*(here->VDMOSsenCgb + 2) = here->VDMOScgb; |
|||
*(here->VDMOSsenCbd + 2) = here->VDMOScapbd; |
|||
*(here->VDMOSsenCbs + 2) = here->VDMOScapbs; |
|||
*(here->VDMOSsenGds + 2) = here->VDMOSgds; |
|||
*(here->VDMOSsenGbs + 2) = here->VDMOSgbs; |
|||
*(here->VDMOSsenGbd + 2) = here->VDMOSgbd; |
|||
*(here->VDMOSsenGm + 2) = here->VDMOSgm; |
|||
*(here->VDMOSsenGmbs + 2) = here->VDMOSgmbs; |
|||
|
|||
*(ckt->CKTstate0 + here->VDMOSvbd) = A0; |
|||
|
|||
} |
|||
|
|||
goto load; |
|||
|
|||
|
|||
pertvgb: /* Perturbation of vgb */ |
|||
#ifdef SENSDEBUG |
|||
printf("\nPerturbation of vgb\n"); |
|||
#endif /* SENSDEBUG */ |
|||
|
|||
flag = 3; |
|||
A0 = model->VDMOStype * (*(ckt->CKTrhsOp + here->VDMOSgNode) |
|||
- *(ckt->CKTrhsOp + here->VDMOSbNode)); |
|||
DELA = info->SENpertfac * A0 + 1e-8; |
|||
DELAinv = model->VDMOStype * 1.0/DELA; |
|||
|
|||
|
|||
if(info->SENacpertflag == 1){ |
|||
/* store the values of small signal parameters |
|||
* corresponding to perturbed vgb */ |
|||
*(ckt->CKTstate0 + here->VDMOSvbs) = vbsOp; |
|||
*(ckt->CKTstate0 + here->VDMOSvbd) = vbdOp; |
|||
*(ckt->CKTrhsOp + here->VDMOSbNode) -= DELA; |
|||
|
|||
if((error = VDMOSload((GENmodel*)model,ckt)) != 0) |
|||
return(error); |
|||
|
|||
*(here->VDMOSsenCgs + 3) = here->VDMOScgs; |
|||
*(here->VDMOSsenCgd + 3) = here->VDMOScgd; |
|||
*(here->VDMOSsenCgb + 3) = here->VDMOScgb; |
|||
*(here->VDMOSsenCbd + 3) = here->VDMOScapbd; |
|||
*(here->VDMOSsenCbs + 3) = here->VDMOScapbs; |
|||
*(here->VDMOSsenGds + 3) = here->VDMOSgds; |
|||
*(here->VDMOSsenGbs + 3) = here->VDMOSgbs; |
|||
*(here->VDMOSsenGbd + 3) = here->VDMOSgbd; |
|||
*(here->VDMOSsenGm + 3) = here->VDMOSgm; |
|||
*(here->VDMOSsenGmbs + 3) = here->VDMOSgmbs; |
|||
|
|||
|
|||
*(ckt->CKTrhsOp + here->VDMOSbNode) += DELA; |
|||
} |
|||
goto load; |
|||
|
|||
pertl: /* Perturbation of length */ |
|||
|
|||
if(here->VDMOSsens_l == 0){ |
|||
goto pertw; |
|||
} |
|||
#ifdef SENSDEBUG |
|||
printf("\nPerturbation of length\n"); |
|||
#endif /* SENSDEBUG */ |
|||
flag = 4; |
|||
A0 = here->VDMOSl; |
|||
DELA = info->SENpertfac * A0; |
|||
DELAinv = 1.0/DELA; |
|||
|
|||
if(info->SENacpertflag == 1){ |
|||
/* store the values of small signal parameters |
|||
* corresponding to perturbed length */ |
|||
Apert = A0 + DELA; |
|||
here->VDMOSl = Apert; |
|||
|
|||
*(ckt->CKTstate0 + here->VDMOSvbs) = vbsOp; |
|||
*(ckt->CKTstate0 + here->VDMOSvbd) = vbdOp; |
|||
|
|||
if ((error = VDMOSload((GENmodel*)model,ckt)) != 0) |
|||
return(error); |
|||
|
|||
*(here->VDMOSsenCgs + 4) = here->VDMOScgs; |
|||
*(here->VDMOSsenCgd + 4) = here->VDMOScgd; |
|||
*(here->VDMOSsenCgb + 4) = here->VDMOScgb; |
|||
*(here->VDMOSsenCbd + 4) = here->VDMOScapbd; |
|||
*(here->VDMOSsenCbs + 4) = here->VDMOScapbs; |
|||
*(here->VDMOSsenGds + 4) = here->VDMOSgds; |
|||
*(here->VDMOSsenGbs + 4) = here->VDMOSgbs; |
|||
*(here->VDMOSsenGbd + 4) = here->VDMOSgbd; |
|||
*(here->VDMOSsenGm + 4) = here->VDMOSgm; |
|||
*(here->VDMOSsenGmbs + 4) = here->VDMOSgmbs; |
|||
|
|||
here->VDMOSl = A0; |
|||
|
|||
} |
|||
|
|||
goto load; |
|||
|
|||
pertw: /* Perturbation of width */ |
|||
if(here->VDMOSsens_w == 0) |
|||
goto next; |
|||
#ifdef SENSDEBUG |
|||
printf("\nPerturbation of width\n"); |
|||
#endif /* SENSDEBUG */ |
|||
flag = 5; |
|||
A0 = here->VDMOSw; |
|||
DELA = info->SENpertfac * A0; |
|||
DELAinv = 1.0/DELA; |
|||
Apert = A0 + DELA; |
|||
|
|||
if(info->SENacpertflag == 1){ |
|||
/* store the values of small signal parameters |
|||
* corresponding to perturbed width */ |
|||
here->VDMOSw = Apert; |
|||
here->VDMOSdrainArea *= (1 + info->SENpertfac); |
|||
here->VDMOSsourceArea *= (1 + info->SENpertfac); |
|||
here->VDMOSCbd *= (1 + info->SENpertfac); |
|||
here->VDMOSCbs *= (1 + info->SENpertfac); |
|||
if(here->VDMOSdrainPerimiter){ |
|||
here->VDMOSCbdsw += here->VDMOSCbdsw * |
|||
DELA/here->VDMOSdrainPerimiter; |
|||
} |
|||
if(here->VDMOSsourcePerimiter){ |
|||
here->VDMOSCbssw += here->VDMOSCbssw * |
|||
DELA/here->VDMOSsourcePerimiter; |
|||
} |
|||
if(vbdOp >= here->VDMOStDepCap){ |
|||
arg = 1-model->VDMOSfwdCapDepCoeff; |
|||
sarg = exp( (-model->VDMOSbulkJctBotGradingCoeff) * |
|||
log(arg) ); |
|||
sargsw = exp( (-model->VDMOSbulkJctSideGradingCoeff) * |
|||
log(arg) ); |
|||
here->VDMOSf2d = here->VDMOSCbd*(1-model->VDMOSfwdCapDepCoeff* |
|||
(1+model->VDMOSbulkJctBotGradingCoeff))* sarg/arg |
|||
+ here->VDMOSCbdsw*(1-model->VDMOSfwdCapDepCoeff* |
|||
(1+model->VDMOSbulkJctSideGradingCoeff))* |
|||
sargsw/arg; |
|||
here->VDMOSf3d = here->VDMOSCbd * |
|||
model->VDMOSbulkJctBotGradingCoeff * sarg/arg/ |
|||
here->VDMOStBulkPot + here->VDMOSCbdsw * |
|||
model->VDMOSbulkJctSideGradingCoeff * sargsw/arg / |
|||
here->VDMOStBulkPot; |
|||
here->VDMOSf4d = here->VDMOSCbd*here->VDMOStBulkPot* |
|||
(1-arg*sarg)/ (1-model->VDMOSbulkJctBotGradingCoeff) |
|||
+ here->VDMOSCbdsw*here->VDMOStBulkPot*(1-arg*sargsw)/ |
|||
(1-model->VDMOSbulkJctSideGradingCoeff) |
|||
-here->VDMOSf3d/2* |
|||
(here->VDMOStDepCap*here->VDMOStDepCap) |
|||
-here->VDMOStDepCap * here->VDMOSf2d; |
|||
} |
|||
if(vbsOp >= here->VDMOStDepCap){ |
|||
arg = 1-model->VDMOSfwdCapDepCoeff; |
|||
sarg = exp( (-model->VDMOSbulkJctBotGradingCoeff) * |
|||
log(arg) ); |
|||
sargsw = exp( (-model->VDMOSbulkJctSideGradingCoeff) * |
|||
log(arg) ); |
|||
here->VDMOSf2s = here->VDMOSCbs*(1-model->VDMOSfwdCapDepCoeff* |
|||
(1+model->VDMOSbulkJctBotGradingCoeff))* sarg/arg |
|||
+ here->VDMOSCbssw*(1-model->VDMOSfwdCapDepCoeff* |
|||
(1+model->VDMOSbulkJctSideGradingCoeff))* |
|||
sargsw/arg; |
|||
here->VDMOSf3s = here->VDMOSCbs * |
|||
model->VDMOSbulkJctBotGradingCoeff * sarg/arg/ |
|||
here->VDMOStBulkPot + here->VDMOSCbssw * |
|||
model->VDMOSbulkJctSideGradingCoeff * sargsw/arg / |
|||
here->VDMOStBulkPot; |
|||
here->VDMOSf4s = here->VDMOSCbs* |
|||
here->VDMOStBulkPot*(1-arg*sarg)/ |
|||
(1-model->VDMOSbulkJctBotGradingCoeff) |
|||
+ here->VDMOSCbssw*here->VDMOStBulkPot*(1-arg*sargsw)/ |
|||
(1-model->VDMOSbulkJctSideGradingCoeff) |
|||
-here->VDMOSf3s/2* |
|||
(here->VDMOStDepCap*here->VDMOStDepCap) |
|||
-here->VDMOStDepCap * here->VDMOSf2s; |
|||
} |
|||
|
|||
*(ckt->CKTstate0 + here->VDMOSvbs) = vbsOp; |
|||
*(ckt->CKTstate0 + here->VDMOSvbd) = vbdOp; |
|||
|
|||
if ((error = VDMOSload((GENmodel*)model,ckt)) != 0) |
|||
return(error); |
|||
|
|||
*(here->VDMOSsenCgs + 5) = here->VDMOScgs; |
|||
*(here->VDMOSsenCgd + 5) = here->VDMOScgd; |
|||
*(here->VDMOSsenCgb + 5) = here->VDMOScgb; |
|||
*(here->VDMOSsenCbd + 5) = here->VDMOScapbd; |
|||
*(here->VDMOSsenCbs + 5) = here->VDMOScapbs; |
|||
*(here->VDMOSsenGds + 5) = here->VDMOSgds; |
|||
*(here->VDMOSsenGbs + 5) = here->VDMOSgbs; |
|||
*(here->VDMOSsenGbd + 5) = here->VDMOSgbd; |
|||
*(here->VDMOSsenGm + 5) = here->VDMOSgm; |
|||
*(here->VDMOSsenGmbs + 5) = here->VDMOSgmbs; |
|||
|
|||
here->VDMOSw = A0; |
|||
here->VDMOSdrainArea /= (1 + info->SENpertfac); |
|||
here->VDMOSsourceArea /= (1 + info->SENpertfac); |
|||
} |
|||
|
|||
load: |
|||
|
|||
gds= *(here->VDMOSsenGds + flag); |
|||
gbs= *(here->VDMOSsenGbs + flag); |
|||
gbd= *(here->VDMOSsenGbd + flag); |
|||
gm= *(here->VDMOSsenGm + flag); |
|||
gmbs= *(here->VDMOSsenGmbs + flag); |
|||
if(flag == 5){ |
|||
gdpr = here->VDMOSdrainConductance * Apert/A0; |
|||
gspr = here->VDMOSsourceConductance * Apert/A0; |
|||
} |
|||
else{ |
|||
gdpr = here->VDMOSdrainConductance; |
|||
gspr = here->VDMOSsourceConductance; |
|||
} |
|||
|
|||
xcgs= *(here->VDMOSsenCgs + flag) * ckt->CKTomega; |
|||
xcgd= *(here->VDMOSsenCgd + flag) * ckt->CKTomega; |
|||
xcgb= *(here->VDMOSsenCgb + flag) * ckt->CKTomega; |
|||
xbd= *(here->VDMOSsenCbd + flag) * ckt->CKTomega; |
|||
xbs= *(here->VDMOSsenCbs + flag) * ckt->CKTomega; |
|||
|
|||
#ifdef SENSDEBUG |
|||
printf("flag = %d \n",flag); |
|||
printf("gspr = %.7e , gdpr = %.7e , gds = %.7e, gbs = %.7e\n", |
|||
gspr,gdpr,gds,gbs); |
|||
printf("gbd = %.7e , gm = %.7e , gmbs = %.7e\n",gbd,gm,gmbs); |
|||
printf("xcgs = %.7e , xcgd = %.7e , xcgb = %.7e,", xcgs,xcgd,xcgb); |
|||
printf("xbd = %.7e,xbs = %.7e\n",xbd,xbs); |
|||
#endif /* SENSDEBUG */ |
|||
cspr = gspr * vspr ; |
|||
icspr = gspr * ivspr ; |
|||
cdpr = gdpr * vdpr ; |
|||
icdpr = gdpr * ivdpr ; |
|||
cgs = ( - xcgs * ivgs ); |
|||
icgs = xcgs * vgs ; |
|||
cgd = ( - xcgd * ivgd ); |
|||
icgd = xcgd * vgd ; |
|||
cgb = ( - xcgb * ivgb ); |
|||
icgb = xcgb * vgb ; |
|||
cbs = ( gbs * vbs - xbs * ivbs ); |
|||
icbs = ( xbs * vbs + gbs * ivbs ); |
|||
cbd = ( gbd * vbd - xbd * ivbd ); |
|||
icbd = ( xbd * vbd + gbd * ivbd ); |
|||
cds = ( gds * vds + xnrm * (gm * vgs + gmbs * vbs) |
|||
- xrev * (gm * vgd + gmbs * vbd) ); |
|||
icds = ( gds * ivds + xnrm * (gm * ivgs + gmbs * ivbs) |
|||
- xrev * (gm * ivgd + gmbs * ivbd) ); |
|||
|
|||
cs = cspr; |
|||
ics = icspr; |
|||
csprm = ( -cspr - cgs - cbs - cds ) ; |
|||
icsprm = ( -icspr - icgs - icbs - icds ) ; |
|||
cd = cdpr; |
|||
icd = icdpr; |
|||
cdprm = ( -cdpr - cgd - cbd + cds ) ; |
|||
icdprm = ( -icdpr - icgd - icbd + icds ) ; |
|||
cg = cgs + cgd + cgb ; |
|||
icg = icgs + icgd + icgb ; |
|||
cb = cbs + cbd - cgb ; |
|||
icb = icbs + icbd - icgb ; |
|||
|
|||
#ifdef SENSDEBUG |
|||
printf("vbs = %.7e , vbd = %.7e , vgb = %.7e\n",vbs,vbd,vgb); |
|||
printf("ivbs = %.7e , ivbd = %.7e , ivgb = %.7e\n",ivbs,ivbd,ivgb); |
|||
printf("cbs = %.7e , cbd = %.7e , cgb = %.7e\n",cbs,cbd,cgb); |
|||
printf("cb = %.7e , cg = %.7e , cs = %.7e\n",cb,cg,cs); |
|||
printf("csprm = %.7e, cd = %.7e, cdprm = %.7e\n",csprm,cd,cdprm); |
|||
printf("icb = %.7e , icg = %.7e , ics = %.7e\n",icb,icg,ics); |
|||
printf("icsprm = %.7e, icd = %.7e, icdprm = %.7e\n", |
|||
icsprm,icd,icdprm); |
|||
#endif /* SENSDEBUG */ |
|||
for(iparmno = 1;iparmno<=info->SENparms;iparmno++){ |
|||
if((flag == 4) && (iparmno != here->VDMOSsenParmNo)) continue; |
|||
if( (flag == 5) && (iparmno != (here->VDMOSsenParmNo + |
|||
here->VDMOSsens_l))) continue; |
|||
|
|||
switch(flag){ |
|||
case 1: |
|||
DvDp = model->VDMOStype * |
|||
(info->SEN_Sap[here->VDMOSbNode][iparmno] |
|||
- info->SEN_Sap[here->VDMOSsNodePrime][iparmno]); |
|||
break; |
|||
case 2: |
|||
DvDp = model->VDMOStype * |
|||
( info->SEN_Sap[here->VDMOSbNode][iparmno] |
|||
- info->SEN_Sap[here->VDMOSdNodePrime][iparmno]); |
|||
break; |
|||
case 3: |
|||
DvDp = model->VDMOStype * |
|||
( info->SEN_Sap[here->VDMOSgNode][iparmno] |
|||
- info->SEN_Sap[here->VDMOSbNode][iparmno]); |
|||
break; |
|||
case 4: |
|||
DvDp = 1; |
|||
break; |
|||
case 5: |
|||
DvDp = 1; |
|||
break; |
|||
} |
|||
*(info->SEN_RHS[here->VDMOSbNode] + iparmno) -= |
|||
( cb - cb0) * DELAinv * DvDp; |
|||
*(info->SEN_iRHS[here->VDMOSbNode] + iparmno) -= |
|||
( icb - icb0) * DELAinv * DvDp; |
|||
|
|||
*(info->SEN_RHS[here->VDMOSgNode] + iparmno) -= |
|||
( cg - cg0) * DELAinv * DvDp; |
|||
*(info->SEN_iRHS[here->VDMOSgNode] + iparmno) -= |
|||
( icg - icg0) * DELAinv * DvDp; |
|||
|
|||
if(here->VDMOSsNode != here->VDMOSsNodePrime){ |
|||
*(info->SEN_RHS[here->VDMOSsNode] + iparmno) -= |
|||
( cs - cs0) * DELAinv * DvDp; |
|||
*(info->SEN_iRHS[here->VDMOSsNode] + iparmno) -= |
|||
( ics - ics0) * DELAinv * DvDp; |
|||
} |
|||
|
|||
*(info->SEN_RHS[here->VDMOSsNodePrime] + iparmno) -= |
|||
( csprm - csprm0) * DELAinv * DvDp; |
|||
*(info->SEN_iRHS[here->VDMOSsNodePrime] + iparmno) -= |
|||
( icsprm - icsprm0) * DELAinv * DvDp; |
|||
|
|||
if(here->VDMOSdNode != here->VDMOSdNodePrime){ |
|||
*(info->SEN_RHS[here->VDMOSdNode] + iparmno) -= |
|||
( cd - cd0) * DELAinv * DvDp; |
|||
*(info->SEN_iRHS[here->VDMOSdNode] + iparmno) -= |
|||
( icd - icd0) * DELAinv * DvDp; |
|||
} |
|||
|
|||
*(info->SEN_RHS[here->VDMOSdNodePrime] + iparmno) -= |
|||
( cdprm - cdprm0) * DELAinv * DvDp; |
|||
*(info->SEN_iRHS[here->VDMOSdNodePrime] + iparmno) -= |
|||
( icdprm - icdprm0) * DELAinv * DvDp; |
|||
#ifdef SENSDEBUG |
|||
printf("after loading\n"); |
|||
printf("DvDp = %.5e , DELAinv = %.5e ,flag = %d ,", |
|||
DvDp,DELAinv,flag); |
|||
printf("iparmno = %d,senparmno = %d\n", |
|||
iparmno,here->VDMOSsenParmNo); |
|||
printf("A0 = %.5e , Apert = %.5e ,CONSTvt = %.5e \n", |
|||
A0,Apert,here->VDMOStVto); |
|||
printf("senb = %.7e + j%.7e ", |
|||
*(info->SEN_RHS[here->VDMOSbNode] + iparmno), |
|||
*(info->SEN_iRHS[here->VDMOSbNode] + iparmno)); |
|||
printf("seng = %.7e + j%.7e ", |
|||
*(info->SEN_RHS[here->VDMOSgNode] + iparmno), |
|||
*(info->SEN_iRHS[here->VDMOSgNode] + iparmno)); |
|||
printf("sens = %.7e + j%.7e ", |
|||
*(info->SEN_RHS[here->VDMOSsNode] + iparmno), |
|||
*(info->SEN_iRHS[here->VDMOSsNode] + iparmno)); |
|||
printf("sensprm = %.7e + j%.7e ", |
|||
*(info->SEN_RHS[here->VDMOSsNodePrime] + iparmno), |
|||
*(info->SEN_iRHS[here->VDMOSsNodePrime] + iparmno)); |
|||
printf("send = %.7e + j%.7e ", |
|||
*(info->SEN_RHS[here->VDMOSdNode] + iparmno), |
|||
*(info->SEN_iRHS[here->VDMOSdNode] + iparmno)); |
|||
printf("sendprm = %.7e + j%.7e ", |
|||
*(info->SEN_RHS[here->VDMOSdNodePrime] + iparmno), |
|||
*(info->SEN_iRHS[here->VDMOSdNodePrime] + iparmno)); |
|||
#endif /* SENSDEBUG */ |
|||
|
|||
} |
|||
switch(flag){ |
|||
case 1: |
|||
goto pertvbd ; |
|||
case 2: |
|||
goto pertvgb ; |
|||
case 3: |
|||
goto pertl ; |
|||
case 4: |
|||
goto pertw ; |
|||
case 5: |
|||
break; |
|||
} |
|||
next: |
|||
; |
|||
|
|||
/* put the unperturbed values back into the state vector */ |
|||
for(i=0; i <= 16; i++) |
|||
*(ckt->CKTstate0 + here->VDMOSstates + i) = *(SaveState + i); |
|||
|
|||
here->VDMOSsourceConductance = *(SaveState + 17) ; |
|||
here->VDMOSdrainConductance = *(SaveState + 18) ; |
|||
here->VDMOScd = *(SaveState + 19) ; |
|||
here->VDMOScbs = *(SaveState + 20) ; |
|||
here->VDMOScbd = *(SaveState + 21) ; |
|||
here->VDMOSgmbs = *(SaveState + 22) ; |
|||
here->VDMOSgm = *(SaveState + 23) ; |
|||
here->VDMOSgds = *(SaveState + 24) ; |
|||
here->VDMOSgbd = *(SaveState + 25) ; |
|||
here->VDMOSgbs = *(SaveState + 26) ; |
|||
here->VDMOScapbd = *(SaveState + 27) ; |
|||
here->VDMOScapbs = *(SaveState + 28) ; |
|||
here->VDMOSCbd = *(SaveState + 29) ; |
|||
here->VDMOSCbdsw = *(SaveState + 30) ; |
|||
here->VDMOSCbs = *(SaveState + 31) ; |
|||
here->VDMOSCbssw = *(SaveState + 32) ; |
|||
here->VDMOSf2d = *(SaveState + 33) ; |
|||
here->VDMOSf3d = *(SaveState + 34) ; |
|||
here->VDMOSf4d = *(SaveState + 35) ; |
|||
here->VDMOSf2s = *(SaveState + 36) ; |
|||
here->VDMOSf3s = *(SaveState + 37) ; |
|||
here->VDMOSf4s = *(SaveState + 38) ; |
|||
here->VDMOScgs = *(SaveState + 39) ; |
|||
here->VDMOScgd = *(SaveState + 40) ; |
|||
here->VDMOScgb = *(SaveState + 41) ; |
|||
here->VDMOSvdsat = *(SaveState + 42) ; |
|||
here->VDMOSvon = *(SaveState + 43) ; |
|||
here->VDMOSmode = save_mode ; |
|||
|
|||
here->VDMOSsenPertFlag = OFF; |
|||
} |
|||
} |
|||
info->SENstatus = NORMAL; |
|||
#ifdef SENSDEBUG |
|||
printf("VDMOSsenacload end\n"); |
|||
#endif /* SENSDEBUG */ |
|||
return(OK); |
|||
} |
|||
|
|||
|
|||
@ -0,0 +1,238 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1985 Thomas L. Quarles |
|||
Modified: 2000 AlansFixes |
|||
**********/ |
|||
|
|||
/* load the VDMOS device structure with those pointers needed later |
|||
* for fast matrix loading |
|||
*/ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "ngspice/smpdefs.h" |
|||
#include "ngspice/cktdefs.h" |
|||
#include "vdmosdefs.h" |
|||
#include "ngspice/sperror.h" |
|||
#include "ngspice/suffix.h" |
|||
|
|||
int |
|||
VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, |
|||
int *states) |
|||
{ |
|||
VDMOSmodel *model = (VDMOSmodel *)inModel; |
|||
VDMOSinstance *here; |
|||
int error; |
|||
CKTnode *tmp; |
|||
|
|||
/* loop through all the VDMOS device models */ |
|||
for( ; model != NULL; model = VDMOSnextModel(model)) { |
|||
|
|||
if(!model->VDMOStypeGiven) { |
|||
model->VDMOStype = NMOS; |
|||
} |
|||
if(!model->VDMOSlatDiffGiven) { |
|||
model->VDMOSlatDiff = 0; |
|||
} |
|||
if(!model->VDMOSjctSatCurDensityGiven) { |
|||
model->VDMOSjctSatCurDensity = 0; |
|||
} |
|||
if(!model->VDMOSjctSatCurGiven) { |
|||
model->VDMOSjctSatCur = 1e-14; |
|||
} |
|||
if(!model->VDMOStransconductanceGiven) { |
|||
model->VDMOStransconductance = 2e-5; |
|||
} |
|||
if(!model->VDMOSgateSourceOverlapCapFactorGiven) { |
|||
model->VDMOSgateSourceOverlapCapFactor = 0; |
|||
} |
|||
if(!model->VDMOSgateDrainOverlapCapFactorGiven) { |
|||
model->VDMOSgateDrainOverlapCapFactor = 0; |
|||
} |
|||
if(!model->VDMOSgateBulkOverlapCapFactorGiven) { |
|||
model->VDMOSgateBulkOverlapCapFactor = 0; |
|||
} |
|||
if(!model->VDMOSvt0Given) { |
|||
model->VDMOSvt0 = 0; |
|||
} |
|||
if(!model->VDMOSbulkCapFactorGiven) { |
|||
model->VDMOSbulkCapFactor = 0; |
|||
} |
|||
if(!model->VDMOSsideWallCapFactorGiven) { |
|||
model->VDMOSsideWallCapFactor = 0; |
|||
} |
|||
if(!model->VDMOSbulkJctPotentialGiven) { |
|||
model->VDMOSbulkJctPotential = .8; |
|||
} |
|||
if(!model->VDMOSbulkJctBotGradingCoeffGiven) { |
|||
model->VDMOSbulkJctBotGradingCoeff = .5; |
|||
} |
|||
if(!model->VDMOSbulkJctSideGradingCoeffGiven) { |
|||
model->VDMOSbulkJctSideGradingCoeff = .5; |
|||
} |
|||
if(!model->VDMOSfwdCapDepCoeffGiven) { |
|||
model->VDMOSfwdCapDepCoeff = .5; |
|||
} |
|||
if(!model->VDMOSphiGiven) { |
|||
model->VDMOSphi = .6; |
|||
} |
|||
if(!model->VDMOSlambdaGiven) { |
|||
model->VDMOSlambda = 0; |
|||
} |
|||
if(!model->VDMOSgammaGiven) { |
|||
model->VDMOSgamma = 0; |
|||
} |
|||
if(!model->VDMOSfNcoefGiven) { |
|||
model->VDMOSfNcoef = 0; |
|||
} |
|||
if(!model->VDMOSfNexpGiven) { |
|||
model->VDMOSfNexp = 1; |
|||
} |
|||
|
|||
/* loop through all the instances of the model */ |
|||
for (here = VDMOSinstances(model); here != NULL ; |
|||
here=VDMOSnextInstance(here)) { |
|||
|
|||
/* allocate a chunk of the state vector */ |
|||
here->VDMOSstates = *states; |
|||
*states += VDMOSnumStates; |
|||
|
|||
if(ckt->CKTsenInfo && (ckt->CKTsenInfo->SENmode & TRANSEN) ){ |
|||
*states += VDMOSnumSenStates * (ckt->CKTsenInfo->SENparms); |
|||
} |
|||
|
|||
if(!here->VDMOSdrainPerimiterGiven) { |
|||
here->VDMOSdrainPerimiter = 0; |
|||
} |
|||
if(!here->VDMOSicVBSGiven) { |
|||
here->VDMOSicVBS = 0; |
|||
} |
|||
if(!here->VDMOSicVDSGiven) { |
|||
here->VDMOSicVDS = 0; |
|||
} |
|||
if(!here->VDMOSicVGSGiven) { |
|||
here->VDMOSicVGS = 0; |
|||
} |
|||
if(!here->VDMOSsourcePerimiterGiven) { |
|||
here->VDMOSsourcePerimiter = 0; |
|||
} |
|||
if(!here->VDMOSvdsatGiven) { |
|||
here->VDMOSvdsat = 0; |
|||
} |
|||
if(!here->VDMOSvonGiven) { |
|||
here->VDMOSvon = 0; |
|||
} |
|||
if(!here->VDMOSdrainSquaresGiven) { |
|||
here->VDMOSdrainSquares=1; |
|||
} |
|||
if(!here->VDMOSsourceSquaresGiven) { |
|||
here->VDMOSsourceSquares=1; |
|||
} |
|||
|
|||
if ((model->VDMOSdrainResistance != 0 |
|||
|| (model->VDMOSsheetResistance != 0 |
|||
&& here->VDMOSdrainSquares != 0) )) { |
|||
if (here->VDMOSdNodePrime == 0) { |
|||
error = CKTmkVolt(ckt,&tmp,here->VDMOSname,"drain"); |
|||
if(error) return(error); |
|||
here->VDMOSdNodePrime = tmp->number; |
|||
|
|||
if (ckt->CKTcopyNodesets) { |
|||
CKTnode *tmpNode; |
|||
IFuid tmpName; |
|||
|
|||
if (CKTinst2Node(ckt,here,1,&tmpNode,&tmpName)==OK) { |
|||
if (tmpNode->nsGiven) { |
|||
tmp->nodeset=tmpNode->nodeset; |
|||
tmp->nsGiven=tmpNode->nsGiven; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
} else { |
|||
here->VDMOSdNodePrime = here->VDMOSdNode; |
|||
} |
|||
|
|||
if((model->VDMOSsourceResistance != 0 || |
|||
(model->VDMOSsheetResistance != 0 && |
|||
here->VDMOSsourceSquares != 0) )) { |
|||
if (here->VDMOSsNodePrime == 0) { |
|||
error = CKTmkVolt(ckt,&tmp,here->VDMOSname,"source"); |
|||
if(error) return(error); |
|||
here->VDMOSsNodePrime = 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->VDMOSsNodePrime = here->VDMOSsNode; |
|||
} |
|||
|
|||
/* macro to make elements with built in test for out of memory */ |
|||
#define TSTALLOC(ptr,first,second) \ |
|||
do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\ |
|||
return(E_NOMEM);\ |
|||
} } while(0) |
|||
TSTALLOC(VDMOSDdPtr,VDMOSdNode,VDMOSdNode); |
|||
TSTALLOC(VDMOSGgPtr,VDMOSgNode,VDMOSgNode); |
|||
TSTALLOC(VDMOSSsPtr,VDMOSsNode,VDMOSsNode); |
|||
TSTALLOC(VDMOSBbPtr,VDMOSbNode,VDMOSbNode); |
|||
TSTALLOC(VDMOSDPdpPtr,VDMOSdNodePrime,VDMOSdNodePrime); |
|||
TSTALLOC(VDMOSSPspPtr,VDMOSsNodePrime,VDMOSsNodePrime); |
|||
TSTALLOC(VDMOSDdpPtr,VDMOSdNode,VDMOSdNodePrime); |
|||
TSTALLOC(VDMOSGbPtr,VDMOSgNode,VDMOSbNode); |
|||
TSTALLOC(VDMOSGdpPtr,VDMOSgNode,VDMOSdNodePrime); |
|||
TSTALLOC(VDMOSGspPtr,VDMOSgNode,VDMOSsNodePrime); |
|||
TSTALLOC(VDMOSSspPtr,VDMOSsNode,VDMOSsNodePrime); |
|||
TSTALLOC(VDMOSBdpPtr,VDMOSbNode,VDMOSdNodePrime); |
|||
TSTALLOC(VDMOSBspPtr,VDMOSbNode,VDMOSsNodePrime); |
|||
TSTALLOC(VDMOSDPspPtr,VDMOSdNodePrime,VDMOSsNodePrime); |
|||
TSTALLOC(VDMOSDPdPtr,VDMOSdNodePrime,VDMOSdNode); |
|||
TSTALLOC(VDMOSBgPtr,VDMOSbNode,VDMOSgNode); |
|||
TSTALLOC(VDMOSDPgPtr,VDMOSdNodePrime,VDMOSgNode); |
|||
TSTALLOC(VDMOSSPgPtr,VDMOSsNodePrime,VDMOSgNode); |
|||
TSTALLOC(VDMOSSPsPtr,VDMOSsNodePrime,VDMOSsNode); |
|||
TSTALLOC(VDMOSDPbPtr,VDMOSdNodePrime,VDMOSbNode); |
|||
TSTALLOC(VDMOSSPbPtr,VDMOSsNodePrime,VDMOSbNode); |
|||
TSTALLOC(VDMOSSPdpPtr,VDMOSsNodePrime,VDMOSdNodePrime); |
|||
|
|||
} |
|||
} |
|||
return(OK); |
|||
} |
|||
|
|||
int |
|||
VDMOSunsetup(GENmodel *inModel, CKTcircuit *ckt) |
|||
{ |
|||
VDMOSmodel *model; |
|||
VDMOSinstance *here; |
|||
|
|||
for (model = (VDMOSmodel *)inModel; model != NULL; |
|||
model = VDMOSnextModel(model)) |
|||
{ |
|||
for (here = VDMOSinstances(model); here != NULL; |
|||
here=VDMOSnextInstance(here)) |
|||
{ |
|||
if (here->VDMOSsNodePrime > 0 |
|||
&& here->VDMOSsNodePrime != here->VDMOSsNode) |
|||
CKTdltNNum(ckt, here->VDMOSsNodePrime); |
|||
here->VDMOSsNodePrime= 0; |
|||
|
|||
if (here->VDMOSdNodePrime > 0 |
|||
&& here->VDMOSdNodePrime != here->VDMOSdNode) |
|||
CKTdltNNum(ckt, here->VDMOSdNodePrime); |
|||
here->VDMOSdNodePrime= 0; |
|||
} |
|||
} |
|||
return OK; |
|||
} |
|||
@ -0,0 +1,623 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1985 Thomas L. Quarles |
|||
|
|||
This function is obsolete (was used by an old sensitivity analysis) |
|||
**********/ |
|||
|
|||
/* actually load the current sensitivity |
|||
* information into the array previously provided |
|||
*/ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "ngspice/smpdefs.h" |
|||
#include "ngspice/cktdefs.h" |
|||
#include "vdmosdefs.h" |
|||
#include "ngspice/sperror.h" |
|||
#include "ngspice/suffix.h" |
|||
|
|||
int |
|||
VDMOSsLoad(GENmodel *inModel, CKTcircuit *ckt) |
|||
{ |
|||
VDMOSmodel *model = (VDMOSmodel *)inModel; |
|||
VDMOSinstance *here; |
|||
double SaveState[44]; |
|||
int save_mode; |
|||
int i; |
|||
int iparmno; |
|||
int error; |
|||
int flag; |
|||
double A0; |
|||
double DELA; |
|||
double Apert; |
|||
double DELAinv; |
|||
double gspr0; |
|||
double gspr; |
|||
double gdpr0; |
|||
double gdpr; |
|||
double cdpr0; |
|||
double cspr0; |
|||
double cd0; |
|||
double cbd0; |
|||
double cbs0; |
|||
double cd; |
|||
double cbd; |
|||
double cbs; |
|||
double DcdprDp; |
|||
double DcsprDp; |
|||
double DcbDp; |
|||
double DcdDp; |
|||
double DcbsDp; |
|||
double DcbdDp; |
|||
double DcdprmDp; |
|||
double DcsprmDp; |
|||
double qgs0; |
|||
double qgd0; |
|||
double qgb0; |
|||
double qbd0; |
|||
double qbd; |
|||
double qbs0; |
|||
double qbs; |
|||
double DqgsDp; |
|||
double DqgdDp; |
|||
double DqgbDp; |
|||
double DqbdDp; |
|||
double DqbsDp; |
|||
double Osxpgs; |
|||
double Osxpgd; |
|||
double Osxpgb; |
|||
double Osxpbd; |
|||
double Osxpbs; |
|||
double tag0; |
|||
double tag1; |
|||
double arg; |
|||
double sarg; |
|||
double sargsw; |
|||
int offset; |
|||
double EffectiveLength; |
|||
SENstruct *info; |
|||
|
|||
#ifdef SENSDEBUG |
|||
printf("VDMOSsenload \n"); |
|||
printf("CKTtime = %.5e\n",ckt->CKTtime); |
|||
printf("CKTorder = %d\n",ckt->CKTorder); |
|||
#endif /* SENSDEBUG */ |
|||
|
|||
info = ckt->CKTsenInfo; |
|||
info->SENstatus = PERTURBATION; |
|||
|
|||
tag0 = ckt->CKTag[0]; |
|||
tag1 = ckt->CKTag[1]; |
|||
if(ckt->CKTorder == 1){ |
|||
tag1 = 0; |
|||
} |
|||
|
|||
/* loop through all the models */ |
|||
for( ; model != NULL; model = VDMOSnextModel(model)) { |
|||
|
|||
/* loop through all the instances of the model */ |
|||
for (here = VDMOSinstances(model); here != NULL ; |
|||
here=VDMOSnextInstance(here)) { |
|||
|
|||
#ifdef SENSDEBUG |
|||
printf("senload instance name %s\n",here->VDMOSname); |
|||
printf("gate = %d ,drain = %d, drainprm = %d\n", |
|||
here->VDMOSgNode,here->VDMOSdNode,here->VDMOSdNodePrime); |
|||
printf("source = %d , sourceprm = %d ,body = %d, senparmno = %d\n", |
|||
here->VDMOSsNode ,here->VDMOSsNodePrime, |
|||
here->VDMOSbNode,here->VDMOSsenParmNo); |
|||
#endif /* SENSDEBUG */ |
|||
|
|||
|
|||
/* save the unperturbed values in the state vector */ |
|||
for(i=0; i <= 16; i++){ |
|||
*(SaveState + i) = *(ckt->CKTstate0 + here->VDMOSstates + i); |
|||
} |
|||
|
|||
*(SaveState + 17) = here->VDMOSsourceConductance; |
|||
*(SaveState + 18) = here->VDMOSdrainConductance; |
|||
*(SaveState + 19) = here->VDMOScd; |
|||
*(SaveState + 20) = here->VDMOScbs; |
|||
*(SaveState + 21) = here->VDMOScbd; |
|||
*(SaveState + 22) = here->VDMOSgmbs; |
|||
*(SaveState + 23) = here->VDMOSgm; |
|||
*(SaveState + 24) = here->VDMOSgds; |
|||
*(SaveState + 25) = here->VDMOSgbd; |
|||
*(SaveState + 26) = here->VDMOSgbs; |
|||
*(SaveState + 27) = here->VDMOScapbd; |
|||
*(SaveState + 28) = here->VDMOScapbs; |
|||
*(SaveState + 29) = here->VDMOSCbd; |
|||
*(SaveState + 30) = here->VDMOSCbdsw; |
|||
*(SaveState + 31) = here->VDMOSCbs; |
|||
*(SaveState + 32) = here->VDMOSCbssw; |
|||
*(SaveState + 33) = here->VDMOSf2d; |
|||
*(SaveState + 34) = here->VDMOSf3d; |
|||
*(SaveState + 35) = here->VDMOSf4d; |
|||
*(SaveState + 36) = here->VDMOSf2s; |
|||
*(SaveState + 37) = here->VDMOSf3s; |
|||
*(SaveState + 38) = here->VDMOSf4s; |
|||
*(SaveState + 39) = here->VDMOScgs; |
|||
*(SaveState + 40) = here->VDMOScgd; |
|||
*(SaveState + 41) = here->VDMOScgb; |
|||
*(SaveState + 42) = here->VDMOSvdsat; |
|||
*(SaveState + 43) = here->VDMOSvon; |
|||
save_mode = here->VDMOSmode; |
|||
|
|||
|
|||
if(here->VDMOSsenParmNo == 0) goto next1; |
|||
|
|||
#ifdef SENSDEBUG |
|||
printf("without perturbation \n"); |
|||
printf("gbd =%.5e\n",here->VDMOSgbd); |
|||
printf("satCur =%.5e\n",here->VDMOStSatCur); |
|||
printf("satCurDens =%.5e\n",here->VDMOStSatCurDens); |
|||
printf("vbd =%.5e\n",*(ckt->CKTstate0 + here->VDMOSvbd)); |
|||
#endif /* SENSDEBUG */ |
|||
|
|||
cdpr0= here->VDMOScd; |
|||
cspr0= -(here->VDMOScd + here->VDMOScbd + here->VDMOScbs); |
|||
if((info->SENmode == TRANSEN) && |
|||
(ckt->CKTmode & MODEINITTRAN)){ |
|||
qgs0 = *(ckt->CKTstate1 + here->VDMOSqgs); |
|||
qgd0 = *(ckt->CKTstate1 + here->VDMOSqgd); |
|||
qgb0 = *(ckt->CKTstate1 + here->VDMOSqgb); |
|||
} |
|||
else{ |
|||
qgs0 = *(ckt->CKTstate0 + here->VDMOSqgs); |
|||
qgd0 = *(ckt->CKTstate0 + here->VDMOSqgd); |
|||
qgb0 = *(ckt->CKTstate0 + here->VDMOSqgb); |
|||
} |
|||
|
|||
here->VDMOSsenPertFlag = ON; |
|||
error = VDMOSload((GENmodel*)model,ckt); |
|||
if(error) return(error); |
|||
|
|||
cd0 = here->VDMOScd ; |
|||
cbd0 = here->VDMOScbd ; |
|||
cbs0 = here->VDMOScbs ; |
|||
gspr0= here->VDMOSsourceConductance ; |
|||
gdpr0= here->VDMOSdrainConductance ; |
|||
|
|||
qbs0 = *(ckt->CKTstate0 + here->VDMOSqbs); |
|||
qbd0 = *(ckt->CKTstate0 + here->VDMOSqbd); |
|||
|
|||
for( flag = 0 ; flag <= 1 ; flag++){ |
|||
if(here->VDMOSsens_l == 0) |
|||
if(flag == 0) goto next2; |
|||
if(here->VDMOSsens_w == 0) |
|||
if(flag == 1) goto next2; |
|||
if(flag == 0){ |
|||
A0 = here->VDMOSl; |
|||
DELA = info->SENpertfac * A0; |
|||
DELAinv = 1.0/DELA; |
|||
Apert = A0 + DELA; |
|||
here->VDMOSl = Apert; |
|||
} |
|||
else{ |
|||
A0 = here->VDMOSw; |
|||
DELA = info->SENpertfac * A0; |
|||
DELAinv = 1.0/DELA; |
|||
Apert = A0 + DELA; |
|||
here->VDMOSw = Apert; |
|||
here->VDMOSdrainArea *= (1 + info->SENpertfac); |
|||
here->VDMOSsourceArea *= (1 + info->SENpertfac); |
|||
here->VDMOSCbd *= (1 + info->SENpertfac); |
|||
here->VDMOSCbs *= (1 + info->SENpertfac); |
|||
if(here->VDMOSdrainPerimiter){ |
|||
here->VDMOSCbdsw += here->VDMOSCbdsw * |
|||
DELA/here->VDMOSdrainPerimiter; |
|||
} |
|||
if(here->VDMOSsourcePerimiter){ |
|||
here->VDMOSCbssw += here->VDMOSCbssw * |
|||
DELA/here->VDMOSsourcePerimiter; |
|||
} |
|||
if(*(ckt->CKTstate0 + here->VDMOSvbd) >= |
|||
here->VDMOStDepCap){ |
|||
arg = 1-model->VDMOSfwdCapDepCoeff; |
|||
sarg = exp( (-model->VDMOSbulkJctBotGradingCoeff) * |
|||
log(arg) ); |
|||
sargsw = exp( (-model->VDMOSbulkJctSideGradingCoeff) * |
|||
log(arg) ); |
|||
here->VDMOSf2d = here->VDMOSCbd* |
|||
(1-model->VDMOSfwdCapDepCoeff* |
|||
(1+model->VDMOSbulkJctBotGradingCoeff))* sarg/arg |
|||
+ here->VDMOSCbdsw*(1-model->VDMOSfwdCapDepCoeff* |
|||
(1+model->VDMOSbulkJctSideGradingCoeff))* |
|||
sargsw/arg; |
|||
here->VDMOSf3d = here->VDMOSCbd * |
|||
model->VDMOSbulkJctBotGradingCoeff * sarg/arg/ |
|||
here->VDMOStBulkPot |
|||
+ here->VDMOSCbdsw * |
|||
model->VDMOSbulkJctSideGradingCoeff * sargsw/arg/ |
|||
here->VDMOStBulkPot; |
|||
here->VDMOSf4d = here->VDMOSCbd* |
|||
here->VDMOStBulkPot*(1-arg*sarg)/ |
|||
(1-model->VDMOSbulkJctBotGradingCoeff) |
|||
+ here->VDMOSCbdsw*here->VDMOStBulkPot* |
|||
(1-arg*sargsw)/ |
|||
(1-model->VDMOSbulkJctSideGradingCoeff) |
|||
-here->VDMOSf3d/2* |
|||
(here->VDMOStDepCap*here->VDMOStDepCap) |
|||
-here->VDMOStDepCap * here->VDMOSf2d; |
|||
} |
|||
if(*(ckt->CKTstate0 + here->VDMOSvbs) >= |
|||
here->VDMOStDepCap){ |
|||
arg = 1-model->VDMOSfwdCapDepCoeff; |
|||
sarg = exp( (-model->VDMOSbulkJctBotGradingCoeff) * |
|||
log(arg) ); |
|||
sargsw = exp( (-model->VDMOSbulkJctSideGradingCoeff) * |
|||
log(arg) ); |
|||
here->VDMOSf2s = here->VDMOSCbs* |
|||
(1-model->VDMOSfwdCapDepCoeff* |
|||
(1+model->VDMOSbulkJctBotGradingCoeff))* sarg/arg |
|||
+ here->VDMOSCbssw*(1-model->VDMOSfwdCapDepCoeff* |
|||
(1+model->VDMOSbulkJctSideGradingCoeff))* |
|||
sargsw/arg; |
|||
here->VDMOSf3s = here->VDMOSCbs * |
|||
model->VDMOSbulkJctBotGradingCoeff * sarg/arg/ |
|||
here->VDMOStBulkPot |
|||
+ here->VDMOSCbssw * |
|||
model->VDMOSbulkJctSideGradingCoeff * sargsw/arg/ |
|||
here->VDMOStBulkPot; |
|||
here->VDMOSf4s = here->VDMOSCbs* |
|||
here->VDMOStBulkPot*(1-arg*sarg)/ |
|||
(1-model->VDMOSbulkJctBotGradingCoeff) |
|||
+ here->VDMOSCbssw*here->VDMOStBulkPot* |
|||
(1-arg*sargsw)/ |
|||
(1-model->VDMOSbulkJctSideGradingCoeff) |
|||
-here->VDMOSf3s/2* |
|||
(here->VDMOStDepCap*here->VDMOStDepCap) |
|||
-here->VDMOStDepCap * here->VDMOSf2s; |
|||
} |
|||
here->VDMOSdrainConductance *= Apert/A0; |
|||
here->VDMOSsourceConductance *= Apert/A0; |
|||
} |
|||
|
|||
|
|||
#ifdef SENSDEBUG |
|||
if(flag == 0) |
|||
printf("perturbation of l\n"); |
|||
if(flag == 1) |
|||
printf("perturbation of w\n"); |
|||
#endif /* SENSDEBUG */ |
|||
|
|||
error = VDMOSload((GENmodel*)model,ckt); |
|||
if(error) return(error); |
|||
|
|||
if(flag == 0){ |
|||
here->VDMOSl = A0; |
|||
} |
|||
else{ |
|||
here->VDMOSw = A0; |
|||
here->VDMOSdrainArea /= (1 + info->SENpertfac); |
|||
here->VDMOSsourceArea /= (1 + info->SENpertfac); |
|||
here->VDMOSdrainConductance *= A0/Apert; |
|||
here->VDMOSsourceConductance *= A0/Apert; |
|||
} |
|||
cd = here->VDMOScd ; |
|||
cbd = here->VDMOScbd ; |
|||
cbs = here->VDMOScbs ; |
|||
|
|||
gspr= here->VDMOSsourceConductance ; |
|||
gdpr= here->VDMOSdrainConductance ; |
|||
|
|||
DcdDp = (cd - cd0) * DELAinv; |
|||
DcbsDp = (cbs - cbs0) * DELAinv; |
|||
DcbdDp = (cbd - cbd0) * DELAinv; |
|||
DcbDp = ( DcbsDp + DcbdDp ); |
|||
|
|||
DcdprDp = 0; |
|||
DcsprDp = 0; |
|||
if(here->VDMOSdNode != here->VDMOSdNodePrime) |
|||
if(gdpr0) DcdprDp = cdpr0 * (gdpr - gdpr0)/gdpr0 * DELAinv; |
|||
if(here->VDMOSsNode != here->VDMOSsNodePrime) |
|||
if(gspr0) DcsprDp = cspr0 * (gspr - gspr0)/gspr0 * DELAinv; |
|||
|
|||
DcdprmDp = ( - DcdprDp + DcdDp); |
|||
DcsprmDp = ( - DcbsDp - DcdDp - DcbdDp - DcsprDp); |
|||
|
|||
if(flag == 0){ |
|||
EffectiveLength = here->VDMOSl |
|||
- 2*model->VDMOSlatDiff; |
|||
if(EffectiveLength == 0){ |
|||
DqgsDp = 0; |
|||
DqgdDp = 0; |
|||
DqgbDp = 0; |
|||
} |
|||
else{ |
|||
DqgsDp = model->VDMOStype * qgs0 / EffectiveLength; |
|||
DqgdDp = model->VDMOStype * qgd0 / EffectiveLength; |
|||
DqgbDp = model->VDMOStype * qgb0 / EffectiveLength; |
|||
} |
|||
} |
|||
else{ |
|||
DqgsDp = model->VDMOStype * qgs0 / here->VDMOSw; |
|||
DqgdDp = model->VDMOStype * qgd0 / here->VDMOSw; |
|||
DqgbDp = model->VDMOStype * qgb0 / here->VDMOSw; |
|||
} |
|||
|
|||
|
|||
qbd = *(ckt->CKTstate0 + here->VDMOSqbd); |
|||
qbs = *(ckt->CKTstate0 + here->VDMOSqbs); |
|||
|
|||
DqbsDp = model->VDMOStype * (qbs - qbs0)*DELAinv; |
|||
DqbdDp = model->VDMOStype * (qbd - qbd0)*DELAinv; |
|||
|
|||
if(flag == 0){ |
|||
*(here->VDMOSdphigs_dl) = DqgsDp; |
|||
*(here->VDMOSdphigd_dl) = DqgdDp; |
|||
*(here->VDMOSdphibs_dl) = DqbsDp; |
|||
*(here->VDMOSdphibd_dl) = DqbdDp; |
|||
*(here->VDMOSdphigb_dl) = DqgbDp; |
|||
} |
|||
else{ |
|||
*(here->VDMOSdphigs_dw) = DqgsDp; |
|||
*(here->VDMOSdphigd_dw) = DqgdDp; |
|||
*(here->VDMOSdphibs_dw) = DqbsDp; |
|||
*(here->VDMOSdphibd_dw) = DqbdDp; |
|||
*(here->VDMOSdphigb_dw) = DqgbDp; |
|||
} |
|||
|
|||
|
|||
#ifdef SENSDEBUG |
|||
printf("CKTag[0]=%.7e,CKTag[1]=%.7e,flag= %d\n", |
|||
ckt->CKTag[0],ckt->CKTag[1],flag); |
|||
printf("cd0 = %.7e ,cd = %.7e,\n",cd0,cd); |
|||
printf("cbs0 = %.7e ,cbs = %.7e,\n",cbs0,cbs); |
|||
printf("cbd0 = %.7e ,cbd = %.7e,\n",cbd0,cbd); |
|||
printf("DcdprmDp = %.7e,\n",DcdprmDp); |
|||
printf("DcsprmDp = %.7e,\n",DcsprmDp); |
|||
printf("DcdprDp = %.7e,\n",DcdprDp); |
|||
printf("DcsprDp = %.7e,\n",DcsprDp); |
|||
printf("qgs0 = %.7e \n",qgs0); |
|||
printf("qgd0 = %.7e \n",qgd0); |
|||
printf("qgb0 = %.7e \n",qgb0); |
|||
printf("qbs0 = %.7e ,qbs = %.7e,\n",qbs0,qbs); |
|||
printf("qbd0 = %.7e ,qbd = %.7e,\n",qbd0,qbd); |
|||
printf("DqgsDp = %.7e \n",DqgsDp); |
|||
printf("DqgdDp = %.7e \n",DqgdDp); |
|||
printf("DqgbDp = %.7e \n",DqgbDp); |
|||
printf("DqbsDp = %.7e \n",DqbsDp); |
|||
printf("DqbdDp = %.7e \n",DqbdDp); |
|||
printf("EffectiveLength = %.7e \n",EffectiveLength); |
|||
printf("tdepCap = %.7e \n",here->VDMOStDepCap); |
|||
printf("\n"); |
|||
#endif /* SENSDEBUG*/ |
|||
if((info->SENmode == TRANSEN) && |
|||
(ckt->CKTmode & MODEINITTRAN)) |
|||
goto next2; |
|||
|
|||
/* |
|||
* load RHS matrix |
|||
*/ |
|||
|
|||
if(flag == 0){ |
|||
*(info->SEN_RHS[here->VDMOSbNode] + here->VDMOSsenParmNo) -= |
|||
model->VDMOStype * DcbDp; |
|||
*(info->SEN_RHS[here->VDMOSdNode] + here->VDMOSsenParmNo) -= |
|||
model->VDMOStype * DcdprDp; |
|||
*(info->SEN_RHS[here->VDMOSdNodePrime] + |
|||
here->VDMOSsenParmNo) -= model->VDMOStype * DcdprmDp; |
|||
*(info->SEN_RHS[here->VDMOSsNode] + here->VDMOSsenParmNo) -= |
|||
model->VDMOStype * DcsprDp; |
|||
*(info->SEN_RHS[here->VDMOSsNodePrime] + |
|||
here->VDMOSsenParmNo) -= model->VDMOStype * DcsprmDp; |
|||
} |
|||
else{ |
|||
offset = here->VDMOSsens_l; |
|||
|
|||
*(info->SEN_RHS[here->VDMOSbNode] + here->VDMOSsenParmNo + |
|||
offset) -= model->VDMOStype * DcbDp; |
|||
*(info->SEN_RHS[here->VDMOSdNode] + here->VDMOSsenParmNo + |
|||
offset) -= model->VDMOStype * DcdprDp; |
|||
*(info->SEN_RHS[here->VDMOSdNodePrime] + here->VDMOSsenParmNo |
|||
+ offset) -= model->VDMOStype * DcdprmDp; |
|||
*(info->SEN_RHS[here->VDMOSsNode] + here->VDMOSsenParmNo + |
|||
offset) -= model->VDMOStype * DcsprDp; |
|||
*(info->SEN_RHS[here->VDMOSsNodePrime] + here->VDMOSsenParmNo |
|||
+ offset) -= model->VDMOStype * DcsprmDp; |
|||
} |
|||
#ifdef SENSDEBUG |
|||
printf("after loading\n"); |
|||
if(flag == 0){ |
|||
printf("DcbDp=%.7e\n", |
|||
*(info->SEN_RHS[here->VDMOSbNode] + |
|||
here->VDMOSsenParmNo)); |
|||
printf("DcdprDp=%.7e\n", |
|||
*(info->SEN_RHS[here->VDMOSdNode] + |
|||
here->VDMOSsenParmNo)); |
|||
printf("DcsprDp=%.7e\n", |
|||
*(info->SEN_RHS[here->VDMOSsNode] + |
|||
here->VDMOSsenParmNo)); |
|||
printf("DcdprmDp=%.7e\n", |
|||
*(info->SEN_RHS[here->VDMOSdNodePrime] + |
|||
here->VDMOSsenParmNo)); |
|||
printf("DcsprmDp=%.7e\n", |
|||
*(info->SEN_RHS[here->VDMOSsNodePrime] + |
|||
here->VDMOSsenParmNo)); |
|||
printf("\n"); |
|||
} |
|||
else{ |
|||
printf("DcbDp=%.7e\n", |
|||
*(info->SEN_RHS[here->VDMOSbNode] + |
|||
here->VDMOSsenParmNo + here->VDMOSsens_l)); |
|||
printf("DcdprDp=%.7e\n", |
|||
*(info->SEN_RHS[here->VDMOSdNode] + |
|||
here->VDMOSsenParmNo + here->VDMOSsens_l)); |
|||
printf("DcsprDp=%.7e\n", |
|||
*(info->SEN_RHS[here->VDMOSsNode] + |
|||
here->VDMOSsenParmNo + here->VDMOSsens_l)); |
|||
printf("DcdprmDp=%.7e\n", |
|||
*(info->SEN_RHS[here->VDMOSdNodePrime] + |
|||
here->VDMOSsenParmNo + here->VDMOSsens_l)); |
|||
printf("DcsprmDp=%.7e\n", |
|||
*(info->SEN_RHS[here->VDMOSsNodePrime] + |
|||
here->VDMOSsenParmNo + here->VDMOSsens_l)); |
|||
} |
|||
#endif /* SENSDEBUG*/ |
|||
next2: |
|||
; |
|||
} |
|||
next1: |
|||
if((info->SENmode == DCSEN) || |
|||
(ckt->CKTmode&MODETRANOP) ) goto restore; |
|||
if((info->SENmode == TRANSEN) && |
|||
(ckt->CKTmode & MODEINITTRAN)) goto restore; |
|||
for(iparmno = 1;iparmno<=info->SENparms;iparmno++){ |
|||
#ifdef SENSDEBUG |
|||
printf("after conductive currents\n"); |
|||
printf("iparmno = %d\n",iparmno); |
|||
printf("DcbDp=%.7e\n", |
|||
*(info->SEN_RHS[here->VDMOSbNode] + iparmno)); |
|||
printf("DcdprDp=%.7e\n", |
|||
*(info->SEN_RHS[here->VDMOSdNode] + iparmno)); |
|||
printf("DcdprmDp=%.7e\n", |
|||
*(info->SEN_RHS[here->VDMOSdNodePrime] + iparmno)); |
|||
printf("DcsprDp=%.7e\n", |
|||
*(info->SEN_RHS[here->VDMOSsNode] + iparmno)); |
|||
printf("DcsprmDp=%.7e\n", |
|||
*(info->SEN_RHS[here->VDMOSsNodePrime] + iparmno)); |
|||
printf("\n"); |
|||
#endif /* SENSDEBUG */ |
|||
Osxpgs = tag0 * *(ckt->CKTstate1 + here->VDMOSsensxpgs + |
|||
10*(iparmno - 1)) |
|||
+ tag1 * *(ckt->CKTstate1 + here->VDMOSsensxpgs + |
|||
10*(iparmno - 1) + 1); |
|||
|
|||
Osxpgd = tag0 * *(ckt->CKTstate1 + here->VDMOSsensxpgd + |
|||
10*(iparmno - 1)) |
|||
+ tag1 * *(ckt->CKTstate1 + here->VDMOSsensxpgd + |
|||
10*(iparmno - 1) + 1); |
|||
|
|||
Osxpbs = tag0 * *(ckt->CKTstate1 + here->VDMOSsensxpbs + |
|||
10*(iparmno - 1)) |
|||
+ tag1 * *(ckt->CKTstate1 + here->VDMOSsensxpbs + |
|||
10*(iparmno - 1) + 1); |
|||
|
|||
Osxpbd =tag0 * *(ckt->CKTstate1 + here->VDMOSsensxpbd + |
|||
10*(iparmno - 1)) |
|||
+ tag1 * *(ckt->CKTstate1 + here->VDMOSsensxpbd + |
|||
10*(iparmno - 1) + 1); |
|||
Osxpgb = tag0 * *(ckt->CKTstate1 + here->VDMOSsensxpgb + |
|||
10*(iparmno - 1)) |
|||
+ tag1 * *(ckt->CKTstate1 + here->VDMOSsensxpgb + |
|||
10*(iparmno - 1) + 1); |
|||
|
|||
#ifdef SENSDEBUG |
|||
printf("iparmno=%d\n",iparmno); |
|||
printf("sxpgs=%.7e,sdgs=%.7e\n", |
|||
*(ckt->CKTstate1 + here->VDMOSsensxpgs + |
|||
10*(iparmno - 1)), *(ckt->CKTstate1 + |
|||
here->VDMOSsensxpgs + 10*(iparmno - 1) + 1)); |
|||
printf("sxpgd=%.7e,sdgd=%.7e\n", |
|||
*(ckt->CKTstate1 + here->VDMOSsensxpgd + |
|||
10*(iparmno - 1)), *(ckt->CKTstate1 + |
|||
here->VDMOSsensxpgd + 10*(iparmno - 1) + 1)); |
|||
printf("sxpbs=%.7e,sdbs=%.7e\n", |
|||
*(ckt->CKTstate1 + here->VDMOSsensxpbs + |
|||
10*(iparmno - 1)), *(ckt->CKTstate1 + |
|||
here->VDMOSsensxpbs + 10*(iparmno - 1) + 1)); |
|||
printf("sxpbd=%.7e,sdbd=%.7e\n", |
|||
*(ckt->CKTstate1 + here->VDMOSsensxpbd + |
|||
10*(iparmno - 1)), *(ckt->CKTstate1 + |
|||
here->VDMOSsensxpbd + 10*(iparmno - 1) + 1)); |
|||
printf("sxpgb=%.7e,sdgb=%.7e\n", |
|||
*(ckt->CKTstate1 + here->VDMOSsensxpgb + |
|||
10*(iparmno - 1)), *(ckt->CKTstate1 + |
|||
here->VDMOSsensxpgb + 10*(iparmno - 1) + 1)); |
|||
printf("before loading DqDp\n"); |
|||
printf("Osxpgs=%.7e,Osxpgd=%.7e\n",Osxpgs,Osxpgd); |
|||
printf("Osxpbs=%.7e,Osxpbd=%.7e,Osxpgb=%.7e\n", |
|||
Osxpbs,Osxpbd,Osxpgb); |
|||
printf("\n"); |
|||
#endif /* SENSDEBUG */ |
|||
if(here->VDMOSsens_l && (iparmno == here->VDMOSsenParmNo)){ |
|||
Osxpgs -= tag0 * *(here->VDMOSdphigs_dl); |
|||
Osxpgd -= tag0 * *(here->VDMOSdphigd_dl); |
|||
Osxpbs -= tag0 * *(here->VDMOSdphibs_dl); |
|||
Osxpbd -= tag0 * *(here->VDMOSdphibd_dl); |
|||
Osxpgb -= tag0 * *(here->VDMOSdphigb_dl); |
|||
} |
|||
if(here->VDMOSsens_w && |
|||
(iparmno == (here->VDMOSsenParmNo + here->VDMOSsens_l))){ |
|||
Osxpgs -= tag0 * *(here->VDMOSdphigs_dw); |
|||
Osxpgd -= tag0 * *(here->VDMOSdphigd_dw); |
|||
Osxpbs -= tag0 * *(here->VDMOSdphibs_dw); |
|||
Osxpbd -= tag0 * *(here->VDMOSdphibd_dw); |
|||
Osxpgb -= tag0 * *(here->VDMOSdphigb_dw); |
|||
} |
|||
#ifdef SENSDEBUG |
|||
printf("after loading DqDp\n"); |
|||
printf("DqgsDp=%.7e",DqgsDp); |
|||
printf("Osxpgs=%.7e,Osxpgd=%.7e\n",Osxpgs,Osxpgd); |
|||
printf("Osxpbs=%.7e,Osxpbd=%.7e,Osxpgb=%.7e\n", |
|||
Osxpbs,Osxpbd,Osxpgb); |
|||
#endif /* SENSDEBUG */ |
|||
|
|||
*(info->SEN_RHS[here->VDMOSbNode] + iparmno) += |
|||
Osxpbs + Osxpbd -Osxpgb; |
|||
*(info->SEN_RHS[here->VDMOSgNode] + iparmno) += |
|||
Osxpgs + Osxpgd + Osxpgb; |
|||
|
|||
*(info->SEN_RHS[here->VDMOSdNodePrime] + iparmno) -= |
|||
Osxpgd + Osxpbd ; |
|||
*(info->SEN_RHS[here->VDMOSsNodePrime] + iparmno) -= |
|||
Osxpgs + Osxpbs; |
|||
#ifdef SENSDEBUG |
|||
printf("after capacitive currents\n"); |
|||
printf("DcbDp=%.7e\n", |
|||
*(info->SEN_RHS[here->VDMOSbNode] + iparmno)); |
|||
printf("DcdprDp=%.7e\n", |
|||
*(info->SEN_RHS[here->VDMOSdNode] + iparmno)); |
|||
printf("DcdprmDp=%.7e\n", |
|||
*(info->SEN_RHS[here->VDMOSdNodePrime] + iparmno)); |
|||
printf("DcsprDp=%.7e\n", |
|||
*(info->SEN_RHS[here->VDMOSsNode] + iparmno)); |
|||
printf("DcsprmDp=%.7e\n", |
|||
*(info->SEN_RHS[here->VDMOSsNodePrime] + iparmno)); |
|||
#endif /* SENSDEBUG */ |
|||
|
|||
} |
|||
restore: /* put the unperturbed values back into the state vector */ |
|||
for(i=0; i <= 16; i++) |
|||
*(ckt->CKTstate0 + here->VDMOSstates + i) = *(SaveState + i); |
|||
here->VDMOSsourceConductance = *(SaveState + 17) ; |
|||
here->VDMOSdrainConductance = *(SaveState + 18) ; |
|||
here->VDMOScd = *(SaveState + 19) ; |
|||
here->VDMOScbs = *(SaveState + 20) ; |
|||
here->VDMOScbd = *(SaveState + 21) ; |
|||
here->VDMOSgmbs = *(SaveState + 22) ; |
|||
here->VDMOSgm = *(SaveState + 23) ; |
|||
here->VDMOSgds = *(SaveState + 24) ; |
|||
here->VDMOSgbd = *(SaveState + 25) ; |
|||
here->VDMOSgbs = *(SaveState + 26) ; |
|||
here->VDMOScapbd = *(SaveState + 27) ; |
|||
here->VDMOScapbs = *(SaveState + 28) ; |
|||
here->VDMOSCbd = *(SaveState + 29) ; |
|||
here->VDMOSCbdsw = *(SaveState + 30) ; |
|||
here->VDMOSCbs = *(SaveState + 31) ; |
|||
here->VDMOSCbssw = *(SaveState + 32) ; |
|||
here->VDMOSf2d = *(SaveState + 33) ; |
|||
here->VDMOSf3d = *(SaveState + 34) ; |
|||
here->VDMOSf4d = *(SaveState + 35) ; |
|||
here->VDMOSf2s = *(SaveState + 36) ; |
|||
here->VDMOSf3s = *(SaveState + 37) ; |
|||
here->VDMOSf4s = *(SaveState + 38) ; |
|||
here->VDMOScgs = *(SaveState + 39) ; |
|||
here->VDMOScgd = *(SaveState + 40) ; |
|||
here->VDMOScgb = *(SaveState + 41) ; |
|||
here->VDMOSvdsat = *(SaveState + 42) ; |
|||
here->VDMOSvon = *(SaveState + 43) ; |
|||
here->VDMOSmode = save_mode ; |
|||
|
|||
here->VDMOSsenPertFlag = OFF; |
|||
|
|||
} |
|||
} |
|||
info->SENstatus = NORMAL; |
|||
#ifdef SENSDEBUG |
|||
printf("VDMOSsenload end\n"); |
|||
#endif /* SENSDEBUG */ |
|||
return(OK); |
|||
} |
|||
|
|||
@ -0,0 +1,68 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1985 Thomas L. Quarles |
|||
Modified: 2000 AlansFixes |
|||
|
|||
This function is obsolete (was used by an old sensitivity analysis) |
|||
**********/ |
|||
|
|||
/* Pretty print the sensitivity info for all |
|||
* the VDMOS devices in the circuit. |
|||
*/ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "ngspice/smpdefs.h" |
|||
#include "ngspice/cktdefs.h" |
|||
#include "vdmosdefs.h" |
|||
#include "ngspice/sperror.h" |
|||
#include "ngspice/suffix.h" |
|||
|
|||
void |
|||
VDMOSsPrint(GENmodel *inModel, CKTcircuit *ckt) |
|||
/* Pretty print the sensitivity info for all the VDMOS |
|||
* devices in the circuit. |
|||
*/ |
|||
{ |
|||
VDMOSmodel *model = (VDMOSmodel *)inModel; |
|||
VDMOSinstance *here; |
|||
|
|||
printf("LEVEL 1 MOSFETS-----------------\n"); |
|||
/* loop through all the VDMOS models */ |
|||
for( ; model != NULL; model = VDMOSnextModel(model)) { |
|||
|
|||
printf("Model name:%s\n",model->VDMOSmodName); |
|||
|
|||
/* loop through all the instances of the model */ |
|||
for (here = VDMOSinstances(model); here != NULL ; |
|||
here=VDMOSnextInstance(here)) { |
|||
|
|||
printf(" Instance name:%s\n",here->VDMOSname); |
|||
printf(" Drain, Gate , Source nodes: %s, %s ,%s\n", |
|||
CKTnodName(ckt,here->VDMOSdNode),CKTnodName(ckt,here->VDMOSgNode), |
|||
CKTnodName(ckt,here->VDMOSsNode)); |
|||
|
|||
printf(" Multiplier: %g ",here->VDMOSm); |
|||
printf(here->VDMOSmGiven ? "(specified)\n" : "(default)\n"); |
|||
|
|||
printf(" Length: %g ",here->VDMOSl); |
|||
printf(here->VDMOSlGiven ? "(specified)\n" : "(default)\n"); |
|||
printf(" Width: %g ",here->VDMOSw); |
|||
printf(here->VDMOSwGiven ? "(specified)\n" : "(default)\n"); |
|||
if(here->VDMOSsens_l == 1){ |
|||
printf(" VDMOSsenParmNo:l = %d ",here->VDMOSsenParmNo); |
|||
} |
|||
else{ |
|||
printf(" VDMOSsenParmNo:l = 0 "); |
|||
} |
|||
if(here->VDMOSsens_w == 1){ |
|||
printf(" w = %d \n",here->VDMOSsenParmNo + here->VDMOSsens_l); |
|||
} |
|||
else{ |
|||
printf(" w = 0 \n"); |
|||
} |
|||
|
|||
|
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,50 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1985 Thomas L. Quarles |
|||
|
|||
This function is obsolete (was used by an old sensitivity analysis) |
|||
**********/ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "ngspice/smpdefs.h" |
|||
#include "ngspice/cktdefs.h" |
|||
#include "vdmosdefs.h" |
|||
#include "ngspice/sperror.h" |
|||
#include "ngspice/suffix.h" |
|||
|
|||
int |
|||
VDMOSsSetup(SENstruct *info, GENmodel *inModel) |
|||
/* loop through all the devices and |
|||
* allocate parameter #s to design parameters |
|||
*/ |
|||
{ |
|||
VDMOSmodel *model = (VDMOSmodel *)inModel; |
|||
VDMOSinstance *here; |
|||
|
|||
/* loop through all the models */ |
|||
for( ; model != NULL; model = VDMOSnextModel(model)) { |
|||
|
|||
/* loop through all the instances of the model */ |
|||
for (here = VDMOSinstances(model); here != NULL ; |
|||
here=VDMOSnextInstance(here)) { |
|||
|
|||
if(here->VDMOSsenParmNo){ |
|||
if((here->VDMOSsens_l)&&(here->VDMOSsens_w)){ |
|||
here->VDMOSsenParmNo = ++(info->SENparms); |
|||
++(info->SENparms);/* MOS has two design parameters */ |
|||
} |
|||
else{ |
|||
here->VDMOSsenParmNo = ++(info->SENparms); |
|||
} |
|||
} |
|||
if((here->VDMOSsens = TMALLOC(double, 70)) == NULL) { |
|||
return(E_NOMEM); |
|||
} |
|||
here->VDMOSsenPertFlag = OFF; |
|||
|
|||
} |
|||
} |
|||
return(OK); |
|||
} |
|||
|
|||
|
|||
@ -0,0 +1,183 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1985 Thomas L. Quarles |
|||
|
|||
This function is obsolete (was used by an old sensitivity analysis) |
|||
**********/ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "ngspice/smpdefs.h" |
|||
#include "ngspice/cktdefs.h" |
|||
#include "vdmosdefs.h" |
|||
#include "ngspice/sperror.h" |
|||
#include "ngspice/suffix.h" |
|||
|
|||
/* update the charge sensitivities and their derivatives */ |
|||
|
|||
int |
|||
VDMOSsUpdate(GENmodel *inModel, CKTcircuit *ckt) |
|||
{ |
|||
VDMOSmodel *model = (VDMOSmodel *)inModel; |
|||
VDMOSinstance *here; |
|||
int iparmno; |
|||
double sb; |
|||
double sg; |
|||
double sdprm; |
|||
double ssprm; |
|||
double sxpgs; |
|||
double sxpgd; |
|||
double sxpbs; |
|||
double sxpbd; |
|||
double sxpgb; |
|||
double dummy1; |
|||
double dummy2; |
|||
SENstruct *info; |
|||
|
|||
|
|||
if(ckt->CKTtime == 0) return(OK); |
|||
info = ckt->CKTsenInfo; |
|||
|
|||
#ifdef SENSDEBUG |
|||
printf("VDMOSsenupdate\n"); |
|||
printf("CKTtime = %.5e\n",ckt->CKTtime); |
|||
#endif /* SENSDEBUG */ |
|||
|
|||
sxpgs = 0; |
|||
sxpgd = 0; |
|||
sxpbs = 0; |
|||
sxpbd = 0; |
|||
sxpgb = 0; |
|||
dummy1 = 0; |
|||
dummy2 = 0; |
|||
|
|||
/* loop through all the VDMOS models */ |
|||
for( ; model != NULL; model = VDMOSnextModel(model)) { |
|||
|
|||
/* loop through all the instances of the model */ |
|||
for (here = VDMOSinstances(model); here != NULL ; |
|||
here=VDMOSnextInstance(here)) { |
|||
|
|||
#ifdef SENSDEBUG |
|||
printf("senupdate instance name %s\n",here->VDMOSname); |
|||
printf("before loading\n"); |
|||
printf("CKTag[0] = %.2e,CKTag[1] = %.2e\n", |
|||
ckt->CKTag[0],ckt->CKTag[1]); |
|||
printf("capgs = %.7e\n",here->VDMOScgs); |
|||
printf("capgd = %.7e\n",here->VDMOScgd); |
|||
printf("capgb = %.7e\n",here->VDMOScgb); |
|||
printf("capbs = %.7e\n",here->VDMOScapbs); |
|||
printf("capbd = %.7e\n",here->VDMOScapbd); |
|||
#endif /* SENSDEBUG */ |
|||
|
|||
for(iparmno = 1;iparmno<=info->SENparms;iparmno++){ |
|||
|
|||
sb = *(info->SEN_Sap[here->VDMOSbNode] + iparmno); |
|||
sg = *(info->SEN_Sap[here->VDMOSgNode] + iparmno); |
|||
ssprm = *(info->SEN_Sap[here->VDMOSsNodePrime] + iparmno); |
|||
sdprm = *(info->SEN_Sap[here->VDMOSdNodePrime] + iparmno); |
|||
#ifdef SENSDEBUG |
|||
printf("iparmno = %d\n",iparmno); |
|||
printf("sb = %.7e,sg = %.7e\n",sb,sg); |
|||
printf("ssprm = %.7e,sdprm = %.7e\n",ssprm,sdprm); |
|||
#endif /* SENSDEBUG */ |
|||
|
|||
sxpgs = (sg - ssprm) * here->VDMOScgs ; |
|||
sxpgd = (sg - sdprm) * here->VDMOScgd ; |
|||
sxpgb = (sg - sb) * here->VDMOScgb ; |
|||
sxpbs = (sb - ssprm) * here->VDMOScapbs ; |
|||
sxpbd = (sb - sdprm) * here->VDMOScapbd ; |
|||
|
|||
if(here->VDMOSsens_l && (iparmno == here->VDMOSsenParmNo)){ |
|||
sxpgs += *(here->VDMOSdphigs_dl); |
|||
sxpgd += *(here->VDMOSdphigd_dl); |
|||
sxpbs += *(here->VDMOSdphibs_dl); |
|||
sxpbd += *(here->VDMOSdphibd_dl); |
|||
sxpgb += *(here->VDMOSdphigb_dl); |
|||
} |
|||
if(here->VDMOSsens_w && |
|||
(iparmno == (here->VDMOSsenParmNo+here->VDMOSsens_l))){ |
|||
sxpgs += *(here->VDMOSdphigs_dw); |
|||
sxpgd += *(here->VDMOSdphigd_dw); |
|||
sxpbs += *(here->VDMOSdphibs_dw); |
|||
sxpbd += *(here->VDMOSdphibd_dw); |
|||
sxpgb += *(here->VDMOSdphigb_dw); |
|||
} |
|||
if(ckt->CKTmode & MODEINITTRAN) { |
|||
*(ckt->CKTstate1 + here->VDMOSsensxpgs + |
|||
10 * (iparmno - 1)) = sxpgs; |
|||
*(ckt->CKTstate1 + here->VDMOSsensxpgd + |
|||
10 * (iparmno - 1)) = sxpgd; |
|||
*(ckt->CKTstate1 + here->VDMOSsensxpbs + |
|||
10 * (iparmno - 1)) = sxpbs; |
|||
*(ckt->CKTstate1 + here->VDMOSsensxpbd + |
|||
10 * (iparmno - 1)) = sxpbd; |
|||
*(ckt->CKTstate1 + here->VDMOSsensxpgb + |
|||
10 * (iparmno - 1)) = sxpgb; |
|||
*(ckt->CKTstate1 + here->VDMOSsensxpgs + |
|||
10 * (iparmno - 1) + 1) = 0; |
|||
*(ckt->CKTstate1 + here->VDMOSsensxpgd + |
|||
10 * (iparmno - 1) + 1) = 0; |
|||
*(ckt->CKTstate1 + here->VDMOSsensxpbs + |
|||
10 * (iparmno - 1) + 1) = 0; |
|||
*(ckt->CKTstate1 + here->VDMOSsensxpbd + |
|||
10 * (iparmno - 1) + 1) = 0; |
|||
*(ckt->CKTstate1 + here->VDMOSsensxpgb + |
|||
10 * (iparmno - 1) + 1) = 0; |
|||
goto next; |
|||
} |
|||
|
|||
*(ckt->CKTstate0 + here->VDMOSsensxpgs + |
|||
10 * (iparmno - 1)) = sxpgs; |
|||
*(ckt->CKTstate0 + here->VDMOSsensxpgd + |
|||
10 * (iparmno - 1)) = sxpgd; |
|||
*(ckt->CKTstate0 + here->VDMOSsensxpbs + |
|||
10 * (iparmno - 1)) = sxpbs; |
|||
*(ckt->CKTstate0 + here->VDMOSsensxpbd + |
|||
10 * (iparmno - 1)) = sxpbd; |
|||
*(ckt->CKTstate0 + here->VDMOSsensxpgb + |
|||
10 * (iparmno - 1)) = sxpgb; |
|||
|
|||
NIintegrate(ckt,&dummy1,&dummy2,here->VDMOScgs, |
|||
here->VDMOSsensxpgs + 10*(iparmno -1)); |
|||
|
|||
NIintegrate(ckt,&dummy1,&dummy2,here->VDMOScgd, |
|||
here->VDMOSsensxpgd + 10*(iparmno -1)); |
|||
|
|||
NIintegrate(ckt,&dummy1,&dummy2,here->VDMOScgb, |
|||
here->VDMOSsensxpgb + 10*(iparmno -1)); |
|||
|
|||
NIintegrate(ckt,&dummy1,&dummy2,here->VDMOScapbs, |
|||
here->VDMOSsensxpbs + 10*(iparmno -1)); |
|||
|
|||
NIintegrate(ckt,&dummy1,&dummy2,here->VDMOScapbd, |
|||
here->VDMOSsensxpbd + 10*(iparmno -1)); |
|||
next: |
|||
; |
|||
#ifdef SENSDEBUG |
|||
printf("after loading\n"); |
|||
printf("sxpgs = %.7e,sdotxpgs = %.7e\n", |
|||
sxpgs,*(ckt->CKTstate0 + here->VDMOSsensxpgs + |
|||
10 * (iparmno - 1) + 1)); |
|||
printf("sxpgd = %.7e,sdotxpgd = %.7e\n", |
|||
sxpgd,*(ckt->CKTstate0 + here->VDMOSsensxpgd + |
|||
10 * (iparmno - 1) + 1)); |
|||
printf("sxpgb = %.7e,sdotxpgb = %.7e\n", |
|||
sxpgb,*(ckt->CKTstate0 + here->VDMOSsensxpgb + |
|||
10 * (iparmno - 1) + 1)); |
|||
printf("sxpbs = %.7e,sdotxpbs = %.7e\n", |
|||
sxpbs,*(ckt->CKTstate0 + here->VDMOSsensxpbs + |
|||
10 * (iparmno - 1) + 1)); |
|||
printf("sxpbd = %.7e,sdotxpbd = %.7e\n", |
|||
sxpbd,*(ckt->CKTstate0 + here->VDMOSsensxpbd + |
|||
10 * (iparmno - 1) + 1)); |
|||
#endif /* SENSDEBUG */ |
|||
} |
|||
} |
|||
} |
|||
#ifdef SENSDEBUG |
|||
printf("VDMOSsenupdate end\n"); |
|||
#endif /* SENSDEBUG */ |
|||
return(OK); |
|||
|
|||
} |
|||
|
|||
@ -0,0 +1,332 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1985 Thomas L. Quarles |
|||
Modified: 2000 AlansFixes |
|||
**********/ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "ngspice/cktdefs.h" |
|||
#include "vdmosdefs.h" |
|||
#include "ngspice/const.h" |
|||
#include "ngspice/sperror.h" |
|||
#include "ngspice/suffix.h" |
|||
|
|||
int |
|||
VDMOStemp(GENmodel *inModel, CKTcircuit *ckt) |
|||
{ |
|||
VDMOSmodel *model = (VDMOSmodel *)inModel; |
|||
VDMOSinstance *here; |
|||
|
|||
double egfet,egfet1; |
|||
double fact1,fact2; |
|||
double kt,kt1; |
|||
double arg1; |
|||
double ratio,ratio4; |
|||
double phio; |
|||
double pbo; |
|||
double gmanew,gmaold; |
|||
double capfact; |
|||
double pbfact1,pbfact; |
|||
double vt,vtnom; |
|||
double wkfngs; |
|||
double wkfng; |
|||
double fermig; |
|||
double fermis; |
|||
double vfb; |
|||
/* loop through all the resistor models */ |
|||
for( ; model != NULL; model = VDMOSnextModel(model)) { |
|||
|
|||
|
|||
/* perform model defaulting */ |
|||
if(!model->VDMOStnomGiven) { |
|||
model->VDMOStnom = ckt->CKTnomTemp; |
|||
} |
|||
|
|||
fact1 = model->VDMOStnom/REFTEMP; |
|||
vtnom = model->VDMOStnom*CONSTKoverQ; |
|||
kt1 = CONSTboltz * model->VDMOStnom; |
|||
egfet1 = 1.16-(7.02e-4*model->VDMOStnom*model->VDMOStnom)/ |
|||
(model->VDMOStnom+1108); |
|||
arg1 = -egfet1/(kt1+kt1)+1.1150877/(CONSTboltz*(REFTEMP+REFTEMP)); |
|||
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); |
|||
} |
|||
|
|||
if(!model->VDMOSoxideThicknessGiven || model->VDMOSoxideThickness == 0) { |
|||
model->VDMOSoxideCapFactor = 0; |
|||
} else { |
|||
model->VDMOSoxideCapFactor = 3.9 * 8.854214871e-12/ |
|||
model->VDMOSoxideThickness; |
|||
if(!model->VDMOStransconductanceGiven) { |
|||
if(!model->VDMOSsurfaceMobilityGiven) { |
|||
model->VDMOSsurfaceMobility=600; |
|||
} |
|||
model->VDMOStransconductance = model->VDMOSsurfaceMobility * |
|||
model->VDMOSoxideCapFactor * 1e-4 /*(m**2/cm**2)*/; |
|||
} |
|||
if(model->VDMOSsubstrateDopingGiven) { |
|||
if(model->VDMOSsubstrateDoping*1e6 /*(cm**3/m**3)*/ >1.45e16) { |
|||
if(!model->VDMOSphiGiven) { |
|||
model->VDMOSphi = 2*vtnom* |
|||
log(model->VDMOSsubstrateDoping* |
|||
1e6/*(cm**3/m**3)*//1.45e16); |
|||
model->VDMOSphi = MAX(.1,model->VDMOSphi); |
|||
} |
|||
fermis = model->VDMOStype * .5 * model->VDMOSphi; |
|||
wkfng = 3.2; |
|||
if(!model->VDMOSgateTypeGiven) model->VDMOSgateType=1; |
|||
if(model->VDMOSgateType != 0) { |
|||
fermig = model->VDMOStype *model->VDMOSgateType*.5*egfet1; |
|||
wkfng = 3.25 + .5 * egfet1 - fermig; |
|||
} |
|||
wkfngs = wkfng - (3.25 + .5 * egfet1 +fermis); |
|||
if(!model->VDMOSgammaGiven) { |
|||
model->VDMOSgamma = sqrt(2 * 11.70 * 8.854214871e-12 * |
|||
CHARGE * model->VDMOSsubstrateDoping* |
|||
1e6/*(cm**3/m**3)*/)/ |
|||
model->VDMOSoxideCapFactor; |
|||
} |
|||
if(!model->VDMOSvt0Given) { |
|||
if(!model->VDMOSsurfaceStateDensityGiven) |
|||
model->VDMOSsurfaceStateDensity=0; |
|||
vfb = wkfngs - |
|||
model->VDMOSsurfaceStateDensity * |
|||
1e4 /*(cm**2/m**2)*/ * |
|||
CHARGE/model->VDMOSoxideCapFactor; |
|||
model->VDMOSvt0 = vfb + model->VDMOStype * |
|||
(model->VDMOSgamma * sqrt(model->VDMOSphi)+ |
|||
model->VDMOSphi); |
|||
} |
|||
} else { |
|||
model->VDMOSsubstrateDoping = 0; |
|||
SPfrontEnd->IFerrorf (ERR_FATAL, |
|||
"%s: Nsub < Ni", model->VDMOSmodName); |
|||
return(E_BADPARM); |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
/* loop through all instances of the model */ |
|||
for(here = VDMOSinstances(model); here!= NULL; |
|||
here = VDMOSnextInstance(here)) { |
|||
double czbd; /* zero voltage bulk-drain capacitance */ |
|||
double czbdsw; /* zero voltage bulk-drain sidewall capacitance */ |
|||
double czbs; /* zero voltage bulk-source capacitance */ |
|||
double czbssw; /* zero voltage bulk-source sidewall capacitance */ |
|||
double arg; /* 1 - fc */ |
|||
double sarg; /* (1-fc) ^^ (-mj) */ |
|||
double sargsw; /* (1-fc) ^^ (-mjsw) */ |
|||
|
|||
/* perform the parameter defaulting */ |
|||
|
|||
if(!here->VDMOSdtempGiven) { |
|||
here->VDMOSdtemp = 0.0; |
|||
} |
|||
if(!here->VDMOStempGiven) { |
|||
here->VDMOStemp = ckt->CKTtemp + here->VDMOSdtemp; |
|||
} |
|||
vt = here->VDMOStemp * CONSTKoverQ; |
|||
ratio = here->VDMOStemp/model->VDMOStnom; |
|||
fact2 = here->VDMOStemp/REFTEMP; |
|||
kt = here->VDMOStemp * CONSTboltz; |
|||
egfet = 1.16-(7.02e-4*here->VDMOStemp*here->VDMOStemp)/ |
|||
(here->VDMOStemp+1108); |
|||
arg = -egfet/(kt+kt)+1.1150877/(CONSTboltz*(REFTEMP+REFTEMP)); |
|||
pbfact = -2*vt *(1.5*log(fact2)+CHARGE*arg); |
|||
|
|||
if(!here->VDMOSdrainAreaGiven) { |
|||
here->VDMOSdrainArea = ckt->CKTdefaultMosAD; |
|||
} |
|||
if(!here->VDMOSmGiven) { |
|||
here->VDMOSm = ckt->CKTdefaultMosM; |
|||
} |
|||
if(!here->VDMOSlGiven) { |
|||
here->VDMOSl = ckt->CKTdefaultMosL; |
|||
} |
|||
if(!here->VDMOSsourceAreaGiven) { |
|||
here->VDMOSsourceArea = ckt->CKTdefaultMosAS; |
|||
} |
|||
if(!here->VDMOSwGiven) { |
|||
here->VDMOSw = ckt->CKTdefaultMosW; |
|||
} |
|||
|
|||
if(here->VDMOSl - 2 * model->VDMOSlatDiff <=0) { |
|||
SPfrontEnd->IFerrorf (ERR_WARNING, |
|||
"%s: effective channel length less than zero", |
|||
model->VDMOSmodName); |
|||
} |
|||
ratio4 = ratio * sqrt(ratio); |
|||
here->VDMOStTransconductance = model->VDMOStransconductance / ratio4; |
|||
here->VDMOStSurfMob = model->VDMOSsurfaceMobility/ratio4; |
|||
phio= (model->VDMOSphi-pbfact1)/fact1; |
|||
here->VDMOStPhi = fact2 * phio + pbfact; |
|||
here->VDMOStVbi = |
|||
model->VDMOSvt0 - model->VDMOStype * |
|||
(model->VDMOSgamma* sqrt(model->VDMOSphi)) |
|||
+.5*(egfet1-egfet) |
|||
+ model->VDMOStype*.5* (here->VDMOStPhi-model->VDMOSphi); |
|||
here->VDMOStVto = here->VDMOStVbi + model->VDMOStype * |
|||
model->VDMOSgamma * sqrt(here->VDMOStPhi); |
|||
here->VDMOStSatCur = model->VDMOSjctSatCur* |
|||
exp(-egfet/vt+egfet1/vtnom); |
|||
here->VDMOStSatCurDens = model->VDMOSjctSatCurDensity * |
|||
exp(-egfet/vt+egfet1/vtnom); |
|||
pbo = (model->VDMOSbulkJctPotential - pbfact1)/fact1; |
|||
gmaold = (model->VDMOSbulkJctPotential-pbo)/pbo; |
|||
capfact = 1/(1+model->VDMOSbulkJctBotGradingCoeff* |
|||
(4e-4*(model->VDMOStnom-REFTEMP)-gmaold)); |
|||
here->VDMOStCbd = model->VDMOScapBD * capfact; |
|||
here->VDMOStCbs = model->VDMOScapBS * capfact; |
|||
here->VDMOStCj = model->VDMOSbulkCapFactor * capfact; |
|||
capfact = 1/(1+model->VDMOSbulkJctSideGradingCoeff* |
|||
(4e-4*(model->VDMOStnom-REFTEMP)-gmaold)); |
|||
here->VDMOStCjsw = model->VDMOSsideWallCapFactor * capfact; |
|||
here->VDMOStBulkPot = fact2 * pbo+pbfact; |
|||
gmanew = (here->VDMOStBulkPot-pbo)/pbo; |
|||
capfact = (1+model->VDMOSbulkJctBotGradingCoeff* |
|||
(4e-4*(here->VDMOStemp-REFTEMP)-gmanew)); |
|||
here->VDMOStCbd *= capfact; |
|||
here->VDMOStCbs *= capfact; |
|||
here->VDMOStCj *= capfact; |
|||
capfact = (1+model->VDMOSbulkJctSideGradingCoeff* |
|||
(4e-4*(here->VDMOStemp-REFTEMP)-gmanew)); |
|||
here->VDMOStCjsw *= capfact; |
|||
here->VDMOStDepCap = model->VDMOSfwdCapDepCoeff * here->VDMOStBulkPot; |
|||
if( (here->VDMOStSatCurDens == 0) || |
|||
(here->VDMOSdrainArea == 0) || |
|||
(here->VDMOSsourceArea == 0) ) { |
|||
here->VDMOSsourceVcrit = here->VDMOSdrainVcrit = |
|||
vt*log(vt/(CONSTroot2*here->VDMOSm*here->VDMOStSatCur)); |
|||
} else { |
|||
here->VDMOSdrainVcrit = |
|||
vt * log( vt / (CONSTroot2 * |
|||
here->VDMOSm * |
|||
here->VDMOStSatCurDens * here->VDMOSdrainArea)); |
|||
here->VDMOSsourceVcrit = |
|||
vt * log( vt / (CONSTroot2 * |
|||
here->VDMOSm * |
|||
here->VDMOStSatCurDens * here->VDMOSsourceArea)); |
|||
} |
|||
|
|||
if(model->VDMOScapBDGiven) { |
|||
czbd = here->VDMOStCbd * here->VDMOSm; |
|||
} else { |
|||
if(model->VDMOSbulkCapFactorGiven) { |
|||
czbd=here->VDMOStCj*here->VDMOSm*here->VDMOSdrainArea; |
|||
} else { |
|||
czbd=0; |
|||
} |
|||
} |
|||
if(model->VDMOSsideWallCapFactorGiven) { |
|||
czbdsw= here->VDMOStCjsw * here->VDMOSdrainPerimiter * |
|||
here->VDMOSm; |
|||
} else { |
|||
czbdsw=0; |
|||
} |
|||
arg = 1-model->VDMOSfwdCapDepCoeff; |
|||
sarg = exp( (-model->VDMOSbulkJctBotGradingCoeff) * log(arg) ); |
|||
sargsw = exp( (-model->VDMOSbulkJctSideGradingCoeff) * log(arg) ); |
|||
here->VDMOSCbd = czbd; |
|||
here->VDMOSCbdsw = czbdsw; |
|||
here->VDMOSf2d = czbd*(1-model->VDMOSfwdCapDepCoeff* |
|||
(1+model->VDMOSbulkJctBotGradingCoeff))* sarg/arg |
|||
+ czbdsw*(1-model->VDMOSfwdCapDepCoeff* |
|||
(1+model->VDMOSbulkJctSideGradingCoeff))* |
|||
sargsw/arg; |
|||
here->VDMOSf3d = czbd * model->VDMOSbulkJctBotGradingCoeff * sarg/arg/ |
|||
here->VDMOStBulkPot |
|||
+ czbdsw * model->VDMOSbulkJctSideGradingCoeff * sargsw/arg / |
|||
here->VDMOStBulkPot; |
|||
here->VDMOSf4d = czbd*here->VDMOStBulkPot*(1-arg*sarg)/ |
|||
(1-model->VDMOSbulkJctBotGradingCoeff) |
|||
+ czbdsw*here->VDMOStBulkPot*(1-arg*sargsw)/ |
|||
(1-model->VDMOSbulkJctSideGradingCoeff) |
|||
-here->VDMOSf3d/2* |
|||
(here->VDMOStDepCap*here->VDMOStDepCap) |
|||
-here->VDMOStDepCap * here->VDMOSf2d; |
|||
if(model->VDMOScapBSGiven) { |
|||
czbs=here->VDMOStCbs * here->VDMOSm; |
|||
} else { |
|||
if(model->VDMOSbulkCapFactorGiven) { |
|||
czbs=here->VDMOStCj*here->VDMOSsourceArea * here->VDMOSm; |
|||
} else { |
|||
czbs=0; |
|||
} |
|||
} |
|||
if(model->VDMOSsideWallCapFactorGiven) { |
|||
czbssw = here->VDMOStCjsw * here->VDMOSsourcePerimiter * |
|||
here->VDMOSm; |
|||
} else { |
|||
czbssw=0; |
|||
} |
|||
arg = 1-model->VDMOSfwdCapDepCoeff; |
|||
sarg = exp( (-model->VDMOSbulkJctBotGradingCoeff) * log(arg) ); |
|||
sargsw = exp( (-model->VDMOSbulkJctSideGradingCoeff) * log(arg) ); |
|||
here->VDMOSCbs = czbs; |
|||
here->VDMOSCbssw = czbssw; |
|||
here->VDMOSf2s = czbs*(1-model->VDMOSfwdCapDepCoeff* |
|||
(1+model->VDMOSbulkJctBotGradingCoeff))* sarg/arg |
|||
+ czbssw*(1-model->VDMOSfwdCapDepCoeff* |
|||
(1+model->VDMOSbulkJctSideGradingCoeff))* |
|||
sargsw/arg; |
|||
here->VDMOSf3s = czbs * model->VDMOSbulkJctBotGradingCoeff * sarg/arg/ |
|||
here->VDMOStBulkPot |
|||
+ czbssw * model->VDMOSbulkJctSideGradingCoeff * sargsw/arg / |
|||
here->VDMOStBulkPot; |
|||
here->VDMOSf4s = czbs*here->VDMOStBulkPot*(1-arg*sarg)/ |
|||
(1-model->VDMOSbulkJctBotGradingCoeff) |
|||
+ czbssw*here->VDMOStBulkPot*(1-arg*sargsw)/ |
|||
(1-model->VDMOSbulkJctSideGradingCoeff) |
|||
-here->VDMOSf3s/2* |
|||
(here->VDMOStDepCap*here->VDMOStDepCap) |
|||
-here->VDMOStDepCap * here->VDMOSf2s; |
|||
|
|||
|
|||
if(model->VDMOSdrainResistanceGiven) { |
|||
if(model->VDMOSdrainResistance != 0) { |
|||
here->VDMOSdrainConductance = here->VDMOSm / |
|||
model->VDMOSdrainResistance; |
|||
} else { |
|||
here->VDMOSdrainConductance = 0; |
|||
} |
|||
} else if (model->VDMOSsheetResistanceGiven) { |
|||
if(model->VDMOSsheetResistance != 0) { |
|||
here->VDMOSdrainConductance = |
|||
here->VDMOSm / |
|||
(model->VDMOSsheetResistance*here->VDMOSdrainSquares); |
|||
} 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 if (model->VDMOSsheetResistanceGiven) { |
|||
if ((model->VDMOSsheetResistance != 0) && |
|||
(here->VDMOSsourceSquares != 0)) { |
|||
here->VDMOSsourceConductance = |
|||
here->VDMOSm / |
|||
(model->VDMOSsheetResistance*here->VDMOSsourceSquares); |
|||
} else { |
|||
here->VDMOSsourceConductance = 0; |
|||
} |
|||
} else { |
|||
here->VDMOSsourceConductance = 0; |
|||
} |
|||
} |
|||
} |
|||
return(OK); |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1985 Thomas L. Quarles |
|||
**********/ |
|||
/* |
|||
*/ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "ngspice/cktdefs.h" |
|||
#include "vdmosdefs.h" |
|||
#include "ngspice/sperror.h" |
|||
#include "ngspice/suffix.h" |
|||
|
|||
|
|||
int |
|||
VDMOStrunc(GENmodel *inModel, CKTcircuit *ckt, double *timeStep) |
|||
{ |
|||
VDMOSmodel *model = (VDMOSmodel *)inModel; |
|||
VDMOSinstance *here; |
|||
|
|||
for( ; model != NULL; model = VDMOSnextModel(model)) { |
|||
for(here=VDMOSinstances(model);here!=NULL;here = VDMOSnextInstance(here)){ |
|||
|
|||
CKTterr(here->VDMOSqgs,ckt,timeStep); |
|||
CKTterr(here->VDMOSqgd,ckt,timeStep); |
|||
CKTterr(here->VDMOSqgb,ckt,timeStep); |
|||
} |
|||
} |
|||
return(OK); |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue