diff --git a/src/spicelib/devices/nbjt/Makefile.am b/src/spicelib/devices/nbjt/Makefile.am new file mode 100644 index 000000000..609303cf8 --- /dev/null +++ b/src/spicelib/devices/nbjt/Makefile.am @@ -0,0 +1,30 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libnbjt.a + +libnbjt_a_SOURCES = \ + nbjt.c \ + nbjtacld.c \ + nbjtask.c \ + nbjtdefs.h \ + nbjtdel.c \ + nbjtdest.c \ + nbjtdump.c \ + nbjtext.h \ + nbjtinit.c \ + nbjtinit.h \ + nbjtitf.h \ + nbjtload.c \ + nbjtmdel.c \ + nbjtmpar.c \ + nbjtparm.c \ + nbjtpzld.c \ + nbjtset.c \ + nbjttemp.c \ + nbjttrun.c + + + +INCLUDES = -I$(top_srcdir)/src/include + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/nbjt/nbjt.c b/src/spicelib/devices/nbjt/nbjt.c new file mode 100644 index 000000000..add74d65e --- /dev/null +++ b/src/spicelib/devices/nbjt/nbjt.c @@ -0,0 +1,69 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "devdefs.h" +#include "nbjtdefs.h" +#include "suffix.h" + +/* + * This file defines the Numerical BJT data structures that are available to + * the next level(s) up the calling hierarchy + */ + +IFparm NBJTpTable[] = { /* parameters */ + IP("off", NBJT_OFF, IF_FLAG, "Device initially off"), + IP("ic.file", NBJT_IC_FILE, IF_STRING, "Initial condition file"), + IOP("area", NBJT_AREA, IF_REAL, "Area factor"), + IP("save", NBJT_PRINT, IF_REAL, "Save Solutions"), + IP("print", NBJT_PRINT, IF_REAL, "Print Solutions"), + OP("g11", NBJT_G11, IF_REAL, "Conductance"), + OP("c11", NBJT_C11, IF_REAL, "Capacitance"), + OP("y11", NBJT_Y11, IF_COMPLEX, "Admittance"), + OP("g12", NBJT_G12, IF_REAL, "Conductance"), + OP("c12", NBJT_C12, IF_REAL, "Capacitance"), + OP("y12", NBJT_Y12, IF_COMPLEX, "Admittance"), + OPU("g13", NBJT_G13, IF_REAL, "Conductance"), + OPU("c13", NBJT_C13, IF_REAL, "Capacitance"), + OPU("y13", NBJT_Y13, IF_COMPLEX, "Admittance"), + OP("g21", NBJT_G21, IF_REAL, "Conductance"), + OP("c21", NBJT_C21, IF_REAL, "Capacitance"), + OP("y21", NBJT_Y21, IF_COMPLEX, "Admittance"), + OP("g22", NBJT_G22, IF_REAL, "Conductance"), + OP("c22", NBJT_C22, IF_REAL, "Capacitance"), + OP("y22", NBJT_Y22, IF_COMPLEX, "Admittance"), + OPU("g23", NBJT_G23, IF_REAL, "Conductance"), + OPU("c23", NBJT_C23, IF_REAL, "Capacitance"), + OPU("y23", NBJT_Y23, IF_COMPLEX, "Admittance"), + OPU("g31", NBJT_G31, IF_REAL, "Conductance"), + OPU("c31", NBJT_C31, IF_REAL, "Capacitance"), + OPU("y31", NBJT_Y31, IF_COMPLEX, "Admittance"), + OPU("g32", NBJT_G32, IF_REAL, "Conductance"), + OPU("c32", NBJT_C32, IF_REAL, "Capacitance"), + OPU("y32", NBJT_Y32, IF_COMPLEX, "Admittance"), + OPU("g33", NBJT_G33, IF_REAL, "Conductance"), + OPU("c33", NBJT_C33, IF_REAL, "Capacitance"), + OPU("y33", NBJT_Y33, IF_COMPLEX, "Admittance"), + IOP("temp", NBJT_TEMP, IF_REAL, "Instance Temperature") +}; + +IFparm NBJTmPTable[] = { /* model parameters */ + /* numerical-device models no longer have parameters */ + /* one is left behind to keep the table from being empty */ + IP("nbjt", NBJT_MOD_NBJT, IF_FLAG, "Numerical BJT Model") +}; + +char *NBJTnames[] = { + "Collector", + "Base", + "Emitter", + "Substrate" +}; + +int NBJTnSize = NUMELEMS(NBJTnames); +int NBJTpTSize = NUMELEMS(NBJTpTable); +int NBJTmPTSize = NUMELEMS(NBJTmPTable); +int NBJTiSize = sizeof(NBJTinstance); +int NBJTmSize = sizeof(NBJTmodel); diff --git a/src/spicelib/devices/nbjt/nbjtacld.c b/src/spicelib/devices/nbjt/nbjtacld.c new file mode 100644 index 000000000..2a8403a02 --- /dev/null +++ b/src/spicelib/devices/nbjt/nbjtacld.c @@ -0,0 +1,100 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * Function to load the COMPLEX circuit matrix using the small signal + * parameters saved during a previous DC operating point analysis. + */ + +#include "ngspice.h" +#include "cktdefs.h" +#include "nbjtdefs.h" +#include "sperror.h" +#include "complex.h" +#include "../../../ciderlib/oned/onedext.h" +#include "cidersupt.h" +#include "numglobs.h" +#include "suffix.h" + +/* External Declarations */ +extern int ONEacDebug; + +int +NBJTacLoad(inModel, ckt) + GENmodel *inModel; + CKTcircuit *ckt; + +{ + register NBJTmodel *model = (NBJTmodel *) inModel; + register NBJTinstance *inst; + SPcomplex yIeVce, yIeVbe; + SPcomplex yIcVce, yIcVbe; + double startTime; + + for (; model != NULL; model = model->NBJTnextModel) { + FieldDepMobility = model->NBJTmodels->MODLfieldDepMobility; + Srh = model->NBJTmodels->MODLsrh; + Auger = model->NBJTmodels->MODLauger; + AvalancheGen = model->NBJTmodels->MODLavalancheGen; + AcAnalysisMethod = model->NBJTmethods->METHacAnalysisMethod; + MobDeriv = model->NBJTmethods->METHmobDeriv; + ONEacDebug = model->NBJToutputs->OUTPacDebug; + + for (inst = model->NBJTinstances; inst != NULL; + inst = inst->NBJTnextInstance) { + if (inst->NBJTowner != ARCHme) continue; + + startTime = SPfrontEnd->IFseconds(); + /* Get Temp.-Dep. Global Parameters */ + GLOBgetGlobals(&(inst->NBJTglobals)); + + model->NBJTmethods->METHacAnalysisMethod = + NBJTadmittance(inst->NBJTpDevice, ckt->CKTomega, + &yIeVce, &yIcVce, &yIeVbe, &yIcVbe); + + *(inst->NBJTcolColPtr) += yIcVce.real; + *(inst->NBJTcolColPtr + 1) += yIcVce.imag; + *(inst->NBJTcolBasePtr) += yIcVbe.real; + *(inst->NBJTcolBasePtr + 1) += yIcVbe.imag; + *(inst->NBJTcolEmitPtr) -= yIcVbe.real + yIcVce.real; + *(inst->NBJTcolEmitPtr + 1) -= yIcVbe.imag + yIcVce.imag; + *(inst->NBJTbaseColPtr) -= yIcVce.real - yIeVce.real; + *(inst->NBJTbaseColPtr + 1) -= yIcVce.imag - yIeVce.imag; + *(inst->NBJTbaseBasePtr) -= yIcVbe.real - yIeVbe.real; + *(inst->NBJTbaseBasePtr + 1) -= yIcVbe.imag - yIeVbe.imag; + *(inst->NBJTbaseEmitPtr) += yIcVbe.real + yIcVce.real - yIeVbe.real - yIeVce.real; + *(inst->NBJTbaseEmitPtr + 1) += yIcVbe.imag + yIcVce.imag - yIeVbe.imag - yIeVce.imag; + *(inst->NBJTemitColPtr) -= yIeVce.real; + *(inst->NBJTemitColPtr + 1) -= yIeVce.imag; + *(inst->NBJTemitBasePtr) -= yIeVbe.real; + *(inst->NBJTemitBasePtr + 1) -= yIeVbe.imag; + *(inst->NBJTemitEmitPtr) += yIeVbe.real + yIeVce.real; + *(inst->NBJTemitEmitPtr + 1) += yIeVbe.imag + yIeVce.imag; + if (ckt->CKTomega != 0.0) { + inst->NBJTc11 = yIcVce.imag / ckt->CKTomega; + inst->NBJTc12 = yIcVbe.imag / ckt->CKTomega; + inst->NBJTc21 = (yIeVce.imag - yIcVce.imag) / ckt->CKTomega; + inst->NBJTc22 = (yIeVbe.imag - yIcVbe.imag) / ckt->CKTomega; + } else { + inst->NBJTc11 = 0.0; /* XXX What else can be done?! */ + inst->NBJTc12 = 0.0; /* XXX What else can be done?! */ + inst->NBJTc21 = 0.0; /* XXX What else can be done?! */ + inst->NBJTc22 = 0.0; /* XXX What else can be done?! */ + } + inst->NBJTy11r = yIcVce.real; + inst->NBJTy11i = yIcVce.imag; + inst->NBJTy12r = yIcVbe.real; + inst->NBJTy12i = yIcVbe.imag; + inst->NBJTy21r = yIeVce.real - yIcVce.real; + inst->NBJTy21i = yIeVce.imag - yIcVce.imag; + inst->NBJTy22r = yIeVbe.real - yIcVbe.real; + inst->NBJTy22i = yIeVbe.imag - yIcVbe.imag; + inst->NBJTsmSigAvail = TRUE; + inst->NBJTpDevice->pStats->totalTime[STAT_AC] += + SPfrontEnd->IFseconds() - startTime; + } + } + return (OK); +} diff --git a/src/spicelib/devices/nbjt/nbjtask.c b/src/spicelib/devices/nbjt/nbjtask.c new file mode 100644 index 000000000..b1ff689f6 --- /dev/null +++ b/src/spicelib/devices/nbjt/nbjtask.c @@ -0,0 +1,212 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include "const.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "nbjtdefs.h" +#include "sperror.h" +#include "suffix.h" + +/* Check out this one */ +extern int NBJTinitSmSig(NBJTinstance *); + + +/* ARGSUSED */ +int +NBJTask(ckt, inInst, which, value, select) + CKTcircuit *ckt; + GENinstance *inInst; + int which; + IFvalue *value; + IFvalue *select; +{ + NBJTinstance *inst = (NBJTinstance *) inInst; + switch (which) { + case NBJT_AREA: + value->rValue = inst->NBJTarea; + return (OK); + case NBJT_TEMP: + value->rValue = inst->NBJTtemp - CONSTCtoK; + return (OK); + case NBJT_G11: + value->rValue = *(ckt->CKTstate0 + inst->NBJTdIcDVce); + return (OK); + case NBJT_G12: + value->rValue = *(ckt->CKTstate0 + inst->NBJTdIcDVbe); + return (OK); + case NBJT_G13: + value->rValue = -*(ckt->CKTstate0 + inst->NBJTdIcDVce) + - *(ckt->CKTstate0 + inst->NBJTdIcDVbe); + return (OK); + case NBJT_G21: + value->rValue = *(ckt->CKTstate0 + inst->NBJTdIeDVce) + - *(ckt->CKTstate0 + inst->NBJTdIcDVce); + return (OK); + case NBJT_G22: + value->rValue = *(ckt->CKTstate0 + inst->NBJTdIeDVbe) + - *(ckt->CKTstate0 + inst->NBJTdIcDVbe); + return (OK); + case NBJT_G23: + value->rValue = -*(ckt->CKTstate0 + inst->NBJTdIeDVce) + + *(ckt->CKTstate0 + inst->NBJTdIcDVce) /* XXX there was a ;*/ + -*(ckt->CKTstate0 + inst->NBJTdIeDVbe) + + *(ckt->CKTstate0 + inst->NBJTdIcDVbe); + return (OK); + case NBJT_G31: + value->rValue = -*(ckt->CKTstate0 + inst->NBJTdIeDVce); + return (OK); + case NBJT_G32: + value->rValue = -*(ckt->CKTstate0 + inst->NBJTdIeDVbe); + return (OK); + case NBJT_G33: + value->rValue = *(ckt->CKTstate0 + inst->NBJTdIeDVce) + + *(ckt->CKTstate0 + inst->NBJTdIeDVbe); + return (OK); + case NBJT_C11: + if (!inst->NBJTsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJTinitSmSig(inst); + } + value->rValue = inst->NBJTc11; + return (OK); + case NBJT_C12: + if (!inst->NBJTsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJTinitSmSig(inst); + } + value->rValue = inst->NBJTc12; + return (OK); + case NBJT_C13: + if (!inst->NBJTsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJTinitSmSig(inst); + } + value->rValue = -inst->NBJTc11 - inst->NBJTc12; + return (OK); + case NBJT_C21: + if (!inst->NBJTsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJTinitSmSig(inst); + } + value->rValue = inst->NBJTc21; + return (OK); + case NBJT_C22: + if (!inst->NBJTsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJTinitSmSig(inst); + } + value->rValue = inst->NBJTc22; + return (OK); + case NBJT_C23: + if (!inst->NBJTsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJTinitSmSig(inst); + } + value->rValue = -inst->NBJTc21 - inst->NBJTc22; + return (OK); + case NBJT_C31: + if (!inst->NBJTsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJTinitSmSig(inst); + } + value->rValue = -inst->NBJTc11 - inst->NBJTc21; + return (OK); + case NBJT_C32: + if (!inst->NBJTsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJTinitSmSig(inst); + } + value->rValue = -inst->NBJTc12 - inst->NBJTc22; + return (OK); + case NBJT_C33: + if (!inst->NBJTsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJTinitSmSig(inst); + } + value->rValue = inst->NBJTc11 + inst->NBJTc21 + + inst->NBJTc12 + inst->NBJTc22; + return (OK); + case NBJT_Y11: + if (!inst->NBJTsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJTinitSmSig(inst); + } + value->cValue.real = inst->NBJTy11r; + value->cValue.imag = inst->NBJTy11i; + return (OK); + case NBJT_Y12: + if (!inst->NBJTsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJTinitSmSig(inst); + } + value->cValue.real = inst->NBJTy12r; + value->cValue.imag = inst->NBJTy12i; + return (OK); + case NBJT_Y13: + if (!inst->NBJTsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJTinitSmSig(inst); + } + value->cValue.real = -inst->NBJTy11r - inst->NBJTy12r; + value->cValue.imag = -inst->NBJTy11i - inst->NBJTy12i; + return (OK); + case NBJT_Y21: + if (!inst->NBJTsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJTinitSmSig(inst); + } + value->cValue.real = inst->NBJTy21r; + value->cValue.imag = inst->NBJTy21i; + return (OK); + case NBJT_Y22: + if (!inst->NBJTsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJTinitSmSig(inst); + } + value->cValue.real = inst->NBJTy22r; + value->cValue.imag = inst->NBJTy22i; + return (OK); + case NBJT_Y23: + if (!inst->NBJTsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJTinitSmSig(inst); + } + value->cValue.real = -inst->NBJTy21r - inst->NBJTy22r; + value->cValue.imag = -inst->NBJTy21i - inst->NBJTy22i; + return (OK); + case NBJT_Y31: + if (!inst->NBJTsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJTinitSmSig(inst); + } + value->cValue.real = -inst->NBJTy11r - inst->NBJTy21r; + value->cValue.imag = -inst->NBJTy11i - inst->NBJTy21i; + return (OK); + case NBJT_Y32: + if (!inst->NBJTsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJTinitSmSig(inst); + } + value->cValue.real = -inst->NBJTy12r - inst->NBJTy22r; + value->cValue.imag = -inst->NBJTy12i - inst->NBJTy22i; + return (OK); + case NBJT_Y33: + if (!inst->NBJTsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJTinitSmSig(inst); + } + value->cValue.real = inst->NBJTy11r + inst->NBJTy21r + + inst->NBJTy12r + inst->NBJTy22r; + value->cValue.imag = inst->NBJTy11i + inst->NBJTy21i + + inst->NBJTy12i + inst->NBJTy22i; + return (OK); + default: + return (E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/nbjt/nbjtdefs.h b/src/spicelib/devices/nbjt/nbjtdefs.h new file mode 100644 index 000000000..423a5b45c --- /dev/null +++ b/src/spicelib/devices/nbjt/nbjtdefs.h @@ -0,0 +1,167 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +Authors: 1987 Karti Mayaram, 1991 David Gates +**********/ + +#ifndef NBJT_H +#define NBJT_H + +/* data structures used to describe 1D Numerical BJTs */ + +/* circuit level includes */ +#include "ifsim.h" +#include "cktdefs.h" +#include "gendefs.h" + +/* device level includes */ +#include "onemesh.h" +#include "onedev.h" +#include "profile.h" +#include "numglobs.h" +#include "carddefs.h" + +/* information needed per instance */ +typedef struct sNBJTinstance { + struct sNBJTmodel *NBJTmodPtr;/* back pointer to model */ + struct sNBJTinstance *NBJTnextInstance; /* pointer to next instance + * of current model */ + IFuid NBJTname; /* pointer to character string naming this + * instance */ + int NBJTowner; /* number of owner process */ + int NBJTstate; /* pointer to start of state vector for bjt */ + + /* entries in the state vector for bjt: */ +#define NBJTvbe NBJTstate +#define NBJTvce NBJTstate+1 +#define NBJTic NBJTstate+2 +#define NBJTie NBJTstate+3 +#define NBJTdIeDVce NBJTstate+4 +#define NBJTdIeDVbe NBJTstate+5 +#define NBJTdIcDVce NBJTstate+6 +#define NBJTdIcDVbe NBJTstate+7 +#define NBJTnumStates 8 + + int NBJTcolNode; /* number of collector node of bjt */ + int NBJTbaseNode; /* number of base node of bjt */ + int NBJTemitNode; /* number of emitter node of bjt */ + ONEdevice *NBJTpDevice; + GLOBvalues NBJTglobals; /* Temp.-Dep. Global Parameters */ + int NBJTtype; + double NBJTarea; /* area factor of the BJT */ + double NBJTtemp; /* Instance Temperature */ + double NBJTc11; /* small-signal capacitance */ + double NBJTy11r; /* small-signal admittance, real part */ + double NBJTy11i; /* small-signal admittance, imag part */ + double NBJTc12; /* small-signal capacitance */ + double NBJTy12r; /* small-signal admittance, real part */ + double NBJTy12i; /* small-signal admittance, imag part */ + double NBJTc21; /* small-signal capacitance */ + double NBJTy21r; /* small-signal admittance, real part */ + double NBJTy21i; /* small-signal admittance, imag part */ + double NBJTc22; /* small-signal capacitance */ + double NBJTy22r; /* small-signal admittance, real part */ + double NBJTy22i; /* small-signal admittance, imag part */ + int NBJTprint; + char *NBJTicFile; /* Name of initial condition file */ + double *NBJTcolColPtr; /* pointer to sparse matrix at + * (collector,collector) */ + double *NBJTbaseBasePtr; /* pointer to sparse matrix at (base,base) */ + double *NBJTemitEmitPtr; /* pointer to sparse matrix at + * (emitter,emitter) */ + double *NBJTcolBasePtr; /* pointer to sparse matrix at + * (collector,base) */ + double *NBJTcolEmitPtr; /* pointer to sparse matrix at + * (collector,emitter) */ + double *NBJTbaseColPtr; /* pointer to sparse matrix at + * (base,collector) */ + double *NBJTbaseEmitPtr; /* pointer to sparse matrix at (base,emitter) */ + double *NBJTemitColPtr; /* pointer to sparse matrix at + * (emitter,collector) */ + double *NBJTemitBasePtr; /* pointer to sparse matrix at (emitter,base) */ + int NBJToff; /* 'off' flag for bjt */ + unsigned NBJTsmSigAvail:1; /* flag to indicate small-signal done */ + unsigned NBJTareaGiven:1; /* flag to indicate area was specified */ + unsigned NBJTicFileGiven:1; /* flag to indicate init. cond. file given */ + unsigned NBJTprintGiven:1; /* flag to indicate if print was given */ + unsigned NBJTtempGiven:1; /* flag to indicate if temp was given */ +} NBJTinstance; + +/* per model data */ +typedef struct sNBJTmodel { /* model structure for a bjt */ + int NBJTmodType; /* type index of this device type */ + struct sNBJTmodel *NBJTnextModel; /* pointer to next possible model in + * linked list */ + NBJTinstance *NBJTinstances; /* pointer to list of instances that have + * this model */ + IFuid NBJTmodName; /* pointer to character string naming this + * model */ + /* Everything below here is numerical-device-specific */ + MESHcard *NBJTxMeshes; /* list of xmesh cards */ + MESHcard *NBJTyMeshes; /* list of ymesh cards */ + DOMNcard *NBJTdomains; /* list of domain cards */ + BDRYcard *NBJTboundaries; /* list of boundary cards */ + DOPcard *NBJTdopings; /* list of doping cards */ + ELCTcard *NBJTelectrodes; /* list of electrode cards */ + CONTcard *NBJTcontacts; /* list of contact cards */ + MODLcard *NBJTmodels; /* list of model cards */ + MATLcard *NBJTmaterials; /* list of material cards */ + MOBcard *NBJTmobility; /* list of mobility cards */ + METHcard *NBJTmethods; /* list of method cards */ + OPTNcard *NBJToptions; /* list of option cards */ + OUTPcard *NBJToutputs; /* list of output cards */ + ONEtranInfo *NBJTpInfo; /* transient analysis information */ + DOPprofile *NBJTprofiles; /* expanded list of doping profiles */ + DOPtable *NBJTdopTables; /* list of tables used by profiles */ + ONEmaterial *NBJTmatlInfo; /* list of material info structures */ +} NBJTmodel; + +/* type of BJT */ +#define NPN 1 +#define PNP -1 + +/* device parameters */ +#define NBJT_AREA 1 +#define NBJT_OFF 2 +#define NBJT_IC_FILE 3 +#define NBJT_PRINT 4 +#define NBJT_TEMP 5 + +#define NBJT_G11 8 +#define NBJT_C11 9 +#define NBJT_Y11 10 +#define NBJT_G12 11 +#define NBJT_C12 12 +#define NBJT_Y12 13 +#define NBJT_G13 14 +#define NBJT_C13 15 +#define NBJT_Y13 16 +#define NBJT_G21 17 +#define NBJT_C21 18 +#define NBJT_Y21 19 +#define NBJT_G22 20 +#define NBJT_C22 21 +#define NBJT_Y22 22 +#define NBJT_G23 23 +#define NBJT_C23 24 +#define NBJT_Y23 25 +#define NBJT_G31 26 +#define NBJT_C31 27 +#define NBJT_Y31 28 +#define NBJT_G32 29 +#define NBJT_C32 30 +#define NBJT_Y32 31 +#define NBJT_G33 32 +#define NBJT_C33 33 +#define NBJT_Y33 34 + +/* model parameters */ +/* NOTE: all true model parameters have been moved to IFcardInfo structures */ +#define NBJT_MOD_NBJT 101 + +/* device questions */ + +/* model questions */ + +#include "nbjtext.h" + +#endif /* NBJT_H */ diff --git a/src/spicelib/devices/nbjt/nbjtdel.c b/src/spicelib/devices/nbjt/nbjtdel.c new file mode 100644 index 000000000..92fd66567 --- /dev/null +++ b/src/spicelib/devices/nbjt/nbjtdel.c @@ -0,0 +1,40 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This routine deletes a NBJT instance from the circuit and frees the + * storage it was using. + */ + +#include "ngspice.h" +#include "nbjtdefs.h" +#include "sperror.h" +#include "suffix.h" + +int +NBJTdelete(inModel, name, kill) + GENmodel *inModel; + IFuid name; + GENinstance **kill; + +{ + NBJTmodel *model = (NBJTmodel *) inModel; + NBJTinstance **fast = (NBJTinstance **) kill; + NBJTinstance **prev = NULL; + NBJTinstance *inst; + + for (; model; model = model->NBJTnextModel) { + prev = &(model->NBJTinstances); + for (inst = *prev; inst; inst = *prev) { + if (inst->NBJTname == name || (fast && inst == *fast)) { + *prev = inst->NBJTnextInstance; + FREE(inst); + return (OK); + } + prev = &(inst->NBJTnextInstance); + } + } + return (E_NODEV); +} diff --git a/src/spicelib/devices/nbjt/nbjtdest.c b/src/spicelib/devices/nbjt/nbjtdest.c new file mode 100644 index 000000000..211345e24 --- /dev/null +++ b/src/spicelib/devices/nbjt/nbjtdest.c @@ -0,0 +1,40 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This routine deletes all NBJTs from the circuit and frees all storage they + * were using. The current implementation has memory leaks. + */ + +#include "ngspice.h" +#include "nbjtdefs.h" +#include "../../../ciderlib/oned/onedext.h" +#include "cidersupt.h" +#include "suffix.h" + +void +NBJTdestroy(inModel) + GENmodel **inModel; + +{ + + NBJTmodel **model = (NBJTmodel **) inModel; + NBJTmodel *mod, *nextMod; + NBJTinstance *inst, *nextInst; + + + for (mod = *model; mod;) { + for (inst = mod->NBJTinstances; inst;) { + ONEdestroy(inst->NBJTpDevice); + nextInst = inst->NBJTnextInstance; + FREE(inst); + inst = nextInst; + } + nextMod = mod->NBJTnextModel; + FREE(mod); + mod = nextMod; + } + *model = NULL; +} diff --git a/src/spicelib/devices/nbjt/nbjtdump.c b/src/spicelib/devices/nbjt/nbjtdump.c new file mode 100644 index 000000000..6f5d0f6d1 --- /dev/null +++ b/src/spicelib/devices/nbjt/nbjtdump.c @@ -0,0 +1,177 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +Author: 1991 David A. Gates, U. C. Berkeley CAD Group +**********/ + +/* + * This is a simple routine to dump the internal device states. It produces + * states for .OP, .DC, & .TRAN simulations. + */ + +#include "ngspice.h" +#include "cktdefs.h" +#include "nbjtdefs.h" +#include "../../../ciderlib/oned/onedext.h" +#include "cidersupt.h" +#include "suffix.h" + + +/* Forward Declarations */ +static void NBJTputHeader(FILE *, CKTcircuit *, NBJTinstance *); + +/* State Counter */ +static int state_numOP = 0; +static int state_numDC = 0; +static int state_numTR = 0; + +void +NBJTdump(inModel, ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + register NBJTmodel *model = (NBJTmodel *) inModel; + register NBJTinstance *inst; + OUTPcard *output; + FILE *fpState; + char fileName[BSIZE_SP]; + char description[BSIZE_SP]; + char *prefix; + int *state_num; + int anyOutput = 0; + + if (ckt->CKTmode & MODEDCOP) { + prefix = "OP"; + state_num = &state_numOP; + sprintf(description, "..."); + } else if (ckt->CKTmode & MODEDCTRANCURVE) { + prefix = "DC"; + state_num = &state_numDC; + sprintf(description, "sweep = % e", ckt->CKTtime); + } else if (ckt->CKTmode & MODETRAN) { + prefix = "TR"; + state_num = &state_numTR; + sprintf(description, "time = % e", ckt->CKTtime); + } else { + /* Not a recognized CKT mode. */ + return; + } + + for (; model != NULL; model = model->NBJTnextModel) { + output = model->NBJToutputs; + for (inst = model->NBJTinstances; inst != NULL; + inst = inst->NBJTnextInstance) { + if (inst->NBJTowner != ARCHme) continue; + + if (inst->NBJTprintGiven) { + if ((ckt->CKTmode & MODETRAN) && + ((ckt->CKTstat->STATaccepted - 1) % inst->NBJTprint != 0)) { + continue; + } + anyOutput = 1; + sprintf(fileName, "%s%s.%d.%s", output->OUTProotFile, prefix, + *state_num, inst->NBJTname); + if (!(fpState = fopen(fileName, "w"))) { + perror(fileName); + } else { + NBJTputHeader(fpState, ckt, inst); + ONEprnSolution(fpState, inst->NBJTpDevice, + model->NBJToutputs); + fclose(fpState); + LOGmakeEntry(fileName, description); + } + } + } + } + if (anyOutput) { + (*state_num)++; + } +} + +#define NBJTnumOutputs 9 + +static +void +NBJTputHeader(file, ckt, inst) + FILE *file; + CKTcircuit *ckt; + NBJTinstance *inst; +{ + char *reference; + double refVal = 0.0; + int numVars = NBJTnumOutputs; + + if (ckt->CKTmode & MODEDCOP) { + reference = NULL; + } else if (ckt->CKTmode & MODEDCTRANCURVE) { + reference = "sweep"; + refVal = ckt->CKTtime; + numVars++; + } else if (ckt->CKTmode & MODETRAN) { + reference = "time"; + refVal = ckt->CKTtime; + numVars++; + } else { + reference = NULL; + } + fprintf(file, "Title: Device %s external state\n", inst->NBJTname); + fprintf(file, "Plotname: Device Operating Point\n"); + fprintf(file, "Command: deftype v conductance S\n"); + fprintf(file, "Flags: real\n"); + fprintf(file, "No. Variables: %d\n", numVars); + fprintf(file, "No. Points: 1\n"); + numVars = 0; + fprintf(file, "Variables:\n"); + if (reference) { + fprintf(file, "\t%d %s unknown\n", numVars++, reference); + } + fprintf(file, "\t%d v13 voltage\n", numVars++); + fprintf(file, "\t%d v23 voltage\n", numVars++); + fprintf(file, "\t%d i1 current\n", numVars++); + fprintf(file, "\t%d i2 current\n", numVars++); + fprintf(file, "\t%d i3 current\n", numVars++); + fprintf(file, "\t%d g22 conductance\n", numVars++); + fprintf(file, "\t%d g21 conductance\n", numVars++); + fprintf(file, "\t%d g12 conductance\n", numVars++); + fprintf(file, "\t%d g11 conductance\n", numVars++); + fprintf(file, "Values:\n0"); + if (reference) { + fprintf(file, "\t% e\n", refVal); + } + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NBJTvce)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NBJTvbe)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NBJTic)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NBJTie) + - *(ckt->CKTstate0 + inst->NBJTic)); + fprintf(file, "\t% e\n", -*(ckt->CKTstate0 + inst->NBJTie)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NBJTdIeDVbe) + - *(ckt->CKTstate0 + inst->NBJTdIcDVbe)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NBJTdIeDVce) + - *(ckt->CKTstate0 + inst->NBJTdIcDVce)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NBJTdIcDVbe)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NBJTdIcDVce)); +} + +void +NBJTacct(inModel, ckt, file) + GENmodel *inModel; + CKTcircuit *ckt; + FILE *file; +{ + register NBJTmodel *model = (NBJTmodel *) inModel; + register NBJTinstance *inst; + OUTPcard *output; + + for (; model != NULL; model = model->NBJTnextModel) { + output = model->NBJToutputs; + for (inst = model->NBJTinstances; inst != NULL; + inst = inst->NBJTnextInstance) { + if (inst->NBJTowner != ARCHme) continue; + + if (output->OUTPstats) { + ONEmemStats(file, inst->NBJTpDevice); + ONEcpuStats(file, inst->NBJTpDevice); + } + } + } +} diff --git a/src/spicelib/devices/nbjt/nbjtext.h b/src/spicelib/devices/nbjt/nbjtext.h new file mode 100644 index 000000000..b9d0a980c --- /dev/null +++ b/src/spicelib/devices/nbjt/nbjtext.h @@ -0,0 +1,27 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Karti Mayaram +**********/ + +#ifndef __NBJT_H +#define __NBJT_H + +extern int NBJTacLoad(GENmodel *, CKTcircuit *); +extern int NBJTask(CKTcircuit *, GENinstance *, int, IFvalue *, IFvalue *); +extern int NBJTdelete(GENmodel *, IFuid, GENinstance **); +extern void NBJTdestroy(GENmodel **); +extern int NBJTgetic(GENmodel *, CKTcircuit *); +extern int NBJTload(GENmodel *, CKTcircuit *); +extern int NBJTmDelete(GENmodel **, IFuid, GENmodel *); +extern int NBJTmParam(int, IFvalue *, GENmodel *); +extern int NBJTparam(int, IFvalue *, GENinstance *, IFvalue *); +extern int NBJTpzLoad(GENmodel *, CKTcircuit *, SPcomplex *); +extern int NBJTsetup(SMPmatrix *, GENmodel *, CKTcircuit *, int *); +extern int NBJTtemp(GENmodel *, CKTcircuit *); +extern int NBJTtrunc(GENmodel *, CKTcircuit *, double *); + +extern void NBJTdump(GENmodel *, CKTcircuit *); +extern void NBJTacct(GENmodel *, CKTcircuit *, FILE *); + + +#endif /* NBJT_H */ diff --git a/src/spicelib/devices/nbjt/nbjtinit.c b/src/spicelib/devices/nbjt/nbjtinit.c new file mode 100644 index 000000000..a0db95d58 --- /dev/null +++ b/src/spicelib/devices/nbjt/nbjtinit.c @@ -0,0 +1,83 @@ +#include + +#include + +#include "nbjtitf.h" +#include "nbjtext.h" +#include "nbjtinit.h" + + +SPICEdev NBJTinfo = { + { + "NBJT", + "1D Numerical Bipolar Junction Transistor model", + + &NBJTnSize, + &NBJTnSize, + NBJTnames, + + &NBJTpTSize, + NBJTpTable, + + &NBJTmPTSize, + NBJTmPTable, + +#ifdef XSPICE +/*---- Fixed by SDB 5.2.2003 to enable XSPICE/tclspice integration -----*/ + NULL, /* This is a SPICE device, it has no MIF info data */ + + 0, /* This is a SPICE device, it has no MIF info data */ + NULL, /* This is a SPICE device, it has no MIF info data */ + + 0, /* This is a SPICE device, it has no MIF info data */ + NULL, /* This is a SPICE device, it has no MIF info data */ + + 0, /* This is a SPICE device, it has no MIF info data */ + NULL, /* This is a SPICE device, it has no MIF info data */ +/*--------------------------- End of SDB fix -------------------------*/ +#endif + + DEV_DEFAULT + }, + + DEVparam : NBJTparam, + DEVmodParam : NBJTmParam, + DEVload : NBJTload, + DEVsetup : NBJTsetup, + DEVunsetup : NULL, + DEVpzSetup : NBJTsetup, + DEVtemperature: NBJTtemp, + DEVtrunc : NBJTtrunc, + DEVfindBranch : NULL, + DEVacLoad : NBJTacLoad, + DEVaccept : NULL, + DEVdestroy : NBJTdestroy, + DEVmodDelete : NBJTmDelete, + DEVdelete : NBJTdelete, + DEVsetic : NULL, + DEVask : NBJTask, + DEVmodAsk : NULL, + DEVpzLoad : NBJTpzLoad, + DEVconvTest : NULL, + DEVsenSetup : NULL, + DEVsenLoad : NULL, + DEVsenUpdate : NULL, + DEVsenAcLoad : NULL, + DEVsenPrint : NULL, + DEVsenTrunc : NULL, + DEVdisto : NULL, + DEVnoise : NULL, + DEVdump : NBJTdump, + DEVacct : NBJTacct, + + DEVinstSize : &NBJTiSize, + DEVmodSize : &NBJTmSize + +}; + + +SPICEdev * +get_nbjt_info(void) +{ + return &NBJTinfo; +} diff --git a/src/spicelib/devices/nbjt/nbjtinit.h b/src/spicelib/devices/nbjt/nbjtinit.h new file mode 100644 index 000000000..e7c6cae38 --- /dev/null +++ b/src/spicelib/devices/nbjt/nbjtinit.h @@ -0,0 +1,13 @@ +#ifndef _NBJTINIT_H +#define _NBJTINIT_H + +extern IFparm NBJTpTable[ ]; +extern IFparm NBJTmPTable[ ]; +extern char *NBJTnames[ ]; +extern int NBJTpTSize; +extern int NBJTmPTSize; +extern int NBJTnSize; +extern int NBJTiSize; +extern int NBJTmSize; + +#endif diff --git a/src/spicelib/devices/nbjt/nbjtitf.h b/src/spicelib/devices/nbjt/nbjtitf.h new file mode 100644 index 000000000..2479b5396 --- /dev/null +++ b/src/spicelib/devices/nbjt/nbjtitf.h @@ -0,0 +1,12 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +**********/ + +#ifndef DEV_NBJT +#define DEV_NBJT + +extern SPICEdev *get_nbjt_info(void); + + +#endif + diff --git a/src/spicelib/devices/nbjt/nbjtload.c b/src/spicelib/devices/nbjt/nbjtload.c new file mode 100644 index 000000000..39cc9257f --- /dev/null +++ b/src/spicelib/devices/nbjt/nbjtload.c @@ -0,0 +1,517 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This is the function called each iteration to evaluate the numerical BJTs + * in the circuit and load them into the matrix as appropriate + */ + +#include "ngspice.h" +#include "devdefs.h" +#include "cktdefs.h" +#include "nbjtdefs.h" +#include "trandefs.h" +#include "sperror.h" +#include "../../../ciderlib/oned/onedext.h" +#include "cidersupt.h" +#include "suffix.h" + +/* Forward declarations */ +int NBJTinitSmSig(NBJTinstance *); + +/* External Declarations */ +extern int ONEdcDebug; +extern int ONEtranDebug; +extern int ONEacDebug; + + +int +NBJTload(inModel, ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + register NBJTmodel *model = (NBJTmodel *) inModel; + register NBJTinstance *inst; + register ONEdevice *pDevice; + double startTime, startTime2, totalTime, totalTime2; + double tol; + double ic, ie; + double iceq, ieeq; + double ichat = 0.0, iehat = 0.0; + double delVce, delVbe; + double vce, vbe, vbc; + double dIeDVce, dIeDVbe; + double dIcDVce, dIcDVbe; + double xfact; + int icheck; + int icheck1; + int i; + double deltaNorm[7]; + int devConverged = 0; + int numDevNonCon; + int deviceType; + int doInitSolve; + int doVoltPred; + char *initStateName; + + /* loop through all the models */ + for (; model != NULL; model = model->NBJTnextModel) { + FieldDepMobility = model->NBJTmodels->MODLfieldDepMobility; + Srh = model->NBJTmodels->MODLsrh; + Auger = model->NBJTmodels->MODLauger; + AvalancheGen = model->NBJTmodels->MODLavalancheGen; + MobDeriv = model->NBJTmethods->METHmobDeriv; + MaxIterations = model->NBJTmethods->METHitLim; + ONEdcDebug = model->NBJToutputs->OUTPdcDebug; + ONEtranDebug = model->NBJToutputs->OUTPtranDebug; + ONEacDebug = model->NBJToutputs->OUTPacDebug; + deviceType = model->NBJToptions->OPTNdeviceType; + doVoltPred = model->NBJTmethods->METHvoltPred; + + if (ckt->CKTmode & MODEINITPRED) { + /* compute normalized deltas and predictor coeff */ + if (!(ckt->CKTmode & MODEDCTRANCURVE)) { + model->NBJTpInfo->order = ckt->CKTorder; + model->NBJTpInfo->method = ckt->CKTintegrateMethod; + for (i = 0; i <= ckt->CKTmaxOrder; i++) { + deltaNorm[i] = ckt->CKTdeltaOld[i] / TNorm; + } + computeIntegCoeff(ckt->CKTintegrateMethod, ckt->CKTorder, + model->NBJTpInfo->intCoeff, deltaNorm); + computePredCoeff(ckt->CKTintegrateMethod, ckt->CKTorder, + model->NBJTpInfo->predCoeff, deltaNorm); + } + } else if (ckt->CKTmode & MODEINITTRAN) { + model->NBJTpInfo->order = ckt->CKTorder; + model->NBJTpInfo->method = ckt->CKTintegrateMethod; + for (i = 0; i <= ckt->CKTmaxOrder; i++) { + deltaNorm[i] = ckt->CKTdeltaOld[i] / TNorm; + } + computeIntegCoeff(ckt->CKTintegrateMethod, ckt->CKTorder, + model->NBJTpInfo->intCoeff, deltaNorm); + } + /* loop through all the instances of the model */ + for (inst = model->NBJTinstances; inst != NULL; + inst = inst->NBJTnextInstance) { + if (inst->NBJTowner != ARCHme) continue; + + pDevice = inst->NBJTpDevice; + + totalTime = 0.0; + startTime = SPfrontEnd->IFseconds(); + + /* Get Temp.-Dep. Global Parameters */ + GLOBgetGlobals(&(inst->NBJTglobals)); + + /* + * initialization + */ + + pDevice->devStates = ckt->CKTstates; + icheck = 1; + doInitSolve = FALSE; + initStateName = NULL; + if (ckt->CKTmode & MODEINITSMSIG) { + vbe = *(ckt->CKTstate0 + inst->NBJTvbe); + vce = *(ckt->CKTstate0 + inst->NBJTvce); + delVbe = 0.0; + delVce = 0.0; + NBJTsetBCs(pDevice, vce, vbe); + } else if (ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate0 + inst->NBJTvbe) = + *(ckt->CKTstate1 + inst->NBJTvbe); + *(ckt->CKTstate0 + inst->NBJTvce) = + *(ckt->CKTstate1 + inst->NBJTvce); + vbe = *(ckt->CKTstate1 + inst->NBJTvbe); + vce = *(ckt->CKTstate1 + inst->NBJTvce); + ONEsaveState(pDevice); + delVbe = 0.0; + delVce = 0.0; + } else if ((ckt->CKTmode & MODEINITJCT) && + (ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) { + doInitSolve = TRUE; + initStateName = inst->NBJTicFile; + vbe = 0.0; + vce = 0.0; + delVbe = vbe; + delVce = vce; + } else if ((ckt->CKTmode & MODEINITJCT) && (inst->NBJToff == 0)) { + doInitSolve = TRUE; + initStateName = inst->NBJTicFile; + vbe = inst->NBJTtype * 0.6; + vce = inst->NBJTtype * 1.0; + delVbe = vbe; + delVce = vce; + } else if (ckt->CKTmode & MODEINITJCT) { + doInitSolve = TRUE; + vbe = 0.0; + vce = 0.0; + delVbe = vbe; + delVce = vce; + } else if ((ckt->CKTmode & MODEINITFIX) && inst->NBJToff) { + vbe = 0.0; + vce = 0.0; + delVbe = vbe; + delVce = vce; + } else { + if (ckt->CKTmode & MODEINITPRED) { + *(ckt->CKTstate0 + inst->NBJTvbe) = + *(ckt->CKTstate1 + inst->NBJTvbe); + *(ckt->CKTstate0 + inst->NBJTvce) = + *(ckt->CKTstate1 + inst->NBJTvce); + *(ckt->CKTstate0 + inst->NBJTic) = + *(ckt->CKTstate1 + inst->NBJTic); + *(ckt->CKTstate0 + inst->NBJTie) = + *(ckt->CKTstate1 + inst->NBJTie); + *(ckt->CKTstate0 + inst->NBJTdIeDVce) = + *(ckt->CKTstate1 + inst->NBJTdIeDVce); + *(ckt->CKTstate0 + inst->NBJTdIeDVbe) = + *(ckt->CKTstate1 + inst->NBJTdIeDVbe); + *(ckt->CKTstate0 + inst->NBJTdIcDVce) = + *(ckt->CKTstate1 + inst->NBJTdIcDVce); + *(ckt->CKTstate0 + inst->NBJTdIcDVbe) = + *(ckt->CKTstate1 + inst->NBJTdIcDVbe); + if (!(ckt->CKTmode & MODEDCTRANCURVE)) { + /* no linear prediction on device voltages */ + vbe = *(ckt->CKTstate1 + inst->NBJTvbe); + vce = *(ckt->CKTstate1 + inst->NBJTvce); + ONEpredict(pDevice, model->NBJTpInfo); + } else { + if (doVoltPred) { + /* linear prediction */ + xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1]; + vbe = (1+xfact) * (*(ckt->CKTstate1 + inst->NBJTvbe)) + - (xfact) * (*(ckt->CKTstate2 + inst->NBJTvbe)); + vce = (1+xfact) * (*(ckt->CKTstate1 + inst->NBJTvce)) + - (xfact) * (*(ckt->CKTstate2 + inst->NBJTvce)); + } else { + vbe = *(ckt->CKTstate1 + inst->NBJTvbe); + vce = *(ckt->CKTstate1 + inst->NBJTvce); + } + } + } else { + /* + * compute new nonlinear branch voltages + */ + vbe = *(ckt->CKTrhsOld + inst->NBJTbaseNode) - + *(ckt->CKTrhsOld + inst->NBJTemitNode); + vce = *(ckt->CKTrhsOld + inst->NBJTcolNode) - + *(ckt->CKTrhsOld + inst->NBJTemitNode); + } + delVbe = vbe - *(ckt->CKTstate0 + inst->NBJTvbe); + delVce = vce - *(ckt->CKTstate0 + inst->NBJTvce); + ichat = *(ckt->CKTstate0 + inst->NBJTic) - + *(ckt->CKTstate0 + inst->NBJTdIcDVbe) * delVbe - + *(ckt->CKTstate0 + inst->NBJTdIcDVce) * delVce; + iehat = *(ckt->CKTstate0 + inst->NBJTie) - + *(ckt->CKTstate0 + inst->NBJTdIeDVbe) * delVbe - + *(ckt->CKTstate0 + inst->NBJTdIeDVce) * delVce; + +#ifndef NOBYPASS + /* + * bypass if solution has not changed + */ + /* + * the following collections of if's would be just one if the average + * compiler could handle it, but many find the expression too + * complicated, thus the split. + */ + if ((ckt->CKTbypass) && pDevice->converged && + (!(ckt->CKTmode & MODEINITPRED)) && + (fabs(delVbe) < (ckt->CKTreltol * MAX(fabs(vbe), + fabs(*(ckt->CKTstate0 + inst->NBJTvbe))) + + ckt->CKTvoltTol))) + if ((fabs(delVce) < ckt->CKTreltol * MAX(fabs(vce), + fabs(*(ckt->CKTstate0 + inst->NBJTvce))) + + ckt->CKTvoltTol)) + if ((fabs(ichat - *(ckt->CKTstate0 + inst->NBJTic)) < + ckt->CKTreltol * MAX(fabs(ichat), + fabs(*(ckt->CKTstate0 + inst->NBJTic))) + + ckt->CKTabstol)) + if ((fabs(iehat - *(ckt->CKTstate0 + inst->NBJTie)) < + ckt->CKTreltol * MAX(fabs(iehat), + fabs(*(ckt->CKTstate0 + inst->NBJTie))) + + ckt->CKTabstol)) { + /* + * bypassing.... + */ + vbe = *(ckt->CKTstate0 + inst->NBJTvbe); + vce = *(ckt->CKTstate0 + inst->NBJTvce); + ic = *(ckt->CKTstate0 + inst->NBJTic); + ie = *(ckt->CKTstate0 + inst->NBJTie); + dIeDVce = *(ckt->CKTstate0 + inst->NBJTdIeDVce); + dIeDVbe = *(ckt->CKTstate0 + inst->NBJTdIeDVbe); + dIcDVce = *(ckt->CKTstate0 + inst->NBJTdIcDVce); + dIcDVbe = *(ckt->CKTstate0 + inst->NBJTdIcDVbe); + goto load; + } +#endif /* NOBYPASS */ + /* + * limit nonlinear branch voltages + */ + icheck1 = 1; + vbe = inst->NBJTtype * limitVbe(inst->NBJTtype * vbe, + inst->NBJTtype * *(ckt->CKTstate0 + inst->NBJTvbe), &icheck); + /* + vbc = vbe - vce; + vbc = inst->NBJTtype * limitVbe(inst->NBJTtype * vbc, + inst->NBJTtype * (*(ckt->CKTstate0 + inst->NBJTvbe) + - *(ckt->CKTstate0 + inst->NBJTvce)), &icheck1); + vce = vbe - vbc; + */ + vce = inst->NBJTtype * limitVce(inst->NBJTtype * vce, + inst->NBJTtype * *(ckt->CKTstate0 + inst->NBJTvce), &icheck1); + if (icheck1 == 1) + icheck = 1; + delVbe = vbe - *(ckt->CKTstate0 + inst->NBJTvbe); + delVce = vce - *(ckt->CKTstate0 + inst->NBJTvce); + } + if (doInitSolve) { + if (ONEdcDebug) { + printVoltages(stdout, + model->NBJTmodName, inst->NBJTname, + deviceType, 2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + } + startTime2 = SPfrontEnd->IFseconds(); + ONEequilSolve(pDevice); + totalTime2 = SPfrontEnd->IFseconds() - startTime2; + pDevice->pStats->totalTime[STAT_SETUP] += totalTime2; + pDevice->pStats->totalTime[STAT_DC] -= totalTime2; + + ONEbiasSolve(pDevice, MaxIterations, FALSE, NULL); + + *(ckt->CKTstate0 + inst->NBJTvbe) = 0.0; + *(ckt->CKTstate0 + inst->NBJTvce) = 0.0; + + if (initStateName != NULL) { + if (ONEreadState(pDevice, initStateName, 2, &vce, &vbe ) < 0) { + fprintf(stderr, + "NBJTload: trouble reading state-file %s\n", initStateName); + } else { + NBJTsetBCs(pDevice, vce, vbe); + delVce = delVbe = 0.0; + } + } + } + /* + * determine dc current and derivatives using the numerical routines + */ + if (ckt->CKTmode & (MODEDCOP | MODETRANOP | MODEDCTRANCURVE | MODEINITSMSIG)) { + + numDevNonCon = 0; + inst->NBJTc11 = inst->NBJTy11r = inst->NBJTy11i = 0.0; + inst->NBJTc12 = inst->NBJTy12r = inst->NBJTy12i = 0.0; + inst->NBJTc21 = inst->NBJTy21r = inst->NBJTy21i = 0.0; + inst->NBJTc22 = inst->NBJTy22r = inst->NBJTy22i = 0.0; + inst->NBJTsmSigAvail = FALSE; + devNonCon: + NBJTproject(pDevice, delVce, delVbe, vbe); + if (ONEdcDebug) { + printVoltages(stdout, + model->NBJTmodName, inst->NBJTname, + deviceType, 2, vce, delVce, vbe, delVbe, 0.0, 0.0); + } + ONEbiasSolve(pDevice, MaxIterations, FALSE, model->NBJTpInfo); + + devConverged = pDevice->converged; + if (devConverged && finite(pDevice->rhsNorm)) { + /* compute the currents */ + NBJTcurrent(pDevice, FALSE, (double *) NULL, + &ie, &ic); + NBJTconductance(pDevice, FALSE, (double *) NULL, + &dIeDVce, &dIcDVce, &dIeDVbe, &dIcDVbe); + /* + * Add Gmin terms to everything in case we are operating at + * abnormally low current levels + */ + ie += ckt->CKTgmin * (vce + vbe); + dIeDVce += ckt->CKTgmin; + dIeDVbe += ckt->CKTgmin; + ic += ckt->CKTgmin * (2.0 * vce - vbe); + dIcDVce += 2.0 * ckt->CKTgmin; + dIcDVbe -= ckt->CKTgmin; + + } else { + /* reduce the voltage step until converged */ + /* restore the boundary potential to previous value */ + NBJTsetBCs(pDevice, vce - delVce, vbe - delVbe); + ONEstoreInitialGuess(pDevice); + ONEresetJacobian(pDevice); + delVbe *= 0.5; + delVce *= 0.5; + vbe = delVbe + *(ckt->CKTstate0 + inst->NBJTvbe); + vce = delVce + *(ckt->CKTstate0 + inst->NBJTvce); + numDevNonCon++; + icheck = 1; + if (numDevNonCon > 10) { + printVoltages(stderr, + model->NBJTmodName, inst->NBJTname, + deviceType, 2, vce, delVce, vbe, delVbe, 0.0, 0.0); + fprintf(stderr, + "*** Non-convergence during load ***\n"); + totalTime += SPfrontEnd->IFseconds() - startTime; + pDevice->pStats->totalTime[STAT_DC] += totalTime; + ckt->CKTtroubleElt = (GENinstance *) inst; + return (E_BADMATRIX); + } else { + goto devNonCon; + } + } + + } + if ((ckt->CKTmode & (MODETRAN | MODEAC)) || + ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) || + (ckt->CKTmode & MODEINITSMSIG)) { + /* + * store small-signal parameters + */ + if ((!(ckt->CKTmode & MODETRANOP)) || + (!(ckt->CKTmode & MODEUIC))) { + if (ckt->CKTmode & MODEINITSMSIG) { + totalTime += SPfrontEnd->IFseconds() - startTime; + pDevice->pStats->totalTime[STAT_DC] += totalTime; + startTime2 = SPfrontEnd->IFseconds(); + NBJTinitSmSig(inst); + pDevice->pStats->totalTime[STAT_AC] += + SPfrontEnd->IFseconds() - startTime2; + continue; + } else { + inst->NBJTsmSigAvail = FALSE; + } + /* + * transient analysis + */ + if (ckt->CKTmode & MODEINITPRED) { + NBJTsetBCs(pDevice, vce, vbe); + ONEstoreInitialGuess(pDevice); + } else { + NBJTupdate(pDevice, delVce, delVbe, vbe, TRUE); + } + if (ONEtranDebug) { + printVoltages(stdout, + model->NBJTmodName, inst->NBJTname, + deviceType, 2, vce, delVce, vbe, delVbe, 0.0, 0.0); + } + ONEbiasSolve(pDevice, 0, TRUE, model->NBJTpInfo); + if (!finite(pDevice->rhsNorm)) { + /* Timestep took us to never-never land. */ + totalTime += SPfrontEnd->IFseconds() - startTime; + pDevice->pStats->totalTime[STAT_TRAN] += totalTime; + ckt->CKTtroubleElt = (GENinstance *) inst; + return (E_BADMATRIX); + } + devConverged = ONEdeviceConverged(pDevice); + pDevice->converged = devConverged; + + /* compute the currents */ + NBJTcurrent(pDevice, TRUE, + model->NBJTpInfo->intCoeff, &ie, &ic); + NBJTconductance(pDevice, TRUE, + model->NBJTpInfo->intCoeff, + &dIeDVce, &dIcDVce, &dIeDVbe, &dIcDVbe); + + /* + * Add Gmin terms to everything in case we are operating at + * abnormally low current levels + */ + ie += ckt->CKTgmin * (vce + vbe); + dIeDVce += ckt->CKTgmin; + dIeDVbe += ckt->CKTgmin; + ic += ckt->CKTgmin * (2.0 * vce - vbe); + dIcDVce += 2.0 * ckt->CKTgmin; + dIcDVbe -= ckt->CKTgmin; + } + } + /* + * check convergence + */ + if ((!(ckt->CKTmode & MODEINITFIX)) || (!(inst->NBJToff))) { + if (icheck == 1 || !devConverged) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) inst; + } else { + tol = ckt->CKTreltol * MAX(fabs(ichat), fabs(ic)) + ckt->CKTabstol; + if (fabs(ichat - ic) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) inst; + } else { + tol = ckt->CKTreltol * MAX(fabs(iehat), fabs(ie)) + + ckt->CKTabstol; + if (fabs(iehat - ie) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) inst; + } + } + } + } + *(ckt->CKTstate0 + inst->NBJTvbe) = vbe; + *(ckt->CKTstate0 + inst->NBJTvce) = vce; + *(ckt->CKTstate0 + inst->NBJTic) = ic; + *(ckt->CKTstate0 + inst->NBJTie) = ie; + *(ckt->CKTstate0 + inst->NBJTdIeDVce) = dIeDVce; + *(ckt->CKTstate0 + inst->NBJTdIeDVbe) = dIeDVbe; + *(ckt->CKTstate0 + inst->NBJTdIcDVce) = dIcDVce; + *(ckt->CKTstate0 + inst->NBJTdIcDVbe) = dIcDVbe; + + load: + /* + * load current excitation vector + */ + iceq = ic - dIcDVce * vce - dIcDVbe * vbe; + ieeq = ie - dIeDVce * vce - dIeDVbe * vbe; + *(ckt->CKTrhs + inst->NBJTcolNode) -= iceq; + *(ckt->CKTrhs + inst->NBJTbaseNode) -= ieeq - iceq; + *(ckt->CKTrhs + inst->NBJTemitNode) += ieeq; + + /* + * load y matrix + */ + *(inst->NBJTcolColPtr) += dIcDVce; + *(inst->NBJTcolBasePtr) += dIcDVbe; + *(inst->NBJTcolEmitPtr) -= dIcDVbe + dIcDVce; + *(inst->NBJTbaseColPtr) -= dIcDVce - dIeDVce; + *(inst->NBJTbaseBasePtr) -= dIcDVbe - dIeDVbe; + *(inst->NBJTbaseEmitPtr) += dIcDVbe + dIcDVce - dIeDVbe - dIeDVce; + *(inst->NBJTemitColPtr) -= dIeDVce; + *(inst->NBJTemitBasePtr) -= dIeDVbe; + *(inst->NBJTemitEmitPtr) += dIeDVbe + dIeDVce; + + totalTime += SPfrontEnd->IFseconds() - startTime; + if (ckt->CKTmode & MODETRAN) { + pDevice->pStats->totalTime[STAT_TRAN] += totalTime; + } else { + pDevice->pStats->totalTime[STAT_DC] += totalTime; + } + } + } + return (OK); +} + +int +NBJTinitSmSig(inst) + NBJTinstance *inst; +{ + SPcomplex yIeVce, yIeVbe; + SPcomplex yIcVce, yIcVbe; + double omega = inst->NBJTmodPtr->NBJTmethods->METHomega; + + AcAnalysisMethod = SOR_ONLY; + (void) NBJTadmittance(inst->NBJTpDevice, omega, + &yIeVce, &yIcVce, &yIeVbe, &yIcVbe); + inst->NBJTc11 = yIcVce.imag / omega; + inst->NBJTc12 = yIcVbe.imag / omega; + inst->NBJTc21 = (yIeVce.imag - yIcVce.imag) / omega; + inst->NBJTc22 = (yIeVbe.imag - yIcVbe.imag) / omega; + inst->NBJTy11r = yIcVce.real; + inst->NBJTy11i = yIcVce.imag; + inst->NBJTy12r = yIcVbe.real; + inst->NBJTy12i = yIcVbe.imag; + inst->NBJTy21r = yIeVce.real - yIcVce.real; + inst->NBJTy21i = yIeVce.imag - yIcVce.imag; + inst->NBJTy22r = yIeVbe.real - yIcVbe.real; + inst->NBJTy22i = yIeVbe.imag - yIcVbe.imag; + inst->NBJTsmSigAvail = TRUE; + return (OK); +} diff --git a/src/spicelib/devices/nbjt/nbjtmdel.c b/src/spicelib/devices/nbjt/nbjtmdel.c new file mode 100644 index 000000000..5b2e52f4c --- /dev/null +++ b/src/spicelib/devices/nbjt/nbjtmdel.c @@ -0,0 +1,43 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This routine deletes a NBJT model from the circuit and frees the storage + * it was using. returns an error if the model has instances + */ + +#include "ngspice.h" +#include "nbjtdefs.h" +#include "sperror.h" +#include "suffix.h" + +int +NBJTmDelete(inModel, modname, kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; + +{ + + NBJTmodel **model = (NBJTmodel **) inModel; + NBJTmodel *modfast = (NBJTmodel *) kill; + NBJTmodel **oldmod; + oldmod = model; + for (; *model; model = &((*model)->NBJTnextModel)) { + if ((*model)->NBJTmodName == modname || + (modfast && *model == modfast)) + goto delgot; + oldmod = model; + } + return (E_NOMOD); + +delgot: + if ((*model)->NBJTinstances) + return (E_NOTEMPTY); + *oldmod = (*model)->NBJTnextModel; /* cut deleted device out of list */ + FREE(*model); + return (OK); + +} diff --git a/src/spicelib/devices/nbjt/nbjtmpar.c b/src/spicelib/devices/nbjt/nbjtmpar.c new file mode 100644 index 000000000..ac73fda90 --- /dev/null +++ b/src/spicelib/devices/nbjt/nbjtmpar.c @@ -0,0 +1,32 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This routine sets model parameters for NBJTs in the circuit. + */ + +#include "ngspice.h" +#include "const.h" +#include "ifsim.h" +#include "nbjtdefs.h" +#include "sperror.h" +#include "suffix.h" + +int +NBJTmParam(param, value, inModel) + int param; + IFvalue *value; + GENmodel *inModel; +{ + switch (param) { + case NBJT_MOD_NBJT: + /* no action - already know it is a numerical bjt, but this */ + /* makes life easier for spice-2 like parsers */ + break; + default: + return (E_BADPARM); + } + return (OK); +} diff --git a/src/spicelib/devices/nbjt/nbjtparm.c b/src/spicelib/devices/nbjt/nbjtparm.c new file mode 100644 index 000000000..f6e483e54 --- /dev/null +++ b/src/spicelib/devices/nbjt/nbjtparm.c @@ -0,0 +1,49 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This routine sets instance parameters for NBJTs in the circuit. + */ + +#include "ngspice.h" +#include "const.h" +#include "ifsim.h" +#include "nbjtdefs.h" +#include "sperror.h" +#include "suffix.h" + +int +NBJTparam(param, value, inInst, select) + int param; + IFvalue *value; + GENinstance *inInst; + IFvalue *select; +{ + register NBJTinstance *inst = (NBJTinstance *) inInst; + switch (param) { + case NBJT_AREA: + inst->NBJTarea = value->rValue; + inst->NBJTareaGiven = TRUE; + break; + case NBJT_OFF: + inst->NBJToff = TRUE; + break; + case NBJT_IC_FILE: + inst->NBJTicFile = value->sValue; + inst->NBJTicFileGiven = TRUE; + break; + case NBJT_PRINT: + inst->NBJTprint = value->rValue; + inst->NBJTprintGiven = TRUE; + break; + case NBJT_TEMP: + inst->NBJTtemp = value->rValue + CONSTCtoK; + inst->NBJTtempGiven = TRUE; + break; + default: + return (E_BADPARM); + } + return (OK); +} diff --git a/src/spicelib/devices/nbjt/nbjtpzld.c b/src/spicelib/devices/nbjt/nbjtpzld.c new file mode 100644 index 000000000..848f4ebd6 --- /dev/null +++ b/src/spicelib/devices/nbjt/nbjtpzld.c @@ -0,0 +1,92 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * Function to load the COMPLEX circuit matrix using the small signal + * parameters saved during a previous DC operating point analysis. + */ + +#include "ngspice.h" +#include "cktdefs.h" +#include "nbjtdefs.h" +#include "../../../ciderlib/oned/onedext.h" +#include "cidersupt.h" +#include "sperror.h" +#include "complex.h" +#include "suffix.h" + +/* External Declarations */ +extern int ONEacDebug; + +int +NBJTpzLoad(inModel, ckt, s) + GENmodel *inModel; + CKTcircuit *ckt; + SPcomplex *s; + +{ + register NBJTmodel *model = (NBJTmodel *) inModel; + register NBJTinstance *inst; + SPcomplex yIeVce, yIeVbe; + SPcomplex yIcVce, yIcVbe; + double startTime; + + for (; model != NULL; model = model->NBJTnextModel) { + FieldDepMobility = model->NBJTmodels->MODLfieldDepMobility; + Srh = model->NBJTmodels->MODLsrh; + Auger = model->NBJTmodels->MODLauger; + AvalancheGen = model->NBJTmodels->MODLavalancheGen; + AcAnalysisMethod = model->NBJTmethods->METHacAnalysisMethod; + MobDeriv = model->NBJTmethods->METHmobDeriv; + ONEacDebug = model->NBJToutputs->OUTPacDebug; + + for (inst = model->NBJTinstances; inst != NULL; + inst = inst->NBJTnextInstance) { + if (inst->NBJTowner != ARCHme) continue; + + startTime = SPfrontEnd->IFseconds(); + /* Get Temp.-Dep. Global Parameters */ + GLOBgetGlobals(&(inst->NBJTglobals)); + + NBJTys(inst->NBJTpDevice, s, + &yIeVce, &yIcVce, &yIeVbe, &yIcVbe); + + if (ONEacDebug) { + fprintf(stdout, "BJT admittances: %s:%s at s = % .5g, % .5g\n", + model->NBJTmodName, inst->NBJTname, s->real, s->imag); + fprintf(stdout, "Ycc: % .5g,% .5g\n", + yIcVce.real, yIcVce.imag); + fprintf(stdout, "Ycb: % .5g,% .5g\n", + yIcVbe.real, yIcVbe.imag); + fprintf(stdout, "Ybc: % .5g,% .5g\n", + yIeVce.real - yIcVce.real, yIeVce.imag - yIcVce.imag); + fprintf(stdout, "Ybb: % .5g,% .5g\n", + yIeVbe.real - yIcVbe.real, yIeVbe.imag - yIcVbe.imag); + } + *(inst->NBJTcolColPtr) += yIcVce.real; + *(inst->NBJTcolColPtr + 1) += yIcVce.imag; + *(inst->NBJTcolBasePtr) += yIcVbe.real; + *(inst->NBJTcolBasePtr + 1) += yIcVbe.imag; + *(inst->NBJTcolEmitPtr) -= yIcVbe.real + yIcVce.real; + *(inst->NBJTcolEmitPtr + 1) -= yIcVbe.imag + yIcVce.imag; + *(inst->NBJTbaseColPtr) -= yIcVce.real - yIeVce.real; + *(inst->NBJTbaseColPtr + 1) -= yIcVce.imag - yIeVce.imag; + *(inst->NBJTbaseBasePtr) -= yIcVbe.real - yIeVbe.real; + *(inst->NBJTbaseBasePtr + 1) -= yIcVbe.imag - yIeVbe.imag; + *(inst->NBJTbaseEmitPtr) += yIcVbe.real + yIcVce.real - yIeVbe.real - yIeVce.real; + *(inst->NBJTbaseEmitPtr + 1) += yIcVbe.imag + yIcVce.imag - yIeVbe.imag - yIeVce.imag; + *(inst->NBJTemitColPtr) -= yIeVce.real; + *(inst->NBJTemitColPtr + 1) -= yIeVce.imag; + *(inst->NBJTemitBasePtr) -= yIeVbe.real; + *(inst->NBJTemitBasePtr + 1) -= yIeVbe.imag; + *(inst->NBJTemitEmitPtr) += yIeVbe.real + yIeVce.real; + *(inst->NBJTemitEmitPtr + 1) += yIeVbe.imag + yIeVce.imag; + + inst->NBJTpDevice->pStats->totalTime[STAT_AC] += + SPfrontEnd->IFseconds() - startTime; + } + } + return (OK); +} diff --git a/src/spicelib/devices/nbjt/nbjtset.c b/src/spicelib/devices/nbjt/nbjtset.c new file mode 100644 index 000000000..349d1bce1 --- /dev/null +++ b/src/spicelib/devices/nbjt/nbjtset.c @@ -0,0 +1,255 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "cktdefs.h" +#include "smpdefs.h" +#include "nbjtdefs.h" +#include "numconst.h" +#include "numenum.h" +#include "sperror.h" +#include "../../../ciderlib/oned/onedext.h" +#include "cidersupt.h" +#include "ciderinp.h" +#include "suffix.h" + +#define NIL(type) ((type *)0) +#define TSCALLOC(var, size, type)\ +if (size && (!(var =(type *)calloc(1, (unsigned)(size)*sizeof(type))))) {\ + return(E_NOMEM);\ +} + +int +NBJTsetup(matrix, inModel, ckt, states) + register SMPmatrix *matrix; + GENmodel *inModel; + CKTcircuit *ckt; + int *states; +/* + * load the diode structure with those pointers needed later for fast matrix + * loading + */ +{ + register NBJTmodel *model = (NBJTmodel *) inModel; + register NBJTinstance *inst; + METHcard *methods; + MODLcard *models; + OPTNcard *options; + OUTPcard *outputs; + char *icFileName = NULL; + int nameLen; + int error; + int xMeshSize; + ONEdevice *pDevice; + ONEcoord *xCoordList = NIL(ONEcoord); + ONEdomain *domainList = NIL(ONEdomain); + DOPprofile *profileList = NIL(DOPprofile); + DOPtable *dopTableList = NIL(DOPtable); + ONEmaterial *pM, *pMaterial = NULL, *materialList = NIL(ONEmaterial); + double startTime; + + + /* loop through all the diode models */ + for (; model != NULL; model = model->NBJTnextModel) { + if (!model->NBJTpInfo) { + TSCALLOC(model->NBJTpInfo, 1, ONEtranInfo); + } + methods = model->NBJTmethods; + if (!methods) { + TSCALLOC(methods, 1, METHcard); + model->NBJTmethods = methods; + } + models = model->NBJTmodels; + if (!models) { + TSCALLOC(models, 1, MODLcard); + model->NBJTmodels = models; + } + options = model->NBJToptions; + if (!options) { + TSCALLOC(options, 1, OPTNcard); + model->NBJToptions = options; + } + outputs = model->NBJToutputs; + if (!outputs) { + TSCALLOC(outputs, 1, OUTPcard); + model->NBJToutputs = outputs; + } + if (!methods->METHvoltPredGiven) { + methods->METHvoltPred = FALSE; + } + if (!methods->METHmobDerivGiven) { + methods->METHmobDeriv = TRUE; + } + if (!methods->METHoneCarrierGiven) { + methods->METHoneCarrier = FALSE; + } + if (!methods->METHacAnalysisMethodGiven) { + methods->METHacAnalysisMethod = SOR; + } + if (!methods->METHdabstolGiven) { + methods->METHdabstol = DABSTOL1D; + } + if (!methods->METHdreltolGiven) { + methods->METHdreltol = ckt->CKTreltol; + } + if (!methods->METHitLimGiven) { + methods->METHitLim = 20; + } + if (!methods->METHomegaGiven || methods->METHomega <= 0.0) { + methods->METHomega = 2.0 * M_PI /* radians/sec */ ; + } + if (!options->OPTNdefaGiven || options->OPTNdefa <= 0.0) { + options->OPTNdefa = 1.0e4 /* cm^2 */ ; + } + if (!options->OPTNbaseLengthGiven) { + options->OPTNbaseLength = 0.0; + } + if (!options->OPTNbaseAreaGiven) { + options->OPTNbaseArea = 1.0; + } + if (!options->OPTNdeviceTypeGiven) { + options->OPTNdeviceType = OPTN_BIPOLAR; + } + if (!options->OPTNicFileGiven) { + options->OPTNicFile = NULL; + options->OPTNunique = FALSE; /* Can't form a unique name. */ + } + if (!options->OPTNuniqueGiven) { + options->OPTNunique = FALSE; + } + + /* Set up the rest of the card lists */ + if ((error = MODLsetup(model->NBJTmodels))) + return (error); + BandGapNarrowing = models->MODLbandGapNarrowing; + ConcDepLifetime = models->MODLconcDepLifetime; + TempDepMobility = models->MODLtempDepMobility; + ConcDepMobility = models->MODLconcDepMobility; + + if ((error = OUTPsetup(model->NBJToutputs))) + return (error); + if ((error = MATLsetup(model->NBJTmaterials, &materialList))) + return (error); + if ((error = MOBsetup(model->NBJTmobility, materialList))) + return (error); + if ((error = MESHsetup('x', model->NBJTxMeshes, &xCoordList, &xMeshSize))) + return (error); + if ((error = DOMNsetup(model->NBJTdomains, &domainList, + xCoordList, NIL(ONEcoord), materialList))) + return (error); + if ((error = BDRYsetup(model->NBJTboundaries, + xCoordList, NIL(ONEcoord), domainList))) + return (error); + if ((error = CONTsetup(model->NBJTcontacts, NULL))) + return (error); + if ((error = DOPsetup(model->NBJTdopings, &profileList, + &dopTableList, xCoordList, NIL(ONEcoord)))) + return (error); + model->NBJTmatlInfo = materialList; + model->NBJTprofiles = profileList; + model->NBJTdopTables = dopTableList; + + /* loop through all the instances of the model */ + for (inst = model->NBJTinstances; inst != NULL; + inst = inst->NBJTnextInstance) { + if (inst->NBJTowner != ARCHme) goto matrixpointers; + + startTime = SPfrontEnd->IFseconds(); + + if (!inst->NBJTprintGiven) { + inst->NBJTprint = 0; + } else if (inst->NBJTprint <= 0) { + inst->NBJTprint = 1; + } + if (!inst->NBJTicFileGiven) { + if (options->OPTNunique) { + nameLen = strlen(options->OPTNicFile) + strlen(inst->NBJTname) + 1; + TSCALLOC(icFileName, nameLen+1, char); + sprintf(icFileName, "%s.%s", options->OPTNicFile, inst->NBJTname); + icFileName[nameLen] = '\0'; + inst->NBJTicFile = icFileName; + } else if (options->OPTNicFile != NULL) { + nameLen = strlen(options->OPTNicFile); + TSCALLOC(icFileName, nameLen+1, char); + icFileName = strcpy(icFileName, options->OPTNicFile); + inst->NBJTicFile = icFileName; + } else { + inst->NBJTicFile = NULL; + } + } + inst->NBJTstate = *states; + *states += NBJTnumStates; + + if (!inst->NBJTpDevice) { + /* Assign the mesh info to each instance. */ + TSCALLOC(pDevice, 1, ONEdevice); + TSCALLOC(pDevice->pStats, 1, ONEstats); + pDevice->name = inst->NBJTname; + pDevice->solverType = SLV_NONE; + pDevice->numNodes = xMeshSize; + pDevice->abstol = methods->METHdabstol; + pDevice->reltol = methods->METHdreltol; + pDevice->rhsImag = NIL(double); + TSCALLOC(pDevice->elemArray, pDevice->numNodes, ONEelem *); + + /* Create a copy of material data that can change with temperature. */ + pDevice->pMaterials = NIL(ONEmaterial); + for (pM = materialList; pM != NIL(ONEmaterial); pM = pM->next) { + if (pDevice->pMaterials == NIL(ONEmaterial)) { + TSCALLOC(pMaterial, 1, ONEmaterial); + pDevice->pMaterials = pMaterial; + } else { + TSCALLOC(pMaterial->next, 1, ONEmaterial); + pMaterial = pMaterial->next; + } + /* Copy everything, then fix the incorrect pointer. */ + bcopy((char *) pM, (char *) pMaterial, sizeof(ONEmaterial)); + pMaterial->next = NIL(ONEmaterial); + } + + /* generate the mesh structure for the device */ + ONEbuildMesh(pDevice, xCoordList, domainList, pDevice->pMaterials); + + if (options->OPTNbaseDepthGiven) { + /* The base contact depth has been specified in the input. */ + pDevice->baseIndex = MESHlocate(xCoordList, options->OPTNbaseDepth); + } else { + pDevice->baseIndex = -1; /* Invalid index acts as a flag */ + } + /* store the device info in the instance */ + inst->NBJTpDevice = pDevice; + } + /* Now update the state pointers. */ + ONEgetStatePointers(inst->NBJTpDevice, states); + + /* Wipe out statistics from previous runs (if any). */ + bzero((char *) inst->NBJTpDevice->pStats, sizeof(ONEstats)); + + inst->NBJTpDevice->pStats->totalTime[STAT_SETUP] += + SPfrontEnd->IFseconds() - startTime; + + /* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if ((inst->ptr = SMPmakeElt(matrix,inst->first,inst->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + +matrixpointers: + TSTALLOC(NBJTcolColPtr, NBJTcolNode, NBJTcolNode) + TSTALLOC(NBJTbaseBasePtr, NBJTbaseNode, NBJTbaseNode) + TSTALLOC(NBJTemitEmitPtr, NBJTemitNode, NBJTemitNode) + TSTALLOC(NBJTcolBasePtr, NBJTcolNode, NBJTbaseNode) + TSTALLOC(NBJTcolEmitPtr, NBJTcolNode, NBJTemitNode) + TSTALLOC(NBJTbaseColPtr, NBJTbaseNode, NBJTcolNode) + TSTALLOC(NBJTbaseEmitPtr, NBJTbaseNode, NBJTemitNode) + TSTALLOC(NBJTemitColPtr, NBJTemitNode, NBJTcolNode) + TSTALLOC(NBJTemitBasePtr, NBJTemitNode, NBJTbaseNode) + } + /* Clean up lists */ + killCoordInfo(xCoordList); + killDomainInfo(domainList); + } + return (OK); +} diff --git a/src/spicelib/devices/nbjt/nbjttemp.c b/src/spicelib/devices/nbjt/nbjttemp.c new file mode 100644 index 000000000..63e12c5aa --- /dev/null +++ b/src/spicelib/devices/nbjt/nbjttemp.c @@ -0,0 +1,160 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +Author: 1992 David A. Gates, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "cktdefs.h" +#include "nbjtdefs.h" +#include "numenum.h" +#include "carddefs.h" +#include "sperror.h" +#include "../../../ciderlib/oned/onedext.h" +#include "cidersupt.h" +#include "suffix.h" + +#define NIL(type) ((type *)0) +extern int ONEdcDebug; +extern double LNorm; + +int +NBJTtemp(inModel, ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +/* + * perform the temperature update to the bjt + */ +{ + register NBJTmodel *model = (NBJTmodel *) inModel; + register NBJTinstance *inst; + METHcard *methods; + MODLcard *models; + OPTNcard *options; + OUTPcard *outputs; + ONEmaterial *pM, *pMaterial, *pNextMaterial; + ONEdevice *pDevice; + double startTime; + int baseIndex, indexBE, indexBC; + + + /* loop through all the bjt models */ + for (; model != NULL; model = model->NBJTnextModel) { + methods = model->NBJTmethods; + models = model->NBJTmodels; + options = model->NBJToptions; + outputs = model->NBJToutputs; + + if (!options->OPTNtnomGiven) { + options->OPTNtnom = ckt->CKTnomTemp; + } + for (pM = model->NBJTmatlInfo; pM != NIL(ONEmaterial); pM = pM->next) { + pM->tnom = options->OPTNtnom; + } + + BandGapNarrowing = models->MODLbandGapNarrowing; + ConcDepLifetime = models->MODLconcDepLifetime; + TempDepMobility = models->MODLtempDepMobility; + ConcDepMobility = models->MODLconcDepMobility; + + for (inst = model->NBJTinstances; inst != NULL; + inst = inst->NBJTnextInstance) { + if (inst->NBJTowner != ARCHme) continue; + + startTime = SPfrontEnd->IFseconds(); + + if (!inst->NBJTtempGiven) { + inst->NBJTtemp = ckt->CKTtemp; + } + if (!inst->NBJTareaGiven || inst->NBJTarea <= 0.0) { + inst->NBJTarea = 1.0; + } + inst->NBJTpDevice->area = inst->NBJTarea * options->OPTNdefa; + + /* Compute and save globals for this instance. */ + GLOBcomputeGlobals(&(inst->NBJTglobals), inst->NBJTtemp); + + /* Calculate new sets of material parameters. */ + pM = model->NBJTmatlInfo; + pMaterial = inst->NBJTpDevice->pMaterials; + for (; pM != NULL; pM = pM->next, pMaterial = pMaterial->next) { + + /* Copy the original values, then fix the incorrect pointer. */ + pNextMaterial = pMaterial->next; + bcopy((char *) pM, (char *) pMaterial, sizeof(ONEmaterial)); + pMaterial->next = pNextMaterial; + + /* Now do the temperature dependence. */ + MATLtempDep(pMaterial, pMaterial->tnom); + if (outputs->OUTPmaterial) { + printMaterialInfo(pMaterial); + } + } + + /* Assign doping to the mesh. */ + ONEsetDoping(inst->NBJTpDevice, model->NBJTprofiles, + model->NBJTdopTables); + + /* Assign other physical parameters to the mesh. */ + ONEsetup(inst->NBJTpDevice); + + /* Assign boundary condition parameters. */ + ONEsetBCparams(inst->NBJTpDevice, model->NBJTboundaries, + model->NBJTcontacts); + + /* Normalize everything. */ + ONEnormalize(inst->NBJTpDevice); + + /* Find the device's type. */ + if (inst->NBJTpDevice->elemArray[1]->pNodes[0]->netConc < 0.0) { + inst->NBJTtype = PNP; + } else { + inst->NBJTtype = NPN; + } + + /* Find the location of the base index. */ + pDevice = inst->NBJTpDevice; + baseIndex = pDevice->baseIndex; + if (baseIndex <= 0) { + if (options->OPTNbaseDepthGiven) { + printf("Warning: base contact not on node -- adjusting contact\n"); + } + NBJTjunctions(pDevice, &indexBE, &indexBC); + pDevice->baseIndex = 0.5 * (indexBE + indexBC); + } + if (inst->NBJTtype == PNP) { + pDevice->elemArray[pDevice->baseIndex]->pNodes[0]->baseType = N_TYPE; + } else if (inst->NBJTtype == NPN) { + pDevice->elemArray[pDevice->baseIndex]->pNodes[0]->baseType = P_TYPE; + } else { + printf("NBJTtemp: unknown BJT type \n"); + } + if (baseIndex <= 0 && !options->OPTNbaseDepthGiven) { + ONEdcDebug = FALSE; + ONEequilSolve(pDevice); + adjustBaseContact(pDevice, indexBE, indexBC); + } + printf("BJT: base contact depth is %g um at node %d\n", + pDevice->elemArray[pDevice->baseIndex]->pNodes[0]->x * 1e4, + pDevice->baseIndex); + + /* Find, normalize and convert to reciprocal-form the base length. */ + pDevice->baseLength = options->OPTNbaseLength; + if (pDevice->baseLength > 0.0) { + pDevice->baseLength /= LNorm; + pDevice->baseLength = 1.0 / pDevice->baseLength; + } else if (pDevice->elemArray[pDevice->baseIndex]->evalNodes[0]) { + pDevice->baseLength = pDevice->elemArray[pDevice->baseIndex]->rDx; + } else { + pDevice->baseLength = pDevice->elemArray[pDevice->baseIndex - 1]->rDx; + } + /* Adjust reciprocal base length to account for base area factor */ + pDevice->baseLength *= options->OPTNbaseArea; + + inst->NBJTpDevice->pStats->totalTime[STAT_SETUP] += + SPfrontEnd->IFseconds() - startTime; + + } + } + return (OK); +} diff --git a/src/spicelib/devices/nbjt/nbjttrun.c b/src/spicelib/devices/nbjt/nbjttrun.c new file mode 100644 index 000000000..da6220a7f --- /dev/null +++ b/src/spicelib/devices/nbjt/nbjttrun.c @@ -0,0 +1,54 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This routine performs truncation error calculations for NBJTs in the + * circuit. + */ + +#include "ngspice.h" +#include "cktdefs.h" +#include "nbjtdefs.h" +#include "sperror.h" +#include "../../../ciderlib/oned/onedext.h" +#include "cidersupt.h" +#include "suffix.h" + + +int +NBJTtrunc(inModel, ckt, timeStep) + GENmodel *inModel; + register CKTcircuit *ckt; + double *timeStep; + +{ + register NBJTmodel *model = (NBJTmodel *) inModel; + register NBJTinstance *inst; + double deltaNew; + double deltaNorm[7]; + double startTime; + int i; + + for (i = 0; i <= ckt->CKTmaxOrder; i++) { + deltaNorm[i] = ckt->CKTdeltaOld[i] / TNorm; + } + for (; model != NULL; model = model->NBJTnextModel) { + model->NBJTpInfo->order = ckt->CKTorder; + model->NBJTpInfo->delta = deltaNorm; + model->NBJTpInfo->lteCoeff = computeLTECoeff(model->NBJTpInfo); + for (inst = model->NBJTinstances; inst != NULL; + inst = inst->NBJTnextInstance) { + if (inst->NBJTowner != ARCHme) continue; + + startTime = SPfrontEnd->IFseconds(); + deltaNew = ONEtrunc(inst->NBJTpDevice, model->NBJTpInfo, + ckt->CKTdelta); + *timeStep = MIN(*timeStep, deltaNew); + inst->NBJTpDevice->pStats->totalTime[STAT_TRAN] += + SPfrontEnd->IFseconds() - startTime; + } + } + return (OK); +} diff --git a/src/spicelib/devices/nbjt2/Makefile.am b/src/spicelib/devices/nbjt2/Makefile.am new file mode 100644 index 000000000..74bf4a7bf --- /dev/null +++ b/src/spicelib/devices/nbjt2/Makefile.am @@ -0,0 +1,30 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libnbjt2.a + +libnbjt2_a_SOURCES = \ + nbt2.c \ + nbt2acld.c \ + nbt2ask.c \ + nbjt2defs.h \ + nbt2del.c \ + nbt2dest.c \ + nbt2dump.c \ + nbjt2ext.h \ + nbt2init.c \ + nbt2init.h \ + nbjt2itf.h \ + nbt2load.c \ + nbt2mdel.c \ + nbt2mpar.c \ + nbt2parm.c \ + nbt2pzld.c \ + nbt2set.c \ + nbt2temp.c \ + nbt2trun.c + + + +INCLUDES = -I$(top_srcdir)/src/include + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/nbjt2/nbjt2def.h b/src/spicelib/devices/nbjt2/nbjt2def.h new file mode 100644 index 000000000..0d151e1f2 --- /dev/null +++ b/src/spicelib/devices/nbjt2/nbjt2def.h @@ -0,0 +1,170 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +Authors: 1987 Karti Mayaram, 1991 David Gates +**********/ + +#ifndef NBJT2_H +#define NBJT2_H "NBJT2defs.h $Revision$ on $Date$ " + +/* structures to describe 2d Numerical Bipolar Junction Transistors */ + +/* circuit level includes */ +#include "ifsim.h" +#include "cktdefs.h" +#include "gendefs.h" + +/* device level includes */ +#include "twomesh.h" +#include "twodev.h" +#include "profile.h" +#include "numglobs.h" +#include "carddefs.h" + +/* information needed per instance */ +typedef struct sNBJT2instance { + struct sNBJT2model *NBJT2modPtr; /* back pointer to model */ + struct sNBJT2instance *NBJT2nextInstance; /* pointer to next instance + * of current model */ + IFuid NBJT2name; /* pointer to character string naming this + * instance */ + int NBJT2owner; /* number of owner process */ + int NBJT2state; /* pointer to start of state vector for bjt */ + + /* entries in the state vector for bjt: */ +#define NBJT2vbe NBJT2state +#define NBJT2vce NBJT2state+1 +#define NBJT2ic NBJT2state+2 +#define NBJT2ie NBJT2state+3 +#define NBJT2dIeDVce NBJT2state+4 +#define NBJT2dIeDVbe NBJT2state+5 +#define NBJT2dIcDVce NBJT2state+6 +#define NBJT2dIcDVbe NBJT2state+7 +#define NBJT2numStates 8 + + int NBJT2colNode; /* number of collector node of bjt */ + int NBJT2baseNode; /* number of base node of bjt */ + int NBJT2emitNode; /* number of emitter node of bjt */ + double NBJT2width; /* width factor for the bjt */ + double NBJT2area; /* area factor for the bjt */ + TWOdevice *NBJT2pDevice; + GLOBvalues NBJT2globals; /* Temp.-Dep. Global Parameters */ + int NBJT2type; + double NBJT2temp; /* Instance Temperature */ + double NBJT2c11; /* small-signal capacitance */ + double NBJT2y11r; /* small-signal admittance, real part */ + double NBJT2y11i; /* small-signal admittance, imag part */ + double NBJT2c12; /* small-signal capacitance */ + double NBJT2y12r; /* small-signal admittance, real part */ + double NBJT2y12i; /* small-signal admittance, imag part */ + double NBJT2c21; /* small-signal capacitance */ + double NBJT2y21r; /* small-signal admittance, real part */ + double NBJT2y21i; /* small-signal admittance, imag part */ + double NBJT2c22; /* small-signal capacitance */ + double NBJT2y22r; /* small-signal admittance, real part */ + double NBJT2y22i; /* small-signal admittance, imag part */ + int NBJT2print; + char *NBJT2icFile; /* Name of initial condition file */ + double *NBJT2colColPtr; /* pointer to sparse matrix at + * (collector,collector) */ + double *NBJT2baseBasePtr; /* pointer to sparse matrix at (base,base) */ + double *NBJT2emitEmitPtr; /* pointer to sparse matrix at + * (emitter,emitter) */ + double *NBJT2colBasePtr; /* pointer to sparse matrix at + * (collector,base) */ + double *NBJT2colEmitPtr; /* pointer to sparse matrix at + * (collector,emitter) */ + double *NBJT2baseColPtr; /* pointer to sparse matrix at + * (base,collector) */ + double *NBJT2baseEmitPtr; /* pointer to sparse matrix at (base,emitter) */ + double *NBJT2emitColPtr; /* pointer to sparse matrix at + * (emitter,collector) */ + double *NBJT2emitBasePtr; /* pointer to sparse matrix at (emitter,base) */ + int NBJT2off; /* 'off' flag for bjt */ + unsigned NBJT2smSigAvail:1; /* flag to indicate small-signal done */ + unsigned NBJT2widthGiven:1; /* flag to indicate width was specified */ + unsigned NBJT2areaGiven:1; /* flag to indicate area was specified */ + unsigned NBJT2icFileGiven:1; /* flag to indicate init. cond. file given */ + unsigned NBJT2printGiven:1; /* flag to indicate print given */ + unsigned NBJT2tempGiven:1; /* flag to indicate temp given */ +} NBJT2instance; + +/* per model data */ +typedef struct sNBJT2model { /* model structure for a bjt */ + int NBJT2modType; /* type index of this device type */ + struct sNBJT2model *NBJT2nextModel; /* pointer to next possible model in + * linked list */ + NBJT2instance *NBJT2instances;/* pointer to list of instances that have + * this model */ + IFuid NBJT2modName; /* pointer to character string naming this + * model */ + /* Everything below here is numerical-device-specific */ + MESHcard *NBJT2xMeshes; /* list of xmesh cards */ + MESHcard *NBJT2yMeshes; /* list of ymesh cards */ + DOMNcard *NBJT2domains; /* list of domain cards */ + BDRYcard *NBJT2boundaries; /* list of boundary cards */ + DOPcard *NBJT2dopings; /* list of doping cards */ + ELCTcard *NBJT2electrodes; /* list of electrode cards */ + CONTcard *NBJT2contacts; /* list of contact cards */ + MODLcard *NBJT2models; /* list of model cards */ + MATLcard *NBJT2materials; /* list of material cards */ + MOBcard *NBJT2mobility; /* list of mobility cards */ + METHcard *NBJT2methods; /* list of method cards */ + OPTNcard *NBJT2options; /* list of option cards */ + OUTPcard *NBJT2outputs; /* list of output cards */ + TWOtranInfo *NBJT2pInfo; /* transient analysis information */ + DOPprofile *NBJT2profiles; /* expanded list of doping profiles */ + DOPtable *NBJT2dopTables; /* list of tables used by profiles */ + TWOmaterial *NBJT2matlInfo; /* list of material info structures */ +} NBJT2model; + +/* type of 2D BJT */ +#define NPN 1 +#define PNP -1 + +/* device parameters */ +#define NBJT2_WIDTH 1 +#define NBJT2_AREA 2 +#define NBJT2_OFF 3 +#define NBJT2_IC_FILE 4 +#define NBJT2_PRINT 7 +#define NBJT2_TEMP 8 + +#define NBJT2_G11 9 +#define NBJT2_C11 10 +#define NBJT2_Y11 11 +#define NBJT2_G12 12 +#define NBJT2_C12 13 +#define NBJT2_Y12 14 +#define NBJT2_G13 15 +#define NBJT2_C13 16 +#define NBJT2_Y13 17 +#define NBJT2_G21 18 +#define NBJT2_C21 19 +#define NBJT2_Y21 20 +#define NBJT2_G22 21 +#define NBJT2_C22 22 +#define NBJT2_Y22 23 +#define NBJT2_G23 24 +#define NBJT2_C23 25 +#define NBJT2_Y23 26 +#define NBJT2_G31 27 +#define NBJT2_C31 28 +#define NBJT2_Y31 29 +#define NBJT2_G32 30 +#define NBJT2_C32 31 +#define NBJT2_Y32 32 +#define NBJT2_G33 33 +#define NBJT2_C33 34 +#define NBJT2_Y33 35 + +/* model parameters */ +/* NOTE: all true model parameters have been moved to IFcardInfo structures */ +#define NBJT2_MOD_NBJT 1 + +/* device questions */ + +/* model questions */ + +#include "nbjt2ext.h" + +#endif /* NBJT2_H */ diff --git a/src/spicelib/devices/nbjt2/nbjt2ext.h b/src/spicelib/devices/nbjt2/nbjt2ext.h new file mode 100644 index 000000000..7448e637d --- /dev/null +++ b/src/spicelib/devices/nbjt2/nbjt2ext.h @@ -0,0 +1,27 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Karti Mayaram +**********/ + +#ifndef NBJT2EXT_H +#define NBJT2EXT_H + + +extern int NBJT2acLoad(GENmodel *, CKTcircuit *); +extern int NBJT2ask(CKTcircuit *, GENinstance *, int, IFvalue *, IFvalue *); +extern int NBJT2delete(GENmodel *, IFuid, GENinstance **); +extern void NBJT2destroy(GENmodel **); +extern int NBJT2getic(GENmodel *, CKTcircuit *); +extern int NBJT2load(GENmodel *, CKTcircuit *); +extern int NBJT2mDelete(GENmodel **, IFuid, GENmodel *); +extern int NBJT2mParam(int, IFvalue *, GENmodel *); +extern int NBJT2param(int, IFvalue *, GENinstance *, IFvalue *); +extern int NBJT2pzLoad(GENmodel *, CKTcircuit *, SPcomplex *); +extern int NBJT2setup(SMPmatrix *, GENmodel *, CKTcircuit *, int *); +extern int NBJT2temp(GENmodel *, CKTcircuit *); +extern int NBJT2trunc(GENmodel *, CKTcircuit *, double *); + +extern void NBJT2dump(GENmodel *, CKTcircuit *); +extern void NBJT2acct(GENmodel *, CKTcircuit *, FILE *); + +#endif /* NBJT2EXT_H */ diff --git a/src/spicelib/devices/nbjt2/nbjt2itf.h b/src/spicelib/devices/nbjt2/nbjt2itf.h new file mode 100644 index 000000000..73eda8397 --- /dev/null +++ b/src/spicelib/devices/nbjt2/nbjt2itf.h @@ -0,0 +1,10 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +**********/ + +#ifndef DEV_NBJT2 +#define DEV_NBJT2 + +extern SPICEdev *get_nbjt2_info(void); + +#endif diff --git a/src/spicelib/devices/nbjt2/nbt2.c b/src/spicelib/devices/nbjt2/nbt2.c new file mode 100644 index 000000000..68f2cddfa --- /dev/null +++ b/src/spicelib/devices/nbjt2/nbt2.c @@ -0,0 +1,71 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "devdefs.h" +#include "nbjt2def.h" +#include "suffix.h" + +/* + * This file defines the 2d Numerical BJT data structures that are available + * to the next level(s) up the calling hierarchy + */ + +IFparm NBJT2pTable[] = { /* parameters */ + IP("off", NBJT2_OFF, IF_FLAG, "Device initially off"), + IP("ic.file", NBJT2_IC_FILE, IF_STRING, "Initial condition file"), + IOP("w", NBJT2_WIDTH, IF_REAL, "Width factor"), + IOP("area", NBJT2_AREA, IF_REAL, "Area factor"), + IP("save", NBJT2_PRINT, IF_REAL, "Save solutions"), + IP("print", NBJT2_PRINT, IF_REAL, "Print solutions"), + OP("g11", NBJT2_G11, IF_REAL, "Conductance"), + OP("c11", NBJT2_C11, IF_REAL, "Capacitance"), + OP("y11", NBJT2_Y11, IF_COMPLEX, "Admittance"), + OP("g12", NBJT2_G12, IF_REAL, "Conductance"), + OP("c12", NBJT2_C12, IF_REAL, "Capacitance"), + OP("y12", NBJT2_Y12, IF_COMPLEX, "Admittance"), + OPU("g13", NBJT2_G13, IF_REAL, "Conductance"), + OPU("c13", NBJT2_C13, IF_REAL, "Capacitance"), + OPU("y13", NBJT2_Y13, IF_COMPLEX, "Admittance"), + OP("g21", NBJT2_G21, IF_REAL, "Conductance"), + OP("c21", NBJT2_C21, IF_REAL, "Capacitance"), + OP("y21", NBJT2_Y21, IF_COMPLEX, "Admittance"), + OP("g22", NBJT2_G22, IF_REAL, "Conductance"), + OP("c22", NBJT2_C22, IF_REAL, "Capacitance"), + OP("y22", NBJT2_Y22, IF_COMPLEX, "Admittance"), + OPU("g23", NBJT2_G23, IF_REAL, "Conductance"), + OPU("c23", NBJT2_C23, IF_REAL, "Capacitance"), + OPU("y23", NBJT2_Y23, IF_COMPLEX, "Admittance"), + OPU("g31", NBJT2_G31, IF_REAL, "Conductance"), + OPU("c31", NBJT2_C31, IF_REAL, "Capacitance"), + OPU("y31", NBJT2_Y31, IF_COMPLEX, "Admittance"), + OPU("g32", NBJT2_G32, IF_REAL, "Conductance"), + OPU("c32", NBJT2_C32, IF_REAL, "Capacitance"), + OPU("y32", NBJT2_Y32, IF_COMPLEX, "Admittance"), + OPU("g33", NBJT2_G33, IF_REAL, "Conductance"), + OPU("c33", NBJT2_C33, IF_REAL, "Capacitance"), + OPU("y33", NBJT2_Y33, IF_COMPLEX, "Admittance"), + IOP("temp", NBJT2_TEMP, IF_REAL, "Instance Temperature") +}; + +IFparm NBJT2mPTable[] = { /* model parameters */ + /* numerical-device models no longer have parameters */ + /* one is left behind to keep the table from being empty */ + IP("nbjt", NBJT2_MOD_NBJT, IF_FLAG, "Numerical BJT Model") +}; + + +char *NBJT2names[] = { + "Collector", + "Base", + "Emitter", + "Substrate" +}; + +int NBJT2nSize = NUMELEMS(NBJT2names); +int NBJT2pTSize = NUMELEMS(NBJT2pTable); +int NBJT2mPTSize = NUMELEMS(NBJT2mPTable); +int NBJT2iSize = sizeof(NBJT2instance); +int NBJT2mSize = sizeof(NBJT2model); diff --git a/src/spicelib/devices/nbjt2/nbt2acld.c b/src/spicelib/devices/nbjt2/nbt2acld.c new file mode 100644 index 000000000..90946423a --- /dev/null +++ b/src/spicelib/devices/nbjt2/nbt2acld.c @@ -0,0 +1,103 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * Function to load the COMPLEX circuit matrix using the small signal + * parameters saved during a previous DC operating point analysis. + */ + +#include "ngspice.h" +#include "cktdefs.h" +#include "nbjt2def.h" +#include "sperror.h" +#include "complex.h" +#include "../../../ciderlib/twod/twoddefs.h" +#include "../../../ciderlib/twod/twodext.h" +#include "cidersupt.h" +#include "suffix.h" + +/* External Declarations */ +extern int TWOacDebug; + +int +NBJT2acLoad(inModel, ckt) + GENmodel *inModel; + CKTcircuit *ckt; + +{ + register NBJT2model *model = (NBJT2model *) inModel; + register NBJT2instance *inst; + SPcomplex yIeVce, yIeVbe; + SPcomplex yIcVce, yIcVbe; + double startTime; + + for (; model != NULL; model = model->NBJT2nextModel) { + FieldDepMobility = model->NBJT2models->MODLfieldDepMobility; + TransDepMobility = model->NBJT2models->MODLtransDepMobility; + SurfaceMobility = model->NBJT2models->MODLsurfaceMobility; + Srh = model->NBJT2models->MODLsrh; + Auger = model->NBJT2models->MODLauger; + AvalancheGen = model->NBJT2models->MODLavalancheGen; + OneCarrier = model->NBJT2methods->METHoneCarrier; + AcAnalysisMethod = model->NBJT2methods->METHacAnalysisMethod; + MobDeriv = model->NBJT2methods->METHmobDeriv; + TWOacDebug = model->NBJT2outputs->OUTPacDebug; + + for (inst = model->NBJT2instances; inst != NULL; + inst = inst->NBJT2nextInstance) { + if (inst->NBJT2owner != ARCHme) continue; + + startTime = SPfrontEnd->IFseconds(); + /* Get Temp.-Dep. Global Parameters */ + GLOBgetGlobals(&(inst->NBJT2globals)); + + model->NBJT2methods->METHacAnalysisMethod = + NBJT2admittance(inst->NBJT2pDevice, ckt->CKTomega, + &yIeVce, &yIcVce, &yIeVbe, &yIcVbe); + + *(inst->NBJT2colColPtr) += yIcVce.real; + *(inst->NBJT2colColPtr + 1) += yIcVce.imag; + *(inst->NBJT2colBasePtr) += yIcVbe.real; + *(inst->NBJT2colBasePtr + 1) += yIcVbe.imag; + *(inst->NBJT2colEmitPtr) -= yIcVbe.real + yIcVce.real; + *(inst->NBJT2colEmitPtr + 1) -= yIcVbe.imag + yIcVce.imag; + *(inst->NBJT2baseColPtr) -= yIcVce.real + yIeVce.real; + *(inst->NBJT2baseColPtr + 1) -= yIcVce.imag + yIeVce.imag; + *(inst->NBJT2baseBasePtr) -= yIcVbe.real + yIeVbe.real; + *(inst->NBJT2baseBasePtr + 1) -= yIcVbe.imag + yIeVbe.imag; + *(inst->NBJT2baseEmitPtr) += yIcVbe.real + yIcVce.real + yIeVbe.real + yIeVce.real; + *(inst->NBJT2baseEmitPtr + 1) += yIcVbe.imag + yIcVce.imag + yIeVbe.imag + yIeVce.imag; + *(inst->NBJT2emitColPtr) += yIeVce.real; + *(inst->NBJT2emitColPtr + 1) += yIeVce.imag; + *(inst->NBJT2emitBasePtr) += yIeVbe.real; + *(inst->NBJT2emitBasePtr + 1) += yIeVbe.imag; + *(inst->NBJT2emitEmitPtr) -= yIeVbe.real + yIeVce.real; + *(inst->NBJT2emitEmitPtr + 1) -= yIeVbe.imag + yIeVce.imag; + if (ckt->CKTomega != 0.0) { + inst->NBJT2c11 = yIcVce.imag / ckt->CKTomega; + inst->NBJT2c12 = yIcVbe.imag / ckt->CKTomega; + inst->NBJT2c21 = (yIeVce.imag - yIcVce.imag) / ckt->CKTomega; + inst->NBJT2c22 = (yIeVbe.imag - yIcVbe.imag) / ckt->CKTomega; + } else { + inst->NBJT2c11 = 0.0; /* XXX What else can be done?! */ + inst->NBJT2c12 = 0.0; /* XXX What else can be done?! */ + inst->NBJT2c21 = 0.0; /* XXX What else can be done?! */ + inst->NBJT2c22 = 0.0; /* XXX What else can be done?! */ + } + inst->NBJT2y11r = yIcVce.real; + inst->NBJT2y11i = yIcVce.imag; + inst->NBJT2y12r = yIcVbe.real; + inst->NBJT2y12i = yIcVbe.imag; + inst->NBJT2y21r = yIeVce.real - yIcVce.real; + inst->NBJT2y21i = yIeVce.imag - yIcVce.imag; + inst->NBJT2y22r = yIeVbe.real - yIcVbe.real; + inst->NBJT2y22i = yIeVbe.imag - yIcVbe.imag; + inst->NBJT2smSigAvail = TRUE; + inst->NBJT2pDevice->pStats->totalTime[STAT_AC] += + SPfrontEnd->IFseconds() - startTime; + } + } + return (OK); +} diff --git a/src/spicelib/devices/nbjt2/nbt2ask.c b/src/spicelib/devices/nbjt2/nbt2ask.c new file mode 100644 index 000000000..4c5012aef --- /dev/null +++ b/src/spicelib/devices/nbjt2/nbt2ask.c @@ -0,0 +1,216 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include "const.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "nbjt2def.h" +#include "sperror.h" +#include "suffix.h" + + +/* Check out this one */ +extern int NBJT2initSmSig(NBJT2instance *); + + +/* ARGSUSED */ +int +NBJT2ask(ckt, inInst, which, value, select) + CKTcircuit *ckt; + GENinstance *inInst; + int which; + IFvalue *value; + IFvalue *select; +{ + NBJT2instance *inst = (NBJT2instance *) inInst; + switch (which) { + case NBJT2_WIDTH: + value->rValue = inst->NBJT2width; + return (OK); + case NBJT2_AREA: + value->rValue = inst->NBJT2area; + return (OK); + case NBJT2_TEMP: + value->rValue = inst->NBJT2temp - CONSTCtoK; + return (OK); + case NBJT2_G11: + value->rValue = *(ckt->CKTstate0 + inst->NBJT2dIcDVce); + return (OK); + case NBJT2_G12: + value->rValue = *(ckt->CKTstate0 + inst->NBJT2dIcDVbe); + return (OK); + case NBJT2_G13: + value->rValue = -*(ckt->CKTstate0 + inst->NBJT2dIcDVce) + - *(ckt->CKTstate0 + inst->NBJT2dIcDVbe); + return (OK); + case NBJT2_G21: + value->rValue = *(ckt->CKTstate0 + inst->NBJT2dIeDVce) + - *(ckt->CKTstate0 + inst->NBJT2dIcDVce); + return (OK); + case NBJT2_G22: + value->rValue = *(ckt->CKTstate0 + inst->NBJT2dIeDVbe) + - *(ckt->CKTstate0 + inst->NBJT2dIcDVbe); + return (OK); + case NBJT2_G23: + value->rValue = -*(ckt->CKTstate0 + inst->NBJT2dIeDVce) + + *(ckt->CKTstate0 + inst->NBJT2dIcDVce) + -*(ckt->CKTstate0 + inst->NBJT2dIeDVbe) + + *(ckt->CKTstate0 + inst->NBJT2dIcDVbe); + return (OK); + case NBJT2_G31: + value->rValue = -*(ckt->CKTstate0 + inst->NBJT2dIeDVce); + return (OK); + case NBJT2_G32: + value->rValue = -*(ckt->CKTstate0 + inst->NBJT2dIeDVbe); + return (OK); + case NBJT2_G33: + value->rValue = *(ckt->CKTstate0 + inst->NBJT2dIeDVce) + + *(ckt->CKTstate0 + inst->NBJT2dIeDVbe); + return (OK); + case NBJT2_C11: + if (!inst->NBJT2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJT2initSmSig(inst); + } + value->rValue = inst->NBJT2c11; + return (OK); + case NBJT2_C12: + if (!inst->NBJT2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJT2initSmSig(inst); + } + value->rValue = inst->NBJT2c12; + return (OK); + case NBJT2_C13: + if (!inst->NBJT2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJT2initSmSig(inst); + } + value->rValue = -inst->NBJT2c11 - inst->NBJT2c12; + return (OK); + case NBJT2_C21: + if (!inst->NBJT2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJT2initSmSig(inst); + } + value->rValue = inst->NBJT2c21; + return (OK); + case NBJT2_C22: + if (!inst->NBJT2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJT2initSmSig(inst); + } + value->rValue = inst->NBJT2c22; + return (OK); + case NBJT2_C23: + if (!inst->NBJT2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJT2initSmSig(inst); + } + value->rValue = -inst->NBJT2c21 - inst->NBJT2c22; + return (OK); + case NBJT2_C31: + if (!inst->NBJT2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJT2initSmSig(inst); + } + value->rValue = -inst->NBJT2c11 - inst->NBJT2c21; + return (OK); + case NBJT2_C32: + if (!inst->NBJT2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJT2initSmSig(inst); + } + value->rValue = -inst->NBJT2c12 - inst->NBJT2c22; + return (OK); + case NBJT2_C33: + if (!inst->NBJT2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJT2initSmSig(inst); + } + value->rValue = inst->NBJT2c11 + inst->NBJT2c21 + + inst->NBJT2c12 + inst->NBJT2c22; + return (OK); + case NBJT2_Y11: + if (!inst->NBJT2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJT2initSmSig(inst); + } + value->cValue.real = inst->NBJT2y11r; + value->cValue.imag = inst->NBJT2y11i; + return (OK); + case NBJT2_Y12: + if (!inst->NBJT2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJT2initSmSig(inst); + } + value->cValue.real = inst->NBJT2y12r; + value->cValue.imag = inst->NBJT2y12i; + return (OK); + case NBJT2_Y13: + if (!inst->NBJT2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJT2initSmSig(inst); + } + value->cValue.real = -inst->NBJT2y11r - inst->NBJT2y12r; + value->cValue.imag = -inst->NBJT2y11i - inst->NBJT2y12i; + return (OK); + case NBJT2_Y21: + if (!inst->NBJT2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJT2initSmSig(inst); + } + value->cValue.real = inst->NBJT2y21r; + value->cValue.imag = inst->NBJT2y21i; + return (OK); + case NBJT2_Y22: + if (!inst->NBJT2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJT2initSmSig(inst); + } + value->cValue.real = inst->NBJT2y22r; + value->cValue.imag = inst->NBJT2y22i; + return (OK); + case NBJT2_Y23: + if (!inst->NBJT2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJT2initSmSig(inst); + } + value->cValue.real = -inst->NBJT2y21r - inst->NBJT2y22r; + value->cValue.imag = -inst->NBJT2y21i - inst->NBJT2y22i; + return (OK); + case NBJT2_Y31: + if (!inst->NBJT2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJT2initSmSig(inst); + } + value->cValue.real = -inst->NBJT2y11r - inst->NBJT2y21r; + value->cValue.imag = -inst->NBJT2y11i - inst->NBJT2y21i; + return (OK); + case NBJT2_Y32: + if (!inst->NBJT2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJT2initSmSig(inst); + } + value->cValue.real = -inst->NBJT2y12r - inst->NBJT2y22r; + value->cValue.imag = -inst->NBJT2y12i - inst->NBJT2y22i; + return (OK); + case NBJT2_Y33: + if (!inst->NBJT2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NBJT2initSmSig(inst); + } + value->cValue.real = inst->NBJT2y11r + inst->NBJT2y21r + + inst->NBJT2y12r + inst->NBJT2y22r; + value->cValue.imag = inst->NBJT2y11i + inst->NBJT2y21i + + inst->NBJT2y12i + inst->NBJT2y22i; + return (OK); + default: + return (E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/nbjt2/nbt2del.c b/src/spicelib/devices/nbjt2/nbt2del.c new file mode 100644 index 000000000..6659f7e1c --- /dev/null +++ b/src/spicelib/devices/nbjt2/nbt2del.c @@ -0,0 +1,41 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This routine deletes a NBJT2 instance from the circuit and frees the + * storage it was using. + */ + +#include "ngspice.h" +#include "nbjt2def.h" +#include "sperror.h" +#include "suffix.h" + +int +NBJT2delete(inModel, name, kill) + GENmodel *inModel; + IFuid name; + GENinstance **kill; + +{ + + NBJT2model *model = (NBJT2model *) inModel; + NBJT2instance **fast = (NBJT2instance **) kill; + NBJT2instance **prev = NULL; + NBJT2instance *inst; + + for (; model; model = model->NBJT2nextModel) { + prev = &(model->NBJT2instances); + for (inst = *prev; inst; inst = *prev) { + if (inst->NBJT2name == name || (fast && inst == *fast)) { + *prev = inst->NBJT2nextInstance; + FREE(inst); + return (OK); + } + prev = &(inst->NBJT2nextInstance); + } + } + return (E_NODEV); +} diff --git a/src/spicelib/devices/nbjt2/nbt2dest.c b/src/spicelib/devices/nbjt2/nbt2dest.c new file mode 100644 index 000000000..161318608 --- /dev/null +++ b/src/spicelib/devices/nbjt2/nbt2dest.c @@ -0,0 +1,40 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This routine deletes all NBJT2s from the circuit and frees all storage + * they were using. The current implementation has memory leaks. + */ + +#include "ngspice.h" +#include "nbjt2def.h" +#include "../../../ciderlib/twod/twoddefs.h" +#include "../../../ciderlib/twod/twodext.h" +#include "suffix.h" + +void +NBJT2destroy(inModel) + GENmodel **inModel; + +{ + + NBJT2model **model = (NBJT2model **) inModel; + NBJT2model *mod, *nextMod; + NBJT2instance *inst, *nextInst; + + + for (mod = *model; mod;) { + for (inst = mod->NBJT2instances; inst;) { + TWOdestroy(inst->NBJT2pDevice); + nextInst = inst->NBJT2nextInstance; + FREE(inst); + inst = nextInst; + } + nextMod = mod->NBJT2nextModel; + FREE(mod); + mod = nextMod; + } + *model = NULL; +} diff --git a/src/spicelib/devices/nbjt2/nbt2dump.c b/src/spicelib/devices/nbjt2/nbt2dump.c new file mode 100644 index 000000000..fb3fb704d --- /dev/null +++ b/src/spicelib/devices/nbjt2/nbt2dump.c @@ -0,0 +1,178 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +Author: 1991 David A. Gates, U. C. Berkeley CAD Group +**********/ + +/* + * This is a simple routine to dump the internal device states. It produces + * states for .OP, .DC, & .TRAN simulations. + */ + +#include "ngspice.h" +#include "cktdefs.h" +#include "nbjt2def.h" +#include "../../../ciderlib/twod/twoddefs.h" +#include "../../../ciderlib/twod/twodext.h" +#include "cidersupt.h" +#include "suffix.h" + + +/* Forward Declarations */ +static void NBJT2putHeader(FILE *, CKTcircuit *, NBJT2instance *); + +/* State Counter */ +static int state_numOP = 0; +static int state_numDC = 0; +static int state_numTR = 0; + +void +NBJT2dump(inModel, ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + register NBJT2model *model = (NBJT2model *) inModel; + register NBJT2instance *inst; + OUTPcard *output; + FILE *fpState; + char fileName[BSIZE_SP]; + char description[BSIZE_SP]; + char *prefix; + int *state_num; + int anyOutput = 0; + + if (ckt->CKTmode & MODEDCOP) { + prefix = "OP"; + state_num = &state_numOP; + sprintf(description, "..."); + } else if (ckt->CKTmode & MODEDCTRANCURVE) { + prefix = "DC"; + state_num = &state_numDC; + sprintf(description, "sweep = % e", ckt->CKTtime); + } else if (ckt->CKTmode & MODETRAN) { + prefix = "TR"; + state_num = &state_numTR; + sprintf(description, "time = % e", ckt->CKTtime); + } else { + /* Not a recognized CKT mode. */ + return; + } + + for (; model != NULL; model = model->NBJT2nextModel) { + output = model->NBJT2outputs; + for (inst = model->NBJT2instances; inst != NULL; + inst = inst->NBJT2nextInstance) { + if (inst->NBJT2owner != ARCHme) continue; + + if (inst->NBJT2printGiven) { + if ((ckt->CKTmode & MODETRAN) && + ((ckt->CKTstat->STATaccepted - 1) % inst->NBJT2print != 0)) { + continue; + } + anyOutput = 1; + sprintf(fileName, "%s%s.%d.%s", output->OUTProotFile, prefix, + *state_num, inst->NBJT2name); + if (!(fpState = fopen(fileName, "w"))) { + perror(fileName); + } else { + NBJT2putHeader(fpState, ckt, inst); + TWOprnSolution(fpState, inst->NBJT2pDevice, + model->NBJT2outputs); + fclose(fpState); + LOGmakeEntry(fileName, description); + } + } + } + } + if (anyOutput) { + (*state_num)++; + } +} + +#define NBJT2numOutputs 9 + +static +void +NBJT2putHeader(file, ckt, inst) + FILE *file; + CKTcircuit *ckt; + NBJT2instance *inst; +{ + char *reference; + double refVal = 0.0; + int numVars = NBJT2numOutputs; + + if (ckt->CKTmode & MODEDCOP) { + reference = NULL; + } else if (ckt->CKTmode & MODEDCTRANCURVE) { + reference = "sweep"; + refVal = ckt->CKTtime; + numVars++; + } else if (ckt->CKTmode & MODETRAN) { + reference = "time"; + refVal = ckt->CKTtime; + numVars++; + } else { + reference = NULL; + } + fprintf(file, "Title: Device %s external state\n", inst->NBJT2name); + fprintf(file, "Plotname: Device Operating Point\n"); + fprintf(file, "Command: deftype v conductance S\n"); + fprintf(file, "Flags: real\n"); + fprintf(file, "No. Variables: %d\n", numVars); + fprintf(file, "No. Points: 1\n"); + numVars = 0; + fprintf(file, "Variables:\n"); + if (reference) { + fprintf(file, "\t%d %s unknown\n", numVars++, reference); + } + fprintf(file, "\t%d v13 voltage\n", numVars++); + fprintf(file, "\t%d v23 voltage\n", numVars++); + fprintf(file, "\t%d i1 current\n", numVars++); + fprintf(file, "\t%d i2 current\n", numVars++); + fprintf(file, "\t%d i3 current\n", numVars++); + fprintf(file, "\t%d g22 conductance\n", numVars++); + fprintf(file, "\t%d g21 conductance\n", numVars++); + fprintf(file, "\t%d g12 conductance\n", numVars++); + fprintf(file, "\t%d g11 conductance\n", numVars++); + fprintf(file, "Values:\n0"); + if (reference) { + fprintf(file, "\t% e\n", refVal); + } + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NBJT2vce)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NBJT2vbe)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NBJT2ic)); + fprintf(file, "\t% e\n", - *(ckt->CKTstate0 + inst->NBJT2ie) + - *(ckt->CKTstate0 + inst->NBJT2ic)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NBJT2ie)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NBJT2dIeDVbe) + - *(ckt->CKTstate0 + inst->NBJT2dIcDVbe)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NBJT2dIeDVce) + - *(ckt->CKTstate0 + inst->NBJT2dIcDVce)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NBJT2dIcDVbe)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NBJT2dIcDVce)); +} + +void +NBJT2acct(inModel, ckt, file) + GENmodel *inModel; + CKTcircuit *ckt; + FILE *file; +{ + register NBJT2model *model = (NBJT2model *) inModel; + register NBJT2instance *inst; + OUTPcard *output; + + for (; model != NULL; model = model->NBJT2nextModel) { + output = model->NBJT2outputs; + for (inst = model->NBJT2instances; inst != NULL; + inst = inst->NBJT2nextInstance) { + if (inst->NBJT2owner != ARCHme) continue; + + if (output->OUTPstats) { + TWOmemStats(file, inst->NBJT2pDevice); + TWOcpuStats(file, inst->NBJT2pDevice); + } + } + } +} diff --git a/src/spicelib/devices/nbjt2/nbt2init.c b/src/spicelib/devices/nbjt2/nbt2init.c new file mode 100644 index 000000000..be1c2f3d4 --- /dev/null +++ b/src/spicelib/devices/nbjt2/nbt2init.c @@ -0,0 +1,83 @@ +#include + +#include + +#include "nbjt2itf.h" +#include "nbjt2ext.h" +#include "nbt2init.h" + + +SPICEdev NBJT2info = { + { + "NBJT2", + "2D Numerical Bipolar Junction Transistor model", + + &NBJT2nSize, + &NBJT2nSize, + NBJT2names, + + &NBJT2pTSize, + NBJT2pTable, + + &NBJT2mPTSize, + NBJT2mPTable, + +#ifdef XSPICE +/*---- Fixed by SDB 5.2.2003 to enable XSPICE/tclspice integration -----*/ + NULL, /* This is a SPICE device, it has no MIF info data */ + + 0, /* This is a SPICE device, it has no MIF info data */ + NULL, /* This is a SPICE device, it has no MIF info data */ + + 0, /* This is a SPICE device, it has no MIF info data */ + NULL, /* This is a SPICE device, it has no MIF info data */ + + 0, /* This is a SPICE device, it has no MIF info data */ + NULL, /* This is a SPICE device, it has no MIF info data */ +/*--------------------------- End of SDB fix -------------------------*/ +#endif + + DEV_DEFAULT + }, + + DEVparam : NBJT2param, + DEVmodParam : NBJT2mParam, + DEVload : NBJT2load, + DEVsetup : NBJT2setup, + DEVunsetup : NULL, + DEVpzSetup : NBJT2setup, + DEVtemperature: NBJT2temp, + DEVtrunc : NBJT2trunc, + DEVfindBranch : NULL, + DEVacLoad : NBJT2acLoad, + DEVaccept : NULL, + DEVdestroy : NBJT2destroy, + DEVmodDelete : NBJT2mDelete, + DEVdelete : NBJT2delete, + DEVsetic : NULL, + DEVask : NBJT2ask, + DEVmodAsk : NULL, + DEVpzLoad : NBJT2pzLoad, + DEVconvTest : NULL, + DEVsenSetup : NULL, + DEVsenLoad : NULL, + DEVsenUpdate : NULL, + DEVsenAcLoad : NULL, + DEVsenPrint : NULL, + DEVsenTrunc : NULL, + DEVdisto : NULL, + DEVnoise : NULL, + DEVdump : NBJT2dump, + DEVacct : NBJT2acct, + + DEVinstSize : &NBJT2iSize, + DEVmodSize : &NBJT2mSize + +}; + + +SPICEdev * +get_nbjt2_info(void) +{ + return &NBJT2info; +} diff --git a/src/spicelib/devices/nbjt2/nbt2init.h b/src/spicelib/devices/nbjt2/nbt2init.h new file mode 100644 index 000000000..52b001494 --- /dev/null +++ b/src/spicelib/devices/nbjt2/nbt2init.h @@ -0,0 +1,13 @@ +#ifndef _NBJT2INIT_H +#define _NBJT2INIT_H + +extern IFparm NBJT2pTable[ ]; +extern IFparm NBJT2mPTable[ ]; +extern char *NBJT2names[ ]; +extern int NBJT2pTSize; +extern int NBJT2mPTSize; +extern int NBJT2nSize; +extern int NBJT2iSize; +extern int NBJT2mSize; + +#endif diff --git a/src/spicelib/devices/nbjt2/nbt2load.c b/src/spicelib/devices/nbjt2/nbt2load.c new file mode 100644 index 000000000..996ee1de8 --- /dev/null +++ b/src/spicelib/devices/nbjt2/nbt2load.c @@ -0,0 +1,509 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This is the function called each iteration to evaluate the 2d numerical + * BJTs in the circuit and load them into the matrix as appropriate + */ + +#include "ngspice.h" +#include "devdefs.h" +#include "cktdefs.h" +#include "nbjt2def.h" +#include "trandefs.h" +#include "sperror.h" +#include "../../../ciderlib/twod/twoddefs.h" +#include "../../../ciderlib/twod/twodext.h" +#include "cidersupt.h" +#include "suffix.h" + +/* External Declarations */ + +/* Check out this one */ +extern int NBJT2initSmSig(NBJT2instance *); + +extern int TWOdcDebug; +extern int TWOtranDebug; +extern int TWOacDebug; + + + +int +NBJT2load(inModel, ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + register NBJT2model *model = (NBJT2model *) inModel; + register NBJT2instance *inst; + register TWOdevice *pDevice; + double startTime, startTime2, totalTime, totalTime2; + double tol; + double ic, ie; + double iceq, ieeq; + double ichat = 0.0, iehat = 0.0; + double delVce, delVbe; + double vce, vbe; + double dIeDVce, dIeDVbe; + double dIcDVce, dIcDVbe; + double xfact; + int icheck; + int icheck1; + int i; + double deltaNorm[7]; + int devConverged = 0; + int numDevNonCon; + int deviceType; + int doInitSolve; + int doVoltPred; + char *initStateName; + + /* loop through all the models */ + for (; model != NULL; model = model->NBJT2nextModel) { + FieldDepMobility = model->NBJT2models->MODLfieldDepMobility; + TransDepMobility = model->NBJT2models->MODLtransDepMobility; + SurfaceMobility = model->NBJT2models->MODLsurfaceMobility; + Srh = model->NBJT2models->MODLsrh; + Auger = model->NBJT2models->MODLauger; + AvalancheGen = model->NBJT2models->MODLavalancheGen; + OneCarrier = model->NBJT2methods->METHoneCarrier; + MobDeriv = model->NBJT2methods->METHmobDeriv; + MaxIterations = model->NBJT2methods->METHitLim; + TWOdcDebug = model->NBJT2outputs->OUTPdcDebug; + TWOtranDebug = model->NBJT2outputs->OUTPtranDebug; + TWOacDebug = model->NBJT2outputs->OUTPacDebug; + deviceType = model->NBJT2options->OPTNdeviceType; + doVoltPred = model->NBJT2methods->METHvoltPred; + + if (ckt->CKTmode & MODEINITPRED) { + /* compute normalized deltas and predictor coeff */ + if (!(ckt->CKTmode & MODEDCTRANCURVE)) { + model->NBJT2pInfo->order = ckt->CKTorder; + model->NBJT2pInfo->method = ckt->CKTintegrateMethod; + for (i = 0; i <= ckt->CKTmaxOrder; i++) { + deltaNorm[i] = ckt->CKTdeltaOld[i] / TNorm; + } + computeIntegCoeff(ckt->CKTintegrateMethod, ckt->CKTorder, + model->NBJT2pInfo->intCoeff, deltaNorm); + computePredCoeff(ckt->CKTintegrateMethod, ckt->CKTorder, + model->NBJT2pInfo->predCoeff, deltaNorm); + } + } else if (ckt->CKTmode & MODEINITTRAN) { + model->NBJT2pInfo->order = ckt->CKTorder; + model->NBJT2pInfo->method = ckt->CKTintegrateMethod; + for (i = 0; i <= ckt->CKTmaxOrder; i++) { + deltaNorm[i] = ckt->CKTdeltaOld[i] / TNorm; + } + computeIntegCoeff(ckt->CKTintegrateMethod, ckt->CKTorder, + model->NBJT2pInfo->intCoeff, deltaNorm); + } + /* loop through all the instances of the model */ + for (inst = model->NBJT2instances; inst != NULL; + inst = inst->NBJT2nextInstance) { + if (inst->NBJT2owner != ARCHme) continue; + + pDevice = inst->NBJT2pDevice; + + totalTime = 0.0; + startTime = SPfrontEnd->IFseconds(); + + /* Get Temp.-Dep. Global Parameters */ + GLOBgetGlobals(&(inst->NBJT2globals)); + + /* + * initialization + */ + pDevice->devStates = ckt->CKTstates; + icheck = 1; + doInitSolve = FALSE; + initStateName = NULL; + if (ckt->CKTmode & MODEINITSMSIG) { + vbe = *(ckt->CKTstate0 + inst->NBJT2vbe); + vce = *(ckt->CKTstate0 + inst->NBJT2vce); + delVbe = 0.0; + delVce = 0.0; + NBJT2setBCs(pDevice, vce, vbe); + } else if (ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate0 + inst->NBJT2vbe) = + *(ckt->CKTstate1 + inst->NBJT2vbe); + *(ckt->CKTstate0 + inst->NBJT2vce) = + *(ckt->CKTstate1 + inst->NBJT2vce); + vbe = *(ckt->CKTstate1 + inst->NBJT2vbe); + vce = *(ckt->CKTstate1 + inst->NBJT2vce); + TWOsaveState(pDevice); + delVbe = 0.0; + delVce = 0.0; + } else if ((ckt->CKTmode & MODEINITJCT) && + (ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) { + doInitSolve = TRUE; + initStateName = inst->NBJT2icFile; + vbe = 0.0; + vce = 0.0; + delVbe = vbe; + delVce = vce; + } else if ((ckt->CKTmode & MODEINITJCT) && (inst->NBJT2off == 0)) { + doInitSolve = TRUE; + initStateName = inst->NBJT2icFile; + if (deviceType == OPTN_JFET) { + vbe = 0.0; + vce = inst->NBJT2type * 0.5; + } else { + vbe = inst->NBJT2type * 0.6; + vce = inst->NBJT2type * 1.0; + } + delVbe = vbe; + delVce = vce; + } else if (ckt->CKTmode & MODEINITJCT) { + doInitSolve = TRUE; + vbe = 0.0; + vce = 0.0; + delVbe = vbe; + delVce = vce; + } else if ((ckt->CKTmode & MODEINITFIX) && inst->NBJT2off) { + vbe = 0.0; + vce = 0.0; + delVbe = vbe; + delVce = vce; + } else { + if (ckt->CKTmode & MODEINITPRED) { + *(ckt->CKTstate0 + inst->NBJT2vbe) = + *(ckt->CKTstate1 + inst->NBJT2vbe); + *(ckt->CKTstate0 + inst->NBJT2vce) = + *(ckt->CKTstate1 + inst->NBJT2vce); + *(ckt->CKTstate0 + inst->NBJT2ic) = + *(ckt->CKTstate1 + inst->NBJT2ic); + *(ckt->CKTstate0 + inst->NBJT2ie) = + *(ckt->CKTstate1 + inst->NBJT2ie); + *(ckt->CKTstate0 + inst->NBJT2dIeDVce) = + *(ckt->CKTstate1 + inst->NBJT2dIeDVce); + *(ckt->CKTstate0 + inst->NBJT2dIeDVbe) = + *(ckt->CKTstate1 + inst->NBJT2dIeDVbe); + *(ckt->CKTstate0 + inst->NBJT2dIcDVce) = + *(ckt->CKTstate1 + inst->NBJT2dIcDVce); + *(ckt->CKTstate0 + inst->NBJT2dIcDVbe) = + *(ckt->CKTstate1 + inst->NBJT2dIcDVbe); + /* compute normalized deltas and predictor coeff */ + if (!(ckt->CKTmode & MODEDCTRANCURVE)) { + /* no linear prediction on device voltages */ + vbe = *(ckt->CKTstate1 + inst->NBJT2vbe); + vce = *(ckt->CKTstate1 + inst->NBJT2vce); + TWOpredict(pDevice, model->NBJT2pInfo); + } else { + if (doVoltPred) { + /* linear prediction */ + xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1]; + vbe = (1+xfact) * (*(ckt->CKTstate1 + inst->NBJT2vbe)) + - (xfact) * (*(ckt->CKTstate2 + inst->NBJT2vbe)); + vce = (1+xfact) * (*(ckt->CKTstate1 + inst->NBJT2vce)) + - (xfact) * (*(ckt->CKTstate2 + inst->NBJT2vce)); + } else { + vbe = *(ckt->CKTstate1 + inst->NBJT2vbe); + vce = *(ckt->CKTstate1 + inst->NBJT2vce); + } + } + } else { + /* + * compute new nonlinear branch voltages + */ + vbe = *(ckt->CKTrhsOld + inst->NBJT2baseNode) - + *(ckt->CKTrhsOld + inst->NBJT2emitNode); + vce = *(ckt->CKTrhsOld + inst->NBJT2colNode) - + *(ckt->CKTrhsOld + inst->NBJT2emitNode); + } + delVbe = vbe - *(ckt->CKTstate0 + inst->NBJT2vbe); + delVce = vce - *(ckt->CKTstate0 + inst->NBJT2vce); + ichat = *(ckt->CKTstate0 + inst->NBJT2ic) + + *(ckt->CKTstate0 + inst->NBJT2dIcDVbe) * delVbe + + *(ckt->CKTstate0 + inst->NBJT2dIcDVce) * delVce; + iehat = *(ckt->CKTstate0 + inst->NBJT2ie) + + *(ckt->CKTstate0 + inst->NBJT2dIeDVbe) * delVbe + + *(ckt->CKTstate0 + inst->NBJT2dIeDVce) * delVce; + + +#ifndef NOBYPASS + /* + * bypass if solution has not changed + */ + /* + * the following collections of if's would be just one if the average + * compiler could handle it, but many find the expression too + * complicated, thus the split. + */ + if ((ckt->CKTbypass) && pDevice->converged && + (!(ckt->CKTmode & MODEINITPRED)) && + (fabs(delVbe) < (ckt->CKTreltol * MAX(fabs(vbe), + fabs(*(ckt->CKTstate0 + inst->NBJT2vbe))) + + ckt->CKTvoltTol))) + if ((fabs(delVce) < ckt->CKTreltol * MAX(fabs(vce), + fabs(*(ckt->CKTstate0 + inst->NBJT2vce))) + + ckt->CKTvoltTol)) + if ((fabs(ichat - *(ckt->CKTstate0 + inst->NBJT2ic)) < + ckt->CKTreltol * MAX(fabs(ichat), + fabs(*(ckt->CKTstate0 + inst->NBJT2ic))) + + ckt->CKTabstol)) + if ((fabs(iehat - *(ckt->CKTstate0 + inst->NBJT2ie)) < + ckt->CKTreltol * MAX(fabs(iehat), + fabs(*(ckt->CKTstate0 + inst->NBJT2ie))) + + ckt->CKTabstol)) { + /* + * bypassing.... + */ + vbe = *(ckt->CKTstate0 + inst->NBJT2vbe); + vce = *(ckt->CKTstate0 + inst->NBJT2vce); + ic = *(ckt->CKTstate0 + inst->NBJT2ic); + ie = *(ckt->CKTstate0 + inst->NBJT2ie); + dIeDVce = *(ckt->CKTstate0 + inst->NBJT2dIeDVce); + dIeDVbe = *(ckt->CKTstate0 + inst->NBJT2dIeDVbe); + dIcDVce = *(ckt->CKTstate0 + inst->NBJT2dIcDVce); + dIcDVbe = *(ckt->CKTstate0 + inst->NBJT2dIcDVbe); + goto load; + } +#endif /* NOBYPASS */ + /* + * limit nonlinear branch voltages + */ + icheck1 = 1; + if (deviceType == OPTN_JFET) { + double vbc, vbc0; + vbe = inst->NBJT2type * limitJunctionVoltage(inst->NBJT2type * vbe, + inst->NBJT2type * *(ckt->CKTstate0 + inst->NBJT2vbe), &icheck); + vbc = vbe - vce; + vbc0 = *(ckt->CKTstate0 + inst->NBJT2vbe) - + *(ckt->CKTstate0 + inst->NBJT2vce); + vbc = inst->NBJT2type * limitJunctionVoltage(inst->NBJT2type * vbc, + inst->NBJT2type * vbc0, &icheck); + if (icheck1 == 1) + icheck = 1; + vce = vbe - vbc; + } else { + vbe = inst->NBJT2type * limitJunctionVoltage(inst->NBJT2type * vbe, + inst->NBJT2type * *(ckt->CKTstate0 + inst->NBJT2vbe), &icheck); + vce = inst->NBJT2type * limitVce(inst->NBJT2type * vce, + inst->NBJT2type * *(ckt->CKTstate0 + inst->NBJT2vce), &icheck1); + if (icheck1 == 1) + icheck = 1; + } + delVbe = vbe - *(ckt->CKTstate0 + inst->NBJT2vbe); + delVce = vce - *(ckt->CKTstate0 + inst->NBJT2vce); + NBJT2setBCs(pDevice, vce - delVce, vbe - delVbe); + } + + if (doInitSolve) { + if (TWOdcDebug) { + printVoltages(stdout, model->NBJT2modName, inst->NBJT2name, + deviceType, 2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + } + startTime2 = SPfrontEnd->IFseconds(); + TWOequilSolve(pDevice); + totalTime2 = SPfrontEnd->IFseconds() - startTime2; + pDevice->pStats->totalTime[STAT_SETUP] += totalTime2; + pDevice->pStats->totalTime[STAT_DC] -= totalTime2; + + TWObiasSolve(pDevice, MaxIterations, FALSE, NULL); + + *(ckt->CKTstate0 + inst->NBJT2vbe) = 0.0; + *(ckt->CKTstate0 + inst->NBJT2vce) = 0.0; + + if (initStateName != NULL) { + if (TWOreadState(pDevice, initStateName, 2, &vce, &vbe, NULL ) < 0) { + fprintf(stderr, + "NBJT2load: trouble reading state-file %s\n", initStateName); + } else { + NBJT2setBCs(pDevice, vce, vbe); + delVce = delVbe = 0.0; + } + } + } + /* + * determine dc current and derivatives using the numerical routines + */ + if (ckt->CKTmode & (MODEDCOP | MODETRANOP | MODEDCTRANCURVE | MODEINITSMSIG)) { + + numDevNonCon = 0; + inst->NBJT2c11 = inst->NBJT2y11r = inst->NBJT2y11i = 0.0; + inst->NBJT2c12 = inst->NBJT2y12r = inst->NBJT2y12i = 0.0; + inst->NBJT2c21 = inst->NBJT2y21r = inst->NBJT2y21i = 0.0; + inst->NBJT2c22 = inst->NBJT2y22r = inst->NBJT2y22i = 0.0; + inst->NBJT2smSigAvail = FALSE; + devNonCon: + NBJT2project(pDevice, delVce, delVbe); + if (TWOdcDebug) { + printVoltages(stdout, model->NBJT2modName, inst->NBJT2name, + deviceType, 2, vce, delVce, vbe, delVbe, 0.0, 0.0); + } + TWObiasSolve(pDevice, MaxIterations, FALSE, model->NBJT2pInfo); + + devConverged = pDevice->converged; + if (devConverged && finite(pDevice->rhsNorm)) { + /* compute the currents */ + NBJT2current(pDevice, FALSE, (double *) NULL, &ie, &ic); + NBJT2conductance(pDevice, FALSE, (double *) NULL, + &dIeDVce, &dIcDVce, &dIeDVbe, &dIcDVbe); + + } else { + /* reduce the voltage step until converged */ + /* restore boundary nodes to previous potential */ + NBJT2setBCs(pDevice, vce - delVce, vbe - delVbe); + TWOstoreInitialGuess(pDevice); + TWOresetJacobian(pDevice); + delVbe *= 0.5; + delVce *= 0.5; + vbe = delVbe + *(ckt->CKTstate0 + inst->NBJT2vbe); + vce = delVce + *(ckt->CKTstate0 + inst->NBJT2vce); + numDevNonCon++; + icheck = 1; + if (numDevNonCon > 10) { + printVoltages(stderr, model->NBJT2modName, inst->NBJT2name, + deviceType, 2, vce, delVce, vbe, delVbe, 0.0, 0.0); + fprintf(stderr, "*** Non-convergence during load ***\n"); + totalTime += SPfrontEnd->IFseconds() - startTime; + pDevice->pStats->totalTime[STAT_DC] += totalTime; + ckt->CKTtroubleElt = (GENinstance *) inst; + return (E_BADMATRIX); + } else { + goto devNonCon; + } + } + } + if ((ckt->CKTmode & (MODETRAN | MODEAC)) || + ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) || + (ckt->CKTmode & MODEINITSMSIG)) { + /* + * store small-signal parameters + */ + if ((!(ckt->CKTmode & MODETRANOP)) || + (!(ckt->CKTmode & MODEUIC))) { + if (ckt->CKTmode & MODEINITSMSIG) { + totalTime += SPfrontEnd->IFseconds() - startTime; + pDevice->pStats->totalTime[STAT_DC] += totalTime; + startTime2 = SPfrontEnd->IFseconds(); + NBJT2initSmSig(inst); + pDevice->pStats->totalTime[STAT_AC] += + SPfrontEnd->IFseconds() - startTime2; + continue; + } else { + inst->NBJT2smSigAvail = FALSE; + } + /* + * transient analysis + */ + if (ckt->CKTmode & MODEINITPRED) { + NBJT2setBCs(pDevice, vce, vbe); + TWOstoreInitialGuess(pDevice); + } else { + NBJT2update(pDevice, delVce, delVbe, TRUE); + } + if (TWOtranDebug) { + printVoltages(stdout, model->NBJT2modName, inst->NBJT2name, + deviceType, 2, vce, delVce, vbe, delVbe, 0.0, 0.0); + } + TWObiasSolve(pDevice, 0, TRUE, model->NBJT2pInfo); + if (!finite(pDevice->rhsNorm)) { + totalTime += SPfrontEnd->IFseconds() - startTime; + pDevice->pStats->totalTime[STAT_TRAN] += totalTime; + ckt->CKTtroubleElt = (GENinstance *) inst; + return (E_BADMATRIX); + } + devConverged = TWOdeviceConverged(pDevice); + pDevice->converged = devConverged; + + /* compute the currents */ + NBJT2current(pDevice, TRUE, + model->NBJT2pInfo->intCoeff, &ie, &ic); + NBJT2conductance(pDevice, TRUE, + model->NBJT2pInfo->intCoeff, + &dIeDVce, &dIcDVce, &dIeDVbe, &dIcDVbe); + } + } + /* + * check convergence + */ + if ((!(ckt->CKTmode & MODEINITFIX)) || (!(inst->NBJT2off))) { + if (icheck == 1 || !devConverged) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) inst; + } else { + tol = ckt->CKTreltol * MAX(fabs(ichat), fabs(ic)) + ckt->CKTabstol; + if (fabs(ichat - ic) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) inst; + } else { + tol = ckt->CKTreltol * MAX(fabs(iehat), fabs(ie)) + + ckt->CKTabstol; + if (fabs(iehat - ie) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) inst; + } + } + } + } + *(ckt->CKTstate0 + inst->NBJT2vbe) = vbe; + *(ckt->CKTstate0 + inst->NBJT2vce) = vce; + *(ckt->CKTstate0 + inst->NBJT2ic) = ic; + *(ckt->CKTstate0 + inst->NBJT2ie) = ie; + *(ckt->CKTstate0 + inst->NBJT2dIeDVce) = dIeDVce; + *(ckt->CKTstate0 + inst->NBJT2dIeDVbe) = dIeDVbe; + *(ckt->CKTstate0 + inst->NBJT2dIcDVce) = dIcDVce; + *(ckt->CKTstate0 + inst->NBJT2dIcDVbe) = dIcDVbe; + + load: + /* + * load current excitation vector + */ + + iceq = ic - dIcDVce * vce - dIcDVbe * vbe; + ieeq = ie - dIeDVce * vce - dIeDVbe * vbe; + *(ckt->CKTrhs + inst->NBJT2colNode) -= iceq; + *(ckt->CKTrhs + inst->NBJT2baseNode) += ieeq + iceq; + *(ckt->CKTrhs + inst->NBJT2emitNode) -= ieeq; + /* + * load y matrix + */ + *(inst->NBJT2colColPtr) += dIcDVce; + *(inst->NBJT2colBasePtr) += dIcDVbe; + *(inst->NBJT2colEmitPtr) -= dIcDVbe + dIcDVce; + *(inst->NBJT2baseColPtr) -= dIcDVce + dIeDVce; + *(inst->NBJT2baseBasePtr) -= dIcDVbe + dIeDVbe; + *(inst->NBJT2baseEmitPtr) += dIcDVbe + dIcDVce + dIeDVbe + dIeDVce; + *(inst->NBJT2emitColPtr) += dIeDVce; + *(inst->NBJT2emitBasePtr) += dIeDVbe; + *(inst->NBJT2emitEmitPtr) -= dIeDVbe + dIeDVce; + + totalTime += SPfrontEnd->IFseconds() - startTime; + if (ckt->CKTmode & MODETRAN) { + pDevice->pStats->totalTime[STAT_TRAN] += totalTime; + } else { + pDevice->pStats->totalTime[STAT_DC] += totalTime; + } + } + } + return (OK); +} + +int +NBJT2initSmSig(inst) + NBJT2instance *inst; +{ + SPcomplex yIeVce, yIeVbe; + SPcomplex yIcVce, yIcVbe; + double omega = inst->NBJT2modPtr->NBJT2methods->METHomega; + + AcAnalysisMethod = SOR_ONLY; + (void) NBJT2admittance(inst->NBJT2pDevice, omega, + &yIeVce, &yIcVce, &yIeVbe, &yIcVbe); + inst->NBJT2c11 = yIcVce.imag / omega; + inst->NBJT2c12 = yIcVbe.imag / omega; + inst->NBJT2c21 = (yIeVce.imag - yIcVce.imag) / omega; + inst->NBJT2c22 = (yIeVbe.imag - yIcVbe.imag) / omega; + inst->NBJT2y11r = yIcVce.real; + inst->NBJT2y11i = yIcVce.imag; + inst->NBJT2y12r = yIcVbe.real; + inst->NBJT2y12i = yIcVbe.imag; + inst->NBJT2y21r = yIeVce.real - yIcVce.real; + inst->NBJT2y21i = yIeVce.imag - yIcVce.imag; + inst->NBJT2y22r = yIeVbe.real - yIcVbe.real; + inst->NBJT2y22i = yIeVbe.imag - yIcVbe.imag; + inst->NBJT2smSigAvail = TRUE; + return (OK); +} diff --git a/src/spicelib/devices/nbjt2/nbt2mdel.c b/src/spicelib/devices/nbjt2/nbt2mdel.c new file mode 100644 index 000000000..51b9c439a --- /dev/null +++ b/src/spicelib/devices/nbjt2/nbt2mdel.c @@ -0,0 +1,43 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This routine deletes a NBJT2 model from the circuit and frees the storage + * it was using. returns an error if the model has instances + */ + +#include "ngspice.h" +#include "nbjt2def.h" +#include "sperror.h" +#include "suffix.h" + +int +NBJT2mDelete(inModel, modname, kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; + +{ + + NBJT2model **model = (NBJT2model **) inModel; + NBJT2model *modfast = (NBJT2model *) kill; + NBJT2model **oldmod; + oldmod = model; + for (; *model; model = &((*model)->NBJT2nextModel)) { + if ((*model)->NBJT2modName == modname || + (modfast && *model == modfast)) + goto delgot; + oldmod = model; + } + return (E_NOMOD); + +delgot: + if ((*model)->NBJT2instances) + return (E_NOTEMPTY); + *oldmod = (*model)->NBJT2nextModel; /* cut deleted device out of list */ + FREE(*model); + return (OK); + +} diff --git a/src/spicelib/devices/nbjt2/nbt2mpar.c b/src/spicelib/devices/nbjt2/nbt2mpar.c new file mode 100644 index 000000000..9bc8f9806 --- /dev/null +++ b/src/spicelib/devices/nbjt2/nbt2mpar.c @@ -0,0 +1,32 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This routine sets model parameters for NBJT2s in the circuit. + */ + +#include "ngspice.h" +#include "const.h" +#include "ifsim.h" +#include "nbjt2def.h" +#include "sperror.h" +#include "suffix.h" + +int +NBJT2mParam(param, value, inModel) + int param; + IFvalue *value; + GENmodel *inModel; +{ + switch (param) { + case NBJT2_MOD_NBJT: + /* no action - already know it is a 2d-numerical bjt, but this */ + /* makes life easier for spice-2 like parsers */ + break; + default: + return (E_BADPARM); + } + return (OK); +} diff --git a/src/spicelib/devices/nbjt2/nbt2parm.c b/src/spicelib/devices/nbjt2/nbt2parm.c new file mode 100644 index 000000000..df952b25e --- /dev/null +++ b/src/spicelib/devices/nbjt2/nbt2parm.c @@ -0,0 +1,53 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This routine sets instance parameters for NBJT2s in the circuit. + */ + +#include "ngspice.h" +#include "const.h" +#include "ifsim.h" +#include "nbjt2def.h" +#include "sperror.h" +#include "suffix.h" + +int +NBJT2param(param, value, inInst, select) + int param; + IFvalue *value; + GENinstance *inInst; + IFvalue *select; +{ + register NBJT2instance *inst = (NBJT2instance *) inInst; + switch (param) { + case NBJT2_WIDTH: + inst->NBJT2width = value->rValue; + inst->NBJT2widthGiven = TRUE; + break; + case NBJT2_AREA: + inst->NBJT2area = value->rValue; + inst->NBJT2areaGiven = TRUE; + break; + case NBJT2_OFF: + inst->NBJT2off = TRUE; + break; + case NBJT2_IC_FILE: + inst->NBJT2icFile = value->sValue; + inst->NBJT2icFileGiven = TRUE; + break; + case NBJT2_PRINT: + inst->NBJT2print = value->rValue; + inst->NBJT2printGiven = TRUE; + break; + case NBJT2_TEMP: + inst->NBJT2temp = value->rValue + CONSTCtoK; + inst->NBJT2tempGiven = TRUE; + break; + default: + return (E_BADPARM); + } + return (OK); +} diff --git a/src/spicelib/devices/nbjt2/nbt2pzld.c b/src/spicelib/devices/nbjt2/nbt2pzld.c new file mode 100644 index 000000000..982c198e8 --- /dev/null +++ b/src/spicelib/devices/nbjt2/nbt2pzld.c @@ -0,0 +1,79 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "cktdefs.h" +#include "complex.h" +#include "nbjt2def.h" +#include "sperror.h" +#include "../../../ciderlib/twod/twoddefs.h" +#include "../../../ciderlib/twod/twodext.h" +#include "cidersupt.h" +#include "suffix.h" + +/* External Declarations */ +extern int TWOacDebug; + +int +NBJT2pzLoad(inModel, ckt, s) + GENmodel *inModel; + CKTcircuit *ckt; + SPcomplex *s; +{ + register NBJT2model *model = (NBJT2model *) inModel; + register NBJT2instance *inst; + SPcomplex yIeVce, yIeVbe; + SPcomplex yIcVce, yIcVbe; + double startTime; + + for (; model != NULL; model = model->NBJT2nextModel) { + FieldDepMobility = model->NBJT2models->MODLfieldDepMobility; + TransDepMobility = model->NBJT2models->MODLtransDepMobility; + SurfaceMobility = model->NBJT2models->MODLsurfaceMobility; + Srh = model->NBJT2models->MODLsrh; + Auger = model->NBJT2models->MODLauger; + AvalancheGen = model->NBJT2models->MODLavalancheGen; + OneCarrier = model->NBJT2methods->METHoneCarrier; + AcAnalysisMethod = model->NBJT2methods->METHacAnalysisMethod; + MobDeriv = model->NBJT2methods->METHmobDeriv; + TWOacDebug = model->NBJT2outputs->OUTPacDebug; + + for (inst = model->NBJT2instances; inst != NULL; + inst = inst->NBJT2nextInstance) { + if (inst->NBJT2owner != ARCHme) continue; + + startTime = SPfrontEnd->IFseconds(); + + /* Get Temp.-Dep. Global Parameters */ + GLOBgetGlobals(&(inst->NBJT2globals)); + + NBJT2ys(inst->NBJT2pDevice, s, + &yIeVce, &yIcVce, &yIeVbe, &yIcVbe); + + *(inst->NBJT2colColPtr) += yIcVce.real; + *(inst->NBJT2colColPtr + 1) += yIcVce.imag; + *(inst->NBJT2colBasePtr) += yIcVbe.real; + *(inst->NBJT2colBasePtr + 1) += yIcVbe.imag; + *(inst->NBJT2colEmitPtr) -= yIcVbe.real + yIcVce.real; + *(inst->NBJT2colEmitPtr + 1) -= yIcVbe.imag + yIcVce.imag; + *(inst->NBJT2baseColPtr) -= yIcVce.real + yIeVce.real; + *(inst->NBJT2baseColPtr + 1) -= yIcVce.imag + yIeVce.imag; + *(inst->NBJT2baseBasePtr) -= yIcVbe.real + yIeVbe.real; + *(inst->NBJT2baseBasePtr + 1) -= yIcVbe.imag + yIeVbe.imag; + *(inst->NBJT2baseEmitPtr) += yIcVbe.real + yIcVce.real + yIeVbe.real + yIeVce.real; + *(inst->NBJT2baseEmitPtr + 1) += yIcVbe.imag + yIcVce.imag + yIeVbe.imag + yIeVce.imag; + *(inst->NBJT2emitColPtr) += yIeVce.real; + *(inst->NBJT2emitColPtr + 1) += yIeVce.imag; + *(inst->NBJT2emitBasePtr) += yIeVbe.real; + *(inst->NBJT2emitBasePtr + 1) += yIeVbe.imag; + *(inst->NBJT2emitEmitPtr) -= yIeVbe.real + yIeVce.real; + *(inst->NBJT2emitEmitPtr + 1) -= yIeVbe.imag + yIeVce.imag; + + inst->NBJT2pDevice->pStats->totalTime[STAT_AC] += + SPfrontEnd->IFseconds() - startTime; + } + } + return (OK); +} diff --git a/src/spicelib/devices/nbjt2/nbt2set.c b/src/spicelib/devices/nbjt2/nbt2set.c new file mode 100644 index 000000000..3673ae28a --- /dev/null +++ b/src/spicelib/devices/nbjt2/nbt2set.c @@ -0,0 +1,274 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "cktdefs.h" +#include "smpdefs.h" +#include "nbjt2def.h" +#include "numconst.h" +#include "numenum.h" +#include "meshext.h" +#include "sperror.h" +#include "../../../ciderlib/twod/twoddefs.h" +#include "../../../ciderlib/twod/twodext.h" +#include "ciderinp.h" +#include "cidersupt.h" +#include "suffix.h" + +#define NIL(type) ((type *)0) +#define TSCALLOC(var, size, type)\ +if (size && (!(var =(type *)calloc(1, (unsigned)(size)*sizeof(type))))) {\ + return(E_NOMEM);\ +} + +int +NBJT2setup(matrix, inModel, ckt, states) + register SMPmatrix *matrix; + GENmodel *inModel; + CKTcircuit *ckt; + int *states; +/* + * load the structure with those pointers needed later for fast matrix + * loading + */ +{ + register NBJT2model *model = (NBJT2model *) inModel; + register NBJT2instance *inst; + METHcard *methods; + MODLcard *models; + OPTNcard *options; + OUTPcard *outputs; + char *icFileName = NULL; + int nameLen; + int error, xIndex, yIndex; + int xMeshSize, yMeshSize; + TWOdevice *pDevice; + TWOcoord *xCoordList = NIL(TWOcoord); + TWOcoord *yCoordList = NIL(TWOcoord); + TWOdomain *domainList = NIL(TWOdomain); + TWOelectrode *electrodeList = NIL(TWOelectrode); + TWOmaterial *pM, *pMaterial = NIL(TWOmaterial), *materialList = NIL(TWOmaterial); + DOPprofile *profileList = NIL(DOPprofile); + DOPtable *dopTableList = NIL(DOPtable); + double startTime; + + + + /* loop through all the models */ + for (; model != NULL; model = model->NBJT2nextModel) { + if (!model->NBJT2pInfo) { + TSCALLOC(model->NBJT2pInfo, 1, TWOtranInfo); + } + methods = model->NBJT2methods; + if (!methods) { + TSCALLOC(methods, 1, METHcard); + model->NBJT2methods = methods; + } + models = model->NBJT2models; + if (!models) { + TSCALLOC(models, 1, MODLcard); + model->NBJT2models = models; + } + options = model->NBJT2options; + if (!options) { + TSCALLOC(options, 1, OPTNcard); + model->NBJT2options = options; + } + outputs = model->NBJT2outputs; + if (!outputs) { + TSCALLOC(outputs, 1, OUTPcard); + model->NBJT2outputs = outputs; + } + if (!methods->METHvoltPredGiven) { + methods->METHvoltPred = FALSE; + } + if (!methods->METHmobDerivGiven) { + methods->METHmobDeriv = TRUE; + } + if (!methods->METHoneCarrierGiven) { + methods->METHoneCarrier = FALSE; + } + if (!methods->METHacAnalysisMethodGiven) { + methods->METHacAnalysisMethod = SOR; + } + if (!methods->METHdabstolGiven) { + methods->METHdabstol = DABSTOL2D; + } + if (!methods->METHdreltolGiven) { + methods->METHdreltol = ckt->CKTreltol; + } + if (!methods->METHitLimGiven) { + methods->METHitLim = 50; + } + if (!methods->METHomegaGiven || methods->METHomega <= 0.0) { + methods->METHomega = 2.0 * M_PI /* radians/sec */ ; + } + if (!options->OPTNdefaGiven || options->OPTNdefa <= 0.0) { + options->OPTNdefa = 1.0e4 /* cm^2 */ ; + } + if (!options->OPTNdeflGiven || options->OPTNdefl <= 0.0) { + options->OPTNdefl = 1.0e2 /* cm */ ; + } + if (!options->OPTNdefwGiven && options->OPTNdefaGiven) { + options->OPTNdefw = options->OPTNdefa / options->OPTNdefl; + } else if (!options->OPTNdefwGiven || options->OPTNdefw <= 0.0) { + options->OPTNdefw = 1.0e2 /* cm */ ; + } + if (!options->OPTNdeviceTypeGiven) { + options->OPTNdeviceType = OPTN_BIPOLAR; + } + if (!options->OPTNicFileGiven) { + options->OPTNicFile = NULL; + options->OPTNunique = FALSE; /* Can't form a unique name. */ + } + if (!options->OPTNuniqueGiven) { + options->OPTNunique = FALSE; + } + OneCarrier = methods->METHoneCarrier; + + /* Set up the rest of the card lists */ + if ((error = MODLsetup(model->NBJT2models))) + return (error); + BandGapNarrowing = models->MODLbandGapNarrowing; + ConcDepLifetime = models->MODLconcDepLifetime; + TempDepMobility = models->MODLtempDepMobility; + ConcDepMobility = models->MODLconcDepMobility; + SurfaceMobility = models->MODLsurfaceMobility; + + if ((error = OUTPsetup(model->NBJT2outputs))) + return (error); + if ((error = MATLsetup(model->NBJT2materials, &materialList))) + return (error); + if ((error = MOBsetup(model->NBJT2mobility, materialList))) + return (error); + if ((error = MESHsetup('x', model->NBJT2xMeshes, &xCoordList, &xMeshSize))) + return (error); + if ((error = MESHsetup('y', model->NBJT2yMeshes, &yCoordList, &yMeshSize))) + return (error); + if ((error = DOMNsetup(model->NBJT2domains, &domainList, + xCoordList, yCoordList, materialList))) + return (error); + if ((error = BDRYsetup(model->NBJT2boundaries, + xCoordList, yCoordList, domainList))) + return (error); + if ((error = ELCTsetup(model->NBJT2electrodes, &electrodeList, + xCoordList, yCoordList))) + return (error); + /* Make sure electrodes are OK. */ + checkElectrodes(electrodeList, 3); /* NBJT2 has 3 electrodes */ + + if ((error = CONTsetup(model->NBJT2contacts, electrodeList))) + return (error); + if ((error = DOPsetup(model->NBJT2dopings, &profileList, + &dopTableList, xCoordList, yCoordList))) + return (error); + model->NBJT2matlInfo = materialList; + model->NBJT2profiles = profileList; + model->NBJT2dopTables = dopTableList; + + /* loop through all the instances of the model */ + for (inst = model->NBJT2instances; inst != NULL; + inst = inst->NBJT2nextInstance) { + if (inst->NBJT2owner != ARCHme) goto matrixpointers; + + startTime = SPfrontEnd->IFseconds(); + + if (!inst->NBJT2printGiven) { + inst->NBJT2print = 0; + } else if (inst->NBJT2print <= 0) { + inst->NBJT2print = 1; + } + if (!inst->NBJT2icFileGiven) { + if (options->OPTNunique) { + nameLen = strlen(options->OPTNicFile) + strlen(inst->NBJT2name) + 1; + TSCALLOC(icFileName, nameLen+1, char); + sprintf(icFileName, "%s.%s", options->OPTNicFile, inst->NBJT2name); + icFileName[nameLen] = '\0'; + inst->NBJT2icFile = icFileName; + } else if (options->OPTNicFile != NULL) { + nameLen = strlen(options->OPTNicFile); + TSCALLOC(icFileName, nameLen+1, char); + icFileName = strcpy(icFileName, options->OPTNicFile); + inst->NBJT2icFile = icFileName; + } else { + inst->NBJT2icFile = NULL; + } + } + inst->NBJT2state = *states; + *states += NBJT2numStates; + + if (!inst->NBJT2pDevice) { + /* Assign the mesh and profile info to each instance. */ + TSCALLOC(pDevice, 1, TWOdevice); + TSCALLOC(pDevice->pStats, 1, TWOstats); + pDevice->name = inst->NBJT2name; + pDevice->solverType = SLV_NONE; + pDevice->numXNodes = xMeshSize; + pDevice->numYNodes = yMeshSize; + pDevice->xScale = MESHmkArray(xCoordList, xMeshSize); + pDevice->yScale = MESHmkArray(yCoordList, yMeshSize); + pDevice->abstol = methods->METHdabstol; + pDevice->reltol = methods->METHdreltol; + pDevice->rhsImag = NIL(double); + TSCALLOC(pDevice->elemArray, pDevice->numXNodes, TWOelem **); + for (xIndex = 1; xIndex < pDevice->numXNodes; xIndex++) { + TSCALLOC(pDevice->elemArray[xIndex], pDevice->numYNodes, TWOelem *); + } + + /* Create a copy of material data that can change with temperature. */ + pDevice->pMaterials = NIL(TWOmaterial); + for (pM = materialList; pM != NIL(TWOmaterial); pM = pM->next) { + if (pDevice->pMaterials == NIL(TWOmaterial)) { + TSCALLOC(pMaterial, 1, TWOmaterial); + pDevice->pMaterials = pMaterial; + } else { + TSCALLOC(pMaterial->next, 1, TWOmaterial); + pMaterial = pMaterial->next; + } + /* Copy everything, then fix the incorrect pointer. */ + bcopy((char *) pM, (char *) pMaterial, sizeof(TWOmaterial)); + pMaterial->next = NIL(TWOmaterial); + } + + /* Generate the mesh structure for the device. */ + TWObuildMesh(pDevice, domainList, electrodeList, pDevice->pMaterials); + + /* Store the device info in the instance. */ + inst->NBJT2pDevice = pDevice; + } + /* Now update the state pointers. */ + TWOgetStatePointers(inst->NBJT2pDevice, states); + + /* Wipe out statistics from previous runs (if any). */ + bzero((char *) inst->NBJT2pDevice->pStats, sizeof(TWOstats)); + + inst->NBJT2pDevice->pStats->totalTime[STAT_SETUP] += + SPfrontEnd->IFseconds() - startTime; + + /* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if ((inst->ptr = SMPmakeElt(matrix,inst->first,inst->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + +matrixpointers: + TSTALLOC(NBJT2colColPtr, NBJT2colNode, NBJT2colNode) + TSTALLOC(NBJT2colBasePtr, NBJT2colNode, NBJT2baseNode) + TSTALLOC(NBJT2colEmitPtr, NBJT2colNode, NBJT2emitNode) + TSTALLOC(NBJT2baseColPtr, NBJT2baseNode, NBJT2colNode) + TSTALLOC(NBJT2baseBasePtr, NBJT2baseNode, NBJT2baseNode) + TSTALLOC(NBJT2baseEmitPtr, NBJT2baseNode, NBJT2emitNode) + TSTALLOC(NBJT2emitColPtr, NBJT2emitNode, NBJT2colNode) + TSTALLOC(NBJT2emitBasePtr, NBJT2emitNode, NBJT2baseNode) + TSTALLOC(NBJT2emitEmitPtr, NBJT2emitNode, NBJT2emitNode) + } + /* Clean up lists */ + killCoordInfo(xCoordList); + killCoordInfo(yCoordList); + killDomainInfo(domainList); + killElectrodeInfo(electrodeList); + } + return (OK); +} diff --git a/src/spicelib/devices/nbjt2/nbt2temp.c b/src/spicelib/devices/nbjt2/nbt2temp.c new file mode 100644 index 000000000..4269e6213 --- /dev/null +++ b/src/spicelib/devices/nbjt2/nbt2temp.c @@ -0,0 +1,130 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +Author: 1992 David A. Gates, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "cktdefs.h" +#include "nbjt2def.h" +#include "numenum.h" +#include "carddefs.h" +#include "sperror.h" +#include "../../../ciderlib/twod/twoddefs.h" +#include "../../../ciderlib/twod/twodext.h" +#include "cidersupt.h" +#include "suffix.h" + +#define NIL(type) ((type *)0) + +int +NBJT2temp(inModel, ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +/* + * perform the temperature update + */ +{ + register NBJT2model *model = (NBJT2model *) inModel; + register NBJT2instance *inst; + METHcard *methods; + MODLcard *models; + OPTNcard *options; + OUTPcard *outputs; + TWOmaterial *pM, *pMaterial, *pNextMaterial; + double startTime; + + + /* loop through all the models */ + for (; model != NULL; model = model->NBJT2nextModel) { + methods = model->NBJT2methods; + models = model->NBJT2models; + options = model->NBJT2options; + outputs = model->NBJT2outputs; + + if (!options->OPTNtnomGiven) { + options->OPTNtnom = ckt->CKTnomTemp; + } + for (pM = model->NBJT2matlInfo; pM != NIL(TWOmaterial); + pM = pM->next) { + pM->tnom = options->OPTNtnom; + } + + BandGapNarrowing = models->MODLbandGapNarrowing; + ConcDepLifetime = models->MODLconcDepLifetime; + TempDepMobility = models->MODLtempDepMobility; + ConcDepMobility = models->MODLconcDepMobility; + SurfaceMobility = models->MODLsurfaceMobility; + MatchingMobility = models->MODLmatchingMobility; + OneCarrier = methods->METHoneCarrier; + + for (inst = model->NBJT2instances; inst != NULL; + inst = inst->NBJT2nextInstance) { + if (inst->NBJT2owner != ARCHme) continue; + + startTime = SPfrontEnd->IFseconds(); + + if (!inst->NBJT2tempGiven) { + inst->NBJT2temp = ckt->CKTtemp; + } + if (!inst->NBJT2areaGiven || inst->NBJT2area <= 0.0) { + inst->NBJT2area = 1.0; + } + if (!inst->NBJT2widthGiven || inst->NBJT2width <= 0.0) { + inst->NBJT2width = 1.0; + } + inst->NBJT2pDevice->width = + inst->NBJT2area * inst->NBJT2width * options->OPTNdefw; + + /* Compute and save globals for this instance. */ + GLOBcomputeGlobals(&(inst->NBJT2globals), inst->NBJT2temp); + + /* Calculate new sets of material parameters. */ + pM = model->NBJT2matlInfo; + pMaterial = inst->NBJT2pDevice->pMaterials; + for (; pM != NULL; pM = pM->next, pMaterial = pMaterial->next) { + + /* Copy everything, then fix the incorrect pointer. */ + pNextMaterial = pMaterial->next; + bcopy((char *) pM, (char *) pMaterial, sizeof(TWOmaterial)); + pMaterial->next = pNextMaterial; + + /* Now do the temperature dependence. */ + MATLtempDep(pMaterial, pMaterial->tnom); + if (outputs->OUTPmaterial) { + printMaterialInfo(pMaterial); + } + } + + /* Assign doping to the mesh. */ + TWOsetDoping(inst->NBJT2pDevice, model->NBJT2profiles, + model->NBJT2dopTables); + + /* Assign physical parameters to the mesh. */ + TWOsetup(inst->NBJT2pDevice); + + /* Assign boundary condition parameters. */ + TWOsetBCparams(inst->NBJT2pDevice, model->NBJT2boundaries); + + /* Normalize everything. */ + TWOnormalize(inst->NBJT2pDevice); + + /* Find the device's type. */ + if (inst->NBJT2pDevice->pFirstContact->pNodes[0]->netConc < 0.0) { + inst->NBJT2type = PNP; + if (OneCarrier) { + methods->METHoneCarrier = P_TYPE; + } + } else { + inst->NBJT2type = NPN; + if (OneCarrier) { + methods->METHoneCarrier = N_TYPE; + } + } + + inst->NBJT2pDevice->pStats->totalTime[STAT_SETUP] += + SPfrontEnd->IFseconds() - startTime; + } + } + return (OK); +} diff --git a/src/spicelib/devices/nbjt2/nbt2trun.c b/src/spicelib/devices/nbjt2/nbt2trun.c new file mode 100644 index 000000000..c02e4dbfa --- /dev/null +++ b/src/spicelib/devices/nbjt2/nbt2trun.c @@ -0,0 +1,57 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This routine performs truncation error calculations for NBJT2s in the + * circuit. + */ + +#include "ngspice.h" +#include "cktdefs.h" +#include "nbjt2def.h" +#include "sperror.h" +#include "../../../ciderlib/twod/twoddefs.h" +#include "../../../ciderlib/twod/twodext.h" +#include "cidersupt.h" +#include "suffix.h" + + +int +NBJT2trunc(inModel, ckt, timeStep) + GENmodel *inModel; + register CKTcircuit *ckt; + double *timeStep; + +{ + register NBJT2model *model = (NBJT2model *) inModel; + register NBJT2instance *inst; + double deltaNew; + double deltaNorm[7]; + double startTime; + int i; + + for (i = 0; i <= ckt->CKTmaxOrder; i++) { + deltaNorm[i] = ckt->CKTdeltaOld[i] / TNorm; + } + + for (; model != NULL; model = model->NBJT2nextModel) { + OneCarrier = model->NBJT2methods->METHoneCarrier; + model->NBJT2pInfo->order = ckt->CKTorder; + model->NBJT2pInfo->delta = deltaNorm; + model->NBJT2pInfo->lteCoeff = computeLTECoeff(model->NBJT2pInfo); + for (inst = model->NBJT2instances; inst != NULL; + inst = inst->NBJT2nextInstance) { + if (inst->NBJT2owner != ARCHme) continue; + + startTime = SPfrontEnd->IFseconds(); + deltaNew = TWOtrunc(inst->NBJT2pDevice, model->NBJT2pInfo, + ckt->CKTdelta); + *timeStep = MIN(*timeStep, deltaNew); + inst->NBJT2pDevice->pStats->totalTime[STAT_TRAN] += + SPfrontEnd->IFseconds() - startTime; + } + } + return (OK); +} diff --git a/src/spicelib/devices/numd/Makefile.am b/src/spicelib/devices/numd/Makefile.am new file mode 100644 index 000000000..33fe6326d --- /dev/null +++ b/src/spicelib/devices/numd/Makefile.am @@ -0,0 +1,29 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libnumd.a + +libnumd_a_SOURCES = \ + numd.c \ + numdacld.c \ + numdask.c \ + numddefs.h \ + numddel.c \ + numddest.c \ + numddump.c \ + numdext.h \ + numdinit.c \ + numdinit.h \ + numditf.h \ + numdload.c \ + numdmdel.c \ + numdmpar.c \ + numdparm.c \ + numdpzld.c \ + numdset.c \ + numdtemp.c \ + numdtrun.c + + +INCLUDES = -I$(top_srcdir)/src/include + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/numd/numd.c b/src/spicelib/devices/numd/numd.c new file mode 100644 index 000000000..021a87b25 --- /dev/null +++ b/src/spicelib/devices/numd/numd.c @@ -0,0 +1,53 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "devdefs.h" +#include "numddefs.h" +#include "suffix.h" + +IFparm NUMDpTable[] = { /* parameters */ + IP("off", NUMD_OFF, IF_FLAG, "Initially off"), + IP("ic.file", NUMD_IC_FILE, IF_REAL, "Initial conditions file"), + IOP("area", NUMD_AREA, IF_REAL, "Area factor"), + IP("save", NUMD_PRINT, IF_REAL, "Save Solutions"), + IP("print", NUMD_PRINT, IF_REAL, "Print Solutions"), + OP("vd", NUMD_VD, IF_REAL, "Voltage"), + OP("id", NUMD_ID, IF_REAL, "Current"), + OP("g11", NUMD_G11, IF_REAL, "Conductance"), + OP("c11", NUMD_C11, IF_REAL, "Capacitance"), + OP("y11", NUMD_Y11, IF_COMPLEX, "Admittance"), + OPU("g12", NUMD_G12, IF_REAL, "Conductance"), + OPU("c12", NUMD_C12, IF_REAL, "Capacitance"), + OPU("y12", NUMD_Y12, IF_COMPLEX, "Admittance"), + OPU("g21", NUMD_G21, IF_REAL, "Conductance"), + OPU("c21", NUMD_C21, IF_REAL, "Capacitance"), + OPU("y21", NUMD_Y21, IF_COMPLEX, "Admittance"), + OPU("g22", NUMD_G22, IF_REAL, "Conductance"), + OPU("c22", NUMD_C22, IF_REAL, "Capacitance"), + OPU("y22", NUMD_Y22, IF_COMPLEX, "Admittance"), + OPR("voltage", NUMD_VD, IF_REAL, "Voltage"), + OPR("current", NUMD_ID, IF_REAL, "Current"), + OPR("conductance", NUMD_G11, IF_REAL, "Conductance"), + OPR("capacitance", NUMD_C11, IF_REAL, "Capacitance"), + IOP("temp", NUMD_TEMP, IF_REAL, "Instance Temperature") +}; + +IFparm NUMDmPTable[] = { /* model parameters */ + /* numerical-device models no longer have parameters */ + /* one is left behind to keep the table from being empty */ + IP("numd", NUMD_MOD_NUMD, IF_REAL, "Numerical Diode") +}; + +char *NUMDnames[] = { + "D+", + "D-" +}; + +int NUMDnSize = NUMELEMS(NUMDnames); +int NUMDpTSize = NUMELEMS(NUMDpTable); +int NUMDmPTSize = NUMELEMS(NUMDmPTable); +int NUMDiSize = sizeof(NUMDinstance); +int NUMDmSize = sizeof(NUMDmodel); diff --git a/src/spicelib/devices/numd/numdacld.c b/src/spicelib/devices/numd/numdacld.c new file mode 100644 index 000000000..2e86b62fc --- /dev/null +++ b/src/spicelib/devices/numd/numdacld.c @@ -0,0 +1,77 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * Function to load the COMPLEX circuit matrix using the small signal + * parameters saved during a previous DC operating point analysis. + */ + +#include "ngspice.h" +#include "cktdefs.h" +#include "numddefs.h" +#include "sperror.h" +#include "complex.h" +#include "../../../ciderlib/oned/onedext.h" +#include "cidersupt.h" +#include "numglobs.h" +#include "suffix.h" + +/* External Declarations */ +extern int ONEacDebug; + +int +NUMDacLoad(inModel, ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + register NUMDmodel *model = (NUMDmodel *) inModel; + register NUMDinstance *inst; + SPcomplex y; + double startTime; + + /* loop through all the diode models */ + for (; model != NULL; model = model->NUMDnextModel) { + FieldDepMobility = model->NUMDmodels->MODLfieldDepMobility; + Srh = model->NUMDmodels->MODLsrh; + Auger = model->NUMDmodels->MODLauger; + AvalancheGen = model->NUMDmodels->MODLavalancheGen; + AcAnalysisMethod = model->NUMDmethods->METHacAnalysisMethod; + MobDeriv = model->NUMDmethods->METHmobDeriv; + ONEacDebug = model->NUMDoutputs->OUTPacDebug; + + for (inst = model->NUMDinstances; inst != NULL; + inst = inst->NUMDnextInstance) { + if (inst->NUMDowner != ARCHme) continue; + + startTime = SPfrontEnd->IFseconds(); + /* Get Temp.-Dep. Global Parameters */ + GLOBgetGlobals(&(inst->NUMDglobals)); + + model->NUMDmethods->METHacAnalysisMethod = + NUMDadmittance(inst->NUMDpDevice, + ckt->CKTomega, &y); + + *(inst->NUMDposPosPtr) += y.real; + *(inst->NUMDposPosPtr + 1) += y.imag; + *(inst->NUMDnegNegPtr) += y.real; + *(inst->NUMDnegNegPtr + 1) += y.imag; + *(inst->NUMDnegPosPtr) -= y.real; + *(inst->NUMDnegPosPtr + 1) -= y.imag; + *(inst->NUMDposNegPtr) -= y.real; + *(inst->NUMDposNegPtr + 1) -= y.imag; + if (ckt->CKTomega != 0.0) { + inst->NUMDc11 = y.imag / ckt->CKTomega; + } else { + inst->NUMDc11 = 0.0; /* XXX What else can be done?! */ + } + inst->NUMDy11r = y.real; + inst->NUMDy11i = y.imag; + inst->NUMDsmSigAvail = TRUE; + inst->NUMDpDevice->pStats->totalTime[STAT_AC] += + SPfrontEnd->IFseconds() - startTime; + } + } + return (OK); +} diff --git a/src/spicelib/devices/numd/numdask.c b/src/spicelib/devices/numd/numdask.c new file mode 100644 index 000000000..d887607bf --- /dev/null +++ b/src/spicelib/devices/numd/numdask.c @@ -0,0 +1,121 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include "const.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "numddefs.h" +#include "complex.h" +#include "sperror.h" +#include "suffix.h" + +/* Check out this one */ +extern int NUMDinitSmSig(NUMDinstance *); + + +/* ARGSUSED */ +int +NUMDask(ckt, inInst, which, value, select) + CKTcircuit *ckt; + GENinstance *inInst; + int which; + IFvalue *value; + IFvalue *select; +{ + NUMDinstance *inst = (NUMDinstance *) inInst; + SPcomplex yd; + + switch (which) { + case NUMD_AREA: + value->rValue = inst->NUMDarea; + return (OK); + case NUMD_TEMP: + value->rValue = inst->NUMDtemp - CONSTCtoK; + return (OK); + case NUMD_VD: + value->rValue = *(ckt->CKTstate0 + inst->NUMDvoltage); + return (OK); + case NUMD_ID: + value->rValue = *(ckt->CKTstate0 + inst->NUMDid); + return (OK); + case NUMD_G11: + value->rValue = *(ckt->CKTstate0 + inst->NUMDconduct); + return (OK); + case NUMD_G12: + value->rValue = -*(ckt->CKTstate0 + inst->NUMDconduct); + return (OK); + case NUMD_G21: + value->rValue = -*(ckt->CKTstate0 + inst->NUMDconduct); + return (OK); + case NUMD_G22: + value->rValue = *(ckt->CKTstate0 + inst->NUMDconduct); + return (OK); + case NUMD_C11: + if (!inst->NUMDsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMDinitSmSig(inst); + } + value->rValue = inst->NUMDc11; + return (OK); + case NUMD_C12: + if (!inst->NUMDsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMDinitSmSig(inst); + } + value->rValue = -inst->NUMDc11; + return (OK); + case NUMD_C21: + if (!inst->NUMDsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMDinitSmSig(inst); + } + value->rValue = -inst->NUMDc11; + return (OK); + case NUMD_C22: + if (!inst->NUMDsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMDinitSmSig(inst); + } + value->rValue = inst->NUMDc11; + return (OK); + case NUMD_Y11: + if (!inst->NUMDsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMDinitSmSig(inst); + } + value->cValue.real = inst->NUMDy11r; + value->cValue.imag = inst->NUMDy11i; + return (OK); + case NUMD_Y12: + if (!inst->NUMDsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMDinitSmSig(inst); + } + value->cValue.real = -inst->NUMDy11r; + value->cValue.imag = -inst->NUMDy11i; + return (OK); + case NUMD_Y21: + if (!inst->NUMDsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMDinitSmSig(inst); + } + value->cValue.real = -inst->NUMDy11r; + value->cValue.imag = -inst->NUMDy11i; + return (OK); + case NUMD_Y22: + if (!inst->NUMDsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMDinitSmSig(inst); + } + value->cValue.real = inst->NUMDy11r; + value->cValue.imag = inst->NUMDy11i; + return (OK); + default: + return (E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/numd/numddefs.h b/src/spicelib/devices/numd/numddefs.h new file mode 100644 index 000000000..b84d6c0a9 --- /dev/null +++ b/src/spicelib/devices/numd/numddefs.h @@ -0,0 +1,135 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +Authors: 1987 Karti Mayaram, 1991 David Gates +**********/ + +#ifndef NUMD_H +#define NUMD_H + +/* data structures used to describe 1D numerical diodes */ + +/* circuit level includes */ +#include "ifsim.h" +#include "cktdefs.h" +#include "gendefs.h" + +/* device level includes */ +#include "onemesh.h" +#include "onedev.h" +#include "profile.h" +#include "numglobs.h" +#include "carddefs.h" + +/* information needed per instance */ +typedef struct sNUMDinstance { + struct sNUMDmodel *NUMDmodPtr;/* back pointer to model */ + struct sNUMDinstance *NUMDnextInstance; /* pointer to next instance + * of current model */ + IFuid NUMDname; /* pointer to character string naming this + * instance */ + int NUMDowner; /* number of owner process */ + int NUMDstate; /* pointer to start of state vector for diode */ + +#define NUMDvoltage NUMDstate +#define NUMDid NUMDstate+1 +#define NUMDconduct NUMDstate+2 +#define NUMDnumStates 3 + + int NUMDposNode; /* number of positive node of diode */ + int NUMDnegNode; /* number of negative node of diode */ + ONEdevice *NUMDpDevice; + GLOBvalues NUMDglobals; /* Temp.-Dep. Global Parameters */ + int NUMDtype; /* device type pn or np */ + double NUMDarea; /* area factor for the diode */ + double NUMDtemp; /* instance temperature */ + double NUMDc11; /* small-signal capacitance */ + double NUMDy11r; /* small-signal admittance, real part */ + double NUMDy11i; /* small-signal admittance, imag part */ + int NUMDprint; /* number of timesteps after which print + * internal */ + char *NUMDicFile; /* Name of initial condition file */ + double *NUMDnegPosPtr; /* pointer to sparse matrix at + * (negative,positive) */ + double *NUMDposNegPtr; /* pointer to sparse matrix at + * (positive,negative) */ + double *NUMDposPosPtr; /* pointer to sparse matrix at + * (positive,positive) */ + double *NUMDnegNegPtr; /* pointer to sparse matrix at + * (negative,negative) */ + + int NUMDoff; /* 'off' flag for diode */ + unsigned NUMDsmSigAvail:1; /* flag to indicate small-signal done */ + unsigned NUMDareaGiven:1; /* flag to indicate area was specified */ + unsigned NUMDicFileGiven:1; /* flag to indicate init. cond. file given */ + unsigned NUMDtempGiven:1; /* flag to indicate temp was specified */ + unsigned NUMDprintGiven:1; /* flag to indicate if print was specified */ +} NUMDinstance; + + +/* per model data */ + +typedef struct sNUMDmodel { /* model structure for a diode */ + int NUMDmodType; /* type index of this device type */ + struct sNUMDmodel *NUMDnextModel; /* pointer to next possible model in + * linked list */ + NUMDinstance *NUMDinstances; /* pointer to list of instances that have + * this model */ + IFuid NUMDmodName; /* pointer to character string naming this + * model */ + /* Everything below here is numerical-device-specific */ + MESHcard *NUMDxMeshes; /* list of xmesh cards */ + MESHcard *NUMDyMeshes; /* list of ymesh cards */ + DOMNcard *NUMDdomains; /* list of domain cards */ + BDRYcard *NUMDboundaries; /* list of boundary cards */ + DOPcard *NUMDdopings; /* list of doping cards */ + ELCTcard *NUMDelectrodes; /* list of electrode cards */ + CONTcard *NUMDcontacts; /* list of contact cards */ + MODLcard *NUMDmodels; /* list of model cards */ + MATLcard *NUMDmaterials; /* list of material cards */ + MOBcard *NUMDmobility; /* list of mobility cards */ + METHcard *NUMDmethods; /* list of method cards */ + OPTNcard *NUMDoptions; /* list of option cards */ + OUTPcard *NUMDoutputs; /* list of output cards */ + ONEtranInfo *NUMDpInfo; /* transient analysis information */ + DOPprofile *NUMDprofiles; /* expanded list of doping profiles */ + DOPtable *NUMDdopTables; /* list of tables used by profiles */ + ONEmaterial *NUMDmatlInfo; /* list of material info structures */ +} NUMDmodel; + +/* type of 1D diode */ +#define PN 1 +#define NP -1 + +/* device parameters */ +#define NUMD_AREA 1 +#define NUMD_IC_FILE 2 +#define NUMD_OFF 3 +#define NUMD_PRINT 4 +#define NUMD_TEMP 5 +#define NUMD_VD 6 +#define NUMD_ID 7 + +#define NUMD_G11 8 +#define NUMD_C11 9 +#define NUMD_Y11 10 +#define NUMD_G12 11 +#define NUMD_C12 12 +#define NUMD_Y12 13 +#define NUMD_G21 14 +#define NUMD_C21 15 +#define NUMD_Y21 16 +#define NUMD_G22 17 +#define NUMD_C22 18 +#define NUMD_Y22 19 + +/* model parameters */ +/* NOTE: all true model parameters have been moved to IFcardInfo structures */ +#define NUMD_MOD_NUMD 101 + +/* device questions */ + +/* model questions */ + +#include "numdext.h" + +#endif /* NUMD_H */ diff --git a/src/spicelib/devices/numd/numddel.c b/src/spicelib/devices/numd/numddel.c new file mode 100644 index 000000000..6e52942ba --- /dev/null +++ b/src/spicelib/devices/numd/numddel.c @@ -0,0 +1,36 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "numddefs.h" +#include "sperror.h" +#include "suffix.h" + +int +NUMDdelete(inModel, name, kill) + GENmodel *inModel; + IFuid name; + GENinstance **kill; + +{ + + NUMDmodel *model = (NUMDmodel *) inModel; + NUMDinstance **fast = (NUMDinstance **) kill; + NUMDinstance **prev = NULL; + NUMDinstance *inst; + + for (; model; model = model->NUMDnextModel) { + prev = &(model->NUMDinstances); + for (inst = *prev; inst; inst = *prev) { + if (inst->NUMDname == name || (fast && inst == *fast)) { + *prev = inst->NUMDnextInstance; + FREE(inst); + return (OK); + } + prev = &(inst->NUMDnextInstance); + } + } + return (E_NODEV); +} diff --git a/src/spicelib/devices/numd/numddest.c b/src/spicelib/devices/numd/numddest.c new file mode 100644 index 000000000..38637dd41 --- /dev/null +++ b/src/spicelib/devices/numd/numddest.c @@ -0,0 +1,39 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This routine deletes all NUMDs from the circuit and frees all storage they + * were using. The current implementation has memory leaks. + */ + +#include "ngspice.h" +#include "numddefs.h" +#include "../../../ciderlib/oned/onedext.h" +#include "cidersupt.h" +#include "suffix.h" + +void +NUMDdestroy(inModel) + GENmodel **inModel; +{ + + NUMDmodel **model = (NUMDmodel **) inModel; + NUMDmodel *mod, *nextMod; + NUMDinstance *inst, *nextInst; + + + for (mod = *model; mod;) { + for (inst = mod->NUMDinstances; inst;) { + ONEdestroy(inst->NUMDpDevice); + nextInst = inst->NUMDnextInstance; + FREE(inst); + inst = nextInst; + } + nextMod = mod->NUMDnextModel; + FREE(mod); + mod = nextMod; + } + *model = NULL; +} diff --git a/src/spicelib/devices/numd/numddump.c b/src/spicelib/devices/numd/numddump.c new file mode 100644 index 000000000..731c9d34f --- /dev/null +++ b/src/spicelib/devices/numd/numddump.c @@ -0,0 +1,164 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +Author: 1991 David A. Gates, U. C. Berkeley CAD Group +**********/ + +/* + * This is a simple routine to dump the internal device states. It produces + * states for .OP, .DC, & .TRAN simulations. + */ + +#include "ngspice.h" +#include "cktdefs.h" +#include "numddefs.h" +#include "../../../ciderlib/oned/onedext.h" +#include "cidersupt.h" +#include "suffix.h" + + +/* Forward Declarations */ +static void NUMDputHeader(FILE *, CKTcircuit *, NUMDinstance *); + +/* State Counter */ +static int state_numOP = 0; +static int state_numDC = 0; +static int state_numTR = 0; + +void +NUMDdump(inModel, ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + register NUMDmodel *model = (NUMDmodel *) inModel; + register NUMDinstance *inst; + OUTPcard *output; + FILE *fpState; + char fileName[BSIZE_SP]; + char description[BSIZE_SP]; + char *prefix; + int *state_num; + int anyOutput = 0; + + if (ckt->CKTmode & MODEDCOP) { + prefix = "OP"; + state_num = &state_numOP; + sprintf(description, "..."); + } else if (ckt->CKTmode & MODEDCTRANCURVE) { + prefix = "DC"; + state_num = &state_numDC; + sprintf(description, "sweep = % e", ckt->CKTtime); + } else if (ckt->CKTmode & MODETRAN) { + prefix = "TR"; + state_num = &state_numTR; + sprintf(description, "time = % e", ckt->CKTtime); + } else { + /* Not a recognized CKT mode. */ + return; + } + + for (; model != NULL; model = model->NUMDnextModel) { + output = model->NUMDoutputs; + for (inst = model->NUMDinstances; inst != NULL; + inst = inst->NUMDnextInstance) { + if (inst->NUMDowner != ARCHme) continue; + + if (inst->NUMDprintGiven) { + if ((ckt->CKTmode & MODETRAN) && + ((ckt->CKTstat->STATaccepted - 1) % inst->NUMDprint != 0)) { + continue; + } + anyOutput = 1; + sprintf(fileName, "%s%s.%d.%s", output->OUTProotFile, prefix, + *state_num, inst->NUMDname); + if (!(fpState = fopen(fileName, "w"))) { + perror(fileName); + } else { + NUMDputHeader(fpState, ckt, inst); + ONEprnSolution(fpState, inst->NUMDpDevice, + model->NUMDoutputs); + fclose(fpState); + LOGmakeEntry(fileName, description); + } + } + } + } + if (anyOutput) { + (*state_num)++; + } +} + +#define NUMDnumOutputs 4 + +static +void +NUMDputHeader(file, ckt, inst) + FILE *file; + CKTcircuit *ckt; + NUMDinstance *inst; +{ + char *reference; + double refVal = 0.0; + int numVars = NUMDnumOutputs; + + if (ckt->CKTmode & MODEDCOP) { + reference = NULL; + } else if (ckt->CKTmode & MODEDCTRANCURVE) { + reference = "sweep"; + refVal = ckt->CKTtime; + numVars++; + } else if (ckt->CKTmode & MODETRAN) { + reference = "time"; + refVal = ckt->CKTtime; + numVars++; + } else { + reference = NULL; + } + fprintf(file, "Title: Device %s external state\n", inst->NUMDname); + fprintf(file, "Plotname: Device Operating Point\n"); + fprintf(file, "Command: deftype v conductance S\n"); + fprintf(file, "Flags: real\n"); + fprintf(file, "No. Variables: %d\n", numVars); + fprintf(file, "No. Points: 1\n"); + numVars = 0; + fprintf(file, "Variables:\n"); + if (reference) { + fprintf(file, "\t%d %s unknown\n", numVars++, reference); + } + fprintf(file, "\t%d v12 voltage\n", numVars++); + fprintf(file, "\t%d i1 current\n", numVars++); + fprintf(file, "\t%d i2 current\n", numVars++); + fprintf(file, "\t%d g11 conductance\n", numVars++); + fprintf(file, "Values:\n0"); + if (reference) { + fprintf(file, "\t% e\n", refVal); + } + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NUMDvoltage)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NUMDid)); + fprintf(file, "\t% e\n", - *(ckt->CKTstate0 + inst->NUMDid)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NUMDconduct)); +} + +void +NUMDacct(inModel, ckt, file) + GENmodel *inModel; + CKTcircuit *ckt; + FILE *file; +{ + register NUMDmodel *model = (NUMDmodel *) inModel; + register NUMDinstance *inst; + OUTPcard *output; + + for (; model != NULL; model = model->NUMDnextModel) { + output = model->NUMDoutputs; + for (inst = model->NUMDinstances; inst != NULL; + inst = inst->NUMDnextInstance) { + if (inst->NUMDowner != ARCHme) continue; + + if (output->OUTPstats) { + ONEmemStats(file, inst->NUMDpDevice); + ONEcpuStats(file, inst->NUMDpDevice); + } + } + } +} diff --git a/src/spicelib/devices/numd/numdext.h b/src/spicelib/devices/numd/numdext.h new file mode 100644 index 000000000..bf98dcd48 --- /dev/null +++ b/src/spicelib/devices/numd/numdext.h @@ -0,0 +1,27 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Karti Mayaram +**********/ + +#ifndef NUMDEXT_H +#define NUMDEXT_H + + +extern int NUMDacLoad(GENmodel *, CKTcircuit *); +extern int NUMDask(CKTcircuit *, GENinstance *, int, IFvalue *, IFvalue *); +extern int NUMDdelete(GENmodel *, IFuid, GENinstance **); +extern void NUMDdestroy(GENmodel **); +extern int NUMDgetic(GENmodel *, CKTcircuit *); +extern int NUMDload(GENmodel *, CKTcircuit *); +extern int NUMDmDelete(GENmodel **, IFuid, GENmodel *); +extern int NUMDmParam(int, IFvalue *, GENmodel *); +extern int NUMDparam(int, IFvalue *, GENinstance *, IFvalue *); +extern int NUMDpzLoad(GENmodel *, CKTcircuit *, SPcomplex *); +extern int NUMDsetup(SMPmatrix *, GENmodel *, CKTcircuit *, int *); +extern int NUMDtemp(GENmodel *, CKTcircuit *); +extern int NUMDtrunc(GENmodel *, CKTcircuit *, double *); + +extern void NUMDdump(GENmodel *, CKTcircuit *); +extern void NUMDacct(GENmodel *, CKTcircuit *, FILE *); + +#endif /* NUMDEXT_H */ diff --git a/src/spicelib/devices/numd/numdinit.c b/src/spicelib/devices/numd/numdinit.c new file mode 100644 index 000000000..18c48f93c --- /dev/null +++ b/src/spicelib/devices/numd/numdinit.c @@ -0,0 +1,83 @@ +#include + +#include + +#include "numditf.h" +#include "numdext.h" +#include "numdinit.h" + + +SPICEdev NUMDinfo = { + { + "NUMD", + "1D Numerical Junction Diode model", + + &NUMDnSize, + &NUMDnSize, + NUMDnames, + + &NUMDpTSize, + NUMDpTable, + + &NUMDmPTSize, + NUMDmPTable, + +#ifdef XSPICE +/*---- Fixed by SDB 5.2.2003 to enable XSPICE/tclspice integration -----*/ + NULL, /* This is a SPICE device, it has no MIF info data */ + + 0, /* This is a SPICE device, it has no MIF info data */ + NULL, /* This is a SPICE device, it has no MIF info data */ + + 0, /* This is a SPICE device, it has no MIF info data */ + NULL, /* This is a SPICE device, it has no MIF info data */ + + 0, /* This is a SPICE device, it has no MIF info data */ + NULL, /* This is a SPICE device, it has no MIF info data */ +/*--------------------------- End of SDB fix -------------------------*/ +#endif + + DEV_DEFAULT + }, + + DEVparam : NUMDparam, + DEVmodParam : NUMDmParam, + DEVload : NUMDload, + DEVsetup : NUMDsetup, + DEVunsetup : NULL, + DEVpzSetup : NUMDsetup, + DEVtemperature: NUMDtemp, + DEVtrunc : NUMDtrunc, + DEVfindBranch : NULL, + DEVacLoad : NUMDacLoad, + DEVaccept : NULL, + DEVdestroy : NUMDdestroy, + DEVmodDelete : NUMDmDelete, + DEVdelete : NUMDdelete, + DEVsetic : NULL, + DEVask : NUMDask, + DEVmodAsk : NULL, + DEVpzLoad : NUMDpzLoad, + DEVconvTest : NULL, + DEVsenSetup : NULL, + DEVsenLoad : NULL, + DEVsenUpdate : NULL, + DEVsenAcLoad : NULL, + DEVsenPrint : NULL, + DEVsenTrunc : NULL, + DEVdisto : NULL, + DEVnoise : NULL, + DEVdump : NUMDdump, + DEVacct : NUMDacct, + + DEVinstSize : &NUMDiSize, + DEVmodSize : &NUMDmSize + +}; + + +SPICEdev * +get_numd_info(void) +{ + return &NUMDinfo; +} diff --git a/src/spicelib/devices/numd/numdinit.h b/src/spicelib/devices/numd/numdinit.h new file mode 100644 index 000000000..ac1ad767a --- /dev/null +++ b/src/spicelib/devices/numd/numdinit.h @@ -0,0 +1,13 @@ +#ifndef _NUMDINIT_H +#define _NUMDINIT_H + +extern IFparm NUMDpTable[ ]; +extern IFparm NUMDmPTable[ ]; +extern char *NUMDnames[ ]; +extern int NUMDpTSize; +extern int NUMDmPTSize; +extern int NUMDnSize; +extern int NUMDiSize; +extern int NUMDmSize; + +#endif diff --git a/src/spicelib/devices/numd/numditf.h b/src/spicelib/devices/numd/numditf.h new file mode 100644 index 000000000..3475aa874 --- /dev/null +++ b/src/spicelib/devices/numd/numditf.h @@ -0,0 +1,10 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +**********/ + +#ifndef DEV_NUMD +#define DEV_NUMD + +extern SPICEdev *get_numd_info(void); + +#endif diff --git a/src/spicelib/devices/numd/numdload.c b/src/spicelib/devices/numd/numdload.c new file mode 100644 index 000000000..677aa66cf --- /dev/null +++ b/src/spicelib/devices/numd/numdload.c @@ -0,0 +1,393 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "devdefs.h" +#include "cktdefs.h" +#include "numddefs.h" +#include "numenum.h" +#include "trandefs.h" +#include "complex.h" +#include "sperror.h" +#include "../../../ciderlib/oned/onedext.h" +#include "cidersupt.h" +#include "suffix.h" + + + +/* Forward declarations */ +int NUMDinitSmSig(NUMDinstance *); + +/* External Declarations */ +extern int ONEdcDebug; +extern int ONEtranDebug; +extern int ONEacDebug; + + +int +NUMDload(inModel, ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + register NUMDmodel *model = (NUMDmodel *) inModel; + register NUMDinstance *inst; + register ONEdevice *pDevice; + double startTime, startTime2, totalTime, totalTime2; + double tol; /* temporary for tolerance calculations */ + double id; + double ideq; + double idhat = 0.0; + double delVd; + double vd; /* current diode voltage */ + double gd; + double xfact; + int check; + int i; + double deltaNorm[7]; + int devConverged = FALSE; + int numDevNonCon; + int deviceType; + int doInitSolve; + int doVoltPred; + char *initStateName; + + /* loop through all the diode models */ + for (; model != NULL; model = model->NUMDnextModel) { + /* Do model things */ + FieldDepMobility = model->NUMDmodels->MODLfieldDepMobility; + Srh = model->NUMDmodels->MODLsrh; + Auger = model->NUMDmodels->MODLauger; + AvalancheGen = model->NUMDmodels->MODLavalancheGen; + MobDeriv = model->NUMDmethods->METHmobDeriv; + MaxIterations = model->NUMDmethods->METHitLim; + ONEdcDebug = model->NUMDoutputs->OUTPdcDebug; + ONEtranDebug = model->NUMDoutputs->OUTPtranDebug; + ONEacDebug = model->NUMDoutputs->OUTPacDebug; + deviceType = model->NUMDoptions->OPTNdeviceType; + doVoltPred = model->NUMDmethods->METHvoltPred; + + if (ckt->CKTmode & MODEINITPRED) { + /* compute normalized deltas and predictor coeff */ + if (!(ckt->CKTmode & MODEDCTRANCURVE)) { + model->NUMDpInfo->order = ckt->CKTorder; + model->NUMDpInfo->method = ckt->CKTintegrateMethod; + for (i = 0; i <= ckt->CKTmaxOrder; i++) { + deltaNorm[i] = ckt->CKTdeltaOld[i] / TNorm; + } + computeIntegCoeff(ckt->CKTintegrateMethod, ckt->CKTorder, + model->NUMDpInfo->intCoeff, deltaNorm); + computePredCoeff(ckt->CKTintegrateMethod, ckt->CKTorder, + model->NUMDpInfo->predCoeff, deltaNorm); + } + } else if (ckt->CKTmode & MODEINITTRAN) { + model->NUMDpInfo->order = ckt->CKTorder; + model->NUMDpInfo->method = ckt->CKTintegrateMethod; + for (i = 0; i <= ckt->CKTmaxOrder; i++) { + deltaNorm[i] = ckt->CKTdeltaOld[i] / TNorm; + } + computeIntegCoeff(ckt->CKTintegrateMethod, ckt->CKTorder, + model->NUMDpInfo->intCoeff, deltaNorm); + } + /* Now do instance things */ + for (inst = model->NUMDinstances; inst != NULL; + inst = inst->NUMDnextInstance) { + if (inst->NUMDowner != ARCHme) continue; + + pDevice = inst->NUMDpDevice; + + totalTime = 0.0; + startTime = SPfrontEnd->IFseconds(); + + /* Get Temp.-Dep. Global Parameters */ + GLOBgetGlobals(&(inst->NUMDglobals)); + + /* + * this routine loads diodes for dc and transient analyses. + */ + pDevice->devStates = ckt->CKTstates; + /* + * initialization + */ + check = 1; + doInitSolve = FALSE; + initStateName = NULL; + if (ckt->CKTmode & MODEINITSMSIG) { + vd = *(ckt->CKTstate0 + inst->NUMDvoltage); + delVd = 0.0; + NUMDsetBCs(pDevice, vd); + } else if (ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate0 + inst->NUMDvoltage) = + *(ckt->CKTstate1 + inst->NUMDvoltage); + vd = *(ckt->CKTstate1 + inst->NUMDvoltage); + ONEsaveState(pDevice); + delVd = 0.0; + } else if ((ckt->CKTmode & MODEINITJCT) && + (ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) { + doInitSolve = TRUE; + initStateName = inst->NUMDicFile; + vd = 0.0; + delVd = vd; + } else if ((ckt->CKTmode & MODEINITJCT) && inst->NUMDoff) { + doInitSolve = TRUE; + vd = 0.0; + delVd = vd; + } else if (ckt->CKTmode & MODEINITJCT) { + doInitSolve = TRUE; + initStateName = inst->NUMDicFile; + if (deviceType == OPTN_DIODE) { + vd = inst->NUMDtype * 0.5; + } else if (deviceType == OPTN_MOSCAP) { + vd = inst->NUMDtype * 0.8; + } else { + vd = 0.0; + } + delVd = vd; + } else if (ckt->CKTmode & MODEINITFIX && inst->NUMDoff) { + vd = 0.0; + delVd = vd; + } else { + if (ckt->CKTmode & MODEINITPRED) { + *(ckt->CKTstate0 + inst->NUMDvoltage) = + *(ckt->CKTstate1 + inst->NUMDvoltage); + *(ckt->CKTstate0 + inst->NUMDid) = + *(ckt->CKTstate1 + inst->NUMDid); + *(ckt->CKTstate0 + inst->NUMDconduct) = + *(ckt->CKTstate1 + inst->NUMDconduct); + /* compute the normalized deltas */ + if (!(ckt->CKTmode & MODEDCTRANCURVE)) { + /* no linear prediction on device voltages */ + vd = *(ckt->CKTstate1 + inst->NUMDvoltage); + ONEpredict(pDevice, model->NUMDpInfo); + } else { + if (doVoltPred) { + /* linear prediction */ + xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1]; + vd = (1+xfact) * (*(ckt->CKTstate1 + inst->NUMDvoltage)) + - (xfact) * (*(ckt->CKTstate2 + inst->NUMDvoltage)); + } else { + vd = *(ckt->CKTstate1 + inst->NUMDvoltage); + } + } + } else { + vd = *(ckt->CKTrhsOld + inst->NUMDposNode) - + *(ckt->CKTrhsOld + inst->NUMDnegNode); + } + delVd = vd - *(ckt->CKTstate0 + inst->NUMDvoltage); + idhat = *(ckt->CKTstate0 + inst->NUMDid) + + *(ckt->CKTstate0 + inst->NUMDconduct) * delVd; + /* + * bypass if solution has not changed + */ + if ((ckt->CKTbypass) && pDevice->converged && + !(ckt->CKTmode & MODEINITPRED)) { + tol = ckt->CKTvoltTol + ckt->CKTreltol * + MAX(fabs(vd), fabs(*(ckt->CKTstate0 + inst->NUMDvoltage))); + if (fabs(delVd) < tol) { + tol = ckt->CKTreltol * + MAX(fabs(idhat), fabs(*(ckt->CKTstate0 + inst->NUMDid))) + + ckt->CKTabstol; + if (fabs(idhat - *(ckt->CKTstate0 + inst->NUMDid)) + < tol) { + vd = *(ckt->CKTstate0 + inst->NUMDvoltage); + id = *(ckt->CKTstate0 + inst->NUMDid); + gd = *(ckt->CKTstate0 + inst->NUMDconduct); + goto load; + } + } + } + /* + * limit new junction voltage + */ + if (deviceType == OPTN_DIODE) { + vd = inst->NUMDtype * limitJunctionVoltage(inst->NUMDtype * vd, + inst->NUMDtype * *(ckt->CKTstate0 + inst->NUMDvoltage), &check); + } else if (deviceType == OPTN_MOSCAP) { + vd = inst->NUMDtype * limitVgb(inst->NUMDtype * vd, + inst->NUMDtype * *(ckt->CKTstate0 + inst->NUMDvoltage), &check); + } else { + vd = inst->NUMDtype * limitResistorVoltage(inst->NUMDtype * vd, + inst->NUMDtype * *(ckt->CKTstate0 + inst->NUMDvoltage), &check); + } + delVd = vd - *(ckt->CKTstate0 + inst->NUMDvoltage); + } + if (doInitSolve) { + if (ONEdcDebug) { + printVoltages(stdout, model->NUMDmodName, inst->NUMDname, + deviceType, 1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + } + startTime2 = SPfrontEnd->IFseconds(); + ONEequilSolve(pDevice); + totalTime2 = SPfrontEnd->IFseconds() - startTime2; + pDevice->pStats->totalTime[STAT_SETUP] += totalTime2; + pDevice->pStats->totalTime[STAT_DC] -= totalTime2; + + ONEbiasSolve(pDevice, MaxIterations, FALSE, NULL); + + *(ckt->CKTstate0 + inst->NUMDvoltage) = 0.0; + + if (initStateName != NULL) { + if (ONEreadState(pDevice, initStateName, 1, &vd, NULL ) < 0) { + fprintf(stderr, + "NUMDload: trouble reading state-file %s\n", initStateName); + } else { + NUMDsetBCs(pDevice, vd); + delVd = 0.0; + } + } + } + /* + * compute dc current and derivatives + */ + /* use the routines for numerical simulation */ + + if (ckt->CKTmode & (MODEDCOP | MODETRANOP | MODEDCTRANCURVE | MODEINITSMSIG)) { + numDevNonCon = 0; + inst->NUMDc11 = inst->NUMDy11r = inst->NUMDy11i = 0.0; + inst->NUMDsmSigAvail = FALSE; + devNonCon: + NUMDproject(pDevice, delVd); + if (ONEdcDebug) { + printVoltages(stdout, model->NUMDmodName, inst->NUMDname, + deviceType, 1, vd, delVd, 0.0, 0.0, 0.0, 0.0); + } + ONEbiasSolve(pDevice, MaxIterations, FALSE, NULL); + devConverged = pDevice->converged; + if (devConverged && finite(pDevice->rhsNorm)) { + /* Get the current and conductance information. */ + NUMDcurrent(pDevice, FALSE, (double *) NULL, &id); + NUMDconductance(pDevice, FALSE, (double *) NULL, &gd); + } else { + /* reduce the voltage step until converged */ + /* restore the boundary potential to previous value */ + NUMDsetBCs(pDevice, vd - delVd); + ONEstoreInitialGuess(pDevice); + ONEresetJacobian(pDevice); + delVd *= 0.5; + vd = delVd + *(ckt->CKTstate0 + inst->NUMDvoltage); + numDevNonCon++; + check = 1; + if (numDevNonCon > 10) { + printVoltages(stderr, model->NUMDmodName, inst->NUMDname, + deviceType, 1, vd, delVd, 0.0, 0.0, 0.0, 0.0); + fprintf(stderr, "*** Non-convergence during load ***\n"); + totalTime += SPfrontEnd->IFseconds() - startTime; + pDevice->pStats->totalTime[STAT_DC] += totalTime; + ckt->CKTtroubleElt = (GENinstance *) inst; + return (E_BADMATRIX); + } else { + goto devNonCon; + } + } + } + if ((ckt->CKTmode & (MODETRAN | MODEAC | MODEINITSMSIG)) || + (ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) { + /* + * store small-signal parameters + */ + if ((!(ckt->CKTmode & MODETRANOP)) || (!(ckt->CKTmode & MODEUIC))) { + if (ckt->CKTmode & MODEINITSMSIG) { + totalTime = SPfrontEnd->IFseconds() - startTime; + pDevice->pStats->totalTime[STAT_DC] += totalTime; + startTime2 = SPfrontEnd->IFseconds(); + NUMDinitSmSig(inst); + pDevice->pStats->totalTime[STAT_AC] += + SPfrontEnd->IFseconds() - startTime2; + continue; + } else { + inst->NUMDsmSigAvail = FALSE; + } + /* + * transient analysis + */ + if (ckt->CKTmode & MODEINITPRED) { + NUMDsetBCs(pDevice, vd); + ONEstoreInitialGuess(pDevice); + } else { + NUMDupdate(pDevice, delVd, TRUE); + } + if (ONEtranDebug) { + printVoltages(stdout, model->NUMDmodName, inst->NUMDname, + deviceType, 1, vd, delVd, 0.0, 0.0, 0.0, 0.0); + } + + ONEbiasSolve(pDevice, 0, TRUE, model->NUMDpInfo); + + if (!finite(pDevice->rhsNorm)) { + totalTime += SPfrontEnd->IFseconds() - startTime; + pDevice->pStats->totalTime[STAT_TRAN] += totalTime; + ckt->CKTtroubleElt = (GENinstance *) inst; + return (E_BADMATRIX); + } + + pDevice->converged = devConverged = ONEdeviceConverged(pDevice); + + /* extract the current and conductance information */ + NUMDcurrent(pDevice, TRUE, model->NUMDpInfo->intCoeff, &id); + NUMDconductance(pDevice, TRUE, model->NUMDpInfo->intCoeff, &gd); + } + } + /* + * check convergence + */ + if ((!(ckt->CKTmode & MODEINITFIX)) || (!(inst->NUMDoff))) { + if (check == 1 || !devConverged) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) inst; + } else { + tol = ckt->CKTreltol * MAX(fabs(idhat), fabs(id)) + ckt->CKTabstol; + if (fabs(idhat - id) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) inst; + } + } + } + *(ckt->CKTstate0 + inst->NUMDvoltage) = vd; + *(ckt->CKTstate0 + inst->NUMDid) = id; + *(ckt->CKTstate0 + inst->NUMDconduct) = gd; + + load: + + /* + * load current vector + */ + + ideq = id - gd * vd; + *(ckt->CKTrhs + inst->NUMDnegNode) += ideq; + *(ckt->CKTrhs + inst->NUMDposNode) -= ideq; + + /* + * load matrix + */ + *(inst->NUMDposPosPtr) += gd; + *(inst->NUMDnegNegPtr) += gd; + *(inst->NUMDnegPosPtr) -= gd; + *(inst->NUMDposNegPtr) -= gd; + + totalTime += SPfrontEnd->IFseconds() - startTime; + if (ckt->CKTmode & MODETRAN) { + pDevice->pStats->totalTime[STAT_TRAN] += totalTime; + } else { + pDevice->pStats->totalTime[STAT_DC] += totalTime; + } + } + } + return (OK); +} + +int +NUMDinitSmSig(inst) + NUMDinstance *inst; +{ + SPcomplex yd; + double omega = inst->NUMDmodPtr->NUMDmethods->METHomega; + + AcAnalysisMethod = SOR_ONLY; + (void) NUMDadmittance(inst->NUMDpDevice, omega, &yd); + inst->NUMDc11 = yd.imag / omega; + inst->NUMDy11r = yd.real; + inst->NUMDy11i = yd.imag; + inst->NUMDsmSigAvail = TRUE; + return (OK); +} diff --git a/src/spicelib/devices/numd/numdmdel.c b/src/spicelib/devices/numd/numdmdel.c new file mode 100644 index 000000000..685f94e0e --- /dev/null +++ b/src/spicelib/devices/numd/numdmdel.c @@ -0,0 +1,43 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "numddefs.h" +#include "sperror.h" +#include "suffix.h" + +int +NUMDmDelete(inModel, modname, kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; +{ + + NUMDmodel **model = (NUMDmodel **) inModel; + NUMDmodel *modfast = (NUMDmodel *) kill; + NUMDinstance *inst; + NUMDinstance *prev = NULL; + NUMDmodel **oldmod; + oldmod = model; + for (; *model; model = &((*model)->NUMDnextModel)) { + if ((*model)->NUMDmodName == modname || + (modfast && *model == modfast)) + goto delgot; + oldmod = model; + } + return (E_NOMOD); + +delgot: + *oldmod = (*model)->NUMDnextModel; /* cut deleted device out of list */ + for (inst = (*model)->NUMDinstances; inst; inst = inst->NUMDnextInstance) { + if (prev) + FREE(prev); + prev = inst; + } + if (prev) + FREE(prev); + FREE(*model); + return (OK); +} diff --git a/src/spicelib/devices/numd/numdmpar.c b/src/spicelib/devices/numd/numdmpar.c new file mode 100644 index 000000000..be5ad11ae --- /dev/null +++ b/src/spicelib/devices/numd/numdmpar.c @@ -0,0 +1,32 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This routine sets model parameters for NUMDs in the circuit. + */ + +#include "ngspice.h" +#include "const.h" +#include "ifsim.h" +#include "numddefs.h" +#include "sperror.h" +#include "suffix.h" + +int +NUMDmParam(param, value, inModel) + int param; + IFvalue *value; + GENmodel *inModel; +{ + switch (param) { + case NUMD_MOD_NUMD: + /* no action - already know it is a 1d-numerical diode, but this */ + /* makes life easier for spice-2 like parsers */ + break; + default: + return (E_BADPARM); + } + return (OK); +} diff --git a/src/spicelib/devices/numd/numdparm.c b/src/spicelib/devices/numd/numdparm.c new file mode 100644 index 000000000..85534a489 --- /dev/null +++ b/src/spicelib/devices/numd/numdparm.c @@ -0,0 +1,45 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "ifsim.h" +#include "const.h" +#include "numddefs.h" +#include "sperror.h" +#include "suffix.h" + +int +NUMDparam(param, value, inInst, select) + int param; + IFvalue *value; + GENinstance *inInst; + IFvalue *select; +{ + NUMDinstance *inst = (NUMDinstance *) inInst; + switch (param) { + case NUMD_AREA: + inst->NUMDarea = value->rValue; + inst->NUMDareaGiven = TRUE; + break; + case NUMD_OFF: + inst->NUMDoff = TRUE; + break; + case NUMD_IC_FILE: + inst->NUMDicFile = value->sValue; + inst->NUMDicFileGiven = TRUE; + break; + case NUMD_PRINT: + inst->NUMDprint = value->rValue; + inst->NUMDprintGiven = TRUE; + break; + case NUMD_TEMP: + inst->NUMDtemp = value->rValue + CONSTCtoK; + inst->NUMDtempGiven = TRUE; + break; + default: + return (E_BADPARM); + } + return (OK); +} diff --git a/src/spicelib/devices/numd/numdpzld.c b/src/spicelib/devices/numd/numdpzld.c new file mode 100644 index 000000000..e07934505 --- /dev/null +++ b/src/spicelib/devices/numd/numdpzld.c @@ -0,0 +1,63 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "cktdefs.h" +#include "complex.h" +#include "sperror.h" +#include "numddefs.h" +#include "../../../ciderlib/oned/onedext.h" +#include "cidersupt.h" +#include "suffix.h" + +/* External Declarations */ +extern int ONEacDebug; + +int +NUMDpzLoad(inModel, ckt, s) + GENmodel *inModel; + register CKTcircuit *ckt; + SPcomplex *s; +{ + register NUMDmodel *model = (NUMDmodel *) inModel; + register NUMDinstance *inst; + SPcomplex y; + double startTime; + + /* loop through all the diode models */ + for (; model != NULL; model = model->NUMDnextModel) { + FieldDepMobility = model->NUMDmodels->MODLfieldDepMobility; + Srh = model->NUMDmodels->MODLsrh; + Auger = model->NUMDmodels->MODLauger; + AvalancheGen = model->NUMDmodels->MODLavalancheGen; + AcAnalysisMethod = model->NUMDmethods->METHacAnalysisMethod; + MobDeriv = model->NUMDmethods->METHmobDeriv; + ONEacDebug = model->NUMDoutputs->OUTPacDebug; + + for (inst = model->NUMDinstances; inst != NULL; + inst = inst->NUMDnextInstance) { + if (inst->NUMDowner != ARCHme) continue; + + startTime = SPfrontEnd->IFseconds(); + /* Get Temp.-Dep. Global Parameters */ + GLOBgetGlobals(&(inst->NUMDglobals)); + + NUMDys(inst->NUMDpDevice, s, &y); + + *(inst->NUMDposPosPtr) += y.real; + *(inst->NUMDposPosPtr + 1) += y.imag; + *(inst->NUMDnegNegPtr) += y.real; + *(inst->NUMDnegNegPtr + 1) += y.imag; + *(inst->NUMDnegPosPtr) -= y.real; + *(inst->NUMDnegPosPtr + 1) -= y.imag; + *(inst->NUMDposNegPtr) -= y.real; + *(inst->NUMDposNegPtr + 1) -= y.imag; + + inst->NUMDpDevice->pStats->totalTime[STAT_AC] += + SPfrontEnd->IFseconds() - startTime; + } + } + return (OK); +} diff --git a/src/spicelib/devices/numd/numdset.c b/src/spicelib/devices/numd/numdset.c new file mode 100644 index 000000000..23b58af25 --- /dev/null +++ b/src/spicelib/devices/numd/numdset.c @@ -0,0 +1,235 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "cktdefs.h" +#include "smpdefs.h" +#include "numddefs.h" +#include "numconst.h" +#include "numenum.h" +#include "sperror.h" +#include "../../../ciderlib/oned/onedext.h" +#include "cidersupt.h" +#include "ciderinp.h" +#include "suffix.h" + +#define NIL(type) ((type *)0) +#define TSCALLOC(var, size, type)\ +if (size && (!(var =(type *)calloc(1, (unsigned)(size)*sizeof(type))))) {\ + return(E_NOMEM);\ +} + + +int +NUMDsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) +/* + * load the structure with those pointers needed later for fast matrix + * loading + */ +{ + register NUMDmodel *model = (NUMDmodel *) inModel; + register NUMDinstance *inst; + METHcard *methods; + MODLcard *models; + OPTNcard *options; + OUTPcard *outputs; + char *icFileName = NULL; + int nameLen; + int error; + int xMeshSize; + ONEdevice *pDevice; + ONEcoord *xCoordList = NIL(ONEcoord); + ONEdomain *domainList = NIL(ONEdomain); + ONEmaterial *pM, *pMaterial = NIL(ONEmaterial), *materialList = NIL(ONEmaterial); + DOPprofile *profileList = NIL(DOPprofile); + DOPtable *dopTableList = NIL(DOPtable); + double startTime; + + + /* loop through all the models */ + for (; model != NULL; model = model->NUMDnextModel) { + if (!model->NUMDpInfo) { + TSCALLOC(model->NUMDpInfo, 1, ONEtranInfo); + } + methods = model->NUMDmethods; + if (!methods) { + TSCALLOC(methods, 1, METHcard); + model->NUMDmethods = methods; + } + models = model->NUMDmodels; + if (!models) { + TSCALLOC(models, 1, MODLcard); + model->NUMDmodels = models; + } + options = model->NUMDoptions; + if (!options) { + TSCALLOC(options, 1, OPTNcard); + model->NUMDoptions = options; + } + outputs = model->NUMDoutputs; + if (!outputs) { + TSCALLOC(outputs, 1, OUTPcard); + model->NUMDoutputs = outputs; + } + if (!methods->METHvoltPredGiven) { + methods->METHvoltPred = FALSE; + } + if (!methods->METHmobDerivGiven) { + methods->METHmobDeriv = TRUE; + } + if (!methods->METHoneCarrierGiven) { + methods->METHoneCarrier = FALSE; + } + if (!methods->METHacAnalysisMethodGiven) { + methods->METHacAnalysisMethod = SOR; + } + if (!methods->METHdabstolGiven) { + methods->METHdabstol = DABSTOL1D; + } + if (!methods->METHdreltolGiven) { + methods->METHdreltol = ckt->CKTreltol; + } + if (!methods->METHitLimGiven) { + methods->METHitLim = 20; + } + if (!methods->METHomegaGiven || methods->METHomega <= 0.0) { + methods->METHomega = 2.0 * M_PI /* radians/sec */ ; + } + if (!options->OPTNdefaGiven || options->OPTNdefa <= 0.0) { + options->OPTNdefa = 1.0e4 /* cm^2 */ ; + } + if (!options->OPTNdeviceTypeGiven) { + options->OPTNdeviceType = OPTN_DIODE; + } + if (!options->OPTNicFileGiven) { + options->OPTNicFile = NULL; + options->OPTNunique = FALSE; /* Can't form a unique name. */ + } + if (!options->OPTNuniqueGiven) { + options->OPTNunique = FALSE; + } + + /* Set up the rest of the card lists */ + if ((error = MODLsetup(model->NUMDmodels))) + return (error); + BandGapNarrowing = models->MODLbandGapNarrowing; + ConcDepLifetime = models->MODLconcDepLifetime; + TempDepMobility = models->MODLtempDepMobility; + ConcDepMobility = models->MODLconcDepMobility; + + if ((error = OUTPsetup(model->NUMDoutputs))) + return (error); + if ((error = MATLsetup(model->NUMDmaterials, &materialList))) + return (error); + if ((error = MOBsetup(model->NUMDmobility, materialList))) + return (error); + if ((error = MESHsetup('x', model->NUMDxMeshes, &xCoordList, &xMeshSize))) + return (error); + if ((error = DOMNsetup(model->NUMDdomains, &domainList, + xCoordList, NIL(ONEcoord), materialList))) + return (error); + if ((error = BDRYsetup(model->NUMDboundaries, + xCoordList, NIL(ONEcoord), domainList))) + return (error); + if ((error = CONTsetup(model->NUMDcontacts, NULL))) + return (error); + if ((error = DOPsetup(model->NUMDdopings, &profileList, + &dopTableList, xCoordList, NIL(ONEcoord)))) + return (error); + model->NUMDmatlInfo = materialList; + model->NUMDprofiles = profileList; + model->NUMDdopTables = dopTableList; + + /* loop through all the instances of the model */ + for (inst = model->NUMDinstances; inst != NULL; + inst = inst->NUMDnextInstance) { + if ((inst->NUMDowner != ARCHme)) goto matrixpointers; + + startTime = SPfrontEnd->IFseconds(); + + if ((!inst->NUMDprintGiven)) { + inst->NUMDprint = 0; + } else if (inst->NUMDprint <= 0) { + inst->NUMDprint = 1; + } + if ((!inst->NUMDicFileGiven)) { + if (options->OPTNunique) { + nameLen = strlen(options->OPTNicFile) + strlen(inst->NUMDname) + 1; + TSCALLOC(icFileName, nameLen+1, char); + sprintf(icFileName, "%s.%s", options->OPTNicFile, inst->NUMDname); + icFileName[nameLen] = '\0'; + inst->NUMDicFile = icFileName; + } else if (options->OPTNicFile != NULL) { + nameLen = strlen(options->OPTNicFile); + TSCALLOC(icFileName, nameLen+1, char); + icFileName = strcpy(icFileName, options->OPTNicFile); + inst->NUMDicFile = icFileName; + } else { + inst->NUMDicFile = NULL; + } + } + inst->NUMDstate = *states; + *states += NUMDnumStates; + + if (!inst->NUMDpDevice) { + /* Assign the mesh info to each instance. */ + TSCALLOC(pDevice, 1, ONEdevice); + TSCALLOC(pDevice->pStats, 1, ONEstats); + pDevice->name = inst->NUMDname; + pDevice->solverType = SLV_NONE; + pDevice->numNodes = xMeshSize; + pDevice->abstol = methods->METHdabstol; + pDevice->reltol = methods->METHdreltol; + pDevice->rhsImag = NIL(double); + TSCALLOC(pDevice->elemArray, pDevice->numNodes, ONEelem *); + + /* Create a copy of material data that can change with temperature. */ + pDevice->pMaterials = NIL(ONEmaterial); + for (pM = materialList; pM != NIL(ONEmaterial); pM = pM->next) { + if (pDevice->pMaterials == NIL(ONEmaterial)) { + TSCALLOC(pMaterial, 1, ONEmaterial); + pDevice->pMaterials = pMaterial; + } else { + TSCALLOC(pMaterial->next, 1, ONEmaterial); + pMaterial = pMaterial->next; + } + /* Copy everything, then fix the incorrect pointer. */ + bcopy((void *) pM, (void *) pMaterial, sizeof(ONEmaterial)); + pMaterial->next = NIL(ONEmaterial); + } + + /* generate the mesh structure for the device */ + ONEbuildMesh(pDevice, xCoordList, domainList, pDevice->pMaterials); + + /* store the device info in the instance */ + inst->NUMDpDevice = pDevice; + } + /* Now update the state pointers. */ + ONEgetStatePointers(inst->NUMDpDevice, states); + + /* Wipe out statistics from previous runs (if any). */ + bzero((void *) inst->NUMDpDevice->pStats, sizeof(ONEstats)); + + inst->NUMDpDevice->pStats->totalTime[STAT_SETUP] += + SPfrontEnd->IFseconds() - startTime; + + /* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if ((inst->ptr = SMPmakeElt(matrix,inst->first,inst->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + +matrixpointers: + TSTALLOC(NUMDposPosPtr, NUMDposNode, NUMDposNode) + TSTALLOC(NUMDnegNegPtr, NUMDnegNode, NUMDnegNode) + TSTALLOC(NUMDnegPosPtr, NUMDnegNode, NUMDposNode) + TSTALLOC(NUMDposNegPtr, NUMDposNode, NUMDnegNode) + } + /* Clean up lists */ + killCoordInfo(xCoordList); + killDomainInfo(domainList); + } + return (OK); +} diff --git a/src/spicelib/devices/numd/numdtemp.c b/src/spicelib/devices/numd/numdtemp.c new file mode 100644 index 000000000..79fd809e8 --- /dev/null +++ b/src/spicelib/devices/numd/numdtemp.c @@ -0,0 +1,133 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +Author: 1992 David A. Gates, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "cktdefs.h" +#include "numddefs.h" +#include "numenum.h" +#include "carddefs.h" +#include "sperror.h" +#include "../../../ciderlib/oned/onedext.h" +#include "cidersupt.h" +#include "suffix.h" + +#define NIL(type) ((type *)0) + +int +NUMDtemp(inModel, ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +/* + * perform the temperature update to the diode + */ +{ + register NUMDmodel *model = (NUMDmodel *) inModel; + register NUMDinstance *inst; + METHcard *methods; + MODLcard *models; + OPTNcard *options; + OUTPcard *outputs; + ONEmaterial *pM, *pMaterial, *pNextMaterial; + double startTime; + + + /* loop through all the diode models */ + for (; model != NULL; model = model->NUMDnextModel) { + methods = model->NUMDmethods; + models = model->NUMDmodels; + options = model->NUMDoptions; + outputs = model->NUMDoutputs; + + if (!options->OPTNtnomGiven) { + options->OPTNtnom = ckt->CKTnomTemp; + } + for (pM = model->NUMDmatlInfo; pM != NIL(ONEmaterial); pM = pM->next) { + pM->tnom = options->OPTNtnom; + } + + BandGapNarrowing = models->MODLbandGapNarrowing; + ConcDepLifetime = models->MODLconcDepLifetime; + TempDepMobility = models->MODLtempDepMobility; + ConcDepMobility = models->MODLconcDepMobility; + + for (inst = model->NUMDinstances; inst != NULL; + inst = inst->NUMDnextInstance) { + if (inst->NUMDowner != ARCHme) continue; + + startTime = SPfrontEnd->IFseconds(); + + if (!inst->NUMDtempGiven) { + inst->NUMDtemp = ckt->CKTtemp; + } + if (!inst->NUMDareaGiven || inst->NUMDarea <= 0.0) { + inst->NUMDarea = 1.0; + } + inst->NUMDpDevice->area = inst->NUMDarea * options->OPTNdefa; + + /* Compute and save globals for this instance. */ + GLOBcomputeGlobals(&(inst->NUMDglobals), inst->NUMDtemp); + if (outputs->OUTPglobals) { + GLOBprnGlobals(stdout, &(inst->NUMDglobals)); + } + /* Calculate new sets of material parameters. */ + pM = model->NUMDmatlInfo; + pMaterial = inst->NUMDpDevice->pMaterials; + for (; pM != NULL; pM = pM->next, pMaterial = pMaterial->next) { + + /* Copy the original values, then fix the incorrect pointer. */ + pNextMaterial = pMaterial->next; + bcopy((char *) pM, (char *) pMaterial, sizeof(ONEmaterial)); + pMaterial->next = pNextMaterial; + + /* Now do the temperature dependence. */ + MATLtempDep(pMaterial, pMaterial->tnom); + if (outputs->OUTPmaterial) { + printMaterialInfo(pMaterial); + } + } + + /* Assign doping to the mesh. */ + ONEsetDoping(inst->NUMDpDevice, model->NUMDprofiles, + model->NUMDdopTables); + + /* Assign other physical parameters to the mesh. */ + ONEsetup(inst->NUMDpDevice); + + /* Assign boundary condition parameters. */ + ONEsetBCparams(inst->NUMDpDevice, model->NUMDboundaries, + model->NUMDcontacts); + + /* Normalize everything. */ + ONEnormalize(inst->NUMDpDevice); + + /* Find the device's polarity type. */ + switch (options->OPTNdeviceType) { + case OPTN_DIODE: + if (inst->NUMDpDevice->elemArray[1] + ->pNodes[0]->netConc < 0.0) { + inst->NUMDtype = PN; + } else { + inst->NUMDtype = NP; + } + break; + case OPTN_MOSCAP: + if (inst->NUMDpDevice->elemArray[inst->NUMDpDevice->numNodes - 1] + ->pNodes[1]->netConc < 0.0) { + inst->NUMDtype = PN; + } else { + inst->NUMDtype = NP; + } + break; + default: + inst->NUMDtype = PN; + break; + } + inst->NUMDpDevice->pStats->totalTime[STAT_SETUP] += + SPfrontEnd->IFseconds() - startTime; + } + } + return (OK); +} diff --git a/src/spicelib/devices/numd/numdtrun.c b/src/spicelib/devices/numd/numdtrun.c new file mode 100644 index 000000000..6a29028ae --- /dev/null +++ b/src/spicelib/devices/numd/numdtrun.c @@ -0,0 +1,49 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "cktdefs.h" +#include "numddefs.h" +#include "sperror.h" +#include "../../../ciderlib/oned/onedext.h" +#include "suffix.h" +#include "cidersupt.h" + + + +int +NUMDtrunc(inModel, ckt, timeStep) + GENmodel *inModel; + register CKTcircuit *ckt; + double *timeStep; + +{ + register NUMDmodel *model = (NUMDmodel *) inModel; + register NUMDinstance *inst; + double deltaNew; + double deltaNorm[7]; + double startTime; + int i; + + for (i = 0; i <= ckt->CKTmaxOrder; i++) { + deltaNorm[i] = ckt->CKTdeltaOld[i] / TNorm; + } + for (; model != NULL; model = model->NUMDnextModel) { + model->NUMDpInfo->order = ckt->CKTorder; + model->NUMDpInfo->delta = deltaNorm; + model->NUMDpInfo->lteCoeff = computeLTECoeff(model->NUMDpInfo); + for (inst = model->NUMDinstances; inst != NULL; + inst = inst->NUMDnextInstance) { + if (inst->NUMDowner != ARCHme) continue; + + startTime = SPfrontEnd->IFseconds(); + deltaNew = ONEtrunc(inst->NUMDpDevice, model->NUMDpInfo, ckt->CKTdelta); + *timeStep = MIN(*timeStep, deltaNew); + inst->NUMDpDevice->pStats->totalTime[STAT_TRAN] += + SPfrontEnd->IFseconds() - startTime; + } + } + return (OK); +} diff --git a/src/spicelib/devices/numd2/Makefile.am b/src/spicelib/devices/numd2/Makefile.am new file mode 100644 index 000000000..07ea63847 --- /dev/null +++ b/src/spicelib/devices/numd2/Makefile.am @@ -0,0 +1,30 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libnumd2.a + +libnumd2_a_SOURCES = \ + nud2.c \ + nud2acld.c \ + nud2ask.c \ + numd2defs.h \ + nud2del.c \ + nud2dest.c \ + nud2dump.c \ + numd2ext.h \ + numd2init.c \ + numd2init.h \ + numd2itf.h \ + nud2load.c \ + nud2mdel.c \ + nud2mpar.c \ + nud2parm.c \ + nud2pzld.c \ + nud2set.c \ + nud2temp.c \ + nud2trun.c + + + +INCLUDES = -I$(top_srcdir)/src/include + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/numd2/nud2.c b/src/spicelib/devices/numd2/nud2.c new file mode 100644 index 000000000..a3b2fd2f6 --- /dev/null +++ b/src/spicelib/devices/numd2/nud2.c @@ -0,0 +1,59 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "devdefs.h" +#include "numd2def.h" +#include "suffix.h" + +/* + * This file defines the 2d Numerical Diode data structures that are + * available to the next level(s) up the calling hierarchy + */ + +IFparm NUMD2pTable[] = { /* parameters */ + IP("off", NUMD2_OFF, IF_FLAG, "Initially off"), + IP("ic.file", NUMD2_IC_FILE, IF_STRING, "Initial condition file"), + IOP("w", NUMD2_WIDTH, IF_REAL, "Width factor"), + IOP("area", NUMD2_AREA, IF_REAL, "Area factor"), + IP("save", NUMD2_PRINT, IF_REAL, "Save solutions"), + IP("print", NUMD2_PRINT, IF_REAL, "Print solutions"), + OP("vd", NUMD2_VD, IF_REAL, "Voltage"), + OP("id", NUMD2_ID, IF_REAL, "Current"), + OP("g11", NUMD2_G11, IF_REAL, "Conductance"), + OP("c11", NUMD2_C11, IF_REAL, "Capacitance"), + OP("y11", NUMD2_Y11, IF_COMPLEX, "Admittance"), + OPU("g12", NUMD2_G12, IF_REAL, "Conductance"), + OPU("c12", NUMD2_C12, IF_REAL, "Capacitance"), + OPU("y12", NUMD2_Y12, IF_COMPLEX, "Admittance"), + OPU("g21", NUMD2_G21, IF_REAL, "Conductance"), + OPU("c21", NUMD2_C21, IF_REAL, "Capacitance"), + OPU("y21", NUMD2_Y21, IF_COMPLEX, "Admittance"), + OPU("g22", NUMD2_G22, IF_REAL, "Conductance"), + OPU("c22", NUMD2_C22, IF_REAL, "Capacitance"), + OPU("y22", NUMD2_Y22, IF_COMPLEX, "Admittance"), + OPR("voltage", NUMD2_VD, IF_REAL, "Voltage"), + OPR("current", NUMD2_ID, IF_REAL, "Current"), + OPR("conductance", NUMD2_G11, IF_REAL, "Conductance"), + OPR("capacitance", NUMD2_C11, IF_REAL, "Capacitance"), + IOP("temp", NUMD2_TEMP, IF_REAL, "Instance Temperature") +}; + +IFparm NUMD2mPTable[] = { /* model parameters */ + /* numerical-device models no longer have parameters */ + /* one is left behind to keep the table from being empty */ + IP("numd", NUMD2_MOD_NUMD, IF_FLAG, "Numerical 2d-Diode Model") +}; + +char *NUMD2names[] = { + "Anode", + "Cathode" +}; + +int NUMD2nSize = NUMELEMS(NUMD2names); +int NUMD2pTSize = NUMELEMS(NUMD2pTable); +int NUMD2mPTSize = NUMELEMS(NUMD2mPTable); +int NUMD2iSize = sizeof(NUMD2instance); +int NUMD2mSize = sizeof(NUMD2model); diff --git a/src/spicelib/devices/numd2/nud2acld.c b/src/spicelib/devices/numd2/nud2acld.c new file mode 100644 index 000000000..0e4e11da1 --- /dev/null +++ b/src/spicelib/devices/numd2/nud2acld.c @@ -0,0 +1,80 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * Function to load the COMPLEX circuit matrix using the small signal + * parameters saved during a previous DC operating point analysis. + */ + +#include "ngspice.h" +#include "cktdefs.h" +#include "numd2def.h" +#include "sperror.h" +#include "complex.h" +#include "../../../ciderlib/twod/twoddefs.h" +#include "../../../ciderlib/twod/twodext.h" +#include "cidersupt.h" +#include "numglobs.h" +#include "suffix.h" + +/* External Declarations */ +extern int TWOacDebug; + +int +NUMD2acLoad(inModel, ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + register NUMD2model *model = (NUMD2model *) inModel; + register NUMD2instance *inst; + SPcomplex y; + double startTime; + + /* loop through all the diode models */ + for (; model != NULL; model = model->NUMD2nextModel) { + FieldDepMobility = model->NUMD2models->MODLfieldDepMobility; + TransDepMobility = model->NUMD2models->MODLtransDepMobility; + SurfaceMobility = model->NUMD2models->MODLsurfaceMobility; + Srh = model->NUMD2models->MODLsrh; + Auger = model->NUMD2models->MODLauger; + AvalancheGen = model->NUMD2models->MODLavalancheGen; + OneCarrier = model->NUMD2methods->METHoneCarrier; + AcAnalysisMethod = model->NUMD2methods->METHacAnalysisMethod; + MobDeriv = model->NUMD2methods->METHmobDeriv; + TWOacDebug = model->NUMD2outputs->OUTPacDebug; + + for (inst = model->NUMD2instances; inst != NULL; + inst = inst->NUMD2nextInstance) { + if (inst->NUMD2owner != ARCHme) continue; + + startTime = SPfrontEnd->IFseconds(); + /* Get Temp.-Dep. Global Parameters */ + GLOBgetGlobals(&(inst->NUMD2globals)); + + model->NUMD2methods->METHacAnalysisMethod = + NUMD2admittance(inst->NUMD2pDevice, ckt->CKTomega, &y); + + *(inst->NUMD2posPosPtr) += y.real; + *(inst->NUMD2posPosPtr + 1) += y.imag; + *(inst->NUMD2negNegPtr) += y.real; + *(inst->NUMD2negNegPtr + 1) += y.imag; + *(inst->NUMD2negPosPtr) -= y.real; + *(inst->NUMD2negPosPtr + 1) -= y.imag; + *(inst->NUMD2posNegPtr) -= y.real; + *(inst->NUMD2posNegPtr + 1) -= y.imag; + if (ckt->CKTomega != 0.0) { + inst->NUMD2c11 = y.imag / ckt->CKTomega; + } else { + inst->NUMD2c11 = 0.0; /* XXX What else can be done?! */ + } + inst->NUMD2y11r = y.real; + inst->NUMD2y11i = y.imag; + inst->NUMD2smSigAvail = TRUE; + inst->NUMD2pDevice->pStats->totalTime[STAT_AC] += + SPfrontEnd->IFseconds() - startTime; + } + } + return (OK); +} diff --git a/src/spicelib/devices/numd2/nud2ask.c b/src/spicelib/devices/numd2/nud2ask.c new file mode 100644 index 000000000..404cf7072 --- /dev/null +++ b/src/spicelib/devices/numd2/nud2ask.c @@ -0,0 +1,121 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include "const.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "numd2def.h" +#include "sperror.h" +#include "suffix.h" + + +/* Check out this one */ +extern int NUMD2initSmSig(NUMD2instance *); + +/* ARGSUSED */ +int +NUMD2ask(ckt, inInst, which, value, select) + CKTcircuit *ckt; + GENinstance *inInst; + int which; + IFvalue *value; + IFvalue *select; +{ + NUMD2instance *inst = (NUMD2instance *) inInst; + switch (which) { + case NUMD2_WIDTH: + value->rValue = inst->NUMD2width; + return (OK); + case NUMD2_AREA: + value->rValue = inst->NUMD2area; + break; + case NUMD2_TEMP: + value->rValue = inst->NUMD2temp - CONSTCtoK; + return (OK); + case NUMD2_VD: + value->rValue = *(ckt->CKTstate0 + inst->NUMD2voltage); + return (OK); + case NUMD2_ID: + value->rValue = *(ckt->CKTstate0 + inst->NUMD2id); + return (OK); + case NUMD2_G11: + value->rValue = *(ckt->CKTstate0 + inst->NUMD2conduct); + return (OK); + case NUMD2_G12: + value->rValue = -*(ckt->CKTstate0 + inst->NUMD2conduct); + return (OK); + case NUMD2_G21: + value->rValue = -*(ckt->CKTstate0 + inst->NUMD2conduct); + return (OK); + case NUMD2_G22: + value->rValue = *(ckt->CKTstate0 + inst->NUMD2conduct); + return (OK); + case NUMD2_C11: + if (!inst->NUMD2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMD2initSmSig(inst); + } + value->rValue = inst->NUMD2c11; + return (OK); + case NUMD2_C12: + if (!inst->NUMD2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMD2initSmSig(inst); + } + value->rValue = -inst->NUMD2c11; + return (OK); + case NUMD2_C21: + if (!inst->NUMD2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMD2initSmSig(inst); + } + value->rValue = -inst->NUMD2c11; + return (OK); + case NUMD2_C22: + if (!inst->NUMD2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMD2initSmSig(inst); + } + value->rValue = inst->NUMD2c11; + return (OK); + case NUMD2_Y11: + if (!inst->NUMD2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMD2initSmSig(inst); + } + value->cValue.real = inst->NUMD2y11r; + value->cValue.imag = inst->NUMD2y11i; + return (OK); + case NUMD2_Y12: + if (!inst->NUMD2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMD2initSmSig(inst); + } + value->cValue.real = -inst->NUMD2y11r; + value->cValue.imag = -inst->NUMD2y11i; + return (OK); + case NUMD2_Y21: + if (!inst->NUMD2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMD2initSmSig(inst); + } + value->cValue.real = -inst->NUMD2y11r; + value->cValue.imag = -inst->NUMD2y11i; + return (OK); + case NUMD2_Y22: + if (!inst->NUMD2smSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMD2initSmSig(inst); + } + value->cValue.real = inst->NUMD2y11r; + value->cValue.imag = inst->NUMD2y11i; + return (OK); + default: + return (E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/numd2/nud2del.c b/src/spicelib/devices/numd2/nud2del.c new file mode 100644 index 000000000..ffe80dd57 --- /dev/null +++ b/src/spicelib/devices/numd2/nud2del.c @@ -0,0 +1,34 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "numd2def.h" +#include "sperror.h" +#include "suffix.h" + +int +NUMD2delete(inModel, name, kill) + GENmodel *inModel; + IFuid name; + GENinstance **kill; +{ + NUMD2model *model = (NUMD2model *) inModel; + NUMD2instance **fast = (NUMD2instance **) kill; + NUMD2instance **prev = NULL; + NUMD2instance *inst; + + for (; model; model = model->NUMD2nextModel) { + prev = &(model->NUMD2instances); + for (inst = *prev; inst; inst = *prev) { + if (inst->NUMD2name == name || (fast && inst == *fast)) { + *prev = inst->NUMD2nextInstance; + FREE(inst); + return (OK); + } + prev = &(inst->NUMD2nextInstance); + } + } + return (E_NODEV); +} diff --git a/src/spicelib/devices/numd2/nud2dest.c b/src/spicelib/devices/numd2/nud2dest.c new file mode 100644 index 000000000..e84d9e387 --- /dev/null +++ b/src/spicelib/devices/numd2/nud2dest.c @@ -0,0 +1,40 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This routine deletes all NUMD2s from the circuit and frees all storage + * they were using. The current implementation has memory leaks. + */ + +#include "ngspice.h" +#include "numd2def.h" +#include "../../../ciderlib/twod/twoddefs.h" +#include "../../../ciderlib/twod/twodext.h" +#include "cidersupt.h" +#include "suffix.h" + +void +NUMD2destroy(inModel) + GENmodel **inModel; +{ + + NUMD2model **model = (NUMD2model **) inModel; + NUMD2model *mod, *nextMod; + NUMD2instance *inst, *nextInst; + + + for (mod = *model; mod;) { + for (inst = mod->NUMD2instances; inst;) { + TWOdestroy(inst->NUMD2pDevice); + nextInst = inst->NUMD2nextInstance; + FREE(inst); + inst = nextInst; + } + nextMod = mod->NUMD2nextModel; + FREE(mod); + mod = nextMod; + } + *model = NULL; +} diff --git a/src/spicelib/devices/numd2/nud2dump.c b/src/spicelib/devices/numd2/nud2dump.c new file mode 100644 index 000000000..89ea652ff --- /dev/null +++ b/src/spicelib/devices/numd2/nud2dump.c @@ -0,0 +1,165 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +Author: 1991 David A. Gates, U. C. Berkeley CAD Group +**********/ + +/* + * This is a simple routine to dump the internal device states. It produces + * states for .OP, .DC, & .TRAN simulations. + */ + +#include "ngspice.h" +#include "cktdefs.h" +#include "numd2def.h" +#include "../../../ciderlib/twod/twoddefs.h" +#include "../../../ciderlib/twod/twodext.h" +#include "cidersupt.h" +#include "suffix.h" + + +/* Forward Declarations */ +static void NUMD2putHeader(FILE *, CKTcircuit *, NUMD2instance *); + +/* State Counter */ +static int state_numOP = 0; +static int state_numDC = 0; +static int state_numTR = 0; + +void +NUMD2dump(inModel, ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + register NUMD2model *model = (NUMD2model *) inModel; + register NUMD2instance *inst; + OUTPcard *output; + FILE *fpState; + char fileName[BSIZE_SP]; + char description[BSIZE_SP]; + char *prefix; + int *state_num; + int anyOutput = 0; + + if (ckt->CKTmode & MODEDCOP) { + prefix = "OP"; + state_num = &state_numOP; + sprintf(description, "..."); + } else if (ckt->CKTmode & MODEDCTRANCURVE) { + prefix = "DC"; + state_num = &state_numDC; + sprintf(description, "sweep = % e", ckt->CKTtime); + } else if (ckt->CKTmode & MODETRAN) { + prefix = "TR"; + state_num = &state_numTR; + sprintf(description, "time = % e", ckt->CKTtime); + } else { + /* Not a recognized CKT mode. */ + return; + } + + for (; model != NULL; model = model->NUMD2nextModel) { + output = model->NUMD2outputs; + for (inst = model->NUMD2instances; inst != NULL; + inst = inst->NUMD2nextInstance) { + if (inst->NUMD2owner != ARCHme) continue; + + if (inst->NUMD2printGiven) { + if ((ckt->CKTmode & MODETRAN) && + ((ckt->CKTstat->STATaccepted - 1) % inst->NUMD2print != 0)) { + continue; + } + anyOutput = 1; + sprintf(fileName, "%s%s.%d.%s", output->OUTProotFile, prefix, + *state_num, inst->NUMD2name); + if (!(fpState = fopen(fileName, "w"))) { + perror(fileName); + } else { + NUMD2putHeader(fpState, ckt, inst); + TWOprnSolution(fpState, inst->NUMD2pDevice, + model->NUMD2outputs); + fclose(fpState); + LOGmakeEntry(fileName, description); + } + } + } + } + if (anyOutput) { + (*state_num)++; + } +} + +#define NUMD2numOutputs 4 + +static +void +NUMD2putHeader(file, ckt, inst) + FILE *file; + CKTcircuit *ckt; + NUMD2instance *inst; +{ + char *reference; + double refVal = 0.0; + int numVars = NUMD2numOutputs; + + if (ckt->CKTmode & MODEDCOP) { + reference = NULL; + } else if (ckt->CKTmode & MODEDCTRANCURVE) { + reference = "sweep"; + refVal = ckt->CKTtime; + numVars++; + } else if (ckt->CKTmode & MODETRAN) { + reference = "time"; + refVal = ckt->CKTtime; + numVars++; + } else { + reference = NULL; + } + fprintf(file, "Title: Device %s external state\n", inst->NUMD2name); + fprintf(file, "Plotname: Device Operating Point\n"); + fprintf(file, "Command: deftype v conductance S\n"); + fprintf(file, "Flags: real\n"); + fprintf(file, "No. Variables: %d\n", numVars); + fprintf(file, "No. Points: 1\n"); + numVars = 0; + fprintf(file, "Variables:\n"); + if (reference) { + fprintf(file, "\t%d %s unknown\n", numVars++, reference); + } + fprintf(file, "\t%d v12 voltage\n", numVars++); + fprintf(file, "\t%d i1 current\n", numVars++); + fprintf(file, "\t%d i2 current\n", numVars++); + fprintf(file, "\t%d g11 conductance\n", numVars++); + fprintf(file, "Values:\n0"); + if (reference) { + fprintf(file, "\t% e\n", refVal); + } + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NUMD2voltage)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NUMD2id)); + fprintf(file, "\t% e\n", - *(ckt->CKTstate0 + inst->NUMD2id)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NUMD2conduct)); +} + +void +NUMD2acct(inModel, ckt, file) + GENmodel *inModel; + CKTcircuit *ckt; + FILE *file; +{ + register NUMD2model *model = (NUMD2model *) inModel; + register NUMD2instance *inst; + OUTPcard *output; + + for (; model != NULL; model = model->NUMD2nextModel) { + output = model->NUMD2outputs; + for (inst = model->NUMD2instances; inst != NULL; + inst = inst->NUMD2nextInstance) { + if (inst->NUMD2owner != ARCHme) continue; + + if (output->OUTPstats) { + TWOmemStats(file, inst->NUMD2pDevice); + TWOcpuStats(file, inst->NUMD2pDevice); + } + } + } +} diff --git a/src/spicelib/devices/numd2/nud2load.c b/src/spicelib/devices/numd2/nud2load.c new file mode 100644 index 000000000..fc20d3329 --- /dev/null +++ b/src/spicelib/devices/numd2/nud2load.c @@ -0,0 +1,408 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This is the function called each iteration to evaluate the 2d numerical + * Diodes in the circuit and load them into the matrix as appropriate + */ + +#include "ngspice.h" +#include "devdefs.h" +#include "cktdefs.h" +#include "numd2def.h" +#include "trandefs.h" +#include "sperror.h" +#include "../../../ciderlib/twod/twoddefs.h" +#include "../../../ciderlib/twod/twodext.h" +#include "cidersupt.h" +#include "suffix.h" + + +/* Forward declarations */ +int NUMD2initSmSig(NUMD2instance *); + +/* External Declarations */ +extern int TWOdcDebug; +extern int TWOtranDebug; +extern int TWOacDebug; + +int +NUMD2load(inModel, ckt) + GENmodel *inModel; + CKTcircuit *ckt; + +{ + register NUMD2model *model = (NUMD2model *) inModel; + register NUMD2instance *inst; + register TWOdevice *pDevice; + double startTime, startTime2, totalTime, totalTime2; + double id; + double idhat = 0.0; + double ideq; + double gd; + double xfact; + double tol; /* temporary for tolerance calculations */ + double vd; /* current diode voltage */ + double delVd; + int Check; + int error; + double deltaNorm[7]; + int devConverged = FALSE; + int i; + int numDevNonCon; + int deviceType; + int doInitSolve; + int doVoltPred; + char *initStateName; + + /* loop through all the diode models */ + for (; model != NULL; model = model->NUMD2nextModel) { + FieldDepMobility = model->NUMD2models->MODLfieldDepMobility; + TransDepMobility = model->NUMD2models->MODLtransDepMobility; + SurfaceMobility = model->NUMD2models->MODLsurfaceMobility; + Srh = model->NUMD2models->MODLsrh; + Auger = model->NUMD2models->MODLauger; + AvalancheGen = model->NUMD2models->MODLavalancheGen; + OneCarrier = model->NUMD2methods->METHoneCarrier; + MobDeriv = model->NUMD2methods->METHmobDeriv; + MaxIterations = model->NUMD2methods->METHitLim; + TWOdcDebug = model->NUMD2outputs->OUTPdcDebug; + TWOtranDebug = model->NUMD2outputs->OUTPtranDebug; + TWOacDebug = model->NUMD2outputs->OUTPacDebug; + deviceType = model->NUMD2options->OPTNdeviceType; + doVoltPred = model->NUMD2methods->METHvoltPred; + + if (ckt->CKTmode & MODEINITPRED) { + /* compute normalized deltas and predictor coeff */ + if (!(ckt->CKTmode & MODEDCTRANCURVE)) { + model->NUMD2pInfo->order = ckt->CKTorder; + model->NUMD2pInfo->method = ckt->CKTintegrateMethod; + for (i = 0; i <= ckt->CKTmaxOrder; i++) { + deltaNorm[i] = ckt->CKTdeltaOld[i] / TNorm; + } + computeIntegCoeff(ckt->CKTintegrateMethod, ckt->CKTorder, + model->NUMD2pInfo->intCoeff, deltaNorm); + computePredCoeff(ckt->CKTintegrateMethod, ckt->CKTorder, + model->NUMD2pInfo->predCoeff, deltaNorm); + } + } else if (ckt->CKTmode & MODEINITTRAN) { + model->NUMD2pInfo->order = ckt->CKTorder; + model->NUMD2pInfo->method = GEAR; + model->NUMD2pInfo->method = ckt->CKTintegrateMethod; + for (i = 0; i <= ckt->CKTmaxOrder; i++) { + deltaNorm[i] = ckt->CKTdeltaOld[i] / TNorm; + } + computeIntegCoeff(ckt->CKTintegrateMethod, ckt->CKTorder, + model->NUMD2pInfo->intCoeff, deltaNorm); + } + /* loop through all the instances of the model */ + for (inst = model->NUMD2instances; inst != NULL; + inst = inst->NUMD2nextInstance) { + if (inst->NUMD2owner != ARCHme) continue; + + pDevice = inst->NUMD2pDevice; + + totalTime = 0.0; + startTime = SPfrontEnd->IFseconds(); + + /* Get Temp.-Dep. Global Parameters */ + GLOBgetGlobals(&(inst->NUMD2globals)); + + pDevice->devStates = ckt->CKTstates; + /* + * initialization + */ + Check = 1; + doInitSolve = FALSE; + initStateName = NULL; + if (ckt->CKTmode & MODEINITSMSIG) { + vd = *(ckt->CKTstate0 + inst->NUMD2voltage); + delVd = 0.0; + NUMD2setBCs(pDevice, vd); + } else if (ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate0 + inst->NUMD2voltage) = + *(ckt->CKTstate1 + inst->NUMD2voltage); + vd = *(ckt->CKTstate1 + inst->NUMD2voltage); + TWOsaveState(pDevice); + delVd = 0.0; + } else if ((ckt->CKTmode & MODEINITJCT) && + (ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) { + doInitSolve = TRUE; + initStateName = inst->NUMD2icFile; + vd = 0.0; + delVd = vd; + } else if ((ckt->CKTmode & MODEINITJCT) && inst->NUMD2off) { + doInitSolve = TRUE; + vd = 0.0; + delVd = vd; + } else if (ckt->CKTmode & MODEINITJCT) { + doInitSolve = TRUE; + initStateName = inst->NUMD2icFile; + if (deviceType == OPTN_DIODE) { + vd = inst->NUMD2type * 0.6; + } else if (deviceType == OPTN_MOSCAP) { + vd = inst->NUMD2type * 0.8; + } else { + vd = 0.0; + } + delVd = vd; + } else if (ckt->CKTmode & MODEINITFIX && inst->NUMD2off) { + vd = 0.0; + delVd = vd; + } else { + if (ckt->CKTmode & MODEINITPRED) { + *(ckt->CKTstate0 + inst->NUMD2voltage) = + *(ckt->CKTstate1 + inst->NUMD2voltage); + *(ckt->CKTstate0 + inst->NUMD2id) = + *(ckt->CKTstate1 + inst->NUMD2id); + *(ckt->CKTstate0 + inst->NUMD2conduct) = + *(ckt->CKTstate1 + inst->NUMD2conduct); + if (!(ckt->CKTmode & MODEDCTRANCURVE)) { + /* no linear prediction on device voltages */ + vd = *(ckt->CKTstate1 + inst->NUMD2voltage); + TWOpredict(pDevice, model->NUMD2pInfo); + } else { + if (doVoltPred) { + /* linear prediction */ + xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1]; + vd = (1+xfact) * (*(ckt->CKTstate1 + inst->NUMD2voltage)) + - (xfact) * (*(ckt->CKTstate2 + inst->NUMD2voltage)); + } else { + vd = *(ckt->CKTstate1 + inst->NUMD2voltage); + } + } + } else { + vd = *(ckt->CKTrhsOld + inst->NUMD2posNode) - + *(ckt->CKTrhsOld + inst->NUMD2negNode); + } + delVd = vd - *(ckt->CKTstate0 + inst->NUMD2voltage); + idhat = *(ckt->CKTstate0 + inst->NUMD2id) + + *(ckt->CKTstate0 + inst->NUMD2conduct) * delVd; + /* + * bypass if solution has not changed + */ + if ((ckt->CKTbypass) && pDevice->converged && + !(ckt->CKTmode & MODEINITPRED)) { + tol = ckt->CKTvoltTol + ckt->CKTreltol * + MAX(fabs(vd), fabs(*(ckt->CKTstate0 + inst->NUMD2voltage))); + if (fabs(delVd) < tol) { + tol = ckt->CKTreltol * + MAX(fabs(idhat), fabs(*(ckt->CKTstate0 + inst->NUMD2id))) + + ckt->CKTabstol; + if (fabs(idhat - *(ckt->CKTstate0 + inst->NUMD2id)) + < tol) { + vd = *(ckt->CKTstate0 + inst->NUMD2voltage); + id = *(ckt->CKTstate0 + inst->NUMD2id); + gd = *(ckt->CKTstate0 + inst->NUMD2conduct); + goto load; + } + } + } + /* + * limit new junction voltage + */ + if (deviceType == OPTN_DIODE) { + vd = inst->NUMD2type * limitJunctionVoltage( + inst->NUMD2type * vd, + inst->NUMD2type * *(ckt->CKTstate0 + inst->NUMD2voltage), + &Check); + } else if (deviceType == OPTN_MOSCAP) { + vd = inst->NUMD2type * limitVgb( + inst->NUMD2type * vd, + inst->NUMD2type * *(ckt->CKTstate0 + inst->NUMD2voltage), + &Check); + } else { + vd = inst->NUMD2type * limitResistorVoltage( + inst->NUMD2type * vd, + inst->NUMD2type * *(ckt->CKTstate0 + inst->NUMD2voltage), + &Check); + } + delVd = vd - *(ckt->CKTstate0 + inst->NUMD2voltage); + NUMD2setBCs(pDevice, vd - delVd); + } + if (doInitSolve) { + if (TWOdcDebug) { + printVoltages(stdout, + model->NUMD2modName, inst->NUMD2name, + deviceType, 1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + } + startTime2 = SPfrontEnd->IFseconds(); + TWOequilSolve(pDevice); + totalTime2 = SPfrontEnd->IFseconds() - startTime2; + pDevice->pStats->totalTime[STAT_SETUP] += totalTime2; + pDevice->pStats->totalTime[STAT_DC] -= totalTime2; + + TWObiasSolve(pDevice, MaxIterations, FALSE, NULL); + + *(ckt->CKTstate0 + inst->NUMD2voltage) = 0.0; + + if (initStateName != NULL) { + if (TWOreadState(pDevice, initStateName, 1, &vd, NULL, NULL ) < 0) { + fprintf(stderr, + "NUMD2load: trouble reading state-file %s\n", initStateName); + } else { + *(ckt->CKTstate0 + inst->NUMD2voltage) = vd; + NUMD2setBCs(pDevice, vd); + delVd = 0.0; + } + } + } + /* + * compute dc current and derivitives + */ + /* use the routines for numerical simulation */ + + if (ckt->CKTmode & (MODEDCOP | MODETRANOP | MODEDCTRANCURVE | MODEINITSMSIG)) { + numDevNonCon = 0; + inst->NUMD2c11 = inst->NUMD2y11r = inst->NUMD2y11i = 0.0; + inst->NUMD2smSigAvail = FALSE; + devNonCon: + NUMD2project(pDevice, delVd); + if (TWOdcDebug) { + printVoltages(stdout, + model->NUMD2modName, inst->NUMD2name, + deviceType, 1, vd, delVd, 0.0, 0.0, 0.0, 0.0); + } + TWObiasSolve(pDevice, MaxIterations, FALSE, model->NUMD2pInfo); + devConverged = pDevice->converged; + + if (devConverged && finite(pDevice->rhsNorm)) { + /* extract the current and conductance information */ + NUMD2current(pDevice, FALSE, (double *) NULL, &id); + NUMD2conductance(pDevice, FALSE, (double *) NULL, &gd); + } else { + /* do voltage step backtracking */ + /* restore the boundary nodes to the previous value */ + NUMD2setBCs(pDevice, vd - delVd); + TWOstoreInitialGuess(pDevice); + TWOresetJacobian(pDevice); + delVd *= 0.5; + vd = delVd + *(ckt->CKTstate0 + inst->NUMD2voltage); + numDevNonCon++; + Check = 1; + if (numDevNonCon > 10) { + printVoltages(stderr, + model->NUMD2modName, inst->NUMD2name, + deviceType, 1, vd, delVd, 0.0, 0.0, 0.0, 0.0); + fprintf(stderr, + "*** Non-convergence during load ***\n"); + totalTime += SPfrontEnd->IFseconds() - startTime; + pDevice->pStats->totalTime[STAT_DC] += totalTime; + ckt->CKTtroubleElt = (GENinstance *) inst; + return (E_BADMATRIX); + } else { + goto devNonCon; + } + } + } + if ((ckt->CKTmode & (MODETRAN | MODEAC | MODEINITSMSIG)) || + (ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) { + /* + * store small-signal parameters + */ + if ((!(ckt->CKTmode & MODETRANOP)) || + (!(ckt->CKTmode & MODEUIC))) { + if (ckt->CKTmode & MODEINITSMSIG) { + totalTime = SPfrontEnd->IFseconds() - startTime; + pDevice->pStats->totalTime[STAT_DC] += totalTime; + startTime2 = SPfrontEnd->IFseconds(); + NUMD2initSmSig(inst); + pDevice->pStats->totalTime[STAT_AC] += + SPfrontEnd->IFseconds() - startTime2; + continue; + } else { + inst->NUMD2smSigAvail = FALSE; + } + /* + * transient analysis + */ + if (ckt->CKTmode & MODEINITPRED) { + NUMD2setBCs(pDevice, vd); + TWOstoreInitialGuess(pDevice); + } else { + NUMD2update(pDevice, delVd, TRUE); + } + if (TWOtranDebug) { + printVoltages(stdout, + model->NUMD2modName, inst->NUMD2name, + deviceType, 1, vd, delVd, 0.0, 0.0, 0.0, 0.0); + } + TWObiasSolve(pDevice, 0, TRUE, model->NUMD2pInfo); + + if (!finite(pDevice->rhsNorm)) { + totalTime += SPfrontEnd->IFseconds() - startTime; + pDevice->pStats->totalTime[STAT_TRAN] += totalTime; + ckt->CKTtroubleElt = (GENinstance *) inst; + return (E_BADMATRIX); + } + devConverged = TWOdeviceConverged(pDevice); + pDevice->converged = devConverged; + + /* extract the current and conductance information */ + NUMD2current(pDevice, TRUE, model->NUMD2pInfo->intCoeff, &id); + NUMD2conductance(pDevice, TRUE, model->NUMD2pInfo->intCoeff, &gd); + } + } + /* + * check convergence + */ + if ((!(ckt->CKTmode & MODEINITFIX)) || (!(inst->NUMD2off))) { + if (Check == 1 || !devConverged) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) inst; + } else { + tol = ckt->CKTreltol * MAX(fabs(idhat), fabs(id)) + ckt->CKTabstol; + if (fabs(idhat - id) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) inst; + } + } + } + *(ckt->CKTstate0 + inst->NUMD2voltage) = vd; + *(ckt->CKTstate0 + inst->NUMD2id) = id; + *(ckt->CKTstate0 + inst->NUMD2conduct) = gd; + + load: + + /* + * load current vector + */ + ideq = id - gd * vd; + *(ckt->CKTrhs + inst->NUMD2negNode) += ideq; + *(ckt->CKTrhs + inst->NUMD2posNode) -= ideq; + /* + * load matrix + */ + *(inst->NUMD2posPosPtr) += gd; + *(inst->NUMD2negNegPtr) += gd; + *(inst->NUMD2negPosPtr) -= gd; + *(inst->NUMD2posNegPtr) -= gd; + + totalTime += SPfrontEnd->IFseconds() - startTime; + if (ckt->CKTmode & MODETRAN) { + pDevice->pStats->totalTime[STAT_TRAN] += totalTime; + } else { + pDevice->pStats->totalTime[STAT_DC] += totalTime; + } + } + } + return (OK); +} + +int +NUMD2initSmSig(inst) + NUMD2instance *inst; +{ + SPcomplex yd; + double omega = inst->NUMD2modPtr->NUMD2methods->METHomega; + + AcAnalysisMethod = SOR_ONLY; + (void) NUMD2admittance(inst->NUMD2pDevice, omega, &yd); + inst->NUMD2c11 = yd.imag / omega; + inst->NUMD2y11r = yd.real; + inst->NUMD2y11i = yd.imag; + inst->NUMD2smSigAvail = TRUE; + return (OK); +} diff --git a/src/spicelib/devices/numd2/nud2mdel.c b/src/spicelib/devices/numd2/nud2mdel.c new file mode 100644 index 000000000..16030df67 --- /dev/null +++ b/src/spicelib/devices/numd2/nud2mdel.c @@ -0,0 +1,44 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "numd2def.h" +#include "sperror.h" +#include "suffix.h" + +int +NUMD2mDelete(inModel, modname, kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; + +{ + NUMD2model **model = (NUMD2model **) inModel; + NUMD2model *modfast = (NUMD2model *) kill; + NUMD2instance *inst; + NUMD2instance *prev = NULL; + NUMD2model **oldmod; + oldmod = model; + for (; *model; model = &((*model)->NUMD2nextModel)) { + if ((*model)->NUMD2modName == modname || + (modfast && *model == modfast)) + goto delgot; + oldmod = model; + } + return (E_NOMOD); + +delgot: + *oldmod = (*model)->NUMD2nextModel; /* cut deleted device out of list */ + for (inst = (*model)->NUMD2instances; inst; inst = inst->NUMD2nextInstance) { + if (prev) + FREE(prev); + prev = inst; + } + if (prev) + FREE(prev); + FREE(*model); + return (OK); + +} diff --git a/src/spicelib/devices/numd2/nud2mpar.c b/src/spicelib/devices/numd2/nud2mpar.c new file mode 100644 index 000000000..c782a5901 --- /dev/null +++ b/src/spicelib/devices/numd2/nud2mpar.c @@ -0,0 +1,32 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This routine sets model parameters for NUMD2s in the circuit. + */ + +#include "ngspice.h" +#include "const.h" +#include "ifsim.h" +#include "numd2def.h" +#include "sperror.h" +#include "suffix.h" + +int +NUMD2mParam(param, value, inModel) + int param; + IFvalue *value; + GENmodel *inModel; +{ + switch (param) { + case NUMD2_MOD_NUMD: + /* no action - already know it is a 2d-numerical diode, but this */ + /* makes life easier for spice-2 like parsers */ + break; + default: + return (E_BADPARM); + } + return (OK); +} diff --git a/src/spicelib/devices/numd2/nud2parm.c b/src/spicelib/devices/numd2/nud2parm.c new file mode 100644 index 000000000..367d9a0f7 --- /dev/null +++ b/src/spicelib/devices/numd2/nud2parm.c @@ -0,0 +1,49 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "const.h" +#include "ifsim.h" +#include "numd2def.h" +#include "sperror.h" +#include "suffix.h" + +int +NUMD2param(param, value, inInst, select) + int param; + IFvalue *value; + GENinstance *inInst; + IFvalue *select; +{ + NUMD2instance *inst = (NUMD2instance *) inInst; + switch (param) { + case NUMD2_WIDTH: + inst->NUMD2width = value->rValue; + inst->NUMD2widthGiven = TRUE; + break; + case NUMD2_AREA: + inst->NUMD2area = value->rValue; + inst->NUMD2areaGiven = TRUE; + break; + case NUMD2_OFF: + inst->NUMD2off = TRUE; + break; + case NUMD2_IC_FILE: + inst->NUMD2icFile = value->sValue; + inst->NUMD2icFileGiven = TRUE; + break; + case NUMD2_PRINT: + inst->NUMD2print = value->rValue; + inst->NUMD2printGiven = TRUE; + break; + case NUMD2_TEMP: + inst->NUMD2temp = value->rValue + CONSTCtoK; + inst->NUMD2tempGiven = TRUE; + break; + default: + return (E_BADPARM); + } + return (OK); +} diff --git a/src/spicelib/devices/numd2/nud2pzld.c b/src/spicelib/devices/numd2/nud2pzld.c new file mode 100644 index 000000000..e30f4bafe --- /dev/null +++ b/src/spicelib/devices/numd2/nud2pzld.c @@ -0,0 +1,67 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "cktdefs.h" +#include "complex.h" +#include "sperror.h" +#include "numd2def.h" +#include "../../../ciderlib/twod/twoddefs.h" +#include "../../../ciderlib/twod/twodext.h" +#include "cidersupt.h" +#include "suffix.h" + +/* External Declarations */ +extern int TWOacDebug; + +int +NUMD2pzLoad(inModel, ckt, s) + GENmodel *inModel; + register CKTcircuit *ckt; + SPcomplex *s; +{ + register NUMD2model *model = (NUMD2model *) inModel; + register NUMD2instance *inst; + SPcomplex y; + double startTime; + + /* loop through all the diode models */ + for (; model != NULL; model = model->NUMD2nextModel) { + FieldDepMobility = model->NUMD2models->MODLfieldDepMobility; + TransDepMobility = model->NUMD2models->MODLtransDepMobility; + SurfaceMobility = model->NUMD2models->MODLsurfaceMobility; + Srh = model->NUMD2models->MODLsrh; + Auger = model->NUMD2models->MODLauger; + AvalancheGen = model->NUMD2models->MODLavalancheGen; + OneCarrier = model->NUMD2methods->METHoneCarrier; + AcAnalysisMethod = model->NUMD2methods->METHacAnalysisMethod; + MobDeriv = model->NUMD2methods->METHmobDeriv; + TWOacDebug = model->NUMD2outputs->OUTPacDebug; + + for (inst = model->NUMD2instances; inst != NULL; + inst = inst->NUMD2nextInstance) { + if (inst->NUMD2owner != ARCHme) continue; + + startTime = SPfrontEnd->IFseconds(); + /* Get Temp.-Dep. Global Parameters */ + GLOBgetGlobals(&(inst->NUMD2globals)); + + NUMD2ys(inst->NUMD2pDevice, s, &y); + + *(inst->NUMD2posPosPtr) += y.real; + *(inst->NUMD2posPosPtr + 1) += y.imag; + *(inst->NUMD2negNegPtr) += y.real; + *(inst->NUMD2negNegPtr + 1) += y.imag; + *(inst->NUMD2negPosPtr) -= y.real; + *(inst->NUMD2negPosPtr + 1) -= y.imag; + *(inst->NUMD2posNegPtr) -= y.real; + *(inst->NUMD2posNegPtr + 1) -= y.imag; + + inst->NUMD2pDevice->pStats->totalTime[STAT_AC] += + SPfrontEnd->IFseconds() - startTime; + } + } + return (OK); +} diff --git a/src/spicelib/devices/numd2/nud2set.c b/src/spicelib/devices/numd2/nud2set.c new file mode 100644 index 000000000..c7ab61ae9 --- /dev/null +++ b/src/spicelib/devices/numd2/nud2set.c @@ -0,0 +1,266 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "cktdefs.h" +#include "smpdefs.h" +#include "numd2def.h" +#include "numconst.h" +#include "numenum.h" +#include "meshext.h" +#include "sperror.h" +#include "../../../ciderlib/twod/twoddefs.h" +#include "../../../ciderlib/twod/twodext.h" +#include "cidersupt.h" +#include "ciderinp.h" +#include "suffix.h" + +#define NIL(type) ((type *)0) +#define TSCALLOC(var, size, type)\ +if (size && (!(var =(type *)calloc(1, (unsigned)(size)*sizeof(type))))) {\ + return(E_NOMEM);\ +} + +int +NUMD2setup(matrix, inModel, ckt, states) + register SMPmatrix *matrix; + GENmodel *inModel; + CKTcircuit *ckt; + int *states; +/* + * load the structure with those pointers needed later for fast matrix + * loading + */ +{ + register NUMD2model *model = (NUMD2model *) inModel; + register NUMD2instance *inst; + METHcard *methods; + MODLcard *models; + OPTNcard *options; + OUTPcard *outputs; + char *icFileName = NULL; + int nameLen; + int error, xIndex, yIndex; + int xMeshSize, yMeshSize; + TWOdevice *pDevice; + TWOcoord *xCoordList = NIL(TWOcoord); + TWOcoord *yCoordList = NIL(TWOcoord); + TWOdomain *domainList = NIL(TWOdomain); + TWOelectrode *electrodeList = NIL(TWOelectrode); + TWOmaterial *pM, *pMaterial = NIL(TWOmaterial), *materialList = NIL(TWOmaterial); + DOPprofile *profileList = NIL(DOPprofile); + DOPtable *dopTableList = NIL(DOPtable); + double startTime; + + + /* loop through all the models */ + for (; model != NULL; model = model->NUMD2nextModel) { + if (!model->NUMD2pInfo) { + TSCALLOC(model->NUMD2pInfo, 1, TWOtranInfo); + } + methods = model->NUMD2methods; + if (!methods) { + TSCALLOC(methods, 1, METHcard); + model->NUMD2methods = methods; + } + models = model->NUMD2models; + if (!models) { + TSCALLOC(models, 1, MODLcard); + model->NUMD2models = models; + } + options = model->NUMD2options; + if (!options) { + TSCALLOC(options, 1, OPTNcard); + model->NUMD2options = options; + } + outputs = model->NUMD2outputs; + if (!outputs) { + TSCALLOC(outputs, 1, OUTPcard); + model->NUMD2outputs = outputs; + } + if (!methods->METHvoltPredGiven) { + methods->METHvoltPred = FALSE; + } + if (!methods->METHmobDerivGiven) { + methods->METHmobDeriv = TRUE; + } + if (!methods->METHoneCarrierGiven) { + methods->METHoneCarrier = FALSE; + } + if (!methods->METHacAnalysisMethodGiven) { + methods->METHacAnalysisMethod = SOR; + } + if (!methods->METHdabstolGiven) { + methods->METHdabstol = DABSTOL2D; + } + if (!methods->METHdreltolGiven) { + methods->METHdreltol = ckt->CKTreltol; + } + if (!methods->METHitLimGiven) { + methods->METHitLim = 50; + } + if (!methods->METHomegaGiven || methods->METHomega <= 0.0) { + methods->METHomega = 2.0 * M_PI /* radians/sec */ ; + } + if (!options->OPTNdefaGiven || options->OPTNdefa <= 0.0) { + options->OPTNdefa = 1.0e4 /* cm^2 */ ; + } + if (!options->OPTNdeflGiven || options->OPTNdefl <= 0.0) { + options->OPTNdefl = 1.0e2 /* cm */ ; + } + if (!options->OPTNdefwGiven && options->OPTNdefaGiven) { + options->OPTNdefw = options->OPTNdefa / options->OPTNdefl; + } else if (!options->OPTNdefwGiven || options->OPTNdefw <= 0.0) { + options->OPTNdefw = 1.0e2 /* cm */ ; + } + if (!options->OPTNdeviceTypeGiven) { + options->OPTNdeviceType = OPTN_DIODE; + } + if (!options->OPTNicFileGiven) { + options->OPTNicFile = NULL; + options->OPTNunique = FALSE; /* Can't form a unique name. */ + } + if (!options->OPTNuniqueGiven) { + options->OPTNunique = FALSE; + } + OneCarrier = methods->METHoneCarrier; + + /* Set up the rest of the card lists */ + if ((error = MODLsetup(model->NUMD2models))) + return (error); + BandGapNarrowing = models->MODLbandGapNarrowing; + ConcDepLifetime = models->MODLconcDepLifetime; + TempDepMobility = models->MODLtempDepMobility; + ConcDepMobility = models->MODLconcDepMobility; + SurfaceMobility = models->MODLsurfaceMobility; + + if ((error = OUTPsetup(model->NUMD2outputs))) + return (error); + if ((error = MATLsetup(model->NUMD2materials, &materialList))) + return (error); + if ((error = MOBsetup(model->NUMD2mobility, materialList))) + return (error); + if ((error = MESHsetup('x', model->NUMD2xMeshes, &xCoordList, &xMeshSize))) + return (error); + if ((error = MESHsetup('y', model->NUMD2yMeshes, &yCoordList, &yMeshSize))) + return (error); + if ((error = DOMNsetup(model->NUMD2domains, &domainList, + xCoordList, yCoordList, materialList))) + return (error); + if ((error = BDRYsetup(model->NUMD2boundaries, + xCoordList, yCoordList, domainList))) + return (error); + if ((error = ELCTsetup(model->NUMD2electrodes, &electrodeList, + xCoordList, yCoordList))) + return (error); + /* Make sure electrodes are OK. */ + checkElectrodes(electrodeList, 2); /* NUMD2 has 4 electrodes */ + + if ((error = CONTsetup(model->NUMD2contacts, electrodeList))) + return (error); + if ((error = DOPsetup(model->NUMD2dopings, &profileList, + &dopTableList, xCoordList, yCoordList))) + return (error); + model->NUMD2matlInfo = materialList; + model->NUMD2profiles = profileList; + model->NUMD2dopTables = dopTableList; + + /* loop through all the instances of the model */ + for (inst = model->NUMD2instances; inst != NULL; + inst = inst->NUMD2nextInstance) { + if (inst->NUMD2owner != ARCHme) goto matrixpointers; + + startTime = SPfrontEnd->IFseconds(); + + if (!inst->NUMD2printGiven) { + inst->NUMD2print = 0; + } else if (inst->NUMD2print <= 0) { + inst->NUMD2print = 1; + } + if (!inst->NUMD2icFileGiven) { + if (options->OPTNunique) { + nameLen = strlen(options->OPTNicFile) + strlen(inst->NUMD2name) + 1; + TSCALLOC(icFileName, nameLen+1, char); + sprintf(icFileName, "%s.%s", options->OPTNicFile, inst->NUMD2name); + icFileName[nameLen] = '\0'; + inst->NUMD2icFile = icFileName; + } else if (options->OPTNicFile != NULL) { + nameLen = strlen(options->OPTNicFile); + TSCALLOC(icFileName, nameLen+1, char); + icFileName = strcpy(icFileName, options->OPTNicFile); + inst->NUMD2icFile = icFileName; + } else { + inst->NUMD2icFile = NULL; + } + } + inst->NUMD2state = *states; + *states += NUMD2numStates; + + if (!inst->NUMD2pDevice) { + /* Assign the mesh and profile info to each instance. */ + TSCALLOC(pDevice, 1, TWOdevice); + TSCALLOC(pDevice->pStats, 1, TWOstats); + pDevice->name = inst->NUMD2name; + pDevice->solverType = SLV_NONE; + pDevice->numXNodes = xMeshSize; + pDevice->numYNodes = yMeshSize; + pDevice->xScale = MESHmkArray(xCoordList, xMeshSize); + pDevice->yScale = MESHmkArray(yCoordList, yMeshSize); + pDevice->abstol = methods->METHdabstol; + pDevice->reltol = methods->METHdreltol; + TSCALLOC(pDevice->elemArray, pDevice->numXNodes, TWOelem **); + for (xIndex = 1; xIndex < pDevice->numXNodes; xIndex++) { + TSCALLOC(pDevice->elemArray[xIndex], pDevice->numYNodes, TWOelem *); + } + + /* Create a copy of material data that can change with temperature. */ + pDevice->pMaterials = NIL(TWOmaterial); + for (pM = materialList; pM != NIL(TWOmaterial); pM = pM->next) { + if (pDevice->pMaterials == NIL(TWOmaterial)) { + TSCALLOC(pMaterial, 1, TWOmaterial); + pDevice->pMaterials = pMaterial; + } else { + TSCALLOC(pMaterial->next, 1, TWOmaterial); + pMaterial = pMaterial->next; + } + /* Copy everything, then fix the incorrect pointer. */ + bcopy((char *) pM, (char *) pMaterial, sizeof(TWOmaterial)); + pMaterial->next = NIL(TWOmaterial); + } + + /* Generate the mesh structure for the device. */ + TWObuildMesh(pDevice, domainList, electrodeList, pDevice->pMaterials); + + /* Store the device info in the instance. */ + inst->NUMD2pDevice = pDevice; + } + /* Now update the state pointers. */ + TWOgetStatePointers(inst->NUMD2pDevice, states); + + /* Wipe out statistics from previous runs (if any). */ + bzero((char *) inst->NUMD2pDevice->pStats, sizeof(TWOstats)); + + inst->NUMD2pDevice->pStats->totalTime[STAT_SETUP] += + SPfrontEnd->IFseconds() - startTime; + + /* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if ((inst->ptr = SMPmakeElt(matrix,inst->first,inst->second))==(double *)NULL){\ + return(E_NOMEM);\ +} +matrixpointers: + TSTALLOC(NUMD2posPosPtr, NUMD2posNode, NUMD2posNode) + TSTALLOC(NUMD2negNegPtr, NUMD2negNode, NUMD2negNode) + TSTALLOC(NUMD2negPosPtr, NUMD2negNode, NUMD2posNode) + TSTALLOC(NUMD2posNegPtr, NUMD2posNode, NUMD2negNode) + } + /* Clean up lists */ + killCoordInfo(xCoordList); + killCoordInfo(yCoordList); + killDomainInfo(domainList); + killElectrodeInfo(electrodeList); + } + return (OK); +} diff --git a/src/spicelib/devices/numd2/nud2temp.c b/src/spicelib/devices/numd2/nud2temp.c new file mode 100644 index 000000000..5cd7c6bd8 --- /dev/null +++ b/src/spicelib/devices/numd2/nud2temp.c @@ -0,0 +1,127 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +Author: 1992 David A. Gates, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "cktdefs.h" +#include "numd2def.h" +#include "numenum.h" +#include "carddefs.h" +#include "sperror.h" +#include "../../../ciderlib/twod/twoddefs.h" +#include "../../../ciderlib/twod/twodext.h" +#include "cidersupt.h" +#include "suffix.h" + +#define NIL(type) ((type *)0) + +int +NUMD2temp(inModel, ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +/* + * perform the temperature update + */ +{ + register NUMD2model *model = (NUMD2model *) inModel; + register NUMD2instance *inst; + METHcard *methods; + MODLcard *models; + OPTNcard *options; + OUTPcard *outputs; + TWOmaterial *pM, *pMaterial, *pNextMaterial; + double startTime; + + /* loop through all the models */ + for (; model != NULL; model = model->NUMD2nextModel) { + methods = model->NUMD2methods; + models = model->NUMD2models; + options = model->NUMD2options; + outputs = model->NUMD2outputs; + + if (!options->OPTNtnomGiven) { + options->OPTNtnom = ckt->CKTnomTemp; + } + for (pM = model->NUMD2matlInfo; pM != NIL(TWOmaterial); + pM = pM->next) { + pM->tnom = options->OPTNtnom; + } + BandGapNarrowing = models->MODLbandGapNarrowing; + ConcDepLifetime = models->MODLconcDepLifetime; + TempDepMobility = models->MODLtempDepMobility; + ConcDepMobility = models->MODLconcDepMobility; + SurfaceMobility = models->MODLsurfaceMobility; + MatchingMobility = models->MODLmatchingMobility; + OneCarrier = methods->METHoneCarrier; + + for (inst = model->NUMD2instances; inst != NULL; + inst = inst->NUMD2nextInstance) { + if (inst->NUMD2owner != ARCHme) continue; + + startTime = SPfrontEnd->IFseconds(); + + if (!inst->NUMD2tempGiven) { + inst->NUMD2temp = ckt->CKTtemp; + } + if (!inst->NUMD2areaGiven || inst->NUMD2area <= 0.0) { + inst->NUMD2area = 1.0; + } + if (!inst->NUMD2widthGiven || inst->NUMD2width <= 0.0) { + inst->NUMD2width = 1.0; + } + inst->NUMD2pDevice->width = + inst->NUMD2area * inst->NUMD2width * options->OPTNdefw; + + /* Compute and save globals for this instance. */ + GLOBcomputeGlobals(&(inst->NUMD2globals), inst->NUMD2temp); + + /* Calculate new sets of material parameters. */ + pM = model->NUMD2matlInfo; + pMaterial = inst->NUMD2pDevice->pMaterials; + for (; pM != NULL; pM = pM->next, pMaterial = pMaterial->next) { + + /* Copy everything, then fix the incorrect pointer. */ + pNextMaterial = pMaterial->next; + bcopy((char *) pM, (char *) pMaterial, sizeof(TWOmaterial)); + pMaterial->next = pNextMaterial; + + /* Now do the temperature dependence. */ + MATLtempDep(pMaterial, pMaterial->tnom); + if (outputs->OUTPmaterial) { + printMaterialInfo(pMaterial); + } + } + + /* Assign doping to the mesh. */ + TWOsetDoping(inst->NUMD2pDevice, model->NUMD2profiles, + model->NUMD2dopTables); + + /* Assign physical parameters to the mesh. */ + TWOsetup(inst->NUMD2pDevice); + + /* Assign boundary condition parameters. */ + TWOsetBCparams(inst->NUMD2pDevice, model->NUMD2boundaries); + + /* Normalize everything. */ + TWOnormalize(inst->NUMD2pDevice); + + /* Find the device's type. */ + if (inst->NUMD2pDevice->pFirstContact->pNodes[0]->netConc < 0.0) { + inst->NUMD2type = PN; + if (OneCarrier) { + methods->METHoneCarrier = P_TYPE; + } + } else { + inst->NUMD2type = NP; + if (OneCarrier) { + methods->METHoneCarrier = N_TYPE; + } + } + inst->NUMD2pDevice->pStats->totalTime[STAT_SETUP] += + SPfrontEnd->IFseconds() - startTime; + } + } + return (OK); +} diff --git a/src/spicelib/devices/numd2/nud2trun.c b/src/spicelib/devices/numd2/nud2trun.c new file mode 100644 index 000000000..34806faeb --- /dev/null +++ b/src/spicelib/devices/numd2/nud2trun.c @@ -0,0 +1,50 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "cktdefs.h" +#include "numd2def.h" +#include "sperror.h" +#include "../../../ciderlib/twod/twoddefs.h" +#include "../../../ciderlib/twod/twodext.h" +#include "suffix.h" +#include "cidersupt.h" + +int +NUMD2trunc(inModel, ckt, timeStep) + GENmodel *inModel; + register CKTcircuit *ckt; + double *timeStep; +{ + register NUMD2model *model = (NUMD2model *) inModel; + register NUMD2instance *inst; + double deltaNew; + double deltaNorm[7]; + double startTime; + int i; + + for (i = 0; i <= ckt->CKTmaxOrder; i++) { + deltaNorm[i] = ckt->CKTdeltaOld[i] / TNorm; + } + + for (; model != NULL; model = model->NUMD2nextModel) { + OneCarrier = model->NUMD2methods->METHoneCarrier; + model->NUMD2pInfo->order = ckt->CKTorder; + model->NUMD2pInfo->delta = deltaNorm; + model->NUMD2pInfo->lteCoeff = computeLTECoeff(model->NUMD2pInfo); + for (inst = model->NUMD2instances; inst != NULL; + inst = inst->NUMD2nextInstance) { + if (inst->NUMD2owner != ARCHme) continue; + + startTime = SPfrontEnd->IFseconds(); + deltaNew = TWOtrunc(inst->NUMD2pDevice, model->NUMD2pInfo, + ckt->CKTdelta); + *timeStep = MIN(*timeStep, deltaNew); + inst->NUMD2pDevice->pStats->totalTime[STAT_TRAN] += + SPfrontEnd->IFseconds() - startTime; + } + } + return (OK); +} diff --git a/src/spicelib/devices/numd2/numd2def.h b/src/spicelib/devices/numd2/numd2def.h new file mode 100644 index 000000000..f3d737e8f --- /dev/null +++ b/src/spicelib/devices/numd2/numd2def.h @@ -0,0 +1,138 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +Authors: 1987 Karti Mayaram, 1991 David Gates +**********/ + +#ifndef NUMD2_H +#define NUMD2_H "NUMD2defs.h $Revision$ on $Date$ " + +/* data structures used to describe 2D numerical diodes */ + +/* circuit level includes */ +#include "ifsim.h" +#include "cktdefs.h" +#include "gendefs.h" + +/* device level includes */ +#include "twomesh.h" +#include "twodev.h" +#include "profile.h" +#include "numglobs.h" +#include "carddefs.h" + +/* information needed per instance */ +typedef struct sNUMD2instance { + struct sNUMD2model *NUMD2modPtr; /* back pointer to model */ + struct sNUMD2instance *NUMD2nextInstance; /* pointer to next instance + * of current model */ + IFuid NUMD2name; /* pointer to character string naming this + * instance */ + int NUMD2owner; /* number of owner process */ + int NUMD2state; /* pointer to start of state vector for diode */ + +#define NUMD2voltage NUMD2state +#define NUMD2id NUMD2state+1 +#define NUMD2conduct NUMD2state+2 +#define NUMD2numStates 3 + + int NUMD2posNode; /* number of positive node of diode */ + int NUMD2negNode; /* number of negative node of diode */ + TWOdevice *NUMD2pDevice; + GLOBvalues NUMD2globals; /* Temp.-Dep. Global Parameters */ + int NUMD2type; /* device type pn or np */ + double NUMD2width; /* width factor for the diode */ + double NUMD2area; /* area factor for the diode */ + double NUMD2temp; /* instance temperature */ + double NUMD2c11; /* small-signal capacitance */ + double NUMD2y11r; /* small-signal admittance, real part */ + double NUMD2y11i; /* small-signal admittance, imag part */ + int NUMD2print; /* number of timesteps after which print + * internal */ + char *NUMD2icFile; /* Name of initial condition file */ + double *NUMD2negPosPtr; /* pointer to sparse matrix at + * (negative,positive) */ + double *NUMD2posNegPtr; /* pointer to sparse matrix at + * (positive,negative) */ + double *NUMD2posPosPtr; /* pointer to sparse matrix at + * (positive,positive) */ + double *NUMD2negNegPtr; /* pointer to sparse matrix at + * (negative,negative) */ + + int NUMD2off; /* 'off' flag for diode */ + unsigned NUMD2smSigAvail:1; /* flag to indicate small-signal done */ + unsigned NUMD2widthGiven:1; /* flag to indicate width was specified */ + unsigned NUMD2areaGiven:1; /* flag to indicate area was specified */ + unsigned NUMD2icFileGiven:1; /* flag to indicate init. cond. file given */ + unsigned NUMD2tempGiven:1; /* flag to indicate temp was specified */ + unsigned NUMD2printGiven:1; /* flag to indicate if print was specified */ +} NUMD2instance; + + +/* per model data */ + +typedef struct sNUMD2model { /* model structure for a diode */ + int NUMD2modType; /* type index of this device type */ + struct sNUMD2model *NUMD2nextModel; /* pointer to next possible model in + * linked list */ + NUMD2instance *NUMD2instances;/* pointer to list of instances that have + * this model */ + IFuid NUMD2modName; /* pointer to character string naming this + * model */ + /* Everything below here is numerical-device-specific */ + MESHcard *NUMD2xMeshes; /* list of xmesh cards */ + MESHcard *NUMD2yMeshes; /* list of ymesh cards */ + DOMNcard *NUMD2domains; /* list of domain cards */ + BDRYcard *NUMD2boundaries; /* list of boundary cards */ + DOPcard *NUMD2dopings; /* list of doping cards */ + ELCTcard *NUMD2electrodes; /* list of electrode cards */ + CONTcard *NUMD2contacts; /* list of contact cards */ + MODLcard *NUMD2models; /* list of model cards */ + MATLcard *NUMD2materials; /* list of material cards */ + MOBcard *NUMD2mobility; /* list of mobility cards */ + METHcard *NUMD2methods; /* list of method cards */ + OPTNcard *NUMD2options; /* list of option cards */ + OUTPcard *NUMD2outputs; /* list of output cards */ + TWOtranInfo *NUMD2pInfo; /* transient analysis information */ + DOPprofile *NUMD2profiles; /* expanded list of doping profiles */ + DOPtable *NUMD2dopTables; /* list of tables used by profiles */ + TWOmaterial *NUMD2matlInfo; /* list of material info structures */ +} NUMD2model; + +/* type of 2D diode */ +#define PN 1 +#define NP -1 + +/* device parameters */ +#define NUMD2_WIDTH 1 +#define NUMD2_AREA 2 +#define NUMD2_IC_FILE 3 +#define NUMD2_OFF 4 +#define NUMD2_PRINT 5 +#define NUMD2_TEMP 6 +#define NUMD2_VD 7 +#define NUMD2_ID 8 + +#define NUMD2_G11 9 +#define NUMD2_C11 10 +#define NUMD2_Y11 11 +#define NUMD2_G12 12 +#define NUMD2_C12 13 +#define NUMD2_Y12 14 +#define NUMD2_G21 15 +#define NUMD2_C21 16 +#define NUMD2_Y21 17 +#define NUMD2_G22 18 +#define NUMD2_C22 19 +#define NUMD2_Y22 20 + +/* model parameters */ +/* NOTE: all true model parameters have been moved to IFcardInfo structures */ +#define NUMD2_MOD_NUMD 101 + +/* device questions */ + +/* model questions */ + +#include "numd2ext.h" + +#endif /* NUMD2_H */ diff --git a/src/spicelib/devices/numd2/numd2ext.h b/src/spicelib/devices/numd2/numd2ext.h new file mode 100644 index 000000000..a23cd1169 --- /dev/null +++ b/src/spicelib/devices/numd2/numd2ext.h @@ -0,0 +1,28 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Karti Mayaram +**********/ + +#ifndef NUMD2EXT_H +#define NUMD2EXT_H + + +extern int NUMD2acLoad(GENmodel *, CKTcircuit *); +extern int NUMD2ask(CKTcircuit *, GENinstance *, int, IFvalue *, IFvalue *); +extern int NUMD2delete(GENmodel *, IFuid, GENinstance **); +extern void NUMD2destroy(GENmodel **); +extern int NUMD2getic(GENmodel *, CKTcircuit *); +extern int NUMD2load(GENmodel *, CKTcircuit *); +extern int NUMD2mDelete(GENmodel **, IFuid, GENmodel *); +extern int NUMD2mParam(int, IFvalue *, GENmodel *); +extern int NUMD2param(int, IFvalue *, GENinstance *, IFvalue *); +extern int NUMD2pzLoad(GENmodel *, CKTcircuit *, SPcomplex *); +extern int NUMD2setup(SMPmatrix *, GENmodel *, CKTcircuit *, int *); +extern int NUMD2temp(GENmodel *, CKTcircuit *); +extern int NUMD2trunc(GENmodel *, CKTcircuit *, double *); + +extern void NUMD2dump(GENmodel *, CKTcircuit *); +extern void NUMD2acct(GENmodel *, CKTcircuit *, FILE *); + + +#endif /* NUMD2EXT_H */ diff --git a/src/spicelib/devices/numd2/numd2init.c b/src/spicelib/devices/numd2/numd2init.c new file mode 100644 index 000000000..a6ecc1717 --- /dev/null +++ b/src/spicelib/devices/numd2/numd2init.c @@ -0,0 +1,83 @@ +#include + +#include + +#include "numd2itf.h" +#include "numd2ext.h" +#include "numd2init.h" + + +SPICEdev NUMD2info = { + { + "NUMD2", + "2D Numerical Junction Diode model", + + &NUMD2nSize, + &NUMD2nSize, + NUMD2names, + + &NUMD2pTSize, + NUMD2pTable, + + &NUMD2mPTSize, + NUMD2mPTable, + +#ifdef XSPICE +/*---- Fixed by SDB 5.2.2003 to enable XSPICE/tclspice integration -----*/ + NULL, /* This is a SPICE device, it has no MIF info data */ + + 0, /* This is a SPICE device, it has no MIF info data */ + NULL, /* This is a SPICE device, it has no MIF info data */ + + 0, /* This is a SPICE device, it has no MIF info data */ + NULL, /* This is a SPICE device, it has no MIF info data */ + + 0, /* This is a SPICE device, it has no MIF info data */ + NULL, /* This is a SPICE device, it has no MIF info data */ +/*--------------------------- End of SDB fix -------------------------*/ +#endif + + DEV_DEFAULT + }, + + DEVparam : NUMD2param, + DEVmodParam : NUMD2mParam, + DEVload : NUMD2load, + DEVsetup : NUMD2setup, + DEVunsetup : NULL, + DEVpzSetup : NUMD2setup, + DEVtemperature: NUMD2temp, + DEVtrunc : NUMD2trunc, + DEVfindBranch : NULL, + DEVacLoad : NUMD2acLoad, + DEVaccept : NULL, + DEVdestroy : NUMD2destroy, + DEVmodDelete : NUMD2mDelete, + DEVdelete : NUMD2delete, + DEVsetic : NULL, + DEVask : NUMD2ask, + DEVmodAsk : NULL, + DEVpzLoad : NUMD2pzLoad, + DEVconvTest : NULL, + DEVsenSetup : NULL, + DEVsenLoad : NULL, + DEVsenUpdate : NULL, + DEVsenAcLoad : NULL, + DEVsenPrint : NULL, + DEVsenTrunc : NULL, + DEVdisto : NULL, + DEVnoise : NULL, + DEVdump : NUMD2dump, + DEVacct : NUMD2acct, + + DEVinstSize : &NUMD2iSize, + DEVmodSize : &NUMD2mSize + +}; + + +SPICEdev * +get_numd2_info(void) +{ + return &NUMD2info; +} diff --git a/src/spicelib/devices/numd2/numd2init.h b/src/spicelib/devices/numd2/numd2init.h new file mode 100644 index 000000000..dbbcf7d2f --- /dev/null +++ b/src/spicelib/devices/numd2/numd2init.h @@ -0,0 +1,13 @@ +#ifndef _NUMD2INIT_H +#define _NUMD2INIT_H + +extern IFparm NUMD2pTable[ ]; +extern IFparm NUMD2mPTable[ ]; +extern char *NUMD2names[ ]; +extern int NUMD2pTSize; +extern int NUMD2mPTSize; +extern int NUMD2nSize; +extern int NUMD2iSize; +extern int NUMD2mSize; + +#endif diff --git a/src/spicelib/devices/numd2/numd2itf.h b/src/spicelib/devices/numd2/numd2itf.h new file mode 100644 index 000000000..2dc39132a --- /dev/null +++ b/src/spicelib/devices/numd2/numd2itf.h @@ -0,0 +1,10 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +**********/ + +#ifndef DEV_NUMD2 +#define DEV_NUMD2 + +extern SPICEdev *get_numd2_info(void); + +#endif diff --git a/src/spicelib/devices/numos/Makefile.am b/src/spicelib/devices/numos/Makefile.am new file mode 100644 index 000000000..e4f0f4213 --- /dev/null +++ b/src/spicelib/devices/numos/Makefile.am @@ -0,0 +1,30 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libnumos.a + +libnumos_a_SOURCES = \ + numm.c \ + nummacld.c \ + nummask.c \ + numosdef.h \ + nummdel.c \ + nummdest.c \ + nummdump.c \ + numosext.h \ + numosinit.c \ + numosinit.h \ + numositf.h \ + nummload.c \ + nummmdel.c \ + nummmpar.c \ + nummparm.c \ + nummpzld.c \ + nummset.c \ + nummtemp.c \ + nummtrun.c + + + +INCLUDES = -I$(top_srcdir)/src/include + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/numos/numm.c b/src/spicelib/devices/numos/numm.c new file mode 100644 index 000000000..944c72b2a --- /dev/null +++ b/src/spicelib/devices/numos/numm.c @@ -0,0 +1,93 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +Author: 1991 David A. Gates, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "devdefs.h" +#include "numosdef.h" +#include "suffix.h" + +/* + * This file defines the 2d Numerical MOSFET data structures that are + * available to the next level(s) up the calling hierarchy + */ + +IFparm NUMOSpTable[] = { /* parameters */ + IP("off", NUMOS_OFF, IF_FLAG, "Device initially off"), + IP("ic.file", NUMOS_IC_FILE, IF_STRING, "Initial condition file"), + IOP("area", NUMOS_AREA, IF_REAL, "Area factor"), + IOP("w", NUMOS_WIDTH, IF_REAL, "Width factor"), + IOP("l", NUMOS_LENGTH, IF_REAL, "Length factor"), + IP("save", NUMOS_PRINT, IF_REAL, "Save solutions"), + IP("print", NUMOS_PRINT, IF_REAL, "Print solutions"), + OP("g11", NUMOS_G11, IF_REAL, "Conductance"), + OP("c11", NUMOS_C11, IF_REAL, "Capacitance"), + OP("y11", NUMOS_Y11, IF_COMPLEX, "Admittance"), + OP("g12", NUMOS_G12, IF_REAL, "Conductance"), + OP("c12", NUMOS_C12, IF_REAL, "Capacitance"), + OP("y12", NUMOS_Y12, IF_COMPLEX, "Admittance"), + OP("g13", NUMOS_G13, IF_REAL, "Conductance"), + OP("c13", NUMOS_C13, IF_REAL, "Capacitance"), + OP("y13", NUMOS_Y13, IF_COMPLEX, "Admittance"), + OPU("g14", NUMOS_G14, IF_REAL, "Conductance"), + OPU("c14", NUMOS_C14, IF_REAL, "Capacitance"), + OPU("y14", NUMOS_Y14, IF_COMPLEX, "Admittance"), + OP("g21", NUMOS_G21, IF_REAL, "Conductance"), + OP("c21", NUMOS_C21, IF_REAL, "Capacitance"), + OP("y21", NUMOS_Y21, IF_COMPLEX, "Admittance"), + OP("g22", NUMOS_G22, IF_REAL, "Conductance"), + OP("c22", NUMOS_C22, IF_REAL, "Capacitance"), + OP("y22", NUMOS_Y22, IF_COMPLEX, "Admittance"), + OP("g23", NUMOS_G23, IF_REAL, "Conductance"), + OP("c23", NUMOS_C23, IF_REAL, "Capacitance"), + OP("y23", NUMOS_Y23, IF_COMPLEX, "Admittance"), + OPU("g24", NUMOS_G24, IF_REAL, "Conductance"), + OPU("c24", NUMOS_C24, IF_REAL, "Capacitance"), + OPU("y24", NUMOS_Y24, IF_COMPLEX, "Admittance"), + OP("g31", NUMOS_G31, IF_REAL, "Conductance"), + OP("c31", NUMOS_C31, IF_REAL, "Capacitance"), + OP("y31", NUMOS_Y31, IF_COMPLEX, "Admittance"), + OP("g32", NUMOS_G32, IF_REAL, "Conductance"), + OP("c32", NUMOS_C32, IF_REAL, "Capacitance"), + OP("y32", NUMOS_Y32, IF_COMPLEX, "Admittance"), + OP("g33", NUMOS_G33, IF_REAL, "Conductance"), + OP("c33", NUMOS_C33, IF_REAL, "Capacitance"), + OP("y33", NUMOS_Y33, IF_COMPLEX, "Admittance"), + OPU("g34", NUMOS_G34, IF_REAL, "Conductance"), + OPU("c34", NUMOS_C34, IF_REAL, "Capacitance"), + OPU("y34", NUMOS_Y34, IF_COMPLEX, "Admittance"), + OPU("g41", NUMOS_G41, IF_REAL, "Conductance"), + OPU("c41", NUMOS_C41, IF_REAL, "Capacitance"), + OPU("y41", NUMOS_Y41, IF_COMPLEX, "Admittance"), + OPU("g42", NUMOS_G42, IF_REAL, "Conductance"), + OPU("c42", NUMOS_C42, IF_REAL, "Capacitance"), + OPU("y42", NUMOS_Y42, IF_COMPLEX, "Admittance"), + OPU("g43", NUMOS_G43, IF_REAL, "Conductance"), + OPU("c43", NUMOS_C43, IF_REAL, "Capacitance"), + OPU("y43", NUMOS_Y43, IF_COMPLEX, "Admittance"), + OPU("g44", NUMOS_G44, IF_REAL, "Conductance"), + OPU("c44", NUMOS_C44, IF_REAL, "Capacitance"), + OPU("y44", NUMOS_Y44, IF_COMPLEX, "Admittance"), + IOP("temp", NUMOS_TEMP, IF_REAL, "Instance temperature") +}; + +IFparm NUMOSmPTable[] = { /* model parameters */ + /* numerical-device models no longer have parameters */ + /* one is left behind to keep the table from being empty */ + IP("numos", NUMOS_MOD_NUMOS, IF_FLAG, "Numerical MOSFET"), +}; + +char *NUMOSnames[] = { + "Drain", + "Gate", + "Source", + "Substrate" +}; + +int NUMOSnSize = NUMELEMS(NUMOSnames); +int NUMOSpTSize = NUMELEMS(NUMOSpTable); +int NUMOSmPTSize = NUMELEMS(NUMOSmPTable); +int NUMOSiSize = sizeof(NUMOSinstance); +int NUMOSmSize = sizeof(NUMOSmodel); diff --git a/src/spicelib/devices/numos/nummacld.c b/src/spicelib/devices/numos/nummacld.c new file mode 100644 index 000000000..8e6c33ba5 --- /dev/null +++ b/src/spicelib/devices/numos/nummacld.c @@ -0,0 +1,158 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * Function to load the COMPLEX circuit matrix using the small signal + * parameters saved during a previous DC operating point analysis. + */ + +#include "ngspice.h" +#include "cktdefs.h" +#include "numosdef.h" +#include "sperror.h" +#include "suffix.h" +#include "complex.h" +#include "../../../ciderlib/twod/twoddefs.h" +#include "../../../ciderlib/twod/twodext.h" +#include "cidersupt.h" + +/* External Declarations */ +extern int TWOacDebug; + +int +NUMOSacLoad(inModel, ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + register NUMOSmodel *model = (NUMOSmodel *) inModel; + register NUMOSinstance *inst; + struct mosAdmittances yAc; + double startTime; + + for (; model != NULL; model = model->NUMOSnextModel) { + FieldDepMobility = model->NUMOSmodels->MODLfieldDepMobility; + TransDepMobility = model->NUMOSmodels->MODLtransDepMobility; + SurfaceMobility = model->NUMOSmodels->MODLsurfaceMobility; + Srh = model->NUMOSmodels->MODLsrh; + Auger = model->NUMOSmodels->MODLauger; + AvalancheGen = model->NUMOSmodels->MODLavalancheGen; + OneCarrier = model->NUMOSmethods->METHoneCarrier; + AcAnalysisMethod = model->NUMOSmethods->METHacAnalysisMethod; + MobDeriv = model->NUMOSmethods->METHmobDeriv; + TWOacDebug = model->NUMOSoutputs->OUTPacDebug; + + for (inst = model->NUMOSinstances; inst != NULL; + inst = inst->NUMOSnextInstance) { + if (inst->NUMOSowner != ARCHme) continue; + + startTime = SPfrontEnd->IFseconds(); + /* Get Temp.-Dep. Global Parameters */ + GLOBgetGlobals(&(inst->NUMOSglobals)); + + model->NUMOSmethods->METHacAnalysisMethod = + NUMOSadmittance(inst->NUMOSpDevice, + ckt->CKTomega, &yAc); + + *(inst->NUMOSdrainDrainPtr) += yAc.yIdVdb.real; + *(inst->NUMOSdrainDrainPtr + 1) += yAc.yIdVdb.imag; + *(inst->NUMOSdrainSourcePtr) += yAc.yIdVsb.real; + *(inst->NUMOSdrainSourcePtr + 1) += yAc.yIdVsb.imag; + *(inst->NUMOSdrainGatePtr) += yAc.yIdVgb.real; + *(inst->NUMOSdrainGatePtr + 1) += yAc.yIdVgb.imag; + *(inst->NUMOSdrainBulkPtr) -= + yAc.yIdVdb.real + yAc.yIdVsb.real + yAc.yIdVgb.real; + *(inst->NUMOSdrainBulkPtr + 1) -= + yAc.yIdVdb.imag + yAc.yIdVsb.imag + yAc.yIdVgb.imag; + + *(inst->NUMOSsourceDrainPtr) += yAc.yIsVdb.real; + *(inst->NUMOSsourceDrainPtr + 1) += yAc.yIsVdb.imag; + *(inst->NUMOSsourceSourcePtr) += yAc.yIsVsb.real; + *(inst->NUMOSsourceSourcePtr + 1) += yAc.yIsVsb.imag; + *(inst->NUMOSsourceGatePtr) += yAc.yIsVgb.real; + *(inst->NUMOSsourceGatePtr + 1) += yAc.yIsVgb.imag; + *(inst->NUMOSsourceBulkPtr) -= + yAc.yIsVdb.real + yAc.yIsVsb.real + yAc.yIsVgb.real; + *(inst->NUMOSsourceBulkPtr + 1) -= + yAc.yIsVdb.imag + yAc.yIsVsb.imag + yAc.yIsVgb.imag; + + *(inst->NUMOSgateDrainPtr) += yAc.yIgVdb.real; + *(inst->NUMOSgateDrainPtr + 1) += yAc.yIgVdb.imag; + *(inst->NUMOSgateSourcePtr) += yAc.yIgVsb.real; + *(inst->NUMOSgateSourcePtr + 1) += yAc.yIgVsb.imag; + *(inst->NUMOSgateGatePtr) += yAc.yIgVgb.real; + *(inst->NUMOSgateGatePtr + 1) += yAc.yIgVgb.imag; + *(inst->NUMOSgateBulkPtr) -= + yAc.yIgVdb.real + yAc.yIgVsb.real + yAc.yIgVgb.real; + *(inst->NUMOSgateBulkPtr + 1) -= + yAc.yIgVdb.imag + yAc.yIgVsb.imag + yAc.yIgVgb.imag; + + *(inst->NUMOSbulkDrainPtr) -= + yAc.yIdVdb.real + yAc.yIsVdb.real + yAc.yIgVdb.real; + *(inst->NUMOSbulkDrainPtr + 1) -= + yAc.yIdVdb.imag + yAc.yIsVdb.imag + yAc.yIgVdb.imag; + *(inst->NUMOSbulkSourcePtr) -= + yAc.yIdVsb.real + yAc.yIsVsb.real + yAc.yIgVsb.real; + *(inst->NUMOSbulkSourcePtr + 1) -= + yAc.yIdVsb.imag + yAc.yIsVsb.imag + yAc.yIgVsb.imag; + *(inst->NUMOSbulkGatePtr) -= + yAc.yIdVgb.real + yAc.yIsVgb.real + yAc.yIgVgb.real; + *(inst->NUMOSbulkGatePtr + 1) -= + yAc.yIdVgb.imag + yAc.yIsVgb.imag + yAc.yIgVgb.imag; + *(inst->NUMOSbulkBulkPtr) += yAc.yIdVdb.real + yAc.yIdVsb.real + + yAc.yIdVgb.real + yAc.yIsVdb.real + + yAc.yIsVsb.real + yAc.yIsVgb.real + + yAc.yIgVdb.real + yAc.yIgVsb.real + + yAc.yIgVgb.real; + *(inst->NUMOSbulkBulkPtr + 1) -= yAc.yIdVdb.imag + yAc.yIdVsb.imag + + yAc.yIdVgb.imag + yAc.yIsVdb.imag + + yAc.yIsVsb.imag + yAc.yIsVgb.imag + + yAc.yIgVdb.imag + yAc.yIgVsb.imag + + yAc.yIgVgb.imag; + if (ckt->CKTomega != 0.0) { + inst->NUMOSc11 = yAc.yIdVdb.imag / ckt->CKTomega; + inst->NUMOSc12 = yAc.yIdVgb.imag / ckt->CKTomega; + inst->NUMOSc13 = yAc.yIdVsb.imag / ckt->CKTomega; + inst->NUMOSc21 = yAc.yIgVdb.imag / ckt->CKTomega; + inst->NUMOSc22 = yAc.yIgVgb.imag / ckt->CKTomega; + inst->NUMOSc23 = yAc.yIgVsb.imag / ckt->CKTomega; + inst->NUMOSc31 = yAc.yIsVdb.imag / ckt->CKTomega; + inst->NUMOSc32 = yAc.yIsVgb.imag / ckt->CKTomega; + inst->NUMOSc33 = yAc.yIsVsb.imag / ckt->CKTomega; + } else { + inst->NUMOSc11 = 0.0; /* XXX What else can be done?! */ + inst->NUMOSc12 = 0.0; /* XXX What else can be done?! */ + inst->NUMOSc13 = 0.0; /* XXX What else can be done?! */ + inst->NUMOSc21 = 0.0; /* XXX What else can be done?! */ + inst->NUMOSc22 = 0.0; /* XXX What else can be done?! */ + inst->NUMOSc23 = 0.0; /* XXX What else can be done?! */ + inst->NUMOSc31 = 0.0; /* XXX What else can be done?! */ + inst->NUMOSc32 = 0.0; /* XXX What else can be done?! */ + inst->NUMOSc33 = 0.0; /* XXX What else can be done?! */ + } + inst->NUMOSy11r = yAc.yIdVdb.real; + inst->NUMOSy11i = yAc.yIdVdb.imag; + inst->NUMOSy12r = yAc.yIdVgb.real; + inst->NUMOSy12i = yAc.yIdVgb.imag; + inst->NUMOSy13r = yAc.yIdVsb.real; + inst->NUMOSy13i = yAc.yIdVsb.imag; + inst->NUMOSy21r = yAc.yIgVdb.real; + inst->NUMOSy21i = yAc.yIgVdb.imag; + inst->NUMOSy22r = yAc.yIgVgb.real; + inst->NUMOSy22i = yAc.yIgVgb.imag; + inst->NUMOSy23r = yAc.yIgVsb.real; + inst->NUMOSy23i = yAc.yIgVsb.imag; + inst->NUMOSy31r = yAc.yIsVdb.real; + inst->NUMOSy31i = yAc.yIsVdb.imag; + inst->NUMOSy32r = yAc.yIsVgb.real; + inst->NUMOSy32i = yAc.yIsVgb.imag; + inst->NUMOSy33r = yAc.yIsVsb.real; + inst->NUMOSy33i = yAc.yIsVsb.imag; + inst->NUMOSsmSigAvail = TRUE; + inst->NUMOSpDevice->pStats->totalTime[STAT_AC] += + SPfrontEnd->IFseconds() - startTime; + } + } + return (OK); +} diff --git a/src/spicelib/devices/numos/nummask.c b/src/spicelib/devices/numos/nummask.c new file mode 100644 index 000000000..b5471ea7a --- /dev/null +++ b/src/spicelib/devices/numos/nummask.c @@ -0,0 +1,359 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include "const.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "numosdef.h" +#include "sperror.h" +#include "suffix.h" + +/* Externals Declarations */ +extern int NUMOSinitSmSig(NUMOSinstance *); + +/* ARGSUSED */ +int +NUMOSask(ckt, inInst, which, value, select) + CKTcircuit *ckt; + GENinstance *inInst; + int which; + IFvalue *value; + IFvalue *select; +{ + NUMOSinstance *inst = (NUMOSinstance *) inInst; + switch (which) { + case NUMOS_AREA: + value->rValue = inst->NUMOSarea; + return (OK); + case NUMOS_WIDTH: + value->rValue = inst->NUMOSwidth; + return (OK); + case NUMOS_LENGTH: + value->rValue = inst->NUMOSlength; + return (OK); + case NUMOS_TEMP: + value->rValue = inst->NUMOStemp - CONSTCtoK; + return (OK); + case NUMOS_G11: + value->rValue = *(ckt->CKTstate0 + inst->NUMOSdIdDVdb); + return (OK); + case NUMOS_G12: + value->rValue = *(ckt->CKTstate0 + inst->NUMOSdIdDVgb); + return (OK); + case NUMOS_G13: + value->rValue = *(ckt->CKTstate0 + inst->NUMOSdIdDVsb); + return (OK); + case NUMOS_G14: + value->rValue = -*(ckt->CKTstate0 + inst->NUMOSdIdDVdb) + - *(ckt->CKTstate0 + inst->NUMOSdIdDVgb) + - *(ckt->CKTstate0 + inst->NUMOSdIdDVsb); + return (OK); + case NUMOS_G21: + value->rValue = *(ckt->CKTstate0 + inst->NUMOSdIgDVdb); + return (OK); + case NUMOS_G22: + value->rValue = *(ckt->CKTstate0 + inst->NUMOSdIgDVgb); + return (OK); + case NUMOS_G23: + value->rValue = *(ckt->CKTstate0 + inst->NUMOSdIgDVsb); + return (OK); + case NUMOS_G24: + value->rValue = -*(ckt->CKTstate0 + inst->NUMOSdIgDVdb) + - *(ckt->CKTstate0 + inst->NUMOSdIgDVgb) + - *(ckt->CKTstate0 + inst->NUMOSdIgDVsb); + return (OK); + case NUMOS_G31: + value->rValue = *(ckt->CKTstate0 + inst->NUMOSdIsDVdb); + return (OK); + case NUMOS_G32: + value->rValue = *(ckt->CKTstate0 + inst->NUMOSdIsDVgb); + return (OK); + case NUMOS_G33: + value->rValue = *(ckt->CKTstate0 + inst->NUMOSdIsDVsb); + return (OK); + case NUMOS_G34: + value->rValue = -*(ckt->CKTstate0 + inst->NUMOSdIsDVdb) + - *(ckt->CKTstate0 + inst->NUMOSdIsDVgb) + - *(ckt->CKTstate0 + inst->NUMOSdIsDVsb); + return (OK); + case NUMOS_G41: + value->rValue = -*(ckt->CKTstate0 + inst->NUMOSdIdDVdb) + - *(ckt->CKTstate0 + inst->NUMOSdIgDVdb) + - *(ckt->CKTstate0 + inst->NUMOSdIsDVdb); + return (OK); + case NUMOS_G42: + value->rValue = -*(ckt->CKTstate0 + inst->NUMOSdIdDVgb) + - *(ckt->CKTstate0 + inst->NUMOSdIgDVgb) + - *(ckt->CKTstate0 + inst->NUMOSdIsDVgb); + return (OK); + case NUMOS_G43: + value->rValue = -*(ckt->CKTstate0 + inst->NUMOSdIdDVsb) + - *(ckt->CKTstate0 + inst->NUMOSdIgDVsb) + - *(ckt->CKTstate0 + inst->NUMOSdIsDVsb); + return (OK); + case NUMOS_G44: + value->rValue = *(ckt->CKTstate0 + inst->NUMOSdIdDVdb) + + *(ckt->CKTstate0 + inst->NUMOSdIgDVdb) + + *(ckt->CKTstate0 + inst->NUMOSdIsDVdb) + + *(ckt->CKTstate0 + inst->NUMOSdIdDVgb) + + *(ckt->CKTstate0 + inst->NUMOSdIgDVgb) + + *(ckt->CKTstate0 + inst->NUMOSdIsDVgb) + + *(ckt->CKTstate0 + inst->NUMOSdIdDVsb) + + *(ckt->CKTstate0 + inst->NUMOSdIgDVsb) + + *(ckt->CKTstate0 + inst->NUMOSdIsDVsb); + return (OK); + case NUMOS_C11: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->rValue = inst->NUMOSc11; + return (OK); + case NUMOS_C12: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->rValue = inst->NUMOSc12; + return (OK); + case NUMOS_C13: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->rValue = inst->NUMOSc13; + return (OK); + case NUMOS_C14: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->rValue = -inst->NUMOSc11 - inst->NUMOSc12 - inst->NUMOSc13; + return (OK); + case NUMOS_C21: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->rValue = inst->NUMOSc21; + return (OK); + case NUMOS_C22: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->rValue = inst->NUMOSc22; + return (OK); + case NUMOS_C23: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->rValue = inst->NUMOSc23; + return (OK); + case NUMOS_C24: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->rValue = -inst->NUMOSc21 - inst->NUMOSc22 - inst->NUMOSc23; + return (OK); + case NUMOS_C31: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->rValue = inst->NUMOSc31; + return (OK); + case NUMOS_C32: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->rValue = inst->NUMOSc32; + return (OK); + case NUMOS_C33: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->rValue = inst->NUMOSc33; + return (OK); + case NUMOS_C34: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->rValue = -inst->NUMOSc31 - inst->NUMOSc32 - inst->NUMOSc33; + return (OK); + case NUMOS_C41: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->rValue = -inst->NUMOSc11 - inst->NUMOSc21 - inst->NUMOSc31; + return (OK); + case NUMOS_C42: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->rValue = -inst->NUMOSc12 - inst->NUMOSc22 - inst->NUMOSc32; + return (OK); + case NUMOS_C43: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->rValue = -inst->NUMOSc13 - inst->NUMOSc23 - inst->NUMOSc33; + return (OK); + case NUMOS_C44: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->rValue = inst->NUMOSc11 + inst->NUMOSc12 + inst->NUMOSc13 + + inst->NUMOSc21 + inst->NUMOSc22 + inst->NUMOSc23 + + inst->NUMOSc31 + inst->NUMOSc32 + inst->NUMOSc33; + return (OK); + case NUMOS_Y11: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->cValue.real = inst->NUMOSy11r; + value->cValue.imag = inst->NUMOSy11i; + return (OK); + case NUMOS_Y12: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->cValue.real = inst->NUMOSy12r; + value->cValue.imag = inst->NUMOSy12i; + return (OK); + case NUMOS_Y13: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->cValue.real = inst->NUMOSy13r; + value->cValue.imag = inst->NUMOSy13i; + return (OK); + case NUMOS_Y14: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->cValue.real = -inst->NUMOSy11r - inst->NUMOSy11r - inst->NUMOSy11r; + value->cValue.imag = -inst->NUMOSy11i - inst->NUMOSy11i - inst->NUMOSy11i; + return (OK); + case NUMOS_Y21: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->cValue.real = inst->NUMOSy21r; + value->cValue.imag = inst->NUMOSy21i; + return (OK); + case NUMOS_Y22: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->cValue.real = inst->NUMOSy22r; + value->cValue.imag = inst->NUMOSy22i; + return (OK); + case NUMOS_Y23: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->cValue.real = inst->NUMOSy23r; + value->cValue.imag = inst->NUMOSy23i; + return (OK); + case NUMOS_Y24: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->cValue.real = -inst->NUMOSy21r - inst->NUMOSy22r - inst->NUMOSy23r; + value->cValue.imag = -inst->NUMOSy21i - inst->NUMOSy22i - inst->NUMOSy23i; + return (OK); + case NUMOS_Y31: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->cValue.real = inst->NUMOSy31r; + value->cValue.imag = inst->NUMOSy31i; + return (OK); + case NUMOS_Y32: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->cValue.real = inst->NUMOSy32r; + value->cValue.imag = inst->NUMOSy32i; + return (OK); + case NUMOS_Y33: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->cValue.real = inst->NUMOSy33r; + value->cValue.imag = inst->NUMOSy33i; + return (OK); + case NUMOS_Y34: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->cValue.real = -inst->NUMOSy31r - inst->NUMOSy32r - inst->NUMOSy33r; + value->cValue.imag = -inst->NUMOSy31i - inst->NUMOSy32i - inst->NUMOSy33i; + return (OK); + case NUMOS_Y41: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->cValue.real = -inst->NUMOSy11r - inst->NUMOSy21r - inst->NUMOSy31r; + value->cValue.imag = -inst->NUMOSy11i - inst->NUMOSy21i - inst->NUMOSy31i; + return (OK); + case NUMOS_Y42: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->cValue.real = -inst->NUMOSy12r - inst->NUMOSy22r - inst->NUMOSy32r; + value->cValue.imag = -inst->NUMOSy12i - inst->NUMOSy22i - inst->NUMOSy32i; + return (OK); + case NUMOS_Y43: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->cValue.real = -inst->NUMOSy13r - inst->NUMOSy23r - inst->NUMOSy33r; + value->cValue.imag = -inst->NUMOSy13i - inst->NUMOSy23i - inst->NUMOSy33i; + return (OK); + case NUMOS_Y44: + if (!inst->NUMOSsmSigAvail + && ckt->CKTcurrentAnalysis != DOING_TRAN) { + NUMOSinitSmSig(inst); + } + value->cValue.real = inst->NUMOSy11r + inst->NUMOSy21r + inst->NUMOSy31r + + inst->NUMOSy12r + inst->NUMOSy22r + inst->NUMOSy32r + + inst->NUMOSy13r + inst->NUMOSy23r + inst->NUMOSy33r; + value->cValue.imag = inst->NUMOSy11i + inst->NUMOSy21i + inst->NUMOSy31i + + inst->NUMOSy12i + inst->NUMOSy22i + inst->NUMOSy32i + + inst->NUMOSy13i + inst->NUMOSy23i + inst->NUMOSy33i; + return (OK); + default: + return (E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/numos/nummdel.c b/src/spicelib/devices/numos/nummdel.c new file mode 100644 index 000000000..82e8be22b --- /dev/null +++ b/src/spicelib/devices/numos/nummdel.c @@ -0,0 +1,41 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This routine deletes a NUMOS instance from the circuit and frees the + * storage it was using. + */ + +#include "ngspice.h" +#include "numosdef.h" +#include "sperror.h" +#include "suffix.h" + +int +NUMOSdelete(inModel, name, kill) + GENmodel *inModel; + IFuid name; + GENinstance **kill; + +{ + + NUMOSmodel *model = (NUMOSmodel *) inModel; + NUMOSinstance **fast = (NUMOSinstance **) kill; + NUMOSinstance **prev = NULL; + NUMOSinstance *inst; + + for (; model; model = model->NUMOSnextModel) { + prev = &(model->NUMOSinstances); + for (inst = *prev; inst; inst = *prev) { + if (inst->NUMOSname == name || (fast && inst == *fast)) { + *prev = inst->NUMOSnextInstance; + FREE(inst); + return (OK); + } + prev = &(inst->NUMOSnextInstance); + } + } + return (E_NODEV); +} diff --git a/src/spicelib/devices/numos/nummdest.c b/src/spicelib/devices/numos/nummdest.c new file mode 100644 index 000000000..248af2737 --- /dev/null +++ b/src/spicelib/devices/numos/nummdest.c @@ -0,0 +1,39 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This routine deletes all NUMOSs from the circuit and frees all storage + * they were using. The current implementation has memory leaks. + */ + +#include "ngspice.h" +#include "numosdef.h" +#include "../../../ciderlib/twod/twoddefs.h" +#include "../../../ciderlib/twod/twodext.h" +#include "suffix.h" + +void +NUMOSdestroy(inModel) + GENmodel **inModel; + +{ + + NUMOSmodel **model = (NUMOSmodel **) inModel; + NUMOSmodel *mod, *nextMod; + NUMOSinstance *inst, *nextInst; + + for (mod = *model; mod;) { + for (inst = mod->NUMOSinstances; inst;) { + TWOdestroy(inst->NUMOSpDevice); + nextInst = inst->NUMOSnextInstance; + FREE(inst); + inst = nextInst; + } + nextMod = mod->NUMOSnextModel; + FREE(mod); + mod = nextMod; + } + *model = NULL; +} diff --git a/src/spicelib/devices/numos/nummdump.c b/src/spicelib/devices/numos/nummdump.c new file mode 100644 index 000000000..d78d205f9 --- /dev/null +++ b/src/spicelib/devices/numos/nummdump.c @@ -0,0 +1,179 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +Author: 1991 David A. Gates, U. C. Berkeley CAD Group +**********/ + +/* + * This is a simple routine to dump the internal device states. It produces + * states for .OP, .DC, & .TRAN simulations. + */ + +#include "ngspice.h" +#include "cktdefs.h" +#include "numosdef.h" +#include "../../../ciderlib/twod/twoddefs.h" +#include "../../../ciderlib/twod/twodext.h" +#include "cidersupt.h" +#include "suffix.h" + + +/* Forward Declarations */ +static void NUMOSputHeader(FILE *, CKTcircuit *, NUMOSinstance *); + +/* State Counter */ +static int state_numOP = 0; +static int state_numDC = 0; +static int state_numTR = 0; + +void +NUMOSdump(inModel, ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + register NUMOSmodel *model = (NUMOSmodel *) inModel; + register NUMOSinstance *inst; + OUTPcard *output; + FILE *fpState; + char fileName[BSIZE_SP]; + char description[BSIZE_SP]; + char *prefix; + int *state_num; + int anyOutput = 0; + + if (ckt->CKTmode & MODEDCOP) { + prefix = "OP"; + state_num = &state_numOP; + sprintf(description, "..."); + } else if (ckt->CKTmode & MODEDCTRANCURVE) { + prefix = "DC"; + state_num = &state_numDC; + sprintf(description, "sweep = % e", ckt->CKTtime); + } else if (ckt->CKTmode & MODETRAN) { + prefix = "TR"; + state_num = &state_numTR; + sprintf(description, "time = % e", ckt->CKTtime); + } else { + /* Not a recognized CKT mode. */ + return; + } + + for (; model != NULL; model = model->NUMOSnextModel) { + output = model->NUMOSoutputs; + for (inst = model->NUMOSinstances; inst != NULL; + inst = inst->NUMOSnextInstance) { + if (inst->NUMOSowner != ARCHme) continue; + + if (inst->NUMOSprintGiven) { + if ((ckt->CKTmode & MODETRAN) && + ((ckt->CKTstat->STATaccepted - 1) % inst->NUMOSprint != 0)) { + continue; + } + anyOutput = 1; + sprintf(fileName, "%s%s.%d.%s", output->OUTProotFile, prefix, + *state_num, inst->NUMOSname); + if (!(fpState = fopen(fileName, "w"))) { + perror(fileName); + } else { + NUMOSputHeader(fpState, ckt, inst); + TWOprnSolution(fpState, inst->NUMOSpDevice, + model->NUMOSoutputs); + fclose(fpState); + LOGmakeEntry(fileName, description); + } + } + } + } + if (anyOutput) { + (*state_num)++; + } +} + +#define NUMOSnumOutputs 10 + +static +void +NUMOSputHeader(file, ckt, inst) + FILE *file; + CKTcircuit *ckt; + NUMOSinstance *inst; +{ + char *reference; + double refVal = 0.0; + int numVars = NUMOSnumOutputs; + + if (ckt->CKTmode & MODEDCOP) { + reference = NULL; + } else if (ckt->CKTmode & MODEDCTRANCURVE) { + reference = "sweep"; + refVal = ckt->CKTtime; + numVars++; + } else if (ckt->CKTmode & MODETRAN) { + reference = "time"; + refVal = ckt->CKTtime; + numVars++; + } else { + reference = NULL; + } + fprintf(file, "Title: Device %s external state\n", inst->NUMOSname); + fprintf(file, "Plotname: Device Operating Point\n"); + fprintf(file, "Command: deftype v conductance S\n"); + fprintf(file, "Flags: real\n"); + fprintf(file, "No. Variables: %d\n", numVars); + fprintf(file, "No. Points: 1\n"); + numVars = 0; + fprintf(file, "Variables:\n"); + if (reference) { + fprintf(file, "\t%d %s unknown\n", numVars++, reference); + } + fprintf(file, "\t%d v14 voltage\n", numVars++); + fprintf(file, "\t%d v24 voltage\n", numVars++); + fprintf(file, "\t%d v34 voltage\n", numVars++); + fprintf(file, "\t%d i1 current\n", numVars++); + fprintf(file, "\t%d i2 current\n", numVars++); + fprintf(file, "\t%d i3 current\n", numVars++); + fprintf(file, "\t%d i4 current\n", numVars++); + fprintf(file, "\t%d g11 conductance\n", numVars++); + fprintf(file, "\t%d g12 conductance\n", numVars++); + fprintf(file, "\t%d g13 conductance\n", numVars++); + fprintf(file, "Values:\n0"); + if (reference) { + fprintf(file, "\t% e\n", refVal); + } + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NUMOSvdb)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NUMOSvgb)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NUMOSvsb)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NUMOSid)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NUMOSig)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NUMOSis)); + fprintf(file, "\t% e\n", -*(ckt->CKTstate0 + inst->NUMOSid) + - *(ckt->CKTstate0 + inst->NUMOSig) + - *(ckt->CKTstate0 + inst->NUMOSis)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NUMOSdIdDVdb)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NUMOSdIdDVgb)); + fprintf(file, "\t% e\n", *(ckt->CKTstate0 + inst->NUMOSdIdDVsb)); +} + +void +NUMOSacct(inModel, ckt, file) + GENmodel *inModel; + CKTcircuit *ckt; + FILE *file; +{ + register NUMOSmodel *model = (NUMOSmodel *) inModel; + register NUMOSinstance *inst; + OUTPcard *output; + + for (; model != NULL; model = model->NUMOSnextModel) { + output = model->NUMOSoutputs; + for (inst = model->NUMOSinstances; inst != NULL; + inst = inst->NUMOSnextInstance) { + if (inst->NUMOSowner != ARCHme) continue; + + if (output->OUTPstats) { + TWOmemStats(file, inst->NUMOSpDevice); + TWOcpuStats(file, inst->NUMOSpDevice); + } + } + } +} diff --git a/src/spicelib/devices/numos/nummload.c b/src/spicelib/devices/numos/nummload.c new file mode 100644 index 000000000..ffa574237 --- /dev/null +++ b/src/spicelib/devices/numos/nummload.c @@ -0,0 +1,639 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This is the function called each iteration to evaluate the 2d numerical + * MOSFETs in the circuit and load them into the matrix as appropriate + */ + +#include "ngspice.h" +#include "devdefs.h" +#include "cktdefs.h" +#include "numosdef.h" +#include "trandefs.h" +#include "sperror.h" +#include "../../../ciderlib/twod/twoddefs.h" +#include "../../../ciderlib/twod/twodext.h" +#include "cidersupt.h" +#include "suffix.h" + + + +/* External Declarations */ +extern int TWOdcDebug; +extern int TWOtranDebug; +extern int TWOacDebug; + +/* Forward Declarations */ + +int NUMOSinitSmSig(NUMOSinstance *inst); + +int +NUMOSload(inModel, ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + register NUMOSmodel *model = (NUMOSmodel *) inModel; + register NUMOSinstance *inst; + register TWOdevice *pDevice; + double startTime, startTime2, totalTime, totalTime2; + double tol; + double xfact; + double id, is, ig; + double ideq, iseq, igeq; + double idhat = 0.0, ishat = 0.0, ighat = 0.0; + double delVdb, delVsb, delVgb; + double vdb, vsb, vgb; + struct mosConductances g; + int icheck; + int icheck1; + int i; + double deltaNorm[7]; + int devConverged = 0; + int numDevNonCon; + int deviceType; + int doInitSolve; + int doVoltPred; + char *initStateName; + + /* loop through all the models */ + for (; model != NULL; model = model->NUMOSnextModel) { + FieldDepMobility = model->NUMOSmodels->MODLfieldDepMobility; + TransDepMobility = model->NUMOSmodels->MODLtransDepMobility; + SurfaceMobility = model->NUMOSmodels->MODLsurfaceMobility; + Srh = model->NUMOSmodels->MODLsrh; + Auger = model->NUMOSmodels->MODLauger; + AvalancheGen = model->NUMOSmodels->MODLavalancheGen; + OneCarrier = model->NUMOSmethods->METHoneCarrier; + MobDeriv = model->NUMOSmethods->METHmobDeriv; + MaxIterations = model->NUMOSmethods->METHitLim; + TWOdcDebug = model->NUMOSoutputs->OUTPdcDebug; + TWOtranDebug = model->NUMOSoutputs->OUTPtranDebug; + TWOacDebug = model->NUMOSoutputs->OUTPacDebug; + deviceType = model->NUMOSoptions->OPTNdeviceType; + doVoltPred = model->NUMOSmethods->METHvoltPred; + + if (ckt->CKTmode & MODEINITPRED) { + /* compute normalized deltas and predictor coeff */ + if (!(ckt->CKTmode & MODEDCTRANCURVE)) { + model->NUMOSpInfo->order = ckt->CKTorder; + model->NUMOSpInfo->method = ckt->CKTintegrateMethod; + for (i = 0; i <= ckt->CKTmaxOrder; i++) { + deltaNorm[i] = ckt->CKTdeltaOld[i] / TNorm; + } + computeIntegCoeff(ckt->CKTintegrateMethod, ckt->CKTorder, + model->NUMOSpInfo->intCoeff, deltaNorm); + computePredCoeff(ckt->CKTintegrateMethod, ckt->CKTorder, + model->NUMOSpInfo->predCoeff, deltaNorm); + } + } else if (ckt->CKTmode & MODEINITTRAN) { + model->NUMOSpInfo->order = ckt->CKTorder; + model->NUMOSpInfo->method = ckt->CKTintegrateMethod; + for (i = 0; i <= ckt->CKTmaxOrder; i++) { + deltaNorm[i] = ckt->CKTdeltaOld[i] / TNorm; + } + computeIntegCoeff(ckt->CKTintegrateMethod, ckt->CKTorder, + model->NUMOSpInfo->intCoeff, deltaNorm); + } + /* loop through all the instances of the model */ + for (inst = model->NUMOSinstances; inst != NULL; + inst = inst->NUMOSnextInstance) { + if (inst->NUMOSowner != ARCHme) continue; + + pDevice = inst->NUMOSpDevice; + + totalTime = 0.0; + startTime = SPfrontEnd->IFseconds(); + + /* Get Temp.-Dep. Global Parameters */ + GLOBgetGlobals(&(inst->NUMOSglobals)); + + /* + * initialization + */ + pDevice->devStates = ckt->CKTstates; + icheck = 1; + doInitSolve = FALSE; + initStateName = NULL; + if (ckt->CKTmode & MODEINITSMSIG) { + vdb = *(ckt->CKTstate0 + inst->NUMOSvdb); + vsb = *(ckt->CKTstate0 + inst->NUMOSvsb); + vgb = *(ckt->CKTstate0 + inst->NUMOSvgb); + delVdb = 0.0; + delVsb = 0.0; + delVgb = 0.0; + NUMOSsetBCs(pDevice, vdb, vsb, vgb); + } else if (ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate0 + inst->NUMOSvdb) = + *(ckt->CKTstate1 + inst->NUMOSvdb); + *(ckt->CKTstate0 + inst->NUMOSvsb) = + *(ckt->CKTstate1 + inst->NUMOSvsb); + *(ckt->CKTstate0 + inst->NUMOSvgb) = + *(ckt->CKTstate1 + inst->NUMOSvgb); + vdb = *(ckt->CKTstate1 + inst->NUMOSvdb); + vsb = *(ckt->CKTstate1 + inst->NUMOSvsb); + vgb = *(ckt->CKTstate1 + inst->NUMOSvgb); + TWOsaveState(pDevice); + delVdb = 0.0; + delVsb = 0.0; + delVgb = 0.0; + } else if ((ckt->CKTmode & MODEINITJCT) && + (ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) { + doInitSolve = TRUE; + initStateName = inst->NUMOSicFile; + vdb = 0.0; + vsb = 0.0; + vgb = 0.0; + delVdb = vdb; + delVsb = vsb; + delVgb = vgb; + } else if ((ckt->CKTmode & MODEINITJCT) && (inst->NUMOSoff == 0)) { + doInitSolve = TRUE; + initStateName = inst->NUMOSicFile; + if (deviceType == OPTN_BIPOLAR) { + /* d,g,s,b => c,b,e,s */ + vdb = 0.0; + vsb = -inst->NUMOStype * 1.0; + vgb = -inst->NUMOStype * (1.0 - 0.6); + } else if (deviceType == OPTN_JFET) { + vdb = inst->NUMOStype * 0.5; + vsb = 0.0; + vgb = 0.0; + } else { + vdb = inst->NUMOStype * 0.5; + vsb = 0.0; + vgb = inst->NUMOStype * 1.0; + } + delVdb = vdb; + delVsb = vsb; + delVgb = vgb; + } else if (ckt->CKTmode & MODEINITJCT) { + doInitSolve = TRUE; + vdb = 0.0; + vsb = 0.0; + vgb = 0.0; + delVdb = vdb; + delVsb = vsb; + delVgb = vgb; + } else if ((ckt->CKTmode & MODEINITFIX) && inst->NUMOSoff) { + vdb = 0.0; + vsb = 0.0; + vgb = 0.0; + delVdb = vdb; + delVsb = vsb; + delVgb = vgb; + } else { + if (ckt->CKTmode & MODEINITPRED) { + *(ckt->CKTstate0 + inst->NUMOSvdb) = + *(ckt->CKTstate1 + inst->NUMOSvdb); + *(ckt->CKTstate0 + inst->NUMOSvsb) = + *(ckt->CKTstate1 + inst->NUMOSvsb); + *(ckt->CKTstate0 + inst->NUMOSvgb) = + *(ckt->CKTstate1 + inst->NUMOSvgb); + *(ckt->CKTstate0 + inst->NUMOSid) = + *(ckt->CKTstate1 + inst->NUMOSid); + *(ckt->CKTstate0 + inst->NUMOSis) = + *(ckt->CKTstate1 + inst->NUMOSis); + *(ckt->CKTstate0 + inst->NUMOSig) = + *(ckt->CKTstate1 + inst->NUMOSig); + *(ckt->CKTstate0 + inst->NUMOSdIdDVdb) = + *(ckt->CKTstate1 + inst->NUMOSdIdDVdb); + *(ckt->CKTstate0 + inst->NUMOSdIdDVsb) = + *(ckt->CKTstate1 + inst->NUMOSdIdDVsb); + *(ckt->CKTstate0 + inst->NUMOSdIdDVgb) = + *(ckt->CKTstate1 + inst->NUMOSdIdDVgb); + *(ckt->CKTstate0 + inst->NUMOSdIsDVdb) = + *(ckt->CKTstate1 + inst->NUMOSdIsDVdb); + *(ckt->CKTstate0 + inst->NUMOSdIsDVsb) = + *(ckt->CKTstate1 + inst->NUMOSdIsDVsb); + *(ckt->CKTstate0 + inst->NUMOSdIsDVgb) = + *(ckt->CKTstate1 + inst->NUMOSdIsDVgb); + *(ckt->CKTstate0 + inst->NUMOSdIgDVdb) = + *(ckt->CKTstate1 + inst->NUMOSdIgDVdb); + *(ckt->CKTstate0 + inst->NUMOSdIgDVsb) = + *(ckt->CKTstate1 + inst->NUMOSdIgDVsb); + *(ckt->CKTstate0 + inst->NUMOSdIgDVgb) = + *(ckt->CKTstate1 + inst->NUMOSdIgDVgb); + if (!(ckt->CKTmode & MODEDCTRANCURVE)) { + /* no linear prediction on device voltages */ + vdb = *(ckt->CKTstate1 + inst->NUMOSvdb); + vsb = *(ckt->CKTstate1 + inst->NUMOSvsb); + vgb = *(ckt->CKTstate1 + inst->NUMOSvgb); + TWOpredict(pDevice, model->NUMOSpInfo); + } else { + if (doVoltPred) { + /* linear prediction */ + xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1]; + vdb = (1+xfact) * (*(ckt->CKTstate1 + inst->NUMOSvdb)) + - (xfact) * (*(ckt->CKTstate2 + inst->NUMOSvdb)); + vsb = (1+xfact) * (*(ckt->CKTstate1 + inst->NUMOSvsb)) + - (xfact) * (*(ckt->CKTstate2 + inst->NUMOSvsb)); + vgb = (1+xfact) * (*(ckt->CKTstate1 + inst->NUMOSvgb)) + - (xfact) * (*(ckt->CKTstate2 + inst->NUMOSvgb)); + } else { + vdb = *(ckt->CKTstate1 + inst->NUMOSvdb); + vsb = *(ckt->CKTstate1 + inst->NUMOSvsb); + vgb = *(ckt->CKTstate1 + inst->NUMOSvgb); + } + } + } else { + /* + * compute new nonlinear branch voltages + */ + vdb = *(ckt->CKTrhsOld + inst->NUMOSdrainNode) + - *(ckt->CKTrhsOld + inst->NUMOSbulkNode); + vsb = *(ckt->CKTrhsOld + inst->NUMOSsourceNode) + - *(ckt->CKTrhsOld + inst->NUMOSbulkNode); + vgb = *(ckt->CKTrhsOld + inst->NUMOSgateNode) + - *(ckt->CKTrhsOld + inst->NUMOSbulkNode); + } + delVdb = vdb - *(ckt->CKTstate0 + inst->NUMOSvdb); + delVsb = vsb - *(ckt->CKTstate0 + inst->NUMOSvsb); + delVgb = vgb - *(ckt->CKTstate0 + inst->NUMOSvgb); + idhat = *(ckt->CKTstate0 + inst->NUMOSid) + + *(ckt->CKTstate0 + inst->NUMOSdIdDVdb) * delVdb + + *(ckt->CKTstate0 + inst->NUMOSdIdDVsb) * delVsb + + *(ckt->CKTstate0 + inst->NUMOSdIdDVgb) * delVgb; + ishat = *(ckt->CKTstate0 + inst->NUMOSis) + + *(ckt->CKTstate0 + inst->NUMOSdIsDVdb) * delVdb + + *(ckt->CKTstate0 + inst->NUMOSdIsDVsb) * delVsb + + *(ckt->CKTstate0 + inst->NUMOSdIsDVgb) * delVgb; + ighat = *(ckt->CKTstate0 + inst->NUMOSig) + + *(ckt->CKTstate0 + inst->NUMOSdIgDVdb) * delVdb + + *(ckt->CKTstate0 + inst->NUMOSdIgDVsb) * delVsb + + *(ckt->CKTstate0 + inst->NUMOSdIgDVgb) * delVgb; + + +#ifndef NOBYPASS + /* + * bypass if solution has not changed + */ + /* + * the following collections of if's would be just one if the average + * compiler could handle it, but many find the expression too + * complicated, thus the split. + */ + if ((ckt->CKTbypass) && pDevice->converged && + (!(ckt->CKTmode & MODEINITPRED)) && + (fabs(delVdb) < (ckt->CKTreltol * MAX(fabs(vdb), + fabs(*(ckt->CKTstate0 + inst->NUMOSvdb))) + + ckt->CKTvoltTol))) + if ((fabs(delVsb) < ckt->CKTreltol * MAX(fabs(vsb), + fabs(*(ckt->CKTstate0 + inst->NUMOSvsb))) + + ckt->CKTvoltTol)) + if ((fabs(delVgb) < ckt->CKTreltol * MAX(fabs(vgb), + fabs(*(ckt->CKTstate0 + inst->NUMOSvgb))) + + ckt->CKTvoltTol)) + if ((fabs(idhat - *(ckt->CKTstate0 + inst->NUMOSid)) < + ckt->CKTreltol * MAX(fabs(idhat), + fabs(*(ckt->CKTstate0 + inst->NUMOSid))) + + ckt->CKTabstol)) + if ((fabs(ishat - *(ckt->CKTstate0 + inst->NUMOSis)) < + ckt->CKTreltol * MAX(fabs(ishat), + fabs(*(ckt->CKTstate0 + inst->NUMOSis))) + + ckt->CKTabstol)) + if ((fabs(ighat - *(ckt->CKTstate0 + inst->NUMOSig)) < + ckt->CKTreltol * MAX(fabs(ighat), + fabs(*(ckt->CKTstate0 + inst->NUMOSig))) + + ckt->CKTabstol)) { + /* + * bypassing.... + */ + vdb = *(ckt->CKTstate0 + inst->NUMOSvdb); + vsb = *(ckt->CKTstate0 + inst->NUMOSvsb); + vgb = *(ckt->CKTstate0 + inst->NUMOSvgb); + id = *(ckt->CKTstate0 + inst->NUMOSid); + is = *(ckt->CKTstate0 + inst->NUMOSis); + ig = *(ckt->CKTstate0 + inst->NUMOSig); + g.dIdDVdb = *(ckt->CKTstate0 + inst->NUMOSdIdDVdb); + g.dIdDVsb = *(ckt->CKTstate0 + inst->NUMOSdIdDVsb); + g.dIdDVgb = *(ckt->CKTstate0 + inst->NUMOSdIdDVgb); + g.dIsDVdb = *(ckt->CKTstate0 + inst->NUMOSdIsDVdb); + g.dIsDVsb = *(ckt->CKTstate0 + inst->NUMOSdIsDVsb); + g.dIsDVgb = *(ckt->CKTstate0 + inst->NUMOSdIsDVgb); + g.dIgDVdb = *(ckt->CKTstate0 + inst->NUMOSdIgDVdb); + g.dIgDVsb = *(ckt->CKTstate0 + inst->NUMOSdIgDVsb); + g.dIgDVgb = *(ckt->CKTstate0 + inst->NUMOSdIgDVgb); + goto load; + } +#endif /* NOBYPASS */ + /* + * limit nonlinear branch voltages + */ + icheck1 = 1; + if (deviceType == OPTN_BIPOLAR) { + double vbe, vbe0; + double vce, vce0; + + vdb = -inst->NUMOStype * limitJunctionVoltage(-inst->NUMOStype * vdb, + -inst->NUMOStype * *(ckt->CKTstate0 + inst->NUMOSvdb), &icheck); + vce = vdb - vsb; + vce0 = *(ckt->CKTstate0 + inst->NUMOSvdb) - + *(ckt->CKTstate0 + inst->NUMOSvsb); + vce = inst->NUMOStype * limitVce(inst->NUMOStype * vce, + inst->NUMOStype * vce0, &icheck1); + if (icheck1 == 1) + icheck = 1; + vsb = vdb - vce; + vbe = vgb - vsb; + vbe0 = *(ckt->CKTstate0 + inst->NUMOSvgb) - + *(ckt->CKTstate0 + inst->NUMOSvsb); + vbe = inst->NUMOStype * limitVbe(inst->NUMOStype * vbe, + inst->NUMOStype * vbe0, &icheck1); + if (icheck1 == 1) + icheck = 1; + vgb = vbe + vsb; + } else { + vdb = -inst->NUMOStype * limitJunctionVoltage(-inst->NUMOStype * vdb, + -inst->NUMOStype * *(ckt->CKTstate0 + inst->NUMOSvdb), &icheck); + vsb = -inst->NUMOStype * limitJunctionVoltage(-inst->NUMOStype * vsb, + -inst->NUMOStype * *(ckt->CKTstate0 + inst->NUMOSvsb), &icheck1); + if (icheck1 == 1) + icheck = 1; + vgb = inst->NUMOStype * limitVgb(inst->NUMOStype * vgb, + inst->NUMOStype * *(ckt->CKTstate0 + inst->NUMOSvgb), &icheck1); + if (icheck1 == 1) + icheck = 1; + } + delVdb = vdb - *(ckt->CKTstate0 + inst->NUMOSvdb); + delVsb = vsb - *(ckt->CKTstate0 + inst->NUMOSvsb); + delVgb = vgb - *(ckt->CKTstate0 + inst->NUMOSvgb); + NUMOSsetBCs(pDevice, vdb - delVdb, vsb - delVsb, vgb - delVgb); + } + + if (doInitSolve) { + if (TWOdcDebug) { + printVoltages(stdout, model->NUMOSmodName, inst->NUMOSname, + deviceType, 3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + } + startTime2 = SPfrontEnd->IFseconds(); + TWOequilSolve(pDevice); + totalTime2 = SPfrontEnd->IFseconds() - startTime2; + pDevice->pStats->totalTime[STAT_SETUP] += totalTime2; + pDevice->pStats->totalTime[STAT_DC] -= totalTime2; + + TWObiasSolve(pDevice, MaxIterations, FALSE, NULL); + + *(ckt->CKTstate0 + inst->NUMOSvdb) = 0.0; + *(ckt->CKTstate0 + inst->NUMOSvsb) = 0.0; + *(ckt->CKTstate0 + inst->NUMOSvgb) = 0.0; + + if (initStateName != NULL) { + if (TWOreadState(pDevice, initStateName, 3, &vdb, &vgb, &vsb ) < 0) { + fprintf(stderr, + "NUMOSload: trouble reading state-file %s\n", initStateName); + } else { + NUMOSsetBCs(pDevice, vdb, vsb, vgb); + delVdb = delVsb = delVgb = 0.0; + } + } + } + /* + * determine dc current and derivatives using the numerical routines + */ + if (ckt->CKTmode & (MODEDCOP | MODETRANOP | MODEDCTRANCURVE | MODEINITSMSIG)) { + numDevNonCon = 0; + inst->NUMOSc11 = inst->NUMOSy11r = inst->NUMOSy11i = 0.0; + inst->NUMOSc12 = inst->NUMOSy12r = inst->NUMOSy12i = 0.0; + inst->NUMOSc13 = inst->NUMOSy13r = inst->NUMOSy13i = 0.0; + inst->NUMOSc21 = inst->NUMOSy21r = inst->NUMOSy21i = 0.0; + inst->NUMOSc22 = inst->NUMOSy22r = inst->NUMOSy22i = 0.0; + inst->NUMOSc23 = inst->NUMOSy23r = inst->NUMOSy23i = 0.0; + inst->NUMOSc31 = inst->NUMOSy31r = inst->NUMOSy31i = 0.0; + inst->NUMOSc32 = inst->NUMOSy32r = inst->NUMOSy32i = 0.0; + inst->NUMOSc33 = inst->NUMOSy33r = inst->NUMOSy33i = 0.0; + inst->NUMOSsmSigAvail = FALSE; + devNonCon: + NUMOSproject(pDevice, delVdb, delVsb, delVgb); + if (TWOdcDebug) { + printVoltages(stdout, model->NUMOSmodName, inst->NUMOSname, + deviceType, 3, vdb, delVdb, vgb, delVgb, vsb, delVsb); + } + TWObiasSolve(pDevice, MaxIterations, FALSE, model->NUMOSpInfo); + + devConverged = pDevice->converged; + if (devConverged && finite(pDevice->rhsNorm)) { + /* compute the currents */ + NUMOScurrent(pDevice, FALSE, (double *) NULL, &id, &is, &ig); + NUMOSconductance(pDevice, FALSE, (double *) NULL, &g); + /* + * Add gmin to the gate conductance terms since they will be zero. + * XXX This messes up the gXY output values, but we choose not to + * correct this error, because it shouldn't cause practical problems. + */ + g.dIgDVdb += ckt->CKTgmin; + g.dIgDVsb += ckt->CKTgmin; + g.dIgDVgb += ckt->CKTgmin; + + } else { + /* reduce the voltage step until converged */ + /* restore boundary nodes to previous potential */ + NUMOSsetBCs(pDevice, + vdb - delVdb, vsb - delVsb, vgb - delVgb); + TWOstoreInitialGuess(pDevice); + TWOresetJacobian(pDevice); + delVdb *= 0.5; + delVsb *= 0.5; + delVgb *= 0.5; + vdb = delVdb + *(ckt->CKTstate0 + inst->NUMOSvdb); + vsb = delVsb + *(ckt->CKTstate0 + inst->NUMOSvsb); + vgb = delVgb + *(ckt->CKTstate0 + inst->NUMOSvgb); + numDevNonCon++; + icheck = 1; + if (numDevNonCon > 10) { + printVoltages(stderr, model->NUMOSmodName, inst->NUMOSname, + deviceType, 3, vdb, delVdb, vgb, delVgb, vsb, delVsb); + fprintf(stderr, "*** Non-convergence during load ***\n"); + totalTime += SPfrontEnd->IFseconds() - startTime; + pDevice->pStats->totalTime[STAT_DC] += totalTime; + ckt->CKTtroubleElt = (GENinstance *) inst; + return (E_BADMATRIX); + } else { + goto devNonCon; + } + } + } + if ((ckt->CKTmode & (MODETRAN | MODEAC)) || + ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) || + (ckt->CKTmode & MODEINITSMSIG)) { + /* + * store small-signal parameters + */ + if ((!(ckt->CKTmode & MODETRANOP)) || + (!(ckt->CKTmode & MODEUIC))) { + if (ckt->CKTmode & MODEINITSMSIG) { + totalTime += SPfrontEnd->IFseconds() - startTime; + pDevice->pStats->totalTime[STAT_DC] += totalTime; + startTime2 = SPfrontEnd->IFseconds(); + NUMOSinitSmSig(inst); + pDevice->pStats->totalTime[STAT_AC] += + SPfrontEnd->IFseconds() - startTime2; + continue; + } else { + inst->NUMOSsmSigAvail = FALSE; + } + /* + * transient analysis + */ + if (ckt->CKTmode & MODEINITPRED) { + NUMOSsetBCs(pDevice, vdb, vsb, vgb); + TWOstoreInitialGuess(pDevice); + } else { + NUMOSupdate(pDevice, delVdb, delVsb, delVgb, TRUE); + } + if (TWOtranDebug) { + printVoltages(stdout, model->NUMOSmodName, inst->NUMOSname, + deviceType, 3, vdb, delVdb, vgb, delVgb, vsb, delVsb); + } + TWObiasSolve(pDevice, 0, TRUE, model->NUMOSpInfo); + if (!finite(pDevice->rhsNorm)) { + totalTime += SPfrontEnd->IFseconds() - startTime; + pDevice->pStats->totalTime[STAT_TRAN] += totalTime; + ckt->CKTtroubleElt = (GENinstance *) inst; + return (E_BADMATRIX); + } + devConverged = TWOdeviceConverged(pDevice); + pDevice->converged = devConverged; + + /* compute the currents and conductances */ + NUMOScurrent(pDevice, TRUE, model->NUMOSpInfo->intCoeff, + &id, &is, &ig); + NUMOSconductance(pDevice, TRUE, + model->NUMOSpInfo->intCoeff, &g); + } + } + /* + * check convergence + */ + if ((!(ckt->CKTmode & MODEINITFIX)) || (!(inst->NUMOSoff))) { + if (icheck == 1 || !devConverged) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) inst; + } else { + tol = ckt->CKTreltol * MAX(fabs(idhat), fabs(id)) + ckt->CKTabstol; + if (fabs(idhat - id) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) inst; + } else { + tol = ckt->CKTreltol * MAX(fabs(ishat), fabs(is)) + + ckt->CKTabstol; + if (fabs(ishat - is) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) inst; + } else { + tol = ckt->CKTreltol * MAX(fabs(ighat), fabs(ig)) + + ckt->CKTabstol; + if (fabs(ighat - ig) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) inst; + } + } + } + } + } + *(ckt->CKTstate0 + inst->NUMOSvdb) = vdb; + *(ckt->CKTstate0 + inst->NUMOSvsb) = vsb; + *(ckt->CKTstate0 + inst->NUMOSvgb) = vgb; + *(ckt->CKTstate0 + inst->NUMOSid) = id; + *(ckt->CKTstate0 + inst->NUMOSis) = is; + *(ckt->CKTstate0 + inst->NUMOSig) = ig; + *(ckt->CKTstate0 + inst->NUMOSdIdDVdb) = g.dIdDVdb; + *(ckt->CKTstate0 + inst->NUMOSdIdDVsb) = g.dIdDVsb; + *(ckt->CKTstate0 + inst->NUMOSdIdDVgb) = g.dIdDVgb; + *(ckt->CKTstate0 + inst->NUMOSdIsDVdb) = g.dIsDVdb; + *(ckt->CKTstate0 + inst->NUMOSdIsDVsb) = g.dIsDVsb; + *(ckt->CKTstate0 + inst->NUMOSdIsDVgb) = g.dIsDVgb; + *(ckt->CKTstate0 + inst->NUMOSdIgDVdb) = g.dIgDVdb; + *(ckt->CKTstate0 + inst->NUMOSdIgDVsb) = g.dIgDVsb; + *(ckt->CKTstate0 + inst->NUMOSdIgDVgb) = g.dIgDVgb; + + load: + /* + * load current excitation vector + */ + + ideq = id - g.dIdDVdb * vdb - g.dIdDVsb * vsb - g.dIdDVgb * vgb; + iseq = is - g.dIsDVdb * vdb - g.dIsDVsb * vsb - g.dIsDVgb * vgb; + igeq = ig - g.dIgDVdb * vdb - g.dIgDVsb * vsb - g.dIgDVgb * vgb; + *(ckt->CKTrhs + inst->NUMOSdrainNode) -= ideq; + *(ckt->CKTrhs + inst->NUMOSsourceNode) -= iseq; + *(ckt->CKTrhs + inst->NUMOSgateNode) -= igeq; + *(ckt->CKTrhs + inst->NUMOSbulkNode) += ideq + iseq + igeq; + /* + * load y matrix + */ + + *(inst->NUMOSdrainDrainPtr) += g.dIdDVdb; + *(inst->NUMOSdrainSourcePtr) += g.dIdDVsb; + *(inst->NUMOSdrainGatePtr) += g.dIdDVgb; + *(inst->NUMOSdrainBulkPtr) -= g.dIdDVdb + g.dIdDVsb + g.dIdDVgb; + + *(inst->NUMOSsourceDrainPtr) += g.dIsDVdb; + *(inst->NUMOSsourceSourcePtr) += g.dIsDVsb; + *(inst->NUMOSsourceGatePtr) += g.dIsDVgb; + *(inst->NUMOSsourceBulkPtr) -= g.dIsDVdb + g.dIsDVsb + g.dIsDVgb; + + *(inst->NUMOSgateDrainPtr) += g.dIgDVdb; + *(inst->NUMOSgateSourcePtr) += g.dIgDVsb; + *(inst->NUMOSgateGatePtr) += g.dIgDVgb; + *(inst->NUMOSgateBulkPtr) -= g.dIgDVdb + g.dIgDVsb + g.dIgDVgb; + + *(inst->NUMOSbulkDrainPtr) -= g.dIdDVdb + g.dIsDVdb + g.dIgDVdb; + *(inst->NUMOSbulkSourcePtr) -= g.dIdDVsb + g.dIsDVsb + g.dIgDVsb; + *(inst->NUMOSbulkGatePtr) -= g.dIdDVgb + g.dIsDVgb + g.dIgDVgb; + *(inst->NUMOSbulkBulkPtr) += g.dIdDVdb + g.dIdDVsb + g.dIdDVgb + + g.dIsDVdb + g.dIsDVsb + g.dIsDVgb + + g.dIgDVdb + g.dIgDVsb + g.dIgDVgb; + + totalTime += SPfrontEnd->IFseconds() - startTime; + if (ckt->CKTmode & MODETRAN) { + pDevice->pStats->totalTime[STAT_TRAN] += totalTime; + } else { + pDevice->pStats->totalTime[STAT_DC] += totalTime; + } + } + } + return (OK); +} + +int +NUMOSinitSmSig(inst) + NUMOSinstance *inst; +{ + struct mosAdmittances yAc; + double omega = inst->NUMOSmodPtr->NUMOSmethods->METHomega; + + AcAnalysisMethod = SOR_ONLY; + (void) NUMOSadmittance(inst->NUMOSpDevice, omega, &yAc); + inst->NUMOSc11 = yAc.yIdVdb.imag / omega; + inst->NUMOSc12 = yAc.yIdVgb.imag / omega; + inst->NUMOSc13 = yAc.yIdVsb.imag / omega; + inst->NUMOSc21 = yAc.yIgVdb.imag / omega; + inst->NUMOSc22 = yAc.yIgVgb.imag / omega; + inst->NUMOSc23 = yAc.yIgVsb.imag / omega; + inst->NUMOSc31 = yAc.yIsVdb.imag / omega; + inst->NUMOSc32 = yAc.yIsVgb.imag / omega; + inst->NUMOSc33 = yAc.yIsVsb.imag / omega; + inst->NUMOSy11r = yAc.yIdVdb.real; + inst->NUMOSy11i = yAc.yIdVdb.imag; + inst->NUMOSy12r = yAc.yIdVgb.real; + inst->NUMOSy12i = yAc.yIdVgb.imag; + inst->NUMOSy13r = yAc.yIdVsb.real; + inst->NUMOSy13i = yAc.yIdVsb.imag; + inst->NUMOSy21r = yAc.yIgVdb.real; + inst->NUMOSy21i = yAc.yIgVdb.imag; + inst->NUMOSy22r = yAc.yIgVgb.real; + inst->NUMOSy22i = yAc.yIgVgb.imag; + inst->NUMOSy23r = yAc.yIgVsb.real; + inst->NUMOSy23i = yAc.yIgVsb.imag; + inst->NUMOSy31r = yAc.yIsVdb.real; + inst->NUMOSy31i = yAc.yIsVdb.imag; + inst->NUMOSy32r = yAc.yIsVgb.real; + inst->NUMOSy32i = yAc.yIsVgb.imag; + inst->NUMOSy33r = yAc.yIsVsb.real; + inst->NUMOSy33i = yAc.yIsVsb.imag; + inst->NUMOSsmSigAvail = TRUE; + return (OK); +} diff --git a/src/spicelib/devices/numos/nummmdel.c b/src/spicelib/devices/numos/nummmdel.c new file mode 100644 index 000000000..6d029af74 --- /dev/null +++ b/src/spicelib/devices/numos/nummmdel.c @@ -0,0 +1,43 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This routine deletes a NUMOS model from the circuit and frees the storage + * it was using. returns an error if the model has instances + */ + +#include "ngspice.h" +#include "numosdef.h" +#include "sperror.h" +#include "suffix.h" + +int +NUMOSmDelete(inModel, modname, kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; + +{ + + NUMOSmodel **model = (NUMOSmodel **) inModel; + NUMOSmodel *modfast = (NUMOSmodel *) kill; + NUMOSmodel **oldmod; + oldmod = model; + for (; *model; model = &((*model)->NUMOSnextModel)) { + if ((*model)->NUMOSmodName == modname || + (modfast && *model == modfast)) + goto delgot; + oldmod = model; + } + return (E_NOMOD); + +delgot: + if ((*model)->NUMOSinstances) + return (E_NOTEMPTY); + *oldmod = (*model)->NUMOSnextModel; /* cut deleted device out of list */ + FREE(*model); + return (OK); + +} diff --git a/src/spicelib/devices/numos/nummmpar.c b/src/spicelib/devices/numos/nummmpar.c new file mode 100644 index 000000000..a1fd26872 --- /dev/null +++ b/src/spicelib/devices/numos/nummmpar.c @@ -0,0 +1,32 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This routine sets model parameters for NUMOSs in the circuit. + */ + +#include "ngspice.h" +#include "const.h" +#include "ifsim.h" +#include "numosdef.h" +#include "sperror.h" +#include "suffix.h" + +int +NUMOSmParam(param, value, inModel) + int param; + IFvalue *value; + GENmodel *inModel; +{ + switch (param) { + case NUMOS_MOD_NUMOS: + /* no action - already know it is a 2d-numerical MOS, but this */ + /* makes life easier for spice-2 like parsers */ + break; + default: + return (E_BADPARM); + } + return (OK); +} diff --git a/src/spicelib/devices/numos/nummparm.c b/src/spicelib/devices/numos/nummparm.c new file mode 100644 index 000000000..24675eec7 --- /dev/null +++ b/src/spicelib/devices/numos/nummparm.c @@ -0,0 +1,57 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This routine sets instance parameters for NUMOSs in the circuit. + */ + +#include "ngspice.h" +#include "const.h" +#include "ifsim.h" +#include "numosdef.h" +#include "sperror.h" +#include "suffix.h" + +int +NUMOSparam(param, value, inInst, select) + int param; + IFvalue *value; + GENinstance *inInst; + IFvalue *select; +{ + register NUMOSinstance *inst = (NUMOSinstance *) inInst; + switch (param) { + case NUMOS_AREA: + inst->NUMOSarea = value->rValue; + inst->NUMOSareaGiven = TRUE; + break; + case NUMOS_WIDTH: + inst->NUMOSwidth = value->rValue; + inst->NUMOSwidthGiven = TRUE; + break; + case NUMOS_LENGTH: + inst->NUMOSlength = value->rValue; + inst->NUMOSlengthGiven = TRUE; + break; + case NUMOS_OFF: + inst->NUMOSoff = TRUE; + break; + case NUMOS_IC_FILE: + inst->NUMOSicFile = value->sValue; + inst->NUMOSicFileGiven = TRUE; + break; + case NUMOS_PRINT: + inst->NUMOSprint = value->rValue; + inst->NUMOSprintGiven = TRUE; + break; + case NUMOS_TEMP: + inst->NUMOStemp = value->rValue + CONSTCtoK; + inst->NUMOStempGiven = TRUE; + break; + default: + return (E_BADPARM); + } + return (OK); +} diff --git a/src/spicelib/devices/numos/nummpzld.c b/src/spicelib/devices/numos/nummpzld.c new file mode 100644 index 000000000..bb5de01d5 --- /dev/null +++ b/src/spicelib/devices/numos/nummpzld.c @@ -0,0 +1,113 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "cktdefs.h" +#include "complex.h" +#include "numosdef.h" +#include "sperror.h" +#include "../../../ciderlib/twod/twoddefs.h" +#include "../../../ciderlib/twod/twodext.h" +#include "cidersupt.h" +#include "suffix.h" + +/* External Declarations */ +extern int TWOacDebug; + + +int +NUMOSpzLoad(inModel, ckt, s) + GENmodel *inModel; + CKTcircuit *ckt; + SPcomplex *s; + +{ + register NUMOSmodel *model = (NUMOSmodel *) inModel; + register NUMOSinstance *inst; + struct mosAdmittances yAc; + double startTime; + + for (; model != NULL; model = model->NUMOSnextModel) { + FieldDepMobility = model->NUMOSmodels->MODLfieldDepMobility; + TransDepMobility = model->NUMOSmodels->MODLtransDepMobility; + SurfaceMobility = model->NUMOSmodels->MODLsurfaceMobility; + Srh = model->NUMOSmodels->MODLsrh; + Auger = model->NUMOSmodels->MODLauger; + AvalancheGen = model->NUMOSmodels->MODLavalancheGen; + OneCarrier = model->NUMOSmethods->METHoneCarrier; + AcAnalysisMethod = model->NUMOSmethods->METHacAnalysisMethod; + MobDeriv = model->NUMOSmethods->METHmobDeriv; + TWOacDebug = model->NUMOSoutputs->OUTPacDebug; + + for (inst = model->NUMOSinstances; inst != NULL; + inst = inst->NUMOSnextInstance) { + if (inst->NUMOSowner != ARCHme) continue; + + startTime = SPfrontEnd->IFseconds(); + /* Get Temp.-Dep. Global Parameters */ + GLOBgetGlobals(&(inst->NUMOSglobals)); + + NUMOSys(inst->NUMOSpDevice, s, &yAc); + + *(inst->NUMOSdrainDrainPtr) += yAc.yIdVdb.real; + *(inst->NUMOSdrainDrainPtr + 1) += yAc.yIdVdb.imag; + *(inst->NUMOSdrainSourcePtr) += yAc.yIdVsb.real; + *(inst->NUMOSdrainSourcePtr + 1) += yAc.yIdVsb.imag; + *(inst->NUMOSdrainGatePtr) += yAc.yIdVgb.real; + *(inst->NUMOSdrainGatePtr + 1) += yAc.yIdVgb.imag; + *(inst->NUMOSdrainBulkPtr) -= + yAc.yIdVdb.real + yAc.yIdVsb.real + yAc.yIdVgb.real; + *(inst->NUMOSdrainBulkPtr + 1) -= + yAc.yIdVdb.imag + yAc.yIdVsb.imag + yAc.yIdVgb.imag; + + *(inst->NUMOSsourceDrainPtr) += yAc.yIsVdb.real; + *(inst->NUMOSsourceDrainPtr + 1) += yAc.yIsVdb.imag; + *(inst->NUMOSsourceSourcePtr) += yAc.yIsVsb.real; + *(inst->NUMOSsourceSourcePtr + 1) += yAc.yIsVsb.imag; + *(inst->NUMOSsourceGatePtr) += yAc.yIsVgb.real; + *(inst->NUMOSsourceGatePtr + 1) += yAc.yIsVgb.imag; + *(inst->NUMOSsourceBulkPtr) -= + yAc.yIsVdb.real + yAc.yIsVsb.real + yAc.yIsVgb.real; + *(inst->NUMOSsourceBulkPtr + 1) -= + yAc.yIsVdb.imag + yAc.yIsVsb.imag + yAc.yIsVgb.imag; + + *(inst->NUMOSgateDrainPtr) += yAc.yIgVdb.real; + *(inst->NUMOSgateDrainPtr + 1) += yAc.yIgVdb.imag; + *(inst->NUMOSgateSourcePtr) += yAc.yIgVsb.real; + *(inst->NUMOSgateSourcePtr + 1) += yAc.yIgVsb.imag; + *(inst->NUMOSgateGatePtr) += yAc.yIgVgb.real; + *(inst->NUMOSgateGatePtr + 1) += yAc.yIgVgb.imag; + *(inst->NUMOSgateBulkPtr) -= + yAc.yIgVdb.real + yAc.yIgVsb.real + yAc.yIgVgb.real; + *(inst->NUMOSgateBulkPtr + 1) -= + yAc.yIgVdb.imag + yAc.yIgVsb.imag + yAc.yIgVgb.imag; + + *(inst->NUMOSbulkDrainPtr) -= + yAc.yIdVdb.real + yAc.yIsVdb.real + yAc.yIgVdb.real; + *(inst->NUMOSbulkDrainPtr + 1) -= + yAc.yIdVdb.imag + yAc.yIsVdb.imag + yAc.yIgVdb.imag; + *(inst->NUMOSbulkSourcePtr) -= + yAc.yIdVsb.real + yAc.yIsVsb.real + yAc.yIgVsb.real; + *(inst->NUMOSbulkSourcePtr + 1) -= + yAc.yIdVsb.imag + yAc.yIsVsb.imag + yAc.yIgVsb.imag; + *(inst->NUMOSbulkGatePtr) -= + yAc.yIdVgb.real + yAc.yIsVgb.real + yAc.yIgVgb.real; + *(inst->NUMOSbulkGatePtr + 1) -= + yAc.yIdVgb.imag + yAc.yIsVgb.imag + yAc.yIgVgb.imag; + *(inst->NUMOSbulkBulkPtr) += + yAc.yIdVdb.real + yAc.yIdVsb.real + yAc.yIdVgb.real + + yAc.yIsVdb.real + yAc.yIsVsb.real + yAc.yIsVgb.real + + yAc.yIgVdb.real + yAc.yIgVsb.real + yAc.yIgVgb.real; + *(inst->NUMOSbulkBulkPtr + 1) -= + yAc.yIdVdb.imag + yAc.yIdVsb.imag + yAc.yIdVgb.imag + + yAc.yIsVdb.imag + yAc.yIsVsb.imag + yAc.yIsVgb.imag + + yAc.yIgVdb.imag + yAc.yIgVsb.imag + yAc.yIgVgb.imag; + + inst->NUMOSpDevice->pStats->totalTime[STAT_AC] += + SPfrontEnd->IFseconds() - startTime; + } + } + return (OK); +} diff --git a/src/spicelib/devices/numos/nummset.c b/src/spicelib/devices/numos/nummset.c new file mode 100644 index 000000000..dc63e7cfc --- /dev/null +++ b/src/spicelib/devices/numos/nummset.c @@ -0,0 +1,278 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "cktdefs.h" +#include "smpdefs.h" +#include "numosdef.h" +#include "numconst.h" +#include "numenum.h" +#include "meshext.h" +#include "sperror.h" +#include "../../../ciderlib/twod/twoddefs.h" +#include "../../../ciderlib/twod/twodext.h" +#include "cidersupt.h" +#include "ciderinp.h" +#include "suffix.h" + +#define NIL(type) ((type *)0) +#define TSCALLOC(var, size, type)\ +if (size && (!(var =(type *)calloc(1, (unsigned)(size)*sizeof(type))))) {\ + return(E_NOMEM);\ +} + +int +NUMOSsetup(matrix, inModel, ckt, states) + register SMPmatrix *matrix; + GENmodel *inModel; + CKTcircuit *ckt; + int *states; +/* + * load the structure with those pointers needed later for fast matrix + * loading + */ +{ + register NUMOSmodel *model = (NUMOSmodel *) inModel; + register NUMOSinstance *inst; + METHcard *methods; + MODLcard *models; + OPTNcard *options; + OUTPcard *outputs; + char *icFileName = NULL; + int nameLen; + int error, xIndex, yIndex; + int xMeshSize, yMeshSize; + TWOdevice *pDevice; + TWOcoord *xCoordList = NIL(TWOcoord); + TWOcoord *yCoordList = NIL(TWOcoord); + TWOdomain *domainList = NIL(TWOdomain); + TWOelectrode *electrodeList = NIL(TWOelectrode); + TWOmaterial *pM, *pMaterial = NIL(TWOmaterial), *materialList = NIL(TWOmaterial); + DOPprofile *profileList = NIL(DOPprofile); + DOPtable *dopTableList = NIL(DOPtable); + double startTime; + + /* loop through all the models */ + for (; model != NULL; model = model->NUMOSnextModel) { + if (!model->NUMOSpInfo) { + TSCALLOC(model->NUMOSpInfo, 1, TWOtranInfo); + } + methods = model->NUMOSmethods; + if (!methods) { + TSCALLOC(methods, 1, METHcard); + model->NUMOSmethods = methods; + } + models = model->NUMOSmodels; + if (!models) { + TSCALLOC(models, 1, MODLcard); + model->NUMOSmodels = models; + } + options = model->NUMOSoptions; + if (!options) { + TSCALLOC(options, 1, OPTNcard); + model->NUMOSoptions = options; + } + outputs = model->NUMOSoutputs; + if (!outputs) { + TSCALLOC(outputs, 1, OUTPcard); + model->NUMOSoutputs = outputs; + } + if (!methods->METHvoltPredGiven) { + methods->METHvoltPred = FALSE; + } + if (!methods->METHmobDerivGiven) { + methods->METHmobDeriv = TRUE; + } + if (!methods->METHoneCarrierGiven) { + methods->METHoneCarrier = FALSE; + } + if (!methods->METHacAnalysisMethodGiven) { + methods->METHacAnalysisMethod = SOR; + } + if (!methods->METHdabstolGiven) { + methods->METHdabstol = DABSTOL2D; + } + if (!methods->METHdreltolGiven) { + methods->METHdreltol = ckt->CKTreltol; + } + if (!methods->METHitLimGiven) { + methods->METHitLim = 50; + } + if (!methods->METHomegaGiven || methods->METHomega <= 0.0) { + methods->METHomega = 2.0 * M_PI /* radians/sec */ ; + } + if (!options->OPTNdefaGiven || options->OPTNdefa <= 0.0) { + options->OPTNdefa = 1.0e4 /* cm^2 */ ; + } + if (!options->OPTNdeflGiven || options->OPTNdefl <= 0.0) { + options->OPTNdefl = 1.0e2 /* cm */ ; + } + if (!options->OPTNdefwGiven && options->OPTNdefaGiven) { + options->OPTNdefw = options->OPTNdefa / options->OPTNdefl; + } else if (!options->OPTNdefwGiven || options->OPTNdefw <= 0.0) { + options->OPTNdefw = 1.0e2 /* cm */ ; + } + if (!options->OPTNdeviceTypeGiven) { + options->OPTNdeviceType = OPTN_MOSFET; + } + if (!options->OPTNicFileGiven) { + options->OPTNicFile = NULL; + options->OPTNunique = FALSE; /* Can't form a unique name. */ + } + if (!options->OPTNuniqueGiven) { + options->OPTNunique = FALSE; + } + OneCarrier = methods->METHoneCarrier; + + /* Set up the rest of the card lists */ + if ((error = MODLsetup(model->NUMOSmodels))) + return (error); + BandGapNarrowing = models->MODLbandGapNarrowing; + ConcDepLifetime = models->MODLconcDepLifetime; + TempDepMobility = models->MODLtempDepMobility; + ConcDepMobility = models->MODLconcDepMobility; + SurfaceMobility = models->MODLsurfaceMobility; + + if ((error = OUTPsetup(model->NUMOSoutputs))) + return (error); + if ((error = MATLsetup(model->NUMOSmaterials, &materialList))) + return (error); + if ((error = MOBsetup(model->NUMOSmobility, materialList))) + return (error); + if ((error = MESHsetup('x', model->NUMOSxMeshes, &xCoordList, &xMeshSize))) + return (error); + if ((error = MESHsetup('y', model->NUMOSyMeshes, &yCoordList, &yMeshSize))) + return (error); + if ((error = DOMNsetup(model->NUMOSdomains, &domainList, + xCoordList, yCoordList, materialList))) + return (error); + if ((error = BDRYsetup(model->NUMOSboundaries, + xCoordList, yCoordList, domainList))) + return (error); + if ((error = ELCTsetup(model->NUMOSelectrodes, &electrodeList, + xCoordList, yCoordList))) + return (error); + /* Make sure electrodes are OK. */ + checkElectrodes(electrodeList, 4); /* NUMOS has 4 electrodes */ + + if ((error = CONTsetup(model->NUMOScontacts, electrodeList))) + return (error); + if ((error = DOPsetup(model->NUMOSdopings, &profileList, + &dopTableList, xCoordList, yCoordList))) + return (error); + model->NUMOSmatlInfo = materialList; + model->NUMOSprofiles = profileList; + model->NUMOSdopTables = dopTableList; + + /* loop through all the instances of the model */ + for (inst = model->NUMOSinstances; inst != NULL; + inst = inst->NUMOSnextInstance) { + if (inst->NUMOSowner != ARCHme) goto matrixpointers; + + startTime = SPfrontEnd->IFseconds(); + + if (!inst->NUMOSprintGiven) { + inst->NUMOSprint = 0; + } else if (inst->NUMOSprint <= 0) { + inst->NUMOSprint = 1; + } + if (!inst->NUMOSicFileGiven) { + if (options->OPTNunique) { + nameLen = strlen(options->OPTNicFile) + strlen(inst->NUMOSname) + 1; + TSCALLOC(icFileName, nameLen+1, char); + sprintf(icFileName, "%s.%s", options->OPTNicFile, inst->NUMOSname); + icFileName[nameLen] = '\0'; + inst->NUMOSicFile = icFileName; + } else if (options->OPTNicFile != NULL) { + nameLen = strlen(options->OPTNicFile); + TSCALLOC(icFileName, nameLen+1, char); + icFileName = strcpy(icFileName, options->OPTNicFile); + inst->NUMOSicFile = icFileName; + } else { + inst->NUMOSicFile = NULL; + } + } + inst->NUMOSstate = *states; + *states += NUMOSnumStates; + + if (!inst->NUMOSpDevice) { + /* Assign the mesh info to each instance. */ + TSCALLOC(pDevice, 1, TWOdevice); + TSCALLOC(pDevice->pStats, 1, TWOstats); + pDevice->name = inst->NUMOSname; + pDevice->solverType = SLV_NONE; + pDevice->numXNodes = xMeshSize; + pDevice->numYNodes = yMeshSize; + pDevice->xScale = MESHmkArray(xCoordList, xMeshSize); + pDevice->yScale = MESHmkArray(yCoordList, yMeshSize); + pDevice->abstol = methods->METHdabstol; + pDevice->reltol = methods->METHdreltol; + TSCALLOC(pDevice->elemArray, pDevice->numXNodes, TWOelem **); + for (xIndex = 1; xIndex < pDevice->numXNodes; xIndex++) { + TSCALLOC(pDevice->elemArray[xIndex], pDevice->numYNodes, TWOelem *); + } + + /* Create a copy of material data that can change with temperature. */ + pDevice->pMaterials = NIL(TWOmaterial); + for (pM = materialList; pM != NIL(TWOmaterial); pM = pM->next) { + if (pDevice->pMaterials == NIL(TWOmaterial)) { + TSCALLOC(pMaterial, 1, TWOmaterial); + pDevice->pMaterials = pMaterial; + } else { + TSCALLOC(pMaterial->next, 1, TWOmaterial); + pMaterial = pMaterial->next; + } + /* Copy everything, then fix the incorrect pointer. */ + bcopy((char *) pM, (char *) pMaterial, sizeof(TWOmaterial)); + pMaterial->next = NIL(TWOmaterial); + } + + /* Generate the mesh structure for the device. */ + TWObuildMesh(pDevice, domainList, electrodeList, pDevice->pMaterials); + + /* Store the device info in the instance. */ + inst->NUMOSpDevice = pDevice; + } + /* Now update the state pointers. */ + TWOgetStatePointers(inst->NUMOSpDevice, states); + + /* Wipe out statistics from previous runs (if any). */ + bzero((char *) inst->NUMOSpDevice->pStats, sizeof(TWOstats)); + + inst->NUMOSpDevice->pStats->totalTime[STAT_SETUP] += + SPfrontEnd->IFseconds() - startTime; + + /* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if ((inst->ptr = SMPmakeElt(matrix,inst->first,inst->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + +matrixpointers: + TSTALLOC(NUMOSdrainDrainPtr, NUMOSdrainNode, NUMOSdrainNode) + TSTALLOC(NUMOSdrainSourcePtr, NUMOSdrainNode, NUMOSsourceNode) + TSTALLOC(NUMOSdrainGatePtr, NUMOSdrainNode, NUMOSgateNode) + TSTALLOC(NUMOSdrainBulkPtr, NUMOSdrainNode, NUMOSbulkNode) + TSTALLOC(NUMOSsourceDrainPtr, NUMOSsourceNode, NUMOSdrainNode) + TSTALLOC(NUMOSsourceSourcePtr, NUMOSsourceNode, NUMOSsourceNode) + TSTALLOC(NUMOSsourceGatePtr, NUMOSsourceNode, NUMOSgateNode) + TSTALLOC(NUMOSsourceBulkPtr, NUMOSsourceNode, NUMOSbulkNode) + TSTALLOC(NUMOSgateDrainPtr, NUMOSgateNode, NUMOSdrainNode) + TSTALLOC(NUMOSgateSourcePtr, NUMOSgateNode, NUMOSsourceNode) + TSTALLOC(NUMOSgateGatePtr, NUMOSgateNode, NUMOSgateNode) + TSTALLOC(NUMOSgateBulkPtr, NUMOSgateNode, NUMOSbulkNode) + TSTALLOC(NUMOSbulkDrainPtr, NUMOSbulkNode, NUMOSdrainNode) + TSTALLOC(NUMOSbulkSourcePtr, NUMOSbulkNode, NUMOSsourceNode) + TSTALLOC(NUMOSbulkGatePtr, NUMOSbulkNode, NUMOSgateNode) + TSTALLOC(NUMOSbulkBulkPtr, NUMOSbulkNode, NUMOSbulkNode) + } + /* Clean up lists */ + killCoordInfo(xCoordList); + killCoordInfo(yCoordList); + killDomainInfo(domainList); + killElectrodeInfo(electrodeList); + } + return (OK); +} diff --git a/src/spicelib/devices/numos/nummtemp.c b/src/spicelib/devices/numos/nummtemp.c new file mode 100644 index 000000000..1b3c23c00 --- /dev/null +++ b/src/spicelib/devices/numos/nummtemp.c @@ -0,0 +1,128 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +Author: 1991 David A. Gates, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "cktdefs.h" +#include "numosdef.h" +#include "numenum.h" +#include "carddefs.h" +#include "sperror.h" +#include "../../../ciderlib/twod/twoddefs.h" +#include "../../../ciderlib/twod/twodext.h" +#include "cidersupt.h" +#include "suffix.h" + +#define NIL(type) ((type *)0) + +int +NUMOStemp(inModel, ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +/* + * perform the temperature update + */ +{ + register NUMOSmodel *model = (NUMOSmodel *) inModel; + register NUMOSinstance *inst; + METHcard *methods; + MODLcard *models; + OPTNcard *options; + OUTPcard *outputs; + TWOmaterial *pM, *pMaterial, *pNextMaterial; + double startTime; + + + /* loop through all the models */ + for (; model != NULL; model = model->NUMOSnextModel) { + methods = model->NUMOSmethods; + models = model->NUMOSmodels; + options = model->NUMOSoptions; + outputs = model->NUMOSoutputs; + + if (!options->OPTNtnomGiven) { + options->OPTNtnom = ckt->CKTnomTemp; + } + for (pM = model->NUMOSmatlInfo; pM != NIL(TWOmaterial); + pM = pM->next) { + pM->tnom = options->OPTNtnom; + } + BandGapNarrowing = models->MODLbandGapNarrowing; + ConcDepLifetime = models->MODLconcDepLifetime; + TempDepMobility = models->MODLtempDepMobility; + ConcDepMobility = models->MODLconcDepMobility; + SurfaceMobility = models->MODLsurfaceMobility; + MatchingMobility = models->MODLmatchingMobility; + OneCarrier = methods->METHoneCarrier; + + for (inst = model->NUMOSinstances; inst != NULL; + inst = inst->NUMOSnextInstance) { + if (inst->NUMOSowner != ARCHme) continue; + + startTime = SPfrontEnd->IFseconds(); + + if (!inst->NUMOStempGiven) { + inst->NUMOStemp = ckt->CKTtemp; + } + if (!inst->NUMOSareaGiven || inst->NUMOSarea <= 0.0) { + inst->NUMOSarea = 1.0; + } + if (!inst->NUMOSwidthGiven || inst->NUMOSwidth <= 0.0) { + inst->NUMOSwidth = 1.0; + } + inst->NUMOSpDevice->width = + inst->NUMOSarea * inst->NUMOSwidth * options->OPTNdefw; + + /* Compute and save globals for this instance. */ + GLOBcomputeGlobals(&(inst->NUMOSglobals), inst->NUMOStemp); + + /* Calculate new sets of material parameters. */ + pM = model->NUMOSmatlInfo; + pMaterial = inst->NUMOSpDevice->pMaterials; + for (; pM != NULL; pM = pM->next, pMaterial = pMaterial->next) { + + /* Copy everything, then fix the incorrect pointer. */ + pNextMaterial = pMaterial->next; + bcopy((char *) pM, (char *) pMaterial, sizeof(TWOmaterial)); + pMaterial->next = pNextMaterial; + + /* Now do the temperature dependence. */ + MATLtempDep(pMaterial, pMaterial->tnom); + if (outputs->OUTPmaterial) { + printMaterialInfo(pMaterial); + } + } + + /* Assign doping to the mesh. */ + TWOsetDoping(inst->NUMOSpDevice, model->NUMOSprofiles, + model->NUMOSdopTables); + + /* Assign physical parameters to the mesh. */ + TWOsetup(inst->NUMOSpDevice); + + /* Assign boundary condition parameters. */ + TWOsetBCparams(inst->NUMOSpDevice, model->NUMOSboundaries); + + /* Normalize everything. */ + TWOnormalize(inst->NUMOSpDevice); + + /* Find the device's type. */ + if (inst->NUMOSpDevice->pFirstContact->pNodes[0]->netConc < 0.0) { + inst->NUMOStype = P_CH; + if (OneCarrier) { + methods->METHoneCarrier = P_TYPE; + } + } else { + inst->NUMOStype = N_CH; + if (OneCarrier) { + methods->METHoneCarrier = N_TYPE; + } + } + inst->NUMOSpDevice->pStats->totalTime[STAT_SETUP] += + SPfrontEnd->IFseconds() - startTime; + } + } + return (OK); +} diff --git a/src/spicelib/devices/numos/nummtrun.c b/src/spicelib/devices/numos/nummtrun.c new file mode 100644 index 000000000..eb37aa6ee --- /dev/null +++ b/src/spicelib/devices/numos/nummtrun.c @@ -0,0 +1,56 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group +**********/ + +/* + * This routine performs truncation error calculations for NUMOSs in the + * circuit. + */ + +#include "ngspice.h" +#include "cktdefs.h" +#include "numosdef.h" +#include "sperror.h" +#include "../../../ciderlib/twod/twoddefs.h" +#include "../../../ciderlib/twod/twodext.h" +#include "cidersupt.h" +#include "suffix.h" + + +int +NUMOStrunc(inModel, ckt, timeStep) + GENmodel *inModel; + register CKTcircuit *ckt; + double *timeStep; +{ + register NUMOSmodel *model = (NUMOSmodel *) inModel; + register NUMOSinstance *inst; + double deltaNew; + double deltaNorm[7]; + double startTime; + int i; + + for (i = 0; i <= ckt->CKTmaxOrder; i++) { + deltaNorm[i] = ckt->CKTdeltaOld[i] / TNorm; + } + + for (; model != NULL; model = model->NUMOSnextModel) { + OneCarrier = model->NUMOSmethods->METHoneCarrier; + model->NUMOSpInfo->order = ckt->CKTorder; + model->NUMOSpInfo->delta = deltaNorm; + model->NUMOSpInfo->lteCoeff = computeLTECoeff(model->NUMOSpInfo); + for (inst = model->NUMOSinstances; inst != NULL; + inst = inst->NUMOSnextInstance) { + if (inst->NUMOSowner != ARCHme) continue; + + startTime = SPfrontEnd->IFseconds(); + deltaNew = TWOtrunc(inst->NUMOSpDevice, model->NUMOSpInfo, + ckt->CKTdelta); + *timeStep = MIN(*timeStep, deltaNew); + inst->NUMOSpDevice->pStats->totalTime[STAT_TRAN] += + SPfrontEnd->IFseconds() - startTime; + } + } + return (OK); +} diff --git a/src/spicelib/devices/numos/numosdef.h b/src/spicelib/devices/numos/numosdef.h new file mode 100644 index 000000000..b9907f368 --- /dev/null +++ b/src/spicelib/devices/numos/numosdef.h @@ -0,0 +1,218 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +Authors: 1987 Karti Mayaram, 1991 David Gates +**********/ + +#ifndef NUMOS_H +#define NUMOS_H "NUMOSdefs.h $Revision$ on $Date$ " + +/* data structures used to describe 2D Numerical MOSFETs */ + +/* circuit level includes */ +#include "ifsim.h" +#include "cktdefs.h" +#include "gendefs.h" + +/* device level includes */ +#include "twomesh.h" +#include "twodev.h" +#include "profile.h" +#include "numglobs.h" +#include "carddefs.h" + +/* information needed per instance */ +typedef struct sNUMOSinstance { + struct sNUMOSmodel *NUMOSmodPtr; /* back pointer to model */ + struct sNUMOSinstance *NUMOSnextInstance; /* pointer to next instance + * of current model */ + IFuid NUMOSname; /* pointer to character string naming this + * instance */ + int NUMOSowner; /* number of owner process */ + int NUMOSstate; /* pointer to start of state vector for + * mosfet */ + + /* entries in the state vector for mosfet: */ +#define NUMOSvdb NUMOSstate +#define NUMOSvsb NUMOSstate+1 +#define NUMOSvgb NUMOSstate+2 +#define NUMOSid NUMOSstate+3 +#define NUMOSis NUMOSstate+4 +#define NUMOSig NUMOSstate+5 +#define NUMOSdIdDVdb NUMOSstate+6 +#define NUMOSdIdDVsb NUMOSstate+7 +#define NUMOSdIdDVgb NUMOSstate+8 +#define NUMOSdIsDVdb NUMOSstate+9 +#define NUMOSdIsDVsb NUMOSstate+10 +#define NUMOSdIsDVgb NUMOSstate+11 +#define NUMOSdIgDVdb NUMOSstate+12 +#define NUMOSdIgDVsb NUMOSstate+13 +#define NUMOSdIgDVgb NUMOSstate+14 +#define NUMOSnumStates 15 + + int NUMOSdrainNode; /* number of drain node of MOSFET */ + int NUMOSgateNode; /* number of gate node of MOSFET */ + int NUMOSsourceNode; /* number of source node of MOSFET */ + int NUMOSbulkNode; /* number of bulk node of MOSFET */ + double NUMOSarea; /* area factor for the mosfet */ + double NUMOSwidth; /* width factor for the mosfet */ + double NUMOSlength; /* length factor for the mosfet */ + TWOdevice *NUMOSpDevice; + int NUMOStype; + double NUMOStemp; /* Instance Temperature */ + double NUMOSc11; /* small-signal capacitance */ + double NUMOSy11r; /* small-signal admittance, real part */ + double NUMOSy11i; /* small-signal admittance, imag part */ + double NUMOSc12; /* small-signal capacitance */ + double NUMOSy12r; /* small-signal admittance, real part */ + double NUMOSy12i; /* small-signal admittance, imag part */ + double NUMOSc13; /* small-signal capacitance */ + double NUMOSy13r; /* small-signal admittance, real part */ + double NUMOSy13i; /* small-signal admittance, imag part */ + double NUMOSc21; /* small-signal capacitance */ + double NUMOSy21r; /* small-signal admittance, real part */ + double NUMOSy21i; /* small-signal admittance, imag part */ + double NUMOSc22; /* small-signal capacitance */ + double NUMOSy22r; /* small-signal admittance, real part */ + double NUMOSy22i; /* small-signal admittance, imag part */ + double NUMOSc23; /* small-signal capacitance */ + double NUMOSy23r; /* small-signal admittance, real part */ + double NUMOSy23i; /* small-signal admittance, imag part */ + double NUMOSc31; /* small-signal capacitance */ + double NUMOSy31r; /* small-signal admittance, real part */ + double NUMOSy31i; /* small-signal admittance, imag part */ + double NUMOSc32; /* small-signal capacitance */ + double NUMOSy32r; /* small-signal admittance, real part */ + double NUMOSy32i; /* small-signal admittance, imag part */ + double NUMOSc33; /* small-signal capacitance */ + double NUMOSy33r; /* small-signal admittance, real part */ + double NUMOSy33i; /* small-signal admittance, imag part */ + GLOBvalues NUMOSglobals; /* Temp.-Dep. Global Parameters */ + int NUMOSprint; /* print timepoints */ + char *NUMOSicFile; /* Name of initial condition file */ + double *NUMOSdrainDrainPtr; /* pointer to sparse matrix at (drain,drain) */ + double *NUMOSdrainSourcePtr; /* pointer to sparse matrix at (drain,source) */ + double *NUMOSdrainGatePtr; /* pointer to sparse matrix at (drain,gate) */ + double *NUMOSdrainBulkPtr; /* pointer to sparse matrix at (drain,bulk) */ + double *NUMOSsourceDrainPtr; /* pointer to sparse matrix at (source,drain) */ + double *NUMOSsourceSourcePtr; /* pointer to sparse matrix at + * (source,source) */ + double *NUMOSsourceGatePtr; /* pointer to sparse matrix at (source,gate) */ + double *NUMOSsourceBulkPtr; /* pointer to sparse matrix at (source,bulk) */ + double *NUMOSgateDrainPtr; /* pointer to sparse matrix at (gate,drain) */ + double *NUMOSgateSourcePtr; /* pointer to sparse matrix at (gate,source) */ + double *NUMOSgateGatePtr; /* pointer to sparse matrix at (gate,gate) */ + double *NUMOSgateBulkPtr; /* pointer to sparse matrix at (gate,bulk) */ + double *NUMOSbulkDrainPtr; /* pointer to sparse matrix at (bulk,drain) */ + double *NUMOSbulkSourcePtr; /* pointer to sparse matrix at (bulk,source) */ + double *NUMOSbulkGatePtr; /* pointer to sparse matrix at (bulk,gate) */ + double *NUMOSbulkBulkPtr; /* pointer to sparse matrix at (bulk,bulk) */ + + int NUMOSoff; /* 'off' flag for mosfet */ + unsigned NUMOSsmSigAvail:1; /* flag to indicate small-signal done */ + unsigned NUMOSareaGiven:1; /* flag to indicate area was specified */ + unsigned NUMOSwidthGiven:1; /* flag to indicate width was specified */ + unsigned NUMOSlengthGiven:1; /* flag to indicate length was specified */ + unsigned NUMOSicFileGiven:1; /* flag to indicate init. cond. file given */ + unsigned NUMOSprintGiven:1; /* flag to indicate print was given */ + unsigned NUMOStempGiven:1; /* flag to indicate temp was given */ +} NUMOSinstance; + +/* per model data */ +typedef struct sNUMOSmodel { /* model structure for a numerical device */ + int NUMOSmodType; /* type index of this device type */ + struct sNUMOSmodel *NUMOSnextModel; /* pointer to next model in list */ + NUMOSinstance *NUMOSinstances;/* pointer to list of instances */ + IFuid NUMOSmodName; /* pointer to string naming this model */ + /* Everything below here is numerical-device-specific */ + MESHcard *NUMOSxMeshes; /* list of xmesh cards */ + MESHcard *NUMOSyMeshes; /* list of ymesh cards */ + DOMNcard *NUMOSdomains; /* list of domain cards */ + BDRYcard *NUMOSboundaries; /* list of boundary cards */ + DOPcard *NUMOSdopings; /* list of doping cards */ + ELCTcard *NUMOSelectrodes; /* list of electrode cards */ + CONTcard *NUMOScontacts; /* list of contact cards */ + MODLcard *NUMOSmodels; /* list of model cards */ + MATLcard *NUMOSmaterials; /* list of material cards */ + MOBcard *NUMOSmobility; /* list of mobility cards */ + METHcard *NUMOSmethods; /* list of method cards */ + OPTNcard *NUMOSoptions; /* list of option cards */ + OUTPcard *NUMOSoutputs; /* list of output cards */ + TWOtranInfo *NUMOSpInfo; /* transient analysis information */ + DOPprofile *NUMOSprofiles; /* expanded list of doping profiles */ + DOPtable *NUMOSdopTables; /* list of tables used by profiles */ + TWOmaterial *NUMOSmatlInfo; /* list of material info structures */ +} NUMOSmodel; + +/* type of 2D MOSFET */ +#define N_CH 1 +#define P_CH -1 + +/* device parameters */ +#define NUMOS_AREA 1 +#define NUMOS_WIDTH 2 +#define NUMOS_LENGTH 3 +#define NUMOS_OFF 4 +#define NUMOS_IC_FILE 5 +#define NUMOS_PRINT 9 +#define NUMOS_TEMP 10 + +#define NUMOS_G11 11 +#define NUMOS_C11 12 +#define NUMOS_Y11 13 +#define NUMOS_G12 14 +#define NUMOS_C12 15 +#define NUMOS_Y12 16 +#define NUMOS_G13 17 +#define NUMOS_C13 18 +#define NUMOS_Y13 19 +#define NUMOS_G14 20 +#define NUMOS_C14 21 +#define NUMOS_Y14 22 +#define NUMOS_G21 23 +#define NUMOS_C21 24 +#define NUMOS_Y21 25 +#define NUMOS_G22 26 +#define NUMOS_C22 27 +#define NUMOS_Y22 28 +#define NUMOS_G23 29 +#define NUMOS_C23 30 +#define NUMOS_Y23 31 +#define NUMOS_G24 32 +#define NUMOS_C24 33 +#define NUMOS_Y24 34 +#define NUMOS_G31 35 +#define NUMOS_C31 36 +#define NUMOS_Y31 37 +#define NUMOS_G32 38 +#define NUMOS_C32 39 +#define NUMOS_Y32 40 +#define NUMOS_G33 41 +#define NUMOS_C33 42 +#define NUMOS_Y33 43 +#define NUMOS_G34 44 +#define NUMOS_C34 45 +#define NUMOS_Y34 46 +#define NUMOS_G41 47 +#define NUMOS_C41 48 +#define NUMOS_Y41 49 +#define NUMOS_G42 50 +#define NUMOS_C42 51 +#define NUMOS_Y42 52 +#define NUMOS_G43 53 +#define NUMOS_C43 54 +#define NUMOS_Y43 55 +#define NUMOS_G44 56 +#define NUMOS_C44 57 +#define NUMOS_Y44 58 + +/* model parameters */ +/* NOTE: all true model parameters have been moved to IFcardInfo structures */ +#define NUMOS_MOD_NUMOS 1 + +/* device questions */ + +/* model questions */ + +#include "numosext.h" + +#endif /* NUMOS_H */ diff --git a/src/spicelib/devices/numos/numosext.h b/src/spicelib/devices/numos/numosext.h new file mode 100644 index 000000000..411c5b03b --- /dev/null +++ b/src/spicelib/devices/numos/numosext.h @@ -0,0 +1,27 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Karti Mayaram +**********/ + +#ifndef NUMOSEXT_H +#define NUMOSEXT_H + + +extern int NUMOSacLoad(GENmodel *, CKTcircuit *); +extern int NUMOSask(CKTcircuit *, GENinstance *, int, IFvalue *, IFvalue *); +extern int NUMOSdelete(GENmodel *, IFuid, GENinstance **); +extern void NUMOSdestroy(GENmodel **); +extern int NUMOSgetic(GENmodel *, CKTcircuit *); +extern int NUMOSload(GENmodel *, CKTcircuit *); +extern int NUMOSmDelete(GENmodel **, IFuid, GENmodel *); +extern int NUMOSmParam(int, IFvalue *, GENmodel *); +extern int NUMOSparam(int, IFvalue *, GENinstance *, IFvalue *); +extern int NUMOSpzLoad(GENmodel *, CKTcircuit *, SPcomplex *); +extern int NUMOSsetup(SMPmatrix *, GENmodel *, CKTcircuit *, int *); +extern int NUMOStemp(GENmodel *, CKTcircuit *); +extern int NUMOStrunc(GENmodel *, CKTcircuit *, double *); + +extern void NUMOSdump(GENmodel *, CKTcircuit *); +extern void NUMOSacct(GENmodel *, CKTcircuit *, FILE *); + +#endif /* NUMOSEXT_H */ diff --git a/src/spicelib/devices/numos/numosinit.c b/src/spicelib/devices/numos/numosinit.c new file mode 100644 index 000000000..d5a007fc0 --- /dev/null +++ b/src/spicelib/devices/numos/numosinit.c @@ -0,0 +1,83 @@ +#include + +#include + +#include "numositf.h" +#include "numosext.h" +#include "numosinit.h" + + +SPICEdev NUMOSinfo = { + { + "NUMOS", + "2D Numerical MOS Field Effect Transistor model", + + &NUMOSnSize, + &NUMOSnSize, + NUMOSnames, + + &NUMOSpTSize, + NUMOSpTable, + + &NUMOSmPTSize, + NUMOSmPTable, + +#ifdef XSPICE +/*---- Fixed by SDB 5.2.2003 to enable XSPICE/tclspice integration -----*/ + NULL, /* This is a SPICE device, it has no MIF info data */ + + 0, /* This is a SPICE device, it has no MIF info data */ + NULL, /* This is a SPICE device, it has no MIF info data */ + + 0, /* This is a SPICE device, it has no MIF info data */ + NULL, /* This is a SPICE device, it has no MIF info data */ + + 0, /* This is a SPICE device, it has no MIF info data */ + NULL, /* This is a SPICE device, it has no MIF info data */ +/*--------------------------- End of SDB fix -------------------------*/ +#endif + + DEV_DEFAULT + }, + + DEVparam : NUMOSparam, + DEVmodParam : NUMOSmParam, + DEVload : NUMOSload, + DEVsetup : NUMOSsetup, + DEVunsetup : NULL, + DEVpzSetup : NUMOSsetup, + DEVtemperature: NUMOStemp, + DEVtrunc : NUMOStrunc, + DEVfindBranch : NULL, + DEVacLoad : NUMOSacLoad, + DEVaccept : NULL, + DEVdestroy : NUMOSdestroy, + DEVmodDelete : NUMOSmDelete, + DEVdelete : NUMOSdelete, + DEVsetic : NULL, + DEVask : NUMOSask, + DEVmodAsk : NULL, + DEVpzLoad : NUMOSpzLoad, + DEVconvTest : NULL, + DEVsenSetup : NULL, + DEVsenLoad : NULL, + DEVsenUpdate : NULL, + DEVsenAcLoad : NULL, + DEVsenPrint : NULL, + DEVsenTrunc : NULL, + DEVdisto : NULL, + DEVnoise : NULL, + DEVdump : NUMOSdump, + DEVacct : NUMOSacct, + + DEVinstSize : &NUMOSiSize, + DEVmodSize : &NUMOSmSize + +}; + + +SPICEdev * +get_numos_info(void) +{ + return &NUMOSinfo; +} diff --git a/src/spicelib/devices/numos/numosinit.h b/src/spicelib/devices/numos/numosinit.h new file mode 100644 index 000000000..3139c1e34 --- /dev/null +++ b/src/spicelib/devices/numos/numosinit.h @@ -0,0 +1,13 @@ +#ifndef _NUMOSINIT_H +#define _NUMOSINIT_H + +extern IFparm NUMOSpTable[ ]; +extern IFparm NUMOSmPTable[ ]; +extern char *NUMOSnames[ ]; +extern int NUMOSpTSize; +extern int NUMOSmPTSize; +extern int NUMOSnSize; +extern int NUMOSiSize; +extern int NUMOSmSize; + +#endif diff --git a/src/spicelib/devices/numos/numositf.h b/src/spicelib/devices/numos/numositf.h new file mode 100644 index 000000000..2a66e5284 --- /dev/null +++ b/src/spicelib/devices/numos/numositf.h @@ -0,0 +1,10 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +**********/ + +#ifndef DEV_NUMOS +#define DEV_NUMOS + +extern SPICEdev *get_numos_info(void); + +#endif