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/devdefs.h"
#include "ngspice/cktdefs.h"
#include "ngspice/suffix.h"
#include <stdarg.h>
* Limit the per-iteration change of VDS
*/
double
DEVlimvds(double vnew, double vold)
{
if(vold >= 3.5) {
if(vnew > vold) {
vnew = MIN(vnew,(3 * vold) +2);
} else {
if (vnew < 3.5) {
vnew = MAX(vnew,2);
}
}
} else {
if(vnew > vold) {
vnew = MIN(vnew,4);
} else {
vnew = MAX(vnew,-.5);
}
}
return(vnew);
}
* Limit the per-iteration change of PN junction voltages
*
* This code has been fixed by Alan Gillespie adding limiting
* for negative voltages.
*/
double
DEVpnjlim(double vnew, double vold, double vt, double vcrit, int *icheck)
{
double arg;
if((vnew > vcrit) && (fabs(vnew - vold) > (vt + vt))) {
if(vold > 0) {
arg = (vnew - vold) / vt;
if(arg > 0) {
vnew = vold + vt * (2+log(arg-2));
} else {
vnew = vold - vt * (2+log(2-arg));
}
} else {
vnew = vt *log(vnew/vt);
}
*icheck = 1;
} else {
if (vnew < 0) {
if (vold > 0) {
arg = -1*vold-1;
} else {
arg = 2*vold-1;
}
if (vnew < arg) {
vnew = arg;
*icheck = 1;
} else {
*icheck = 0;
}
} else {
*icheck = 0;
}
}
return(vnew);
}
* Limit the per-iteration change of FET voltages
*
* This code has been fixed by Alan Gillespie: a new
* definition for vtstlo.
*/
double
DEVfetlim(double vnew, double vold, double vto)
{
double vtsthi;
double vtstlo;
double vtox;
double delv;
double vtemp;
vtsthi = fabs(2*(vold-vto))+2;
vtstlo = fabs(vold-vto)+1;
vtox = vto + 3.5;
delv = vnew-vold;
if (vold >= vto) {
if(vold >= vtox) {
if(delv <= 0) {
if(vnew >= vtox) {
if(-delv >vtstlo) {
vnew = vold - vtstlo;
}
} else {
vnew = MAX(vnew,vto+2);
}
} else {
if(delv >= vtsthi) {
vnew = vold + vtsthi;
}
}
} else {
if(delv <= 0) {
vnew = MAX(vnew,vto-.5);
} else {
vnew = MIN(vnew,vto+4);
}
}
} else {
if(delv <= 0) {
if(-delv >vtsthi) {
vnew = vold - vtsthi;
}
} else {
vtemp = vto + .5;
if(vnew <= vtemp) {
if(delv >vtstlo) {
vnew = vold + vtstlo;
}
} else {
vnew = vtemp;
}
}
}
return(vnew);
}
* Logarithmic damping the per-iteration change of deltemp beyond LIM_TOL.
*/
double
DEVlimitlog(
double deltemp,
double deltemp_old,
double LIM_TOL,
int *check)
{
static bool shown = FALSE;
*check = 0;
if (!shown && (isnan (deltemp) || isnan (deltemp_old)))
{
fprintf(stderr, "\n\nThe temperature limiting function received NaN.\n");
fprintf(stderr, "Please check your power dissipation and improve your heat sink Rth!\n");
fprintf(stderr, " This message will be shown only once.\n\n");
deltemp = 0.0;
*check = 1;
shown = TRUE;
}
if (deltemp > deltemp_old + LIM_TOL) {
deltemp = deltemp_old + LIM_TOL + log10((deltemp-deltemp_old)/LIM_TOL);
*check = 1;
}
else if (deltemp < deltemp_old - LIM_TOL) {
deltemp = deltemp_old - LIM_TOL - log10((deltemp_old-deltemp)/LIM_TOL);
*check = 1;
}
return deltemp;
}
int
ACM_SourceDrainResistances(
int ACM,
double LD,
double LDIF,
double HDIF,
double WMLT,
double w,
double XW,
double RSH,
int drainSquaresGiven,
double RD,
double RDC,
double drainSquares,
int sourceSquaresGiven,
double RS,
double RSC,
double sourceSquares,
double *drainResistance,
double *sourceResistance
)
{
switch (ACM)
{
case 1:
case 11:
*drainResistance = (LD + LDIF)/(w * WMLT + XW)*RD + RSH*drainSquares + RDC;
*sourceResistance = (LD + LDIF)/(w * WMLT + XW)*RS + RSH*sourceSquares + RSC;
break;
case 2:
case 12:
case 3:
case 13:
if (drainSquaresGiven)
*drainResistance = (LD + LDIF)/(w * WMLT + XW)*RD + RSH*drainSquares + RDC;
else
*drainResistance = ((LD + LDIF)*RD + (HDIF * WMLT)*RSH)/(w * WMLT + XW) + RDC;
if (sourceSquaresGiven)
*sourceResistance = (LD + LDIF)/(w * WMLT + XW)*RS + RSH*sourceSquares + RSC;
else
*sourceResistance = ((LD + LDIF)*RS + (HDIF * WMLT)*RSH)/(w * WMLT + XW) + RSC;
break;
default:
break;
}
return 0;
}
int
ACM_saturationCurrents(
int ACM,
int CALCACM,
int GEO,
double HDIF,
double WMLT,
double w,
double XW,
double jctTempSatCurDensity,
double jctSidewallTempSatCurDensity,
int drainAreaGiven,
double drainArea,
int drainPerimeterGiven,
double drainPerimeter,
int sourceAreaGiven,
double sourceArea,
int sourcePerimeterGiven,
double sourcePerimeter,
double *DrainSatCurrent,
double *SourceSatCurrent
)
{
switch (ACM)
{
case 1:
case 11:
drainArea = (w * WMLT + XW) * WMLT;
drainPerimeter = (w * WMLT + XW);
*DrainSatCurrent = drainArea * jctTempSatCurDensity + drainPerimeter * jctSidewallTempSatCurDensity;
if (*DrainSatCurrent <= 0.0) *DrainSatCurrent = 1.0e-14;
sourceArea = (w * WMLT + XW) * WMLT;
sourcePerimeter = (w * WMLT + XW);
*SourceSatCurrent = sourceArea * jctTempSatCurDensity + sourcePerimeter * jctSidewallTempSatCurDensity;
if (*SourceSatCurrent <= 0.0) *SourceSatCurrent = 1.0e-14;
break;
case 2:
case 12:
if ((ACM == 2) || ((ACM == 12) && (CALCACM == 1))) {
if (!drainAreaGiven)
drainArea = 2.0 * (HDIF * WMLT) * (w * WMLT + XW);
else
drainArea = drainArea * WMLT * WMLT;
if (!drainPerimeterGiven)
drainPerimeter = 4.0 * (HDIF * WMLT) + 2.0 * (w * WMLT + XW);
else
drainPerimeter = drainPerimeter * WMLT;
}
*DrainSatCurrent = drainArea * jctTempSatCurDensity + drainPerimeter * jctSidewallTempSatCurDensity;
if (*DrainSatCurrent <= 0.0) *DrainSatCurrent = 1.0e-14;
if ((ACM == 2) || ((ACM == 12) && (CALCACM == 1))) {
if (!sourceAreaGiven)
sourceArea = 2.0 * (HDIF * WMLT) * (w * WMLT + XW);
else
sourceArea = sourceArea * WMLT * WMLT;
if (!sourcePerimeterGiven)
sourcePerimeter = 4.0 * (HDIF * WMLT) + 2.0 * (w * WMLT + XW);
else
sourcePerimeter = sourcePerimeter * WMLT;
}
*SourceSatCurrent = sourceArea * jctTempSatCurDensity + sourcePerimeter * jctSidewallTempSatCurDensity;
if (*SourceSatCurrent <= 0.0) *SourceSatCurrent = 1.0e-14;
break;
case 3:
case 13:
if (!drainAreaGiven)
if ((GEO == 0) || (GEO == 2))
drainArea = 2.0 * (HDIF * WMLT) * (w * WMLT + XW);
else
drainArea = (HDIF * WMLT) * (w * WMLT + XW);
else
drainArea = drainArea * WMLT * WMLT;
if (!drainPerimeterGiven)
if ((GEO == 0) || (GEO == 2))
drainPerimeter = 4.0 * (HDIF * WMLT) + (w * WMLT + XW);
else
drainPerimeter = 2.0 * (HDIF * WMLT);
else
drainPerimeter = drainPerimeter * WMLT;
*DrainSatCurrent = drainArea * jctTempSatCurDensity + drainPerimeter * jctSidewallTempSatCurDensity;
if (*DrainSatCurrent <= 0.0) *DrainSatCurrent = 1.0e-14;
if (!sourceAreaGiven)
if ((GEO == 0) || (GEO == 1))
sourceArea = 2.0 * (HDIF * WMLT) * (w * WMLT + XW);
else
sourceArea = (HDIF * WMLT) * (w * WMLT + XW);
else
sourceArea = sourceArea * WMLT * WMLT;
if (!sourcePerimeterGiven)
if ((GEO == 0) || (GEO == 1))
sourcePerimeter = 4.0 * (HDIF * WMLT) + (w * WMLT + XW);
else
sourcePerimeter = 2.0 * (HDIF * WMLT);
else
sourcePerimeter = sourcePerimeter * WMLT;
*SourceSatCurrent = sourceArea * jctTempSatCurDensity + sourcePerimeter * jctSidewallTempSatCurDensity;
if (*SourceSatCurrent <= 0.0) *SourceSatCurrent = 1.0e-14;
break;
default:
break;
}
return 0;
}
int
ACM_junctionCapacitances(
int ACM,
int CALCACM,
int GEO,
double HDIF,
double WMLT,
double w,
double XW,
int drainAreaGiven,
double drainArea,
int drainPerimeterGiven,
double drainPerimeter,
int sourceAreaGiven,
double sourceArea,
int sourcePerimeterGiven,
double sourcePerimeter,
double CJ,
double CJSW,
double CJGATE,
double *areaDrainBulkCapacitance,
double *periDrainBulkCapacitance,
double *gateDrainBulkCapacitance,
double *areaSourceBulkCapacitance,
double *periSourceBulkCapacitance,
double *gateSourceBulkCapacitance
)
{
switch (ACM)
{
case 1:
drainArea = (w * WMLT + XW) * WMLT;
drainPerimeter = (w * WMLT + XW);
*areaDrainBulkCapacitance = drainArea * CJ;
*periDrainBulkCapacitance = drainPerimeter * CJSW;
*gateDrainBulkCapacitance = 0.0;
sourceArea = (w * WMLT + XW) * WMLT;
sourcePerimeter = (w * WMLT + XW);
*areaSourceBulkCapacitance = sourceArea * CJ;
*periSourceBulkCapacitance = sourcePerimeter * CJSW;
*gateSourceBulkCapacitance = 0.0;
break;
case 2:
if (!drainAreaGiven)
drainArea = 2.0 * (HDIF * WMLT) * (w * WMLT + XW);
else
drainArea = drainArea * WMLT * WMLT;
if (!drainPerimeterGiven)
drainPerimeter = 4.0 * (HDIF * WMLT) + 2.0 * (w * WMLT + XW);
else
drainPerimeter = drainPerimeter * WMLT;
*areaDrainBulkCapacitance = drainArea * CJ;
if (drainPerimeter > (w * WMLT + XW)) {
*periDrainBulkCapacitance = (drainPerimeter - (w * WMLT + XW)) * CJSW;
*gateDrainBulkCapacitance = (w * WMLT + XW) * CJGATE;
} else {
*periDrainBulkCapacitance = drainPerimeter * CJGATE;
*gateDrainBulkCapacitance = 0.0;
}
if (!sourceAreaGiven)
sourceArea = 2.0 * (HDIF * WMLT) * (w * WMLT + XW);
else
sourceArea = sourceArea * WMLT * WMLT;
if (!sourcePerimeterGiven)
sourcePerimeter = 4.0 * (HDIF * WMLT) + 2.0 * (w * WMLT + XW);
else
sourcePerimeter = sourcePerimeter * WMLT;
*areaSourceBulkCapacitance = sourceArea * CJ;
if (sourcePerimeter > (w * WMLT + XW)) {
*periSourceBulkCapacitance = (sourcePerimeter - (w * WMLT + XW)) * CJSW;
*gateSourceBulkCapacitance = (w * WMLT + XW) * CJGATE;
} else {
*periSourceBulkCapacitance = sourcePerimeter * CJGATE;
*gateSourceBulkCapacitance = 0.0;
}
break;
case 3:
if (!drainAreaGiven)
if ((GEO == 0) || (GEO == 2))
drainArea = 2.0 * (HDIF * WMLT) * (w * WMLT + XW);
else
drainArea = (HDIF * WMLT) * (w * WMLT + XW);
else
drainArea = drainArea * WMLT * WMLT;
if (!drainPerimeterGiven)
if ((GEO == 0) || (GEO == 2))
drainPerimeter = 4.0 * (HDIF * WMLT) + (w * WMLT + XW);
else
drainPerimeter = 2.0 * (HDIF * WMLT);
else
drainPerimeter = drainPerimeter * WMLT;
*areaDrainBulkCapacitance = drainArea * CJ;
*periDrainBulkCapacitance = drainPerimeter * CJSW ;
*gateDrainBulkCapacitance = (w * WMLT + XW) * CJGATE;
if (!sourceAreaGiven)
if ((GEO == 0) || (GEO == 1))
sourceArea = 2.0 * (HDIF * WMLT) * (w * WMLT + XW);
else
sourceArea = (HDIF * WMLT) * (w * WMLT + XW);
else
sourceArea = sourceArea * WMLT * WMLT;
if (!sourcePerimeterGiven)
if ((GEO == 0) || (GEO == 1))
sourcePerimeter = 4.0 * (HDIF * WMLT) + (w * WMLT + XW);
else
sourcePerimeter = 2.0 * (HDIF * WMLT);
else
sourcePerimeter = sourcePerimeter * WMLT;
*areaSourceBulkCapacitance = sourceArea * CJ;
*periSourceBulkCapacitance = sourcePerimeter * CJSW;
*gateSourceBulkCapacitance = (w * WMLT + XW) * CJGATE;
break;
case 11:
drainArea = (w * WMLT + XW) * WMLT;
drainPerimeter = (w * WMLT + XW);
*areaDrainBulkCapacitance = drainArea * CJ;
*periDrainBulkCapacitance = drainPerimeter * CJSW;
*gateDrainBulkCapacitance = 0.0;
sourceArea = (w * WMLT + XW) * WMLT;
sourcePerimeter = (w * WMLT + XW);
*areaSourceBulkCapacitance = sourceArea * CJ;
*periSourceBulkCapacitance = sourcePerimeter * CJSW;
*gateSourceBulkCapacitance = 0.0;
break;
case 12:
if (CALCACM == 1) {
if (!drainAreaGiven)
drainArea = 2.0 * (HDIF * WMLT) * (w * WMLT + XW);
else
drainArea = drainArea * WMLT * WMLT;
if (!drainPerimeterGiven)
drainPerimeter = 4.0 * (HDIF * WMLT) + 2.0 * (w * WMLT + XW);
else
drainPerimeter = drainPerimeter * WMLT;
}
*areaDrainBulkCapacitance = drainArea * CJ;
if (drainPerimeter > (w * WMLT + XW)) {
*periDrainBulkCapacitance = (drainPerimeter - (w * WMLT + XW)) * CJSW;
*gateDrainBulkCapacitance = (w * WMLT + XW) * CJGATE;
} else {
*periDrainBulkCapacitance = 0.0;
*gateDrainBulkCapacitance = drainPerimeter * CJGATE;
}
if (CALCACM == 1) {
if (!sourceAreaGiven)
sourceArea = 2.0 * (HDIF * WMLT) * (w * WMLT + XW);
else
sourceArea = sourceArea * WMLT * WMLT;
if (!sourcePerimeterGiven)
sourcePerimeter = 4.0 * (HDIF * WMLT) + 2.0 * (w * WMLT + XW);
else
sourcePerimeter = sourcePerimeter * WMLT;
}
*areaSourceBulkCapacitance = sourceArea * CJ;
if (sourcePerimeter > (w * WMLT + XW)) {
*periSourceBulkCapacitance = (sourcePerimeter - (w * WMLT + XW)) * CJSW;
*gateSourceBulkCapacitance = (w * WMLT + XW) * CJGATE;
} else {
*periSourceBulkCapacitance = 0.0;
*gateSourceBulkCapacitance = sourcePerimeter * CJGATE;
}
break;
case 13:
drainArea = drainArea * WMLT * WMLT;
drainPerimeter = drainPerimeter * WMLT;
*areaDrainBulkCapacitance = drainArea * CJ;
if (drainPerimeter > (w * WMLT + XW)) {
*periDrainBulkCapacitance = (drainPerimeter - (w * WMLT + XW)) * CJSW;
*gateDrainBulkCapacitance = (w * WMLT + XW) * CJGATE;
} else {
*periDrainBulkCapacitance = 0.0;
*gateDrainBulkCapacitance = drainPerimeter * CJGATE;
}
sourceArea = sourceArea * WMLT * WMLT;
sourcePerimeter = sourcePerimeter * WMLT;
*areaSourceBulkCapacitance = sourceArea * CJ;
if (sourcePerimeter > (w * WMLT + XW)) {
*periSourceBulkCapacitance = (sourcePerimeter - (w * WMLT + XW)) * CJSW;
*gateSourceBulkCapacitance = (w * WMLT + XW) * CJGATE;
} else {
*periSourceBulkCapacitance = 0.0;
*gateSourceBulkCapacitance = sourcePerimeter * CJGATE;
}
break;
default:
break;
}
return 0;
}
* terminal voltages
*
* PN 2002: As of ngspice this code is not used by any device.
*/
void
DEVcmeyer(double vgs0,
double vgd0,
double vgb0,
double von0,
double vdsat0,
double vgs1,
double vgd1,
double vgb1,
double covlgs,
double covlgd,
double covlgb,
double *cgs,
double *cgd,
double *cgb,
double phi,
double cox,
double von,
double vdsat)
{
double vdb;
double vdbsat;
double vddif;
double vddif1;
double vddif2;
double vgbt;
*cgs = 0;
*cgd = 0;
*cgb = 0;
vgbt = vgs1-von;
if (vgbt <= -phi) {
*cgb = cox;
} else if (vgbt <= -phi/2) {
*cgb = -vgbt*cox/phi;
} else if (vgbt <= 0) {
*cgb = -vgbt*cox/phi;
*cgs = cox/(7.5e-1*phi)*vgbt+cox/1.5;
} else {
vdbsat = vdsat-(vgs1-vgb1);
vdb = vgb1-vgd1;
if (vdbsat <= vdb) {
*cgs = cox/1.5;
} else {
vddif = 2.0*vdbsat-vdb;
vddif1 = vdbsat-vdb-1.0e-12;
vddif2 = vddif*vddif;
*cgd = cox*(1.0-vdbsat*vdbsat/vddif2)/1.5;
*cgs = cox*(1.0-vddif1*vddif1/vddif2)/1.5;
}
}
vgbt = vgs0-von0;
if (vgbt <= -phi) {
*cgb += cox;
} else if (vgbt <= -phi/2) {
*cgb += -vgbt*cox/phi;
} else if (vgbt <= 0) {
*cgb += -vgbt*cox/phi;
*cgs += cox/(7.5e-1*phi)*vgbt+cox/1.5;
} else {
vdbsat = vdsat0-(vgs0-vgb0);
vdb = vgb0-vgd0;
if (vdbsat <= vdb) {
*cgs += cox/1.5;
} else {
vddif = 2.0*vdbsat-vdb;
vddif1 = vdbsat-vdb-1.0e-12;
vddif2 = vddif*vddif;
*cgd += cox*(1.0-vdbsat*vdbsat/vddif2)/1.5;
*cgs += cox*(1.0-vddif1*vddif1/vddif2)/1.5;
}
}
*cgs = *cgs *.5 + covlgs;
*cgd = *cgd *.5 + covlgd;
*cgb = *cgb *.5 + covlgb;
}
http://ltwiki.org/index.php5?title=Undocumented_LTspice#VDMOS:_Breakdown_and_Sub-threshold_Enhancements
*/
void
DevCapVDMOS(double vgd, double cgdmin,
double cgdmax, double a, double cgs,
double *capgs, double *capgd)
{
double s = (cgdmax - cgdmin) / (1 + M_PI / 2);
double y = cgdmax - s;
if (vgd > 0)
*capgd = 0.5 * (s * tanh(a * vgd) + y);
else
*capgd = 0.5 * (s * atan(a * vgd) + y);
*capgs = 0.5 * cgs;
}
* terminal voltages
*
* PN 2002: This is the Meyer model used by MOS1 MOS2 MOS3 MOS6 and MOS9
* device models.
*/
void
DEVqmeyer(double vgs,
double vgd,
double vgb,
double von,
double vdsat,
double *capgs,
capacitance */
double *capgd,
capacitance */
double *capgb,
capacitance */
double phi,
double cox)
{
double vds;
double vddif;
double vddif1;
double vddif2;
double vgst;
NG_IGNORE(vgb);
#define MAGIC_VDS 0.025
vgst = vgs-von;
vdsat = MAX(vdsat, MAGIC_VDS);
if (vgst <= -phi) {
*capgb = cox/2;
*capgs = 0;
*capgd = 0;
} else if (vgst <= -phi/2) {
*capgb = -vgst*cox/(2*phi);
*capgs = 0;
*capgd = 0;
} else if (vgst <= 0) {
*capgb = -vgst*cox/(2*phi);
*capgs = vgst*cox/(1.5*phi)+cox/3;
vds = vgs-vgd;
if (vds>=vdsat) {
*capgd = 0;
} else {
vddif = 2.0*vdsat-vds;
vddif1 = vdsat-vds;
vddif2 = vddif*vddif;
*capgd = *capgs*(1.0-vdsat*vdsat/vddif2);
*capgs = *capgs*(1.0-vddif1*vddif1/vddif2);
}
} else {
vds = vgs-vgd;
vdsat = MAX(vdsat, MAGIC_VDS);
if (vdsat <= vds) {
*capgs = cox/3;
*capgd = 0;
*capgb = 0;
} else {
vddif = 2.0*vdsat-vds;
vddif1 = vdsat-vds;
vddif2 = vddif*vddif;
*capgd = cox*(1.0-vdsat*vdsat/vddif2)/3;
*capgs = cox*(1.0-vddif1*vddif1/vddif2)/3;
*capgb = 0;
}
}
}
#ifdef notdef
* PN 2002: This is industrial archaelology
*/
void
DEVcap(CKTcircuit *ckt, double vgd, double vgs, double vgb, double covlgd,
double covlgs, double covlgb, double capbd, double capbs, double cggb,
double cgdb, double cgsb, double cbgb, double cbdb, double cbsb,
double *gcggb, double *gcgdb, double *gcgsb, double *gcbgb,
double *gcbdb, double *gcbsb, double *gcdgb, double *gcddb,
double *gcdsb, double *gcsgb, double *gcsdb, double *gcssb,
double qgate, double qchan, double qbulk, double *qdrn, double *qsrc,
double xqc)
* compute equivalent conductances
* divide up the channel charge (1-xqc)/xqc to source and drain
*/
{
double gcd;
double gcdxd;
double gcdxs;
double gcg;
double gcgxd;
double gcgxs;
double gcs;
double gcsxd;
double gcsxs;
double qgb;
double qgd;
double qgs;
gcg = (cggb+cbgb)*ckt->CKTag[1];
gcd = (cgdb+cbdb)*ckt->CKTag[1];
gcs = (cgsb+cbsb)*ckt->CKTag[1];
gcgxd = -xqc*gcg;
gcgxs = -(1-xqc)*gcg;
gcdxd = -xqc*gcd;
gcdxs = -(1-xqc)*gcd;
gcsxd = -xqc*gcs;
gcsxs = -(1-xqc)*gcs;
*gcdgb = gcgxd-covlgd*ckt->CKTag[1];
*gcddb = gcdxd+(capbd+covlgd)*ckt->CKTag[1];
*gcdsb = gcsxd;
*gcsgb = gcgxs-covlgs*ckt->CKTag[1];
*gcsdb = gcdxs;
*gcssb = gcsxs+(capbs+covlgs)*ckt->CKTag[1];
*gcggb = (cggb+covlgd+covlgs+covlgb)*ckt->CKTag[1];
*gcgdb = (cgdb-covlgd)*ckt->CKTag[1];
*gcgsb = (cgsb-covlgs)*ckt->CKTag[1];
*gcbgb = (cbgb-covlgb)*ckt->CKTag[1];
*gcbdb = (cbdb-capbd)*ckt->CKTag[1];
*gcbsb = (cbsb-capbs)*ckt->CKTag[1];
* compute total terminal charges
*/
qgd = covlgd*vgd;
qgs = covlgs*vgs;
qgb = covlgb*vgb;
qgate = qgate+qgd+qgs+qgb;
qbulk = qbulk-qgb;
*qdrn = xqc*qchan-qgd;
*qsrc = (1-xqc)*qchan-qgs;
* finished
*/
}
#endif
* previous values */
double
DEVpred(CKTcircuit *ckt, int loct)
{
#ifndef NEWTRUNC
double xfact;
xfact = ckt->CKTdelta/ckt->CKTdeltaOld[1];
return( ( (1+xfact) * *(ckt->CKTstate1+loct) ) -
( xfact * *(ckt->CKTstate2+loct) ) );
#endif
}
extern FILE *slogp;
void
soa_printf(CKTcircuit *ckt, GENinstance *instance, const char *fmt, ...)
{
FILE *fp = slogp ? slogp : stdout;
va_list ap;
va_start(ap, fmt);
if (ckt->CKTmode & MODETRAN)
fprintf(fp, "Instance: %s Model: %s Time: %g ",
instance->GENname, instance->GENmodPtr->GENmodName, ckt->CKTtime);
else
fprintf(fp, "Instance: %s Model: %s ",
instance->GENname, instance->GENmodPtr->GENmodName);
vfprintf(fp, fmt, ap);
va_end(ap);
}