diff --git a/src/spicelib/devices/mos9/Makefile.am b/src/spicelib/devices/mos9/Makefile.am new file mode 100644 index 000000000..26b3b725b --- /dev/null +++ b/src/spicelib/devices/mos9/Makefile.am @@ -0,0 +1,27 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libmos9.la + +libmos9_la_SOURCES = \ + mos9.c \ + mos9ask.c \ + mos9conv.c \ + mos9defs.h \ + mos9dest.c \ + mos9ext.h \ + mos9ic.c \ + mos9init.c \ + mos9init.h \ + mos9itf.h \ + mos9load.c \ + mos9mask.c \ + mos9mpar.c \ + mos9par.c \ + mos9set.c \ + mos9temp.c \ + mos9trun.c + + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/mos9/mos9.c b/src/spicelib/devices/mos9/mos9.c new file mode 100644 index 000000000..c4c1cb806 --- /dev/null +++ b/src/spicelib/devices/mos9/mos9.c @@ -0,0 +1,174 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +Modified: Alan Gillespie +**********/ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "ifsim.h" +#include "mos9defs.h" +#include "suffix.h" + +IFparm MOS9pTable[] = { /* parameters */ + + IOPU("m", MOS9_M, IF_REAL , "Multiplier"), + IOPU("l", MOS9_L, IF_REAL , "Length"), + IOPU("w", MOS9_W, IF_REAL , "Width"), + IOPU("ad", MOS9_AD, IF_REAL , "Drain area"), + IOPU("as", MOS9_AS, IF_REAL , "Source area"), + IOPU("pd", MOS9_PD, IF_REAL , "Drain perimeter"), + IOPU("ps", MOS9_PS, IF_REAL , "Source perimeter"), + OP("id", MOS9_CD, IF_REAL, "Drain current"), + OPR("cd", MOS9_CD, IF_REAL, "Drain current"), + OPU("ibd", MOS9_CBD, IF_REAL, "B-D junction current"), + OPU("ibs", MOS9_CBS, IF_REAL, "B-S junction current"), + OPU("is", MOS9_CS, IF_REAL, "Source current"), + OPU("ig", MOS9_CG, IF_REAL, "Gate current"), + OPU("ib", MOS9_CB, IF_REAL, "Bulk current"), + OP("vgs", MOS9_VGS, IF_REAL, "Gate-Source voltage"), + OP("vds", MOS9_VDS, IF_REAL, "Drain-Source voltage"), + OP("vbs", MOS9_VBS, IF_REAL, "Bulk-Source voltage"), + OPU("vbd", MOS9_VBD, IF_REAL, "Bulk-Drain voltage"), + IOPU("nrd", MOS9_NRD, IF_REAL , "Drain squares"), + IOPU("nrs", MOS9_NRS, IF_REAL , "Source squares"), + IP("off", MOS9_OFF, IF_FLAG , "Device initially off"), + IOPAU("icvds", MOS9_IC_VDS, IF_REAL , "Initial D-S voltage"), + IOPAU("icvgs", MOS9_IC_VGS, IF_REAL , "Initial G-S voltage"), + IOPAU("icvbs", MOS9_IC_VBS, IF_REAL , "Initial B-S voltage"), + IOPU("ic", MOS9_IC, IF_REALVEC, "Vector of D-S, G-S, B-S voltages"), + IOPU("temp", MOS9_TEMP, IF_REAL , "Instance operating temperature"), + IP("sens_l", MOS9_L_SENS, IF_FLAG, "flag to request sensitivity WRT length"), + IP("sens_w", MOS9_W_SENS, IF_FLAG, "flag to request sensitivity WRT width"), + OPU("dnode", MOS9_DNODE, IF_INTEGER, "Number of drain node"), + OPU("gnode", MOS9_GNODE, IF_INTEGER, "Number of gate node"), + OPU("snode", MOS9_SNODE, IF_INTEGER, "Number of source node"), + OPU("bnode", MOS9_BNODE, IF_INTEGER, "Number of bulk node"), + OPU("dnodeprime", MOS9_DNODEPRIME,IF_INTEGER,"Number of internal drain node"), + OPU("snodeprime", MOS9_SNODEPRIME,IF_INTEGER,"Number of internal source node"), + OP("von", MOS9_VON, IF_REAL, "Turn-on voltage"), + OP("vdsat", MOS9_VDSAT, IF_REAL, "Saturation drain voltage"), + OPU("sourcevcrit", MOS9_SOURCEVCRIT, IF_REAL, "Critical source voltage"), + OPU("drainvcrit", MOS9_DRAINVCRIT, IF_REAL, "Critical drain voltage"), + OP("rs", MOS9_SOURCERESIST, IF_REAL, "Source resistance"), + OPU("sourceconductance", MOS9_SOURCECONDUCT, IF_REAL, "Source conductance"), + OP("rd", MOS9_DRAINRESIST, IF_REAL, "Drain resistance"), + OPU("drainconductance", MOS9_DRAINCONDUCT, IF_REAL, "Drain conductance"), + OP("gm", MOS9_GM, IF_REAL, "Transconductance"), + OP("gds", MOS9_GDS, IF_REAL, "Drain-Source conductance"), + OP("gmb", MOS9_GMBS, IF_REAL, "Bulk-Source transconductance"), + OPR("gmbs", MOS9_GMBS, IF_REAL, "Bulk-Source transconductance"), + OPU("gbd", MOS9_GBD, IF_REAL, "Bulk-Drain conductance"), + OPU("gbs", MOS9_GBS, IF_REAL, "Bulk-Source conductance"), + + OP("cbd", MOS9_CAPBD, IF_REAL, "Bulk-Drain capacitance"), + OP("cbs", MOS9_CAPBS, IF_REAL, "Bulk-Source capacitance"), + OP("cgs", MOS9_CAPGS, IF_REAL, "Gate-Source capacitance"), +/* OPR("cgs", MOS9_CGS, IF_REAL , "Gate-Source capacitance"),*/ + OP("cgd", MOS9_CAPGD, IF_REAL, "Gate-Drain capacitance"), +/* OPR("cgd", MOS9_CGD, IF_REAL , "Gate-Drain capacitance"),*/ + OP("cgb", MOS9_CAPGB, IF_REAL, "Gate-Bulk capacitance"), + + OPU("cqgs",MOS9_CQGS,IF_REAL,"Capacitance due to gate-source charge storage"), + OPU("cqgd",MOS9_CQGD, IF_REAL,"Capacitance due to gate-drain charge storage"), + OPU("cqgb",MOS9_CQGB, IF_REAL,"Capacitance due to gate-bulk charge storage"), + OPU("cqbd",MOS9_CQBD,IF_REAL,"Capacitance due to bulk-drain charge storage"), + OPU("cqbs",MOS9_CQBS,IF_REAL,"Capacitance due to bulk-source charge storage"), + + OPU("cbd0",MOS9_CAPZEROBIASBD,IF_REAL,"Zero-Bias B-D junction capacitance"), + OPU("cbdsw0",MOS9_CAPZEROBIASBDSW,IF_REAL, + "Zero-Bias B-D sidewall capacitance"), + OPU("cbs0",MOS9_CAPZEROBIASBS,IF_REAL,"Zero-Bias B-S junction capacitance"), + OPU("cbssw0",MOS9_CAPZEROBIASBSSW,IF_REAL, + "Zero-Bias B-S sidewall capacitance"), + OPU("qbs", MOS9_QBS, IF_REAL, "Bulk-Source charge storage"), + OPU("qgs", MOS9_QGS, IF_REAL, "Gate-Source charge storage"), + OPU("qgd", MOS9_QGD, IF_REAL, "Gate-Drain charge storage"), + OPU("qgb", MOS9_QGB, IF_REAL, "Gate-Bulk charge storage"), + OPU("qbd", MOS9_QBD, IF_REAL, "Bulk-Drain charge storage"), + OPU("p", MOS9_POWER, IF_REAL, "Instantaneous power"), + OPU("sens_l_dc", MOS9_L_SENS_DC, IF_REAL, "dc sensitivity wrt length"), + OPU("sens_l_real",MOS9_L_SENS_REAL, IF_REAL, + "real part of ac sensitivity wrt length"), + OPU("sens_l_imag",MOS9_L_SENS_IMAG, IF_REAL, + "imag part of ac sensitivity wrt length"), + OPU("sens_l_cplx",MOS9_L_SENS_CPLX, IF_COMPLEX, "ac sensitivity wrt length"), + OPU("sens_l_mag", MOS9_L_SENS_MAG, IF_REAL, + "sensitivity wrt l of ac magnitude"), + OPU("sens_l_ph", MOS9_L_SENS_PH, IF_REAL, "sensitivity wrt l of ac phase"), + OPU("sens_w_dc", MOS9_W_SENS_DC, IF_REAL, "dc sensitivity wrt width"), + OPU("sens_w_real",MOS9_W_SENS_REAL, IF_REAL, + "real part of ac sensitivity wrt width"), + OPU("sens_w_imag",MOS9_W_SENS_IMAG, IF_REAL, + "imag part of ac sensitivity wrt width"), + OPU("sens_w_mag", MOS9_W_SENS_MAG, IF_REAL, + "sensitivity wrt w of ac magnitude"), + OPU("sens_w_ph", MOS9_W_SENS_PH, IF_REAL, "sensitivity wrt w of ac phase"), + OPU("sens_w_cplx",MOS9_W_SENS_CPLX, IF_COMPLEX, "ac sensitivity wrt width") +}; + +IFparm MOS9mPTable[] = { /* model parameters */ + OP("type", MOS9_MOD_TYPE, IF_STRING ,"N-channel or P-channel MOS"), + IP("nmos", MOS9_MOD_NMOS, IF_FLAG ,"N type MOSfet model"), + IP("pmos", MOS9_MOD_PMOS, IF_FLAG ,"P type MOSfet model"), + IOP("vto", MOS9_MOD_VTO, IF_REAL ,"Threshold voltage"), + IOPR("vt0", MOS9_MOD_VTO, IF_REAL ,"Threshold voltage"), + IOP("kp", MOS9_MOD_KP, IF_REAL ,"Transconductance parameter"), + IOP("gamma", MOS9_MOD_GAMMA, IF_REAL ,"Bulk threshold parameter"), + IOP("phi", MOS9_MOD_PHI, IF_REAL ,"Surface potential"), + IOP("rd", MOS9_MOD_RD, IF_REAL ,"Drain ohmic resistance"), + IOP("rs", MOS9_MOD_RS, IF_REAL ,"Source ohmic resistance"), + IOPA("cbd", MOS9_MOD_CBD, IF_REAL ,"B-D junction capacitance"), + IOPA("cbs", MOS9_MOD_CBS, IF_REAL ,"B-S junction capacitance"), + IOP("is", MOS9_MOD_IS, IF_REAL ,"Bulk junction sat. current"), + IOP("pb", MOS9_MOD_PB, IF_REAL ,"Bulk junction potential"), + IOPA("cgso", MOS9_MOD_CGSO, IF_REAL ,"Gate-source overlap cap."), + IOPA("cgdo", MOS9_MOD_CGDO, IF_REAL ,"Gate-drain overlap cap."), + IOPA("cgbo", MOS9_MOD_CGBO, IF_REAL ,"Gate-bulk overlap cap."), + IOP("rsh", MOS9_MOD_RSH, IF_REAL ,"Sheet resistance"), + IOPA("cj", MOS9_MOD_CJ, IF_REAL ,"Bottom junction cap per area"), + IOP("mj", MOS9_MOD_MJ, IF_REAL ,"Bottom grading coefficient"), + IOPA("cjsw", MOS9_MOD_CJSW, IF_REAL ,"Side junction cap per area"), + IOP("mjsw", MOS9_MOD_MJSW, IF_REAL ,"Side grading coefficient"), + IOPU("js", MOS9_MOD_JS, IF_REAL ,"Bulk jct. sat. current density"), + IOP("tox", MOS9_MOD_TOX, IF_REAL ,"Oxide thickness"), + IOP("ld", MOS9_MOD_LD, IF_REAL ,"Lateral diffusion"), + IOP("xl", MOS9_MOD_XL, IF_REAL ,"Length mask adjustment"), + IOP("wd", MOS9_MOD_WD, IF_REAL ,"Width Narrowing (Diffusion)"), + IOP("xw", MOS9_MOD_XW, IF_REAL ,"Width mask adjustment"), + IOPU("delvto", MOS9_MOD_DELVTO, IF_REAL ,"Threshold voltage Adjust"), + IOPR("delvt0", MOS9_MOD_DELVTO, IF_REAL ,"Threshold voltage Adjust"), + IOP("u0", MOS9_MOD_U0, IF_REAL ,"Surface mobility"), + IOPR("uo", MOS9_MOD_U0, IF_REAL ,"Surface mobility"), + IOP("fc", MOS9_MOD_FC, IF_REAL ,"Forward bias jct. fit parm."), + IOP("nsub", MOS9_MOD_NSUB, IF_REAL ,"Substrate doping"), + IOP("tpg", MOS9_MOD_TPG, IF_INTEGER,"Gate type"), + IOP("nss", MOS9_MOD_NSS, IF_REAL ,"Surface state density"), + IOP("vmax", MOS9_MOD_VMAX, IF_REAL ,"Maximum carrier drift velocity"), + IOP("xj", MOS9_MOD_XJ, IF_REAL ,"Junction depth"), + IOP("nfs", MOS9_MOD_NFS, IF_REAL ,"Fast surface state density"), + IOP("xd", MOS9_MOD_XD, IF_REAL ,"Depletion layer width"), + IOP("alpha", MOS9_MOD_ALPHA, IF_REAL ,"Alpha"), + IOP("eta", MOS9_MOD_ETA, IF_REAL ,"Vds dependence of threshold voltage"), + IOP("delta", MOS9_MOD_DELTA, IF_REAL ,"Width effect on threshold"), + IOPR("input_delta", MOS9_DELTA, IF_REAL ,""), + IOP("theta", MOS9_MOD_THETA, IF_REAL ,"Vgs dependence on mobility"), + IOP("kappa", MOS9_MOD_KAPPA, IF_REAL ,"Kappa"), + IOPU("tnom", MOS9_MOD_TNOM, IF_REAL ,"Parameter measurement temperature"), + IOP("kf", MOS9_MOD_KF, IF_REAL ,"Flicker noise coefficient"), + IOP("af", MOS9_MOD_AF, IF_REAL ,"Flicker noise exponent") +}; + +char *MOS9names[] = { + "Drain", + "Gate", + "Source", + "Bulk" +}; + +int MOS9nSize = NUMELEMS(MOS9names); +int MOS9pTSize = NUMELEMS(MOS9pTable); +int MOS9mPTSize = NUMELEMS(MOS9mPTable); +int MOS9iSize = sizeof(MOS9instance); +int MOS9mSize = sizeof(MOS9model); diff --git a/src/spicelib/devices/mos9/mos9acld.c b/src/spicelib/devices/mos9/mos9acld.c new file mode 100644 index 000000000..b99965dec --- /dev/null +++ b/src/spicelib/devices/mos9/mos9acld.c @@ -0,0 +1,128 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Alan Gillespie +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos9defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS9acLoad(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + MOS9model *model = (MOS9model *)inModel; + MOS9instance *here; + int xnrm; + int xrev; + double EffectiveLength; + double EffectiveWidth; + double xgs; + double xgd; + double xgb; + double xbd; + double xbs; + double capgs; + double capgd; + double capgb; + double GateBulkOverlapCap; + double GateDrainOverlapCap; + double GateSourceOverlapCap; + + for( ; model != NULL; model = model->MOS9nextModel) { + for(here = model->MOS9instances; here!= NULL; + here = here->MOS9nextInstance) { + + if (here->MOS9mode < 0) { + xnrm=0; + xrev=1; + } else { + xnrm=1; + xrev=0; + } + /* + * charge oriented model parameters + */ + EffectiveWidth=here->MOS9w-2*model->MOS9widthNarrow+ + model->MOS9widthAdjust; + EffectiveLength=here->MOS9l - 2*model->MOS9latDiff+ + model->MOS9lengthAdjust; + GateSourceOverlapCap = model->MOS9gateSourceOverlapCapFactor * + here->MOS9m * EffectiveWidth; + GateDrainOverlapCap = model->MOS9gateDrainOverlapCapFactor * + here->MOS9m * EffectiveWidth; + GateBulkOverlapCap = model->MOS9gateBulkOverlapCapFactor * + here->MOS9m * EffectiveLength; + + + /* + * meyer"s model parameters + */ + capgs = ( *(ckt->CKTstate0+here->MOS9capgs)+ + *(ckt->CKTstate0+here->MOS9capgs) + + GateSourceOverlapCap ); + capgd = ( *(ckt->CKTstate0+here->MOS9capgd)+ + *(ckt->CKTstate0+here->MOS9capgd) + + GateDrainOverlapCap ); + capgb = ( *(ckt->CKTstate0+here->MOS9capgb)+ + *(ckt->CKTstate0+here->MOS9capgb) + + GateBulkOverlapCap ); + xgs = capgs * ckt->CKTomega; + xgd = capgd * ckt->CKTomega; + xgb = capgb * ckt->CKTomega; + xbd = here->MOS9capbd * ckt->CKTomega; + xbs = here->MOS9capbs * ckt->CKTomega; + + /* + * load matrix + */ + + *(here->MOS9GgPtr +1) += xgd+xgs+xgb; + *(here->MOS9BbPtr +1) += xgb+xbd+xbs; + *(here->MOS9DPdpPtr +1) += xgd+xbd; + *(here->MOS9SPspPtr +1) += xgs+xbs; + *(here->MOS9GbPtr +1) -= xgb; + *(here->MOS9GdpPtr +1) -= xgd; + *(here->MOS9GspPtr +1) -= xgs; + *(here->MOS9BgPtr +1) -= xgb; + *(here->MOS9BdpPtr +1) -= xbd; + *(here->MOS9BspPtr +1) -= xbs; + *(here->MOS9DPgPtr +1) -= xgd; + *(here->MOS9DPbPtr +1) -= xbd; + *(here->MOS9SPgPtr +1) -= xgs; + *(here->MOS9SPbPtr +1) -= xbs; + *(here->MOS9DdPtr) += here->MOS9drainConductance; + *(here->MOS9SsPtr) += here->MOS9sourceConductance; + *(here->MOS9BbPtr) += here->MOS9gbd+here->MOS9gbs; + *(here->MOS9DPdpPtr) += here->MOS9drainConductance+ + here->MOS9gds+here->MOS9gbd+ + xrev*(here->MOS9gm+here->MOS9gmbs); + *(here->MOS9SPspPtr) += here->MOS9sourceConductance+ + here->MOS9gds+here->MOS9gbs+ + xnrm*(here->MOS9gm+here->MOS9gmbs); + *(here->MOS9DdpPtr) -= here->MOS9drainConductance; + *(here->MOS9SspPtr) -= here->MOS9sourceConductance; + *(here->MOS9BdpPtr) -= here->MOS9gbd; + *(here->MOS9BspPtr) -= here->MOS9gbs; + *(here->MOS9DPdPtr) -= here->MOS9drainConductance; + *(here->MOS9DPgPtr) += (xnrm-xrev)*here->MOS9gm; + *(here->MOS9DPbPtr) += -here->MOS9gbd+(xnrm-xrev)*here->MOS9gmbs; + *(here->MOS9DPspPtr) -= here->MOS9gds+ + xnrm*(here->MOS9gm+here->MOS9gmbs); + *(here->MOS9SPgPtr) -= (xnrm-xrev)*here->MOS9gm; + *(here->MOS9SPsPtr) -= here->MOS9sourceConductance; + *(here->MOS9SPbPtr) -= here->MOS9gbs+(xnrm-xrev)*here->MOS9gmbs; + *(here->MOS9SPdpPtr) -= here->MOS9gds+ + xrev*(here->MOS9gm+here->MOS9gmbs); + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos9/mos9ask.c b/src/spicelib/devices/mos9/mos9ask.c new file mode 100644 index 000000000..c82b80abd --- /dev/null +++ b/src/spicelib/devices/mos9/mos9ask.c @@ -0,0 +1,444 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Mathew Lew and Thomas L. Quarles +Modified: Alan Gillespie +**********/ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "mos9defs.h" +#include "sperror.h" +#include "suffix.h" + +/*ARGSUSED*/ +int +MOS9ask(ckt,inst,which,value,select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + MOS9instance *here = (MOS9instance *)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 MOS9_TEMP: + value->rValue = here->MOS9temp-CONSTCtoK; + return(OK); + case MOS9_CGS: + value->rValue = 2* *(ckt->CKTstate0 + here->MOS9capgs); + return(OK); + case MOS9_CGD: + value->rValue = 2* *(ckt->CKTstate0 + here->MOS9capgd); + return(OK); + case MOS9_M: + value->rValue = here->MOS9m; + return(OK); + case MOS9_L: + value->rValue = here->MOS9l; + return(OK); + case MOS9_W: + value->rValue = here->MOS9w; + return(OK); + case MOS9_AS: + value->rValue = here->MOS9sourceArea; + return(OK); + case MOS9_AD: + value->rValue = here->MOS9drainArea; + return(OK); + case MOS9_PS: + value->rValue = here->MOS9sourcePerimiter; + return(OK); + case MOS9_PD: + value->rValue = here->MOS9drainPerimiter; + return(OK); + case MOS9_NRS: + value->rValue = here->MOS9sourceSquares; + return(OK); + case MOS9_NRD: + value->rValue = here->MOS9drainSquares; + return(OK); + case MOS9_OFF: + value->rValue = here->MOS9off; + return(OK); + case MOS9_IC_VBS: + value->rValue = here->MOS9icVBS; + return(OK); + case MOS9_IC_VDS: + value->rValue = here->MOS9icVDS; + return(OK); + case MOS9_IC_VGS: + value->rValue = here->MOS9icVGS; + return(OK); + case MOS9_DNODE: + value->iValue = here->MOS9dNode; + return(OK); + case MOS9_GNODE: + value->iValue = here->MOS9gNode; + return(OK); + case MOS9_SNODE: + value->iValue = here->MOS9sNode; + return(OK); + case MOS9_BNODE: + value->iValue = here->MOS9bNode; + return(OK); + case MOS9_DNODEPRIME: + value->iValue = here->MOS9dNodePrime; + return(OK); + case MOS9_SNODEPRIME: + value->iValue = here->MOS9sNodePrime; + return(OK); + case MOS9_SOURCECONDUCT: + value->rValue = here->MOS9sourceConductance; + return(OK); + case MOS9_DRAINCONDUCT: + value->rValue = here->MOS9drainConductance; + return(OK); + case MOS9_SOURCERESIST: + if (here->MOS9sNodePrime != here->MOS9sNode) + value->rValue = 1.0 / here->MOS9sourceConductance; + else + value->rValue = 0.0; + return(OK); + case MOS9_DRAINRESIST: + if (here->MOS9dNodePrime != here->MOS9dNode) + value->rValue = 1.0 / here->MOS9drainConductance; + else + value->rValue = 0.0; + return(OK); + case MOS9_VON: + value->rValue = here->MOS9von; + return(OK); + case MOS9_VDSAT: + value->rValue = here->MOS9vdsat; + return(OK); + case MOS9_SOURCEVCRIT: + value->rValue = here->MOS9sourceVcrit; + return(OK); + case MOS9_DRAINVCRIT: + value->rValue = here->MOS9drainVcrit; + return(OK); + case MOS9_CD: + value->rValue = here->MOS9cd; + return(OK); + case MOS9_CBS: + value->rValue = here->MOS9cbs; + return(OK); + case MOS9_CBD: + value->rValue = here->MOS9cbd; + return(OK); + case MOS9_GMBS: + value->rValue = here->MOS9gmbs; + return(OK); + case MOS9_GM: + value->rValue = here->MOS9gm; + return(OK); + case MOS9_GDS: + value->rValue = here->MOS9gds; + return(OK); + case MOS9_GBD: + value->rValue = here->MOS9gbd; + return(OK); + case MOS9_GBS: + value->rValue = here->MOS9gbs; + return(OK); + case MOS9_CAPBD: + value->rValue = here->MOS9capbd; + return(OK); + case MOS9_CAPBS: + value->rValue = here->MOS9capbs; + return(OK); + case MOS9_CAPZEROBIASBD: + value->rValue = here->MOS9Cbd; + return(OK); + case MOS9_CAPZEROBIASBDSW: + value->rValue = here->MOS9Cbdsw; + return(OK); + case MOS9_CAPZEROBIASBS: + value->rValue = here->MOS9Cbs; + return(OK); + case MOS9_CAPZEROBIASBSSW: + value->rValue = here->MOS9Cbssw; + return(OK); + case MOS9_VBD: + value->rValue = *(ckt->CKTstate0 + here->MOS9vbd); + return(OK); + case MOS9_VBS: + value->rValue = *(ckt->CKTstate0 + here->MOS9vbs); + return(OK); + case MOS9_VGS: + value->rValue = *(ckt->CKTstate0 + here->MOS9vgs); + return(OK); + case MOS9_VDS: + value->rValue = *(ckt->CKTstate0 + here->MOS9vds); + return(OK); + case MOS9_CAPGS: + value->rValue = 2* *(ckt->CKTstate0 + here->MOS9capgs); +/* add overlap capacitance */ + value->rValue += (here->MOS9modPtr->MOS9gateSourceOverlapCapFactor) + * here->MOS9m + * (here->MOS9w + +here->MOS9modPtr->MOS9widthAdjust + -2*(here->MOS9modPtr->MOS9widthNarrow)); + return(OK); + case MOS9_QGS: + value->rValue = *(ckt->CKTstate0 + here->MOS9qgs); + return(OK); + case MOS9_CQGS: + value->rValue = *(ckt->CKTstate0 + here->MOS9cqgs); + return(OK); + case MOS9_CAPGD: + value->rValue = 2* *(ckt->CKTstate0 + here->MOS9capgd); +/* add overlap capacitance */ + value->rValue += (here->MOS9modPtr->MOS9gateDrainOverlapCapFactor) + * here->MOS9m + * (here->MOS9w + +here->MOS9modPtr->MOS9widthAdjust + -2*(here->MOS9modPtr->MOS9widthNarrow)); + return(OK); + case MOS9_QGD: + value->rValue = *(ckt->CKTstate0 + here->MOS9qgd); + return(OK); + case MOS9_CQGD: + value->rValue = *(ckt->CKTstate0 + here->MOS9cqgd); + return(OK); + case MOS9_CAPGB: + value->rValue = 2* *(ckt->CKTstate0 + here->MOS9capgb); +/* add overlap capacitance */ + value->rValue += (here->MOS9modPtr->MOS9gateBulkOverlapCapFactor) + * here->MOS9m + * (here->MOS9l + +here->MOS9modPtr->MOS9lengthAdjust + -2*(here->MOS9modPtr->MOS9latDiff)); + return(OK); + case MOS9_QGB: + value->rValue = *(ckt->CKTstate0 + here->MOS9qgb); + return(OK); + case MOS9_CQGB: + value->rValue = *(ckt->CKTstate0 + here->MOS9cqgb); + return(OK); + case MOS9_QBD: + value->rValue = *(ckt->CKTstate0 + here->MOS9qbd); + return(OK); + case MOS9_CQBD: + value->rValue = *(ckt->CKTstate0 + here->MOS9cqbd); + return(OK); + case MOS9_QBS: + value->rValue = *(ckt->CKTstate0 + here->MOS9qbs); + return(OK); + case MOS9_CQBS: + value->rValue = *(ckt->CKTstate0 + here->MOS9cqbs); + return(OK); + case MOS9_L_SENS_DC: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_Sap[select->iValue + 1]+ + here->MOS9senParmNo); + } + return(OK); + case MOS9_L_SENS_REAL: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS9senParmNo); + } + return(OK); + case MOS9_L_SENS_IMAG: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS9senParmNo); + } + return(OK); + case MOS9_L_SENS_MAG: + if(ckt->CKTsenInfo){ + 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->MOS9senParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS9senParmNo); + value->rValue = (vr * sr + vi * si)/vm; + } + return(OK); + case MOS9_L_SENS_PH: + if(ckt->CKTsenInfo){ + 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->MOS9senParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS9senParmNo); + value->rValue = (vr * si - vi * sr)/vm; + } + return(OK); + case MOS9_L_SENS_CPLX: + if(ckt->CKTsenInfo){ + value->cValue.real= + *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS9senParmNo); + value->cValue.imag= + *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS9senParmNo); + } + return(OK); + case MOS9_W_SENS_DC: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_Sap[select->iValue + 1]+ + here->MOS9senParmNo + here->MOS9sens_l); + } + return(OK); + case MOS9_W_SENS_REAL: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS9senParmNo + here->MOS9sens_l); + } + return(OK); + case MOS9_W_SENS_IMAG: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS9senParmNo + here->MOS9sens_l); + } + return(OK); + case MOS9_W_SENS_MAG: + if(ckt->CKTsenInfo){ + 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->MOS9senParmNo + here->MOS9sens_l); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS9senParmNo + here->MOS9sens_l); + value->rValue = (vr * sr + vi * si)/vm; + } + return(OK); + case MOS9_W_SENS_PH: + if(ckt->CKTsenInfo){ + 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->MOS9senParmNo + here->MOS9sens_l); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS9senParmNo + here->MOS9sens_l); + value->rValue = (vr * si - vi * sr)/vm; + } + return(OK); + case MOS9_W_SENS_CPLX: + if(ckt->CKTsenInfo){ + value->cValue.real= + *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS9senParmNo + here->MOS9sens_l); + value->cValue.imag= + *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS9senParmNo + here->MOS9sens_l); + } + return(OK); + case MOS9_CB : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "MOS9ask.c"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else { + value->rValue = here->MOS9cbd + here->MOS9cbs - *(ckt->CKTstate0 + + here->MOS9cqgb); + } + return(OK); + case MOS9_CG : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "MOS9ask.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->MOS9cqgb) + + *(ckt->CKTstate0 + here->MOS9cqgd) + *(ckt->CKTstate0 + + here->MOS9cqgs); + } + return(OK); + case MOS9_CS : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "MOS9ask.c"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else { + value->rValue = -here->MOS9cd; + value->rValue -= here->MOS9cbd + here->MOS9cbs - + *(ckt->CKTstate0 + here->MOS9cqgb); + if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && + !(ckt->CKTmode & MODETRANOP)) { + value->rValue -= *(ckt->CKTstate0 + here->MOS9cqgb) + + *(ckt->CKTstate0 + here->MOS9cqgd) + + *(ckt->CKTstate0 + here->MOS9cqgs); + } + } + return(OK); + case MOS9_POWER : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "MOS9ask.c"; + strcpy(errMsg,msg); + return(E_ASKPOWER); + } else { + double temp; + + value->rValue = here->MOS9cd * + *(ckt->CKTrhsOld + here->MOS9dNode); + value->rValue += (here->MOS9cbd + here->MOS9cbs - + *(ckt->CKTstate0 + here->MOS9cqgb)) * + *(ckt->CKTrhsOld + here->MOS9bNode); + if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && + !(ckt->CKTmode & MODETRANOP)) { + value->rValue += (*(ckt->CKTstate0 + here->MOS9cqgb) + + *(ckt->CKTstate0 + here->MOS9cqgd) + + *(ckt->CKTstate0 + here->MOS9cqgs)) * + *(ckt->CKTrhsOld + here->MOS9gNode); + } + temp = -here->MOS9cd; + temp -= here->MOS9cbd + here->MOS9cbs ; + if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && + !(ckt->CKTmode & MODETRANOP)) { + temp -= *(ckt->CKTstate0 + here->MOS9cqgb) + + *(ckt->CKTstate0 + here->MOS9cqgd) + + *(ckt->CKTstate0 + here->MOS9cqgs); + } + value->rValue += temp * *(ckt->CKTrhsOld + here->MOS9sNode); + } + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + diff --git a/src/spicelib/devices/mos9/mos9conv.c b/src/spicelib/devices/mos9/mos9conv.c new file mode 100644 index 000000000..84fd2d433 --- /dev/null +++ b/src/spicelib/devices/mos9/mos9conv.c @@ -0,0 +1,104 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Alan Gillespie +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos9defs.h" +#include "sperror.h" + +#include "suffix.h" + +int +MOS9convTest(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + MOS9model *model = (MOS9model *)inModel; + MOS9instance *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 = model->MOS9nextModel) { + for(here = model->MOS9instances; here!= NULL; + here = here->MOS9nextInstance) { + + vbs = model->MOS9type * ( + *(ckt->CKTrhs+here->MOS9bNode) - + *(ckt->CKTrhs+here->MOS9sNodePrime)); + vgs = model->MOS9type * ( + *(ckt->CKTrhs+here->MOS9gNode) - + *(ckt->CKTrhs+here->MOS9sNodePrime)); + vds = model->MOS9type * ( + *(ckt->CKTrhs+here->MOS9dNodePrime) - + *(ckt->CKTrhs+here->MOS9sNodePrime)); + vbd=vbs-vds; + vgd=vgs-vds; + vgdo = *(ckt->CKTstate0 + here->MOS9vgs) - + *(ckt->CKTstate0 + here->MOS9vds); + delvbs = vbs - *(ckt->CKTstate0 + here->MOS9vbs); + delvbd = vbd - *(ckt->CKTstate0 + here->MOS9vbd); + delvgs = vgs - *(ckt->CKTstate0 + here->MOS9vgs); + delvds = vds - *(ckt->CKTstate0 + here->MOS9vds); + delvgd = vgd-vgdo; + + /* these are needed for convergence testing */ + + if (here->MOS9mode >= 0) { + cdhat= + here->MOS9cd- + here->MOS9gbd * delvbd + + here->MOS9gmbs * delvbs + + here->MOS9gm * delvgs + + here->MOS9gds * delvds ; + } else { + cdhat= + here->MOS9cd - + ( here->MOS9gbd - + here->MOS9gmbs) * delvbd - + here->MOS9gm * delvgd + + here->MOS9gds * delvds ; + } + cbhat= + here->MOS9cbs + + here->MOS9cbd + + here->MOS9gbd * delvbd + + here->MOS9gbs * delvbs ; + /* + * check convergence + */ + tol=ckt->CKTreltol*MAX(fabs(cdhat),fabs(here->MOS9cd))+ + ckt->CKTabstol; + if (fabs(cdhat-here->MOS9cd) >= 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->MOS9cbs+here->MOS9cbd)) + + ckt->CKTabstol; + if (fabs(cbhat-(here->MOS9cbs+here->MOS9cbd)) > 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/mos9/mos9defs.h b/src/spicelib/devices/mos9/mos9defs.h new file mode 100644 index 000000000..3ce526c46 --- /dev/null +++ b/src/spicelib/devices/mos9/mos9defs.h @@ -0,0 +1,560 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Alan Gillespie +**********/ + +#ifndef MOS9 +#define MOS9 + +#include "ifsim.h" +#include "cktdefs.h" +#include "gendefs.h" +#include "complex.h" +#include "noisedef.h" + + /* declarations for level 9 MOSFETs */ + +/* information needed for each instance */ + +typedef struct sMOS9instance { + struct sMOS9model *MOS9modPtr; /* backpointer to model */ + struct sMOS9instance *MOS9nextInstance; /* pointer to next instance of + *current model*/ + IFuid MOS9name; /* pointer to character string naming this instance */ + int MOS9owner; /* number of owner process */ + int MOS9states; /* index into state table for this device */ + int MOS9dNode; /* number of the gate node of the mosfet */ + int MOS9gNode; /* number of the gate node of the mosfet */ + int MOS9sNode; /* number of the source node of the mosfet */ + int MOS9bNode; /* number of the bulk node of the mosfet */ + int MOS9dNodePrime; /* number of the internal drain node of the mosfet */ + int MOS9sNodePrime; /* number of the internal source node of the mosfet */ + + double MOS9m; /* parallel device multiplier */ + double MOS9l; /* the length of the channel region */ + double MOS9w; /* the width of the channel region */ + double MOS9drainArea; /* the area of the drain diffusion */ + double MOS9sourceArea; /* the area of the source diffusion */ + double MOS9drainSquares; /* the length of the drain in squares */ + double MOS9sourceSquares; /* the length of the source in squares */ + double MOS9drainPerimiter; + double MOS9sourcePerimiter; + double MOS9sourceConductance; /*conductance of source(or 0):set in setup*/ + double MOS9drainConductance; /*conductance of drain(or 0):set in setup*/ + double MOS9temp; /* operating temperature of this instance */ + + double MOS9tTransconductance; /* temperature corrected transconductance*/ + double MOS9tSurfMob; /* temperature corrected surface mobility */ + double MOS9tPhi; /* temperature corrected Phi */ + double MOS9tVto; /* temperature corrected Vto */ + double MOS9tSatCur; /* temperature corrected saturation Cur. */ + double MOS9tSatCurDens; /* temperature corrected saturation Cur. density*/ + double MOS9tCbd; /* temperature corrected B-D Capacitance */ + double MOS9tCbs; /* temperature corrected B-S Capacitance */ + double MOS9tCj; /* temperature corrected Bulk bottom Capacitance */ + double MOS9tCjsw; /* temperature corrected Bulk side Capacitance */ + double MOS9tBulkPot; /* temperature corrected Bulk potential */ + double MOS9tDepCap; /* temperature adjusted transition point in */ + /* the cureve matching Fc * Vj */ + double MOS9tVbi; /* temperature adjusted Vbi */ + + double MOS9icVBS; /* initial condition B-S voltage */ + double MOS9icVDS; /* initial condition D-S voltage */ + double MOS9icVGS; /* initial condition G-S voltage */ + double MOS9von; + double MOS9vdsat; + double MOS9sourceVcrit; /* vcrit for pos. vds */ + double MOS9drainVcrit; /* vcrit for neg. vds */ + double MOS9cd; + double MOS9cbs; + double MOS9cbd; + double MOS9gmbs; + double MOS9gm; + double MOS9gds; + double MOS9gbd; + double MOS9gbs; + double MOS9capbd; + double MOS9capbs; + double MOS9Cbd; + double MOS9Cbdsw; + double MOS9Cbs; + double MOS9Cbssw; + double MOS9f2d; + double MOS9f3d; + double MOS9f4d; + double MOS9f2s; + double MOS9f3s; + double MOS9f4s; + int MOS9mode; /* device mode : 1 = normal, -1 = inverse */ + + + unsigned MOS9off :1;/* non-zero to indicate device is off for dc analysis*/ + unsigned MOS9tempGiven :1; /* instance temperature specified */ + + unsigned MOS9mGiven :1; + + unsigned MOS9lGiven :1; + unsigned MOS9wGiven :1; + unsigned MOS9drainAreaGiven :1; + unsigned MOS9sourceAreaGiven :1; + unsigned MOS9drainSquaresGiven :1; + unsigned MOS9sourceSquaresGiven :1; + unsigned MOS9drainPerimiterGiven :1; + unsigned MOS9sourcePerimiterGiven :1; + unsigned MOS9dNodePrimeSet :1; + unsigned MOS9sNodePrimeSet :1; + unsigned MOS9icVBSGiven :1; + unsigned MOS9icVDSGiven :1; + unsigned MOS9icVGSGiven :1; + unsigned MOS9vonGiven :1; + unsigned MOS9vdsatGiven :1; + unsigned MOS9modeGiven :1; + + + double *MOS9DdPtr; /* pointer to sparse matrix element at + * (Drain node,drain node) */ + double *MOS9GgPtr; /* pointer to sparse matrix element at + * (gate node,gate node) */ + double *MOS9SsPtr; /* pointer to sparse matrix element at + * (source node,source node) */ + double *MOS9BbPtr; /* pointer to sparse matrix element at + * (bulk node,bulk node) */ + double *MOS9DPdpPtr; /* pointer to sparse matrix element at + * (drain prime node,drain prime node) */ + double *MOS9SPspPtr; /* pointer to sparse matrix element at + * (source prime node,source prime node) */ + double *MOS9DdpPtr; /* pointer to sparse matrix element at + * (drain node,drain prime node) */ + double *MOS9GbPtr; /* pointer to sparse matrix element at + * (gate node,bulk node) */ + double *MOS9GdpPtr; /* pointer to sparse matrix element at + * (gate node,drain prime node) */ + double *MOS9GspPtr; /* pointer to sparse matrix element at + * (gate node,source prime node) */ + double *MOS9SspPtr; /* pointer to sparse matrix element at + * (source node,source prime node) */ + double *MOS9BdpPtr; /* pointer to sparse matrix element at + * (bulk node,drain prime node) */ + double *MOS9BspPtr; /* pointer to sparse matrix element at + * (bulk node,source prime node) */ + double *MOS9DPspPtr; /* pointer to sparse matrix element at + * (drain prime node,source prime node) */ + double *MOS9DPdPtr; /* pointer to sparse matrix element at + * (drain prime node,drain node) */ + double *MOS9BgPtr; /* pointer to sparse matrix element at + * (bulk node,gate node) */ + double *MOS9DPgPtr; /* pointer to sparse matrix element at + * (drain prime node,gate node) */ + + double *MOS9SPgPtr; /* pointer to sparse matrix element at + * (source prime node,gate node) */ + double *MOS9SPsPtr; /* pointer to sparse matrix element at + * (source prime node,source node) */ + double *MOS9DPbPtr; /* pointer to sparse matrix element at + * (drain prime node,bulk node) */ + double *MOS9SPbPtr; /* pointer to sparse matrix element at + * (source prime node,bulk node) */ + double *MOS9SPdpPtr; /* pointer to sparse matrix element at + * (source prime node,drain prime node) */ + int MOS9senParmNo; /* parameter # for sensitivity use; + set equal to 0 if neither length + nor width of the mosfet is a design + parameter */ + unsigned MOS9sens_l :1; /* field which indicates whether + length of the mosfet is a design + parameter or not */ + unsigned MOS9sens_w :1; /* field which indicates whether + width of the mosfet is a design + parameter or not */ + unsigned MOS9senPertFlag :1; /* indictes whether the the parameter of + the particular instance is to be perturbed */ + double MOS9cgs; + double MOS9cgd; + double MOS9cgb; + double *MOS9sens; + +#define MOS9senGdpr MOS9sens +#define MOS9senGspr MOS9sens + 1 +#define MOS9senCgs MOS9sens + 2 /* contains pertured values of cgs */ +#define MOS9senCgd MOS9sens + 8 /* contains perturbed values of cgd*/ +#define MOS9senCgb MOS9sens + 14 /* contains perturbed values of cgb*/ +#define MOS9senCbd MOS9sens + 20 /* contains perturbed values of cbd*/ +#define MOS9senCbs MOS9sens + 26 /* contains perturbed values of cbs*/ +#define MOS9senGds MOS9sens + 32 /* contains perturbed values of gds*/ +#define MOS9senGbs MOS9sens + 38 /* contains perturbed values of gbs*/ +#define MOS9senGbd MOS9sens + 44 /* contains perturbed values of gbd*/ +#define MOS9senGm MOS9sens + 50 /* contains perturbed values of gm*/ +#define MOS9senGmbs MOS9sens + 56 /* contains perturbed values of gmbs*/ +#define MOS9dphigs_dl MOS9sens + 62 +#define MOS9dphigd_dl MOS9sens + 63 +#define MOS9dphigb_dl MOS9sens + 64 +#define MOS9dphibs_dl MOS9sens + 65 +#define MOS9dphibd_dl MOS9sens + 66 +#define MOS9dphigs_dw MOS9sens + 67 +#define MOS9dphigd_dw MOS9sens + 68 +#define MOS9dphigb_dw MOS9sens + 69 +#define MOS9dphibs_dw MOS9sens + 70 +#define MOS9dphibd_dw MOS9sens + 71 + + /* distortion stuff */ +/* + * naming convention: + * x = vgs + * y = vbs + * z = vds + * cdr = cdrain + */ + + +#define MOS9NDCOEFFS 30 + +#ifndef NODISTO + double MOS9dCoeffs[MOS9NDCOEFFS]; +#else /* NODISTO */ + double *MOS9dCoeffs; +#endif /* NODISTO */ + +#ifndef CONFIG + +#define capbs2 MOS9dCoeffs[0] +#define capbs3 MOS9dCoeffs[1] +#define capbd2 MOS9dCoeffs[2] +#define capbd3 MOS9dCoeffs[3] +#define gbs2 MOS9dCoeffs[4] +#define gbs3 MOS9dCoeffs[5] +#define gbd2 MOS9dCoeffs[6] +#define gbd3 MOS9dCoeffs[7] +#define capgb2 MOS9dCoeffs[8] +#define capgb3 MOS9dCoeffs[9] +#define cdr_x2 MOS9dCoeffs[10] +#define cdr_y2 MOS9dCoeffs[11] +#define cdr_z2 MOS9dCoeffs[12] +#define cdr_xy MOS9dCoeffs[13] +#define cdr_yz MOS9dCoeffs[14] +#define cdr_xz MOS9dCoeffs[15] +#define cdr_x3 MOS9dCoeffs[16] +#define cdr_y3 MOS9dCoeffs[17] +#define cdr_z3 MOS9dCoeffs[18] +#define cdr_x2z MOS9dCoeffs[19] +#define cdr_x2y MOS9dCoeffs[20] +#define cdr_y2z MOS9dCoeffs[21] +#define cdr_xy2 MOS9dCoeffs[22] +#define cdr_xz2 MOS9dCoeffs[23] +#define cdr_yz2 MOS9dCoeffs[24] +#define cdr_xyz MOS9dCoeffs[25] +#define capgs2 MOS9dCoeffs[26] +#define capgs3 MOS9dCoeffs[27] +#define capgd2 MOS9dCoeffs[28] +#define capgd3 MOS9dCoeffs[29] + +#endif + + /* end distortion coeffs. */ +/* indices to the array of MOSFET(3) noise sources */ + +#define MOS9RDNOIZ 0 +#define MOS9RSNOIZ 1 +#define MOS9IDNOIZ 2 +#define MOS9FLNOIZ 3 +#define MOS9TOTNOIZ 4 + +#define MOS9NSRCS 5 /* the number of MOSFET(9) noise sources */ + +#ifndef NONOISE + double MOS9nVar[NSTATVARS][MOS9NSRCS]; +#else /* NONOISE */ + double **MOS9nVar; +#endif /* NONOISE */ + +} MOS9instance ; + +#define MOS9vbd MOS9states+ 0 +#define MOS9vbs MOS9states+ 1 +#define MOS9vgs MOS9states+ 2 +#define MOS9vds MOS9states+ 3 + +/* meyer capacitances */ +#define MOS9capgs MOS9states+ 4 /* gate-source capacitor value */ +#define MOS9qgs MOS9states+ 5 /* gate-source capacitor charge */ +#define MOS9cqgs MOS9states+ 6 /* gate-source capacitor current */ + +#define MOS9capgd MOS9states+ 7 /* gate-drain capacitor value */ +#define MOS9qgd MOS9states+ 8 /* gate-drain capacitor charge */ +#define MOS9cqgd MOS9states+ 9 /* gate-drain capacitor current */ + +#define MOS9capgb MOS9states+ 10/* gate-bulk capacitor value */ +#define MOS9qgb MOS9states+ 11 /* gate-bulk capacitor charge */ +#define MOS9cqgb MOS9states+ 12 /* gate-bulk capacitor current */ + +/* diode capacitances */ +#define MOS9qbd MOS9states+ 13 /* bulk-drain capacitor charge */ +#define MOS9cqbd MOS9states+ 14 /* bulk-drain capacitor current */ + +#define MOS9qbs MOS9states+ 15 /* bulk-source capacitor charge */ +#define MOS9cqbs MOS9states+ 16 /* bulk-source capacitor current */ + +#define MOS9NUMSTATES 17 + + +#define MOS9sensxpgs MOS9states+17 /* charge sensitivities and their derivatives + +18 for the derivatives - pointer to the + beginning of the array */ +#define MOS9sensxpgd MOS9states+19 +#define MOS9sensxpgb MOS9states+21 +#define MOS9sensxpbs MOS9states+23 +#define MOS9sensxpbd MOS9states+25 + +#define MOS9numSenStates 10 + + +/* per model data */ + + /* NOTE: parameters marked 'input - use xxxx' are paramters for + * which a temperature correction is applied in MOS9temp, thus + * the MOS9xxxx value in the per-instance structure should be used + * instead in all calculations + */ + +typedef struct sMOS9model { /* model structure for a resistor */ + int MOS9modType; /* type index of this device type */ + struct sMOS9model *MOS9nextModel; /* pointer to next possible model + *in linked list */ + MOS9instance * MOS9instances; /* pointer to list of instances + * that have this model */ + IFuid MOS9modName; /* pointer to character string naming this model */ + int MOS9type; /* device type : 1 = nmos, -1 = pmos */ + double MOS9tnom; /* temperature at which parameters measured */ + double MOS9latDiff; + double MOS9lengthAdjust; /* New parm: mask adjustment to length */ + double MOS9widthNarrow; /* New parm to reduce effective width */ + double MOS9widthAdjust; /* New parm: mask adjustment to width */ + double MOS9delvt0; /* New parm: adjustment to calculated vtO */ + double MOS9jctSatCurDensity; /* input - use tSatCurDens*/ + double MOS9jctSatCur; /* input - use tSatCur instead */ + double MOS9drainResistance; + double MOS9sourceResistance; + double MOS9sheetResistance; + double MOS9transconductance; /* input - use tTransconductance */ + double MOS9gateSourceOverlapCapFactor; + double MOS9gateDrainOverlapCapFactor; + double MOS9gateBulkOverlapCapFactor; + double MOS9oxideCapFactor; + double MOS9vt0; /* input - use tVto */ + double MOS9capBD; /* input - use tCbs */ + double MOS9capBS; /* input - use tCbd */ + double MOS9bulkCapFactor; /* input - use tCj */ + double MOS9sideWallCapFactor; /* input - use tCjsw */ + double MOS9bulkJctPotential; /* input - use tBulkPot */ + double MOS9bulkJctBotGradingCoeff; + double MOS9bulkJctSideGradingCoeff; + double MOS9fwdCapDepCoeff; + double MOS9phi; /* input - use tPhi */ + double MOS9gamma; + double MOS9substrateDoping; + int MOS9gateType; + double MOS9surfaceStateDensity; + double MOS9oxideThickness; + double MOS9surfaceMobility; /* input - use tSurfMob */ + double MOS9eta; + double MOS9junctionDepth; + double MOS9coeffDepLayWidth; /* xd */ + double MOS9narrowFactor; /* delta */ + double MOS9delta; /* input delta */ + double MOS9fastSurfaceStateDensity; /* nfs */ + double MOS9theta; /* theta */ + double MOS9maxDriftVel; /* vmax */ + double MOS9alpha; /* alpha */ + double MOS9kappa; /* kappa */ + double MOS9fNcoef; + double MOS9fNexp; + + unsigned MOS9typeGiven :1; + unsigned MOS9latDiffGiven :1; + unsigned MOS9lengthAdjustGiven :1; + unsigned MOS9widthNarrowGiven :1; + unsigned MOS9widthAdjustGiven :1; + unsigned MOS9delvt0Given :1; + unsigned MOS9jctSatCurDensityGiven :1; + unsigned MOS9jctSatCurGiven :1; + unsigned MOS9drainResistanceGiven :1; + unsigned MOS9sourceResistanceGiven :1; + unsigned MOS9sheetResistanceGiven :1; + unsigned MOS9transconductanceGiven :1; + unsigned MOS9gateSourceOverlapCapFactorGiven :1; + unsigned MOS9gateDrainOverlapCapFactorGiven :1; + unsigned MOS9gateBulkOverlapCapFactorGiven :1; + unsigned MOS9vt0Given :1; + unsigned MOS9capBDGiven :1; + unsigned MOS9capBSGiven :1; + unsigned MOS9bulkCapFactorGiven :1; + unsigned MOS9sideWallCapFactorGiven :1; + unsigned MOS9bulkJctPotentialGiven :1; + unsigned MOS9bulkJctBotGradingCoeffGiven :1; + unsigned MOS9bulkJctSideGradingCoeffGiven :1; + unsigned MOS9fwdCapDepCoeffGiven :1; + unsigned MOS9phiGiven :1; + unsigned MOS9gammaGiven :1; + unsigned MOS9substrateDopingGiven :1; + unsigned MOS9gateTypeGiven :1; + unsigned MOS9surfaceStateDensityGiven :1; + unsigned MOS9oxideThicknessGiven :1; + unsigned MOS9surfaceMobilityGiven :1; + unsigned MOS9etaGiven :1; + unsigned MOS9junctionDepthGiven :1; + unsigned MOS9deltaGiven :1; /* delta */ + unsigned MOS9fastSurfaceStateDensityGiven :1; /* nfs */ + unsigned MOS9thetaGiven :1; /* theta */ + unsigned MOS9maxDriftVelGiven :1; /* vmax */ + unsigned MOS9kappaGiven :1; /* kappa */ + unsigned MOS9tnomGiven :1; /* Tnom was given? */ + unsigned MOS9fNcoefGiven :1; + unsigned MOS9fNexpGiven :1; + +} MOS9model; + +#ifndef NMOS +#define NMOS 1 +#define PMOS -1 +#endif /*NMOS*/ + +/* device parameters */ +#define MOS9_W 1 +#define MOS9_L 2 +#define MOS9_AS 3 +#define MOS9_AD 4 +#define MOS9_PS 5 +#define MOS9_PD 6 +#define MOS9_NRS 7 +#define MOS9_NRD 8 +#define MOS9_OFF 9 +#define MOS9_IC 10 +#define MOS9_IC_VBS 11 +#define MOS9_IC_VDS 12 +#define MOS9_IC_VGS 13 +#define MOS9_W_SENS 14 +#define MOS9_L_SENS 15 +#define MOS9_CB 16 +#define MOS9_CG 17 +#define MOS9_CS 18 +#define MOS9_POWER 19 +#define MOS9_CGS 20 +#define MOS9_CGD 21 +#define MOS9_DNODE 22 +#define MOS9_GNODE 23 +#define MOS9_SNODE 24 +#define MOS9_BNODE 25 +#define MOS9_DNODEPRIME 26 +#define MOS9_SNODEPRIME 27 +#define MOS9_SOURCECONDUCT 28 +#define MOS9_DRAINCONDUCT 29 +#define MOS9_VON 30 +#define MOS9_VDSAT 31 +#define MOS9_SOURCEVCRIT 32 +#define MOS9_DRAINVCRIT 33 +#define MOS9_CD 34 +#define MOS9_CBS 35 +#define MOS9_CBD 36 +#define MOS9_GMBS 37 +#define MOS9_GM 38 +#define MOS9_GDS 39 +#define MOS9_GBD 40 +#define MOS9_GBS 41 +#define MOS9_CAPBD 42 +#define MOS9_CAPBS 43 +#define MOS9_CAPZEROBIASBD 44 +#define MOS9_CAPZEROBIASBDSW 45 +#define MOS9_CAPZEROBIASBS 46 +#define MOS9_CAPZEROBIASBSSW 47 +#define MOS9_VBD 48 +#define MOS9_VBS 49 +#define MOS9_VGS 50 +#define MOS9_VDS 51 +#define MOS9_CAPGS 52 +#define MOS9_QGS 53 +#define MOS9_CQGS 54 +#define MOS9_CAPGD 55 +#define MOS9_QGD 56 +#define MOS9_CQGD 57 +#define MOS9_CAPGB 58 +#define MOS9_QGB 59 +#define MOS9_CQGB 60 +#define MOS9_QBD 61 +#define MOS9_CQBD 62 +#define MOS9_QBS 63 +#define MOS9_CQBS 64 +#define MOS9_W_SENS_REAL 65 +#define MOS9_W_SENS_IMAG 66 +#define MOS9_W_SENS_MAG 67 +#define MOS9_W_SENS_PH 68 +#define MOS9_W_SENS_CPLX 69 +#define MOS9_L_SENS_REAL 70 +#define MOS9_L_SENS_IMAG 71 +#define MOS9_L_SENS_MAG 72 +#define MOS9_L_SENS_PH 73 +#define MOS9_L_SENS_CPLX 74 +#define MOS9_W_SENS_DC 75 +#define MOS9_L_SENS_DC 76 +#define MOS9_TEMP 77 +#define MOS9_SOURCERESIST 78 +#define MOS9_DRAINRESIST 79 +#define MOS9_M 80 + +/* model parameters */ +#define MOS9_MOD_VTO 101 +#define MOS9_MOD_KP 102 +#define MOS9_MOD_GAMMA 103 +#define MOS9_MOD_PHI 104 +#define MOS9_MOD_RD 105 +#define MOS9_MOD_RS 106 +#define MOS9_MOD_CBD 107 +#define MOS9_MOD_CBS 108 +#define MOS9_MOD_IS 109 +#define MOS9_MOD_PB 110 +#define MOS9_MOD_CGSO 111 +#define MOS9_MOD_CGDO 112 +#define MOS9_MOD_CGBO 113 +#define MOS9_MOD_RSH 114 +#define MOS9_MOD_CJ 115 +#define MOS9_MOD_MJ 116 +#define MOS9_MOD_CJSW 117 +#define MOS9_MOD_MJSW 118 +#define MOS9_MOD_JS 119 +#define MOS9_MOD_TOX 120 +#define MOS9_MOD_LD 121 +#define MOS9_MOD_U0 122 +#define MOS9_MOD_FC 123 +#define MOS9_MOD_NSUB 124 +#define MOS9_MOD_TPG 125 +#define MOS9_MOD_NSS 126 +#define MOS9_MOD_ETA 127 +#define MOS9_MOD_DELTA 128 +#define MOS9_MOD_NFS 129 +#define MOS9_MOD_THETA 130 +#define MOS9_MOD_VMAX 131 +#define MOS9_MOD_KAPPA 132 +#define MOS9_MOD_NMOS 133 +#define MOS9_MOD_PMOS 134 +#define MOS9_MOD_XJ 135 +#define MOS9_MOD_UEXP 136 +#define MOS9_MOD_NEFF 137 +#define MOS9_MOD_XD 138 +#define MOS9_MOD_ALPHA 139 +#define MOS9_DELTA 140 +#define MOS9_MOD_TNOM 141 +#define MOS9_MOD_KF 142 +#define MOS9_MOD_AF 143 +#define MOS9_MOD_TYPE 144 +#define MOS9_MOD_XL 145 +#define MOS9_MOD_WD 146 +#define MOS9_MOD_XW 147 +#define MOS9_MOD_DELVTO 148 + +/* device questions */ + + +/* model questions */ + +#include "mos9ext.h" + +#endif /*MOS9*/ diff --git a/src/spicelib/devices/mos9/mos9del.c b/src/spicelib/devices/mos9/mos9del.c new file mode 100644 index 000000000..b00d04d7b --- /dev/null +++ b/src/spicelib/devices/mos9/mos9del.c @@ -0,0 +1,39 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Alan Gillespie +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "mos9defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS9delete(inModel,name,inst) + GENmodel *inModel; + IFuid name; + GENinstance **inst; +{ + MOS9model *model = (MOS9model *)inModel; + MOS9instance **fast = (MOS9instance **)inst; + MOS9instance **prev = NULL; + MOS9instance *here; + + for( ; model ; model = model->MOS9nextModel) { + prev = &(model->MOS9instances); + for(here = *prev; here ; here = *prev) { + if(here->MOS9name == name || (fast && here==*fast) ) { + *prev= here->MOS9nextInstance; + FREE(here); + return(OK); + } + prev = &(here->MOS9nextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/mos9/mos9dest.c b/src/spicelib/devices/mos9/mos9dest.c new file mode 100644 index 000000000..ea701111d --- /dev/null +++ b/src/spicelib/devices/mos9/mos9dest.c @@ -0,0 +1,40 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Alan Gillespie +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "mos9defs.h" +#include "suffix.h" + + +void +MOS9destroy(inModel) + GENmodel **inModel; +{ + MOS9model **model = (MOS9model **)inModel; + MOS9instance *here; + MOS9instance *prev = NULL; + MOS9model *mod = *model; + MOS9model *oldmod = NULL; + + for( ; mod ; mod = mod->MOS9nextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (MOS9instance *)NULL; + for(here = mod->MOS9instances ; here ; here = here->MOS9nextInstance) { + if(prev){ + if(prev->MOS9sens) FREE(prev->MOS9sens); + FREE(prev); + } + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/mos9/mos9dist.c b/src/spicelib/devices/mos9/mos9dist.c new file mode 100644 index 000000000..9a93f45bb --- /dev/null +++ b/src/spicelib/devices/mos9/mos9dist.c @@ -0,0 +1,1386 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jaijeet S Roychowdhury +Modified: Alan Gillespie +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos9defs.h" +#include "sperror.h" +#include "distodef.h" +#include "suffix.h" + +int +MOS9disto(mode,genmodel,ckt) + GENmodel *genmodel; + CKTcircuit *ckt; + int mode; + +/* assuming here that ckt->CKTomega has been initialised to + * the correct value + */ +{ + MOS9model *model = (MOS9model *) 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; + register MOS9instance *here; + +if (mode == D_SETUP) + return(MOS9dSetup(model,ckt)); + +if ((mode == D_TWOF1) || (mode == D_THRF1) || + (mode == D_F1PF2) || (mode == D_F1MF2) || + (mode == D_2F1MF2)) { + + /* loop through all the MOS9 models */ +for( ; model != NULL; model = model->MOS9nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MOS9instances; here != NULL ; + here=here->MOS9nextInstance) { + + + + /* loading starts here */ + + switch (mode) { + case D_TWOF1: + /* x = vgs, y = vbs z = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->MOS9gNode)) - + *(job->r1H1ptr + (here->MOS9sNodePrime)); + i1h1x = *(job->i1H1ptr + (here->MOS9gNode)) - + *(job->i1H1ptr + (here->MOS9sNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->MOS9bNode)) - + *(job->r1H1ptr + (here->MOS9sNodePrime)); + i1h1y = *(job->i1H1ptr + (here->MOS9bNode)) - + *(job->i1H1ptr + (here->MOS9sNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->MOS9dNodePrime)) - + *(job->r1H1ptr + (here->MOS9sNodePrime)); + i1h1z = *(job->i1H1ptr + (here->MOS9dNodePrime)) - + *(job->i1H1ptr + (here->MOS9sNodePrime)); + + /* 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->MOS9dNodePrime)) -= temp; + *(ckt->CKTirhs + (here->MOS9dNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->MOS9sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9sNodePrime)) += itemp; + + /* cdrain term over */ + + /* loading gbs term */ + + temp = D1n2F1(here->gbs2, + r1h1y, + i1h1y); + + itemp = D1i2F1(here->gbs2, + r1h1y, + i1h1y); + + + *(ckt->CKTrhs + (here->MOS9bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9sNodePrime)) += 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->MOS9bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9dNodePrime)) += 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->MOS9gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9sNodePrime)) += 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->MOS9gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9dNodePrime)) += 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->MOS9gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9bNode)) += temp; + *(ckt->CKTirhs + (here->MOS9bNode)) += 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->MOS9bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9sNodePrime)) += 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->MOS9bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9dNodePrime)) += 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->MOS9gNode)) - + *(job->r1H1ptr + (here->MOS9sNodePrime)); + i1h1x = *(job->i1H1ptr + (here->MOS9gNode)) - + *(job->i1H1ptr + (here->MOS9sNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->MOS9bNode)) - + *(job->r1H1ptr + (here->MOS9sNodePrime)); + i1h1y = *(job->i1H1ptr + (here->MOS9bNode)) - + *(job->i1H1ptr + (here->MOS9sNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->MOS9dNodePrime)) - + *(job->r1H1ptr + (here->MOS9sNodePrime)); + i1h1z = *(job->i1H1ptr + (here->MOS9dNodePrime)) - + *(job->i1H1ptr + (here->MOS9sNodePrime)); + + r2h11x = *(job->r2H11ptr + (here->MOS9gNode)) - + *(job->r2H11ptr + (here->MOS9sNodePrime)); + i2h11x = *(job->i2H11ptr + (here->MOS9gNode)) - + *(job->i2H11ptr + (here->MOS9sNodePrime)); + + r2h11y = *(job->r2H11ptr + (here->MOS9bNode)) - + *(job->r2H11ptr + (here->MOS9sNodePrime)); + i2h11y = *(job->i2H11ptr + (here->MOS9bNode)) - + *(job->i2H11ptr + (here->MOS9sNodePrime)); + + r2h11z = *(job->r2H11ptr + (here->MOS9dNodePrime)) - + *(job->r2H11ptr + (here->MOS9sNodePrime)); + i2h11z = *(job->i2H11ptr + (here->MOS9dNodePrime)) - + *(job->i2H11ptr + (here->MOS9sNodePrime)); + /* 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->MOS9dNodePrime)) -= temp; + *(ckt->CKTirhs + (here->MOS9dNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->MOS9sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9sNodePrime)) += 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->MOS9bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9sNodePrime)) += 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->MOS9bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9dNodePrime)) += 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->MOS9gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9sNodePrime)) += 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->MOS9gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9dNodePrime)) += 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->MOS9gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9bNode)) += temp; + *(ckt->CKTirhs + (here->MOS9bNode)) += 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->MOS9bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9sNodePrime)) += 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->MOS9bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9dNodePrime)) += 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->MOS9gNode)) - + *(job->r1H1ptr + (here->MOS9sNodePrime)); + i1h1x = *(job->i1H1ptr + (here->MOS9gNode)) - + *(job->i1H1ptr + (here->MOS9sNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->MOS9bNode)) - + *(job->r1H1ptr + (here->MOS9sNodePrime)); + i1h1y = *(job->i1H1ptr + (here->MOS9bNode)) - + *(job->i1H1ptr + (here->MOS9sNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->MOS9dNodePrime)) - + *(job->r1H1ptr + (here->MOS9sNodePrime)); + i1h1z = *(job->i1H1ptr + (here->MOS9dNodePrime)) - + *(job->i1H1ptr + (here->MOS9sNodePrime)); + + r1h2x = *(job->r1H2ptr + (here->MOS9gNode)) - + *(job->r1H2ptr + (here->MOS9sNodePrime)); + i1h2x = *(job->i1H2ptr + (here->MOS9gNode)) - + *(job->i1H2ptr + (here->MOS9sNodePrime)); + + r1h2y = *(job->r1H2ptr + (here->MOS9bNode)) - + *(job->r1H2ptr + (here->MOS9sNodePrime)); + i1h2y = *(job->i1H2ptr + (here->MOS9bNode)) - + *(job->i1H2ptr + (here->MOS9sNodePrime)); + + r1h2z = *(job->r1H2ptr + (here->MOS9dNodePrime)) - + *(job->r1H2ptr + (here->MOS9sNodePrime)); + i1h2z = *(job->i1H2ptr + (here->MOS9dNodePrime)) - + *(job->i1H2ptr + (here->MOS9sNodePrime)); + + /* 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->MOS9dNodePrime)) -= temp; + *(ckt->CKTirhs + (here->MOS9dNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->MOS9sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9sNodePrime)) += 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->MOS9bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9sNodePrime)) += 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->MOS9bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9dNodePrime)) += 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->MOS9gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9sNodePrime)) += 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->MOS9gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9dNodePrime)) += 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->MOS9gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9bNode)) += temp; + *(ckt->CKTirhs + (here->MOS9bNode)) += 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->MOS9bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9sNodePrime)) += 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->MOS9bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9dNodePrime)) += 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->MOS9gNode)) - + *(job->r1H1ptr + (here->MOS9sNodePrime)); + i1h1x = *(job->i1H1ptr + (here->MOS9gNode)) - + *(job->i1H1ptr + (here->MOS9sNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->MOS9bNode)) - + *(job->r1H1ptr + (here->MOS9sNodePrime)); + i1h1y = *(job->i1H1ptr + (here->MOS9bNode)) - + *(job->i1H1ptr + (here->MOS9sNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->MOS9dNodePrime)) - + *(job->r1H1ptr + (here->MOS9sNodePrime)); + i1h1z = *(job->i1H1ptr + (here->MOS9dNodePrime)) - + *(job->i1H1ptr + (here->MOS9sNodePrime)); + + r1hm2x = *(job->r1H2ptr + (here->MOS9gNode)) - + *(job->r1H2ptr + (here->MOS9sNodePrime)); + i1hm2x = -(*(job->i1H2ptr + (here->MOS9gNode)) - + *(job->i1H2ptr + (here->MOS9sNodePrime))); + + r1hm2y = *(job->r1H2ptr + (here->MOS9bNode)) - + *(job->r1H2ptr + (here->MOS9sNodePrime)); + i1hm2y = -(*(job->i1H2ptr + (here->MOS9bNode)) - + *(job->i1H2ptr + (here->MOS9sNodePrime))); + + r1hm2z = *(job->r1H2ptr + (here->MOS9dNodePrime)) - + *(job->r1H2ptr + (here->MOS9sNodePrime)); + i1hm2z = -(*(job->i1H2ptr + (here->MOS9dNodePrime)) - + *(job->i1H2ptr + (here->MOS9sNodePrime))); + + /* 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->MOS9dNodePrime)) -= temp; + *(ckt->CKTirhs + (here->MOS9dNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->MOS9sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9sNodePrime)) += 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->MOS9bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9sNodePrime)) += 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->MOS9bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9dNodePrime)) += 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->MOS9gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9sNodePrime)) += 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->MOS9gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9dNodePrime)) += 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->MOS9gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9bNode)) += temp; + *(ckt->CKTirhs + (here->MOS9bNode)) += 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->MOS9bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9sNodePrime)) += 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->MOS9bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9dNodePrime)) += 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->MOS9gNode)) - + *(job->r1H1ptr + (here->MOS9sNodePrime)); + i1h1x = *(job->i1H1ptr + (here->MOS9gNode)) - + *(job->i1H1ptr + (here->MOS9sNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->MOS9bNode)) - + *(job->r1H1ptr + (here->MOS9sNodePrime)); + i1h1y = *(job->i1H1ptr + (here->MOS9bNode)) - + *(job->i1H1ptr + (here->MOS9sNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->MOS9dNodePrime)) - + *(job->r1H1ptr + (here->MOS9sNodePrime)); + i1h1z = *(job->i1H1ptr + (here->MOS9dNodePrime)) - + *(job->i1H1ptr + (here->MOS9sNodePrime)); + + r1hm2x = *(job->r1H2ptr + (here->MOS9gNode)) - + *(job->r1H2ptr + (here->MOS9sNodePrime)); + i1hm2x = -(*(job->i1H2ptr + (here->MOS9gNode)) - + *(job->i1H2ptr + (here->MOS9sNodePrime))); + + r1hm2y = *(job->r1H2ptr + (here->MOS9bNode)) - + *(job->r1H2ptr + (here->MOS9sNodePrime)); + i1hm2y = -(*(job->i1H2ptr + (here->MOS9bNode)) - + *(job->i1H2ptr + (here->MOS9sNodePrime))); + + r1hm2z = *(job->r1H2ptr + (here->MOS9dNodePrime)) - + *(job->r1H2ptr + (here->MOS9sNodePrime)); + i1hm2z = -(*(job->i1H2ptr + (here->MOS9dNodePrime)) - + *(job->i1H2ptr + (here->MOS9sNodePrime))); + + r2h11x = *(job->r1H1ptr + (here->MOS9gNode)) - + *(job->r1H1ptr + (here->MOS9sNodePrime)); + i2h11x = *(job->i1H1ptr + (here->MOS9gNode)) - + *(job->i1H1ptr + (here->MOS9sNodePrime)); + + r2h11y = *(job->r1H1ptr + (here->MOS9bNode)) - + *(job->r1H1ptr + (here->MOS9sNodePrime)); + i2h11y = *(job->i1H1ptr + (here->MOS9bNode)) - + *(job->i1H1ptr + (here->MOS9sNodePrime)); + + r2h11z = *(job->r1H1ptr + (here->MOS9dNodePrime)) - + *(job->r1H1ptr + (here->MOS9sNodePrime)); + i2h11z = *(job->i1H1ptr + (here->MOS9dNodePrime)) - + *(job->i1H1ptr + (here->MOS9sNodePrime)); + + r2h1m2x = *(job->r2H1m2ptr + (here->MOS9gNode)) - + *(job->r2H1m2ptr + (here->MOS9sNodePrime)); + i2h1m2x = *(job->i2H1m2ptr + (here->MOS9gNode)) - + *(job->i2H1m2ptr + (here->MOS9sNodePrime)); + + r2h1m2y = *(job->r2H1m2ptr + (here->MOS9bNode)) - + *(job->r2H1m2ptr + (here->MOS9sNodePrime)); + i2h1m2y = *(job->i2H1m2ptr + (here->MOS9bNode)) - + *(job->i2H1m2ptr + (here->MOS9sNodePrime)); + +r2h1m2z = *(job->r2H1m2ptr + (here->MOS9dNodePrime)) - + *(job->r2H1m2ptr + (here->MOS9sNodePrime)); +i2h1m2z = *(job->i2H1m2ptr + (here->MOS9dNodePrime)) - + *(job->i2H1m2ptr + (here->MOS9sNodePrime)); + + /* 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->MOS9dNodePrime)) -= temp; + *(ckt->CKTirhs + (here->MOS9dNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->MOS9sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9sNodePrime)) += 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->MOS9bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9sNodePrime)) += 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->MOS9bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9dNodePrime)) += 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->MOS9gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9sNodePrime)) += 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->MOS9gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9dNodePrime)) += 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->MOS9gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9bNode)) += temp; + *(ckt->CKTirhs + (here->MOS9bNode)) += 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->MOS9bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9sNodePrime)) += 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->MOS9bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS9bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS9dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS9dNodePrime)) += itemp; + + /* capbd over */ + /* all done */ + + break; + default: +; + } + } +} +return(OK); +} + else + return(E_BADPARM); +} diff --git a/src/spicelib/devices/mos9/mos9dset.c b/src/spicelib/devices/mos9/mos9dset.c new file mode 100644 index 000000000..94bb9c2ad --- /dev/null +++ b/src/spicelib/devices/mos9/mos9dset.c @@ -0,0 +1,979 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jaijeet S Roychowdhury +Modified: Alan Gillespie +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "mos9defs.h" +#include "trandefs.h" +#include "distodef.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS9dSetup(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; + /* actually load the current value into the + * sparse matrix previously provided + */ +{ + register MOS9model *model = (MOS9model *)inModel; + register MOS9instance *here; + double Beta; + double DrainSatCur; + double EffectiveLength; + double EffectiveWidth; + double GateBulkOverlapCap; + double GateDrainOverlapCap; + double GateSourceOverlapCap; + double OxideCap; + double SourceSatCur; + double arg; + double cdrain; + double evbs; + double sarg; + double sargsw; + double lvgs; + double vbd; + double vbs; + double vds; + double vdsat; + double vgb; + double vgd; + double vgs; + double von; + double lcapgs2,lcapgs3; /* total gate-source capacitance */ + double lcapgd2,lcapgd3; /* total gate-drain capacitance */ + double lcapgb2,lcapgb3; /* total gate-bulk capacitance */ + double lgbs, lgbs2, lgbs3; + double lgbd, lgbd2, lgbd3; + double gm2, gb2, gds2, gmb, gmds, gbds; + double gm3, gb3, gds3, gm2ds, gm2b, gb2ds, gbds2, gmb2, gmds2, gmbds; + double lcapbd, lcapbd2, lcapbd3; + double lcapbs, lcapbs2, lcapbs3; + double ebd; + double vt; /* vt at instance temperature */ + Dderivs d_cdrain; + + + + /* loop through all the MOS9 device models */ +next: for( ; model != NULL; model = model->MOS9nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MOS9instances; here != NULL ; + here=here->MOS9nextInstance) { + + vt = CONSTKoverQ * here->MOS9temp; + + + /* 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 + */ + + EffectiveWidth=here->MOS9w-2*model->MOS9widthNarrow+ + model->MOS9widthAdjust; + EffectiveLength=here->MOS9l - 2*model->MOS9latDiff+ + model->MOS9lengthAdjust; + + if( (here->MOS9tSatCurDens == 0) || + (here->MOS9drainArea == 0) || + (here->MOS9sourceArea == 0)) { + DrainSatCur = here->MOS9m * here->MOS9tSatCur; + SourceSatCur = here->MOS9m * here->MOS9tSatCur; + } else { + DrainSatCur = here->MOS9tSatCurDens * + here->MOS9m * here->MOS9drainArea; + SourceSatCur = here->MOS9tSatCurDens * + here->MOS9m * here->MOS9sourceArea; + } + GateSourceOverlapCap = model->MOS9gateSourceOverlapCapFactor * + here->MOS9m * EffectiveWidth; + GateDrainOverlapCap = model->MOS9gateDrainOverlapCapFactor * + here->MOS9m * EffectiveWidth; + GateBulkOverlapCap = model->MOS9gateBulkOverlapCapFactor * + here->MOS9m * EffectiveLength; + Beta = here->MOS9tTransconductance * here->MOS9m * + EffectiveWidth/EffectiveLength; + OxideCap = model->MOS9oxideCapFactor * EffectiveLength * + here->MOS9m * EffectiveWidth; + + + /* + * 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 + */ + + + /* general iteration */ + + vbs = model->MOS9type * ( + *(ckt->CKTrhsOld+here->MOS9bNode) - + *(ckt->CKTrhsOld+here->MOS9sNodePrime)); + vgs = model->MOS9type * ( + *(ckt->CKTrhsOld+here->MOS9gNode) - + *(ckt->CKTrhsOld+here->MOS9sNodePrime)); + vds = model->MOS9type * ( + *(ckt->CKTrhsOld+here->MOS9dNodePrime) - + *(ckt->CKTrhsOld+here->MOS9sNodePrime)); + + /* now some common crunching for some more useful quantities */ + + + + /* + * 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 doides + * here we just evaluate the ideal diode current and the + * correspoinding derivative (conductance). + */ +next1: 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->MOS9type *0.5 * (lgbs - ckt->CKTgmin)/vt; + lgbs3 = model->MOS9type *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->MOS9type *0.5 * (lgbd - ckt->CKTgmin)/vt; + lgbd3 = model->MOS9type *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->MOS9mode = 1; + } else { + /* inverse mode */ + here->MOS9mode = -1; + } + + { + /* + * subroutine moseq3(vds,vbs,vgs,gm,gds,gmbs, + * qg,qc,qb,cggb,cgdb,cgsb,cbgb,cbdb,cbsb) + */ + + /* + * this routine evaluates the drain current, its derivatives and + * the charges associated with the gate, channel and bulk + * for mosfets based on semi-empirical equations + */ + + /* + common /mosarg/ vto,beta,gamma,phi,phib,cox,xnsub,xnfs,xd,xj,xld, + 1 xlamda,uo,uexp,vbp,utra,vmax,xneff,xl,xw,vbi,von,vdsat,qspof, + 2 beta0,beta1,cdrain,xqco,xqc,fnarrw,fshort,lev + common /status/ omega,time,delta,delold(7),ag(7),vt,xni,egfet, + 1 xmu,sfactr,mode,modedc,icalc,initf,method,iord,maxord,noncon, + 2 iterno,itemno,nosolv,modac,ipiv,ivmflg,ipostp,iscrch,iofile + common /knstnt/ twopi,xlog2,xlog10,root2,rad,boltz,charge,ctok, + 1 gmin,reltol,abstol,vntol,trtol,chgtol,eps0,epssil,epsox, + 2 pivtol,pivrel + */ + + /* equivalence (xlamda,alpha),(vbp,theta),(uexp,eta),(utra,xkappa)*/ + + double coeff0 = 0.0631353e0; + double coeff1 = 0.8013292e0; + double coeff2 = -0.01110777e0; + double oneoverxl; /* 1/effective length */ + double eta; /* eta from model after length factor */ + double phibs; /* phi - vbs */ + double sqphbs; /* square root of phibs */ + double sqphis; /* square root of phi */ + double wps; + double oneoverxj; /* 1/junction depth */ + double xjonxl; /* junction depth/effective length */ + double djonxj; + double wponxj; + double arga; + double argb; + double argc; + double gammas; + double fbodys; + double fbody; + double onfbdy; + double qbonco; + double vbix; + double wconxj; + double vth; + double csonco; + double cdonco; + double vgsx; + double onfg; + double fgate; + double us; + double xn; + double vdsc; + double onvdsc; + double vdsx; + double cdnorm; + double cdo; + double fdrain; + double gdsat; + double cdsat; + double emax; + double delxl; + double dlonxl; + double xlfact; + double ondvt; + double onxn; + double wfact; + double fshort; + double lvds, lvbs, lvbd; + Dderivs d_onxn, d_ondvt, d_wfact, d_MOS9gds; + Dderivs d_emax, d_delxl, d_dlonxl, d_xlfact; + Dderivs d_cdonco, d_fdrain, d_cdsat, d_gdsat; + Dderivs d_vdsx, d_cdo, d_cdnorm, d_Beta, d_dummy; + Dderivs d_vdsc, d_onvdsc, d_arga, d_argb; + Dderivs d_onfg, d_fgate, d_us, d_vgsx; + Dderivs d_von, d_xn, d_vth, d_onfbdy, d_qbonco, d_vbix; + Dderivs d_argc, d_fshort, d_gammas, d_fbodys, d_fbody; + Dderivs d_wps, d_wconxj, d_wponxj; + Dderivs d_phibs, d_sqphbs; + Dderivs d_p, d_q, d_r, d_zero, d_vdsat; + + /* + * bypasses the computation of charges + */ + if (here->MOS9mode == 1) { + lvgs = vgs; + lvds = vds; + lvbs = vbs; + lvbd = vbd; + } else { + lvgs = vgd; + lvds = -vds; + lvbs = vbd; + lvbd = vbs; + } + + /* + * reference cdrain equations to source and + * charge equations to bulk + */ +d_p.value = 0.0; +d_p.d1_p = 1.0; +d_p.d1_q = 0.0; +d_p.d1_r = 0.0; +d_p.d2_p2 = 0.0; +d_p.d2_q2 = 0.0; +d_p.d2_r2 = 0.0; +d_p.d2_pq = 0.0; +d_p.d2_qr = 0.0; +d_p.d2_pr = 0.0; +d_p.d3_p3 = 0.0; +d_p.d3_q3 = 0.0; +d_p.d3_r3 = 0.0; +d_p.d3_p2r = 0.0; +d_p.d3_p2q = 0.0; +d_p.d3_q2r = 0.0; +d_p.d3_pq2 = 0.0; +d_p.d3_pr2 = 0.0; +d_p.d3_qr2 = 0.0; +d_p.d3_pqr = 0.0; + EqualDeriv(&d_q,&d_p); + EqualDeriv(&d_r,&d_p); + EqualDeriv(&d_zero,&d_p); + d_q.d1_p = d_r.d1_p = d_zero.d1_p = 0.0; + d_q.d1_q = d_r.d1_r = 1.0; + vdsat = 0.0; + EqualDeriv(&d_vdsat,&d_zero); + oneoverxl = 1.0/EffectiveLength;/*const*/ + eta = model->MOS9eta * 8.15e-22/(model->MOS9oxideCapFactor* + EffectiveLength*EffectiveLength*EffectiveLength);/*const*/ + /* + *.....square root term + */ + if ( lvbs <= 0.0 ) { + phibs = here->MOS9tPhi-lvbs; + EqualDeriv(&d_phibs,&d_q); + d_phibs.value = lvbs; + TimesDeriv(&d_phibs,&d_phibs,-1.0); + d_phibs.value += here->MOS9tPhi; + sqphbs = sqrt(phibs); + SqrtDeriv(&d_sqphbs,&d_phibs); + } else { + sqphis = sqrt(here->MOS9tPhi);/*const*/ + /*sqphs3 = here->MOS9tPhi*sqphis;const*/ + sqphbs = sqphis/(1.0+lvbs/ + (here->MOS9tPhi+here->MOS9tPhi)); + EqualDeriv(&d_sqphbs,&d_q); d_sqphbs.value = lvbs; + TimesDeriv(&d_sqphbs,&d_sqphbs,1/(here->MOS9tPhi+here->MOS9tPhi)); + d_sqphbs.value += 1.0; + InvDeriv(&d_sqphbs,&d_sqphbs); + TimesDeriv(&d_sqphbs,&d_sqphbs,sqphis); + phibs = sqphbs*sqphbs; + MultDeriv(&d_phibs,&d_sqphbs,&d_sqphbs); + } + /* + *.....short channel effect factor + */ + if ( (model->MOS9junctionDepth != 0.0) && + (model->MOS9coeffDepLayWidth != 0.0) ) { + wps = model->MOS9coeffDepLayWidth*sqphbs; + TimesDeriv(&d_wps,&d_sqphbs,model->MOS9coeffDepLayWidth); + oneoverxj = 1.0/model->MOS9junctionDepth;/*const*/ + xjonxl = model->MOS9junctionDepth*oneoverxl;/*const*/ + djonxj = model->MOS9latDiff*oneoverxj;/*const*/ + wponxj = wps*oneoverxj; + TimesDeriv(&d_wponxj,&d_wps,oneoverxj); + wconxj = coeff0+coeff1*wponxj+coeff2*wponxj*wponxj; + TimesDeriv(&d_wconxj,&d_wponxj,coeff2); + d_wconxj.value += coeff1; + MultDeriv(&d_wconxj,&d_wconxj,&d_wponxj); + d_wconxj.value += coeff0; + arga = wconxj + djonxj; + EqualDeriv(&d_arga,&d_wconxj); d_arga.value += djonxj; + argc = wponxj/(1.0+wponxj); + EqualDeriv(&d_argc,&d_wponxj); + d_argc.value += 1.0; + InvDeriv(&d_argc,&d_argc); + MultDeriv(&d_argc,&d_argc,&d_wponxj); + argb = sqrt(1.0-argc*argc); + MultDeriv(&d_argb,&d_argc,&d_argc); + TimesDeriv(&d_argb,&d_argb,-1.0); + d_argb.value += 1.0; + SqrtDeriv(&d_argb,&d_argb); + + fshort = 1.0-xjonxl*(arga*argb-djonxj); + MultDeriv(&d_fshort,&d_arga,&d_argb); + d_fshort.value -= djonxj; + TimesDeriv(&d_fshort,&d_fshort,-xjonxl); + d_fshort.value += 1.0; + } else { + fshort = 1.0; + EqualDeriv(&d_fshort,&d_zero); + d_fshort.value = 1.0; + + } + /* + *.....body effect + */ + gammas = model->MOS9gamma*fshort; + TimesDeriv(&d_gammas,&d_fshort,model->MOS9gamma); + fbodys = 0.5*gammas/(sqphbs+sqphbs); + DivDeriv(&d_fbodys,&d_gammas,&d_sqphbs); + TimesDeriv(&d_fbodys,&d_fbodys,0.25); + fbody = fbodys+model->MOS9narrowFactor/EffectiveWidth; + EqualDeriv(&d_fbody,&d_fbodys); + d_fbody.value += fbody - fbodys; + + onfbdy = 1.0/(1.0+fbody); + EqualDeriv(&d_onfbdy,&d_fbody); + d_onfbdy.value += 1.0; + InvDeriv(&d_onfbdy,&d_onfbdy); + qbonco =gammas*sqphbs+model->MOS9narrowFactor*phibs/EffectiveWidth; + EqualDeriv(&d_dummy,&d_phibs); + TimesDeriv(&d_dummy,&d_dummy,model-> + MultDeriv(&d_qbonco,&d_gammas,&d_sqphbs); + PlusDeriv(&d_qbonco,&d_qbonco,&d_dummy); + /* + *.....static feedback effect + */ + vbix = here->MOS9tVbi*model->MOS9type-eta*(lvds); + EqualDeriv(&d_vbix,&d_r); d_vbix.value = vbix; + d_vbix.d1_r = -eta; + /* + *.....threshold voltage + */ + vth = vbix+qbonco; + PlusDeriv(&d_vth,&d_vbix,&d_qbonco); + /* + *.....joint weak inversion and strong inversion + */ + von = vth; + EqualDeriv(&d_von,&d_vth); + if ( model->MOS9fastSurfaceStateDensity != 0.0 ) { + csonco = CHARGE*model->MOS9fastSurfaceStateDensity * + 1e4 /*(cm**2/m**2)*/ *EffectiveLength*EffectiveWidth * + here->MOS9m/OxideCap; /*const*/ + cdonco = 0.5*qbonco/phibs; + DivDeriv(&d_cdonco,&d_qbonco,&d_phibs); + TimesDeriv(&d_cdonco,&d_cdonco,0.5); + xn = 1.0+csonco+cdonco; + EqualDeriv(&d_xn,&d_cdonco); + d_xn.value += 1.0 + csonco; + von = vth+vt*xn; + TimesDeriv(&d_von,&d_xn,vt); + PlusDeriv(&d_von,&d_von,&d_vth); + + + } else { + /* + *.....cutoff region + */ + if ( lvgs <= von ) { + cdrain = 0.0; + EqualDeriv(&d_cdrain,&d_zero); + goto innerline1000; + } + } + /* + *.....device is on + */ + vgsx = MAX(lvgs,von); +if (lvgs >= von) { +EqualDeriv(&d_vgsx,&d_p); +d_vgsx.value = lvgs; +} else { +EqualDeriv(&d_vgsx,&d_von); +} + /* + *.....mobility modulation by gate voltage + */ + onfg = 1.0+model->MOS9theta*(vgsx-vth); + TimesDeriv(&d_onfg,&d_vth,-1.0); + PlusDeriv(&d_onfg,&d_onfg,&d_vgsx); + TimesDeriv(&d_onfg,&d_onfg,model->MOS9theta); + d_onfg.value += 1.0; + fgate = 1.0/onfg; + InvDeriv(&d_fgate,&d_onfg); + us = here->MOS9tSurfMob * 1e-4 /*(m**2/cm**2)*/ *fgate; + TimesDeriv(&d_us,&d_fgate,here->MOS9tSurfMob * 1e-4); + /* + *.....saturation voltage + */ + vdsat = (vgsx-vth)*onfbdy; + TimesDeriv(&d_vdsat,&d_vth, -1.0); + PlusDeriv(&d_vdsat,&d_vdsat,&d_vgsx); + MultDeriv(&d_vdsat,&d_vdsat,&d_onfbdy); + if ( model->MOS9maxDriftVel <= 0.0 ) { + } else { + vdsc = EffectiveLength*model->MOS9maxDriftVel/us; + InvDeriv(&d_vdsc,&d_us); + TimesDeriv(&d_vdsc,&d_vdsc,EffectiveLength*model->MOS9maxDriftVel); + onvdsc = 1.0/vdsc; + InvDeriv(&d_onvdsc,&d_vdsc); + arga = (vgsx-vth)*onfbdy; + /* note arga = vdsat at this point */ + EqualDeriv(&d_arga,&d_vdsat); + argb = sqrt(arga*arga+vdsc*vdsc); + MultDeriv(&d_dummy,&d_arga,&d_arga); + MultDeriv(&d_argb,&d_vdsc,&d_vdsc); + PlusDeriv(&d_argb,&d_argb,&d_dummy); + SqrtDeriv(&d_argb,&d_argb); + vdsat = arga+vdsc-argb; + TimesDeriv(&d_vdsat,&d_argb,-1.0); + PlusDeriv(&d_vdsat,&d_vdsat,&d_vdsc); + PlusDeriv(&d_vdsat,&d_vdsat,&d_arga); + } + /* + *.....current factors in linear region + */ + vdsx = MIN((lvds),vdsat); +if (lvds < vdsat) { +EqualDeriv(&d_vdsx,&d_r); +d_vdsx.value = lvds; +} else { +EqualDeriv(&d_vdsx,&d_vdsat); +} + + if ( vdsx == 0.0 ) goto line900; + cdo = vgsx-vth-0.5*(1.0+fbody)*vdsx; + EqualDeriv(&d_cdo,&d_fbody); + d_cdo.value += 1.0; + MultDeriv(&d_cdo,&d_cdo,&d_vdsx); + TimesDeriv(&d_cdo,&d_cdo,0.5); + PlusDeriv(&d_cdo,&d_cdo,&d_vth); + TimesDeriv(&d_cdo,&d_cdo,-1.0); + PlusDeriv(&d_cdo,&d_cdo,&d_vgsx); + + + /* + *.....normalized drain current + */ + cdnorm = cdo*vdsx; + MultDeriv(&d_cdnorm,&d_cdo,&d_vdsx); + /* + *.....drain current without velocity saturation effect + */ +/* Beta is a constant till now */ + Beta = Beta*fgate; + TimesDeriv(&d_Beta,&d_fgate,Beta); + cdrain = Beta*cdnorm; + MultDeriv(&d_cdrain,&d_Beta,&d_cdnorm); + /* + *.....velocity saturation factor + */ + if ( model->MOS9maxDriftVel != 0.0 ) { + fdrain = 1.0/(1.0+vdsx*onvdsc); + MultDeriv(&d_fdrain,&d_vdsx,&d_onvdsc); + d_fdrain.value += 1.0; + InvDeriv(&d_fdrain,&d_fdrain); + /* + *.....drain current + */ + cdrain = fdrain*cdrain; + MultDeriv(&d_cdrain,&d_cdrain,&d_fdrain); + Beta = Beta*fdrain; + MultDeriv(&d_Beta,&d_Beta,&d_fdrain); + + } + /* + *.....channel length modulation + */ + if ( (lvds) <= vdsat ) goto line700; + if ( model->MOS9maxDriftVel == 0.0 ) goto line510; + if (model->MOS9alpha == 0.0) goto line700; + cdsat = cdrain; + EqualDeriv(&d_cdsat,&d_cdrain); + gdsat = cdsat*(1.0-fdrain)*onvdsc; + TimesDeriv(&d_dummy,&d_fdrain,-1.0); + d_dummy.value += 1.0; + MultDeriv(&d_gdsat,&d_cdsat,&d_dummy); + MultDeriv(&d_gdsat,&d_gdsat,&d_onvdsc); + gdsat = MAX(1.0e-12,gdsat); + if (gdsat == 1.0e-12) { + EqualDeriv(&d_gdsat,&d_zero); + d_gdsat.value = gdsat; + } + + emax = cdsat*oneoverxl/gdsat; + DivDeriv(&d_emax,&d_cdsat,&d_gdsat); + TimesDeriv(&d_emax,&d_emax,oneoverxl); + + + arga = 0.5*emax*model->MOS9alpha; + TimesDeriv(&d_arga,&d_emax,0.5*model->MOS9alpha); + argc = model->MOS9kappa*model->MOS9alpha;/*const*/ + argb = sqrt(arga*arga+argc*((lvds)-vdsat)); + TimesDeriv(&d_dummy,&d_vdsat,-1.0); + d_dummy.value += lvds; + d_dummy.d1_r += 1.0; + TimesDeriv(&d_argb,&d_dummy,argc); + MultDeriv(&d_dummy,&d_arga,&d_arga); + PlusDeriv(&d_argb,&d_argb,&d_dummy); + SqrtDeriv(&d_argb,&d_argb); + delxl = argb-arga; + TimesDeriv(&d_delxl,&d_arga,-1.0); + PlusDeriv(&d_delxl,&d_argb,&d_delxl); + goto line520; +line510: + delxl = sqrt(model->MOS9kappa*((lvds)-vdsat)*model->MOS9alpha); + TimesDeriv(&d_delxl,&d_vdsat,-1.0); + d_delxl.value += lvds; + d_delxl.d1_r += 1.0; + TimesDeriv(&d_delxl,&d_delxl,model->MOS9kappa*model->MOS9alpha); + SqrtDeriv(&d_delxl,&d_delxl); + + /* + *.....punch through approximation + */ +line520: + if ( delxl > (0.5*EffectiveLength) ) { + delxl = EffectiveLength - (EffectiveLength*EffectiveLength/ + delxl*0.25); + InvDeriv(&d_delxl,&d_delxl); + TimesDeriv(&d_delxl,&d_delxl,-EffectiveLength*EffectiveLength*0.25); + d_delxl.value += EffectiveLength; + } + /* + *.....saturation region + */ + dlonxl = delxl*oneoverxl; + TimesDeriv(&d_dlonxl,&d_delxl,oneoverxl); + xlfact = 1.0/(1.0-dlonxl); + TimesDeriv(&d_xlfact,&d_dlonxl,-1.0); + d_xlfact.value += 1.0; + InvDeriv(&d_xlfact,&d_xlfact); + + cdrain = cdrain*xlfact; + MultDeriv(&d_cdrain,&d_cdrain,&d_xlfact); + /* + *.....finish strong inversion case + */ +line700: + if ( lvgs < von ) { + /* + *.....weak inversion + */ + onxn = 1.0/xn; + InvDeriv(&d_onxn,&d_xn); + ondvt = onxn/vt; + TimesDeriv(&d_ondvt,&d_onxn,1/vt); + wfact = exp( (lvgs-von)*ondvt ); + TimesDeriv(&d_wfact,&d_von,-1.0); + d_wfact.value += lvgs; + d_wfact.d1_p += 1.0; + MultDeriv(&d_wfact,&d_wfact,&d_ondvt); + ExpDeriv(&d_wfact,&d_wfact); + cdrain = cdrain*wfact; + MultDeriv(&d_cdrain,&d_cdrain,&d_wfact); + } + /* + *.....charge computation + */ + goto innerline1000; + /* + *.....special case of vds = 0.0d0 + */ + +line900: + Beta = Beta*fgate; + /* Beta is still a constant */ + TimesDeriv(&d_Beta,&d_fgate,Beta); + cdrain = 0.0; + EqualDeriv(&d_cdrain,&d_zero); + here->MOS9gds = Beta*(vgsx-vth); + TimesDeriv(&d_MOS9gds,&d_vth,-1.0); + PlusDeriv(&d_MOS9gds,&d_MOS9gds,&d_vgsx); + MultDeriv(&d_MOS9gds,&d_MOS9gds,&d_Beta); + if ( (model->MOS9fastSurfaceStateDensity != 0.0) && + (lvgs < von) ) { + here->MOS9gds *=exp((lvgs-von)/(vt*xn)); + TimesDeriv(&d_dummy,&d_von,-1.0); + d_dummy.value += lvgs; + d_dummy.d1_p += 1.0; + DivDeriv(&d_dummy,&d_dummy,&d_xn); + TimesDeriv(&d_dummy,&d_dummy,1/vt); + ExpDeriv(&d_dummy,&d_dummy); + MultDeriv(&d_MOS9gds,&d_MOS9gds,&d_dummy); + } + d_cdrain.d1_r = d_MOS9gds.value; + d_cdrain.d2_r2 = d_MOS9gds.d1_r; + d_cdrain.d3_r3 = d_MOS9gds.d2_r2; + + + +innerline1000:; + /* + *.....done + */ + } + + + /* + * 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->MOS9tDepCap){ + arg=1-vbs/here->MOS9tBulkPot; + /* + * 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->MOS9bulkJctBotGradingCoeff == + model->MOS9bulkJctSideGradingCoeff) { + if(model->MOS9bulkJctBotGradingCoeff == .5) { + sarg = sargsw = 1/sqrt(arg); + } else { + sarg = sargsw = + exp(-model->MOS9bulkJctBotGradingCoeff* + log(arg)); + } + } else { + if(model->MOS9bulkJctBotGradingCoeff == .5) { + sarg = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sarg = exp(-model->MOS9bulkJctBotGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + if(model->MOS9bulkJctSideGradingCoeff == .5) { + sargsw = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sargsw =exp(-model->MOS9bulkJctSideGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + } +#endif /*NOSQRT*/ + lcapbs=here->MOS9Cbs*sarg+ + here->MOS9Cbssw*sargsw; + lcapbs2 = model->MOS9type*0.5/here->MOS9tBulkPot*( + here->MOS9Cbs*model->MOS9bulkJctBotGradingCoeff* + sarg/arg + here->MOS9Cbssw* + model->MOS9bulkJctSideGradingCoeff*sargsw/arg); + lcapbs3 = here->MOS9Cbs*sarg* + model->MOS9bulkJctBotGradingCoeff* + (model->MOS9bulkJctBotGradingCoeff+1); + lcapbs3 += here->MOS9Cbssw*sargsw* + model->MOS9bulkJctSideGradingCoeff* + (model->MOS9bulkJctSideGradingCoeff+1); + lcapbs3 = lcapbs3/(6*here->MOS9tBulkPot* + here->MOS9tBulkPot*arg*arg); + } else { + /* *(ckt->CKTstate0 + here->MOS9qbs)= here->MOS9f4s + + vbs*(here->MOS9f2s+vbs*(here->MOS9f3s/2));*/ + lcapbs=here->MOS9f2s+here->MOS9f3s*vbs; + lcapbs2 = 0.5*here->MOS9f3s; + lcapbs3 = 0; + } + if (vbd < here->MOS9tDepCap) { + arg=1-vbd/here->MOS9tBulkPot; + /* + * 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->MOS9bulkJctBotGradingCoeff == .5 && + model->MOS9bulkJctSideGradingCoeff == .5) { + sarg = sargsw = 1/sqrt(arg); + } else { + if(model->MOS9bulkJctBotGradingCoeff == .5) { + sarg = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sarg = exp(-model->MOS9bulkJctBotGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + if(model->MOS9bulkJctSideGradingCoeff == .5) { + sargsw = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sargsw =exp(-model->MOS9bulkJctSideGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + } +#endif /*NOSQRT*/ + lcapbd=here->MOS9Cbd*sarg+ + here->MOS9Cbdsw*sargsw; + lcapbd2 = model->MOS9type*0.5/here->MOS9tBulkPot*( + here->MOS9Cbd*model->MOS9bulkJctBotGradingCoeff* + sarg/arg + here->MOS9Cbdsw* + model->MOS9bulkJctSideGradingCoeff*sargsw/arg); + lcapbd3 = here->MOS9Cbd*sarg* + model->MOS9bulkJctBotGradingCoeff* + (model->MOS9bulkJctBotGradingCoeff+1); + lcapbd3 += here->MOS9Cbdsw*sargsw* + model->MOS9bulkJctSideGradingCoeff* + (model->MOS9bulkJctSideGradingCoeff+1); + lcapbd3 = lcapbd3/(6*here->MOS9tBulkPot* + here->MOS9tBulkPot*arg*arg); + } else { + lcapbd=here->MOS9f2d + vbd * here->MOS9f3d; + lcapbd2=0.5*here->MOS9f3d; + 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 MOS9 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; + double vgst; + /* von, lvgs and vdsat have already been adjusted for + possible source-drain interchange */ + + + + vgst = lvgs -von; + phi = here->MOS9tPhi; + 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 MOS9modes are around because + vds has not been adjusted */ + if (vdsat <= here->MOS9mode*vds) { + lcapgb2=lcapgb3=lcapgs2=lcapgs3=lcapgd2=lcapgd3=0; + } else { + vddif = 2.0*vdsat-here->MOS9mode*vds; + vddif1 = vdsat-here->MOS9mode*vds/*-1.0e-12*/; + vddif2 = vddif*vddif; + lcapgd2 = -vdsat*here->MOS9mode*vds*cox/(3*vddif*vddif2); + lcapgd3 = - here->MOS9mode*vds*cox*(vddif - 6*vdsat)/(9*vddif2*vddif2); + lcapgs2 = -vddif1*here->MOS9mode*vds*cox/(3*vddif*vddif2); + lcapgs3 = - here->MOS9mode*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->MOS9type*lcapgb2; + here->capgb3 = lcapgb3; + /* + * process to get Taylor coefficients, taking into + * account type and mode. + */ +gm2 = d_cdrain.d2_p2; +gb2 = d_cdrain.d2_q2; +gds2 = d_cdrain.d2_r2; +gmb = d_cdrain.d2_pq; +gbds = d_cdrain.d2_qr; +gmds = d_cdrain.d2_pr; +gm3 = d_cdrain.d3_p3; +gb3 = d_cdrain.d3_q3; +gds3 = d_cdrain.d3_r3; +gm2ds = d_cdrain.d3_p2r; +gm2b = d_cdrain.d3_p2q; +gb2ds = d_cdrain.d3_q2r; +gmb2 = d_cdrain.d3_pq2; +gmds2 = d_cdrain.d3_pr2; +gbds2 = d_cdrain.d3_qr2; +gmbds = d_cdrain.d3_pqr; + + if (here->MOS9mode == 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->MOS9type*lcapgs2; + here->capgs3 = lcapgs3; + here->capgd2 = model->MOS9type*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->MOS9type*lcapgd2; + here->capgs3 = lcapgd3; + + here->capgd2 = model->MOS9type*lcapgs2; + here->capgd3 = lcapgs3; + +} + +/* now to adjust for type and multiply by factors to convert to Taylor coeffs. */ + +here->cdr_x2 = 0.5*model->MOS9type*here->cdr_x2; +here->cdr_y2 = 0.5*model->MOS9type*here->cdr_y2; +here->cdr_z2 = 0.5*model->MOS9type*here->cdr_z2; +here->cdr_xy = model->MOS9type*here->cdr_xy; +here->cdr_yz = model->MOS9type*here->cdr_yz; +here->cdr_xz = model->MOS9type*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/mos9/mos9ext.h b/src/spicelib/devices/mos9/mos9ext.h new file mode 100644 index 000000000..e8d94eaf2 --- /dev/null +++ b/src/spicelib/devices/mos9/mos9ext.h @@ -0,0 +1,30 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Alan Gillespie +**********/ + +extern int MOS9acLoad(GENmodel*,CKTcircuit*); +extern int MOS9ask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int MOS9convTest(GENmodel *,CKTcircuit *); +extern int MOS9delete(GENmodel*,IFuid,GENinstance**); +extern void MOS9destroy(GENmodel**); +extern int MOS9getic(GENmodel*,CKTcircuit*); +extern int MOS9load(GENmodel*,CKTcircuit*); +extern int MOS9mAsk(CKTcircuit*,GENmodel*,int,IFvalue*); +extern int MOS9mDelete(GENmodel**,IFuid,GENmodel*); +extern int MOS9mParam(int,IFvalue*,GENmodel*); +extern int MOS9param(int,IFvalue*,GENinstance*,IFvalue*); +extern int MOS9pzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int MOS9sAcLoad(GENmodel*,CKTcircuit*); +extern int MOS9sLoad(GENmodel*,CKTcircuit*); +extern void MOS9sPrint(GENmodel*,CKTcircuit*); +extern int MOS9sSetup(SENstruct*,GENmodel*); +extern int MOS9sUpdate(GENmodel*,CKTcircuit*); +extern int MOS9setup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int MOS9unsetup(GENmodel*,CKTcircuit*); +extern int MOS9temp(GENmodel*,CKTcircuit*); +extern int MOS9trunc(GENmodel*,CKTcircuit*,double*); +extern int MOS9disto(int,GENmodel*,CKTcircuit*); +extern int MOS9noise(int,int,GENmodel*,CKTcircuit*,Ndata*,double*); +extern int MOS9dSetup(GENmodel*,CKTcircuit*); \ No newline at end of file diff --git a/src/spicelib/devices/mos9/mos9ic.c b/src/spicelib/devices/mos9/mos9ic.c new file mode 100644 index 000000000..87ed60635 --- /dev/null +++ b/src/spicelib/devices/mos9/mos9ic.c @@ -0,0 +1,49 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Alan Gillespie +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos9defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS9getic(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + MOS9model *model = (MOS9model *)inModel; + MOS9instance *here; + /* + * grab initial conditions out of rhs array. User specified, so use + * external nodes to get values + */ + + for( ; model ; model = model->MOS9nextModel) { + for(here = model->MOS9instances; here ; here = here->MOS9nextInstance) { + if(!here->MOS9icVBSGiven) { + here->MOS9icVBS = + *(ckt->CKTrhs + here->MOS9bNode) - + *(ckt->CKTrhs + here->MOS9sNode); + } + if(!here->MOS9icVDSGiven) { + here->MOS9icVDS = + *(ckt->CKTrhs + here->MOS9dNode) - + *(ckt->CKTrhs + here->MOS9sNode); + } + if(!here->MOS9icVGSGiven) { + here->MOS9icVGS = + *(ckt->CKTrhs + here->MOS9gNode) - + *(ckt->CKTrhs + here->MOS9sNode); + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos9/mos9init.c b/src/spicelib/devices/mos9/mos9init.c new file mode 100644 index 000000000..7f5b9a6ac --- /dev/null +++ b/src/spicelib/devices/mos9/mos9init.c @@ -0,0 +1,65 @@ +#include + +#include + +#include "mos9itf.h" +#include "mos9ext.h" +#include "mos9init.h" + + +SPICEdev MOS9info = { + { + "Mos9", + "Modified Level 3 MOSfet model", + + &MOS9nSize, + &MOS9nSize, + MOS9names, + + &MOS9pTSize, + MOS9pTable, + + &MOS9mPTSize, + MOS9mPTable, + DEV_DEFAULT + }, + + DEVparam : MOS9param, + DEVmodParam : MOS9mParam, + DEVload : MOS9load, + DEVsetup : MOS9setup, + DEVunsetup : MOS9unsetup, + DEVpzSetup : MOS9setup, + DEVtemperature: MOS9temp, + DEVtrunc : MOS9trunc, + DEVfindBranch : NULL, + DEVacLoad : MOS9acLoad, + DEVaccept : NULL, + DEVdestroy : MOS9destroy, + DEVmodDelete : MOS9mDelete, + DEVdelete : MOS9delete, + DEVsetic : MOS9getic, + DEVask : MOS9ask, + DEVmodAsk : MOS9mAsk, + DEVpzLoad : MOS9pzLoad, + DEVconvTest : MOS9convTest, + DEVsenSetup : MOS9sSetup, + DEVsenLoad : MOS9sLoad, + DEVsenUpdate : MOS9sUpdate, + DEVsenAcLoad : MOS9sAcLoad, + DEVsenPrint : MOS9sPrint, + DEVsenTrunc : NULL, + DEVdisto : MOS9disto, + DEVnoise : MOS9noise, + + DEVinstSize : &MOS9iSize, + DEVmodSize : &MOS9mSize + +}; + + +SPICEdev * +get_mos9_info(void) +{ + return &MOS9info; +} diff --git a/src/spicelib/devices/mos9/mos9init.h b/src/spicelib/devices/mos9/mos9init.h new file mode 100644 index 000000000..5163e2188 --- /dev/null +++ b/src/spicelib/devices/mos9/mos9init.h @@ -0,0 +1,13 @@ +#ifndef _MOS9INIT_H +#define _MOS9INIT_H + +extern IFparm MOS9pTable[ ]; +extern IFparm MOS9mPTable[ ]; +extern char *MOS9names[ ]; +extern int MOS9pTSize; +extern int MOS9mPTSize; +extern int MOS9nSize; +extern int MOS9iSize; +extern int MOS9mSize; + +#endif diff --git a/src/spicelib/devices/mos9/mos9itf.h b/src/spicelib/devices/mos9/mos9itf.h new file mode 100644 index 000000000..6abc9b9a4 --- /dev/null +++ b/src/spicelib/devices/mos9/mos9itf.h @@ -0,0 +1,10 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ + +#ifndef DEV_MOS9 +#define DEV_MOS9 + +SPICEdev *get_mos9_info(void); + +#endif \ No newline at end of file diff --git a/src/spicelib/devices/mos9/mos9load.c b/src/spicelib/devices/mos9/mos9load.c new file mode 100644 index 000000000..9fef457d2 --- /dev/null +++ b/src/spicelib/devices/mos9/mos9load.c @@ -0,0 +1,1358 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Alan Gillespie +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "mos9defs.h" +#include "trandefs.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS9load(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; + /* actually load the current value into the + * sparse matrix previously provided + */ +{ + MOS9model *model = (MOS9model *)inModel; + MOS9instance *here; + double Beta; + double DrainSatCur; + double EffectiveLength; + double EffectiveWidth; + 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 tol; + 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 xfact; + int xnrm; + int xrev; + double capgs; /* total gate-source capacitance */ + double capgd; /* total gate-drain capacitance */ + double capgb; /* total gate-bulk capacitance */ + int Check; + double tempv; + int error; +#ifdef CAPBYPASS + int senflag; +#endif /* CAPBYPASS */ + int SenCond; + double vt; /* vt at instance temperature */ + + +#ifdef CAPBYPASS + senflag = 0; +#endif /* CAPBYPASS */ + if(ckt->CKTsenInfo){ + if(ckt->CKTsenInfo->SENstatus == PERTURBATION) { + if((ckt->CKTsenInfo->SENmode == ACSEN)|| + (ckt->CKTsenInfo->SENmode == TRANSEN)){ +#ifdef CAPBYPASS + senflag = 1; +#endif /* CAPBYPASS */ + } + goto next; + } + } + + /* loop through all the MOS9 device models */ +next: + for( ; model != NULL; model = model->MOS9nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MOS9instances; here != NULL ; + here=here->MOS9nextInstance) { + + vt = CONSTKoverQ * here->MOS9temp; + Check=1; + + if(ckt->CKTsenInfo){ +#ifdef SENSDEBUG + printf("MOS9load \n"); +#endif /* SENSDEBUG */ + + if(ckt->CKTsenInfo->SENstatus == PERTURBATION) + if(here->MOS9senPertFlag == OFF)continue; + + } + SenCond = ckt->CKTsenInfo && here->MOS9senPertFlag; +#ifdef DETAILPROF +asm(" .globl mos9pta"); +asm("mos9pta:"); +#endif /* DETAILPROF */ + + /* 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 + */ + + EffectiveWidth=here->MOS9w-2*model->MOS9widthNarrow+ + model->MOS9widthAdjust; + EffectiveLength=here->MOS9l - 2*model->MOS9latDiff+ + model->MOS9lengthAdjust; + + if( (here->MOS9tSatCurDens == 0) || + (here->MOS9drainArea == 0) || + (here->MOS9sourceArea == 0)) { + DrainSatCur = here->MOS9m * here->MOS9tSatCur; + SourceSatCur = here->MOS9m * here->MOS9tSatCur; + } else { + DrainSatCur = here->MOS9m * here->MOS9tSatCurDens * + here->MOS9drainArea; + SourceSatCur = here->MOS9m * here->MOS9tSatCurDens * + here->MOS9sourceArea; + } + GateSourceOverlapCap = model->MOS9gateSourceOverlapCapFactor * + here->MOS9m * EffectiveWidth; + GateDrainOverlapCap = model->MOS9gateDrainOverlapCapFactor * + here->MOS9m * EffectiveWidth; + GateBulkOverlapCap = model->MOS9gateBulkOverlapCapFactor * + here->MOS9m * EffectiveLength; + Beta = here->MOS9tTransconductance * + here->MOS9m * EffectiveWidth/EffectiveLength; + OxideCap = model->MOS9oxideCapFactor * EffectiveLength * + here->MOS9m * EffectiveWidth; + + + if(SenCond){ +#ifdef SENSDEBUG + printf("MOS9senPertFlag = ON \n"); +#endif /* SENSDEBUG */ + if((ckt->CKTsenInfo->SENmode == TRANSEN) && + (ckt->CKTmode & MODEINITTRAN)) { + vgs = *(ckt->CKTstate1 + here->MOS9vgs); + vds = *(ckt->CKTstate1 + here->MOS9vds); + vbs = *(ckt->CKTstate1 + here->MOS9vbs); + vbd = *(ckt->CKTstate1 + here->MOS9vbd); + vgb = vgs - vbs; + vgd = vgs - vds; + } + else if (ckt->CKTsenInfo->SENmode == ACSEN){ + vgb = model->MOS9type * ( + *(ckt->CKTrhsOp+here->MOS9gNode) - + *(ckt->CKTrhsOp+here->MOS9bNode)); + vbs = *(ckt->CKTstate0 + here->MOS9vbs); + vbd = *(ckt->CKTstate0 + here->MOS9vbd); + vgd = vgb + vbd ; + vgs = vgb + vbs ; + vds = vbs - vbd ; + } + else{ + vgs = *(ckt->CKTstate0 + here->MOS9vgs); + vds = *(ckt->CKTstate0 + here->MOS9vds); + vbs = *(ckt->CKTstate0 + here->MOS9vbs); + vbd = *(ckt->CKTstate0 + here->MOS9vbd); + 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; + } + +#ifdef DETAILPROF +asm(" .globl mos9ptax"); +asm("mos9ptax:"); +#endif /* DETAILPROF */ + + /* + * 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((ckt->CKTmode & (MODEINITFLOAT | MODEINITPRED | MODEINITSMSIG | + MODEINITTRAN)) || + ( (ckt->CKTmode & MODEINITFIX) && (!here->MOS9off) ) ) { +#ifndef PREDICTOR + if(ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) { + + /* predictor step */ + + xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1]; + *(ckt->CKTstate0 + here->MOS9vbs) = + *(ckt->CKTstate1 + here->MOS9vbs); + vbs = (1+xfact)* (*(ckt->CKTstate1 + here->MOS9vbs)) + -(xfact * (*(ckt->CKTstate2 + here->MOS9vbs))); + *(ckt->CKTstate0 + here->MOS9vgs) = + *(ckt->CKTstate1 + here->MOS9vgs); + vgs = (1+xfact)* (*(ckt->CKTstate1 + here->MOS9vgs)) + -(xfact * (*(ckt->CKTstate2 + here->MOS9vgs))); + *(ckt->CKTstate0 + here->MOS9vds) = + *(ckt->CKTstate1 + here->MOS9vds); + vds = (1+xfact)* (*(ckt->CKTstate1 + here->MOS9vds)) + -(xfact * (*(ckt->CKTstate2 + here->MOS9vds))); + *(ckt->CKTstate0 + here->MOS9vbd) = + *(ckt->CKTstate0 + here->MOS9vbs)- + *(ckt->CKTstate0 + here->MOS9vds); + } else { +#endif /*PREDICTOR*/ + + /* general iteration */ + + vbs = model->MOS9type * ( + *(ckt->CKTrhsOld+here->MOS9bNode) - + *(ckt->CKTrhsOld+here->MOS9sNodePrime)); + vgs = model->MOS9type * ( + *(ckt->CKTrhsOld+here->MOS9gNode) - + *(ckt->CKTrhsOld+here->MOS9sNodePrime)); + vds = model->MOS9type * ( + *(ckt->CKTrhsOld+here->MOS9dNodePrime) - + *(ckt->CKTrhsOld+here->MOS9sNodePrime)); +#ifndef PREDICTOR + } +#endif /*PREDICTOR*/ + + /* now some common crunching for some more useful quantities */ +#ifdef DETAILPROF +asm(" .globl mos9ptay"); +asm("mos9ptay:"); +#endif /* DETAILPROF */ + + vbd=vbs-vds; + vgd=vgs-vds; + vgdo = *(ckt->CKTstate0 + here->MOS9vgs) - + *(ckt->CKTstate0 + here->MOS9vds); + delvbs = vbs - *(ckt->CKTstate0 + here->MOS9vbs); + delvbd = vbd - *(ckt->CKTstate0 + here->MOS9vbd); + delvgs = vgs - *(ckt->CKTstate0 + here->MOS9vgs); + delvds = vds - *(ckt->CKTstate0 + here->MOS9vds); + delvgd = vgd-vgdo; + + /* these are needed for convergence testing */ + + if (here->MOS9mode >= 0) { + cdhat= + here->MOS9cd- + here->MOS9gbd * delvbd + + here->MOS9gmbs * delvbs + + here->MOS9gm * delvgs + + here->MOS9gds * delvds ; + } else { + cdhat= + here->MOS9cd - + ( here->MOS9gbd - + here->MOS9gmbs) * delvbd - + here->MOS9gm * delvgd + + here->MOS9gds * delvds ; + } + cbhat= + here->MOS9cbs + + here->MOS9cbd + + here->MOS9gbd * delvbd + + here->MOS9gbs * delvbs ; + +#ifdef DETAILPROF +asm(" .globl mos9ptb"); +asm("mos9ptb:"); +#endif /* DETAILPROF */ + /* now lets see if we can bypass (ugh) */ + /* the following mess should be one if statement, but + * many compilers can't handle it all at once, so it + * is split into several successive if statements + */ + tempv = MAX(fabs(cbhat),fabs(here->MOS9cbs + + here->MOS9cbd))+ckt->CKTabstol; + if((!(ckt->CKTmode & (MODEINITPRED|MODEINITTRAN|MODEINITSMSIG) + )) && (ckt->CKTbypass) ) + if ( (fabs(cbhat-(here->MOS9cbs + + here->MOS9cbd)) < ckt->CKTreltol * + tempv)) + if( (fabs(delvbs) < (ckt->CKTreltol * MAX(fabs(vbs), + fabs(*(ckt->CKTstate0+here->MOS9vbs)))+ + ckt->CKTvoltTol))) + if ( (fabs(delvbd) < (ckt->CKTreltol * MAX(fabs(vbd), + fabs(*(ckt->CKTstate0+here->MOS9vbd)))+ + ckt->CKTvoltTol)) ) + if( (fabs(delvgs) < (ckt->CKTreltol * MAX(fabs(vgs), + fabs(*(ckt->CKTstate0+here->MOS9vgs)))+ + ckt->CKTvoltTol))) + if ( (fabs(delvds) < (ckt->CKTreltol * MAX(fabs(vds), + fabs(*(ckt->CKTstate0+here->MOS9vds)))+ + ckt->CKTvoltTol)) ) + if( (fabs(cdhat- here->MOS9cd) < + ckt->CKTreltol * MAX(fabs(cdhat),fabs( + here->MOS9cd)) + 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->MOS9vbs); + vbd = *(ckt->CKTstate0 + here->MOS9vbd); + vgs = *(ckt->CKTstate0 + here->MOS9vgs); + vds = *(ckt->CKTstate0 + here->MOS9vds); + vgd = vgs - vds; + vgb = vgs - vbs; + cdrain = here->MOS9mode * (here->MOS9cd + here->MOS9cbd); + if(ckt->CKTmode & (MODETRAN | MODETRANOP)) { + capgs = ( *(ckt->CKTstate0+here->MOS9capgs)+ + *(ckt->CKTstate1+here->MOS9capgs) + + GateSourceOverlapCap ); + capgd = ( *(ckt->CKTstate0+here->MOS9capgd)+ + *(ckt->CKTstate1+here->MOS9capgd) + + GateDrainOverlapCap ); + capgb = ( *(ckt->CKTstate0+here->MOS9capgb)+ + *(ckt->CKTstate1+here->MOS9capgb) + + GateBulkOverlapCap ); + } + goto bypass; + } + +#ifdef DETAILPROF +asm(" .globl mos9ptc"); +asm("mos9ptc:"); +#endif /* DETAILPROF */ + /* ok - bypass is out, do it the hard way */ + + von = model->MOS9type * here->MOS9von; + +#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->MOS9vds) >=0) { + vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->MOS9vgs) + ,von); + vds = vgs - vgd; + vds = DEVlimvds(vds,*(ckt->CKTstate0 + here->MOS9vds)); + vgd = vgs - vds; + } else { + vgd = DEVfetlim(vgd,vgdo,von); + vds = vgs - vgd; + if(!(ckt->CKTfixLimit)) { + vds = -DEVlimvds(-vds,-(*(ckt->CKTstate0 + + here->MOS9vds))); + } + vgs = vgd + vds; + } + if(vds >= 0) { + vbs = DEVpnjlim(vbs,*(ckt->CKTstate0 + here->MOS9vbs), + vt,here->MOS9sourceVcrit,&Check); + vbd = vbs-vds; + } else { + vbd = DEVpnjlim(vbd,*(ckt->CKTstate0 + here->MOS9vbd), + vt,here->MOS9drainVcrit,&Check); + vbs = vbd + vds; + } +#endif /*NODELIMITING*/ + + } else { + +#ifdef DETAILPROF +asm(" .globl mos9ptd"); +asm("mos9ptd:"); +#endif /* DETAILPROF */ + /* 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->MOS9off) { + vds= model->MOS9type * here->MOS9icVDS; + vgs= model->MOS9type * here->MOS9icVGS; + vbs= model->MOS9type * here->MOS9icVBS; + if((vds==0) && (vgs==0) && (vbs==0) && + ((ckt->CKTmode & + (MODETRAN|MODEDCOP|MODEDCTRANCURVE)) || + (!(ckt->CKTmode & MODEUIC)))) { + vbs = -1; + vgs = model->MOS9type * here->MOS9tVto; + vds = 0; + } + } else { + vbs=vgs=vds=0; + } + } + +#ifdef DETAILPROF +asm(" .globl mos9pte"); +asm("mos9pte:"); +#endif /* DETAILPROF */ + /* + * 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) { + arg=3*vt/(vbs*CONSTe); + arg = arg * arg * arg; + here->MOS9cbs = -SourceSatCur*(1+arg)+ckt->CKTgmin*vbs; + here->MOS9gbs = SourceSatCur*3*arg/vbs+ckt->CKTgmin; + } else { + evbs = exp(MIN(MAX_EXP_ARG,vbs/vt)); + here->MOS9gbs = SourceSatCur*evbs/vt + ckt->CKTgmin; + here->MOS9cbs = SourceSatCur*(evbs-1) + ckt->CKTgmin*vbs; + } + if(vbd <= -3*vt) { + arg=3*vt/(vbd*CONSTe); + arg = arg * arg * arg; + here->MOS9cbd = -DrainSatCur*(1+arg)+ckt->CKTgmin*vbd; + here->MOS9gbd = DrainSatCur*3*arg/vbd+ckt->CKTgmin; + } else { + evbd = exp(MIN(MAX_EXP_ARG,vbd/vt)); + here->MOS9gbd = DrainSatCur*evbd/vt + ckt->CKTgmin; + here->MOS9cbd = 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->MOS9mode = 1; + } else { + /* inverse mode */ + here->MOS9mode = -1; + } + +#ifdef DETAILPROF +asm(" .globl mos9ptf"); +asm("mos9ptf:"); +#endif /* DETAILPROF */ + { + /* + * subroutine moseq3(vds,vbs,vgs,gm,gds,gmbs, + * qg,qc,qb,cggb,cgdb,cgsb,cbgb,cbdb,cbsb) + */ + + /* + * this routine evaluates the drain current, its derivatives and + * the charges associated with the gate, channel and bulk + * for mosfets based on semi-empirical equations + */ + + /* + common /mosarg/ vto,beta,gamma,phi,phib,cox,xnsub,xnfs,xd,xj,xld, + 1 xlamda,uo,uexp,vbp,utra,vmax,xneff,xl,xw,vbi,von,vdsat,qspof, + 2 beta0,beta1,cdrain,xqco,xqc,fnarrw,fshort,lev + common /status/ omega,time,delta,delold(7),ag(7),vt,xni,egfet, + 1 xmu,sfactr,mode,modedc,icalc,initf,method,iord,maxord,noncon, + 2 iterno,itemno,nosolv,modac,ipiv,ivmflg,ipostp,iscrch,iofile + common /knstnt/ twopi,xlog2,xlog10,root2,rad,boltz,charge,ctok, + 1 gmin,reltol,abstol,vntol,trtol,chgtol,eps0,epssil,epsox, + 2 pivtol,pivrel + */ + + /* equivalence (xlamda,alpha),(vbp,theta),(uexp,eta),(utra,xkappa)*/ + + double coeff0 = 0.0631353e0; + double coeff1 = 0.8013292e0; + double coeff2 = -0.01110777e0; + double oneoverxl; /* 1/effective length */ + double eta; /* eta from model after length factor */ + double phibs; /* phi - vbs */ + double sqphbs; /* square root of phibs */ + double dsqdvb; /* */ + double sqphis; /* square root of phi */ + double sqphs3; /* square root of phi cubed */ + double wps; + double oneoverxj; /* 1/junction depth */ + double xjonxl; /* junction depth/effective length */ + double djonxj; + double wponxj; + double arga; + double argb; + double argc; + double dwpdvb; + double dadvb; + double dbdvb; + double gammas; + double fbodys; + double fbody; + double onfbdy; + double qbonco; + double vbix; + double wconxj; + double dfsdvb; + double dfbdvb; + double dqbdvb; + double vth; + double dvtdvb; + double csonco; + double cdonco; + double dxndvb; + double dvodvb; + double dvodvd; + double vgsx; + double dvtdvd; + double onfg; + double fgate; + double us; + double dfgdvg; + double dfgdvd; + double dfgdvb; + double dvsdvg; + double dvsdvb; + double dvsdvd; + double xn; + double vdsc; + double onvdsc; + double dvsdga; + double vdsx; + double dcodvb; + double cdnorm; + double cdo; + double cd1; + double fdrain; + double fd2; + double dfddvg; + double dfddvb; + double dfddvd; + double gdsat; + double cdsat; + double gdoncd; + double gdonfd; + double gdonfg; + double dgdvg; + double dgdvd; + double dgdvb; + double emax; + double emongd; + double demdvg; + double demdvd; + double demdvb; + double delxl; + double dldvd; + double dldem; + double ddldvg; + double ddldvd; + double ddldvb; + double dlonxl; + double xlfact; + double diddl; + double gds0; + double emoncd; + double ondvt; + double onxn; + double wfact; + double gms; + double gmw; + double fshort; + + /* + * bypasses the computation of charges + */ + + /* + * reference cdrain equations to source and + * charge equations to bulk + */ + vdsat = 0.0; + oneoverxl = 1.0/EffectiveLength; + eta = model->MOS9eta * 8.15e-22/(model->MOS9oxideCapFactor* + EffectiveLength*EffectiveLength*EffectiveLength); + /* + *.....square root term + */ + if ( (here->MOS9mode==1?vbs:vbd) <= 0.0 ) { + phibs = here->MOS9tPhi-(here->MOS9mode==1?vbs:vbd); + sqphbs = sqrt(phibs); + dsqdvb = -0.5/sqphbs; + } else { + sqphis = sqrt(here->MOS9tPhi); + sqphs3 = here->MOS9tPhi*sqphis; + sqphbs = sqphis/(1.0+(here->MOS9mode==1?vbs:vbd)/ + (here->MOS9tPhi+here->MOS9tPhi)); + phibs = sqphbs*sqphbs; + dsqdvb = -phibs/(sqphs3+sqphs3); + } + /* + *.....short channel effect factor + */ + if ( (model->MOS9junctionDepth != 0.0) && + (model->MOS9coeffDepLayWidth != 0.0) ) { + wps = model->MOS9coeffDepLayWidth*sqphbs; + oneoverxj = 1.0/model->MOS9junctionDepth; + xjonxl = model->MOS9junctionDepth*oneoverxl; + djonxj = model->MOS9latDiff*oneoverxj; + wponxj = wps*oneoverxj; + wconxj = coeff0+coeff1*wponxj+coeff2*wponxj*wponxj; + arga = wconxj+djonxj; + argc = wponxj/(1.0+wponxj); + argb = sqrt(1.0-argc*argc); + fshort = 1.0-xjonxl*(arga*argb-djonxj); + dwpdvb = model->MOS9coeffDepLayWidth*dsqdvb; + dadvb = (coeff1+coeff2*(wponxj+wponxj))*dwpdvb*oneoverxj; + dbdvb = -argc*argc*(1.0-argc)*dwpdvb/(argb*wps); + dfsdvb = -xjonxl*(dadvb*argb+arga*dbdvb); + } else { + fshort = 1.0; + dfsdvb = 0.0; + } + /* + *.....body effect + */ + gammas = model->MOS9gamma*fshort; + fbodys = 0.5*gammas/(sqphbs+sqphbs); + fbody = fbodys+model->MOS9narrowFactor/EffectiveWidth; + onfbdy = 1.0/(1.0+fbody); + dfbdvb = -fbodys*dsqdvb/sqphbs+fbodys*dfsdvb/fshort; + qbonco =gammas*sqphbs+model->MOS9narrowFactor*phibs/EffectiveWidth; + dqbdvb = gammas*dsqdvb+model->MOS9gamma*dfsdvb*sqphbs- + model->MOS9narrowFactor/EffectiveWidth; + + /* + *.....static feedback effect + */ + vbix = here->MOS9tVbi*model->MOS9type-eta*(here->MOS9mode*vds); + /* + *.....threshold voltage + */ + vth = vbix+qbonco; + dvtdvd = -eta; + dvtdvb = dqbdvb; + /* + *.....joint weak inversion and strong inversion + */ + von = vth; + if ( model->MOS9fastSurfaceStateDensity != 0.0 ) { + csonco = CHARGE*model->MOS9fastSurfaceStateDensity * + 1e4 /*(cm**2/m**2)*/ *EffectiveLength*EffectiveWidth * + here->MOS9m/OxideCap; + cdonco = qbonco/(phibs+phibs); + xn = 1.0+csonco+cdonco; + von = vth+vt*xn; + dxndvb = dqbdvb/(phibs+phibs)-qbonco*dsqdvb/(phibs*sqphbs); + dvodvd = dvtdvd; + dvodvb = dvtdvb+vt*dxndvb; + } else { + /* + *.....cutoff region + */ + if ( (here->MOS9mode==1?vgs:vgd) <= von ) { + cdrain = 0.0; + here->MOS9gm = 0.0; + here->MOS9gds = 0.0; + here->MOS9gmbs = 0.0; + goto innerline1000; + } + } + /* + *.....device is on + */ + vgsx = MAX((here->MOS9mode==1?vgs:vgd),von); + /* + *.....mobility modulation by gate voltage + */ + onfg = 1.0+model->MOS9theta*(vgsx-vth); + fgate = 1.0/onfg; + us = here->MOS9tSurfMob * 1e-4 /*(m**2/cm**2)*/ *fgate; + dfgdvg = -model->MOS9theta*fgate*fgate; + dfgdvd = -dfgdvg*dvtdvd; + dfgdvb = -dfgdvg*dvtdvb; + /* + *.....saturation voltage + */ + vdsat = (vgsx-vth)*onfbdy; + if ( model->MOS9maxDriftVel <= 0.0 ) { + dvsdvg = onfbdy; + dvsdvd = -dvsdvg*dvtdvd; + dvsdvb = -dvsdvg*dvtdvb-vdsat*dfbdvb*onfbdy; + } else { + vdsc = EffectiveLength*model->MOS9maxDriftVel/us; + onvdsc = 1.0/vdsc; + arga = (vgsx-vth)*onfbdy; + argb = sqrt(arga*arga+vdsc*vdsc); + vdsat = arga+vdsc-argb; + dvsdga = (1.0-arga/argb)*onfbdy; + dvsdvg = dvsdga-(1.0-vdsc/argb)*vdsc*dfgdvg*onfg; + dvsdvd = -dvsdvg*dvtdvd; + dvsdvb = -dvsdvg*dvtdvb-arga*dvsdga*dfbdvb; + } + /* + *.....current factors in linear region + */ + vdsx = MIN((here->MOS9mode*vds),vdsat); + if ( vdsx == 0.0 ) goto line900; + cdo = vgsx-vth-0.5*(1.0+fbody)*vdsx; + dcodvb = -dvtdvb-0.5*dfbdvb*vdsx; + /* + *.....normalized drain current + */ + cdnorm = cdo*vdsx; + here->MOS9gm = vdsx; + if ((here->MOS9mode*vds) > vdsat) here->MOS9gds = -dvtdvd*vdsx; + else here->MOS9gds = vgsx-vth-(1.0+fbody+dvtdvd)*vdsx; + here->MOS9gmbs = dcodvb*vdsx; + /* + *.....drain current without velocity saturation effect + */ + cd1 = Beta*cdnorm; + Beta = Beta*fgate; + cdrain = Beta*cdnorm; + here->MOS9gm = Beta*here->MOS9gm+dfgdvg*cd1; + here->MOS9gds = Beta*here->MOS9gds+dfgdvd*cd1; + here->MOS9gmbs = Beta*here->MOS9gmbs+dfgdvb*cd1; + /* + *.....velocity saturation factor + */ + if ( model->MOS9maxDriftVel > 0.0 ) { + fdrain = 1.0/(1.0+vdsx*onvdsc); + fd2 = fdrain*fdrain; + arga = fd2*vdsx*onvdsc*onfg; + dfddvg = -dfgdvg*arga; + if ((here->MOS9mode*vds) > vdsat) dfddvd = -dfgdvd*arga; + else dfddvd = -dfgdvd*arga-fd2*onvdsc; + dfddvb = -dfgdvb*arga; + /* + *.....drain current + */ + here->MOS9gm = fdrain*here->MOS9gm+dfddvg*cdrain; + here->MOS9gds = fdrain*here->MOS9gds+dfddvd*cdrain; + here->MOS9gmbs = fdrain*here->MOS9gmbs+dfddvb*cdrain; + cdrain = fdrain*cdrain; + Beta = Beta*fdrain; + } + /* + *.....channel length modulation + */ + if ((here->MOS9mode*vds) <= vdsat) { + if ( (model->MOS9maxDriftVel > 0.0) || + (model->MOS9alpha == 0.0) || + (ckt->CKTbadMos3) ) goto line700; + else { + arga = (here->MOS9mode*vds)/vdsat; + delxl = sqrt(model->MOS9kappa*model->MOS9alpha*vdsat/8); + dldvd = 4*delxl*arga*arga*arga/vdsat; + arga *= arga; + arga *= arga; + delxl *= arga; + ddldvg = 0.0; + ddldvd = -dldvd; + ddldvb = 0.0; + goto line520; + }; + }; + if ( model->MOS9maxDriftVel <= 0.0 ) goto line510; + if (model->MOS9alpha == 0.0) goto line700; + cdsat = cdrain; + gdsat = cdsat*(1.0-fdrain)*onvdsc; + gdsat = MAX(1.0e-12,gdsat); + gdoncd = gdsat/cdsat; + gdonfd = gdsat/(1.0-fdrain); + gdonfg = gdsat*onfg; + dgdvg = gdoncd*here->MOS9gm-gdonfd*dfddvg+gdonfg*dfgdvg; + dgdvd = gdoncd*here->MOS9gds-gdonfd*dfddvd+gdonfg*dfgdvd; + dgdvb = gdoncd*here->MOS9gmbs-gdonfd*dfddvb+gdonfg*dfgdvb; + + if (ckt->CKTbadMos3) + emax = cdsat*oneoverxl/gdsat; + else + emax = model->MOS9kappa * cdsat*oneoverxl/gdsat; + emoncd = emax/cdsat; + emongd = emax/gdsat; + demdvg = emoncd*here->MOS9gm-emongd*dgdvg; + demdvd = emoncd*here->MOS9gds-emongd*dgdvd; + demdvb = emoncd*here->MOS9gmbs-emongd*dgdvb; + + arga = 0.5*emax*model->MOS9alpha; + argc = model->MOS9kappa*model->MOS9alpha; + argb = sqrt(arga*arga+argc*((here->MOS9mode*vds)-vdsat)); + delxl = argb-arga; + dldvd = argc/(argb+argb); + dldem = 0.5*(arga/argb-1.0)*model->MOS9alpha; + ddldvg = dldem*demdvg; + ddldvd = dldem*demdvd-dldvd; + ddldvb = dldem*demdvb; + goto line520; +line510: + if (ckt->CKTbadMos3) { + delxl = sqrt(model->MOS9kappa*((here->MOS9mode*vds)-vdsat)* + model->MOS9alpha); + dldvd = 0.5*delxl/((here->MOS9mode*vds)-vdsat); + } else { + delxl = sqrt(model->MOS9kappa*model->MOS9alpha* + ((here->MOS9mode*vds)-vdsat+(vdsat/8))); + dldvd = 0.5*delxl/((here->MOS9mode*vds)-vdsat+(vdsat/8)); + }; + ddldvg = 0.0; + ddldvd = -dldvd; + ddldvb = 0.0; + /* + *.....punch through approximation + */ +line520: + if ( delxl > (0.5*EffectiveLength) ) { + delxl = EffectiveLength-(EffectiveLength*EffectiveLength/ + (4.0*delxl)); + arga = 4.0*(EffectiveLength-delxl)*(EffectiveLength-delxl)/ + (EffectiveLength*EffectiveLength); + ddldvg = ddldvg*arga; + ddldvd = ddldvd*arga; + ddldvb = ddldvb*arga; + dldvd = dldvd*arga; + } + /* + *.....saturation region + */ + dlonxl = delxl*oneoverxl; + xlfact = 1.0/(1.0-dlonxl); + cd1 = cdrain; + cdrain = cdrain*xlfact; + diddl = cdrain/(EffectiveLength-delxl); + here->MOS9gm = here->MOS9gm*xlfact+diddl*ddldvg; + here->MOS9gmbs = here->MOS9gmbs*xlfact+diddl*ddldvb; + gds0 = diddl*ddldvd; + here->MOS9gm = here->MOS9gm+gds0*dvsdvg; + here->MOS9gmbs = here->MOS9gmbs+gds0*dvsdvb; + here->MOS9gds = here->MOS9gds*xlfact+diddl*dldvd+gds0*dvsdvd; +/* here->MOS9gds = (here->MOS9gds*xlfact)+gds0*dvsdvd- + (cd1*ddldvd/(EffectiveLength*(1-2*dlonxl+dlonxl*dlonxl)));*/ + + /* + *.....finish strong inversion case + */ +line700: + if ( (here->MOS9mode==1?vgs:vgd) < von ) { + /* + *.....weak inversion + */ + onxn = 1.0/xn; + ondvt = onxn/vt; + wfact = exp( ((here->MOS9mode==1?vgs:vgd)-von)*ondvt ); + cdrain = cdrain*wfact; + gms = here->MOS9gm*wfact; + gmw = cdrain*ondvt; + here->MOS9gm = gmw; + if ((here->MOS9mode*vds) > vdsat) { + here->MOS9gm = here->MOS9gm+gds0*dvsdvg*wfact; + } + here->MOS9gds = here->MOS9gds*wfact+(gms-gmw)*dvodvd; + here->MOS9gmbs = here->MOS9gmbs*wfact+(gms-gmw)*dvodvb-gmw* + ((here->MOS9mode==1?vgs:vgd)-von)*onxn*dxndvb; + } + /* + *.....charge computation + */ + goto innerline1000; + /* + *.....special case of vds = 0.0d0 + */ +line900: + Beta = Beta*fgate; + cdrain = 0.0; + here->MOS9gm = 0.0; + here->MOS9gds = Beta*(vgsx-vth); + here->MOS9gmbs = 0.0; + if ( (model->MOS9fastSurfaceStateDensity != 0.0) && + ((here->MOS9mode==1?vgs:vgd) < von) ) { + here->MOS9gds *=exp(((here->MOS9mode==1?vgs:vgd)-von)/(vt*xn)); + } +innerline1000:; + /* + *.....done + */ + } + +#ifdef DETAILPROF +asm(" .globl mos9ptg"); +asm("mos9ptg:"); +#endif /* DETAILPROF */ + + /* now deal with n vs p polarity */ + + here->MOS9von = model->MOS9type * von; + here->MOS9vdsat = model->MOS9type * vdsat; + /* line 490 */ + /* + * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE + */ + here->MOS9cd=here->MOS9mode * cdrain - here->MOS9cbd; + + 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->MOS9vbs)))+ + ckt->CKTvoltTol)|| senflag ) +#endif /*CAPBYPASS*/ + { + /* can't bypass the diode capacitance calculations */ +#ifdef CAPZEROBYPASS + if(here->MOS9Cbs != 0 || here->MOS9Cbssw != 0 ) { +#endif /*CAPZEROBYPASS*/ + if (vbs < here->MOS9tDepCap){ + arg=1-vbs/here->MOS9tBulkPot; + /* + * 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->MOS9bulkJctBotGradingCoeff == + model->MOS9bulkJctSideGradingCoeff) { + if(model->MOS9bulkJctBotGradingCoeff == .5) { + sarg = sargsw = 1/sqrt(arg); + } else { + sarg = sargsw = + exp(-model->MOS9bulkJctBotGradingCoeff* + log(arg)); + } + } else { + if(model->MOS9bulkJctBotGradingCoeff == .5) { + sarg = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sarg = exp(-model->MOS9bulkJctBotGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + if(model->MOS9bulkJctSideGradingCoeff == .5) { + sargsw = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sargsw =exp(-model->MOS9bulkJctSideGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + } +#endif /*NOSQRT*/ + *(ckt->CKTstate0 + here->MOS9qbs) = + here->MOS9tBulkPot*(here->MOS9Cbs* + (1-arg*sarg)/(1-model->MOS9bulkJctBotGradingCoeff) + +here->MOS9Cbssw* + (1-arg*sargsw)/ + (1-model->MOS9bulkJctSideGradingCoeff)); + here->MOS9capbs=here->MOS9Cbs*sarg+ + here->MOS9Cbssw*sargsw; + } else { + *(ckt->CKTstate0 + here->MOS9qbs) = here->MOS9f4s + + vbs*(here->MOS9f2s+vbs*(here->MOS9f3s/2)); + here->MOS9capbs=here->MOS9f2s+here->MOS9f3s*vbs; + } +#ifdef CAPZEROBYPASS + } else { + *(ckt->CKTstate0 + here->MOS9qbs) = 0; + here->MOS9capbs=0; + } +#endif /*CAPZEROBYPASS*/ + } +#ifdef CAPBYPASS + if(((ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) || + fabs(delvbd) >= ckt->CKTreltol * MAX(fabs(vbd), + fabs(*(ckt->CKTstate0+here->MOS9vbd)))+ + ckt->CKTvoltTol)|| senflag ) +#endif /*CAPBYPASS*/ + /* can't bypass the diode capacitance calculations */ + { +#ifdef CAPZEROBYPASS + if(here->MOS9Cbd != 0 || here->MOS9Cbdsw != 0 ) { +#endif /*CAPZEROBYPASS*/ + if (vbd < here->MOS9tDepCap) { + arg=1-vbd/here->MOS9tBulkPot; + /* + * 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->MOS9bulkJctBotGradingCoeff == .5 && + model->MOS9bulkJctSideGradingCoeff == .5) { + sarg = sargsw = 1/sqrt(arg); + } else { + if(model->MOS9bulkJctBotGradingCoeff == .5) { + sarg = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sarg = exp(-model->MOS9bulkJctBotGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + if(model->MOS9bulkJctSideGradingCoeff == .5) { + sargsw = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sargsw =exp(-model->MOS9bulkJctSideGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + } +#endif /*NOSQRT*/ + *(ckt->CKTstate0 + here->MOS9qbd) = + here->MOS9tBulkPot*(here->MOS9Cbd* + (1-arg*sarg) + /(1-model->MOS9bulkJctBotGradingCoeff) + +here->MOS9Cbdsw* + (1-arg*sargsw) + /(1-model->MOS9bulkJctSideGradingCoeff)); + here->MOS9capbd=here->MOS9Cbd*sarg+ + here->MOS9Cbdsw*sargsw; + } else { + *(ckt->CKTstate0 + here->MOS9qbd) = here->MOS9f4d + + vbd * (here->MOS9f2d + vbd * here->MOS9f3d/2); + here->MOS9capbd=here->MOS9f2d + vbd * here->MOS9f3d; + } +#ifdef CAPZEROBYPASS + } else { + *(ckt->CKTstate0 + here->MOS9qbd) = 0; + here->MOS9capbd = 0; + } +#endif /*CAPZEROBYPASS*/ + } +#ifdef DETAILPROF +asm(" .globl mos9pth"); +asm("mos9pth:"); +#endif /* DETAILPROF */ + if(SenCond && (ckt->CKTsenInfo->SENmode==TRANSEN)) goto next2; + + if ( ckt->CKTmode & MODETRAN ) { + /* (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->MOS9capbd, + here->MOS9qbd); + if(error) return(error); + here->MOS9gbd += geq; + here->MOS9cbd += *(ckt->CKTstate0 + here->MOS9cqbd); + here->MOS9cd -= *(ckt->CKTstate0 + here->MOS9cqbd); + error = NIintegrate(ckt,&geq,&ceq,here->MOS9capbs, + here->MOS9qbs); + if(error) return(error); + here->MOS9gbs += geq; + here->MOS9cbs += *(ckt->CKTstate0 + here->MOS9cqbs); + } + } +#ifdef DETAILPROF +asm(" .globl mos9pti"); +asm("mos9pti:"); +#endif /* DETAILPROF */ + if(SenCond) goto next2; + + /* + * check convergence + */ + if ( (here->MOS9off == 0) || + (!(ckt->CKTmode & (MODEINITFIX|MODEINITSMSIG))) ){ + if (Check == 1) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + } + } + +#ifdef DETAILPROF +asm(" .globl mos9ptj"); +asm("mos9ptj:"); +#endif /* DETAILPROF */ + + /* save things away for next time */ + +next2: *(ckt->CKTstate0 + here->MOS9vbs) = vbs; + *(ckt->CKTstate0 + here->MOS9vbd) = vbd; + *(ckt->CKTstate0 + here->MOS9vgs) = vgs; + *(ckt->CKTstate0 + here->MOS9vds) = vds; + +#ifdef DETAILPROF +asm(" .globl mos9ptk"); +asm("mos9ptk:"); +#endif /* DETAILPROF */ + + /* + * 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->MOS9mode > 0){ + DEVqmeyer (vgs,vgd,vgb,von,vdsat, + (ckt->CKTstate0 + here->MOS9capgs), + (ckt->CKTstate0 + here->MOS9capgd), + (ckt->CKTstate0 + here->MOS9capgb), + here->MOS9tPhi,OxideCap); + } else { + DEVqmeyer (vgd,vgs,vgb,von,vdsat, + (ckt->CKTstate0 + here->MOS9capgd), + (ckt->CKTstate0 + here->MOS9capgs), + (ckt->CKTstate0 + here->MOS9capgb), + here->MOS9tPhi,OxideCap); + } + vgs1 = *(ckt->CKTstate1 + here->MOS9vgs); + vgd1 = vgs1 - *(ckt->CKTstate1 + here->MOS9vds); + vgb1 = vgs1 - *(ckt->CKTstate1 + here->MOS9vbs); + if(ckt->CKTmode & MODETRANOP) { + capgs = 2 * *(ckt->CKTstate0+here->MOS9capgs)+ + GateSourceOverlapCap ; + capgd = 2 * *(ckt->CKTstate0+here->MOS9capgd)+ + GateDrainOverlapCap ; + capgb = 2 * *(ckt->CKTstate0+here->MOS9capgb)+ + GateBulkOverlapCap ; + } else { + capgs = ( *(ckt->CKTstate0+here->MOS9capgs)+ + *(ckt->CKTstate1+here->MOS9capgs) + + GateSourceOverlapCap ); + capgd = ( *(ckt->CKTstate0+here->MOS9capgd)+ + *(ckt->CKTstate1+here->MOS9capgd) + + GateDrainOverlapCap ); + capgb = ( *(ckt->CKTstate0+here->MOS9capgb)+ + *(ckt->CKTstate1+here->MOS9capgb) + + GateBulkOverlapCap ); + } + if(ckt->CKTsenInfo){ + here->MOS9cgs = capgs; + here->MOS9cgd = capgd; + here->MOS9cgb = capgb; + } + +#ifdef DETAILPROF +asm(" .globl mos9ptl"); +asm("mos9ptl:"); +#endif /* DETAILPROF */ + /* + * store small-signal parameters (for meyer's model) + * all parameters already stored, so done... + */ + + + if(SenCond){ + if(ckt->CKTsenInfo->SENmode & (DCSEN|ACSEN)) { + continue; + } + } +#ifndef PREDICTOR + if (ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) { + *(ckt->CKTstate0 + here->MOS9qgs) = + (1+xfact) * *(ckt->CKTstate1 + here->MOS9qgs) + - xfact * *(ckt->CKTstate2 + here->MOS9qgs); + *(ckt->CKTstate0 + here->MOS9qgd) = + (1+xfact) * *(ckt->CKTstate1 + here->MOS9qgd) + - xfact * *(ckt->CKTstate2 + here->MOS9qgd); + *(ckt->CKTstate0 + here->MOS9qgb) = + (1+xfact) * *(ckt->CKTstate1 + here->MOS9qgb) + - xfact * *(ckt->CKTstate2 + here->MOS9qgb); + } else { +#endif /*PREDICTOR*/ + if(ckt->CKTmode & MODETRAN) { + *(ckt->CKTstate0 + here->MOS9qgs) = (vgs-vgs1)*capgs + + *(ckt->CKTstate1 + here->MOS9qgs) ; + *(ckt->CKTstate0 + here->MOS9qgd) = (vgd-vgd1)*capgd + + *(ckt->CKTstate1 + here->MOS9qgd) ; + *(ckt->CKTstate0 + here->MOS9qgb) = (vgb-vgb1)*capgb + + *(ckt->CKTstate1 + here->MOS9qgb) ; + } else { + /* TRANOP only */ + *(ckt->CKTstate0 + here->MOS9qgs) = vgs*capgs; + *(ckt->CKTstate0 + here->MOS9qgd) = vgd*capgd; + *(ckt->CKTstate0 + here->MOS9qgb) = vgb*capgb; + } +#ifndef PREDICTOR + } +#endif /*PREDICTOR*/ + } +bypass: + if(SenCond) continue; +#ifdef DETAILPROF +asm(" .globl mos9ptm"); +asm("mos9ptm:"); +#endif /* DETAILPROF */ + + 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->MOS9cqgs) =0; + if(capgd == 0) *(ckt->CKTstate0 + here->MOS9cqgd) =0; + if(capgb == 0) *(ckt->CKTstate0 + here->MOS9cqgb) =0; + /* + * calculate equivalent conductances and currents for + * meyer"s capacitors + */ + error = NIintegrate(ckt,&gcgs,&ceqgs,capgs,here->MOS9qgs); + if(error) return(error); + error = NIintegrate(ckt,&gcgd,&ceqgd,capgd,here->MOS9qgd); + if(error) return(error); + error = NIintegrate(ckt,&gcgb,&ceqgb,capgb,here->MOS9qgb); + if(error) return(error); + ceqgs=ceqgs-gcgs*vgs+ckt->CKTag[0]* + *(ckt->CKTstate0 + here->MOS9qgs); + ceqgd=ceqgd-gcgd*vgd+ckt->CKTag[0]* + *(ckt->CKTstate0 + here->MOS9qgd); + ceqgb=ceqgb-gcgb*vgb+ckt->CKTag[0]* + *(ckt->CKTstate0 + here->MOS9qgb); + } + /* + * store charge storage info for meyer's cap in lx table + */ + +#ifdef DETAILPROF +asm(" .globl mos9ptn"); +asm("mos9ptn:"); +#endif /* DETAILPROF */ + /* + * load current vector + */ + ceqbs = model->MOS9type * + (here->MOS9cbs-(here->MOS9gbs)*vbs); + ceqbd = model->MOS9type * + (here->MOS9cbd-(here->MOS9gbd)*vbd); + if (here->MOS9mode >= 0) { + xnrm=1; + xrev=0; + cdreq=model->MOS9type*(cdrain-here->MOS9gds*vds- + here->MOS9gm*vgs-here->MOS9gmbs*vbs); + } else { + xnrm=0; + xrev=1; + cdreq = -(model->MOS9type)*(cdrain-here->MOS9gds*(-vds)- + here->MOS9gm*vgd-here->MOS9gmbs*vbd); + } + *(ckt->CKTrhs + here->MOS9gNode) -= + (model->MOS9type * (ceqgs + ceqgb + ceqgd)); + *(ckt->CKTrhs + here->MOS9bNode) -= + (ceqbs + ceqbd - model->MOS9type * ceqgb); + *(ckt->CKTrhs + here->MOS9dNodePrime) += + (ceqbd - cdreq + model->MOS9type * ceqgd); + *(ckt->CKTrhs + here->MOS9sNodePrime) += + cdreq + ceqbs + model->MOS9type * ceqgs; + /* + * load y matrix + */ +/*printf(" loading %s at time %g\n",here->MOS9name,ckt->CKTtime);*/ +/*printf("%g %g %g %g %g\n", here->MOS9drainConductance,gcgd+gcgs+gcgb, + here->MOS9sourceConductance,here->MOS9gbd,here->MOS9gbs);*/ +/*printf("%g %g %g %g %g\n",-gcgb,0.0,0.0,here->MOS9gds,here->MOS9gm);*/ +/*printf("%g %g %g %g %g\n", here->MOS9gds,here->MOS9gmbs,gcgd,-gcgs,-gcgd);*/ +/*printf("%g %g %g %g %g\n", -gcgs,-gcgd,0.0,-gcgs,0.0);*/ + + *(here->MOS9DdPtr) += (here->MOS9drainConductance); + *(here->MOS9GgPtr) += ((gcgd+gcgs+gcgb)); + *(here->MOS9SsPtr) += (here->MOS9sourceConductance); + *(here->MOS9BbPtr) += (here->MOS9gbd+here->MOS9gbs+gcgb); + *(here->MOS9DPdpPtr) += + (here->MOS9drainConductance+here->MOS9gds+ + here->MOS9gbd+xrev*(here->MOS9gm+here->MOS9gmbs)+gcgd); + *(here->MOS9SPspPtr) += + (here->MOS9sourceConductance+here->MOS9gds+ + here->MOS9gbs+xnrm*(here->MOS9gm+here->MOS9gmbs)+gcgs); + *(here->MOS9DdpPtr) += (-here->MOS9drainConductance); + *(here->MOS9GbPtr) -= gcgb; + *(here->MOS9GdpPtr) -= gcgd; + *(here->MOS9GspPtr) -= gcgs; + *(here->MOS9SspPtr) += (-here->MOS9sourceConductance); + *(here->MOS9BgPtr) -= gcgb; + *(here->MOS9BdpPtr) -= here->MOS9gbd; + *(here->MOS9BspPtr) -= here->MOS9gbs; + *(here->MOS9DPdPtr) += (-here->MOS9drainConductance); + *(here->MOS9DPgPtr) += ((xnrm-xrev)*here->MOS9gm-gcgd); + *(here->MOS9DPbPtr) += (-here->MOS9gbd+(xnrm-xrev)*here->MOS9gmbs); + *(here->MOS9DPspPtr) += (-here->MOS9gds- + xnrm*(here->MOS9gm+here->MOS9gmbs)); + *(here->MOS9SPgPtr) += (-(xnrm-xrev)*here->MOS9gm-gcgs); + *(here->MOS9SPsPtr) += (-here->MOS9sourceConductance); + *(here->MOS9SPbPtr) += (-here->MOS9gbs-(xnrm-xrev)*here->MOS9gmbs); + *(here->MOS9SPdpPtr) += (-here->MOS9gds- + xrev*(here->MOS9gm+here->MOS9gmbs)); + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos9/mos9mask.c b/src/spicelib/devices/mos9/mos9mask.c new file mode 100644 index 000000000..d31e9cd5e --- /dev/null +++ b/src/spicelib/devices/mos9/mos9mask.c @@ -0,0 +1,171 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +Modified: Alan Gillespie +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "mos9defs.h" +#include "sperror.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +MOS9mAsk(ckt,inst,which,value) + CKTcircuit *ckt; + GENmodel *inst; + int which; + IFvalue *value; +{ + MOS9model *here = (MOS9model *)inst; + switch(which) { + case MOS9_MOD_TNOM: + value->rValue = here->MOS9tnom-CONSTCtoK; + return(OK); + case MOS9_MOD_VTO: + value->rValue = here->MOS9vt0; + return(OK); + case MOS9_MOD_KP: + value->rValue = here->MOS9transconductance; + return(OK); + case MOS9_MOD_GAMMA: + value->rValue = here->MOS9gamma; + return(OK); + case MOS9_MOD_PHI: + value->rValue = here->MOS9phi; + return(OK); + case MOS9_MOD_RD: + value->rValue = here->MOS9drainResistance; + return(OK); + case MOS9_MOD_RS: + value->rValue = here->MOS9sourceResistance; + return(OK); + case MOS9_MOD_CBD: + value->rValue = here->MOS9capBD; + return(OK); + case MOS9_MOD_CBS: + value->rValue = here->MOS9capBS; + return(OK); + case MOS9_MOD_IS: + value->rValue = here->MOS9jctSatCur; + return(OK); + case MOS9_MOD_PB: + value->rValue = here->MOS9bulkJctPotential; + return(OK); + case MOS9_MOD_CGSO: + value->rValue = here->MOS9gateSourceOverlapCapFactor; + return(OK); + case MOS9_MOD_CGDO: + value->rValue = here->MOS9gateDrainOverlapCapFactor; + return(OK); + case MOS9_MOD_CGBO: + value->rValue = here->MOS9gateBulkOverlapCapFactor; + return(OK); + case MOS9_MOD_CJ: + value->rValue = here->MOS9bulkCapFactor; + return(OK); + case MOS9_MOD_MJ: + value->rValue = here->MOS9bulkJctBotGradingCoeff; + return(OK); + case MOS9_MOD_CJSW: + value->rValue = here->MOS9sideWallCapFactor; + return(OK); + case MOS9_MOD_MJSW: + value->rValue = here->MOS9bulkJctSideGradingCoeff; + return(OK); + case MOS9_MOD_JS: + value->rValue = here->MOS9jctSatCurDensity; + return(OK); + case MOS9_MOD_TOX: + value->rValue = here->MOS9oxideThickness; + return(OK); + case MOS9_MOD_LD: + value->rValue = here->MOS9latDiff; + return(OK); + case MOS9_MOD_XL: + value->rValue = here->MOS9lengthAdjust; + return(OK); + case MOS9_MOD_WD: + value->rValue = here->MOS9widthNarrow; + return(OK); + case MOS9_MOD_XW: + value->rValue = here->MOS9widthAdjust; + return(OK); + case MOS9_MOD_DELVTO: + value->rValue = here->MOS9delvt0; + return(OK); + case MOS9_MOD_RSH: + value->rValue = here->MOS9sheetResistance; + return(OK); + case MOS9_MOD_U0: + value->rValue = here->MOS9surfaceMobility; + return(OK); + case MOS9_MOD_FC: + value->rValue = here->MOS9fwdCapDepCoeff; + return(OK); + case MOS9_MOD_NSUB: + value->rValue = here->MOS9substrateDoping; + return(OK); + case MOS9_MOD_TPG: + value->iValue = here->MOS9gateType; + return(OK); + case MOS9_MOD_NSS: + value->rValue = here->MOS9surfaceStateDensity; + return(OK); + case MOS9_MOD_NFS: + value->rValue = here->MOS9fastSurfaceStateDensity; + return(OK); + case MOS9_MOD_DELTA: + value->rValue = here->MOS9narrowFactor; + return(OK); + case MOS9_MOD_VMAX: + value->rValue = here->MOS9maxDriftVel; + return(OK); + case MOS9_MOD_XJ: + value->rValue = here->MOS9junctionDepth; + return(OK); + case MOS9_MOD_ETA: + value->rValue = here->MOS9eta; + return(OK); + case MOS9_MOD_XD: + value->rValue = here->MOS9coeffDepLayWidth; + return(OK); + case MOS9_DELTA: + value->rValue = here->MOS9delta; + return(OK); + case MOS9_MOD_THETA: + value->rValue = here->MOS9theta; + return(OK); + case MOS9_MOD_ALPHA: + value->rValue = here->MOS9alpha; + return(OK); + case MOS9_MOD_KAPPA: + value->rValue = here->MOS9kappa; + return(OK); + case MOS9_MOD_KF: + value->rValue = here->MOS9fNcoef; + return(OK); + case MOS9_MOD_AF: + value->rValue = here->MOS9fNexp; + return(OK); + + case MOS9_MOD_TYPE: + if (here->MOS9type > 0) + value->sValue = "nmos"; + else + value->sValue = "pmos"; + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + diff --git a/src/spicelib/devices/mos9/mos9mdel.c b/src/spicelib/devices/mos9/mos9mdel.c new file mode 100644 index 000000000..04b660f73 --- /dev/null +++ b/src/spicelib/devices/mos9/mos9mdel.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Alan Gillespie +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "mos9defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS9mDelete(inModel,modname,kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; +{ + MOS9model **model = (MOS9model **)inModel; + MOS9model *modfast = (MOS9model *)kill; + MOS9instance *here; + MOS9instance *prev = NULL; + MOS9model **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->MOS9nextModel)) { + if( (*model)->MOS9modName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->MOS9nextModel; /* cut deleted device out of list */ + for(here = (*model)->MOS9instances ; here ; here = here->MOS9nextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} diff --git a/src/spicelib/devices/mos9/mos9mpar.c b/src/spicelib/devices/mos9/mos9mpar.c new file mode 100644 index 000000000..3aed52e31 --- /dev/null +++ b/src/spicelib/devices/mos9/mos9mpar.c @@ -0,0 +1,202 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Alan Gillespie +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "mos9defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS9mParam(param,value,inModel) + int param; + IFvalue *value; + GENmodel *inModel; +{ + register MOS9model *model = (MOS9model *)inModel; + switch(param) { + case MOS9_MOD_VTO: + model->MOS9vt0 = value->rValue; + model->MOS9vt0Given = TRUE; + break; + case MOS9_MOD_KP: + model->MOS9transconductance = value->rValue; + model->MOS9transconductanceGiven = TRUE; + break; + case MOS9_MOD_GAMMA: + model->MOS9gamma = value->rValue; + model->MOS9gammaGiven = TRUE; + break; + case MOS9_MOD_PHI: + model->MOS9phi = value->rValue; + model->MOS9phiGiven = TRUE; + break; + case MOS9_MOD_RD: + model->MOS9drainResistance = value->rValue; + model->MOS9drainResistanceGiven = TRUE; + break; + case MOS9_MOD_RS: + model->MOS9sourceResistance = value->rValue; + model->MOS9sourceResistanceGiven = TRUE; + break; + case MOS9_MOD_CBD: + model->MOS9capBD = value->rValue; + model->MOS9capBDGiven = TRUE; + break; + case MOS9_MOD_CBS: + model->MOS9capBS = value->rValue; + model->MOS9capBSGiven = TRUE; + break; + case MOS9_MOD_IS: + model->MOS9jctSatCur = value->rValue; + model->MOS9jctSatCurGiven = TRUE; + break; + case MOS9_MOD_PB: + model->MOS9bulkJctPotential = value->rValue; + model->MOS9bulkJctPotentialGiven = TRUE; + break; + case MOS9_MOD_CGSO: + model->MOS9gateSourceOverlapCapFactor = value->rValue; + model->MOS9gateSourceOverlapCapFactorGiven = TRUE; + break; + case MOS9_MOD_CGDO: + model->MOS9gateDrainOverlapCapFactor = value->rValue; + model->MOS9gateDrainOverlapCapFactorGiven = TRUE; + break; + case MOS9_MOD_CGBO: + model->MOS9gateBulkOverlapCapFactor = value->rValue; + model->MOS9gateBulkOverlapCapFactorGiven = TRUE; + break; + case MOS9_MOD_RSH: + model->MOS9sheetResistance = value->rValue; + model->MOS9sheetResistanceGiven = TRUE; + break; + case MOS9_MOD_CJ: + model->MOS9bulkCapFactor = value->rValue; + model->MOS9bulkCapFactorGiven = TRUE; + break; + case MOS9_MOD_MJ: + model->MOS9bulkJctBotGradingCoeff = value->rValue; + model->MOS9bulkJctBotGradingCoeffGiven = TRUE; + break; + case MOS9_MOD_CJSW: + model->MOS9sideWallCapFactor = value->rValue; + model->MOS9sideWallCapFactorGiven = TRUE; + break; + case MOS9_MOD_MJSW: + model->MOS9bulkJctSideGradingCoeff = value->rValue; + model->MOS9bulkJctSideGradingCoeffGiven = TRUE; + break; + case MOS9_MOD_JS: + model->MOS9jctSatCurDensity = value->rValue; + model->MOS9jctSatCurDensityGiven = TRUE; + break; + case MOS9_MOD_TOX: + model->MOS9oxideThickness = value->rValue; + model->MOS9oxideThicknessGiven = TRUE; + break; + case MOS9_MOD_LD: + model->MOS9latDiff = value->rValue; + model->MOS9latDiffGiven = TRUE; + break; + case MOS9_MOD_XL: + model->MOS9lengthAdjust = value->rValue; + model->MOS9lengthAdjustGiven = TRUE; + break; + case MOS9_MOD_WD: + model->MOS9widthNarrow = value->rValue; + model->MOS9widthNarrowGiven = TRUE; + break; + case MOS9_MOD_XW: + model->MOS9widthAdjust = value->rValue; + model->MOS9widthAdjustGiven = TRUE; + break; + case MOS9_MOD_DELVTO: + model->MOS9delvt0 = value->rValue; + model->MOS9delvt0Given = TRUE; + break; + case MOS9_MOD_U0: + model->MOS9surfaceMobility = value->rValue; + model->MOS9surfaceMobilityGiven = TRUE; + break; + case MOS9_MOD_FC: + model->MOS9fwdCapDepCoeff = value->rValue; + model->MOS9fwdCapDepCoeffGiven = TRUE; + break; + case MOS9_MOD_NSUB: + model->MOS9substrateDoping = value->rValue; + model->MOS9substrateDopingGiven = TRUE; + break; + case MOS9_MOD_TPG: + model->MOS9gateType = value->iValue; + model->MOS9gateTypeGiven = TRUE; + break; + case MOS9_MOD_NSS: + model->MOS9surfaceStateDensity = value->rValue; + model->MOS9surfaceStateDensityGiven = TRUE; + break; + case MOS9_MOD_ETA: + model->MOS9eta = value->rValue; + model->MOS9etaGiven = TRUE; + break; + case MOS9_MOD_DELTA: + model->MOS9delta = value->rValue; + model->MOS9deltaGiven = TRUE; + break; + case MOS9_MOD_NFS: + model->MOS9fastSurfaceStateDensity = value->rValue; + model->MOS9fastSurfaceStateDensityGiven = TRUE; + break; + case MOS9_MOD_THETA: + model->MOS9theta = value->rValue; + model->MOS9thetaGiven = TRUE; + break; + case MOS9_MOD_VMAX: + model->MOS9maxDriftVel = value->rValue; + model->MOS9maxDriftVelGiven = TRUE; + break; + case MOS9_MOD_KAPPA: + model->MOS9kappa = value->rValue; + model->MOS9kappaGiven = TRUE; + break; + case MOS9_MOD_NMOS: + if(value->iValue) { + model->MOS9type = 1; + model->MOS9typeGiven = TRUE; + } + break; + case MOS9_MOD_PMOS: + if(value->iValue) { + model->MOS9type = -1; + model->MOS9typeGiven = TRUE; + } + break; + case MOS9_MOD_XJ: + model->MOS9junctionDepth = value->rValue; + model->MOS9junctionDepthGiven = TRUE; + break; + case MOS9_MOD_TNOM: + model->MOS9tnom = value->rValue+CONSTCtoK; + model->MOS9tnomGiven = TRUE; + break; + case MOS9_MOD_KF: + model->MOS9fNcoef = value->rValue; + model->MOS9fNcoefGiven = TRUE; + break; + case MOS9_MOD_AF: + model->MOS9fNexp = value->rValue; + model->MOS9fNexpGiven = TRUE; + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/mos9/mos9noi.c b/src/spicelib/devices/mos9/mos9noi.c new file mode 100644 index 000000000..06e79ebe3 --- /dev/null +++ b/src/spicelib/devices/mos9/mos9noi.c @@ -0,0 +1,220 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Gary W. Ng +Modified: Alan Gillespie +**********/ + +#include "ngspice.h" +#include +#include "mos9defs.h" +#include "cktdefs.h" +#include "fteconst.h" +#include "iferrmsg.h" +#include "noisedef.h" +#include "suffix.h" + +/* + * MOS9noise (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". + */ + +extern void NevalSrc(); +extern double Nintegrate(); + +int +MOS9noise (mode, operation, genmodel, ckt, data, OnDens) + int mode; + int operation; + GENmodel *genmodel; + CKTcircuit *ckt; + Ndata *data; + double *OnDens; +{ + MOS9model *firstModel = (MOS9model *) genmodel; + MOS9model *model; + MOS9instance *inst; + char name[N_MXVLNTH]; + double tempOnoise; + double tempInoise; + double noizDens[MOS9NSRCS]; + double lnNdens[MOS9NSRCS]; + int error; + int i; + + /* define the names of the noise sources */ + + static char *MOS9nNames[MOS9NSRCS] = { /* Note that we have to keep the order */ + "_rd", /* noise due to rd */ /* consistent with the index definitions */ + "_rs", /* noise due to rs */ /* in MOS9defs.h */ + "_id", /* noise due to id */ + "_1overf", /* flicker (1/f) noise */ + "" /* total transistor noise */ + }; + + for (model=firstModel; model != NULL; model=model->MOS9nextModel) { + for (inst=model->MOS9instances; inst != NULL; inst=inst->MOS9nextInstance) { + switch (operation) { + + case N_OPEN: + + /* see if we have to to produce a summary report */ + /* if so, name all the noise generators */ + + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + switch (mode) { + + case N_DENS: + for (i=0; i < MOS9NSRCS; i++) { + (void)sprintf(name,"onoise_%s%s",inst->MOS9name,MOS9nNames[i]); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(GENERIC **)NULL); + /* we've added one more plot */ + + + } + break; + + case INT_NOIZ: + for (i=0; i < MOS9NSRCS; i++) { + (void)sprintf(name,"onoise_total_%s%s",inst->MOS9name,MOS9nNames[i]); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(GENERIC **)NULL); + /* we've added one more plot */ + + + (void)sprintf(name,"inoise_total_%s%s",inst->MOS9name,MOS9nNames[i]); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(GENERIC **)NULL); + /* we've added one more plot */ + + + + } + break; + } + } + break; + + case N_CALC: + switch (mode) { + + case N_DENS: + NevalSrc(&noizDens[MOS9RDNOIZ],&lnNdens[MOS9RDNOIZ], + ckt,THERMNOISE,inst->MOS9dNodePrime,inst->MOS9dNode, + inst->MOS9drainConductance); + + NevalSrc(&noizDens[MOS9RSNOIZ],&lnNdens[MOS9RSNOIZ], + ckt,THERMNOISE,inst->MOS9sNodePrime,inst->MOS9sNode, + inst->MOS9sourceConductance); + + NevalSrc(&noizDens[MOS9IDNOIZ],&lnNdens[MOS9IDNOIZ], + ckt,THERMNOISE,inst->MOS9dNodePrime,inst->MOS9sNodePrime, + (2.0/3.0 * fabs(inst->MOS9gm))); + + NevalSrc(&noizDens[MOS9FLNOIZ],(double*)NULL,ckt, + N_GAIN,inst->MOS9dNodePrime, inst->MOS9sNodePrime, + (double)0.0); + noizDens[MOS9FLNOIZ] *= model->MOS9fNcoef * + exp(model->MOS9fNexp * + log(MAX(fabs(inst->MOS9cd),N_MINLOG))) / + (data->freq * + (inst->MOS9w - 2*model->MOS9widthNarrow) * + inst->MOS9m * + (inst->MOS9l - 2*model->MOS9latDiff) * + model->MOS9oxideCapFactor * model->MOS9oxideCapFactor); + lnNdens[MOS9FLNOIZ] = + log(MAX(noizDens[MOS9FLNOIZ],N_MINLOG)); + + noizDens[MOS9TOTNOIZ] = noizDens[MOS9RDNOIZ] + + noizDens[MOS9RSNOIZ] + + noizDens[MOS9IDNOIZ] + + noizDens[MOS9FLNOIZ]; + lnNdens[MOS9TOTNOIZ] = + log(MAX(noizDens[MOS9TOTNOIZ], N_MINLOG)); + + *OnDens += noizDens[MOS9TOTNOIZ]; + + if (data->delFreq == 0.0) { + + /* if we haven't done any previous integration, we need to */ + /* initialize our "history" variables */ + + for (i=0; i < MOS9NSRCS; i++) { + inst->MOS9nVar[LNLSTDENS][i] = lnNdens[i]; + } + + /* clear out our integration variables if it's the first pass */ + + if (data->freq == ((NOISEAN*)ckt->CKTcurJob)->NstartFreq) { + for (i=0; i < MOS9NSRCS; i++) { + inst->MOS9nVar[OUTNOIZ][i] = 0.0; + inst->MOS9nVar[INNOIZ][i] = 0.0; + } + } + } else { /* data->delFreq != 0.0 (we have to integrate) */ + for (i=0; i < MOS9NSRCS; i++) { + if (i != MOS9TOTNOIZ) { + tempOnoise = Nintegrate(noizDens[i], lnNdens[i], + inst->MOS9nVar[LNLSTDENS][i], data); + tempInoise = Nintegrate(noizDens[i] * data->GainSqInv , + lnNdens[i] + data->lnGainInv, + inst->MOS9nVar[LNLSTDENS][i] + data->lnGainInv, + data); + inst->MOS9nVar[LNLSTDENS][i] = lnNdens[i]; + data->outNoiz += tempOnoise; + data->inNoise += tempInoise; + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + inst->MOS9nVar[OUTNOIZ][i] += tempOnoise; + inst->MOS9nVar[OUTNOIZ][MOS9TOTNOIZ] += tempOnoise; + inst->MOS9nVar[INNOIZ][i] += tempInoise; + inst->MOS9nVar[INNOIZ][MOS9TOTNOIZ] += tempInoise; + } + } + } + } + if (data->prtSummary) { + for (i=0; i < MOS9NSRCS; i++) { /* print a summary report */ + data->outpVector[data->outNumber++] = noizDens[i]; + } + } + break; + + case INT_NOIZ: /* already calculated, just output */ + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + for (i=0; i < MOS9NSRCS; i++) { + data->outpVector[data->outNumber++] = inst->MOS9nVar[OUTNOIZ][i]; + data->outpVector[data->outNumber++] = inst->MOS9nVar[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/mos9/mos9par.c b/src/spicelib/devices/mos9/mos9par.c new file mode 100644 index 000000000..1d35827d2 --- /dev/null +++ b/src/spicelib/devices/mos9/mos9par.c @@ -0,0 +1,116 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Alan Gillespie +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "mos9defs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +MOS9param(param,value,inst,select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + MOS9instance *here = (MOS9instance *)inst; + switch(param) { + + case MOS9_M: + here->MOS9m = value->rValue; + here->MOS9mGiven = TRUE; + break; + case MOS9_W: + here->MOS9w = value->rValue; + here->MOS9wGiven = TRUE; + break; + case MOS9_L: + here->MOS9l = value->rValue; + here->MOS9lGiven = TRUE; + break; + case MOS9_AS: + here->MOS9sourceArea = value->rValue; + here->MOS9sourceAreaGiven = TRUE; + break; + case MOS9_AD: + here->MOS9drainArea = value->rValue; + here->MOS9drainAreaGiven = TRUE; + break; + case MOS9_PS: + here->MOS9sourcePerimiter = value->rValue; + here->MOS9sourcePerimiterGiven = TRUE; + break; + case MOS9_PD: + here->MOS9drainPerimiter = value->rValue; + here->MOS9drainPerimiterGiven = TRUE; + break; + case MOS9_NRS: + here->MOS9sourceSquares = value->rValue; + here->MOS9sourceSquaresGiven = TRUE; + break; + case MOS9_NRD: + here->MOS9drainSquares = value->rValue; + here->MOS9drainSquaresGiven = TRUE; + break; + case MOS9_OFF: + here->MOS9off = value->iValue; + break; + case MOS9_IC_VBS: + here->MOS9icVBS = value->rValue; + here->MOS9icVBSGiven = TRUE; + break; + case MOS9_IC_VDS: + here->MOS9icVDS = value->rValue; + here->MOS9icVDSGiven = TRUE; + break; + case MOS9_IC_VGS: + here->MOS9icVGS = value->rValue; + here->MOS9icVGSGiven = TRUE; + break; + case MOS9_TEMP: + here->MOS9temp = value->rValue+CONSTCtoK; + here->MOS9tempGiven = TRUE; + break; + case MOS9_IC: + switch(value->v.numValue){ + case 3: + here->MOS9icVBS = *(value->v.vec.rVec+2); + here->MOS9icVBSGiven = TRUE; + case 2: + here->MOS9icVGS = *(value->v.vec.rVec+1); + here->MOS9icVGSGiven = TRUE; + case 1: + here->MOS9icVDS = *(value->v.vec.rVec); + here->MOS9icVDSGiven = TRUE; + break; + default: + return(E_BADPARM); + } + break; + case MOS9_L_SENS: + if(value->iValue) { + here->MOS9senParmNo = 1; + here->MOS9sens_l = 1; + } + break; + case MOS9_W_SENS: + if(value->iValue) { + here->MOS9senParmNo = 1; + here->MOS9sens_w = 1; + } + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/mos9/mos9pzld.c b/src/spicelib/devices/mos9/mos9pzld.c new file mode 100644 index 000000000..2c6e8302b --- /dev/null +++ b/src/spicelib/devices/mos9/mos9pzld.c @@ -0,0 +1,141 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Alan Gillespie +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "complex.h" +#include "mos9defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS9pzLoad(inModel,ckt,s) + GENmodel *inModel; + CKTcircuit *ckt; + SPcomplex *s; +{ + MOS9model *model = (MOS9model *)inModel; + MOS9instance *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; + double EffectiveWidth; + + for( ; model != NULL; model = model->MOS9nextModel) { + for(here = model->MOS9instances; here!= NULL; + here = here->MOS9nextInstance) { + + if (here->MOS9mode < 0) { + xnrm=0; + xrev=1; + } else { + xnrm=1; + xrev=0; + } + /* + * meyer's model parameters + */ + + EffectiveWidth=here->MOS9w-2*model->MOS9widthNarrow+ + model->MOS9widthAdjust; + EffectiveLength=here->MOS9l - 2*model->MOS9latDiff+ + model->MOS9lengthAdjust; + + GateSourceOverlapCap = model->MOS9gateSourceOverlapCapFactor * + here->MOS9m * EffectiveWidth; + GateDrainOverlapCap = model->MOS9gateDrainOverlapCapFactor * + here->MOS9m * EffectiveWidth; + GateBulkOverlapCap = model->MOS9gateBulkOverlapCapFactor * + here->MOS9m * EffectiveLength; + + capgs = ( 2* *(ckt->CKTstate0+here->MOS9capgs)+ + GateSourceOverlapCap ); + capgd = ( 2* *(ckt->CKTstate0+here->MOS9capgd)+ + GateDrainOverlapCap ); + capgb = ( 2* *(ckt->CKTstate0+here->MOS9capgb)+ + GateBulkOverlapCap ); + xgs = capgs; + xgd = capgd; + xgb = capgb; + xbd = here->MOS9capbd; + xbs = here->MOS9capbs; + /*printf("mos2: xgs=%g, xgd=%g, xgb=%g, xbd=%g, xbs=%g\n", + xgs,xgd,xgb,xbd,xbs);*/ + /* + * load matrix + */ + + *(here->MOS9GgPtr ) += (xgd+xgs+xgb)*s->real; + *(here->MOS9GgPtr +1) += (xgd+xgs+xgb)*s->imag; + *(here->MOS9BbPtr ) += (xgb+xbd+xbs)*s->real; + *(here->MOS9BbPtr +1) += (xgb+xbd+xbs)*s->imag; + *(here->MOS9DPdpPtr ) += (xgd+xbd)*s->real; + *(here->MOS9DPdpPtr +1) += (xgd+xbd)*s->imag; + *(here->MOS9SPspPtr ) += (xgs+xbs)*s->real; + *(here->MOS9SPspPtr +1) += (xgs+xbs)*s->imag; + *(here->MOS9GbPtr ) -= xgb*s->real; + *(here->MOS9GbPtr +1) -= xgb*s->imag; + *(here->MOS9GdpPtr ) -= xgd*s->real; + *(here->MOS9GdpPtr +1) -= xgd*s->imag; + *(here->MOS9GspPtr ) -= xgs*s->real; + *(here->MOS9GspPtr +1) -= xgs*s->imag; + *(here->MOS9BgPtr ) -= xgb*s->real; + *(here->MOS9BgPtr +1) -= xgb*s->imag; + *(here->MOS9BdpPtr ) -= xbd*s->real; + *(here->MOS9BdpPtr +1) -= xbd*s->imag; + *(here->MOS9BspPtr ) -= xbs*s->real; + *(here->MOS9BspPtr +1) -= xbs*s->imag; + *(here->MOS9DPgPtr ) -= xgd*s->real; + *(here->MOS9DPgPtr +1) -= xgd*s->imag; + *(here->MOS9DPbPtr ) -= xbd*s->real; + *(here->MOS9DPbPtr +1) -= xbd*s->imag; + *(here->MOS9SPgPtr ) -= xgs*s->real; + *(here->MOS9SPgPtr +1) -= xgs*s->imag; + *(here->MOS9SPbPtr ) -= xbs*s->real; + *(here->MOS9SPbPtr +1) -= xbs*s->imag; + *(here->MOS9DdPtr) += here->MOS9drainConductance; + *(here->MOS9SsPtr) += here->MOS9sourceConductance; + *(here->MOS9BbPtr) += here->MOS9gbd+here->MOS9gbs; + *(here->MOS9DPdpPtr) += here->MOS9drainConductance+ + here->MOS9gds+here->MOS9gbd+ + xrev*(here->MOS9gm+here->MOS9gmbs); + *(here->MOS9SPspPtr) += here->MOS9sourceConductance+ + here->MOS9gds+here->MOS9gbs+ + xnrm*(here->MOS9gm+here->MOS9gmbs); + *(here->MOS9DdpPtr) -= here->MOS9drainConductance; + *(here->MOS9SspPtr) -= here->MOS9sourceConductance; + *(here->MOS9BdpPtr) -= here->MOS9gbd; + *(here->MOS9BspPtr) -= here->MOS9gbs; + *(here->MOS9DPdPtr) -= here->MOS9drainConductance; + *(here->MOS9DPgPtr) += (xnrm-xrev)*here->MOS9gm; + *(here->MOS9DPbPtr) += -here->MOS9gbd+(xnrm-xrev)*here->MOS9gmbs; + *(here->MOS9DPspPtr) -= here->MOS9gds+ + xnrm*(here->MOS9gm+here->MOS9gmbs); + *(here->MOS9SPgPtr) -= (xnrm-xrev)*here->MOS9gm; + *(here->MOS9SPsPtr) -= here->MOS9sourceConductance; + *(here->MOS9SPbPtr) -= here->MOS9gbs+(xnrm-xrev)*here->MOS9gmbs; + *(here->MOS9SPdpPtr) -= here->MOS9gds+ + xrev*(here->MOS9gm+here->MOS9gmbs); + + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos9/mos9sacl.c b/src/spicelib/devices/mos9/mos9sacl.c new file mode 100644 index 000000000..ba553cb93 --- /dev/null +++ b/src/spicelib/devices/mos9/mos9sacl.c @@ -0,0 +1,782 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Alan Gillespie +**********/ + +/* actually load the current ac sensitivity + * information into the array previously provided + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "const.h" +#include "mos9defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS9sAcLoad(inModel,ckt) +GENmodel *inModel; +CKTcircuit *ckt; +{ + MOS9model *model = (MOS9model *)inModel; + MOS9instance *here; + int xnrm; + int xrev; + double A0; + double Apert; + 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; + 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("MOS9senacload\n"); + printf("CKTomega = %.5e\n",ckt->CKTomega); +#endif /* SENSDEBUG */ + info = ckt->CKTsenInfo; + info->SENstatus = PERTURBATION; + for( ; model != NULL; model = model->MOS9nextModel) { + for(here = model->MOS9instances; here!= NULL; + here = here->MOS9nextInstance) { + + /* save the unperturbed values in the state vector */ + for(i=0; i <= 16; i++) + *(SaveState + i) = *(ckt->CKTstate0 + here->MOS9states + i); + + *(SaveState + 17) = here->MOS9sourceConductance; + *(SaveState + 18) = here->MOS9drainConductance; + *(SaveState + 19) = here->MOS9cd; + *(SaveState + 20) = here->MOS9cbs; + *(SaveState + 21) = here->MOS9cbd; + *(SaveState + 22) = here->MOS9gmbs; + *(SaveState + 23) = here->MOS9gm; + *(SaveState + 24) = here->MOS9gds; + *(SaveState + 25) = here->MOS9gbd; + *(SaveState + 26) = here->MOS9gbs; + *(SaveState + 27) = here->MOS9capbd; + *(SaveState + 28) = here->MOS9capbs; + *(SaveState + 29) = here->MOS9Cbd; + *(SaveState + 30) = here->MOS9Cbdsw; + *(SaveState + 31) = here->MOS9Cbs; + *(SaveState + 32) = here->MOS9Cbssw; + *(SaveState + 33) = here->MOS9f2d; + *(SaveState + 34) = here->MOS9f3d; + *(SaveState + 35) = here->MOS9f4d; + *(SaveState + 36) = here->MOS9f2s; + *(SaveState + 37) = here->MOS9f3s; + *(SaveState + 38) = here->MOS9f4s; + *(SaveState + 39) = here->MOS9cgs; + *(SaveState + 40) = here->MOS9cgd; + *(SaveState + 41) = here->MOS9cgb; + *(SaveState + 42) = here->MOS9vdsat; + *(SaveState + 43) = here->MOS9von; + save_mode = here->MOS9mode; + + xnrm=1; + xrev=0; + if (here->MOS9mode < 0) { + xnrm=0; + xrev=1; + } + + vbsOp = model->MOS9type * ( + *(ckt->CKTrhsOp+here->MOS9bNode) - + *(ckt->CKTrhsOp+here->MOS9sNodePrime)); + vbdOp = model->MOS9type * ( + *(ckt->CKTrhsOp+here->MOS9bNode) - + *(ckt->CKTrhsOp+here->MOS9dNodePrime)); + vspr = *(ckt->CKTrhsOld + here->MOS9sNode) + - *(ckt->CKTrhsOld + + here->MOS9sNodePrime) ; + ivspr = *(ckt->CKTirhsOld + here->MOS9sNode) + - *(ckt->CKTirhsOld + + here->MOS9sNodePrime) ; + vdpr = *(ckt->CKTrhsOld + here->MOS9dNode) + - *(ckt->CKTrhsOld + + here->MOS9dNodePrime) ; + ivdpr = *(ckt->CKTirhsOld + here->MOS9dNode) + - *(ckt->CKTirhsOld + + here->MOS9dNodePrime) ; + vgb = *(ckt->CKTrhsOld + here->MOS9gNode) + - *(ckt->CKTrhsOld + + here->MOS9bNode) ; + ivgb = *(ckt->CKTirhsOld + here->MOS9gNode) + - *(ckt->CKTirhsOld + + here->MOS9bNode) ; + vbs = *(ckt->CKTrhsOld + here->MOS9bNode) + - *(ckt->CKTrhsOld + + here->MOS9sNodePrime) ; + ivbs = *(ckt->CKTirhsOld + here->MOS9bNode) + - *(ckt->CKTirhsOld + + here->MOS9sNodePrime) ; + vbd = *(ckt->CKTrhsOld + here->MOS9bNode) + - *(ckt->CKTrhsOld + + here->MOS9dNodePrime) ; + ivbd = *(ckt->CKTirhsOld + here->MOS9bNode) + - *(ckt->CKTirhsOld + + here->MOS9dNodePrime) ; + 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->MOS9name); + printf("gate = %d ,drain = %d, drainprm = %d\n", + here->MOS9gNode,here->MOS9dNode,here->MOS9dNodePrime); + printf("source = %d , sourceprm = %d ,body = %d, senparmno = %d\n", + here->MOS9sNode ,here->MOS9sNodePrime, + here->MOS9bNode,here->MOS9senParmNo); + printf("\n without perturbation \n"); +#endif /* SENSDEBUG */ + /* without perturbation */ + *(ckt->CKTstate0 + here->MOS9vbs) = vbsOp; + *(ckt->CKTstate0 + here->MOS9vbd) = vbdOp; + + here->MOS9senPertFlag = ON ; + if(info->SENacpertflag == 1){ + /* store the unperturbed values of small signal parameters */ + if(error = MOS9load((GENmodel*)model,ckt)) return(error); + *(here->MOS9senCgs) = here->MOS9cgs; + *(here->MOS9senCgd) = here->MOS9cgd; + *(here->MOS9senCgb) = here->MOS9cgb; + *(here->MOS9senCbd) = here->MOS9capbd; + *(here->MOS9senCbs) = here->MOS9capbs; + *(here->MOS9senGds) = here->MOS9gds; + *(here->MOS9senGbs) = here->MOS9gbs; + *(here->MOS9senGbd) = here->MOS9gbd; + *(here->MOS9senGm) = here->MOS9gm; + *(here->MOS9senGmbs) = here->MOS9gmbs; + + } + xcgs0= *(here->MOS9senCgs) * ckt->CKTomega; + xcgd0= *(here->MOS9senCgd) * ckt->CKTomega; + xcgb0= *(here->MOS9senCgb) * ckt->CKTomega; + xbd0= *(here->MOS9senCbd) * ckt->CKTomega; + xbs0= *(here->MOS9senCbs) * ckt->CKTomega; + gds0= *(here->MOS9senGds); + gbs0= *(here->MOS9senGbs); + gbd0= *(here->MOS9senGbd); + gm0= *(here->MOS9senGm); + gmbs0= *(here->MOS9senGmbs); + gdpr0 = here->MOS9drainConductance; + gspr0 = here->MOS9sourceConductance; + + + 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 ,", xcgs0,xcgd0); + printf("xcgb0 = %.7e, xbd0 = %.7e,xbs0 = %.7e\n" ,xcgb0,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 * CONSTvt0 ; + 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->MOS9vbs) = Apert; + *(ckt->CKTstate0 + here->MOS9vbd) = vbdOp; + + if(error = MOS9load((GENmodel*)model,ckt)) return(error); + + *(here->MOS9senCgs + 1) = here->MOS9cgs; + *(here->MOS9senCgd + 1) = here->MOS9cgd; + *(here->MOS9senCgb + 1) = here->MOS9cgb; + *(here->MOS9senCbd + 1) = here->MOS9capbd; + *(here->MOS9senCbs + 1) = here->MOS9capbs; + *(here->MOS9senGds + 1) = here->MOS9gds; + *(here->MOS9senGbs + 1) = here->MOS9gbs; + *(here->MOS9senGbd + 1) = here->MOS9gbd; + *(here->MOS9senGm + 1) = here->MOS9gm; + *(here->MOS9senGmbs + 1) = here->MOS9gmbs; + + *(ckt->CKTstate0 + here->MOS9vbs) = A0; + + + } + + goto load; + + +pertvbd: /* Perturbation of vbd */ +#ifdef SENSDEBUG + printf("\nPerturbation of vbd\n"); +#endif /* SENSDEBUG */ + + flag = 2; + A0 = vbdOp; + DELA = info->SENpertfac * CONSTvt0 + 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->MOS9vbs) = vbsOp; + *(ckt->CKTstate0 + here->MOS9vbd) = Apert; + + if(error = MOS9load((GENmodel*)model,ckt)) return(error); + + *(here->MOS9senCgs + 2) = here->MOS9cgs; + *(here->MOS9senCgd + 2) = here->MOS9cgd; + *(here->MOS9senCgb + 2) = here->MOS9cgb; + *(here->MOS9senCbd + 2) = here->MOS9capbd; + *(here->MOS9senCbs + 2) = here->MOS9capbs; + *(here->MOS9senGds + 2) = here->MOS9gds; + *(here->MOS9senGbs + 2) = here->MOS9gbs; + *(here->MOS9senGbd + 2) = here->MOS9gbd; + *(here->MOS9senGm + 2) = here->MOS9gm; + *(here->MOS9senGmbs + 2) = here->MOS9gmbs; + + *(ckt->CKTstate0 + here->MOS9vbd) = A0; + + } + + goto load; + + +pertvgb: /* Perturbation of vgb */ +#ifdef SENSDEBUG + printf("\nPerturbation of vgb\n"); +#endif /* SENSDEBUG */ + + flag = 3; + A0 = model->MOS9type * (*(ckt->CKTrhsOp + here->MOS9gNode) + - *(ckt->CKTrhsOp + here->MOS9bNode)); + DELA = info->SENpertfac * A0 + 1e-8; + DELAinv = model->MOS9type * 1.0/DELA; + + + if(info->SENacpertflag == 1){ + /* store the values of small signal parameters + * corresponding to perturbed vgb */ + *(ckt->CKTstate0 + here->MOS9vbs) = vbsOp; + *(ckt->CKTstate0 + here->MOS9vbd) = vbdOp; + *(ckt->CKTrhsOp + here->MOS9bNode) -= DELA; + + if(error = MOS9load((GENmodel*)model,ckt)) return(error); + + *(here->MOS9senCgs + 3) = here->MOS9cgs; + *(here->MOS9senCgd + 3) = here->MOS9cgd; + *(here->MOS9senCgb + 3) = here->MOS9cgb; + *(here->MOS9senCbd + 3) = here->MOS9capbd; + *(here->MOS9senCbs + 3) = here->MOS9capbs; + *(here->MOS9senGds + 3) = here->MOS9gds; + *(here->MOS9senGbs + 3) = here->MOS9gbs; + *(here->MOS9senGbd + 3) = here->MOS9gbd; + *(here->MOS9senGm + 3) = here->MOS9gm; + *(here->MOS9senGmbs + 3) = here->MOS9gmbs; + + + *(ckt->CKTrhsOp + here->MOS9bNode) += DELA; + } + goto load; + +pertl: /* Perturbation of length */ + + if(here->MOS9sens_l == 0){ + goto pertw; + } +#ifdef SENSDEBUG + printf("\nPerturbation of length\n"); +#endif /* SENSDEBUG */ + flag = 4; + A0 = here->MOS9l; + 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->MOS9l = Apert; + + *(ckt->CKTstate0 + here->MOS9vbs) = vbsOp; + *(ckt->CKTstate0 + here->MOS9vbd) = vbdOp; + + if(error = MOS9load((GENmodel*)model,ckt)) return(error); + + *(here->MOS9senCgs + 4) = here->MOS9cgs; + *(here->MOS9senCgd + 4) = here->MOS9cgd; + *(here->MOS9senCgb + 4) = here->MOS9cgb; + *(here->MOS9senCbd + 4) = here->MOS9capbd; + *(here->MOS9senCbs + 4) = here->MOS9capbs; + *(here->MOS9senGds + 4) = here->MOS9gds; + *(here->MOS9senGbs + 4) = here->MOS9gbs; + *(here->MOS9senGbd + 4) = here->MOS9gbd; + *(here->MOS9senGm + 4) = here->MOS9gm; + *(here->MOS9senGmbs + 4) = here->MOS9gmbs; + + here->MOS9l = A0; + + } + + goto load; + +pertw: /* Perturbation of width */ + if(here->MOS9sens_w == 0) + goto next; +#ifdef SENSDEBUG + printf("\nPerturbation of width\n"); +#endif /* SENSDEBUG */ + flag = 5; + A0 = here->MOS9w; + 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->MOS9w = Apert; + here->MOS9drainArea *= (1 + info->SENpertfac); + here->MOS9sourceArea *= (1 + info->SENpertfac); + here->MOS9Cbd *= (1 + info->SENpertfac); + here->MOS9Cbs *= (1 + info->SENpertfac); + if(here->MOS9drainPerimiter){ + here->MOS9Cbdsw += here->MOS9Cbdsw * + DELA/here->MOS9drainPerimiter; + } + if(here->MOS9sourcePerimiter){ + here->MOS9Cbssw += here->MOS9Cbssw * + DELA/here->MOS9sourcePerimiter; + } + if(vbdOp >= here->MOS9tDepCap){ + arg = 1-model->MOS9fwdCapDepCoeff; + sarg = exp( (-model->MOS9bulkJctBotGradingCoeff) * + log(arg) ); + sargsw = exp( (-model->MOS9bulkJctSideGradingCoeff) * + log(arg) ); + here->MOS9f2d = here->MOS9Cbd*(1-model->MOS9fwdCapDepCoeff* + (1+model->MOS9bulkJctBotGradingCoeff))* sarg/arg + + here->MOS9Cbdsw*(1-model->MOS9fwdCapDepCoeff* + (1+model->MOS9bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS9f3d = here->MOS9Cbd * + model->MOS9bulkJctBotGradingCoeff * sarg/arg/ + model->MOS9bulkJctPotential + + here->MOS9Cbdsw * + model->MOS9bulkJctSideGradingCoeff * sargsw/arg / + model->MOS9bulkJctPotential; + here->MOS9f4d = here->MOS9Cbd*model->MOS9bulkJctPotential* + (1-arg*sarg)/ (1-model->MOS9bulkJctBotGradingCoeff) + + here->MOS9Cbdsw*model->MOS9bulkJctPotential* + (1-arg*sargsw)/ + (1-model->MOS9bulkJctSideGradingCoeff) + -here->MOS9f3d/2* + (here->MOS9tDepCap*here->MOS9tDepCap) + -here->MOS9tDepCap * here->MOS9f2d; + } + if(vbsOp >= here->MOS9tDepCap){ + arg = 1-model->MOS9fwdCapDepCoeff; + sarg = exp( (-model->MOS9bulkJctBotGradingCoeff) * + log(arg) ); + sargsw = exp( (-model->MOS9bulkJctSideGradingCoeff) * + log(arg) ); + here->MOS9f2s = here->MOS9Cbs*(1-model->MOS9fwdCapDepCoeff* + (1+model->MOS9bulkJctBotGradingCoeff))* sarg/arg + + here->MOS9Cbssw*(1-model->MOS9fwdCapDepCoeff* + (1+model->MOS9bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS9f3s = here->MOS9Cbs * + model->MOS9bulkJctBotGradingCoeff * sarg/arg/ + model->MOS9bulkJctPotential + here->MOS9Cbssw * + model->MOS9bulkJctSideGradingCoeff * sargsw/arg / + model->MOS9bulkJctPotential; + here->MOS9f4s = here->MOS9Cbs*model->MOS9bulkJctPotential* + (1-arg*sarg)/ (1-model->MOS9bulkJctBotGradingCoeff) + + here->MOS9Cbssw*model->MOS9bulkJctPotential* + (1-arg*sargsw)/ + (1-model->MOS9bulkJctSideGradingCoeff) + -here->MOS9f3s/2* + (here->MOS9tBulkPot*here->MOS9tBulkPot) + -here->MOS9tBulkPot * here->MOS9f2s; + } + + *(ckt->CKTstate0 + here->MOS9vbs) = vbsOp; + *(ckt->CKTstate0 + here->MOS9vbd) = vbdOp; + + if(error = MOS9load((GENmodel*)model,ckt)) return(error); + + *(here->MOS9senCgs + 5) = here->MOS9cgs; + *(here->MOS9senCgd + 5) = here->MOS9cgd; + *(here->MOS9senCgb + 5) = here->MOS9cgb; + *(here->MOS9senCbd + 5) = here->MOS9capbd; + *(here->MOS9senCbs + 5) = here->MOS9capbs; + *(here->MOS9senGds + 5) = here->MOS9gds; + *(here->MOS9senGbs + 5) = here->MOS9gbs; + *(here->MOS9senGbd + 5) = here->MOS9gbd; + *(here->MOS9senGm + 5) = here->MOS9gm; + *(here->MOS9senGmbs + 5) = here->MOS9gmbs; + + here->MOS9w = A0; + here->MOS9drainArea /= (1 + info->SENpertfac); + here->MOS9sourceArea /= (1 + info->SENpertfac); + } + +load: + + gds= *(here->MOS9senGds + flag); + gbs= *(here->MOS9senGbs + flag); + gbd= *(here->MOS9senGbd + flag); + gm= *(here->MOS9senGm + flag); + gmbs= *(here->MOS9senGmbs + flag); + if(flag == 5){ + gdpr = here->MOS9drainConductance * Apert/A0; + gspr = here->MOS9sourceConductance * Apert/A0; + } + else{ + gdpr = here->MOS9drainConductance; + gspr = here->MOS9sourceConductance; + } + + xcgs= *(here->MOS9senCgs + flag) * ckt->CKTomega; + xcgd= *(here->MOS9senCgd + flag) * ckt->CKTomega; + xcgb= *(here->MOS9senCgb + flag) * ckt->CKTomega; + xbd= *(here->MOS9senCbd + flag) * ckt->CKTomega; + xbs= *(here->MOS9senCbs + 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->MOS9senParmNo) ) continue; + if( (flag == 5) && (iparmno != (here->MOS9senParmNo + + here->MOS9sens_l)) ) continue; + + switch(flag){ + case 1: + DvDp = model->MOS9type * + (info->SEN_Sap[here->MOS9bNode][iparmno] + - info->SEN_Sap[here->MOS9sNodePrime][iparmno]); + break; + case 2: + DvDp = model->MOS9type * + ( info->SEN_Sap[here->MOS9bNode][iparmno] + - info->SEN_Sap[here->MOS9dNodePrime][iparmno]); + break; + case 3: + DvDp = model->MOS9type * + ( info->SEN_Sap[here->MOS9gNode][iparmno] + - info->SEN_Sap[here->MOS9bNode][iparmno]); + break; + case 4: + DvDp = 1; + break; + case 5: + DvDp = 1; + break; + } + *(info->SEN_RHS[here->MOS9bNode] + iparmno) -= + ( cb - cb0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->MOS9bNode] + iparmno) -= + ( icb - icb0) * DELAinv * DvDp; + + *(info->SEN_RHS[here->MOS9gNode] + iparmno) -= + ( cg - cg0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->MOS9gNode] + iparmno) -= + ( icg - icg0) * DELAinv * DvDp; + + if(here->MOS9sNode != here->MOS9sNodePrime){ + *(info->SEN_RHS[here->MOS9sNode] + iparmno) -= + ( cs - cs0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->MOS9sNode] + iparmno) -= + ( ics - ics0) * DELAinv * DvDp; + } + + *(info->SEN_RHS[here->MOS9sNodePrime] + iparmno) -= + ( csprm - csprm0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->MOS9sNodePrime] + iparmno) -= + ( icsprm - icsprm0) * DELAinv * DvDp; + + if(here->MOS9dNode != here->MOS9dNodePrime){ + *(info->SEN_RHS[here->MOS9dNode] + iparmno) -= + ( cd - cd0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->MOS9dNode] + iparmno) -= + ( icd - icd0) * DELAinv * DvDp; + } + + *(info->SEN_RHS[here->MOS9dNodePrime] + iparmno) -= + ( cdprm - cdprm0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->MOS9dNodePrime] + 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->MOS9senParmNo); + printf("A0 = %.5e , Apert = %.5e ,CONSTvt0 = %.5e \n", + A0,Apert,CONSTvt0); + printf("senb = %.7e + j%.7e ", + *(info->SEN_RHS[here->MOS9bNode] + iparmno), + *(info->SEN_iRHS[here->MOS9bNode] + iparmno)); + printf("seng = %.7e + j%.7e ", + *(info->SEN_RHS[here->MOS9gNode] + iparmno), + *(info->SEN_iRHS[here->MOS9gNode] + iparmno)); + printf("sens = %.7e + j%.7e ", + *(info->SEN_RHS[here->MOS9sNode] + iparmno), + *(info->SEN_iRHS[here->MOS9sNode] + iparmno)); + printf("sensprm = %.7e + j%.7e ", + *(info->SEN_RHS[here->MOS9sNodePrime] + iparmno), + *(info->SEN_iRHS[here->MOS9sNodePrime] + iparmno)); + printf("send = %.7e + j%.7e ", + *(info->SEN_RHS[here->MOS9dNode] + iparmno), + *(info->SEN_iRHS[here->MOS9dNode] + iparmno)); + printf("sendprm = %.7e + j%.7e ", + *(info->SEN_RHS[here->MOS9dNodePrime] + iparmno), + *(info->SEN_iRHS[here->MOS9dNodePrime] + 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->MOS9states + i) = *(SaveState + i); + + here->MOS9sourceConductance = *(SaveState + 17) ; + here->MOS9drainConductance = *(SaveState + 18) ; + here->MOS9cd = *(SaveState + 19) ; + here->MOS9cbs = *(SaveState + 20) ; + here->MOS9cbd = *(SaveState + 21) ; + here->MOS9gmbs = *(SaveState + 22) ; + here->MOS9gm = *(SaveState + 23) ; + here->MOS9gds = *(SaveState + 24) ; + here->MOS9gbd = *(SaveState + 25) ; + here->MOS9gbs = *(SaveState + 26) ; + here->MOS9capbd = *(SaveState + 27) ; + here->MOS9capbs = *(SaveState + 28) ; + here->MOS9Cbd = *(SaveState + 29) ; + here->MOS9Cbdsw = *(SaveState + 30) ; + here->MOS9Cbs = *(SaveState + 31) ; + here->MOS9Cbssw = *(SaveState + 32) ; + here->MOS9f2d = *(SaveState + 33) ; + here->MOS9f3d = *(SaveState + 34) ; + here->MOS9f4d = *(SaveState + 35) ; + here->MOS9f2s = *(SaveState + 36) ; + here->MOS9f3s = *(SaveState + 37) ; + here->MOS9f4s = *(SaveState + 38) ; + here->MOS9cgs = *(SaveState + 39) ; + here->MOS9cgd = *(SaveState + 40) ; + here->MOS9cgb = *(SaveState + 41) ; + here->MOS9vdsat = *(SaveState + 42) ; + here->MOS9von = *(SaveState + 43) ; + here->MOS9mode = save_mode ; + + here->MOS9senPertFlag = OFF; + } + } + info->SENstatus = NORMAL; +#ifdef SENSDEBUG + printf("MOS9senacload end\n"); +#endif /* SENSDEBUG */ + return(OK); +} + + diff --git a/src/spicelib/devices/mos9/mos9set.c b/src/spicelib/devices/mos9/mos9set.c new file mode 100644 index 000000000..f3a0583f6 --- /dev/null +++ b/src/spicelib/devices/mos9/mos9set.c @@ -0,0 +1,294 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Alan Gillespie +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "mos9defs.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +/* assuming silicon - make definition for epsilon of silicon */ +#define EPSSIL (11.7 * 8.854214871e-12) + +int +MOS9setup(matrix,inModel,ckt,states) + SMPmatrix *matrix; + GENmodel *inModel; + CKTcircuit *ckt; + int *states; + /* load the MOS9 device structure with those pointers needed later + * for fast matrix loading + */ + +{ + register MOS9model *model = (MOS9model *)inModel; + register MOS9instance *here; + int error; + CKTnode *tmp; + + /* loop through all the MOS9 device models */ + for( ; model != NULL; model = model->MOS9nextModel ) { + + /* perform model defaulting */ + if(!model->MOS9typeGiven) { + model->MOS9type = NMOS; + } + if(!model->MOS9latDiffGiven) { + model->MOS9latDiff = 0; + } + if(!model->MOS9lengthAdjustGiven) { + model->MOS9lengthAdjust = 0; + } + if(!model->MOS9widthNarrowGiven) { + model->MOS9widthNarrow = 0; + } + if(!model->MOS9widthAdjustGiven) { + model->MOS9widthAdjust = 0; + } + if(!model->MOS9delvt0Given) { + model->MOS9delvt0 = 0; + } + if(!model->MOS9jctSatCurDensityGiven) { + model->MOS9jctSatCurDensity = 0; + } + if(!model->MOS9jctSatCurGiven) { + model->MOS9jctSatCur = 1e-14; + } + if(!model->MOS9drainResistanceGiven) { + model->MOS9drainResistance = 0; + } + if(!model->MOS9sourceResistanceGiven) { + model->MOS9sourceResistance = 0; + } + if(!model->MOS9sheetResistanceGiven) { + model->MOS9sheetResistance = 0; + } + if(!model->MOS9transconductanceGiven) { + model->MOS9transconductance = 2e-5; + } + if(!model->MOS9gateSourceOverlapCapFactorGiven) { + model->MOS9gateSourceOverlapCapFactor = 0; + } + if(!model->MOS9gateDrainOverlapCapFactorGiven) { + model->MOS9gateDrainOverlapCapFactor = 0; + } + if(!model->MOS9gateBulkOverlapCapFactorGiven) { + model->MOS9gateBulkOverlapCapFactor = 0; + } + if(!model->MOS9vt0Given) { + model->MOS9vt0 = 0; + } + if(!model->MOS9capBDGiven) { + model->MOS9capBD = 0; + } + if(!model->MOS9capBSGiven) { + model->MOS9capBS = 0; + } + if(!model->MOS9bulkCapFactorGiven) { + model->MOS9bulkCapFactor = 0; + } + if(!model->MOS9sideWallCapFactorGiven) { + model->MOS9sideWallCapFactor = 0; + } + if(!model->MOS9bulkJctPotentialGiven) { + model->MOS9bulkJctPotential = .8; + } + if(!model->MOS9bulkJctBotGradingCoeffGiven) { + model->MOS9bulkJctBotGradingCoeff = .5; + } + if(!model->MOS9bulkJctSideGradingCoeffGiven) { + model->MOS9bulkJctSideGradingCoeff = .33; + } + if(!model->MOS9fwdCapDepCoeffGiven) { + model->MOS9fwdCapDepCoeff = .5; + } + if(!model->MOS9phiGiven) { + model->MOS9phi = .6; + } + if(!model->MOS9gammaGiven) { + model->MOS9gamma = 0; + } + if(!model->MOS9deltaGiven) { + model->MOS9delta = 0; + } + if(!model->MOS9maxDriftVelGiven) { + model->MOS9maxDriftVel = 0; + } + if(!model->MOS9junctionDepthGiven) { + model->MOS9junctionDepth = 0; + } + if(!model->MOS9fastSurfaceStateDensityGiven) { + model->MOS9fastSurfaceStateDensity = 0; + } + if(!model->MOS9etaGiven) { + model->MOS9eta = 0; + } + if(!model->MOS9thetaGiven) { + model->MOS9theta = 0; + } + if(!model->MOS9kappaGiven) { + model->MOS9kappa = .2; + } + if(!model->MOS9oxideThicknessGiven) { + model->MOS9oxideThickness = 1e-7; + } + if(!model->MOS9fNcoefGiven) { + model->MOS9fNcoef = 0; + } + if(!model->MOS9fNexpGiven) { + model->MOS9fNexp = 1; + } + + /* loop through all the instances of the model */ + for (here = model->MOS9instances; here != NULL ; + here=here->MOS9nextInstance) { + + CKTnode *tmpNode; + IFuid tmpName; + + /* allocate a chunk of the state vector */ + here->MOS9states = *states; + *states += MOS9NUMSTATES; + + if(!here->MOS9drainAreaGiven) { + here->MOS9drainArea = ckt->CKTdefaultMosAD; + } + if(!here->MOS9drainPerimiterGiven) { + here->MOS9drainPerimiter = 0; + } + if(!here->MOS9drainSquaresGiven) { + here->MOS9drainSquares = 1; + } + if(!here->MOS9icVBSGiven) { + here->MOS9icVBS = 0; + } + if(!here->MOS9icVDSGiven) { + here->MOS9icVDS = 0; + } + if(!here->MOS9icVGSGiven) { + here->MOS9icVGS = 0; + } + if(!here->MOS9sourcePerimiterGiven) { + here->MOS9sourcePerimiter = 0; + } + if(!here->MOS9sourceSquaresGiven) { + here->MOS9sourceSquares = 1; + } + if(!here->MOS9vdsatGiven) { + here->MOS9vdsat = 0; + } + if(!here->MOS9vonGiven) { + here->MOS9von = 0; + } + if(!here->MOS9modeGiven) { + here->MOS9mode = 1; + } + + if((model->MOS9drainResistance != 0 || + (model->MOS9sheetResistance != 0 && + here->MOS9drainSquares != 0 ) ) && + here->MOS9dNodePrime==0) { + error = CKTmkVolt(ckt,&tmp,here->MOS9name,"internal#drain"); + if(error) return(error); + here->MOS9dNodePrime = tmp->number; + if (ckt->CKTcopyNodesets) { + if (CKTinst2Node(ckt,here,1,&tmpNode,&tmpName)==OK) { + if (tmpNode->nsGiven) { + tmp->nodeset=tmpNode->nodeset; + tmp->nsGiven=tmpNode->nsGiven; + } + } + } + } else { + here->MOS9dNodePrime = here->MOS9dNode; + } + + if((model->MOS9sourceResistance != 0 || + (model->MOS9sheetResistance != 0 && + here->MOS9sourceSquares != 0 ) ) && + here->MOS9sNodePrime==0) { + error = CKTmkVolt(ckt,&tmp,here->MOS9name,"internal#source"); + if(error) return(error); + here->MOS9sNodePrime = tmp->number; + if (ckt->CKTcopyNodesets) { + if (CKTinst2Node(ckt,here,3,&tmpNode,&tmpName)==OK) { + if (tmpNode->nsGiven) { + tmp->nodeset=tmpNode->nodeset; + tmp->nsGiven=tmpNode->nsGiven; + } + } + } + } else { + here->MOS9sNodePrime = here->MOS9sNode; + } + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(MOS9DdPtr, MOS9dNode, MOS9dNode) + TSTALLOC(MOS9GgPtr, MOS9gNode, MOS9gNode) + TSTALLOC(MOS9SsPtr, MOS9sNode, MOS9sNode) + TSTALLOC(MOS9BbPtr, MOS9bNode, MOS9bNode) + TSTALLOC(MOS9DPdpPtr, MOS9dNodePrime, MOS9dNodePrime) + TSTALLOC(MOS9SPspPtr, MOS9sNodePrime, MOS9sNodePrime) + TSTALLOC(MOS9DdpPtr, MOS9dNode, MOS9dNodePrime) + TSTALLOC(MOS9GbPtr, MOS9gNode, MOS9bNode) + TSTALLOC(MOS9GdpPtr, MOS9gNode, MOS9dNodePrime) + TSTALLOC(MOS9GspPtr, MOS9gNode, MOS9sNodePrime) + TSTALLOC(MOS9SspPtr, MOS9sNode, MOS9sNodePrime) + TSTALLOC(MOS9BdpPtr, MOS9bNode, MOS9dNodePrime) + TSTALLOC(MOS9BspPtr, MOS9bNode, MOS9sNodePrime) + TSTALLOC(MOS9DPspPtr, MOS9dNodePrime, MOS9sNodePrime) + TSTALLOC(MOS9DPdPtr, MOS9dNodePrime, MOS9dNode) + TSTALLOC(MOS9BgPtr, MOS9bNode, MOS9gNode) + TSTALLOC(MOS9DPgPtr, MOS9dNodePrime, MOS9gNode) + TSTALLOC(MOS9SPgPtr, MOS9sNodePrime, MOS9gNode) + TSTALLOC(MOS9SPsPtr, MOS9sNodePrime, MOS9sNode) + TSTALLOC(MOS9DPbPtr, MOS9dNodePrime, MOS9bNode) + TSTALLOC(MOS9SPbPtr, MOS9sNodePrime, MOS9bNode) + TSTALLOC(MOS9SPdpPtr, MOS9sNodePrime, MOS9dNodePrime) + + } + } + return(OK); +} + +int +MOS9unsetup(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + MOS9model *model; + MOS9instance *here; + + for (model = (MOS9model *)inModel; model != NULL; + model = model->MOS9nextModel) + { + for (here = model->MOS9instances; here != NULL; + here=here->MOS9nextInstance) + { + if (here->MOS9dNodePrime + && here->MOS9dNodePrime != here->MOS9dNode) + { + CKTdltNNum(ckt, here->MOS9dNodePrime); + here->MOS9dNodePrime= 0; + } + if (here->MOS9sNodePrime + && here->MOS9sNodePrime != here->MOS9sNode) + { + CKTdltNNum(ckt, here->MOS9sNodePrime); + here->MOS9sNodePrime= 0; + } + } + } + return OK; +} diff --git a/src/spicelib/devices/mos9/mos9sld.c b/src/spicelib/devices/mos9/mos9sld.c new file mode 100644 index 000000000..f6759197f --- /dev/null +++ b/src/spicelib/devices/mos9/mos9sld.c @@ -0,0 +1,625 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Alan Gillespie +**********/ + +/* actually load the current sensitivity + * information into the array previously provided + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "mos9defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS9sLoad(inModel,ckt) +GENmodel *inModel; +CKTcircuit *ckt; +{ + MOS9model *model = (MOS9model *)inModel; + MOS9instance *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; + double EffectiveWidth; + SENstruct *info; + +#ifdef SENSDEBUG + printf("MOS9senload \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 = model->MOS9nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MOS9instances; here != NULL ; + here=here->MOS9nextInstance) { + + +#ifdef SENSDEBUG + printf("senload instance name %s\n",here->MOS9name); + printf("gate = %d ,drain = %d, drainprm = %d\n", + here->MOS9gNode,here->MOS9dNode,here->MOS9dNodePrime); + printf("source = %d , sourceprm = %d ,body = %d, senparmno = %d\n", + here->MOS9sNode ,here->MOS9sNodePrime, + here->MOS9bNode,here->MOS9senParmNo); +#endif /* SENSDEBUG */ + + + /* save the unperturbed values in the state vector */ + for(i=0; i <= 16; i++){ + *(SaveState + i) = *(ckt->CKTstate0 + here->MOS9states + i); + } + + *(SaveState + 17) = here->MOS9sourceConductance; + *(SaveState + 18) = here->MOS9drainConductance; + *(SaveState + 19) = here->MOS9cd; + *(SaveState + 20) = here->MOS9cbs; + *(SaveState + 21) = here->MOS9cbd; + *(SaveState + 22) = here->MOS9gmbs; + *(SaveState + 23) = here->MOS9gm; + *(SaveState + 24) = here->MOS9gds; + *(SaveState + 25) = here->MOS9gbd; + *(SaveState + 26) = here->MOS9gbs; + *(SaveState + 27) = here->MOS9capbd; + *(SaveState + 28) = here->MOS9capbs; + *(SaveState + 29) = here->MOS9Cbd; + *(SaveState + 30) = here->MOS9Cbdsw; + *(SaveState + 31) = here->MOS9Cbs; + *(SaveState + 32) = here->MOS9Cbssw; + *(SaveState + 33) = here->MOS9f2d; + *(SaveState + 34) = here->MOS9f3d; + *(SaveState + 35) = here->MOS9f4d; + *(SaveState + 36) = here->MOS9f2s; + *(SaveState + 37) = here->MOS9f3s; + *(SaveState + 38) = here->MOS9f4s; + *(SaveState + 39) = here->MOS9cgs; + *(SaveState + 40) = here->MOS9cgd; + *(SaveState + 41) = here->MOS9cgb; + *(SaveState + 42) = here->MOS9vdsat; + *(SaveState + 43) = here->MOS9von; + save_mode = here->MOS9mode; + + + if(here->MOS9senParmNo == 0) goto next1; + +#ifdef SENSDEBUG + printf("without perturbation \n"); +#endif /* SENSDEBUG */ + + cdpr0= here->MOS9cd; + cspr0= -(here->MOS9cd + here->MOS9cbd + here->MOS9cbs); + if((info->SENmode == TRANSEN) && + (ckt->CKTmode & MODEINITTRAN)){ + qgs0 = *(ckt->CKTstate1 + here->MOS9qgs); + qgd0 = *(ckt->CKTstate1 + here->MOS9qgd); + qgb0 = *(ckt->CKTstate1 + here->MOS9qgb); + } + else{ + qgs0 = *(ckt->CKTstate0 + here->MOS9qgs); + qgd0 = *(ckt->CKTstate0 + here->MOS9qgd); + qgb0 = *(ckt->CKTstate0 + here->MOS9qgb); + } + + here->MOS9senPertFlag = ON; + error = MOS9load((GENmodel*)model,ckt); + if(error) return(error); + + cd0 = here->MOS9cd ; + cbd0 = here->MOS9cbd ; + cbs0 = here->MOS9cbs ; + gspr0= here->MOS9sourceConductance ; + gdpr0= here->MOS9drainConductance ; + + qbs0 = *(ckt->CKTstate0 + here->MOS9qbs); + qbd0 = *(ckt->CKTstate0 + here->MOS9qbd); + + for( flag = 0 ; flag <= 1 ; flag++){ + if(here->MOS9sens_l == 0) + if(flag == 0) goto next2; + if(here->MOS9sens_w == 0) + if(flag == 1) goto next2; + if(flag == 0){ + A0 = here->MOS9l; + DELA = info->SENpertfac * A0; + DELAinv = 1.0/DELA; + Apert = A0 + DELA; + here->MOS9l = Apert; + } + else{ + A0 = here->MOS9w; + DELA = info->SENpertfac * A0; + DELAinv = 1.0/DELA; + Apert = A0 + DELA; + here->MOS9w = Apert; + here->MOS9drainArea *= (1 + info->SENpertfac); + here->MOS9sourceArea *= (1 + info->SENpertfac); + here->MOS9Cbd *= (1 + info->SENpertfac); + here->MOS9Cbs *= (1 + info->SENpertfac); + if(here->MOS9drainPerimiter){ + here->MOS9Cbdsw += here->MOS9Cbdsw * + DELA/here->MOS9drainPerimiter; + } + if(here->MOS9sourcePerimiter){ + here->MOS9Cbssw += here->MOS9Cbssw * + DELA/here->MOS9sourcePerimiter; + } + if(*(ckt->CKTstate0 + here->MOS9vbd) >= + here->MOS9tDepCap){ + arg = 1-model->MOS9fwdCapDepCoeff; + sarg = exp( (-model->MOS9bulkJctBotGradingCoeff) * + log(arg) ); + sargsw = exp( (-model->MOS9bulkJctSideGradingCoeff) * + log(arg) ); + here->MOS9f2d = here->MOS9Cbd* + (1-model->MOS9fwdCapDepCoeff* + (1+model->MOS9bulkJctBotGradingCoeff))* sarg/arg + + here->MOS9Cbdsw*(1-model->MOS9fwdCapDepCoeff* + (1+model->MOS9bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS9f3d = here->MOS9Cbd * + model->MOS9bulkJctBotGradingCoeff * sarg/arg/ + model->MOS9bulkJctPotential + + here->MOS9Cbdsw * + model->MOS9bulkJctSideGradingCoeff *sargsw/arg / + model->MOS9bulkJctPotential; + here->MOS9f4d = here->MOS9Cbd* + model->MOS9bulkJctPotential*(1-arg*sarg)/ + (1-model->MOS9bulkJctBotGradingCoeff) + + here->MOS9Cbdsw*model->MOS9bulkJctPotential* + (1-arg*sargsw)/ + (1-model->MOS9bulkJctSideGradingCoeff) + -here->MOS9f3d/2* + (here->MOS9tDepCap*here->MOS9tDepCap) + -here->MOS9tDepCap * here->MOS9f2d; + } + if(*(ckt->CKTstate0 + here->MOS9vbs) >= + here->MOS9tDepCap){ + arg = 1-model->MOS9fwdCapDepCoeff; + sarg = exp( (-model->MOS9bulkJctBotGradingCoeff) * + log(arg) ); + sargsw = exp( (-model->MOS9bulkJctSideGradingCoeff) * + log(arg) ); + here->MOS9f2s = here->MOS9Cbs* + (1-model->MOS9fwdCapDepCoeff* + (1+model->MOS9bulkJctBotGradingCoeff))* sarg/arg + + here->MOS9Cbssw*(1-model->MOS9fwdCapDepCoeff* + (1+model->MOS9bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS9f3s = here->MOS9Cbs * + model->MOS9bulkJctBotGradingCoeff * sarg/arg/ + model->MOS9bulkJctPotential + + here->MOS9Cbssw * + model->MOS9bulkJctSideGradingCoeff * sargsw/arg/ + model->MOS9bulkJctPotential; + here->MOS9f4s = here->MOS9Cbs* + model->MOS9bulkJctPotential*(1-arg*sarg)/ + (1-model->MOS9bulkJctBotGradingCoeff) + + here->MOS9Cbssw*model->MOS9bulkJctPotential* + (1-arg*sargsw)/ + (1-model->MOS9bulkJctSideGradingCoeff) + -here->MOS9f3s/2* + (here->MOS9tBulkPot*here->MOS9tBulkPot) + -here->MOS9tBulkPot * here->MOS9f2s; + } + here->MOS9drainConductance *= Apert/A0; + here->MOS9sourceConductance *= Apert/A0; + } + + +#ifdef SENSDEBUG + if(flag == 0) + printf("perturbation of l\n"); + if(flag == 1) + printf("perturbation of w\n"); +#endif /* SENSDEBUG */ + + error = MOS9load((GENmodel*)model,ckt); + if(error) return(error); + + if(flag == 0){ + here->MOS9l = A0; + } + else{ + here->MOS9w = A0; + here->MOS9drainArea /= (1 + info->SENpertfac); + here->MOS9sourceArea /= (1 + info->SENpertfac); + here->MOS9drainConductance *= A0/Apert; + here->MOS9sourceConductance *= A0/Apert; + } + cd = here->MOS9cd ; + cbd = here->MOS9cbd ; + cbs = here->MOS9cbs ; + + gspr= here->MOS9sourceConductance ; + gdpr= here->MOS9drainConductance ; + + DcdDp = (cd - cd0) * DELAinv; + DcbsDp = (cbs - cbs0) * DELAinv; + DcbdDp = (cbd - cbd0) * DELAinv; + DcbDp = ( DcbsDp + DcbdDp ); + + DcdprDp = 0; + DcsprDp = 0; + if(here->MOS9dNode != here->MOS9dNodePrime) + if(gdpr0) DcdprDp = cdpr0 * (gdpr - gdpr0)/gdpr0 * DELAinv; + if(here->MOS9sNode != here->MOS9sNodePrime) + if(gspr0) DcsprDp = cspr0 * (gspr - gspr0)/gspr0 * DELAinv; + + DcdprmDp = ( - DcdprDp + DcdDp); + DcsprmDp = ( - DcbsDp - DcdDp - DcbdDp - DcsprDp); + + if(flag == 0){ + EffectiveLength = here->MOS9l + - 2*model->MOS9latDiff + model->MOS9lengthAdjust; + if(EffectiveLength == 0){ + DqgsDp = 0; + DqgdDp = 0; + DqgbDp = 0; + } + else{ + DqgsDp = model->MOS9type * qgs0 / EffectiveLength; + DqgdDp = model->MOS9type * qgd0 / EffectiveLength; + DqgbDp = model->MOS9type * qgb0 / EffectiveLength; + } + } + else{ + EffectiveWidth = here->MOS9w + - 2*model->MOS9widthNarrow + model->MOS9widthAdjust; + DqgsDp = model->MOS9type * qgs0 / EffectiveWidth; + DqgdDp = model->MOS9type * qgd0 / EffectiveWidth; + DqgbDp = model->MOS9type * qgb0 / EffectiveWidth; + } + + + qbd = *(ckt->CKTstate0 + here->MOS9qbd); + qbs = *(ckt->CKTstate0 + here->MOS9qbs); + + DqbsDp = model->MOS9type * (qbs - qbs0)*DELAinv; + DqbdDp = model->MOS9type * (qbd - qbd0)*DELAinv; + + if(flag == 0){ + *(here->MOS9dphigs_dl) = DqgsDp; + *(here->MOS9dphigd_dl) = DqgdDp; + *(here->MOS9dphibs_dl) = DqbsDp; + *(here->MOS9dphibd_dl) = DqbdDp; + *(here->MOS9dphigb_dl) = DqgbDp; + } + else{ + *(here->MOS9dphigs_dw) = DqgsDp; + *(here->MOS9dphigd_dw) = DqgdDp; + *(here->MOS9dphibs_dw) = DqbsDp; + *(here->MOS9dphibd_dw) = DqbdDp; + *(here->MOS9dphigb_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->MOS9tDepCap); + printf("\n"); +#endif /* SENSDEBUG*/ + if((info->SENmode == TRANSEN) && + (ckt->CKTmode & MODEINITTRAN)) + goto next2; + + /* + * load RHS matrix + */ + + if(flag == 0){ + *(info->SEN_RHS[here->MOS9bNode] + here->MOS9senParmNo) + -= model->MOS9type * DcbDp; + *(info->SEN_RHS[here->MOS9dNode] + here->MOS9senParmNo) + -= model->MOS9type * DcdprDp; + *(info->SEN_RHS[here->MOS9dNodePrime] + here->MOS9senParmNo) + -= model->MOS9type * DcdprmDp; + *(info->SEN_RHS[here->MOS9sNode] + here->MOS9senParmNo) + -= model->MOS9type * DcsprDp; + *(info->SEN_RHS[here->MOS9sNodePrime] + here->MOS9senParmNo) + -= model->MOS9type * DcsprmDp; + } + else{ + offset = here->MOS9sens_l; + + *(info->SEN_RHS[here->MOS9bNode] + here->MOS9senParmNo + + offset) -= model->MOS9type * DcbDp; + *(info->SEN_RHS[here->MOS9dNode] + here->MOS9senParmNo + + offset) -= model->MOS9type * DcdprDp; + *(info->SEN_RHS[here->MOS9dNodePrime] + here->MOS9senParmNo + + offset) -= model->MOS9type * DcdprmDp; + *(info->SEN_RHS[here->MOS9sNode] + here->MOS9senParmNo + + offset) -= model->MOS9type * DcsprDp; + *(info->SEN_RHS[here->MOS9sNodePrime] + here->MOS9senParmNo + + offset) -= model->MOS9type * DcsprmDp; + } +#ifdef SENSDEBUG + printf("after loading\n"); + if(flag == 0){ + printf("DcbDp=%.7e\n", + *(info->SEN_RHS[here->MOS9bNode] + + here->MOS9senParmNo)); + printf("DcdprDp=%.7e\n", + *(info->SEN_RHS[here->MOS9dNode] + + here->MOS9senParmNo)); + printf("DcsprDp=%.7e\n", + *(info->SEN_RHS[here->MOS9sNode] + + here->MOS9senParmNo)); + printf("DcdprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS9dNodePrime] + + here->MOS9senParmNo)); + printf("DcsprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS9sNodePrime] + + here->MOS9senParmNo)); + printf("\n"); + } + else{ + printf("DcbDp=%.7e\n", + *(info->SEN_RHS[here->MOS9bNode] + + here->MOS9senParmNo + here->MOS9sens_l)); + printf("DcdprDp=%.7e\n", + *(info->SEN_RHS[here->MOS9dNode] + + here->MOS9senParmNo + here->MOS9sens_l)); + printf("DcsprDp=%.7e\n", + *(info->SEN_RHS[here->MOS9sNode] + + here->MOS9senParmNo + here->MOS9sens_l)); + printf("DcdprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS9dNodePrime] + + here->MOS9senParmNo + here->MOS9sens_l)); + printf("DcsprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS9sNodePrime] + + here->MOS9senParmNo + here->MOS9sens_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->MOS9bNode] + iparmno)); + printf("DcdprDp=%.7e\n", + *(info->SEN_RHS[here->MOS9dNode] + iparmno)); + printf("DcdprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS9dNodePrime] + iparmno)); + printf("DcsprDp=%.7e\n", + *(info->SEN_RHS[here->MOS9sNode] + iparmno)); + printf("DcsprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS9sNodePrime] + iparmno)); + printf("\n"); +#endif /* SENSDEBUG */ + Osxpgs = tag0 * *(ckt->CKTstate1 + here->MOS9sensxpgs + + 10*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->MOS9sensxpgs + + 10*(iparmno - 1) + 1); + + Osxpgd = tag0 * *(ckt->CKTstate1 + here->MOS9sensxpgd + + 10*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->MOS9sensxpgd + + 10*(iparmno - 1) + 1); + + Osxpbs = tag0 * *(ckt->CKTstate1 + here->MOS9sensxpbs + + 10*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->MOS9sensxpbs + + 10*(iparmno - 1) + 1); + + Osxpbd =tag0 * *(ckt->CKTstate1 + here->MOS9sensxpbd + + 10*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->MOS9sensxpbd + + 10*(iparmno - 1) + 1); + Osxpgb = tag0 * *(ckt->CKTstate1 + here->MOS9sensxpgb + + 10*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->MOS9sensxpgb + + 10*(iparmno - 1) + 1); + +#ifdef SENSDEBUG + printf("iparmno=%d\n",iparmno); + printf("sxpgs=%.7e,sdgs=%.7e\n", + *(ckt->CKTstate1 + here->MOS9sensxpgs + + 10*(iparmno - 1)), *(ckt->CKTstate1 + + here->MOS9sensxpgs + 10*(iparmno - 1) + 1)); + printf("sxpgd=%.7e,sdgd=%.7e\n", + *(ckt->CKTstate1 + here->MOS9sensxpgd + + 10*(iparmno - 1)), *(ckt->CKTstate1 + + here->MOS9sensxpgd + 10*(iparmno - 1) + 1)); + printf("sxpbs=%.7e,sdbs=%.7e\n", + *(ckt->CKTstate1 + here->MOS9sensxpbs + + 10*(iparmno - 1)), *(ckt->CKTstate1 + + here->MOS9sensxpbs + 10*(iparmno - 1) + 1)); + printf("sxpbd=%.7e,sdbd=%.7e\n", + *(ckt->CKTstate1 + here->MOS9sensxpbd + + 10*(iparmno - 1)), *(ckt->CKTstate1 + + here->MOS9sensxpbd + 10*(iparmno - 1) + 1)); + printf("sxpgb=%.7e,sdgb=%.7e\n", + *(ckt->CKTstate1 + here->MOS9sensxpgb + + 10*(iparmno - 1)), *(ckt->CKTstate1 + + here->MOS9sensxpgb + 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->MOS9sens_l && (iparmno == here->MOS9senParmNo)){ + Osxpgs -= tag0 * *(here->MOS9dphigs_dl); + Osxpgd -= tag0 * *(here->MOS9dphigd_dl); + Osxpbs -= tag0 * *(here->MOS9dphibs_dl); + Osxpbd -= tag0 * *(here->MOS9dphibd_dl); + Osxpgb -= tag0 * *(here->MOS9dphigb_dl); + } + if(here->MOS9sens_w && + (iparmno == (here->MOS9senParmNo + here->MOS9sens_l))){ + Osxpgs -= tag0 * *(here->MOS9dphigs_dw); + Osxpgd -= tag0 * *(here->MOS9dphigd_dw); + Osxpbs -= tag0 * *(here->MOS9dphibs_dw); + Osxpbd -= tag0 * *(here->MOS9dphibd_dw); + Osxpgb -= tag0 * *(here->MOS9dphigb_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->MOS9bNode] + iparmno) += + Osxpbs + Osxpbd -Osxpgb; + *(info->SEN_RHS[here->MOS9gNode] + iparmno) += + Osxpgs + Osxpgd + Osxpgb; + + *(info->SEN_RHS[here->MOS9dNodePrime] + iparmno) -= + Osxpgd + Osxpbd ; + *(info->SEN_RHS[here->MOS9sNodePrime] + iparmno) -= + Osxpgs + Osxpbs; +#ifdef SENSDEBUG + printf("after capacitive currents\n"); + printf("DcbDp=%.7e\n", + *(info->SEN_RHS[here->MOS9bNode] + iparmno)); + printf("DcdprDp=%.7e\n", + *(info->SEN_RHS[here->MOS9dNode] + iparmno)); + printf("DcdprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS9dNodePrime] + iparmno)); + printf("DcsprDp=%.7e\n", + *(info->SEN_RHS[here->MOS9sNode] + iparmno)); + printf("DcsprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS9sNodePrime] + iparmno)); +#endif /* SENSDEBUG */ + + } +restore: /* put the unperturbed values back into the state vector */ + for(i=0; i <= 16; i++) + *(ckt->CKTstate0 + here->MOS9states + i) = *(SaveState + i); + here->MOS9sourceConductance = *(SaveState + 17) ; + here->MOS9drainConductance = *(SaveState + 18) ; + here->MOS9cd = *(SaveState + 19) ; + here->MOS9cbs = *(SaveState + 20) ; + here->MOS9cbd = *(SaveState + 21) ; + here->MOS9gmbs = *(SaveState + 22) ; + here->MOS9gm = *(SaveState + 23) ; + here->MOS9gds = *(SaveState + 24) ; + here->MOS9gbd = *(SaveState + 25) ; + here->MOS9gbs = *(SaveState + 26) ; + here->MOS9capbd = *(SaveState + 27) ; + here->MOS9capbs = *(SaveState + 28) ; + here->MOS9Cbd = *(SaveState + 29) ; + here->MOS9Cbdsw = *(SaveState + 30) ; + here->MOS9Cbs = *(SaveState + 31) ; + here->MOS9Cbssw = *(SaveState + 32) ; + here->MOS9f2d = *(SaveState + 33) ; + here->MOS9f3d = *(SaveState + 34) ; + here->MOS9f4d = *(SaveState + 35) ; + here->MOS9f2s = *(SaveState + 36) ; + here->MOS9f3s = *(SaveState + 37) ; + here->MOS9f4s = *(SaveState + 38) ; + here->MOS9cgs = *(SaveState + 39) ; + here->MOS9cgd = *(SaveState + 40) ; + here->MOS9cgb = *(SaveState + 41) ; + here->MOS9vdsat = *(SaveState + 42) ; + here->MOS9von = *(SaveState + 43) ; + here->MOS9mode = save_mode ; + + here->MOS9senPertFlag = OFF; + + } + } + info->SENstatus = NORMAL; +#ifdef SENSDEBUG + printf("MOS9senload end\n"); +#endif /* SENSDEBUG */ + return(OK); +} + diff --git a/src/spicelib/devices/mos9/mos9sprt.c b/src/spicelib/devices/mos9/mos9sprt.c new file mode 100644 index 000000000..7efe4e89b --- /dev/null +++ b/src/spicelib/devices/mos9/mos9sprt.c @@ -0,0 +1,65 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Alan Gillespie +**********/ + + /* Pretty print the sensitivity info for all the MOS9 + * devices in the circuit. + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "mos9defs.h" +#include "sperror.h" +#include "suffix.h" + +void +MOS9sPrint(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register MOS9model *model = (MOS9model *)inModel; + register MOS9instance *here; + + printf("LEVEL 3 MOSFETS (AG) -----------------\n"); + /* loop through all the MOS9 models */ + for( ; model != NULL; model = model->MOS9nextModel ) { + + printf("Model name:%s\n",model->MOS9modName); + + /* loop through all the instances of the model */ + for (here = model->MOS9instances; here != NULL ; + here=here->MOS9nextInstance) { + + printf(" Instance name:%s\n",here->MOS9name); + printf(" Drain, Gate , Source nodes: %s, %s ,%s\n", + CKTnodName(ckt,here->MOS9dNode),CKTnodName(ckt,here->MOS9gNode), + CKTnodName(ckt,here->MOS9sNode)); + + printf(" Multiplier: %g ",here->MOS9m); + printf(here->MOS9mGiven ? "(specified)\n" : "(default)\n"); + printf(" Length: %g ",here->MOS9l); + printf(here->MOS9lGiven ? "(specified)\n" : "(default)\n"); + printf(" Width: %g ",here->MOS9w); + printf(here->MOS9wGiven ? "(specified)\n" : "(default)\n"); + if(here->MOS9sens_l == 1){ + printf(" MOS9senParmNo:l = %d ",here->MOS9senParmNo); + } + else{ + printf(" MOS9senParmNo:l = 0 "); + } + if(here->MOS9sens_w == 1){ + printf(" w = %d \n",here->MOS9senParmNo + here->MOS9sens_l); + } + else{ + printf(" w = 0 \n"); + } + + + } + } +} + diff --git a/src/spicelib/devices/mos9/mos9sset.c b/src/spicelib/devices/mos9/mos9sset.c new file mode 100644 index 000000000..5551b1250 --- /dev/null +++ b/src/spicelib/devices/mos9/mos9sset.c @@ -0,0 +1,54 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Alan Gillespie +**********/ + + /* loop through all the devices and + * allocate parameter #s to design parameters + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "mos9defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS9sSetup(info,inModel) + SENstruct *info; + GENmodel *inModel; +{ + MOS9model *model = (MOS9model *)inModel; + MOS9instance *here; + + /* loop through all the models */ + for( ; model != NULL; model = model->MOS9nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MOS9instances; here != NULL ; + here=here->MOS9nextInstance) { + + + if(here->MOS9senParmNo){ + if((here->MOS9sens_l)&&(here->MOS9sens_w)){ + here->MOS9senParmNo = ++(info->SENparms); + ++(info->SENparms);/* MOS has two design parameters */ + } + else{ + here->MOS9senParmNo = ++(info->SENparms); + } + } + here->MOS9senPertFlag = OFF; + if((here->MOS9sens = (double *)MALLOC(72*sizeof(double))) == NULL) { + return(E_NOMEM); + } + + } + } + return(OK); +} + + diff --git a/src/spicelib/devices/mos9/mos9supd.c b/src/spicelib/devices/mos9/mos9supd.c new file mode 100644 index 000000000..57ef13992 --- /dev/null +++ b/src/spicelib/devices/mos9/mos9supd.c @@ -0,0 +1,182 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Alan Gillespie +**********/ + +#include +#include "ngspice.h" +#include "smpdefs.h" +#include "cktdefs.h" +#include "mos9defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS9sUpdate(inModel,ckt) +GENmodel *inModel; +CKTcircuit *ckt; +{ + MOS9model *model = (MOS9model *)inModel; + MOS9instance *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("MOS9senupdate\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 MOS9 models */ + for( ; model != NULL; model = model->MOS9nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MOS9instances; here != NULL ; + here=here->MOS9nextInstance) { + + +#ifdef SENSDEBUG + printf("senupdate instance name %s\n",here->MOS9name); + printf("before loading\n"); + printf("CKTag[0] = %.2e,CKTag[1] = %.2e\n", + ckt->CKTag[0],ckt->CKTag[1]); + printf("capgs = %.7e\n",here->MOS9cgs); + printf("capgd = %.7e\n",here->MOS9cgd); + printf("capgb = %.7e\n",here->MOS9cgb); + printf("capbs = %.7e\n",here->MOS9capbs); + printf("capbd = %.7e\n",here->MOS9capbd); +#endif /* SENSDEBUG */ + + for(iparmno = 1;iparmno<=info->SENparms;iparmno++){ + + sb = *(info->SEN_Sap[here->MOS9bNode] + iparmno); + sg = *(info->SEN_Sap[here->MOS9gNode] + iparmno); + ssprm = *(info->SEN_Sap[here->MOS9sNodePrime] + iparmno); + sdprm = *(info->SEN_Sap[here->MOS9dNodePrime] + 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->MOS9cgs ; + sxpgd = (sg - sdprm) * here->MOS9cgd ; + sxpgb = (sg - sb) * here->MOS9cgb ; + sxpbs = (sb - ssprm) * here->MOS9capbs ; + sxpbd = (sb - sdprm) * here->MOS9capbd ; + + if(here->MOS9sens_l && (iparmno == here->MOS9senParmNo)){ + sxpgs += *(here->MOS9dphigs_dl); + sxpgd += *(here->MOS9dphigd_dl); + sxpbs += *(here->MOS9dphibs_dl); + sxpbd += *(here->MOS9dphibd_dl); + sxpgb += *(here->MOS9dphigb_dl); + } + if(here->MOS9sens_w && + (iparmno == (here->MOS9senParmNo+here->MOS9sens_l))){ + sxpgs += *(here->MOS9dphigs_dw); + sxpgd += *(here->MOS9dphigd_dw); + sxpbs += *(here->MOS9dphibs_dw); + sxpbd += *(here->MOS9dphibd_dw); + sxpgb += *(here->MOS9dphigb_dw); + } + if(ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->MOS9sensxpgs + + 10 * (iparmno - 1)) = sxpgs; + *(ckt->CKTstate1 + here->MOS9sensxpgd + + 10 * (iparmno - 1)) = sxpgd; + *(ckt->CKTstate1 + here->MOS9sensxpbs + + 10 * (iparmno - 1)) = sxpbs; + *(ckt->CKTstate1 + here->MOS9sensxpbd + + 10 * (iparmno - 1)) = sxpbd; + *(ckt->CKTstate1 + here->MOS9sensxpgb + + 10 * (iparmno - 1)) = sxpgb; + *(ckt->CKTstate1 + here->MOS9sensxpgs + + 10 * (iparmno - 1) + 1) = 0; + *(ckt->CKTstate1 + here->MOS9sensxpgd + + 10 * (iparmno - 1) + 1) = 0; + *(ckt->CKTstate1 + here->MOS9sensxpbs + + 10 * (iparmno - 1) + 1) = 0; + *(ckt->CKTstate1 + here->MOS9sensxpbd + + 10 * (iparmno - 1) + 1) = 0; + *(ckt->CKTstate1 + here->MOS9sensxpgb + + 10 * (iparmno - 1) + 1) = 0; + goto next; + } + + *(ckt->CKTstate0 + here->MOS9sensxpgs + + 10 * (iparmno - 1)) = sxpgs; + *(ckt->CKTstate0 + here->MOS9sensxpgd + + 10 * (iparmno - 1)) = sxpgd; + *(ckt->CKTstate0 + here->MOS9sensxpbs + + 10 * (iparmno - 1)) = sxpbs; + *(ckt->CKTstate0 + here->MOS9sensxpbd + + 10 * (iparmno - 1)) = sxpbd; + *(ckt->CKTstate0 + here->MOS9sensxpgb + + 10 * (iparmno - 1)) = sxpgb; + + NIintegrate(ckt,&dummy1,&dummy2,here->MOS9cgs, + here->MOS9sensxpgs + 10*(iparmno -1)); + NIintegrate(ckt,&dummy1,&dummy2,here->MOS9cgd, + here->MOS9sensxpgd + 10*(iparmno -1)); + NIintegrate(ckt,&dummy1,&dummy2,here->MOS9cgb, + here->MOS9sensxpgb + 10*(iparmno -1)); + NIintegrate(ckt,&dummy1,&dummy2,here->MOS9capbs, + here->MOS9sensxpbs + 10*(iparmno -1)); + NIintegrate(ckt,&dummy1,&dummy2,here->MOS9capbd, + here->MOS9sensxpbd + 10*(iparmno -1)); + + +next: + ; +#ifdef SENSDEBUG + printf("after loading\n"); + printf("sxpgs = %.7e,sdotxpgs = %.7e\n", + sxpgs,*(ckt->CKTstate0 + here->MOS9sensxpgs + + 10 * (iparmno - 1) + 1)); + printf("sxpgd = %.7e,sdotxpgd = %.7e\n", + sxpgd,*(ckt->CKTstate0 + here->MOS9sensxpgd + + 10 * (iparmno - 1) + 1)); + printf("sxpgb = %.7e,sdotxpgb = %.7e\n", + sxpgb,*(ckt->CKTstate0 + here->MOS9sensxpgb + + 10 * (iparmno - 1) + 1)); + printf("sxpbs = %.7e,sdotxpbs = %.7e\n", + sxpbs,*(ckt->CKTstate0 + here->MOS9sensxpbs + + 10 * (iparmno - 1) + 1)); + printf("sxpbd = %.7e,sdotxpbd = %.7e\n", + sxpbd,*(ckt->CKTstate0 + here->MOS9sensxpbd + + 10 * (iparmno - 1) + 1)); +#endif /* SENSDEBUG */ + } + } + } +#ifdef SENSDEBUG + printf("MOS9senupdate end\n"); +#endif /* SENSDEBUG */ + return(OK); + +} + diff --git a/src/spicelib/devices/mos9/mos9temp.c b/src/spicelib/devices/mos9/mos9temp.c new file mode 100644 index 000000000..843912d38 --- /dev/null +++ b/src/spicelib/devices/mos9/mos9temp.c @@ -0,0 +1,343 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Alan Gillespie +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos9defs.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +/* assuming silicon - make definition for epsilon of silicon */ +#define EPSSIL (11.7 * 8.854214871e-12) + +int +MOS9temp(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + MOS9model *model = (MOS9model *)inModel; + MOS9instance *here; + double wkfngs; + double wkfng; + double fermig; + double fermis; + double vfb; + double fact1,fact2; + double vt,vtnom; + double kt,kt1; + double ratio,ratio4; + double egfet,egfet1; + double pbfact,pbfact1,pbo; + double phio; + double arg1; + double capfact; + double gmanew,gmaold; + double ni_temp, nifact; + /* loop through all the mosfet models */ + for( ; model != NULL; model = model->MOS9nextModel) { + + if(!model->MOS9tnomGiven) { + model->MOS9tnom = ckt->CKTnomTemp; + } + fact1 = model->MOS9tnom/REFTEMP; + vtnom = model->MOS9tnom*CONSTKoverQ; + kt1 = CONSTboltz * model->MOS9tnom; + egfet1 = 1.16-(7.02e-4*model->MOS9tnom*model->MOS9tnom)/ + (model->MOS9tnom+1108); + arg1 = -egfet1/(kt1+kt1)+1.1150877/(CONSTboltz*(REFTEMP+REFTEMP)); + pbfact1 = -2*vtnom *(1.5*log(fact1)+CHARGE*arg1); + + nifact=(model->MOS9tnom/300)*sqrt(model->MOS9tnom/300); + nifact*=exp(0.5*egfet1*((1/(double)300)-(1/model->MOS9tnom))/ + CONSTKoverQ); + ni_temp=1.45e16*nifact; + + + model->MOS9oxideCapFactor = 3.9 * 8.854214871e-12/ + model->MOS9oxideThickness; + if(!model->MOS9surfaceMobilityGiven) model->MOS9surfaceMobility=600; + if(!model->MOS9transconductanceGiven) { + model->MOS9transconductance = model->MOS9surfaceMobility * + model->MOS9oxideCapFactor * 1e-4; + } + if(model->MOS9substrateDopingGiven) { + if(model->MOS9substrateDoping*1e6 /*(cm**3/m**3)*/ >ni_temp) { + + if(!model->MOS9phiGiven) { + model->MOS9phi = 2*vtnom* + log(model->MOS9substrateDoping* + + 1e6/*(cm**3/m**3)*//ni_temp); + + model->MOS9phi = MAX(.1,model->MOS9phi); + } + fermis = model->MOS9type * .5 * model->MOS9phi; + wkfng = 3.2; + if(!model->MOS9gateTypeGiven) model->MOS9gateType=1; + if(model->MOS9gateType != 0) { + fermig = model->MOS9type * model->MOS9gateType*.5*egfet1; + wkfng = 3.25 + .5 * egfet1 - fermig; + } + wkfngs = wkfng - (3.25 + .5 * egfet1 +fermis); + if(!model->MOS9gammaGiven) { + model->MOS9gamma = sqrt(2 * EPSSIL * + CHARGE * model->MOS9substrateDoping* + 1e6 /*(cm**3/m**3)*/ )/ model->MOS9oxideCapFactor; + } + if(!model->MOS9vt0Given) { + if(!model->MOS9surfaceStateDensityGiven) + model->MOS9surfaceStateDensity=0; + vfb = wkfngs - model->MOS9surfaceStateDensity * 1e4 + * CHARGE/model->MOS9oxideCapFactor; + model->MOS9vt0 = vfb + model->MOS9type * + (model->MOS9gamma * sqrt(model->MOS9phi)+ + model->MOS9phi); + } else { + vfb = model->MOS9vt0 - model->MOS9type * (model->MOS9gamma* + sqrt(model->MOS9phi)+model->MOS9phi); + } + model->MOS9alpha = (EPSSIL+EPSSIL)/ + (CHARGE*model->MOS9substrateDoping*1e6 /*(cm**3/m**3)*/ ); + model->MOS9coeffDepLayWidth = sqrt(model->MOS9alpha); + } else { + model->MOS9substrateDoping = 0; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "%s: Nsub < Ni ",&(model->MOS9modName)); + return(E_BADPARM); + } + } + /* now model parameter preprocessing */ + model->MOS9narrowFactor = model->MOS9delta * 0.5 * M_PI * EPSSIL / + model->MOS9oxideCapFactor ; + + + /* loop through all instances of the model */ + for(here = model->MOS9instances; here!= NULL; + here = here->MOS9nextInstance) { + + 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->MOS9tempGiven) { + here->MOS9temp = ckt->CKTtemp; + } + vt = here->MOS9temp * CONSTKoverQ; + ratio = here->MOS9temp/model->MOS9tnom; + fact2 = here->MOS9temp/REFTEMP; + kt = here->MOS9temp * CONSTboltz; + egfet = 1.16-(7.02e-4*here->MOS9temp*here->MOS9temp)/ + (here->MOS9temp+1108); + arg = -egfet/(kt+kt)+1.1150877/(CONSTboltz*(REFTEMP+REFTEMP)); + pbfact = -2*vt *(1.5*log(fact2)+CHARGE*arg); + + if(!here->MOS9mGiven) { + here->MOS9m = ckt->CKTdefaultMosM; + } + + if(!here->MOS9lGiven) { + here->MOS9l = ckt->CKTdefaultMosL; + } + if(!here->MOS9sourceAreaGiven) { + here->MOS9sourceArea = ckt->CKTdefaultMosAS; + } + if(!here->MOS9wGiven) { + here->MOS9w = ckt->CKTdefaultMosW; + } + if(model->MOS9drainResistanceGiven) { + if(model->MOS9drainResistance != 0) { + here->MOS9drainConductance = here->MOS9m / + model->MOS9drainResistance; + } else { + here->MOS9drainConductance = 0; + } + } else if (model->MOS9sheetResistanceGiven) { + if ((model->MOS9sheetResistance != 0) && + (here->MOS9drainSquares != 0)) { + here->MOS9drainConductance = + here->MOS9m / + (model->MOS9sheetResistance*here->MOS9drainSquares); + } else { + here->MOS9drainConductance = 0; + } + } else { + here->MOS9drainConductance = 0; + } + if(model->MOS9sourceResistanceGiven) { + if(model->MOS9sourceResistance != 0) { + here->MOS9sourceConductance = here->MOS9m / + model->MOS9sourceResistance; + } else { + here->MOS9sourceConductance = 0; + } + } else if (model->MOS9sheetResistanceGiven) { + if ((model->MOS9sheetResistance != 0) && + (here->MOS9sourceSquares != 0)) { + here->MOS9sourceConductance = + here->MOS9m / + (model->MOS9sheetResistance*here->MOS9sourceSquares); + } else { + here->MOS9sourceConductance = 0; + } + } else { + here->MOS9sourceConductance = 0; + } + + if(here->MOS9l - 2 * model->MOS9latDiff + + model->MOS9lengthAdjust <1e-6) { + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "%s: effective channel length less than zero", + &(here->MOS9name)); + return(E_PARMVAL); + } + + if(here->MOS9w - 2 * model->MOS9widthNarrow + + model->MOS9widthAdjust <1e-6) { + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "%s: effective channel width less than zero", + &(here->MOS9name)); + return(E_PARMVAL); + } + + + ratio4 = ratio * sqrt(ratio); + here->MOS9tTransconductance = model->MOS9transconductance / ratio4; + here->MOS9tSurfMob = model->MOS9surfaceMobility/ratio4; + phio= (model->MOS9phi-pbfact1)/fact1; + here->MOS9tPhi = fact2 * phio + pbfact; + here->MOS9tVbi = + model->MOS9delvt0 + + model->MOS9vt0 - model->MOS9type * + (model->MOS9gamma* sqrt(model->MOS9phi)) + +.5*(egfet1-egfet) + + model->MOS9type*.5* (here->MOS9tPhi-model->MOS9phi); + here->MOS9tVto = here->MOS9tVbi + model->MOS9type * + model->MOS9gamma * sqrt(here->MOS9tPhi); + here->MOS9tSatCur = model->MOS9jctSatCur* + exp(-egfet/vt+egfet1/vtnom); + here->MOS9tSatCurDens = model->MOS9jctSatCurDensity * + exp(-egfet/vt+egfet1/vtnom); + pbo = (model->MOS9bulkJctPotential - pbfact1)/fact1; + gmaold = (model->MOS9bulkJctPotential-pbo)/pbo; + capfact = 1/(1+model->MOS9bulkJctBotGradingCoeff* + (4e-4*(model->MOS9tnom-REFTEMP)-gmaold)); + here->MOS9tCbd = model->MOS9capBD * capfact; + here->MOS9tCbs = model->MOS9capBS * capfact; + here->MOS9tCj = model->MOS9bulkCapFactor * capfact; + capfact = 1/(1+model->MOS9bulkJctSideGradingCoeff* + (4e-4*(model->MOS9tnom-REFTEMP)-gmaold)); + here->MOS9tCjsw = model->MOS9sideWallCapFactor * capfact; + here->MOS9tBulkPot = fact2 * pbo+pbfact; + gmanew = (here->MOS9tBulkPot-pbo)/pbo; + capfact = (1+model->MOS9bulkJctBotGradingCoeff* + (4e-4*(here->MOS9temp-REFTEMP)-gmanew)); + here->MOS9tCbd *= capfact; + here->MOS9tCbs *= capfact; + here->MOS9tCj *= capfact; + capfact = (1+model->MOS9bulkJctSideGradingCoeff* + (4e-4*(here->MOS9temp-REFTEMP)-gmanew)); + here->MOS9tCjsw *= capfact; + here->MOS9tDepCap = model->MOS9fwdCapDepCoeff * here->MOS9tBulkPot; + + if( (model->MOS9jctSatCurDensity == 0) || + (here->MOS9drainArea == 0) || + (here->MOS9sourceArea == 0) ) { + here->MOS9sourceVcrit = here->MOS9drainVcrit = + vt*log(vt/(CONSTroot2*here->MOS9m*here->MOS9tSatCur)); + } else { + here->MOS9drainVcrit = + vt * log( vt / (CONSTroot2 * + here->MOS9m * + here->MOS9tSatCurDens * here->MOS9drainArea)); + here->MOS9sourceVcrit = + vt * log( vt / (CONSTroot2 * + here->MOS9m * + here->MOS9tSatCurDens * here->MOS9sourceArea)); + } + if(model->MOS9capBDGiven) { + czbd = here->MOS9tCbd * here->MOS9m; + } else { + if(model->MOS9bulkCapFactorGiven) { + czbd=here->MOS9tCj*here->MOS9drainArea * here->MOS9m; + } else { + czbd=0; + } + } + if(model->MOS9sideWallCapFactorGiven) { + czbdsw= here->MOS9tCjsw * here->MOS9drainPerimiter * + here->MOS9m; + } else { + czbdsw=0; + } + arg = 1-model->MOS9fwdCapDepCoeff; + sarg = exp( (-model->MOS9bulkJctBotGradingCoeff) * log(arg) ); + sargsw = exp( (-model->MOS9bulkJctSideGradingCoeff) * log(arg) ); + here->MOS9Cbd = czbd; + here->MOS9Cbdsw = czbdsw; + here->MOS9f2d = czbd*(1-model->MOS9fwdCapDepCoeff* + (1+model->MOS9bulkJctBotGradingCoeff))* sarg/arg + + czbdsw*(1-model->MOS9fwdCapDepCoeff* + (1+model->MOS9bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS9f3d = czbd * model->MOS9bulkJctBotGradingCoeff * sarg/arg/ + here->MOS9tBulkPot + + czbdsw * model->MOS9bulkJctSideGradingCoeff * sargsw/arg / + here->MOS9tBulkPot; + here->MOS9f4d = czbd*here->MOS9tBulkPot*(1-arg*sarg)/ + (1-model->MOS9bulkJctBotGradingCoeff) + + czbdsw*here->MOS9tBulkPot*(1-arg*sargsw)/ + (1-model->MOS9bulkJctSideGradingCoeff) + -here->MOS9f3d/2* + (here->MOS9tDepCap*here->MOS9tDepCap) + -here->MOS9tDepCap * here->MOS9f2d; + if(model->MOS9capBSGiven) { + czbs = here->MOS9tCbs * here->MOS9m; + } else { + if(model->MOS9bulkCapFactorGiven) { + czbs=here->MOS9tCj*here->MOS9sourceArea * here->MOS9m; + } else { + czbs=0; + } + } + if(model->MOS9sideWallCapFactorGiven) { + czbssw = here->MOS9tCjsw * here->MOS9sourcePerimiter * + here->MOS9m; + } else { + czbssw=0; + } + arg = 1-model->MOS9fwdCapDepCoeff; + sarg = exp( (-model->MOS9bulkJctBotGradingCoeff) * log(arg) ); + sargsw = exp( (-model->MOS9bulkJctSideGradingCoeff) * log(arg) ); + here->MOS9Cbs = czbs; + here->MOS9Cbssw = czbssw; + here->MOS9f2s = czbs*(1-model->MOS9fwdCapDepCoeff* + (1+model->MOS9bulkJctBotGradingCoeff))* sarg/arg + + czbssw*(1-model->MOS9fwdCapDepCoeff* + (1+model->MOS9bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS9f3s = czbs * model->MOS9bulkJctBotGradingCoeff * sarg/arg/ + here->MOS9tBulkPot + + czbssw * model->MOS9bulkJctSideGradingCoeff * sargsw/arg / + here->MOS9tBulkPot; + here->MOS9f4s = czbs*here->MOS9tBulkPot*(1-arg*sarg)/ + (1-model->MOS9bulkJctBotGradingCoeff) + + czbssw*here->MOS9tBulkPot*(1-arg*sargsw)/ + (1-model->MOS9bulkJctSideGradingCoeff) + -here->MOS9f3s/2* + (here->MOS9tDepCap*here->MOS9tDepCap) + -here->MOS9tDepCap * here->MOS9f2s; + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos9/mos9trun.c b/src/spicelib/devices/mos9/mos9trun.c new file mode 100644 index 000000000..9b88aa1db --- /dev/null +++ b/src/spicelib/devices/mos9/mos9trun.c @@ -0,0 +1,31 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Alan Gillespie +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos9defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS9trunc(inModel,ckt,timeStep) + GENmodel *inModel; + CKTcircuit *ckt; + double *timeStep; +{ + MOS9model *model = (MOS9model *)inModel; + MOS9instance *here; + + for( ; model != NULL; model = model->MOS9nextModel) { + for(here=model->MOS9instances;here!=NULL;here = here->MOS9nextInstance){ + CKTterr(here->MOS9qgs,ckt,timeStep); + CKTterr(here->MOS9qgd,ckt,timeStep); + CKTterr(here->MOS9qgb,ckt,timeStep); + } + } + return(OK); +}