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