diff --git a/src/spicelib/devices/vdmos/Makefile.am b/src/spicelib/devices/vdmos/Makefile.am new file mode 100644 index 000000000..87967eed3 --- /dev/null +++ b/src/spicelib/devices/vdmos/Makefile.am @@ -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 diff --git a/src/spicelib/devices/vdmos/vdmos.c b/src/spicelib/devices/vdmos/vdmos.c new file mode 100644 index 000000000..264ce35f0 --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmos.c @@ -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); diff --git a/src/spicelib/devices/vdmos/vdmosacld.c b/src/spicelib/devices/vdmos/vdmosacld.c new file mode 100644 index 000000000..4e1bf3e34 --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmosacld.c @@ -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); +} diff --git a/src/spicelib/devices/vdmos/vdmosask.c b/src/spicelib/devices/vdmos/vdmosask.c new file mode 100644 index 000000000..9319b8c42 --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmosask.c @@ -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 */ +} + diff --git a/src/spicelib/devices/vdmos/vdmosconv.c b/src/spicelib/devices/vdmos/vdmosconv.c new file mode 100644 index 000000000..bdf0618c6 --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmosconv.c @@ -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); +} diff --git a/src/spicelib/devices/vdmos/vdmosdefs.h b/src/spicelib/devices/vdmos/vdmosdefs.h new file mode 100644 index 000000000..5a7bdd19a --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmosdefs.h @@ -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*/ + diff --git a/src/spicelib/devices/vdmos/vdmosdel.c b/src/spicelib/devices/vdmos/vdmosdel.c new file mode 100644 index 000000000..7b9c066b5 --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmosdel.c @@ -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; +} diff --git a/src/spicelib/devices/vdmos/vdmosdist.c b/src/spicelib/devices/vdmos/vdmosdist.c new file mode 100644 index 000000000..e161b608d --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmosdist.c @@ -0,0 +1,1379 @@ +/********** +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 "vdmosdefs.h" +#include "ngspice/sperror.h" +#include "ngspice/distodef.h" +#include "ngspice/suffix.h" + +int +VDMOSdisto(int mode, GENmodel *genmodel, CKTcircuit *ckt) + +/* assuming here that ckt->CKTomega has been initialised to + * the correct value + */ +{ + VDMOSmodel *model = (VDMOSmodel *) genmodel; + DISTOAN* job = (DISTOAN*) ckt->CKTcurJob; + DpassStr pass; + double r1h1x,i1h1x; + double r1h1y,i1h1y; + double r1h1z, i1h1z; + double r1h2x, i1h2x; + double r1h2y, i1h2y; + double r1h2z, i1h2z; + double r1hm2x,i1hm2x; + double r1hm2y,i1hm2y; + double r1hm2z, i1hm2z; + double r2h11x,i2h11x; + double r2h11y,i2h11y; + double r2h11z, i2h11z; + double r2h1m2x,i2h1m2x; + double r2h1m2y,i2h1m2y; + double r2h1m2z, i2h1m2z; + double temp, itemp; + VDMOSinstance *here; + +if (mode == D_SETUP) + return(VDMOSdSetup(genmodel,ckt)); + +if ((mode == D_TWOF1) || (mode == D_THRF1) || + (mode == D_F1PF2) || (mode == D_F1MF2) || + (mode == D_2F1MF2)) { + + /* 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)) { + + /* loading starts here */ + + switch (mode) { + case D_TWOF1: + /* x = vgs, y = vbs z = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->VDMOSgNode)) - + *(job->r1H1ptr + (here->VDMOSsNodePrime)); + i1h1x = *(job->i1H1ptr + (here->VDMOSgNode)) - + *(job->i1H1ptr + (here->VDMOSsNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->VDMOSbNode)) - + *(job->r1H1ptr + (here->VDMOSsNodePrime)); + i1h1y = *(job->i1H1ptr + (here->VDMOSbNode)) - + *(job->i1H1ptr + (here->VDMOSsNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->VDMOSdNodePrime)) - + *(job->r1H1ptr + (here->VDMOSsNodePrime)); + i1h1z = *(job->i1H1ptr + (here->VDMOSdNodePrime)) - + *(job->i1H1ptr + (here->VDMOSsNodePrime)); + + /* loading starts here */ + /* loading cdrain term */ + + temp = DFn2F1(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z); + + itemp = DFi2F1(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z); + + *(ckt->CKTrhs + (here->VDMOSdNodePrime)) -= temp; + *(ckt->CKTirhs + (here->VDMOSdNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSsNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSsNodePrime)) += itemp; + + /* cdrain term over */ + + /* loading gbs term */ + + temp = D1n2F1(here->gbs2, + r1h1y, + i1h1y); + + itemp = D1i2F1(here->gbs2, + r1h1y, + i1h1y); + + + *(ckt->CKTrhs + (here->VDMOSbNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSsNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSsNodePrime)) += itemp; + + /* gbs over */ + + /* loading gbd term */ + + temp = D1n2F1(here->gbd2, + r1h1y - r1h1z, + i1h1y - i1h1z); + + itemp = D1i2F1(here->gbd2, + r1h1y - r1h1z, + i1h1y - i1h1z); + + + *(ckt->CKTrhs + (here->VDMOSbNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSdNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSdNodePrime)) += itemp; + + /* gbd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1i2F1(here->capgs2, + r1h1x, + i1h1x); + + itemp = ckt->CKTomega * + D1n2F1(here->capgs2, + r1h1x, + i1h1x); + + *(ckt->CKTrhs + (here->VDMOSgNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSgNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSsNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSsNodePrime)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1i2F1(here->capgd2, + r1h1x - r1h1z, + i1h1x - i1h1z); + + itemp = ckt->CKTomega * + D1n2F1(here->capgd2, + r1h1x - r1h1z, + i1h1x - i1h1z); + + + *(ckt->CKTrhs + (here->VDMOSgNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSgNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSdNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSdNodePrime)) += itemp; + + /* capgd over */ + /* loading capgb term */ + + temp = -ckt->CKTomega * + D1i2F1(here->capgb2, + r1h1x - r1h1y, + i1h1x - i1h1y); + + itemp = ckt->CKTomega * + D1n2F1(here->capgb2, + r1h1x - r1h1y, + i1h1x - i1h1y); + + *(ckt->CKTrhs + (here->VDMOSgNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSgNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSbNode)) += temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) += itemp; + + /* capgb over */ + + /* loading capbs term */ + + temp = -ckt->CKTomega * + D1i2F1(here->capbs2, + r1h1y, + i1h1y); + + itemp = ckt->CKTomega * + D1n2F1(here->capbs2, + r1h1y, + i1h1y); + + + *(ckt->CKTrhs + (here->VDMOSbNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSsNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSsNodePrime)) += itemp; + + /* capbs over */ + + /* loading capbd term */ + + temp = -ckt->CKTomega * + D1i2F1(here->capbd2, + r1h1y - r1h1z, + i1h1y - i1h1z); + + itemp = ckt->CKTomega * + D1n2F1(here->capbd2, + r1h1y - r1h1z, + i1h1y - i1h1z); + + + *(ckt->CKTrhs + (here->VDMOSbNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSdNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSdNodePrime)) += itemp; + + /* capbd over */ + /* all done */ + + break; + + case D_THRF1: + /* x = vgs, y = vbs z = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->VDMOSgNode)) - + *(job->r1H1ptr + (here->VDMOSsNodePrime)); + i1h1x = *(job->i1H1ptr + (here->VDMOSgNode)) - + *(job->i1H1ptr + (here->VDMOSsNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->VDMOSbNode)) - + *(job->r1H1ptr + (here->VDMOSsNodePrime)); + i1h1y = *(job->i1H1ptr + (here->VDMOSbNode)) - + *(job->i1H1ptr + (here->VDMOSsNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->VDMOSdNodePrime)) - + *(job->r1H1ptr + (here->VDMOSsNodePrime)); + i1h1z = *(job->i1H1ptr + (here->VDMOSdNodePrime)) - + *(job->i1H1ptr + (here->VDMOSsNodePrime)); + + r2h11x = *(job->r2H11ptr + (here->VDMOSgNode)) - + *(job->r2H11ptr + (here->VDMOSsNodePrime)); + i2h11x = *(job->i2H11ptr + (here->VDMOSgNode)) - + *(job->i2H11ptr + (here->VDMOSsNodePrime)); + + r2h11y = *(job->r2H11ptr + (here->VDMOSbNode)) - + *(job->r2H11ptr + (here->VDMOSsNodePrime)); + i2h11y = *(job->i2H11ptr + (here->VDMOSbNode)) - + *(job->i2H11ptr + (here->VDMOSsNodePrime)); + + r2h11z = *(job->r2H11ptr + (here->VDMOSdNodePrime)) - + *(job->r2H11ptr + (here->VDMOSsNodePrime)); + i2h11z = *(job->i2H11ptr + (here->VDMOSdNodePrime)) - + *(job->i2H11ptr + (here->VDMOSsNodePrime)); + /* loading starts here */ + /* loading cdrain term */ + + temp = DFn3F1(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + here->cdr_x3, + here->cdr_y3, + here->cdr_z3, + here->cdr_x2y, + here->cdr_x2z, + here->cdr_xy2, + here->cdr_y2z, + here->cdr_xz2, + here->cdr_yz2, + here->cdr_xyz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + r2h11z, + i2h11z); + itemp = DFi3F1(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + here->cdr_x3, + here->cdr_y3, + here->cdr_z3, + here->cdr_x2y, + here->cdr_x2z, + here->cdr_xy2, + here->cdr_y2z, + here->cdr_xz2, + here->cdr_yz2, + here->cdr_xyz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + r2h11z, + i2h11z); + + + *(ckt->CKTrhs + (here->VDMOSdNodePrime)) -= temp; + *(ckt->CKTirhs + (here->VDMOSdNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSsNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSsNodePrime)) += itemp; + + /* cdrain term over */ + + /* loading gbs term */ + + temp = D1n3F1(here->gbs2, + here->gbs3, + r1h1y, + i1h1y, + r2h11y, + i2h11y); + + + itemp = D1i3F1(here->gbs2, + here->gbs3, + r1h1y, + i1h1y, + r2h11y, + i2h11y); + + + *(ckt->CKTrhs + (here->VDMOSbNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSsNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSsNodePrime)) += itemp; + + /* gbs over */ + + /* loading gbd term */ + + temp = D1n3F1(here->gbd2, + here->gbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r2h11y - r2h11z, + i2h11y - i2h11z); + + itemp = D1i3F1(here->gbd2, + here->gbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r2h11y - r2h11z, + i2h11y - i2h11z); + + *(ckt->CKTrhs + (here->VDMOSbNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSdNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSdNodePrime)) += itemp; + + /* gbd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1i3F1(here->capgs2, + here->capgs3, + r1h1x, + i1h1x, + r2h11x, + i2h11x); + + itemp = ckt->CKTomega * + D1n3F1(here->capgs2, + here->capgs3, + r1h1x, + i1h1x, + r2h11x, + i2h11x); + + *(ckt->CKTrhs + (here->VDMOSgNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSgNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSsNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSsNodePrime)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1i3F1(here->capgd2, + here->capgd3, + r1h1x - r1h1z, + i1h1x - i1h1z, + r2h11x - r2h11z, + i2h11x - i2h11z); + + itemp = ckt->CKTomega * + D1n3F1(here->capgd2, + here->capgd3, + r1h1x - r1h1z, + i1h1x - i1h1z, + r2h11x - r2h11z, + i2h11x - i2h11z); + + + *(ckt->CKTrhs + (here->VDMOSgNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSgNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSdNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSdNodePrime)) += itemp; + + /* capgd over */ + /* loading capgb term */ + + temp = -ckt->CKTomega * + D1i3F1(here->capgb2, + here->capgb3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r2h11x - r2h11y, + i2h11x - i2h11y); + + itemp = ckt->CKTomega * + D1n3F1(here->capgb2, + here->capgb3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r2h11x - r2h11y, + i2h11x - i2h11y); + + *(ckt->CKTrhs + (here->VDMOSgNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSgNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSbNode)) += temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) += itemp; + + /* capgb over */ + + /* loading capbs term */ + + temp = -ckt->CKTomega * + D1i3F1(here->capbs2, + here->capbs3, + r1h1y, + i1h1y, + r2h11y, + i2h11y); + + itemp = ckt->CKTomega * + D1n3F1(here->capbs2, + here->capbs3, + r1h1y, + i1h1y, + r2h11y, + i2h11y); + + + *(ckt->CKTrhs + (here->VDMOSbNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSsNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSsNodePrime)) += itemp; + + /* capbs over */ + + /* loading capbd term */ + + temp = -ckt->CKTomega * + D1i3F1(here->capbd2, + here->capbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r2h11y - r2h11z, + i2h11y - i2h11z); + + itemp = ckt->CKTomega * + D1n3F1(here->capbd2, + here->capbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r2h11y - r2h11z, + i2h11y - i2h11z); + + + *(ckt->CKTrhs + (here->VDMOSbNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSdNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSdNodePrime)) += itemp; + + /* capbd over */ + /* all done */ + + break; + case D_F1PF2: + /* x = vgs, y = vbs z = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->VDMOSgNode)) - + *(job->r1H1ptr + (here->VDMOSsNodePrime)); + i1h1x = *(job->i1H1ptr + (here->VDMOSgNode)) - + *(job->i1H1ptr + (here->VDMOSsNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->VDMOSbNode)) - + *(job->r1H1ptr + (here->VDMOSsNodePrime)); + i1h1y = *(job->i1H1ptr + (here->VDMOSbNode)) - + *(job->i1H1ptr + (here->VDMOSsNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->VDMOSdNodePrime)) - + *(job->r1H1ptr + (here->VDMOSsNodePrime)); + i1h1z = *(job->i1H1ptr + (here->VDMOSdNodePrime)) - + *(job->i1H1ptr + (here->VDMOSsNodePrime)); + + r1h2x = *(job->r1H2ptr + (here->VDMOSgNode)) - + *(job->r1H2ptr + (here->VDMOSsNodePrime)); + i1h2x = *(job->i1H2ptr + (here->VDMOSgNode)) - + *(job->i1H2ptr + (here->VDMOSsNodePrime)); + + r1h2y = *(job->r1H2ptr + (here->VDMOSbNode)) - + *(job->r1H2ptr + (here->VDMOSsNodePrime)); + i1h2y = *(job->i1H2ptr + (here->VDMOSbNode)) - + *(job->i1H2ptr + (here->VDMOSsNodePrime)); + + r1h2z = *(job->r1H2ptr + (here->VDMOSdNodePrime)) - + *(job->r1H2ptr + (here->VDMOSsNodePrime)); + i1h2z = *(job->i1H2ptr + (here->VDMOSdNodePrime)) - + *(job->i1H2ptr + (here->VDMOSsNodePrime)); + + /* loading starts here */ + /* loading cdrain term */ + + temp = DFnF12(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + r1h2z, + i1h2z); + + itemp = DFiF12(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + r1h2z, + i1h2z); + + *(ckt->CKTrhs + (here->VDMOSdNodePrime)) -= temp; + *(ckt->CKTirhs + (here->VDMOSdNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSsNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSsNodePrime)) += itemp; + + /* cdrain term over */ + + /* loading gbs term */ + + temp = D1nF12(here->gbs2, + r1h1y, + i1h1y, + r1h2y, + i1h2y); + + itemp = D1iF12(here->gbs2, + r1h1y, + i1h1y, + r1h2y, + i1h2y); + + + *(ckt->CKTrhs + (here->VDMOSbNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSsNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSsNodePrime)) += itemp; + + /* gbs over */ + + /* loading gbd term */ + + temp = D1nF12(here->gbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1h2y - r1h2z, + i1h2y - i1h2z); + + itemp = D1iF12(here->gbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1h2y - r1h2z, + i1h2y - i1h2z); + + + *(ckt->CKTrhs + (here->VDMOSbNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSdNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSdNodePrime)) += itemp; + + /* gbd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgs2, + r1h1x, + i1h1x, + r1h2x, + i1h2x); + + itemp = ckt->CKTomega * + D1nF12(here->capgs2, + r1h1x, + i1h1x, + r1h2x, + i1h2x); + + *(ckt->CKTrhs + (here->VDMOSgNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSgNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSsNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSsNodePrime)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgd2, + r1h1x - r1h1z, + i1h1x - i1h1z, + r1h2x - r1h2z, + i1h2x - i1h2z); + + itemp = ckt->CKTomega * + D1nF12(here->capgd2, + r1h1x - r1h1z, + i1h1x - i1h1z, + r1h2x - r1h2z, + i1h2x - i1h2z); + + + *(ckt->CKTrhs + (here->VDMOSgNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSgNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSdNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSdNodePrime)) += itemp; + + /* capgd over */ + /* loading capgb term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgb2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1h2x - r1h2y, + i1h2x - i1h2y); + + itemp = ckt->CKTomega * + D1nF12(here->capgb2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1h2x - r1h2y, + i1h2x - i1h2y); + + *(ckt->CKTrhs + (here->VDMOSgNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSgNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSbNode)) += temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) += itemp; + + /* capgb over */ + + /* loading capbs term */ + + temp = -ckt->CKTomega * + D1iF12(here->capbs2, + r1h1y, + i1h1y, + r1h2y, + i1h2y); + + itemp = ckt->CKTomega * + D1nF12(here->capbs2, + r1h1y, + i1h1y, + r1h2y, + i1h2y); + + + *(ckt->CKTrhs + (here->VDMOSbNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSsNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSsNodePrime)) += itemp; + + /* capbs over */ + + /* loading capbd term */ + + temp = -ckt->CKTomega * + D1iF12(here->capbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1h2y - r1h2z, + i1h2y - i1h2z); + + itemp = ckt->CKTomega * + D1nF12(here->capbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1h2y - r1h2z, + i1h2y - i1h2z); + + + *(ckt->CKTrhs + (here->VDMOSbNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSdNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSdNodePrime)) += itemp; + + /* capbd over */ + /* all done */ + + break; + case D_F1MF2: + /* x = vgs, y = vbs z = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->VDMOSgNode)) - + *(job->r1H1ptr + (here->VDMOSsNodePrime)); + i1h1x = *(job->i1H1ptr + (here->VDMOSgNode)) - + *(job->i1H1ptr + (here->VDMOSsNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->VDMOSbNode)) - + *(job->r1H1ptr + (here->VDMOSsNodePrime)); + i1h1y = *(job->i1H1ptr + (here->VDMOSbNode)) - + *(job->i1H1ptr + (here->VDMOSsNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->VDMOSdNodePrime)) - + *(job->r1H1ptr + (here->VDMOSsNodePrime)); + i1h1z = *(job->i1H1ptr + (here->VDMOSdNodePrime)) - + *(job->i1H1ptr + (here->VDMOSsNodePrime)); + + r1hm2x = *(job->r1H2ptr + (here->VDMOSgNode)) - + *(job->r1H2ptr + (here->VDMOSsNodePrime)); + i1hm2x = -(*(job->i1H2ptr + (here->VDMOSgNode)) - + *(job->i1H2ptr + (here->VDMOSsNodePrime))); + + r1hm2y = *(job->r1H2ptr + (here->VDMOSbNode)) - + *(job->r1H2ptr + (here->VDMOSsNodePrime)); + i1hm2y = -(*(job->i1H2ptr + (here->VDMOSbNode)) - + *(job->i1H2ptr + (here->VDMOSsNodePrime))); + + r1hm2z = *(job->r1H2ptr + (here->VDMOSdNodePrime)) - + *(job->r1H2ptr + (here->VDMOSsNodePrime)); + i1hm2z = -(*(job->i1H2ptr + (here->VDMOSdNodePrime)) - + *(job->i1H2ptr + (here->VDMOSsNodePrime))); + + /* loading starts here */ + /* loading cdrain term */ + + temp = DFnF12(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + r1hm2z, + i1hm2z); + + itemp = DFiF12(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + r1hm2z, + i1hm2z); + + *(ckt->CKTrhs + (here->VDMOSdNodePrime)) -= temp; + *(ckt->CKTirhs + (here->VDMOSdNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSsNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSsNodePrime)) += itemp; + + /* cdrain term over */ + + /* loading gbs term */ + + temp = D1nF12(here->gbs2, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y); + + itemp = D1iF12(here->gbs2, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y); + + + *(ckt->CKTrhs + (here->VDMOSbNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSsNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSsNodePrime)) += itemp; + + /* gbs over */ + + /* loading gbd term */ + + temp = D1nF12(here->gbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z); + + itemp = D1iF12(here->gbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z); + + + *(ckt->CKTrhs + (here->VDMOSbNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSdNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSdNodePrime)) += itemp; + + /* gbd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgs2, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x); + + itemp = ckt->CKTomega * + D1nF12(here->capgs2, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x); + + *(ckt->CKTrhs + (here->VDMOSgNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSgNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSsNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSsNodePrime)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgd2, + r1h1x - r1h1z, + i1h1x - i1h1z, + r1hm2x - r1hm2z, + i1hm2x - i1hm2z); + + itemp = ckt->CKTomega * + D1nF12(here->capgd2, + r1h1x - r1h1z, + i1h1x - i1h1z, + r1hm2x - r1hm2z, + i1hm2x - i1hm2z); + + + *(ckt->CKTrhs + (here->VDMOSgNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSgNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSdNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSdNodePrime)) += itemp; + + /* capgd over */ + /* loading capgb term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgb2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y); + + itemp = ckt->CKTomega * + D1nF12(here->capgb2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y); + + *(ckt->CKTrhs + (here->VDMOSgNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSgNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSbNode)) += temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) += itemp; + + /* capgb over */ + + /* loading capbs term */ + + temp = -ckt->CKTomega * + D1iF12(here->capbs2, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y); + + itemp = ckt->CKTomega * + D1nF12(here->capbs2, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y); + + + *(ckt->CKTrhs + (here->VDMOSbNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSsNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSsNodePrime)) += itemp; + + /* capbs over */ + + /* loading capbd term */ + + temp = -ckt->CKTomega * + D1iF12(here->capbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z); + + itemp = ckt->CKTomega * + D1nF12(here->capbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z); + + + *(ckt->CKTrhs + (here->VDMOSbNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSdNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSdNodePrime)) += itemp; + + /* capbd over */ + /* all done */ + + break; + case D_2F1MF2: + /* x = vgs, y = vbs z = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->VDMOSgNode)) - + *(job->r1H1ptr + (here->VDMOSsNodePrime)); + i1h1x = *(job->i1H1ptr + (here->VDMOSgNode)) - + *(job->i1H1ptr + (here->VDMOSsNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->VDMOSbNode)) - + *(job->r1H1ptr + (here->VDMOSsNodePrime)); + i1h1y = *(job->i1H1ptr + (here->VDMOSbNode)) - + *(job->i1H1ptr + (here->VDMOSsNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->VDMOSdNodePrime)) - + *(job->r1H1ptr + (here->VDMOSsNodePrime)); + i1h1z = *(job->i1H1ptr + (here->VDMOSdNodePrime)) - + *(job->i1H1ptr + (here->VDMOSsNodePrime)); + + r1hm2x = *(job->r1H2ptr + (here->VDMOSgNode)) - + *(job->r1H2ptr + (here->VDMOSsNodePrime)); + i1hm2x = -(*(job->i1H2ptr + (here->VDMOSgNode)) - + *(job->i1H2ptr + (here->VDMOSsNodePrime))); + + r1hm2y = *(job->r1H2ptr + (here->VDMOSbNode)) - + *(job->r1H2ptr + (here->VDMOSsNodePrime)); + i1hm2y = -(*(job->i1H2ptr + (here->VDMOSbNode)) - + *(job->i1H2ptr + (here->VDMOSsNodePrime))); + + r1hm2z = *(job->r1H2ptr + (here->VDMOSdNodePrime)) - + *(job->r1H2ptr + (here->VDMOSsNodePrime)); + i1hm2z = -(*(job->i1H2ptr + (here->VDMOSdNodePrime)) - + *(job->i1H2ptr + (here->VDMOSsNodePrime))); + + r2h11x = *(job->r1H1ptr + (here->VDMOSgNode)) - + *(job->r1H1ptr + (here->VDMOSsNodePrime)); + i2h11x = *(job->i1H1ptr + (here->VDMOSgNode)) - + *(job->i1H1ptr + (here->VDMOSsNodePrime)); + + r2h11y = *(job->r1H1ptr + (here->VDMOSbNode)) - + *(job->r1H1ptr + (here->VDMOSsNodePrime)); + i2h11y = *(job->i1H1ptr + (here->VDMOSbNode)) - + *(job->i1H1ptr + (here->VDMOSsNodePrime)); + + r2h11z = *(job->r1H1ptr + (here->VDMOSdNodePrime)) - + *(job->r1H1ptr + (here->VDMOSsNodePrime)); + i2h11z = *(job->i1H1ptr + (here->VDMOSdNodePrime)) - + *(job->i1H1ptr + (here->VDMOSsNodePrime)); + + r2h1m2x = *(job->r2H1m2ptr + (here->VDMOSgNode)) - + *(job->r2H1m2ptr + (here->VDMOSsNodePrime)); + i2h1m2x = *(job->i2H1m2ptr + (here->VDMOSgNode)) - + *(job->i2H1m2ptr + (here->VDMOSsNodePrime)); + + r2h1m2y = *(job->r2H1m2ptr + (here->VDMOSbNode)) - + *(job->r2H1m2ptr + (here->VDMOSsNodePrime)); + i2h1m2y = *(job->i2H1m2ptr + (here->VDMOSbNode)) - + *(job->i2H1m2ptr + (here->VDMOSsNodePrime)); + +r2h1m2z = *(job->r2H1m2ptr + (here->VDMOSdNodePrime)) - + *(job->r2H1m2ptr + (here->VDMOSsNodePrime)); +i2h1m2z = *(job->i2H1m2ptr + (here->VDMOSdNodePrime)) - + *(job->i2H1m2ptr + (here->VDMOSsNodePrime)); + + /* loading starts here */ + /* loading cdrain term */ + +pass.cxx = here->cdr_x2; +pass.cyy = here->cdr_y2; +pass.czz = here->cdr_z2; +pass.cxy = here->cdr_xy; +pass.cyz = here->cdr_yz; +pass.cxz = here->cdr_xz; +pass.cxxx = here->cdr_x3; +pass.cyyy = here->cdr_y3; +pass.czzz = here->cdr_z3; +pass.cxxy = here->cdr_x2y; +pass.cxxz = here->cdr_x2z; +pass.cxyy = here->cdr_xy2; +pass.cyyz = here->cdr_y2z; +pass.cxzz = here->cdr_xz2; +pass.cyzz = here->cdr_yz2; +pass.cxyz = here->cdr_xyz; +pass.r1h1x = r1h1x; +pass.i1h1x = i1h1x; +pass.r1h1y = r1h1y; +pass.i1h1y = i1h1y; +pass.r1h1z = r1h1z; +pass.i1h1z = i1h1z; +pass.r1h2x = r1hm2x; +pass.i1h2x = i1hm2x; +pass.r1h2y = r1hm2y; +pass.i1h2y = i1hm2y; +pass.r1h2z = r1hm2z; +pass.i1h2z = i1hm2z; +pass.r2h11x = r2h11x; +pass.i2h11x = i2h11x; +pass.r2h11y = r2h11y; +pass.i2h11y = i2h11y; +pass.r2h11z = r2h11z; +pass.i2h11z = i2h11z; +pass.h2f1f2x = r2h1m2x; +pass.ih2f1f2x = i2h1m2x; +pass.h2f1f2y = r2h1m2y; +pass.ih2f1f2y = i2h1m2y; +pass.h2f1f2z = r2h1m2z; +pass.ih2f1f2z = i2h1m2z; + temp = DFn2F12(&pass); + + itemp = DFi2F12(&pass); + + + *(ckt->CKTrhs + (here->VDMOSdNodePrime)) -= temp; + *(ckt->CKTirhs + (here->VDMOSdNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSsNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSsNodePrime)) += itemp; + + /* cdrain term over */ + + /* loading gbs term */ + + temp = D1n2F12(here->gbs2, + here->gbs3, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y, + r2h11y, + i2h11y, + r2h1m2y, + i2h1m2y); + + + + itemp = D1i2F12(here->gbs2, + here->gbs3, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y, + r2h11y, + i2h11y, + r2h1m2y, + i2h1m2y); + + + *(ckt->CKTrhs + (here->VDMOSbNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSsNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSsNodePrime)) += itemp; + + /* gbs over */ + + /* loading gbd term */ + + temp = D1n2F12(here->gbd2, + here->gbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z, + r2h11y - r2h11z, + i2h11y - i2h11z, + r2h1m2y - r2h1m2z, + i2h1m2y - i2h1m2z); + + itemp = D1i2F12(here->gbd2, + here->gbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z, + r2h11y - r2h11z, + i2h11y - i2h11z, + r2h1m2y - r2h1m2z, + i2h1m2y - i2h1m2z); + + *(ckt->CKTrhs + (here->VDMOSbNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSdNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSdNodePrime)) += itemp; + + /* gbd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1i2F12(here->capgs2, + here->capgs3, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x, + r2h11x, + i2h11x, + r2h1m2x, + i2h1m2x); + + itemp = ckt->CKTomega * + D1n2F12(here->capgs2, + here->capgs3, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x, + r2h11x, + i2h11x, + r2h1m2x, + i2h1m2x); + + *(ckt->CKTrhs + (here->VDMOSgNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSgNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSsNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSsNodePrime)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1i2F12(here->capgd2, + here->capgd3, + r1h1x - r1h1z, + i1h1x - i1h1z, + r1hm2x - r1hm2z, + i1hm2x - i1hm2z, + r2h11x - r2h11z, + i2h11x - i2h11z, + r2h1m2x - r2h1m2z, + i2h1m2x - i2h1m2z); + + itemp = ckt->CKTomega * + D1n2F12(here->capgd2, + here->capgd3, + r1h1x - r1h1z, + i1h1x - i1h1z, + r1hm2x - r1hm2z, + i1hm2x - i1hm2z, + r2h11x - r2h11z, + i2h11x - i2h11z, + r2h1m2x - r2h1m2z, + i2h1m2x - i2h1m2z); + + + *(ckt->CKTrhs + (here->VDMOSgNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSgNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSdNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSdNodePrime)) += itemp; + + /* capgd over */ + /* loading capgb term */ + + temp = -ckt->CKTomega * + D1i2F12(here->capgb2, + here->capgb3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y, + r2h11x - r2h11y, + i2h11x - i2h11y, + r2h1m2x - r2h1m2y, + i2h1m2x - i2h1m2y); + + itemp = ckt->CKTomega * + D1n2F12(here->capgb2, + here->capgb3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y, + r2h11x - r2h11y, + i2h11x - i2h11y, + r2h1m2x - r2h1m2y, + i2h1m2x - i2h1m2y); + + *(ckt->CKTrhs + (here->VDMOSgNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSgNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSbNode)) += temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) += itemp; + + /* capgb over */ + + /* loading capbs term */ + + temp = -ckt->CKTomega * + D1i2F12(here->capbs2, + here->capbs3, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y, + r2h11y, + i2h11y, + r2h1m2y, + i2h1m2y); + + itemp = ckt->CKTomega * + D1n2F12(here->capbs2, + here->capbs3, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y, + r2h11y, + i2h11y, + r2h1m2y, + i2h1m2y); + + + *(ckt->CKTrhs + (here->VDMOSbNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSsNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSsNodePrime)) += itemp; + + /* capbs over */ + + /* loading capbd term */ + + temp = -ckt->CKTomega * + D1i2F12(here->capbd2, + here->capbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z, + r2h11y - r2h11z, + i2h11y - i2h11z, + r2h1m2y - r2h1m2z, + i2h1m2y - i2h1m2z); + + itemp = ckt->CKTomega * + D1n2F12(here->capbd2, + here->capbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z, + r2h11y - r2h11z, + i2h11y - i2h11z, + r2h1m2y - r2h1m2z, + i2h1m2y - i2h1m2z); + + + *(ckt->CKTrhs + (here->VDMOSbNode)) -= temp; + *(ckt->CKTirhs + (here->VDMOSbNode)) -= itemp; + *(ckt->CKTrhs + (here->VDMOSdNodePrime)) += temp; + *(ckt->CKTirhs + (here->VDMOSdNodePrime)) += itemp; + + /* capbd over */ + /* all done */ + + break; + default: +; + } + } +} +return(OK); +} + else + return(E_BADPARM); +} diff --git a/src/spicelib/devices/vdmos/vdmosdset.c b/src/spicelib/devices/vdmos/vdmosdset.c new file mode 100644 index 000000000..5af9b97d0 --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmosdset.c @@ -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); + } diff --git a/src/spicelib/devices/vdmos/vdmosext.h b/src/spicelib/devices/vdmos/vdmosext.h new file mode 100644 index 000000000..e9cbf5807 --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmosext.h @@ -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*); diff --git a/src/spicelib/devices/vdmos/vdmosic.c b/src/spicelib/devices/vdmos/vdmosic.c new file mode 100644 index 000000000..81bbc7e31 --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmosic.c @@ -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); +} diff --git a/src/spicelib/devices/vdmos/vdmosinit.c b/src/spicelib/devices/vdmos/vdmosinit.c new file mode 100644 index 000000000..40904ef09 --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmosinit.c @@ -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; +} diff --git a/src/spicelib/devices/vdmos/vdmosinit.h b/src/spicelib/devices/vdmos/vdmosinit.h new file mode 100644 index 000000000..9329ebe60 --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmosinit.h @@ -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 diff --git a/src/spicelib/devices/vdmos/vdmositf.h b/src/spicelib/devices/vdmos/vdmositf.h new file mode 100644 index 000000000..77289a6f4 --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmositf.h @@ -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 diff --git a/src/spicelib/devices/vdmos/vdmosload.c b/src/spicelib/devices/vdmos/vdmosload.c new file mode 100644 index 000000000..f39c6324a --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmosload.c @@ -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); +} diff --git a/src/spicelib/devices/vdmos/vdmosmask.c b/src/spicelib/devices/vdmos/vdmosmask.c new file mode 100644 index 000000000..643fb1a3a --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmosmask.c @@ -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 */ +} + diff --git a/src/spicelib/devices/vdmos/vdmosmpar.c b/src/spicelib/devices/vdmos/vdmosmpar.c new file mode 100644 index 000000000..7a7c41743 --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmosmpar.c @@ -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); +} diff --git a/src/spicelib/devices/vdmos/vdmosnoi.c b/src/spicelib/devices/vdmos/vdmosnoi.c new file mode 100644 index 000000000..6809dccbc --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmosnoi.c @@ -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); +} diff --git a/src/spicelib/devices/vdmos/vdmospar.c b/src/spicelib/devices/vdmos/vdmospar.c new file mode 100644 index 000000000..0a0263083 --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmospar.c @@ -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); +} diff --git a/src/spicelib/devices/vdmos/vdmospzld.c b/src/spicelib/devices/vdmos/vdmospzld.c new file mode 100644 index 000000000..e2cd9f1cb --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmospzld.c @@ -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); +} diff --git a/src/spicelib/devices/vdmos/vdmossacl.c b/src/spicelib/devices/vdmos/vdmossacl.c new file mode 100644 index 000000000..f4c2b38a9 --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmossacl.c @@ -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); +} + + diff --git a/src/spicelib/devices/vdmos/vdmosset.c b/src/spicelib/devices/vdmos/vdmosset.c new file mode 100644 index 000000000..1021bd2a8 --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmosset.c @@ -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; +} diff --git a/src/spicelib/devices/vdmos/vdmossld.c b/src/spicelib/devices/vdmos/vdmossld.c new file mode 100644 index 000000000..6f0c04c38 --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmossld.c @@ -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); +} + diff --git a/src/spicelib/devices/vdmos/vdmossprt.c b/src/spicelib/devices/vdmos/vdmossprt.c new file mode 100644 index 000000000..2cc0cac1d --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmossprt.c @@ -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"); + } + + + } + } +} + diff --git a/src/spicelib/devices/vdmos/vdmossset.c b/src/spicelib/devices/vdmos/vdmossset.c new file mode 100644 index 000000000..e5d4125aa --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmossset.c @@ -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); +} + + diff --git a/src/spicelib/devices/vdmos/vdmossupd.c b/src/spicelib/devices/vdmos/vdmossupd.c new file mode 100644 index 000000000..06aacff8c --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmossupd.c @@ -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); + +} + diff --git a/src/spicelib/devices/vdmos/vdmostemp.c b/src/spicelib/devices/vdmos/vdmostemp.c new file mode 100644 index 000000000..7a09b847c --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmostemp.c @@ -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); +} diff --git a/src/spicelib/devices/vdmos/vdmostrun.c b/src/spicelib/devices/vdmos/vdmostrun.c new file mode 100644 index 000000000..4f74b2f01 --- /dev/null +++ b/src/spicelib/devices/vdmos/vdmostrun.c @@ -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); +}