execute vdmos-1.el
This commit is contained in:
parent
2072e142a7
commit
572bf10ebd
|
|
@ -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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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);
|
||||
}
|
||||
Loading…
Reference in New Issue