|
|
|
@ -15,8 +15,8 @@ Modified: 2000 AlansFixes |
|
|
|
|
|
|
|
int |
|
|
|
MOS1load(GENmodel *inModel, CKTcircuit *ckt) |
|
|
|
/* actually load the current value into the |
|
|
|
* sparse matrix previously provided |
|
|
|
/* actually load the current value into the |
|
|
|
* sparse matrix previously provided |
|
|
|
*/ |
|
|
|
{ |
|
|
|
MOS1model *model = (MOS1model *) inModel; |
|
|
|
@ -75,13 +75,13 @@ MOS1load(GENmodel *inModel, CKTcircuit *ckt) |
|
|
|
double capgd = 0.0; /* total gate-drain capacitance */ |
|
|
|
double capgb = 0.0; /* total gate-bulk capacitance */ |
|
|
|
int Check; |
|
|
|
#ifndef NOBYPASS |
|
|
|
#ifndef NOBYPASS |
|
|
|
double tempv; |
|
|
|
#endif /*NOBYPASS*/ |
|
|
|
#endif /*NOBYPASS*/ |
|
|
|
int error; |
|
|
|
#ifdef CAPBYPASS |
|
|
|
int senflag; |
|
|
|
#endif /*CAPBYPASS*/ |
|
|
|
#endif /*CAPBYPASS*/ |
|
|
|
int SenCond; |
|
|
|
|
|
|
|
|
|
|
|
@ -92,14 +92,14 @@ MOS1load(GENmodel *inModel, CKTcircuit *ckt) |
|
|
|
(ckt->CKTsenInfo->SENmode & (ACSEN | TRANSEN))) { |
|
|
|
senflag = 1; |
|
|
|
} |
|
|
|
#endif /* CAPBYPASS */ |
|
|
|
#endif /* CAPBYPASS */ |
|
|
|
|
|
|
|
/* loop through all the MOS1 device models */ |
|
|
|
for( ; model != NULL; model = MOS1nextModel(model)) { |
|
|
|
|
|
|
|
/* loop through all the instances of the model */ |
|
|
|
for (here = MOS1instances(model); here != NULL ; |
|
|
|
here=MOS1nextInstance(here)) { |
|
|
|
here=MOS1nextInstance(here)) { |
|
|
|
|
|
|
|
vt = CONSTKoverQ * here->MOS1temp; |
|
|
|
Check=1; |
|
|
|
@ -109,13 +109,13 @@ MOS1load(GENmodel *inModel, CKTcircuit *ckt) |
|
|
|
#endif /* SENSDEBUG */ |
|
|
|
|
|
|
|
if((ckt->CKTsenInfo->SENstatus == PERTURBATION)&& |
|
|
|
(here->MOS1senPertFlag == OFF))continue; |
|
|
|
(here->MOS1senPertFlag == OFF))continue; |
|
|
|
|
|
|
|
} |
|
|
|
SenCond = ckt->CKTsenInfo && here->MOS1senPertFlag; |
|
|
|
|
|
|
|
/* |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
/* first, we compute a few useful values - these could be |
|
|
|
@ -124,30 +124,30 @@ MOS1load(GENmodel *inModel, CKTcircuit *ckt) |
|
|
|
*/ |
|
|
|
|
|
|
|
EffectiveLength=here->MOS1l - 2*model->MOS1latDiff; |
|
|
|
|
|
|
|
if( (here->MOS1tSatCurDens == 0) || |
|
|
|
|
|
|
|
if( (here->MOS1tSatCurDens == 0) || |
|
|
|
(here->MOS1drainArea == 0) || |
|
|
|
(here->MOS1sourceArea == 0)) { |
|
|
|
DrainSatCur = here->MOS1m * here->MOS1tSatCur; |
|
|
|
SourceSatCur = here->MOS1m * here->MOS1tSatCur; |
|
|
|
} else { |
|
|
|
DrainSatCur = here->MOS1tSatCurDens * |
|
|
|
DrainSatCur = here->MOS1tSatCurDens * |
|
|
|
here->MOS1m * here->MOS1drainArea; |
|
|
|
SourceSatCur = here->MOS1tSatCurDens * |
|
|
|
SourceSatCur = here->MOS1tSatCurDens * |
|
|
|
here->MOS1m * here->MOS1sourceArea; |
|
|
|
} |
|
|
|
GateSourceOverlapCap = model->MOS1gateSourceOverlapCapFactor * |
|
|
|
GateSourceOverlapCap = model->MOS1gateSourceOverlapCapFactor * |
|
|
|
here->MOS1m * here->MOS1w; |
|
|
|
GateDrainOverlapCap = model->MOS1gateDrainOverlapCapFactor * |
|
|
|
GateDrainOverlapCap = model->MOS1gateDrainOverlapCapFactor * |
|
|
|
here->MOS1m * here->MOS1w; |
|
|
|
GateBulkOverlapCap = model->MOS1gateBulkOverlapCapFactor * |
|
|
|
GateBulkOverlapCap = model->MOS1gateBulkOverlapCapFactor * |
|
|
|
here->MOS1m * EffectiveLength; |
|
|
|
Beta = here->MOS1tTransconductance * here->MOS1m * |
|
|
|
here->MOS1w/EffectiveLength; |
|
|
|
OxideCap = model->MOS1oxideCapFactor * EffectiveLength * |
|
|
|
OxideCap = model->MOS1oxideCapFactor * EffectiveLength * |
|
|
|
here->MOS1m * here->MOS1w; |
|
|
|
|
|
|
|
/* |
|
|
|
|
|
|
|
/* |
|
|
|
* ok - now to do the start-up operations |
|
|
|
* |
|
|
|
* we must get values for vbs, vds, and vgs from somewhere |
|
|
|
@ -162,7 +162,7 @@ MOS1load(GENmodel *inModel, CKTcircuit *ckt) |
|
|
|
printf("MOS1senPertFlag = ON \n"); |
|
|
|
#endif /* SENSDEBUG */ |
|
|
|
if((ckt->CKTsenInfo->SENmode == TRANSEN) && |
|
|
|
(ckt->CKTmode & MODEINITTRAN)) { |
|
|
|
(ckt->CKTmode & MODEINITTRAN)) { |
|
|
|
vgs = *(ckt->CKTstate1 + here->MOS1vgs); |
|
|
|
vds = *(ckt->CKTstate1 + here->MOS1vds); |
|
|
|
vbs = *(ckt->CKTstate1 + here->MOS1vbs); |
|
|
|
@ -171,7 +171,7 @@ MOS1load(GENmodel *inModel, CKTcircuit *ckt) |
|
|
|
vgd = vgs - vds; |
|
|
|
} |
|
|
|
else if (ckt->CKTsenInfo->SENmode == ACSEN){ |
|
|
|
vgb = model->MOS1type * ( |
|
|
|
vgb = model->MOS1type * ( |
|
|
|
*(ckt->CKTrhsOp+here->MOS1gNode) - |
|
|
|
*(ckt->CKTrhsOp+here->MOS1bNode)); |
|
|
|
vbs = *(ckt->CKTstate0 + here->MOS1vbs); |
|
|
|
@ -197,41 +197,41 @@ MOS1load(GENmodel *inModel, CKTcircuit *ckt) |
|
|
|
|
|
|
|
|
|
|
|
if((ckt->CKTmode & (MODEINITFLOAT | MODEINITPRED | MODEINITSMSIG |
|
|
|
| MODEINITTRAN)) || |
|
|
|
( (ckt->CKTmode & MODEINITFIX) && (!here->MOS1off) ) ) { |
|
|
|
| MODEINITTRAN)) || |
|
|
|
( (ckt->CKTmode & MODEINITFIX) && (!here->MOS1off) ) ) { |
|
|
|
#ifndef PREDICTOR |
|
|
|
if(ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) { |
|
|
|
|
|
|
|
/* predictor step */ |
|
|
|
|
|
|
|
xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1]; |
|
|
|
*(ckt->CKTstate0 + here->MOS1vbs) = |
|
|
|
*(ckt->CKTstate1 + here->MOS1vbs); |
|
|
|
*(ckt->CKTstate0 + here->MOS1vbs) = |
|
|
|
*(ckt->CKTstate1 + here->MOS1vbs); |
|
|
|
vbs = (1+xfact)* (*(ckt->CKTstate1 + here->MOS1vbs)) |
|
|
|
-(xfact * (*(ckt->CKTstate2 + here->MOS1vbs))); |
|
|
|
*(ckt->CKTstate0 + here->MOS1vgs) = |
|
|
|
*(ckt->CKTstate1 + here->MOS1vgs); |
|
|
|
-(xfact * (*(ckt->CKTstate2 + here->MOS1vbs))); |
|
|
|
*(ckt->CKTstate0 + here->MOS1vgs) = |
|
|
|
*(ckt->CKTstate1 + here->MOS1vgs); |
|
|
|
vgs = (1+xfact)* (*(ckt->CKTstate1 + here->MOS1vgs)) |
|
|
|
-(xfact * (*(ckt->CKTstate2 + here->MOS1vgs))); |
|
|
|
*(ckt->CKTstate0 + here->MOS1vds) = |
|
|
|
*(ckt->CKTstate1 + here->MOS1vds); |
|
|
|
-(xfact * (*(ckt->CKTstate2 + here->MOS1vgs))); |
|
|
|
*(ckt->CKTstate0 + here->MOS1vds) = |
|
|
|
*(ckt->CKTstate1 + here->MOS1vds); |
|
|
|
vds = (1+xfact)* (*(ckt->CKTstate1 + here->MOS1vds)) |
|
|
|
-(xfact * (*(ckt->CKTstate2 + here->MOS1vds))); |
|
|
|
*(ckt->CKTstate0 + here->MOS1vbd) = |
|
|
|
*(ckt->CKTstate0 + here->MOS1vbs)- |
|
|
|
*(ckt->CKTstate0 + here->MOS1vds); |
|
|
|
-(xfact * (*(ckt->CKTstate2 + here->MOS1vds))); |
|
|
|
*(ckt->CKTstate0 + here->MOS1vbd) = |
|
|
|
*(ckt->CKTstate0 + here->MOS1vbs)- |
|
|
|
*(ckt->CKTstate0 + here->MOS1vds); |
|
|
|
} else { |
|
|
|
#endif /* PREDICTOR */ |
|
|
|
|
|
|
|
/* general iteration */ |
|
|
|
|
|
|
|
vbs = model->MOS1type * ( |
|
|
|
*(ckt->CKTrhsOld+here->MOS1bNode) - |
|
|
|
*(ckt->CKTrhsOld+here->MOS1sNodePrime)); |
|
|
|
vgs = model->MOS1type * ( |
|
|
|
vbs = model->MOS1type * ( |
|
|
|
*(ckt->CKTrhsOld+here->MOS1bNode) - |
|
|
|
*(ckt->CKTrhsOld+here->MOS1sNodePrime)); |
|
|
|
vgs = model->MOS1type * ( |
|
|
|
*(ckt->CKTrhsOld+here->MOS1gNode) - |
|
|
|
*(ckt->CKTrhsOld+here->MOS1sNodePrime)); |
|
|
|
vds = model->MOS1type * ( |
|
|
|
vds = model->MOS1type * ( |
|
|
|
*(ckt->CKTrhsOld+here->MOS1dNodePrime) - |
|
|
|
*(ckt->CKTrhsOld+here->MOS1sNodePrime)); |
|
|
|
#ifndef PREDICTOR |
|
|
|
@ -242,8 +242,8 @@ MOS1load(GENmodel *inModel, CKTcircuit *ckt) |
|
|
|
|
|
|
|
vbd=vbs-vds; |
|
|
|
vgd=vgs-vds; |
|
|
|
vgdo = *(ckt->CKTstate0 + here->MOS1vgs) - |
|
|
|
*(ckt->CKTstate0 + here->MOS1vds); |
|
|
|
vgdo = *(ckt->CKTstate0 + here->MOS1vgs) - |
|
|
|
*(ckt->CKTstate0 + here->MOS1vds); |
|
|
|
delvbs = vbs - *(ckt->CKTstate0 + here->MOS1vbs); |
|
|
|
delvbd = vbd - *(ckt->CKTstate0 + here->MOS1vbd); |
|
|
|
delvgs = vgs - *(ckt->CKTstate0 + here->MOS1vgs); |
|
|
|
@ -254,98 +254,98 @@ MOS1load(GENmodel *inModel, CKTcircuit *ckt) |
|
|
|
|
|
|
|
if (here->MOS1mode >= 0) { |
|
|
|
cdhat= |
|
|
|
here->MOS1cd- |
|
|
|
here->MOS1gbd * delvbd + |
|
|
|
here->MOS1gmbs * delvbs + |
|
|
|
here->MOS1gm * delvgs + |
|
|
|
here->MOS1gds * delvds ; |
|
|
|
here->MOS1cd- |
|
|
|
here->MOS1gbd * delvbd + |
|
|
|
here->MOS1gmbs * delvbs + |
|
|
|
here->MOS1gm * delvgs + |
|
|
|
here->MOS1gds * delvds ; |
|
|
|
} else { |
|
|
|
cdhat= |
|
|
|
here->MOS1cd - |
|
|
|
( here->MOS1gbd - |
|
|
|
here->MOS1gmbs) * delvbd - |
|
|
|
here->MOS1gm * delvgd + |
|
|
|
here->MOS1cd - |
|
|
|
( here->MOS1gbd - |
|
|
|
here->MOS1gmbs) * delvbd - |
|
|
|
here->MOS1gm * delvgd + |
|
|
|
here->MOS1gds * delvds ; |
|
|
|
} |
|
|
|
cbhat= |
|
|
|
here->MOS1cbs + |
|
|
|
here->MOS1cbd + |
|
|
|
here->MOS1gbd * delvbd + |
|
|
|
here->MOS1gbs * delvbs ; |
|
|
|
here->MOS1cbs + |
|
|
|
here->MOS1cbd + |
|
|
|
here->MOS1gbd * delvbd + |
|
|
|
here->MOS1gbs * delvbs ; |
|
|
|
/* |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
#ifndef NOBYPASS |
|
|
|
/* now lets see if we can bypass (ugh) */ |
|
|
|
tempv = (MAX(fabs(cbhat), |
|
|
|
fabs(here->MOS1cbs + here->MOS1cbd)) + |
|
|
|
ckt->CKTabstol); |
|
|
|
fabs(here->MOS1cbs + here->MOS1cbd)) + |
|
|
|
ckt->CKTabstol); |
|
|
|
if ((!(ckt->CKTmode & |
|
|
|
(MODEINITPRED|MODEINITTRAN|MODEINITSMSIG))) && |
|
|
|
(ckt->CKTbypass) && |
|
|
|
(fabs(cbhat-(here->MOS1cbs + |
|
|
|
here->MOS1cbd)) < ckt->CKTreltol * tempv) && |
|
|
|
(fabs(delvbs) < (ckt->CKTreltol * |
|
|
|
MAX(fabs(vbs), |
|
|
|
fabs( *(ckt->CKTstate0 + |
|
|
|
here->MOS1vbs))) + |
|
|
|
ckt->CKTvoltTol)) && |
|
|
|
(fabs(delvbd) < (ckt->CKTreltol * |
|
|
|
MAX(fabs(vbd), |
|
|
|
fabs(*(ckt->CKTstate0 + |
|
|
|
here->MOS1vbd))) + |
|
|
|
ckt->CKTvoltTol)) && |
|
|
|
(fabs(delvgs) < (ckt->CKTreltol * |
|
|
|
MAX(fabs(vgs), |
|
|
|
fabs(*(ckt->CKTstate0 + |
|
|
|
here->MOS1vgs)))+ |
|
|
|
ckt->CKTvoltTol)) && |
|
|
|
(fabs(delvds) < (ckt->CKTreltol * |
|
|
|
MAX(fabs(vds), |
|
|
|
fabs(*(ckt->CKTstate0 + |
|
|
|
here->MOS1vds))) + |
|
|
|
ckt->CKTvoltTol)) && |
|
|
|
(fabs(cdhat- here->MOS1cd) < (ckt->CKTreltol * |
|
|
|
MAX(fabs(cdhat), |
|
|
|
fabs(here->MOS1cd)) + |
|
|
|
ckt->CKTabstol))) { |
|
|
|
/* bypass code */ |
|
|
|
/* nothing interesting has changed since last |
|
|
|
* iteration on this device, so we just |
|
|
|
* copy all the values computed last iteration out |
|
|
|
* and keep going |
|
|
|
*/ |
|
|
|
vbs = *(ckt->CKTstate0 + here->MOS1vbs); |
|
|
|
vbd = *(ckt->CKTstate0 + here->MOS1vbd); |
|
|
|
vgs = *(ckt->CKTstate0 + here->MOS1vgs); |
|
|
|
vds = *(ckt->CKTstate0 + here->MOS1vds); |
|
|
|
vgd = vgs - vds; |
|
|
|
vgb = vgs - vbs; |
|
|
|
cdrain = here->MOS1mode * (here->MOS1cd + here->MOS1cbd); |
|
|
|
if(ckt->CKTmode & (MODETRAN | MODETRANOP)) { |
|
|
|
capgs = ( *(ckt->CKTstate0+here->MOS1capgs)+ |
|
|
|
*(ckt->CKTstate1+here->MOS1capgs) + |
|
|
|
GateSourceOverlapCap ); |
|
|
|
capgd = ( *(ckt->CKTstate0+here->MOS1capgd)+ |
|
|
|
*(ckt->CKTstate1+here->MOS1capgd) + |
|
|
|
GateDrainOverlapCap ); |
|
|
|
capgb = ( *(ckt->CKTstate0+here->MOS1capgb)+ |
|
|
|
*(ckt->CKTstate1+here->MOS1capgb) + |
|
|
|
GateBulkOverlapCap ); |
|
|
|
|
|
|
|
if(ckt->CKTsenInfo){ |
|
|
|
here->MOS1cgs = capgs; |
|
|
|
here->MOS1cgd = capgd; |
|
|
|
here->MOS1cgb = capgb; |
|
|
|
} |
|
|
|
} |
|
|
|
goto bypass; |
|
|
|
} |
|
|
|
(MODEINITPRED|MODEINITTRAN|MODEINITSMSIG))) && |
|
|
|
(ckt->CKTbypass) && |
|
|
|
(fabs(cbhat-(here->MOS1cbs + |
|
|
|
here->MOS1cbd)) < ckt->CKTreltol * tempv) && |
|
|
|
(fabs(delvbs) < (ckt->CKTreltol * |
|
|
|
MAX(fabs(vbs), |
|
|
|
fabs( *(ckt->CKTstate0 + |
|
|
|
here->MOS1vbs))) + |
|
|
|
ckt->CKTvoltTol)) && |
|
|
|
(fabs(delvbd) < (ckt->CKTreltol * |
|
|
|
MAX(fabs(vbd), |
|
|
|
fabs(*(ckt->CKTstate0 + |
|
|
|
here->MOS1vbd))) + |
|
|
|
ckt->CKTvoltTol)) && |
|
|
|
(fabs(delvgs) < (ckt->CKTreltol * |
|
|
|
MAX(fabs(vgs), |
|
|
|
fabs(*(ckt->CKTstate0 + |
|
|
|
here->MOS1vgs)))+ |
|
|
|
ckt->CKTvoltTol)) && |
|
|
|
(fabs(delvds) < (ckt->CKTreltol * |
|
|
|
MAX(fabs(vds), |
|
|
|
fabs(*(ckt->CKTstate0 + |
|
|
|
here->MOS1vds))) + |
|
|
|
ckt->CKTvoltTol)) && |
|
|
|
(fabs(cdhat- here->MOS1cd) < (ckt->CKTreltol * |
|
|
|
MAX(fabs(cdhat), |
|
|
|
fabs(here->MOS1cd)) + |
|
|
|
ckt->CKTabstol))) { |
|
|
|
/* bypass code */ |
|
|
|
/* nothing interesting has changed since last |
|
|
|
* iteration on this device, so we just |
|
|
|
* copy all the values computed last iteration out |
|
|
|
* and keep going |
|
|
|
*/ |
|
|
|
vbs = *(ckt->CKTstate0 + here->MOS1vbs); |
|
|
|
vbd = *(ckt->CKTstate0 + here->MOS1vbd); |
|
|
|
vgs = *(ckt->CKTstate0 + here->MOS1vgs); |
|
|
|
vds = *(ckt->CKTstate0 + here->MOS1vds); |
|
|
|
vgd = vgs - vds; |
|
|
|
vgb = vgs - vbs; |
|
|
|
cdrain = here->MOS1mode * (here->MOS1cd + here->MOS1cbd); |
|
|
|
if(ckt->CKTmode & (MODETRAN | MODETRANOP)) { |
|
|
|
capgs = ( *(ckt->CKTstate0+here->MOS1capgs)+ |
|
|
|
*(ckt->CKTstate1+here->MOS1capgs) + |
|
|
|
GateSourceOverlapCap ); |
|
|
|
capgd = ( *(ckt->CKTstate0+here->MOS1capgd)+ |
|
|
|
*(ckt->CKTstate1+here->MOS1capgd) + |
|
|
|
GateDrainOverlapCap ); |
|
|
|
capgb = ( *(ckt->CKTstate0+here->MOS1capgb)+ |
|
|
|
*(ckt->CKTstate1+here->MOS1capgb) + |
|
|
|
GateBulkOverlapCap ); |
|
|
|
|
|
|
|
if(ckt->CKTsenInfo){ |
|
|
|
here->MOS1cgs = capgs; |
|
|
|
here->MOS1cgd = capgd; |
|
|
|
here->MOS1cgb = capgb; |
|
|
|
} |
|
|
|
} |
|
|
|
goto bypass; |
|
|
|
} |
|
|
|
#endif /*NOBYPASS*/ |
|
|
|
|
|
|
|
/* |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
/* ok - bypass is out, do it the hard way */ |
|
|
|
@ -353,7 +353,7 @@ MOS1load(GENmodel *inModel, CKTcircuit *ckt) |
|
|
|
von = model->MOS1type * here->MOS1von; |
|
|
|
|
|
|
|
#ifndef NODELIMITING |
|
|
|
/* |
|
|
|
/* |
|
|
|
* limiting |
|
|
|
* we want to keep device voltages from changing |
|
|
|
* so fast that the exponentials churn out overflows |
|
|
|
@ -362,7 +362,7 @@ MOS1load(GENmodel *inModel, CKTcircuit *ckt) |
|
|
|
|
|
|
|
if(*(ckt->CKTstate0 + here->MOS1vds) >=0) { |
|
|
|
vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->MOS1vgs) |
|
|
|
,von); |
|
|
|
,von); |
|
|
|
vds = vgs - vgd; |
|
|
|
vds = DEVlimvds(vds,*(ckt->CKTstate0 + here->MOS1vds)); |
|
|
|
vgd = vgs - vds; |
|
|
|
@ -370,23 +370,23 @@ MOS1load(GENmodel *inModel, CKTcircuit *ckt) |
|
|
|
vgd = DEVfetlim(vgd,vgdo,von); |
|
|
|
vds = vgs - vgd; |
|
|
|
if(!(ckt->CKTfixLimit)) { |
|
|
|
vds = -DEVlimvds(-vds,-(*(ckt->CKTstate0 + |
|
|
|
here->MOS1vds))); |
|
|
|
vds = -DEVlimvds(-vds,-(*(ckt->CKTstate0 + |
|
|
|
here->MOS1vds))); |
|
|
|
} |
|
|
|
vgs = vgd + vds; |
|
|
|
} |
|
|
|
if(vds >= 0) { |
|
|
|
vbs = DEVpnjlim(vbs,*(ckt->CKTstate0 + here->MOS1vbs), |
|
|
|
vt,here->MOS1sourceVcrit,&Check); |
|
|
|
vt,here->MOS1sourceVcrit,&Check); |
|
|
|
vbd = vbs-vds; |
|
|
|
} else { |
|
|
|
vbd = DEVpnjlim(vbd,*(ckt->CKTstate0 + here->MOS1vbd), |
|
|
|
vt,here->MOS1drainVcrit,&Check); |
|
|
|
vt,here->MOS1drainVcrit,&Check); |
|
|
|
vbs = vbd + vds; |
|
|
|
} |
|
|
|
#endif /*NODELIMITING*/ |
|
|
|
/* |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
} else { |
|
|
|
@ -400,20 +400,20 @@ MOS1load(GENmodel *inModel, CKTcircuit *ckt) |
|
|
|
vds= model->MOS1type * here->MOS1icVDS; |
|
|
|
vgs= model->MOS1type * here->MOS1icVGS; |
|
|
|
vbs= model->MOS1type * here->MOS1icVBS; |
|
|
|
if((vds==0) && (vgs==0) && (vbs==0) && |
|
|
|
((ckt->CKTmode & |
|
|
|
(MODETRAN|MODEDCOP|MODEDCTRANCURVE)) || |
|
|
|
(!(ckt->CKTmode & MODEUIC)))) { |
|
|
|
if((vds==0) && (vgs==0) && (vbs==0) && |
|
|
|
((ckt->CKTmode & |
|
|
|
(MODETRAN|MODEDCOP|MODEDCTRANCURVE)) || |
|
|
|
(!(ckt->CKTmode & MODEUIC)))) { |
|
|
|
vbs = -1; |
|
|
|
vgs = model->MOS1type * here->MOS1tVto; |
|
|
|
vds = 0; |
|
|
|
} |
|
|
|
} else { |
|
|
|
vbs=vgs=vds=0; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
/* |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
/* |
|
|
|
@ -457,25 +457,25 @@ next1: if(vbs <= -3*vt) { |
|
|
|
here->MOS1mode = -1; |
|
|
|
} |
|
|
|
/* |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
{ |
|
|
|
/* |
|
|
|
* this block of code evaluates the drain current and its |
|
|
|
* derivatives using the shichman-hodges model and the |
|
|
|
* charges associated with the gate, channel and bulk for |
|
|
|
* mosfets |
|
|
|
* |
|
|
|
*/ |
|
|
|
|
|
|
|
/* the following 4 variables are local to this code block until |
|
|
|
* it is obvious that they can be made global |
|
|
|
*/ |
|
|
|
double arg; |
|
|
|
double betap; |
|
|
|
double sarg; |
|
|
|
double vgst; |
|
|
|
/* |
|
|
|
* this block of code evaluates the drain current and its |
|
|
|
* derivatives using the shichman-hodges model and the |
|
|
|
* charges associated with the gate, channel and bulk for |
|
|
|
* mosfets |
|
|
|
* |
|
|
|
*/ |
|
|
|
|
|
|
|
/* the following 4 variables are local to this code block until |
|
|
|
* it is obvious that they can be made global |
|
|
|
*/ |
|
|
|
double arg; |
|
|
|
double betap; |
|
|
|
double sarg; |
|
|
|
double vgst; |
|
|
|
|
|
|
|
if ((here->MOS1mode==1?vbs:vbd) <= 0 ) { |
|
|
|
sarg=sqrt(here->MOS1tPhi-(here->MOS1mode==1?vbs:vbd)); |
|
|
|
@ -511,17 +511,17 @@ next1: if(vbs <= -3*vt) { |
|
|
|
here->MOS1gds=model->MOS1lambda*Beta*vgst*vgst*.5; |
|
|
|
here->MOS1gmbs=here->MOS1gm*arg; |
|
|
|
} else { |
|
|
|
/* |
|
|
|
* linear region |
|
|
|
*/ |
|
|
|
/* |
|
|
|
* linear region |
|
|
|
*/ |
|
|
|
cdrain=betap*(vds*here->MOS1mode)* |
|
|
|
(vgst-.5*(vds*here->MOS1mode)); |
|
|
|
here->MOS1gm=betap*(vds*here->MOS1mode); |
|
|
|
here->MOS1gds=betap*(vgst-(vds*here->MOS1mode))+ |
|
|
|
model->MOS1lambda*Beta* |
|
|
|
(vds*here->MOS1mode)* |
|
|
|
(vgst-.5*(vds*here->MOS1mode)); |
|
|
|
here->MOS1gmbs=here->MOS1gm*arg; |
|
|
|
model->MOS1lambda*Beta* |
|
|
|
(vds*here->MOS1mode)* |
|
|
|
(vgst-.5*(vds*here->MOS1mode)); |
|
|
|
here->MOS1gmbs=here->MOS1gm*arg; |
|
|
|
} |
|
|
|
} |
|
|
|
/* |
|
|
|
@ -529,7 +529,7 @@ next1: if(vbs <= -3*vt) { |
|
|
|
*/ |
|
|
|
} |
|
|
|
/* |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
/* now deal with n vs p polarity */ |
|
|
|
@ -543,7 +543,7 @@ next1: if(vbs <= -3*vt) { |
|
|
|
here->MOS1cd=here->MOS1mode * cdrain - here->MOS1cbd; |
|
|
|
|
|
|
|
if (ckt->CKTmode & (MODETRAN | MODETRANOP | MODEINITSMSIG)) { |
|
|
|
/* |
|
|
|
/* |
|
|
|
* now we do the hard part of the bulk-drain and bulk-source |
|
|
|
* diode - we evaluate the non-linear capacitance and |
|
|
|
* charge |
|
|
|
@ -563,123 +563,123 @@ next1: if(vbs <= -3*vt) { |
|
|
|
fabs(*(ckt->CKTstate0+here->MOS1vbs)))+ |
|
|
|
ckt->CKTvoltTol)|| senflag) |
|
|
|
#endif /*CAPBYPASS*/ |
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
/* can't bypass the diode capacitance calculations */ |
|
|
|
if(here->MOS1Cbs != 0 || here->MOS1Cbssw != 0 ) { |
|
|
|
if (vbs < here->MOS1tDepCap){ |
|
|
|
arg=1-vbs/here->MOS1tBulkPot; |
|
|
|
/* |
|
|
|
* the following block looks somewhat long and messy, |
|
|
|
* but since most users use the default grading |
|
|
|
* coefficients of .5, and sqrt is MUCH faster than an |
|
|
|
* exp(log()) we use this special case code to buy time. |
|
|
|
* (as much as 10% of total job time!) |
|
|
|
*/ |
|
|
|
if(model->MOS1bulkJctBotGradingCoeff == |
|
|
|
model->MOS1bulkJctSideGradingCoeff) { |
|
|
|
if(model->MOS1bulkJctBotGradingCoeff == .5) { |
|
|
|
sarg = sargsw = 1/sqrt(arg); |
|
|
|
} else { |
|
|
|
sarg = sargsw = |
|
|
|
exp(-model->MOS1bulkJctBotGradingCoeff* |
|
|
|
log(arg)); |
|
|
|
} |
|
|
|
} else { |
|
|
|
if(model->MOS1bulkJctBotGradingCoeff == .5) { |
|
|
|
sarg = 1/sqrt(arg); |
|
|
|
} else { |
|
|
|
sarg = exp(-model->MOS1bulkJctBotGradingCoeff* |
|
|
|
log(arg)); |
|
|
|
} |
|
|
|
if(model->MOS1bulkJctSideGradingCoeff == .5) { |
|
|
|
sargsw = 1/sqrt(arg); |
|
|
|
} else { |
|
|
|
sargsw =exp(-model->MOS1bulkJctSideGradingCoeff* |
|
|
|
log(arg)); |
|
|
|
} |
|
|
|
} |
|
|
|
*(ckt->CKTstate0 + here->MOS1qbs) = |
|
|
|
here->MOS1tBulkPot*(here->MOS1Cbs* |
|
|
|
(1-arg*sarg)/(1-model->MOS1bulkJctBotGradingCoeff) |
|
|
|
+here->MOS1Cbssw* |
|
|
|
(1-arg*sargsw)/ |
|
|
|
(1-model->MOS1bulkJctSideGradingCoeff)); |
|
|
|
here->MOS1capbs=here->MOS1Cbs*sarg+ |
|
|
|
here->MOS1Cbssw*sargsw; |
|
|
|
} else { |
|
|
|
*(ckt->CKTstate0 + here->MOS1qbs) = here->MOS1f4s + |
|
|
|
vbs*(here->MOS1f2s+vbs*(here->MOS1f3s/2)); |
|
|
|
here->MOS1capbs=here->MOS1f2s+here->MOS1f3s*vbs; |
|
|
|
} |
|
|
|
if (vbs < here->MOS1tDepCap){ |
|
|
|
arg=1-vbs/here->MOS1tBulkPot; |
|
|
|
/* |
|
|
|
* the following block looks somewhat long and messy, |
|
|
|
* but since most users use the default grading |
|
|
|
* coefficients of .5, and sqrt is MUCH faster than an |
|
|
|
* exp(log()) we use this special case code to buy time. |
|
|
|
* (as much as 10% of total job time!) |
|
|
|
*/ |
|
|
|
if(model->MOS1bulkJctBotGradingCoeff == |
|
|
|
model->MOS1bulkJctSideGradingCoeff) { |
|
|
|
if(model->MOS1bulkJctBotGradingCoeff == .5) { |
|
|
|
sarg = sargsw = 1/sqrt(arg); |
|
|
|
} else { |
|
|
|
sarg = sargsw = |
|
|
|
exp(-model->MOS1bulkJctBotGradingCoeff* |
|
|
|
log(arg)); |
|
|
|
} |
|
|
|
} else { |
|
|
|
if(model->MOS1bulkJctBotGradingCoeff == .5) { |
|
|
|
sarg = 1/sqrt(arg); |
|
|
|
} else { |
|
|
|
sarg = exp(-model->MOS1bulkJctBotGradingCoeff* |
|
|
|
log(arg)); |
|
|
|
} |
|
|
|
if(model->MOS1bulkJctSideGradingCoeff == .5) { |
|
|
|
sargsw = 1/sqrt(arg); |
|
|
|
} else { |
|
|
|
sargsw =exp(-model->MOS1bulkJctSideGradingCoeff* |
|
|
|
log(arg)); |
|
|
|
} |
|
|
|
} |
|
|
|
*(ckt->CKTstate0 + here->MOS1qbs) = |
|
|
|
here->MOS1tBulkPot*(here->MOS1Cbs* |
|
|
|
(1-arg*sarg)/(1-model->MOS1bulkJctBotGradingCoeff) |
|
|
|
+here->MOS1Cbssw* |
|
|
|
(1-arg*sargsw)/ |
|
|
|
(1-model->MOS1bulkJctSideGradingCoeff)); |
|
|
|
here->MOS1capbs=here->MOS1Cbs*sarg+ |
|
|
|
here->MOS1Cbssw*sargsw; |
|
|
|
} else { |
|
|
|
*(ckt->CKTstate0 + here->MOS1qbs) = here->MOS1f4s + |
|
|
|
vbs*(here->MOS1f2s+vbs*(here->MOS1f3s/2)); |
|
|
|
here->MOS1capbs=here->MOS1f2s+here->MOS1f3s*vbs; |
|
|
|
} |
|
|
|
} else { |
|
|
|
*(ckt->CKTstate0 + here->MOS1qbs) = 0; |
|
|
|
*(ckt->CKTstate0 + here->MOS1qbs) = 0; |
|
|
|
here->MOS1capbs=0; |
|
|
|
} |
|
|
|
} |
|
|
|
#ifdef CAPBYPASS |
|
|
|
if(((ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) || |
|
|
|
fabs(delvbd) >= ckt->CKTreltol * MAX(fabs(vbd), |
|
|
|
fabs(*(ckt->CKTstate0+here->MOS1vbd)))+ |
|
|
|
ckt->CKTvoltTol)|| senflag) |
|
|
|
#endif /*CAPBYPASS*/ |
|
|
|
|
|
|
|
fabs(delvbd) >= ckt->CKTreltol * MAX(fabs(vbd), |
|
|
|
fabs(*(ckt->CKTstate0+here->MOS1vbd)))+ |
|
|
|
ckt->CKTvoltTol)|| senflag) |
|
|
|
#endif /*CAPBYPASS*/ |
|
|
|
|
|
|
|
/* can't bypass the diode capacitance calculations */ |
|
|
|
{ |
|
|
|
if(here->MOS1Cbd != 0 || here->MOS1Cbdsw != 0 ) { |
|
|
|
if (vbd < here->MOS1tDepCap) { |
|
|
|
arg=1-vbd/here->MOS1tBulkPot; |
|
|
|
/* |
|
|
|
* the following block looks somewhat long and messy, |
|
|
|
* but since most users use the default grading |
|
|
|
* coefficients of .5, and sqrt is MUCH faster than an |
|
|
|
* exp(log()) we use this special case code to buy time. |
|
|
|
* (as much as 10% of total job time!) |
|
|
|
*/ |
|
|
|
if(model->MOS1bulkJctBotGradingCoeff == .5 && |
|
|
|
model->MOS1bulkJctSideGradingCoeff == .5) { |
|
|
|
sarg = sargsw = 1/sqrt(arg); |
|
|
|
} else { |
|
|
|
if(model->MOS1bulkJctBotGradingCoeff == .5) { |
|
|
|
sarg = 1/sqrt(arg); |
|
|
|
} else { |
|
|
|
sarg = exp(-model->MOS1bulkJctBotGradingCoeff* |
|
|
|
log(arg)); |
|
|
|
} |
|
|
|
if(model->MOS1bulkJctSideGradingCoeff == .5) { |
|
|
|
sargsw = 1/sqrt(arg); |
|
|
|
} else { |
|
|
|
sargsw =exp(-model->MOS1bulkJctSideGradingCoeff* |
|
|
|
log(arg)); |
|
|
|
} |
|
|
|
} |
|
|
|
*(ckt->CKTstate0 + here->MOS1qbd) = |
|
|
|
here->MOS1tBulkPot*(here->MOS1Cbd* |
|
|
|
(1-arg*sarg) |
|
|
|
/(1-model->MOS1bulkJctBotGradingCoeff) |
|
|
|
+here->MOS1Cbdsw* |
|
|
|
(1-arg*sargsw) |
|
|
|
/(1-model->MOS1bulkJctSideGradingCoeff)); |
|
|
|
here->MOS1capbd=here->MOS1Cbd*sarg+ |
|
|
|
here->MOS1Cbdsw*sargsw; |
|
|
|
} else { |
|
|
|
*(ckt->CKTstate0 + here->MOS1qbd) = here->MOS1f4d + |
|
|
|
vbd * (here->MOS1f2d + vbd * here->MOS1f3d/2); |
|
|
|
here->MOS1capbd=here->MOS1f2d + vbd * here->MOS1f3d; |
|
|
|
} |
|
|
|
} else { |
|
|
|
*(ckt->CKTstate0 + here->MOS1qbd) = 0; |
|
|
|
here->MOS1capbd = 0; |
|
|
|
} |
|
|
|
if (vbd < here->MOS1tDepCap) { |
|
|
|
arg=1-vbd/here->MOS1tBulkPot; |
|
|
|
/* |
|
|
|
* the following block looks somewhat long and messy, |
|
|
|
* but since most users use the default grading |
|
|
|
* coefficients of .5, and sqrt is MUCH faster than an |
|
|
|
* exp(log()) we use this special case code to buy time. |
|
|
|
* (as much as 10% of total job time!) |
|
|
|
*/ |
|
|
|
if(model->MOS1bulkJctBotGradingCoeff == .5 && |
|
|
|
model->MOS1bulkJctSideGradingCoeff == .5) { |
|
|
|
sarg = sargsw = 1/sqrt(arg); |
|
|
|
} else { |
|
|
|
if(model->MOS1bulkJctBotGradingCoeff == .5) { |
|
|
|
sarg = 1/sqrt(arg); |
|
|
|
} else { |
|
|
|
sarg = exp(-model->MOS1bulkJctBotGradingCoeff* |
|
|
|
log(arg)); |
|
|
|
} |
|
|
|
if(model->MOS1bulkJctSideGradingCoeff == .5) { |
|
|
|
sargsw = 1/sqrt(arg); |
|
|
|
} else { |
|
|
|
sargsw =exp(-model->MOS1bulkJctSideGradingCoeff* |
|
|
|
log(arg)); |
|
|
|
} |
|
|
|
} |
|
|
|
*(ckt->CKTstate0 + here->MOS1qbd) = |
|
|
|
here->MOS1tBulkPot*(here->MOS1Cbd* |
|
|
|
(1-arg*sarg) |
|
|
|
/(1-model->MOS1bulkJctBotGradingCoeff) |
|
|
|
+here->MOS1Cbdsw* |
|
|
|
(1-arg*sargsw) |
|
|
|
/(1-model->MOS1bulkJctSideGradingCoeff)); |
|
|
|
here->MOS1capbd=here->MOS1Cbd*sarg+ |
|
|
|
here->MOS1Cbdsw*sargsw; |
|
|
|
} else { |
|
|
|
*(ckt->CKTstate0 + here->MOS1qbd) = here->MOS1f4d + |
|
|
|
vbd * (here->MOS1f2d + vbd * here->MOS1f3d/2); |
|
|
|
here->MOS1capbd=here->MOS1f2d + vbd * here->MOS1f3d; |
|
|
|
} |
|
|
|
} else { |
|
|
|
*(ckt->CKTstate0 + here->MOS1qbd) = 0; |
|
|
|
here->MOS1capbd = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
/* |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
if(SenCond && (ckt->CKTsenInfo->SENmode==TRANSEN)) goto next2; |
|
|
|
|
|
|
|
if ( (ckt->CKTmode & MODETRAN) || ( (ckt->CKTmode&MODEINITTRAN) |
|
|
|
&& !(ckt->CKTmode&MODEUIC)) ) { |
|
|
|
&& !(ckt->CKTmode&MODEUIC)) ) { |
|
|
|
/* (above only excludes tranop, since we're only at this |
|
|
|
* point if tran or tranop ) |
|
|
|
*/ |
|
|
|
@ -692,20 +692,20 @@ next1: if(vbs <= -3*vt) { |
|
|
|
/* integrate the capacitors and save results */ |
|
|
|
|
|
|
|
error = NIintegrate(ckt,&geq,&ceq,here->MOS1capbd, |
|
|
|
here->MOS1qbd); |
|
|
|
here->MOS1qbd); |
|
|
|
if(error) return(error); |
|
|
|
here->MOS1gbd += geq; |
|
|
|
here->MOS1cbd += *(ckt->CKTstate0 + here->MOS1cqbd); |
|
|
|
here->MOS1cd -= *(ckt->CKTstate0 + here->MOS1cqbd); |
|
|
|
error = NIintegrate(ckt,&geq,&ceq,here->MOS1capbs, |
|
|
|
here->MOS1qbs); |
|
|
|
here->MOS1qbs); |
|
|
|
if(error) return(error); |
|
|
|
here->MOS1gbs += geq; |
|
|
|
here->MOS1cbs += *(ckt->CKTstate0 + here->MOS1cqbs); |
|
|
|
} |
|
|
|
} |
|
|
|
/* |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
if(SenCond) goto next2; |
|
|
|
@ -714,26 +714,27 @@ next1: if(vbs <= -3*vt) { |
|
|
|
/* |
|
|
|
* check convergence |
|
|
|
*/ |
|
|
|
if ( (here->MOS1off == 0) || |
|
|
|
(!(ckt->CKTmode & (MODEINITFIX|MODEINITSMSIG))) ){ |
|
|
|
if ( (here->MOS1off == 0) || |
|
|
|
(!(ckt->CKTmode & (MODEINITFIX|MODEINITSMSIG))) ){ |
|
|
|
if (Check == 1) { |
|
|
|
ckt->CKTnoncon++; |
|
|
|
ckt->CKTtroubleElt = (GENinstance *) here; |
|
|
|
ckt->CKTtroubleElt = (GENinstance *) here; |
|
|
|
} |
|
|
|
} |
|
|
|
/* |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
/* save things away for next time */ |
|
|
|
|
|
|
|
next2: *(ckt->CKTstate0 + here->MOS1vbs) = vbs; |
|
|
|
next2: |
|
|
|
*(ckt->CKTstate0 + here->MOS1vbs) = vbs; |
|
|
|
*(ckt->CKTstate0 + here->MOS1vbd) = vbd; |
|
|
|
*(ckt->CKTstate0 + here->MOS1vgs) = vgs; |
|
|
|
*(ckt->CKTstate0 + here->MOS1vds) = vds; |
|
|
|
|
|
|
|
/* |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
/* |
|
|
|
@ -743,7 +744,7 @@ next1: if(vbs <= -3*vt) { |
|
|
|
/* |
|
|
|
* calculate meyer's capacitors |
|
|
|
*/ |
|
|
|
/* |
|
|
|
/* |
|
|
|
* new cmeyer - this just evaluates at the current time, |
|
|
|
* expects you to remember values from previous time |
|
|
|
* returns 1/2 of non-constant portion of capacitance |
|
|
|
@ -752,37 +753,37 @@ next1: if(vbs <= -3*vt) { |
|
|
|
*/ |
|
|
|
if (here->MOS1mode > 0){ |
|
|
|
DEVqmeyer (vgs,vgd,vgb,von,vdsat, |
|
|
|
(ckt->CKTstate0 + here->MOS1capgs), |
|
|
|
(ckt->CKTstate0 + here->MOS1capgd), |
|
|
|
(ckt->CKTstate0 + here->MOS1capgb), |
|
|
|
here->MOS1tPhi,OxideCap); |
|
|
|
(ckt->CKTstate0 + here->MOS1capgs), |
|
|
|
(ckt->CKTstate0 + here->MOS1capgd), |
|
|
|
(ckt->CKTstate0 + here->MOS1capgb), |
|
|
|
here->MOS1tPhi,OxideCap); |
|
|
|
} else { |
|
|
|
DEVqmeyer (vgd,vgs,vgb,von,vdsat, |
|
|
|
(ckt->CKTstate0 + here->MOS1capgd), |
|
|
|
(ckt->CKTstate0 + here->MOS1capgs), |
|
|
|
(ckt->CKTstate0 + here->MOS1capgb), |
|
|
|
here->MOS1tPhi,OxideCap); |
|
|
|
(ckt->CKTstate0 + here->MOS1capgd), |
|
|
|
(ckt->CKTstate0 + here->MOS1capgs), |
|
|
|
(ckt->CKTstate0 + here->MOS1capgb), |
|
|
|
here->MOS1tPhi,OxideCap); |
|
|
|
} |
|
|
|
vgs1 = *(ckt->CKTstate1 + here->MOS1vgs); |
|
|
|
vgd1 = vgs1 - *(ckt->CKTstate1 + here->MOS1vds); |
|
|
|
vgb1 = vgs1 - *(ckt->CKTstate1 + here->MOS1vbs); |
|
|
|
if(ckt->CKTmode & (MODETRANOP|MODEINITSMSIG)) { |
|
|
|
capgs = 2 * *(ckt->CKTstate0+here->MOS1capgs)+ |
|
|
|
GateSourceOverlapCap ; |
|
|
|
capgd = 2 * *(ckt->CKTstate0+here->MOS1capgd)+ |
|
|
|
GateDrainOverlapCap ; |
|
|
|
capgb = 2 * *(ckt->CKTstate0+here->MOS1capgb)+ |
|
|
|
GateBulkOverlapCap ; |
|
|
|
capgs = 2 * *(ckt->CKTstate0+here->MOS1capgs)+ |
|
|
|
GateSourceOverlapCap ; |
|
|
|
capgd = 2 * *(ckt->CKTstate0+here->MOS1capgd)+ |
|
|
|
GateDrainOverlapCap ; |
|
|
|
capgb = 2 * *(ckt->CKTstate0+here->MOS1capgb)+ |
|
|
|
GateBulkOverlapCap ; |
|
|
|
} else { |
|
|
|
capgs = ( *(ckt->CKTstate0+here->MOS1capgs)+ |
|
|
|
*(ckt->CKTstate1+here->MOS1capgs) + |
|
|
|
GateSourceOverlapCap ); |
|
|
|
capgd = ( *(ckt->CKTstate0+here->MOS1capgd)+ |
|
|
|
*(ckt->CKTstate1+here->MOS1capgd) + |
|
|
|
GateDrainOverlapCap ); |
|
|
|
capgb = ( *(ckt->CKTstate0+here->MOS1capgb)+ |
|
|
|
*(ckt->CKTstate1+here->MOS1capgb) + |
|
|
|
GateBulkOverlapCap ); |
|
|
|
capgs = ( *(ckt->CKTstate0+here->MOS1capgs)+ |
|
|
|
*(ckt->CKTstate1+here->MOS1capgs) + |
|
|
|
GateSourceOverlapCap ); |
|
|
|
capgd = ( *(ckt->CKTstate0+here->MOS1capgd)+ |
|
|
|
*(ckt->CKTstate1+here->MOS1capgd) + |
|
|
|
GateDrainOverlapCap ); |
|
|
|
capgb = ( *(ckt->CKTstate0+here->MOS1capgb)+ |
|
|
|
*(ckt->CKTstate1+here->MOS1capgb) + |
|
|
|
GateBulkOverlapCap ); |
|
|
|
} |
|
|
|
if(ckt->CKTsenInfo){ |
|
|
|
here->MOS1cgs = capgs; |
|
|
|
@ -790,7 +791,7 @@ next1: if(vbs <= -3*vt) { |
|
|
|
here->MOS1cgb = capgb; |
|
|
|
} |
|
|
|
/* |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
/* |
|
|
|
@ -799,7 +800,7 @@ next1: if(vbs <= -3*vt) { |
|
|
|
*/ |
|
|
|
if(SenCond){ |
|
|
|
if((ckt->CKTsenInfo->SENmode == DCSEN)|| |
|
|
|
(ckt->CKTsenInfo->SENmode == ACSEN)){ |
|
|
|
(ckt->CKTsenInfo->SENmode == ACSEN)){ |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -807,14 +808,14 @@ next1: if(vbs <= -3*vt) { |
|
|
|
#ifndef PREDICTOR |
|
|
|
if (ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) { |
|
|
|
*(ckt->CKTstate0 + here->MOS1qgs) = |
|
|
|
(1+xfact) * *(ckt->CKTstate1 + here->MOS1qgs) |
|
|
|
- xfact * *(ckt->CKTstate2 + here->MOS1qgs); |
|
|
|
(1+xfact) * *(ckt->CKTstate1 + here->MOS1qgs) |
|
|
|
- xfact * *(ckt->CKTstate2 + here->MOS1qgs); |
|
|
|
*(ckt->CKTstate0 + here->MOS1qgd) = |
|
|
|
(1+xfact) * *(ckt->CKTstate1 + here->MOS1qgd) |
|
|
|
- xfact * *(ckt->CKTstate2 + here->MOS1qgd); |
|
|
|
(1+xfact) * *(ckt->CKTstate1 + here->MOS1qgd) |
|
|
|
- xfact * *(ckt->CKTstate2 + here->MOS1qgd); |
|
|
|
*(ckt->CKTstate0 + here->MOS1qgb) = |
|
|
|
(1+xfact) * *(ckt->CKTstate1 + here->MOS1qgb) |
|
|
|
- xfact * *(ckt->CKTstate2 + here->MOS1qgb); |
|
|
|
(1+xfact) * *(ckt->CKTstate1 + here->MOS1qgb) |
|
|
|
- xfact * *(ckt->CKTstate2 + here->MOS1qgb); |
|
|
|
} else { |
|
|
|
#endif /*PREDICTOR*/ |
|
|
|
if(ckt->CKTmode & MODETRAN) { |
|
|
|
@ -835,14 +836,14 @@ next1: if(vbs <= -3*vt) { |
|
|
|
#endif /*PREDICTOR*/ |
|
|
|
} |
|
|
|
#ifndef NOBYPASS |
|
|
|
bypass: |
|
|
|
bypass: |
|
|
|
#endif |
|
|
|
if(SenCond) continue; |
|
|
|
|
|
|
|
if ( (ckt->CKTmode & (MODEINITTRAN)) || |
|
|
|
(! (ckt->CKTmode & (MODETRAN)) ) ) { |
|
|
|
if ( (ckt->CKTmode & (MODEINITTRAN)) || |
|
|
|
(! (ckt->CKTmode & (MODETRAN)) ) ) { |
|
|
|
/* |
|
|
|
* initialize to zero charge conductances |
|
|
|
* initialize to zero charge conductances |
|
|
|
* and current |
|
|
|
*/ |
|
|
|
gcgs=0; |
|
|
|
@ -865,12 +866,12 @@ next1: if(vbs <= -3*vt) { |
|
|
|
if(error) return(error); |
|
|
|
error = NIintegrate(ckt,&gcgb,&ceqgb,capgb,here->MOS1qgb); |
|
|
|
if(error) return(error); |
|
|
|
ceqgs=ceqgs-gcgs*vgs+ckt->CKTag[0]* |
|
|
|
*(ckt->CKTstate0 + here->MOS1qgs); |
|
|
|
ceqgs=ceqgs-gcgs*vgs+ckt->CKTag[0]* |
|
|
|
*(ckt->CKTstate0 + here->MOS1qgs); |
|
|
|
ceqgd=ceqgd-gcgd*vgd+ckt->CKTag[0]* |
|
|
|
*(ckt->CKTstate0 + here->MOS1qgd); |
|
|
|
*(ckt->CKTstate0 + here->MOS1qgd); |
|
|
|
ceqgb=ceqgb-gcgb*vgb+ckt->CKTag[0]* |
|
|
|
*(ckt->CKTstate0 + here->MOS1qgb); |
|
|
|
*(ckt->CKTstate0 + here->MOS1qgb); |
|
|
|
} |
|
|
|
/* |
|
|
|
* store charge storage info for meyer's cap in lx table |
|
|
|
@ -879,29 +880,29 @@ next1: if(vbs <= -3*vt) { |
|
|
|
/* |
|
|
|
* load current vector |
|
|
|
*/ |
|
|
|
ceqbs = model->MOS1type * |
|
|
|
(here->MOS1cbs-(here->MOS1gbs)*vbs); |
|
|
|
ceqbd = model->MOS1type * |
|
|
|
(here->MOS1cbd-(here->MOS1gbd)*vbd); |
|
|
|
ceqbs = model->MOS1type * |
|
|
|
(here->MOS1cbs-(here->MOS1gbs)*vbs); |
|
|
|
ceqbd = model->MOS1type * |
|
|
|
(here->MOS1cbd-(here->MOS1gbd)*vbd); |
|
|
|
if (here->MOS1mode >= 0) { |
|
|
|
xnrm=1; |
|
|
|
xrev=0; |
|
|
|
cdreq=model->MOS1type*(cdrain-here->MOS1gds*vds- |
|
|
|
here->MOS1gm*vgs-here->MOS1gmbs*vbs); |
|
|
|
here->MOS1gm*vgs-here->MOS1gmbs*vbs); |
|
|
|
} else { |
|
|
|
xnrm=0; |
|
|
|
xrev=1; |
|
|
|
cdreq = -(model->MOS1type)*(cdrain-here->MOS1gds*(-vds)- |
|
|
|
here->MOS1gm*vgd-here->MOS1gmbs*vbd); |
|
|
|
here->MOS1gm*vgd-here->MOS1gmbs*vbd); |
|
|
|
} |
|
|
|
*(ckt->CKTrhs + here->MOS1gNode) -= |
|
|
|
(model->MOS1type * (ceqgs + ceqgb + ceqgd)); |
|
|
|
*(ckt->CKTrhs + here->MOS1gNode) -= |
|
|
|
(model->MOS1type * (ceqgs + ceqgb + ceqgd)); |
|
|
|
*(ckt->CKTrhs + here->MOS1bNode) -= |
|
|
|
(ceqbs + ceqbd - model->MOS1type * ceqgb); |
|
|
|
(ceqbs + ceqbd - model->MOS1type * ceqgb); |
|
|
|
*(ckt->CKTrhs + here->MOS1dNodePrime) += |
|
|
|
(ceqbd - cdreq + model->MOS1type * ceqgd); |
|
|
|
*(ckt->CKTrhs + here->MOS1sNodePrime) += |
|
|
|
cdreq + ceqbs + model->MOS1type * ceqgs; |
|
|
|
(ceqbd - cdreq + model->MOS1type * ceqgd); |
|
|
|
*(ckt->CKTrhs + here->MOS1sNodePrime) += |
|
|
|
cdreq + ceqbs + model->MOS1type * ceqgs; |
|
|
|
/* |
|
|
|
* load y matrix |
|
|
|
*/ |
|
|
|
@ -910,12 +911,12 @@ next1: if(vbs <= -3*vt) { |
|
|
|
*(here->MOS1GgPtr) += ((gcgd+gcgs+gcgb)); |
|
|
|
*(here->MOS1SsPtr) += (here->MOS1sourceConductance); |
|
|
|
*(here->MOS1BbPtr) += (here->MOS1gbd+here->MOS1gbs+gcgb); |
|
|
|
*(here->MOS1DPdpPtr) += |
|
|
|
(here->MOS1drainConductance+here->MOS1gds+ |
|
|
|
here->MOS1gbd+xrev*(here->MOS1gm+here->MOS1gmbs)+gcgd); |
|
|
|
*(here->MOS1SPspPtr) += |
|
|
|
(here->MOS1sourceConductance+here->MOS1gds+ |
|
|
|
here->MOS1gbs+xnrm*(here->MOS1gm+here->MOS1gmbs)+gcgs); |
|
|
|
*(here->MOS1DPdpPtr) += |
|
|
|
(here->MOS1drainConductance+here->MOS1gds+ |
|
|
|
here->MOS1gbd+xrev*(here->MOS1gm+here->MOS1gmbs)+gcgd); |
|
|
|
*(here->MOS1SPspPtr) += |
|
|
|
(here->MOS1sourceConductance+here->MOS1gds+ |
|
|
|
here->MOS1gbs+xnrm*(here->MOS1gm+here->MOS1gmbs)+gcgs); |
|
|
|
*(here->MOS1DdpPtr) += (-here->MOS1drainConductance); |
|
|
|
*(here->MOS1GbPtr) -= gcgb; |
|
|
|
*(here->MOS1GdpPtr) -= gcgd; |
|
|
|
@ -928,13 +929,13 @@ next1: if(vbs <= -3*vt) { |
|
|
|
*(here->MOS1DPgPtr) += ((xnrm-xrev)*here->MOS1gm-gcgd); |
|
|
|
*(here->MOS1DPbPtr) += (-here->MOS1gbd+(xnrm-xrev)*here->MOS1gmbs); |
|
|
|
*(here->MOS1DPspPtr) += (-here->MOS1gds-xnrm* |
|
|
|
(here->MOS1gm+here->MOS1gmbs)); |
|
|
|
(here->MOS1gm+here->MOS1gmbs)); |
|
|
|
*(here->MOS1SPgPtr) += (-(xnrm-xrev)*here->MOS1gm-gcgs); |
|
|
|
*(here->MOS1SPsPtr) += (-here->MOS1sourceConductance); |
|
|
|
*(here->MOS1SPbPtr) += (-here->MOS1gbs-(xnrm-xrev)*here->MOS1gmbs); |
|
|
|
*(here->MOS1SPdpPtr) += (-here->MOS1gds-xrev* |
|
|
|
(here->MOS1gm+here->MOS1gmbs)); |
|
|
|
(here->MOS1gm+here->MOS1gmbs)); |
|
|
|
} |
|
|
|
} |
|
|
|
return(OK); |
|
|
|
} |
|
|
|
} /* end of function MOS1load */ |