You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

348 lines
13 KiB

/**********
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Thomas L. Quarles
Modified: Alan Gillespie
**********/
/*
* This routine should only be called when circuit topology
* changes, since its computations do not depend on most
* device or model parameters, only on topology (as
* affected by emitter, collector, and base resistances)
*/
#include "ngspice.h"
#include "cktdefs.h"
#include "smpdefs.h"
#include "bjt2defs.h"
#include "const.h"
#include "sperror.h"
#include "ifsim.h"
#include "suffix.h"
int
BJT2setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
/* load the BJT2 structure with those pointers needed later
* for fast matrix loading
*/
{
BJT2model *model = (BJT2model*)inModel;
BJT2instance *here;
int error;
CKTnode *tmp;
/* loop through all the diode models */
for( ; model != NULL; model = model->BJT2nextModel ) {
if(model->BJT2type != NPN && model->BJT2type != PNP) {
model->BJT2type = NPN;
}
#ifndef GEOMETRY_COMPAT
if(!model->BJT2subsGiven ||
(model->BJT2subs != VERTICAL && model->BJT2subs != LATERAL)) {
model->BJT2subs = VERTICAL;
}
#else
if(!model->BJT2subsGiven ||
(model->BJT2subs != VERTICAL && model->BJT2subs != LATERAL)) {
if (model->BJT2type = NPN)
model->BJT2subs = VERTICAL; /* Vertical for NPN */
else
model->BJT2subs = LATERAL; /* Lateral for PNP */
}
#endif
if(!model->BJT2satCurGiven) {
model->BJT2satCur = 1e-16;
}
if(!model->BJT2subSatCurGiven) {
model->BJT2subSatCur = 1e-16;
}
if(!model->BJT2betaFGiven) {
model->BJT2betaF = 100;
}
if(!model->BJT2emissionCoeffFGiven) {
model->BJT2emissionCoeffF = 1;
}
if(!model->BJT2leakBEemissionCoeffGiven) {
model->BJT2leakBEemissionCoeff = 1.5;
}
if(!model->BJT2betaRGiven) {
model->BJT2betaR = 1;
}
if(!model->BJT2emissionCoeffRGiven) {
model->BJT2emissionCoeffR = 1;
}
if(!model->BJT2leakBCemissionCoeffGiven) {
model->BJT2leakBCemissionCoeff = 2;
}
if(!model->BJT2baseResistGiven) {
model->BJT2baseResist = 0;
}
if(!model->BJT2emitterResistGiven) {
model->BJT2emitterResist = 0;
}
if(!model->BJT2collectorResistGiven) {
model->BJT2collectorResist = 0;
}
if(!model->BJT2depletionCapBEGiven) {
model->BJT2depletionCapBE = 0;
}
if(!model->BJT2potentialBEGiven) {
model->BJT2potentialBE = .75;
}
if(!model->BJT2junctionExpBEGiven) {
model->BJT2junctionExpBE = .33;
}
if(!model->BJT2transitTimeFGiven) {
model->BJT2transitTimeF = 0;
}
if(!model->BJT2transitTimeBiasCoeffFGiven) {
model->BJT2transitTimeBiasCoeffF = 0;
}
if(!model->BJT2transitTimeHighCurrentFGiven) {
model->BJT2transitTimeHighCurrentF = 0;
}
if(!model->BJT2excessPhaseGiven) {
model->BJT2excessPhase = 0;
}
if(!model->BJT2depletionCapBCGiven) {
model->BJT2depletionCapBC = 0;
}
if(!model->BJT2potentialBCGiven) {
model->BJT2potentialBC = .75;
}
if(!model->BJT2junctionExpBCGiven) {
model->BJT2junctionExpBC = .33;
}
if(!model->BJT2baseFractionBCcapGiven) {
model->BJT2baseFractionBCcap = 1;
}
if(!model->BJT2transitTimeRGiven) {
model->BJT2transitTimeR = 0;
}
if(!model->BJT2capSubGiven) {
model->BJT2capSub = 0;
}
if(!model->BJT2potentialSubstrateGiven) {
model->BJT2potentialSubstrate = .75;
}
if(!model->BJT2exponentialSubstrateGiven) {
model->BJT2exponentialSubstrate = 0;
}
if(!model->BJT2betaExpGiven) {
model->BJT2betaExp = 0;
}
if(!model->BJT2energyGapGiven) {
model->BJT2energyGap = 1.11;
}
if(!model->BJT2tempExpISGiven) {
model->BJT2tempExpIS = 3;
}
if(!model->BJT2reTempCoeff1Given) {
model->BJT2reTempCoeff1 = 0.0;
}
if(!model->BJT2reTempCoeff2Given) {
model->BJT2reTempCoeff2 = 0.0;
}
if(!model->BJT2rcTempCoeff1Given) {
model->BJT2rcTempCoeff1 = 0.0;
}
if(!model->BJT2rcTempCoeff2Given) {
model->BJT2rcTempCoeff2 = 0.0;
}
if(!model->BJT2rbTempCoeff1Given) {
model->BJT2rbTempCoeff1 = 0.0;
}
if(!model->BJT2rbTempCoeff2Given) {
model->BJT2rbTempCoeff2 = 0.0;
}
if(!model->BJT2rbmTempCoeff1Given) {
model->BJT2rbmTempCoeff1 = 0.0;
}
if(!model->BJT2rbmTempCoeff2Given) {
model->BJT2rbmTempCoeff2 = 0.0;
}
if(!model->BJT2fNcoefGiven) {
model->BJT2fNcoef = 0;
}
if(!model->BJT2fNexpGiven) {
model->BJT2fNexp = 1;
}
/*
* COMPATABILITY WARNING!
* special note: for backward compatability to much older models, spice 2G
* implemented a special case which checked if B-E leakage saturation
* current was >1, then it was instead a the B-E leakage saturation current
* divided by IS, and multiplied it by IS at this point. This was not
* handled correctly in the 2G code, and there is some question on its
* reasonability, since it is also undocumented, so it has been left out
* here. It could easily be added with 1 line. (The same applies to the B-C
* leakage saturation current). TQ 6/29/84
*/
/* loop through all the instances of the model */
for (here = model->BJT2instances; here != NULL ;
here=here->BJT2nextInstance) {
CKTnode *tmpNode;
IFuid tmpName;
if (here->BJT2owner != ARCHme)
goto matrixpointers;
if(!here->BJT2areaGiven) {
here->BJT2area = 1;
}
if(!here->BJT2areabGiven) {
here->BJT2areab = here->BJT2area;
}
if(!here->BJT2areacGiven) {
here->BJT2areac = here->BJT2area;
}
if(!here->BJT2mGiven) {
here->BJT2m = 1.0;
}
here->BJT2state = *states;
*states += BJT2numStates;
if(ckt->CKTsenInfo && (ckt->CKTsenInfo->SENmode & TRANSEN) ){
*states += 8 * (ckt->CKTsenInfo->SENparms);
}
matrixpointers:
if(model->BJT2collectorResist == 0) {
here->BJT2colPrimeNode = here->BJT2colNode;
} else if(here->BJT2colPrimeNode == 0) {
error = CKTmkVolt(ckt,&tmp,here->BJT2name,"collector");
if(error) return(error);
here->BJT2colPrimeNode = tmp->number;
if (ckt->CKTcopyNodesets) {
if (CKTinst2Node(ckt,here,1,&tmpNode,&tmpName)==OK) {
if (tmpNode->nsGiven) {
tmp->nodeset=tmpNode->nodeset;
tmp->nsGiven=tmpNode->nsGiven;
/* fprintf(stderr, "Nodeset copied from %s\n", tmpName);
fprintf(stderr, " to %s\n", tmp->name);
fprintf(stderr, " value %g\n",
tmp->nodeset);*/
}
}
}
}
if(model->BJT2baseResist == 0) {
here->BJT2basePrimeNode = here->BJT2baseNode;
} else if(here->BJT2basePrimeNode == 0){
error = CKTmkVolt(ckt,&tmp,here->BJT2name, "base");
if(error) return(error);
here->BJT2basePrimeNode = tmp->number;
if (ckt->CKTcopyNodesets) {
if (CKTinst2Node(ckt,here,2,&tmpNode,&tmpName)==OK) {
if (tmpNode->nsGiven) {
tmp->nodeset=tmpNode->nodeset;
tmp->nsGiven=tmpNode->nsGiven;
/* fprintf(stderr, "Nodeset copied from %s\n", tmpName);
fprintf(stderr, " to %s\n", tmp->name);
fprintf(stderr, " value %g\n",
tmp->nodeset);*/
}
}
}
}
if(model->BJT2emitterResist == 0) {
here->BJT2emitPrimeNode = here->BJT2emitNode;
} else if(here->BJT2emitPrimeNode == 0) {
error = CKTmkVolt(ckt,&tmp,here->BJT2name, "emitter");
if(error) return(error);
here->BJT2emitPrimeNode = tmp->number;
if (ckt->CKTcopyNodesets) {
if (CKTinst2Node(ckt,here,3,&tmpNode,&tmpName)==OK) {
if (tmpNode->nsGiven) {
tmp->nodeset=tmpNode->nodeset;
tmp->nsGiven=tmpNode->nsGiven;
/* fprintf(stderr, "Nodeset copied from %s\n", tmpName);
fprintf(stderr, " to %s\n", tmp->name);
fprintf(stderr, " value %g\n",
tmp->nodeset);*/
}
}
}
}
/* macro to make elements with built in test for out of memory */
#define TSTALLOC(ptr,first,second) \
if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\
return(E_NOMEM);\
}
TSTALLOC(BJT2colColPrimePtr,BJT2colNode,BJT2colPrimeNode)
TSTALLOC(BJT2baseBasePrimePtr,BJT2baseNode,BJT2basePrimeNode)
TSTALLOC(BJT2emitEmitPrimePtr,BJT2emitNode,BJT2emitPrimeNode)
TSTALLOC(BJT2colPrimeColPtr,BJT2colPrimeNode,BJT2colNode)
TSTALLOC(BJT2colPrimeBasePrimePtr,BJT2colPrimeNode,BJT2basePrimeNode)
TSTALLOC(BJT2colPrimeEmitPrimePtr,BJT2colPrimeNode,BJT2emitPrimeNode)
TSTALLOC(BJT2basePrimeBasePtr,BJT2basePrimeNode,BJT2baseNode)
TSTALLOC(BJT2basePrimeColPrimePtr,BJT2basePrimeNode,BJT2colPrimeNode)
TSTALLOC(BJT2basePrimeEmitPrimePtr,BJT2basePrimeNode,BJT2emitPrimeNode)
TSTALLOC(BJT2emitPrimeEmitPtr,BJT2emitPrimeNode,BJT2emitNode)
TSTALLOC(BJT2emitPrimeColPrimePtr,BJT2emitPrimeNode,BJT2colPrimeNode)
TSTALLOC(BJT2emitPrimeBasePrimePtr,BJT2emitPrimeNode,BJT2basePrimeNode)
TSTALLOC(BJT2colColPtr,BJT2colNode,BJT2colNode)
TSTALLOC(BJT2baseBasePtr,BJT2baseNode,BJT2baseNode)
TSTALLOC(BJT2emitEmitPtr,BJT2emitNode,BJT2emitNode)
TSTALLOC(BJT2colPrimeColPrimePtr,BJT2colPrimeNode,BJT2colPrimeNode)
TSTALLOC(BJT2basePrimeBasePrimePtr,BJT2basePrimeNode,BJT2basePrimeNode)
TSTALLOC(BJT2emitPrimeEmitPrimePtr,BJT2emitPrimeNode,BJT2emitPrimeNode)
TSTALLOC(BJT2substSubstPtr,BJT2substNode,BJT2substNode)
if (model -> BJT2subs == LATERAL) {
here -> BJT2substConNode = here -> BJT2basePrimeNode;
here -> BJT2substConSubstConPtr =
here -> BJT2basePrimeBasePrimePtr;
} else {
here -> BJT2substConNode = here -> BJT2colPrimeNode;
here -> BJT2substConSubstConPtr = here -> BJT2colPrimeColPrimePtr;
};
TSTALLOC(BJT2substConSubstPtr,BJT2substConNode,BJT2substNode)
TSTALLOC(BJT2substSubstConPtr,BJT2substNode,BJT2substConNode)
TSTALLOC(BJT2baseColPrimePtr,BJT2baseNode,BJT2colPrimeNode)
TSTALLOC(BJT2colPrimeBasePtr,BJT2colPrimeNode,BJT2baseNode)
}
}
return(OK);
}
int
BJT2unsetup(GENmodel *inModel, CKTcircuit *ckt)
{
BJT2model *model;
BJT2instance *here;
for (model = (BJT2model *)inModel; model != NULL;
model = model->BJT2nextModel)
{
for (here = model->BJT2instances; here != NULL;
here=here->BJT2nextInstance)
{
if (here->BJT2colPrimeNode
&& here->BJT2colPrimeNode != here->BJT2colNode)
{
CKTdltNNum(ckt, here->BJT2colPrimeNode);
here->BJT2colPrimeNode = 0;
}
if (here->BJT2basePrimeNode
&& here->BJT2basePrimeNode != here->BJT2baseNode)
{
CKTdltNNum(ckt, here->BJT2basePrimeNode);
here->BJT2basePrimeNode = 0;
}
if (here->BJT2emitPrimeNode
&& here->BJT2emitPrimeNode != here->BJT2emitNode)
{
CKTdltNNum(ckt, here->BJT2emitPrimeNode);
here->BJT2emitPrimeNode = 0;
}
}
}
return OK;
}