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.
721 lines
24 KiB
721 lines
24 KiB
/**********
|
|
STAG version 2.7
|
|
Copyright 2000 owned by the United Kingdom Secretary of State for Defence
|
|
acting through the Defence Evaluation and Research Agency.
|
|
Developed by : Jim Benson,
|
|
Department of Electronics and Computer Science,
|
|
University of Southampton,
|
|
United Kingdom.
|
|
With help from : Nele D'Halleweyn, Ketan Mistry, Bill Redman-White,
|
|
and Craig Easson.
|
|
|
|
Based on STAG version 2.1
|
|
Developed by : Mike Lee,
|
|
With help from : Bernard Tenbroek, Bill Redman-White, Mike Uren, Chris Edwards
|
|
and John Bunyan.
|
|
Acknowledgements : Rupert Howes and Pete Mole.
|
|
**********/
|
|
|
|
/**********
|
|
Modified by Paolo Nenzi 2002
|
|
ngspice integration
|
|
**********/
|
|
|
|
#include "ngspice.h"
|
|
#include "smpdefs.h"
|
|
#include "cktdefs.h"
|
|
#include "soi3defs.h"
|
|
#include "sperror.h"
|
|
#include "suffix.h"
|
|
|
|
|
|
int
|
|
SOI3setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
|
|
{
|
|
SOI3model *model = (SOI3model *)inModel;
|
|
SOI3instance *here;
|
|
int error;
|
|
CKTnode *tmp;
|
|
|
|
/* JimB - new variable for RT and CT scaling */
|
|
double thermal_area;
|
|
|
|
double rtargs[5];
|
|
double * rtptr;
|
|
int node_count;
|
|
|
|
CKTnode *tmpNode;
|
|
IFuid tmpName;
|
|
|
|
|
|
|
|
/****** Part 1 - set any model parameters that are not present in ******/
|
|
/****** the netlist to default values. ******/
|
|
|
|
/* loop through all the SOI3 device models */
|
|
for( ; model != NULL; model = model->SOI3nextModel ) {
|
|
|
|
if(!model->SOI3typeGiven) {
|
|
model->SOI3type = NSOI3;
|
|
}
|
|
if(!model->SOI3latDiffGiven) {
|
|
model->SOI3latDiff = 0;
|
|
}
|
|
if(!model->SOI3jctSatCurDensityGiven) {
|
|
model->SOI3jctSatCurDensity = 1.0e-10;
|
|
}
|
|
if(!model->SOI3jctSatCurDensity1Given) {
|
|
model->SOI3jctSatCurDensity1 = 0.0;
|
|
}
|
|
if(!model->SOI3jctSatCurGiven) {
|
|
model->SOI3jctSatCur = 0.0;
|
|
}
|
|
if(!model->SOI3jctSatCur1Given) {
|
|
model->SOI3jctSatCur1 = 0.0;
|
|
}
|
|
if(!model->SOI3transconductanceGiven) {
|
|
model->SOI3transconductance = 2e-5;
|
|
}
|
|
if(!model->SOI3frontGateSourceOverlapCapFactorGiven) {
|
|
model->SOI3frontGateSourceOverlapCapFactor = 0;
|
|
}
|
|
if(!model->SOI3frontGateDrainOverlapCapFactorGiven) {
|
|
model->SOI3frontGateDrainOverlapCapFactor = 0;
|
|
}
|
|
if(!model->SOI3frontGateBulkOverlapCapFactorGiven) {
|
|
model->SOI3frontGateBulkOverlapCapFactor = 0;
|
|
}
|
|
if(!model->SOI3backGateSourceOverlapCapAreaFactorGiven) {
|
|
model->SOI3backGateSourceOverlapCapAreaFactor = 0;
|
|
}
|
|
if(!model->SOI3backGateDrainOverlapCapAreaFactorGiven) {
|
|
model->SOI3backGateDrainOverlapCapAreaFactor = 0;
|
|
}
|
|
if(!model->SOI3backGateBulkOverlapCapAreaFactorGiven) {
|
|
model->SOI3backGateBulkOverlapCapAreaFactor = 0;
|
|
}
|
|
if(!model->SOI3sideWallCapFactorGiven) {
|
|
model->SOI3sideWallCapFactor = 0;
|
|
}
|
|
if(!model->SOI3bulkJctPotentialGiven) {
|
|
model->SOI3bulkJctPotential = 0.8;
|
|
}
|
|
if(!model->SOI3bulkJctSideGradingCoeffGiven) {
|
|
model->SOI3bulkJctSideGradingCoeff = 0.5;
|
|
}
|
|
if(!model->SOI3fwdCapDepCoeffGiven) {
|
|
model->SOI3fwdCapDepCoeff = 0.5;
|
|
}
|
|
if(!model->SOI3lambdaGiven) {
|
|
model->SOI3lambda = 0;
|
|
}
|
|
if(!model->SOI3thetaGiven) {
|
|
model->SOI3theta = 0;
|
|
}
|
|
/* JimB - If SiO2 thermal conductivity given in netlist then use */
|
|
/* that value, otherwise use literature value. (Units W/K*m). */
|
|
if(!model->SOI3oxideThermalConductivityGiven) {
|
|
model->SOI3oxideThermalConductivity = 1.4;
|
|
}
|
|
/* JimB - If Si specific heat given in netlist then use that value, */
|
|
/* otherwise use literature value. (Units J/kg*K). */
|
|
if(!model->SOI3siliconSpecificHeatGiven) {
|
|
model->SOI3siliconSpecificHeat = 700;
|
|
}
|
|
/* JimB - If density of Si given in netlist then use that value, */
|
|
/* otherwise use literature value. (kg/m^3). */
|
|
if(!model->SOI3siliconDensityGiven) {
|
|
model->SOI3siliconDensity = 2330;
|
|
}
|
|
if(!model->SOI3frontFixedChargeDensityGiven) {
|
|
model->SOI3frontFixedChargeDensity = 0;
|
|
}
|
|
if(!model->SOI3backFixedChargeDensityGiven) {
|
|
model->SOI3backFixedChargeDensity = 0;
|
|
}
|
|
if(!model->SOI3frontSurfaceStateDensityGiven) {
|
|
model->SOI3frontSurfaceStateDensity = 0;
|
|
}
|
|
if(!model->SOI3backSurfaceStateDensityGiven) {
|
|
model->SOI3backSurfaceStateDensity = 0;
|
|
}
|
|
if(!model->SOI3gammaGiven) {
|
|
model->SOI3gamma = 0;
|
|
}
|
|
if(!model->SOI3fNcoefGiven) {
|
|
model->SOI3fNcoef = 0;
|
|
}
|
|
if(!model->SOI3fNexpGiven) {
|
|
model->SOI3fNexp = 1;
|
|
}
|
|
/* extra stuff for newer model - msll Jan96 */
|
|
if(!model->SOI3sigmaGiven) {
|
|
model->SOI3sigma = 0;
|
|
}
|
|
if(!model->SOI3chiFBGiven) {
|
|
model->SOI3chiFB = 0;
|
|
}
|
|
if(!model->SOI3chiPHIGiven) {
|
|
model->SOI3chiPHI = 0;
|
|
}
|
|
if(!model->SOI3deltaWGiven) {
|
|
model->SOI3deltaW = 0;
|
|
}
|
|
if(!model->SOI3deltaLGiven) {
|
|
model->SOI3deltaL = 0;
|
|
}
|
|
if(!model->SOI3vsatGiven) {
|
|
model->SOI3vsat = 0; /* special case - must check for it */
|
|
}
|
|
if(!model->SOI3kGiven) {
|
|
model->SOI3k = 1.5; /* defaults to old SPICE value */
|
|
}
|
|
if(!model->SOI3lxGiven) {
|
|
model->SOI3lx = 0;
|
|
}
|
|
if(!model->SOI3vpGiven) {
|
|
model->SOI3vp = 0;
|
|
}
|
|
if(!model->SOI3gammaBGiven) {
|
|
model->SOI3gammaB = 0;
|
|
}
|
|
if(!model->SOI3etaGiven) {
|
|
model->SOI3eta = 1.0; /* normal field for imp. ion. */
|
|
}
|
|
if(!model->SOI3alpha0Given) {
|
|
model->SOI3alpha0=0;
|
|
}
|
|
if(!model->SOI3beta0Given) {
|
|
model->SOI3beta0=1.92e6;
|
|
}
|
|
if(!model->SOI3lmGiven) {
|
|
model->SOI3lm = 0;
|
|
}
|
|
if(!model->SOI3lm1Given) {
|
|
model->SOI3lm1 = 0;
|
|
}
|
|
if(!model->SOI3lm2Given) {
|
|
model->SOI3lm2 = 0;
|
|
}
|
|
if((!model->SOI3etadGiven) || (model->SOI3etad == 0 )) {
|
|
model->SOI3etad = 1.0;
|
|
}
|
|
if((!model->SOI3etad1Given) || (model->SOI3etad1 == 0 )) {
|
|
model->SOI3etad1 = 1.0;
|
|
}
|
|
if(!model->SOI3chibetaGiven) {
|
|
model->SOI3chibeta = 0.0;
|
|
}
|
|
if(!model->SOI3dvtGiven) {
|
|
model->SOI3dvt = 1;
|
|
}
|
|
if(!model->SOI3nLevGiven) {
|
|
model->SOI3nLev = 0;
|
|
}
|
|
if(!model->SOI3betaBJTGiven) {
|
|
model->SOI3betaBJT = 0.0;
|
|
}
|
|
if(!model->SOI3tauFBJTGiven) {
|
|
model->SOI3tauFBJT = 0.0;
|
|
}
|
|
if(!model->SOI3tauRBJTGiven) {
|
|
model->SOI3tauRBJT = 0.0;
|
|
}
|
|
if(!model->SOI3betaEXPGiven) {
|
|
model->SOI3betaEXP = 2.0;
|
|
}
|
|
if(!model->SOI3tauEXPGiven) {
|
|
model->SOI3tauEXP = 0.0;
|
|
}
|
|
if(!model->SOI3rswGiven) {
|
|
model->SOI3rsw = 0.0;
|
|
}
|
|
if(!model->SOI3rdwGiven) {
|
|
model->SOI3rdw = 0.0;
|
|
}
|
|
if(!model->SOI3minimumFeatureSizeGiven) {
|
|
model->SOI3minimumFeatureSize = 0.0;
|
|
}
|
|
if(!model->SOI3vtexGiven) {
|
|
model->SOI3vtex = 0.0;
|
|
}
|
|
if(!model->SOI3vdexGiven) {
|
|
model->SOI3vdex = 0.0;
|
|
}
|
|
if(!model->SOI3delta0Given) {
|
|
model->SOI3delta0 = 0.0;
|
|
}
|
|
if(!model->SOI3satChargeShareFactorGiven) {
|
|
model->SOI3satChargeShareFactor = 0.5;
|
|
}
|
|
if(!model->SOI3nplusDopingGiven) {
|
|
model->SOI3nplusDoping = 1e20;
|
|
}
|
|
if(!model->SOI3rtaGiven) {
|
|
model->SOI3rta = 0;
|
|
}
|
|
if(!model->SOI3ctaGiven) {
|
|
model->SOI3cta = 0;
|
|
}
|
|
if(!model->SOI3mexpGiven) {
|
|
model->SOI3mexp = 0;
|
|
}
|
|
|
|
/* now check to determine which CLM model to use */
|
|
if((model->SOI3lx != 0) && (model->SOI3lambda != 0))
|
|
{
|
|
|
|
(*(SPfrontEnd->IFerror))(ERR_WARNING,
|
|
"%s: Non-zero values for BOTH LAMBDA and LX. \nDefaulting to simple LAMBDA model",
|
|
&model->SOI3modName);
|
|
|
|
model->SOI3useLAMBDA = TRUE;
|
|
}
|
|
|
|
/* if only lx given, AND vp!=0, AND mexp (integer) is at least 1, use lx/vp, else basic lambda model*/
|
|
if ((model->SOI3lxGiven) && (model->SOI3lx != 0) &&
|
|
(!model->SOI3lambdaGiven) && (model->SOI3vp != 0) && (model->SOI3mexp > 0))
|
|
{
|
|
model->SOI3useLAMBDA = FALSE;
|
|
}
|
|
else
|
|
{
|
|
model->SOI3useLAMBDA = TRUE;
|
|
}
|
|
|
|
|
|
/****** Part 2 - set any instance parameters that are not present ******/
|
|
/****** in the netlist to default values. ******/
|
|
|
|
/* loop through all the instances of the model */
|
|
for (here = model->SOI3instances; here != NULL ;
|
|
here=here->SOI3nextInstance) {
|
|
|
|
|
|
if(!here->SOI3icVBSGiven) {
|
|
here->SOI3icVBS = 0;
|
|
}
|
|
if(!here->SOI3icVDSGiven) {
|
|
here->SOI3icVDS = 0;
|
|
}
|
|
if(!here->SOI3icVGFSGiven) {
|
|
here->SOI3icVGFS = 0;
|
|
}
|
|
if(!here->SOI3icVGBSGiven) {
|
|
here->SOI3icVGBS = 0;
|
|
}
|
|
if(!here->SOI3drainSquaresGiven || here->SOI3drainSquares==0) {
|
|
here->SOI3drainSquares=1;
|
|
}
|
|
if(!here->SOI3sourceSquaresGiven || here->SOI3sourceSquares==0) {
|
|
here->SOI3sourceSquares=1;
|
|
}
|
|
|
|
if (!here->SOI3mGiven)
|
|
here->SOI3m = 1;
|
|
|
|
/****** Part 3 - Initialise transconductances. ******/
|
|
|
|
/* initialise gM's */
|
|
here->SOI3iMdb= 0.0;
|
|
here->SOI3iMsb= 0.0;
|
|
here->SOI3gMmbs = 0.0;
|
|
here->SOI3gMmf = 0.0;
|
|
here->SOI3gMmb = 0.0;
|
|
here->SOI3gMd = 0.0;
|
|
here->SOI3gMdeltaT = 0.0;
|
|
|
|
if (here->SOI3owner == ARCHme)
|
|
{
|
|
|
|
/* allocate a chunk of the state vector */
|
|
here->SOI3states = *states;
|
|
*states += SOI3numStates;
|
|
/* if(ckt->CKTsenInfo && (ckt->CKTsenInfo->SENmode & TRANSEN) ){
|
|
*states += 10 * (ckt->CKTsenInfo->SENparms);
|
|
}
|
|
*/
|
|
}
|
|
/****** Part 4 - check resistance values for internal nodes, ******/
|
|
/****** to see which internal nodes need to be created. ******/
|
|
|
|
/* Start with internal source and drain nodes */
|
|
|
|
if((model->SOI3drainResistance != 0
|
|
|| (model->SOI3sheetResistance != 0 &&
|
|
here->SOI3drainSquares != 0)
|
|
|| model->SOI3rdw != 0)
|
|
&& here->SOI3dNodePrime == 0)
|
|
{
|
|
error = CKTmkVolt(ckt,&tmp,here->SOI3name,"drain");
|
|
|
|
if(error)
|
|
{
|
|
return(error);
|
|
}
|
|
here->SOI3dNodePrime = 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->SOI3dNodePrime = here->SOI3dNode;
|
|
}
|
|
|
|
if((model->SOI3sourceResistance != 0 ||
|
|
(model->SOI3sheetResistance != 0 &&
|
|
here->SOI3sourceSquares != 0) ||
|
|
model->SOI3rsw != 0) &&
|
|
here->SOI3sNodePrime==0)
|
|
{
|
|
error = CKTmkVolt(ckt,&tmp,here->SOI3name,"source");
|
|
|
|
if(error)
|
|
{
|
|
return(error);
|
|
}
|
|
here->SOI3sNodePrime = 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->SOI3sNodePrime = here->SOI3sNode;
|
|
}
|
|
|
|
/* Now for thermal node */
|
|
|
|
/* JimB - If minimum feature size has non-zero value, then this */
|
|
/* will be used to calculate thermal area of SiO2 - this gives */
|
|
/* more accurate values of RT for short-channel devices. Assume*/
|
|
/* 4*fmin added to L, and 2*fmin added to W (fmin in microns). */
|
|
thermal_area = (here->SOI3w + 2*1e-6*model->SOI3minimumFeatureSize)
|
|
* (here->SOI3l + 4*1e-6*model->SOI3minimumFeatureSize);
|
|
|
|
/* Now calculate RT and CT. */
|
|
|
|
/* If RT is given on instance line, use it, otherwise calculate from */
|
|
/* above variables. */
|
|
if (!here->SOI3rtGiven)
|
|
{
|
|
if (model->SOI3rtaGiven)
|
|
{
|
|
here->SOI3rt = model->SOI3rta/thermal_area;
|
|
}
|
|
else
|
|
{
|
|
if (model->SOI3oxideThermalConductivity != 0)
|
|
{
|
|
here->SOI3rt = model->SOI3backOxideThickness /
|
|
(model->SOI3oxideThermalConductivity * thermal_area);
|
|
}
|
|
else
|
|
/* If conductivity set to zero in netlist, switch off self-heating. */
|
|
{
|
|
here->SOI3rt = 0;
|
|
}
|
|
}
|
|
}
|
|
if (!here->SOI3rt1Given)
|
|
{
|
|
here->SOI3rt1=0;
|
|
}
|
|
if (!here->SOI3rt2Given)
|
|
{
|
|
here->SOI3rt2=0;
|
|
}
|
|
if (!here->SOI3rt3Given)
|
|
{
|
|
here->SOI3rt3=0;
|
|
}
|
|
if (!here->SOI3rt4Given)
|
|
{
|
|
here->SOI3rt4=0;
|
|
}
|
|
|
|
/* Now same thing for CT, but less complex as CT=0 does not cause problems */
|
|
if (!here->SOI3ctGiven)
|
|
{
|
|
if (model->SOI3ctaGiven)
|
|
{
|
|
here->SOI3ct = model->SOI3cta*thermal_area;
|
|
}
|
|
else
|
|
{
|
|
here->SOI3ct = model->SOI3siliconDensity * model->SOI3siliconSpecificHeat *
|
|
thermal_area * model->SOI3bodyThickness;
|
|
}
|
|
}
|
|
if (!here->SOI3ct1Given)
|
|
{
|
|
here->SOI3ct1=0;
|
|
}
|
|
if (!here->SOI3ct2Given)
|
|
{
|
|
here->SOI3ct2=0;
|
|
}
|
|
if (!here->SOI3ct3Given)
|
|
{
|
|
here->SOI3ct3=0;
|
|
}
|
|
if (!here->SOI3ct4Given)
|
|
{
|
|
here->SOI3ct4=0;
|
|
}
|
|
|
|
/* JimB - 15/9/99 */
|
|
rtargs[0]=here->SOI3rt;
|
|
rtargs[1]=here->SOI3rt1;
|
|
rtargs[2]=here->SOI3rt2;
|
|
rtargs[3]=here->SOI3rt3;
|
|
rtargs[4]=here->SOI3rt4;
|
|
rtptr = rtargs; /* Set pointer to start address of rtargs array. */
|
|
node_count=0;
|
|
|
|
while ( (*rtptr) && (node_count<5) )
|
|
{
|
|
node_count++;
|
|
if (node_count<5)
|
|
{
|
|
rtptr++; /* Increment pointer to next array element. */
|
|
}
|
|
}
|
|
here->SOI3numThermalNodes=node_count;
|
|
|
|
/* Thermal node is now external and so is automatically created by CKTcreate in INP2A.
|
|
It is also bound to the created node's number. However, if rt=0 then no thermal so
|
|
make tout be the thermal ground. Can't simply use CKTbindNode 'cos the row and column
|
|
associated with the original node has already been created. Thus problems will occur
|
|
during pivoting. Instead put zero voltage source here. First create branch for it.*/
|
|
|
|
if ((here->SOI3rt == 0) && (here->SOI3branch == 0))
|
|
{
|
|
error = CKTmkCur(ckt,&tmp,here->SOI3name,"branch");
|
|
|
|
if(error)
|
|
{
|
|
return(error);
|
|
}
|
|
here->SOI3branch = tmp->number;
|
|
}
|
|
else
|
|
{ /* have thermal - now how many time constants ? */
|
|
if ((here->SOI3numThermalNodes > 1) &&
|
|
(here->SOI3tout1Node == 0))
|
|
{
|
|
error = CKTmkVolt(ckt,&tmp,here->SOI3name,"tout1");
|
|
if (error) return (error);
|
|
here->SOI3tout1Node = tmp->number;
|
|
}
|
|
else
|
|
{
|
|
here->SOI3tout1Node = 0;
|
|
}
|
|
if ((here->SOI3numThermalNodes > 2) &&
|
|
(here->SOI3tout2Node == 0))
|
|
{
|
|
error = CKTmkVolt(ckt,&tmp,here->SOI3name,"tout2");
|
|
if (error) return (error);
|
|
here->SOI3tout2Node = tmp->number;
|
|
}
|
|
else
|
|
{
|
|
here->SOI3tout2Node = 0;
|
|
}
|
|
if ((here->SOI3numThermalNodes > 3) &&
|
|
(here->SOI3tout3Node == 0))
|
|
{
|
|
error = CKTmkVolt(ckt,&tmp,here->SOI3name,"tout3");
|
|
if (error) return (error);
|
|
here->SOI3tout3Node = tmp->number;
|
|
}
|
|
else
|
|
{
|
|
here->SOI3tout3Node = 0;
|
|
}
|
|
if ((here->SOI3numThermalNodes > 4) &&
|
|
(here->SOI3tout4Node == 0))
|
|
{
|
|
error = CKTmkVolt(ckt,&tmp,here->SOI3name,"tout4");
|
|
if (error) return (error);
|
|
here->SOI3tout4Node = tmp->number;
|
|
}
|
|
else
|
|
{
|
|
here->SOI3tout4Node = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/****** Part 5 - allocate memory to matrix elements corresponding to ******/
|
|
/****** pairs of nodes. ******/
|
|
|
|
/* 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(SOI3D_dPtr,SOI3dNode,SOI3dNode)
|
|
TSTALLOC(SOI3D_dpPtr,SOI3dNode,SOI3dNodePrime)
|
|
TSTALLOC(SOI3DP_dPtr,SOI3dNodePrime,SOI3dNode)
|
|
|
|
TSTALLOC(SOI3S_sPtr,SOI3sNode,SOI3sNode)
|
|
TSTALLOC(SOI3S_spPtr,SOI3sNode,SOI3sNodePrime)
|
|
TSTALLOC(SOI3SP_sPtr,SOI3sNodePrime,SOI3sNode)
|
|
|
|
TSTALLOC(SOI3GF_gfPtr,SOI3gfNode,SOI3gfNode)
|
|
TSTALLOC(SOI3GF_gbPtr,SOI3gfNode,SOI3gbNode)
|
|
TSTALLOC(SOI3GF_dpPtr,SOI3gfNode,SOI3dNodePrime)
|
|
TSTALLOC(SOI3GF_spPtr,SOI3gfNode,SOI3sNodePrime)
|
|
TSTALLOC(SOI3GF_bPtr,SOI3gfNode,SOI3bNode)
|
|
|
|
TSTALLOC(SOI3GB_gfPtr,SOI3gbNode,SOI3gfNode)
|
|
TSTALLOC(SOI3GB_gbPtr,SOI3gbNode,SOI3gbNode)
|
|
TSTALLOC(SOI3GB_dpPtr,SOI3gbNode,SOI3dNodePrime)
|
|
TSTALLOC(SOI3GB_spPtr,SOI3gbNode,SOI3sNodePrime)
|
|
TSTALLOC(SOI3GB_bPtr,SOI3gbNode,SOI3bNode)
|
|
|
|
TSTALLOC(SOI3B_gfPtr,SOI3bNode,SOI3gfNode)
|
|
TSTALLOC(SOI3B_gbPtr,SOI3bNode,SOI3gbNode)
|
|
TSTALLOC(SOI3B_dpPtr,SOI3bNode,SOI3dNodePrime)
|
|
TSTALLOC(SOI3B_spPtr,SOI3bNode,SOI3sNodePrime)
|
|
TSTALLOC(SOI3B_bPtr,SOI3bNode,SOI3bNode)
|
|
|
|
TSTALLOC(SOI3DP_gfPtr,SOI3dNodePrime,SOI3gfNode)
|
|
TSTALLOC(SOI3DP_gbPtr,SOI3dNodePrime,SOI3gbNode)
|
|
TSTALLOC(SOI3DP_dpPtr,SOI3dNodePrime,SOI3dNodePrime)
|
|
TSTALLOC(SOI3DP_spPtr,SOI3dNodePrime,SOI3sNodePrime)
|
|
TSTALLOC(SOI3DP_bPtr,SOI3dNodePrime,SOI3bNode)
|
|
|
|
TSTALLOC(SOI3SP_gfPtr,SOI3sNodePrime,SOI3gfNode)
|
|
TSTALLOC(SOI3SP_gbPtr,SOI3sNodePrime,SOI3gbNode)
|
|
TSTALLOC(SOI3SP_dpPtr,SOI3sNodePrime,SOI3dNodePrime)
|
|
TSTALLOC(SOI3SP_spPtr,SOI3sNodePrime,SOI3sNodePrime)
|
|
TSTALLOC(SOI3SP_bPtr,SOI3sNodePrime,SOI3bNode)
|
|
|
|
if (here->SOI3rt == 0)
|
|
{
|
|
TSTALLOC(SOI3TOUT_ibrPtr,SOI3toutNode,SOI3branch)
|
|
TSTALLOC(SOI3IBR_toutPtr,SOI3branch,SOI3toutNode)
|
|
}
|
|
else
|
|
{
|
|
TSTALLOC(SOI3TOUT_toutPtr,SOI3toutNode,SOI3toutNode)
|
|
if (here->SOI3numThermalNodes > 1)
|
|
{
|
|
TSTALLOC(SOI3TOUT_tout1Ptr,SOI3toutNode,SOI3tout1Node)
|
|
TSTALLOC(SOI3TOUT1_toutPtr,SOI3tout1Node,SOI3toutNode)
|
|
TSTALLOC(SOI3TOUT1_tout1Ptr,SOI3tout1Node,SOI3tout1Node)
|
|
}
|
|
if (here->SOI3numThermalNodes > 2)
|
|
{
|
|
TSTALLOC(SOI3TOUT1_tout2Ptr,SOI3tout1Node,SOI3tout2Node)
|
|
TSTALLOC(SOI3TOUT2_tout1Ptr,SOI3tout2Node,SOI3tout1Node)
|
|
TSTALLOC(SOI3TOUT2_tout2Ptr,SOI3tout2Node,SOI3tout2Node)
|
|
}
|
|
if (here->SOI3numThermalNodes > 3)
|
|
{
|
|
TSTALLOC(SOI3TOUT2_tout3Ptr,SOI3tout2Node,SOI3tout3Node)
|
|
TSTALLOC(SOI3TOUT3_tout2Ptr,SOI3tout3Node,SOI3tout2Node)
|
|
TSTALLOC(SOI3TOUT3_tout3Ptr,SOI3tout3Node,SOI3tout3Node)
|
|
}
|
|
if (here->SOI3numThermalNodes > 4)
|
|
{
|
|
TSTALLOC(SOI3TOUT3_tout4Ptr,SOI3tout3Node,SOI3tout4Node)
|
|
TSTALLOC(SOI3TOUT4_tout3Ptr,SOI3tout4Node,SOI3tout3Node)
|
|
TSTALLOC(SOI3TOUT4_tout4Ptr,SOI3tout4Node,SOI3tout4Node)
|
|
}
|
|
|
|
TSTALLOC(SOI3TOUT_toutPtr,SOI3toutNode,SOI3toutNode)
|
|
TSTALLOC(SOI3TOUT_gfPtr,SOI3toutNode,SOI3gfNode)
|
|
TSTALLOC(SOI3TOUT_gbPtr,SOI3toutNode,SOI3gbNode)
|
|
TSTALLOC(SOI3TOUT_dpPtr,SOI3toutNode,SOI3dNodePrime)
|
|
TSTALLOC(SOI3TOUT_spPtr,SOI3toutNode,SOI3sNodePrime)
|
|
TSTALLOC(SOI3TOUT_bPtr,SOI3toutNode,SOI3bNode)
|
|
|
|
TSTALLOC(SOI3GF_toutPtr,SOI3gfNode,SOI3toutNode)
|
|
TSTALLOC(SOI3GB_toutPtr,SOI3gbNode,SOI3toutNode)
|
|
TSTALLOC(SOI3DP_toutPtr,SOI3dNodePrime,SOI3toutNode)
|
|
TSTALLOC(SOI3SP_toutPtr,SOI3sNodePrime,SOI3toutNode)
|
|
TSTALLOC(SOI3B_toutPtr,SOI3bNode,SOI3toutNode)
|
|
}
|
|
}
|
|
}
|
|
return(OK);
|
|
}
|
|
|
|
|
|
|
|
int
|
|
SOI3unsetup(GENmodel *inModel, CKTcircuit *ckt)
|
|
{
|
|
SOI3model *model;
|
|
SOI3instance *here;
|
|
|
|
for (model = (SOI3model *)inModel; model != NULL;
|
|
model = model->SOI3nextModel)
|
|
{
|
|
for (here = model->SOI3instances; here != NULL;
|
|
here=here->SOI3nextInstance)
|
|
{
|
|
if (here->SOI3dNodePrime
|
|
&& here->SOI3dNodePrime != here->SOI3dNode)
|
|
{
|
|
CKTdltNNum(ckt, here->SOI3dNodePrime);
|
|
here->SOI3dNodePrime= 0;
|
|
}
|
|
if (here->SOI3sNodePrime
|
|
&& here->SOI3sNodePrime != here->SOI3sNode)
|
|
{
|
|
CKTdltNNum(ckt, here->SOI3sNodePrime);
|
|
here->SOI3sNodePrime= 0;
|
|
}
|
|
if (here->SOI3branch)
|
|
{
|
|
CKTdltNNum(ckt, here->SOI3branch);
|
|
here->SOI3branch=0;
|
|
}
|
|
if (here->SOI3tout1Node)
|
|
{
|
|
CKTdltNNum(ckt, here->SOI3tout1Node);
|
|
here->SOI3tout1Node = 0;
|
|
}
|
|
if (here->SOI3tout2Node)
|
|
{
|
|
CKTdltNNum(ckt, here->SOI3tout2Node);
|
|
here->SOI3tout2Node = 0;
|
|
}
|
|
if (here->SOI3tout3Node)
|
|
{
|
|
CKTdltNNum(ckt, here->SOI3tout3Node);
|
|
here->SOI3tout3Node = 0;
|
|
}
|
|
if (here->SOI3tout4Node)
|
|
{
|
|
CKTdltNNum(ckt, here->SOI3tout4Node);
|
|
here->SOI3tout4Node = 0;
|
|
}
|
|
}
|
|
}
|
|
return OK;
|
|
}
|