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.
289 lines
9.4 KiB
289 lines
9.4 KiB
/**********
|
|
Copyright 1990 Regents of the University of California. All rights reserved.
|
|
Author: 1985 Thomas L. Quarlesù
|
|
Modified: 2000 AlansFixes
|
|
**********/
|
|
|
|
#include "ngspice/ngspice.h"
|
|
#include "ngspice/smpdefs.h"
|
|
#include "ngspice/cktdefs.h"
|
|
#include "mos3defs.h"
|
|
#include "ngspice/const.h"
|
|
#include "ngspice/sperror.h"
|
|
#include "ngspice/suffix.h"
|
|
|
|
/* assuming silicon - make definition for epsilon of silicon */
|
|
#define EPSSIL (11.7 * 8.854214871e-12)
|
|
|
|
int
|
|
MOS3setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
|
|
/* load the MOS3 device structure with those pointers needed later
|
|
* for fast matrix loading
|
|
*/
|
|
|
|
{
|
|
MOS3model *model = (MOS3model *)inModel;
|
|
MOS3instance *here;
|
|
int error;
|
|
CKTnode *tmp;
|
|
|
|
/* loop through all the MOS3 device models */
|
|
for( ; model != NULL; model = model->MOS3nextModel ) {
|
|
|
|
/* perform model defaulting */
|
|
if(!model->MOS3typeGiven) {
|
|
model->MOS3type = NMOS;
|
|
}
|
|
if(!model->MOS3latDiffGiven) {
|
|
model->MOS3latDiff = 0;
|
|
}
|
|
if(!model->MOS3lengthAdjustGiven) {
|
|
model->MOS3lengthAdjust = 0;
|
|
}
|
|
if(!model->MOS3widthNarrowGiven) {
|
|
model->MOS3widthNarrow = 0;
|
|
}
|
|
if(!model->MOS3widthAdjustGiven) {
|
|
model->MOS3widthAdjust = 0;
|
|
}
|
|
if(!model->MOS3delvt0Given) {
|
|
model->MOS3delvt0 = 0;
|
|
}
|
|
if(!model->MOS3jctSatCurDensityGiven) {
|
|
model->MOS3jctSatCurDensity = 0;
|
|
}
|
|
if(!model->MOS3jctSatCurGiven) {
|
|
model->MOS3jctSatCur = 1e-14;
|
|
}
|
|
if(!model->MOS3drainResistanceGiven) {
|
|
model->MOS3drainResistance = 0;
|
|
}
|
|
if(!model->MOS3sourceResistanceGiven) {
|
|
model->MOS3sourceResistance = 0;
|
|
}
|
|
if(!model->MOS3sheetResistanceGiven) {
|
|
model->MOS3sheetResistance = 0;
|
|
}
|
|
if(!model->MOS3transconductanceGiven) {
|
|
model->MOS3transconductance = 2e-5;
|
|
}
|
|
if(!model->MOS3gateSourceOverlapCapFactorGiven) {
|
|
model->MOS3gateSourceOverlapCapFactor = 0;
|
|
}
|
|
if(!model->MOS3gateDrainOverlapCapFactorGiven) {
|
|
model->MOS3gateDrainOverlapCapFactor = 0;
|
|
}
|
|
if(!model->MOS3gateBulkOverlapCapFactorGiven) {
|
|
model->MOS3gateBulkOverlapCapFactor = 0;
|
|
}
|
|
if(!model->MOS3vt0Given) {
|
|
model->MOS3vt0 = 0;
|
|
}
|
|
if(!model->MOS3capBDGiven) {
|
|
model->MOS3capBD = 0;
|
|
}
|
|
if(!model->MOS3capBSGiven) {
|
|
model->MOS3capBS = 0;
|
|
}
|
|
if(!model->MOS3bulkCapFactorGiven) {
|
|
model->MOS3bulkCapFactor = 0;
|
|
}
|
|
if(!model->MOS3sideWallCapFactorGiven) {
|
|
model->MOS3sideWallCapFactor = 0;
|
|
}
|
|
if(!model->MOS3bulkJctPotentialGiven) {
|
|
model->MOS3bulkJctPotential = .8;
|
|
}
|
|
if(!model->MOS3bulkJctBotGradingCoeffGiven) {
|
|
model->MOS3bulkJctBotGradingCoeff = .5;
|
|
}
|
|
if(!model->MOS3bulkJctSideGradingCoeffGiven) {
|
|
model->MOS3bulkJctSideGradingCoeff = .33;
|
|
}
|
|
if(!model->MOS3fwdCapDepCoeffGiven) {
|
|
model->MOS3fwdCapDepCoeff = .5;
|
|
}
|
|
if(!model->MOS3phiGiven) {
|
|
model->MOS3phi = .6;
|
|
}
|
|
if(!model->MOS3gammaGiven) {
|
|
model->MOS3gamma = 0;
|
|
}
|
|
if(!model->MOS3deltaGiven) {
|
|
model->MOS3delta = 0;
|
|
}
|
|
if(!model->MOS3maxDriftVelGiven) {
|
|
model->MOS3maxDriftVel = 0;
|
|
}
|
|
if(!model->MOS3junctionDepthGiven) {
|
|
model->MOS3junctionDepth = 0;
|
|
}
|
|
if(!model->MOS3fastSurfaceStateDensityGiven) {
|
|
model->MOS3fastSurfaceStateDensity = 0;
|
|
}
|
|
if(!model->MOS3etaGiven) {
|
|
model->MOS3eta = 0;
|
|
}
|
|
if(!model->MOS3thetaGiven) {
|
|
model->MOS3theta = 0;
|
|
}
|
|
if(!model->MOS3kappaGiven) {
|
|
model->MOS3kappa = .2;
|
|
}
|
|
if(!model->MOS3oxideThicknessGiven) {
|
|
model->MOS3oxideThickness = 1e-7;
|
|
}
|
|
if(!model->MOS3fNcoefGiven) {
|
|
model->MOS3fNcoef = 0;
|
|
}
|
|
if(!model->MOS3fNexpGiven) {
|
|
model->MOS3fNexp = 1;
|
|
}
|
|
|
|
/* loop through all the instances of the model */
|
|
for (here = model->MOS3instances; here != NULL ;
|
|
here=here->MOS3nextInstance) {
|
|
|
|
CKTnode *tmpNode;
|
|
IFuid tmpName;
|
|
|
|
/* allocate a chunk of the state vector */
|
|
here->MOS3states = *states;
|
|
*states += MOS3NUMSTATES;
|
|
|
|
if(!here->MOS3drainAreaGiven) {
|
|
here->MOS3drainArea = ckt->CKTdefaultMosAD;
|
|
}
|
|
if(!here->MOS3drainPerimiterGiven) {
|
|
here->MOS3drainPerimiter = 0;
|
|
}
|
|
if(!here->MOS3drainSquaresGiven) {
|
|
here->MOS3drainSquares = 1;
|
|
}
|
|
if(!here->MOS3icVBSGiven) {
|
|
here->MOS3icVBS = 0;
|
|
}
|
|
if(!here->MOS3icVDSGiven) {
|
|
here->MOS3icVDS = 0;
|
|
}
|
|
if(!here->MOS3icVGSGiven) {
|
|
here->MOS3icVGS = 0;
|
|
}
|
|
if(!here->MOS3sourcePerimiterGiven) {
|
|
here->MOS3sourcePerimiter = 0;
|
|
}
|
|
if(!here->MOS3sourceSquaresGiven) {
|
|
here->MOS3sourceSquares = 1;
|
|
}
|
|
if(!here->MOS3vdsatGiven) {
|
|
here->MOS3vdsat = 0;
|
|
}
|
|
if(!here->MOS3vonGiven) {
|
|
here->MOS3von = 0;
|
|
}
|
|
if(!here->MOS3modeGiven) {
|
|
here->MOS3mode = 1;
|
|
}
|
|
|
|
if((model->MOS3drainResistance != 0 ||
|
|
(model->MOS3sheetResistance != 0 &&
|
|
here->MOS3drainSquares != 0 ) )) {
|
|
if (here->MOS3dNodePrime == 0) {
|
|
error = CKTmkVolt(ckt,&tmp,here->MOS3name,"internal#drain");
|
|
if(error) return(error);
|
|
here->MOS3dNodePrime = tmp->number;
|
|
if (ckt->CKTcopyNodesets) {
|
|
if (CKTinst2Node(ckt,here,1,&tmpNode,&tmpName)==OK) {
|
|
if (tmpNode->nsGiven) {
|
|
tmp->nodeset=tmpNode->nodeset;
|
|
tmp->nsGiven=tmpNode->nsGiven;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
here->MOS3dNodePrime = here->MOS3dNode;
|
|
}
|
|
|
|
if((model->MOS3sourceResistance != 0 ||
|
|
(model->MOS3sheetResistance != 0 &&
|
|
here->MOS3sourceSquares != 0 ) )) {
|
|
if (here->MOS3sNodePrime == 0) {
|
|
error = CKTmkVolt(ckt,&tmp,here->MOS3name,"internal#source");
|
|
if(error) return(error);
|
|
here->MOS3sNodePrime = tmp->number;
|
|
if (ckt->CKTcopyNodesets) {
|
|
if (CKTinst2Node(ckt,here,3,&tmpNode,&tmpName)==OK) {
|
|
if (tmpNode->nsGiven) {
|
|
tmp->nodeset=tmpNode->nodeset;
|
|
tmp->nsGiven=tmpNode->nsGiven;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
here->MOS3sNodePrime = here->MOS3sNode;
|
|
}
|
|
|
|
/* macro to make elements with built in test for out of memory */
|
|
#define TSTALLOC(ptr,first,second) \
|
|
do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\
|
|
return(E_NOMEM);\
|
|
} } while(0)
|
|
|
|
TSTALLOC(MOS3DdPtr, MOS3dNode, MOS3dNode);
|
|
TSTALLOC(MOS3GgPtr, MOS3gNode, MOS3gNode);
|
|
TSTALLOC(MOS3SsPtr, MOS3sNode, MOS3sNode);
|
|
TSTALLOC(MOS3BbPtr, MOS3bNode, MOS3bNode);
|
|
TSTALLOC(MOS3DPdpPtr, MOS3dNodePrime, MOS3dNodePrime);
|
|
TSTALLOC(MOS3SPspPtr, MOS3sNodePrime, MOS3sNodePrime);
|
|
TSTALLOC(MOS3DdpPtr, MOS3dNode, MOS3dNodePrime);
|
|
TSTALLOC(MOS3GbPtr, MOS3gNode, MOS3bNode);
|
|
TSTALLOC(MOS3GdpPtr, MOS3gNode, MOS3dNodePrime);
|
|
TSTALLOC(MOS3GspPtr, MOS3gNode, MOS3sNodePrime);
|
|
TSTALLOC(MOS3SspPtr, MOS3sNode, MOS3sNodePrime);
|
|
TSTALLOC(MOS3BdpPtr, MOS3bNode, MOS3dNodePrime);
|
|
TSTALLOC(MOS3BspPtr, MOS3bNode, MOS3sNodePrime);
|
|
TSTALLOC(MOS3DPspPtr, MOS3dNodePrime, MOS3sNodePrime);
|
|
TSTALLOC(MOS3DPdPtr, MOS3dNodePrime, MOS3dNode);
|
|
TSTALLOC(MOS3BgPtr, MOS3bNode, MOS3gNode);
|
|
TSTALLOC(MOS3DPgPtr, MOS3dNodePrime, MOS3gNode);
|
|
TSTALLOC(MOS3SPgPtr, MOS3sNodePrime, MOS3gNode);
|
|
TSTALLOC(MOS3SPsPtr, MOS3sNodePrime, MOS3sNode);
|
|
TSTALLOC(MOS3DPbPtr, MOS3dNodePrime, MOS3bNode);
|
|
TSTALLOC(MOS3SPbPtr, MOS3sNodePrime, MOS3bNode);
|
|
TSTALLOC(MOS3SPdpPtr, MOS3sNodePrime, MOS3dNodePrime);
|
|
|
|
}
|
|
}
|
|
return(OK);
|
|
}
|
|
|
|
int
|
|
MOS3unsetup(GENmodel *inModel, CKTcircuit *ckt)
|
|
{
|
|
MOS3model *model;
|
|
MOS3instance *here;
|
|
|
|
for (model = (MOS3model *)inModel; model != NULL;
|
|
model = model->MOS3nextModel)
|
|
{
|
|
for (here = model->MOS3instances; here != NULL;
|
|
here=here->MOS3nextInstance)
|
|
{
|
|
if (here->MOS3dNodePrime
|
|
&& here->MOS3dNodePrime != here->MOS3dNode)
|
|
{
|
|
CKTdltNNum(ckt, here->MOS3dNodePrime);
|
|
here->MOS3dNodePrime= 0;
|
|
}
|
|
if (here->MOS3sNodePrime
|
|
&& here->MOS3sNodePrime != here->MOS3sNode)
|
|
{
|
|
CKTdltNNum(ckt, here->MOS3sNodePrime);
|
|
here->MOS3sNodePrime= 0;
|
|
}
|
|
}
|
|
}
|
|
return OK;
|
|
}
|