Exemplo n.º 1
0
int
B1load(GENmodel *inModel, CKTcircuit *ckt)

        /* actually load the current value into the 
         * sparse matrix previously provided 
         */
{
    B1model *model = (B1model*)inModel;
    B1instance *here;
    double DrainSatCurrent = 0.0;
    double EffectiveLength = 0.0;
    double GateBulkOverlapCap = 0.0;
    double GateDrainOverlapCap = 0.0;
    double GateSourceOverlapCap = 0.0;
    double SourceSatCurrent = 0.0;
    double DrainArea = 0.0;
    double SourceArea = 0.0;
    double DrainPerimeter = 0.0;
    double SourcePerimeter = 0.0;
    double arg = 0.0;
    double capbd = 0.0;
    double capbs = 0.0;
    double cbd = 0.0;
    double cbhat = 0.0;
    double cbs = 0.0;
    double cd = 0.0;
    double cdrain = 0.0;
    double cdhat = 0.0;
    double cdreq = 0.0;
    double ceq = 0.0;
    double ceqbd = 0.0;
    double ceqbs = 0.0;
    double ceqqb = 0.0;
    double ceqqd = 0.0;
    double ceqqg = 0.0;
    double czbd = 0.0;
    double czbdsw = 0.0;
    double czbs = 0.0;
    double czbssw = 0.0;
    double delvbd = 0.0;
    double delvbs = 0.0;
    double delvds = 0.0;
    double delvgd = 0.0;
    double delvgs = 0.0;
    double evbd = 0.0;
    double evbs = 0.0;
    double gbd = 0.0;
    double gbs = 0.0;
    double gcbdb = 0.0;
    double gcbgb = 0.0;
    double gcbsb = 0.0;
    double gcddb = 0.0;
    double gcdgb = 0.0;
    double gcdsb = 0.0;
    double gcgdb = 0.0;
    double gcggb = 0.0;
    double gcgsb = 0.0;
    double gcsdb = 0.0;
    double gcsgb = 0.0;
    double gcssb = 0.0;
    double gds = 0.0;
    double geq = 0.0;
    double gm = 0.0;
    double gmbs = 0.0;
    double sarg = 0.0;
    double sargsw = 0.0;
    double vbd = 0.0;
    double vbs = 0.0;
    double vcrit = 0.0;
    double vds = 0.0;
    double vdsat = 0.0;
    double vgb = 0.0;
    double vgd = 0.0;
    double vgdo = 0.0;
    double vgs = 0.0;
    double von = 0.0;
    double xfact = 0.0;
    double xnrm = 0.0;
    double xrev = 0.0;
    int Check = 0;
    double cgdb = 0.0;
    double cgsb = 0.0;
    double cbdb = 0.0;
    double cdgb = 0.0;
    double cddb = 0.0;
    double cdsb = 0.0;
    double cggb = 0.0;
    double cbgb = 0.0;
    double cbsb = 0.0;
    double csgb = 0.0;
    double cssb = 0.0;
    double csdb = 0.0;
    double PhiB = 0.0;
    double PhiBSW = 0.0;
    double MJ = 0.0;
    double MJSW = 0.0;
    double argsw = 0.0;
    double qgate = 0.0;
    double qbulk = 0.0;
    double qdrn = 0.0;
    double qsrc = 0.0;
    double cqgate = 0.0;
    double cqbulk = 0.0;
    double cqdrn = 0.0;
    double vt0 = 0.0;
    double args[8];
    int    ByPass = 0;
#ifndef NOBYPASS
    double tempv = 0.0;
#endif /*NOBYPASS*/
    int error = 0;

    double m; /* parallel multiplier */

    /*  loop through all the B1 device models */
    for( ; model != NULL; model = model->B1nextModel ) {

        /* loop through all the instances of the model */
        for (here = model->B1instances; here != NULL ;
                here=here->B1nextInstance) {
	    if (here->B1owner != ARCHme) continue;
        
            EffectiveLength=here->B1l - model->B1deltaL * 1.e-6;/* m */
            DrainArea = here->B1drainArea;
            SourceArea = here->B1sourceArea;
            DrainPerimeter = here->B1drainPerimeter;
            SourcePerimeter = here->B1sourcePerimeter;
            if( (DrainSatCurrent=DrainArea*model->B1jctSatCurDensity) 
                    < 1e-15){
                DrainSatCurrent = 1.0e-15;
            }
            if( (SourceSatCurrent=SourceArea*model->B1jctSatCurDensity)
                    <1.0e-15){
                SourceSatCurrent = 1.0e-15;
            }
            GateSourceOverlapCap = model->B1gateSourceOverlapCap *here->B1w;
            GateDrainOverlapCap = model->B1gateDrainOverlapCap * here->B1w;
            GateBulkOverlapCap = model->B1gateBulkOverlapCap *EffectiveLength;
            von = model->B1type * here->B1von;
            vdsat = model->B1type * here->B1vdsat;
            vt0 = model->B1type * here->B1vt0;

            Check=1;
            ByPass = 0;
            if((ckt->CKTmode & MODEINITSMSIG)) {
                vbs= *(ckt->CKTstate0 + here->B1vbs);
                vgs= *(ckt->CKTstate0 + here->B1vgs);
                vds= *(ckt->CKTstate0 + here->B1vds);
            } else if ((ckt->CKTmode & MODEINITTRAN)) {
                vbs= *(ckt->CKTstate1 + here->B1vbs);
                vgs= *(ckt->CKTstate1 + here->B1vgs);
                vds= *(ckt->CKTstate1 + here->B1vds);
            } else if((ckt->CKTmode & MODEINITJCT) && !here->B1off) {
                vds= model->B1type * here->B1icVDS;
                vgs= model->B1type * here->B1icVGS;
                vbs= model->B1type * here->B1icVBS;
                if((vds==0) && (vgs==0) && (vbs==0) && 
                        ((ckt->CKTmode & 
                        (MODETRAN|MODEAC|MODEDCOP|MODEDCTRANCURVE)) ||
                        (!(ckt->CKTmode & MODEUIC)))) {
                    vbs = -1;
                    vgs = vt0;
                    vds = 0;
                }
            } else if((ckt->CKTmode & (MODEINITJCT | MODEINITFIX) ) && 
                    (here->B1off)) {
                vbs=vgs=vds=0;
            } else {
#ifndef PREDICTOR
                if((ckt->CKTmode & MODEINITPRED)) {
                    xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1];
                    *(ckt->CKTstate0 + here->B1vbs) = 
                            *(ckt->CKTstate1 + here->B1vbs);
                    vbs = (1+xfact)* (*(ckt->CKTstate1 + here->B1vbs))
                            -(xfact * (*(ckt->CKTstate2 + here->B1vbs)));
                    *(ckt->CKTstate0 + here->B1vgs) = 
                            *(ckt->CKTstate1 + here->B1vgs);
                    vgs = (1+xfact)* (*(ckt->CKTstate1 + here->B1vgs))
                            -(xfact * (*(ckt->CKTstate2 + here->B1vgs)));
                    *(ckt->CKTstate0 + here->B1vds) = 
                            *(ckt->CKTstate1 + here->B1vds);
                    vds = (1+xfact)* (*(ckt->CKTstate1 + here->B1vds))
                            -(xfact * (*(ckt->CKTstate2 + here->B1vds)));
                    *(ckt->CKTstate0 + here->B1vbd) = 
                            *(ckt->CKTstate0 + here->B1vbs)-
                            *(ckt->CKTstate0 + here->B1vds);
                    *(ckt->CKTstate0 + here->B1cd) = 
                            *(ckt->CKTstate1 + here->B1cd);
                    *(ckt->CKTstate0 + here->B1cbs) = 
                            *(ckt->CKTstate1 + here->B1cbs);
                    *(ckt->CKTstate0 + here->B1cbd) = 
                            *(ckt->CKTstate1 + here->B1cbd);
                    *(ckt->CKTstate0 + here->B1gm) = 
                            *(ckt->CKTstate1 + here->B1gm);
                    *(ckt->CKTstate0 + here->B1gds) = 
                            *(ckt->CKTstate1 + here->B1gds);
                    *(ckt->CKTstate0 + here->B1gmbs) = 
                            *(ckt->CKTstate1 + here->B1gmbs);
                    *(ckt->CKTstate0 + here->B1gbd) = 
                            *(ckt->CKTstate1 + here->B1gbd);
                    *(ckt->CKTstate0 + here->B1gbs) = 
                            *(ckt->CKTstate1 + here->B1gbs);
                    *(ckt->CKTstate0 + here->B1cggb) = 
                            *(ckt->CKTstate1 + here->B1cggb);
                    *(ckt->CKTstate0 + here->B1cbgb) = 
                            *(ckt->CKTstate1 + here->B1cbgb);
                    *(ckt->CKTstate0 + here->B1cbsb) = 
                            *(ckt->CKTstate1 + here->B1cbsb);
                    *(ckt->CKTstate0 + here->B1cgdb) = 
                            *(ckt->CKTstate1 + here->B1cgdb);
                    *(ckt->CKTstate0 + here->B1cgsb) = 
                            *(ckt->CKTstate1 + here->B1cgsb);
                    *(ckt->CKTstate0 + here->B1cbdb) = 
                            *(ckt->CKTstate1 + here->B1cbdb);
                    *(ckt->CKTstate0 + here->B1cdgb) = 
                            *(ckt->CKTstate1 + here->B1cdgb);
                    *(ckt->CKTstate0 + here->B1cddb) = 
                            *(ckt->CKTstate1 + here->B1cddb);
                    *(ckt->CKTstate0 + here->B1cdsb) = 
                            *(ckt->CKTstate1 + here->B1cdsb);
                } else {
#endif /* PREDICTOR */
                    vbs = model->B1type * ( 
                        *(ckt->CKTrhsOld+here->B1bNode) -
                        *(ckt->CKTrhsOld+here->B1sNodePrime));
                    vgs = model->B1type * ( 
                        *(ckt->CKTrhsOld+here->B1gNode) -
                        *(ckt->CKTrhsOld+here->B1sNodePrime));
                    vds = model->B1type * ( 
                        *(ckt->CKTrhsOld+here->B1dNodePrime) -
                        *(ckt->CKTrhsOld+here->B1sNodePrime));
#ifndef PREDICTOR
                }
#endif /* PREDICTOR */
                vbd=vbs-vds;
                vgd=vgs-vds;
                vgdo = *(ckt->CKTstate0 + here->B1vgs) - 
                    *(ckt->CKTstate0 + here->B1vds);
                delvbs = vbs - *(ckt->CKTstate0 + here->B1vbs);
                delvbd = vbd - *(ckt->CKTstate0 + here->B1vbd);
                delvgs = vgs - *(ckt->CKTstate0 + here->B1vgs);
                delvds = vds - *(ckt->CKTstate0 + here->B1vds);
                delvgd = vgd-vgdo;

                if (here->B1mode >= 0) {
                    cdhat=
                        *(ckt->CKTstate0 + here->B1cd) -
                        *(ckt->CKTstate0 + here->B1gbd) * delvbd +
                        *(ckt->CKTstate0 + here->B1gmbs) * delvbs +
                        *(ckt->CKTstate0 + here->B1gm) * delvgs + 
                        *(ckt->CKTstate0 + here->B1gds) * delvds ;
                } else {
                    cdhat=
                        *(ckt->CKTstate0 + here->B1cd) -
                        ( *(ckt->CKTstate0 + here->B1gbd) -
                          *(ckt->CKTstate0 + here->B1gmbs)) * delvbd -
                        *(ckt->CKTstate0 + here->B1gm) * delvgd +
                        *(ckt->CKTstate0 + here->B1gds) * delvds;
                }
                cbhat=
                    *(ckt->CKTstate0 + here->B1cbs) +
                    *(ckt->CKTstate0 + here->B1cbd) +
                    *(ckt->CKTstate0 + here->B1gbd) * delvbd +
                    *(ckt->CKTstate0 + here->B1gbs) * delvbs ;

#ifndef NOBYPASS
                    /* now lets see if we can bypass (ugh) */

                /* following should be one big if connected by && all over
                 * the place, but some C compilers can't handle that, so
                 * we split it up here to let them digest it in stages
                 */
                tempv = MAX(fabs(cbhat),fabs(*(ckt->CKTstate0 + here->B1cbs)
                        + *(ckt->CKTstate0 + here->B1cbd)))+ckt->CKTabstol;
                if((!(ckt->CKTmode & MODEINITPRED)) && (ckt->CKTbypass) )
                if( (fabs(delvbs) < (ckt->CKTreltol * MAX(fabs(vbs),
                        fabs(*(ckt->CKTstate0+here->B1vbs)))+
                        ckt->CKTvoltTol)) )
                if ( (fabs(delvbd) < (ckt->CKTreltol * MAX(fabs(vbd),
                        fabs(*(ckt->CKTstate0+here->B1vbd)))+
                        ckt->CKTvoltTol)) )
                if( (fabs(delvgs) < (ckt->CKTreltol * MAX(fabs(vgs),
                        fabs(*(ckt->CKTstate0+here->B1vgs)))+
                        ckt->CKTvoltTol)))
                if ( (fabs(delvds) < (ckt->CKTreltol * MAX(fabs(vds),
                        fabs(*(ckt->CKTstate0+here->B1vds)))+
                        ckt->CKTvoltTol)) )
                if( (fabs(cdhat- *(ckt->CKTstate0 + here->B1cd)) <
                        ckt->CKTreltol * MAX(fabs(cdhat),fabs(*(ckt->CKTstate0 +
                        here->B1cd))) + ckt->CKTabstol) )
                if ( (fabs(cbhat-(*(ckt->CKTstate0 + here->B1cbs) +
                        *(ckt->CKTstate0 + here->B1cbd))) < ckt->CKTreltol *
                        tempv)) {
                    /* bypass code */
                    vbs = *(ckt->CKTstate0 + here->B1vbs);
                    vbd = *(ckt->CKTstate0 + here->B1vbd);
                    vgs = *(ckt->CKTstate0 + here->B1vgs);
                    vds = *(ckt->CKTstate0 + here->B1vds);
                    vgd = vgs - vds;
                    vgb = vgs - vbs;
                    cd = *(ckt->CKTstate0 + here->B1cd);
                    cbs = *(ckt->CKTstate0 + here->B1cbs);
                    cbd = *(ckt->CKTstate0 + here->B1cbd);
                    cdrain = here->B1mode * (cd + cbd);
                    gm = *(ckt->CKTstate0 + here->B1gm);
                    gds = *(ckt->CKTstate0 + here->B1gds);
                    gmbs = *(ckt->CKTstate0 + here->B1gmbs);
                    gbd = *(ckt->CKTstate0 + here->B1gbd);
                    gbs = *(ckt->CKTstate0 + here->B1gbs);
                    if((ckt->CKTmode & (MODETRAN | MODEAC)) || 
                            ((ckt->CKTmode & MODETRANOP) && 
                            (ckt->CKTmode & MODEUIC))) {
                        cggb = *(ckt->CKTstate0 + here->B1cggb);
                        cgdb = *(ckt->CKTstate0 + here->B1cgdb);
                        cgsb = *(ckt->CKTstate0 + here->B1cgsb);
                        cbgb = *(ckt->CKTstate0 + here->B1cbgb);
                        cbdb = *(ckt->CKTstate0 + here->B1cbdb);
                        cbsb = *(ckt->CKTstate0 + here->B1cbsb);
                        cdgb = *(ckt->CKTstate0 + here->B1cdgb);
                        cddb = *(ckt->CKTstate0 + here->B1cddb);
                        cdsb = *(ckt->CKTstate0 + here->B1cdsb);
                        capbs = *(ckt->CKTstate0 + here->B1capbs);
                        capbd = *(ckt->CKTstate0 + here->B1capbd);
                        ByPass = 1;
                        goto line755;
                    } else {
                        goto line850;
                    }
                }
#endif /*NOBYPASS*/

                von = model->B1type * here->B1von;
                if(*(ckt->CKTstate0 + here->B1vds) >=0) {
                    vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->B1vgs)
                            ,von);
                    vds = vgs - vgd;
                    vds = DEVlimvds(vds,*(ckt->CKTstate0 + here->B1vds));
                    vgd = vgs - vds;
                } else {
                    vgd = DEVfetlim(vgd,vgdo,von);
                    vds = vgs - vgd;
                    vds = -DEVlimvds(-vds,-(*(ckt->CKTstate0 + here->B1vds)));
                    vgs = vgd + vds;
                }
                if(vds >= 0) {
                    vcrit =CONSTvt0*log(CONSTvt0/(CONSTroot2*SourceSatCurrent));
                    vbs = DEVpnjlim(vbs,*(ckt->CKTstate0 + here->B1vbs),
                            CONSTvt0,vcrit,&Check); /* B1 test */
                    vbd = vbs-vds;
                } else {
                    vcrit = CONSTvt0*log(CONSTvt0/(CONSTroot2*DrainSatCurrent));
                    vbd = DEVpnjlim(vbd,*(ckt->CKTstate0 + here->B1vbd),
                            CONSTvt0,vcrit,&Check); /* B1 test*/
                    vbs = vbd + vds;
                }
            } 

             /* determine DC current and derivatives */
            vbd = vbs - vds;
            vgd = vgs - vds;
            vgb = vgs - vbs;


            if(vbs <= 0.0 ) {
                gbs = SourceSatCurrent / CONSTvt0 + ckt->CKTgmin;
                cbs = gbs * vbs ;
            } else {
                evbs = exp(vbs/CONSTvt0);
                gbs = SourceSatCurrent*evbs/CONSTvt0 + ckt->CKTgmin;
                cbs = SourceSatCurrent * (evbs-1) + ckt->CKTgmin * vbs ;
            }
            if(vbd <= 0.0) {
                gbd = DrainSatCurrent / CONSTvt0 + ckt->CKTgmin;
                cbd = gbd * vbd ;
            } else {
                evbd = exp(vbd/CONSTvt0);
                gbd = DrainSatCurrent*evbd/CONSTvt0 +ckt->CKTgmin;
                cbd = DrainSatCurrent *(evbd-1)+ckt->CKTgmin*vbd;
            }
            /* line 400 */
            if(vds >= 0) {
                /* normal mode */
                here->B1mode = 1;
            } else {
                /* inverse mode */
                here->B1mode = -1;
            }
            /* call B1evaluate to calculate drain current and its 
             * derivatives and charge and capacitances related to gate
             * drain, and bulk
             */
           if( vds >= 0 )  {
                B1evaluate(vds,vbs,vgs,here,model,&gm,&gds,&gmbs,&qgate,
                    &qbulk,&qdrn,&cggb,&cgdb,&cgsb,&cbgb,&cbdb,&cbsb,&cdgb,
                    &cddb,&cdsb,&cdrain,&von,&vdsat,ckt);
            } else {
                B1evaluate(-vds,vbd,vgd,here,model,&gm,&gds,&gmbs,&qgate,
                    &qbulk,&qsrc,&cggb,&cgsb,&cgdb,&cbgb,&cbsb,&cbdb,&csgb,
                    &cssb,&csdb,&cdrain,&von,&vdsat,ckt);
            }
          
            here->B1von = model->B1type * von;
            here->B1vdsat = model->B1type * vdsat;  

        

            /*
             *  COMPUTE EQUIVALENT DRAIN CURRENT SOURCE
             */
            cd=here->B1mode * cdrain - cbd;
            if ((ckt->CKTmode & (MODETRAN | MODEAC | MODEINITSMSIG)) ||
                    ((ckt->CKTmode & MODETRANOP ) && 
                    (ckt->CKTmode & MODEUIC))) {
                /*
                 *  charge storage elements
                 *
                 *   bulk-drain and bulk-source depletion capacitances
                 *  czbd : zero bias drain junction capacitance
                 *  czbs : zero bias source junction capacitance
                 * czbdsw:zero bias drain junction sidewall capacitance
                 * czbssw:zero bias source junction sidewall capacitance
                 */

                czbd  = model->B1unitAreaJctCap * DrainArea;
                czbs  = model->B1unitAreaJctCap * SourceArea;
                czbdsw= model->B1unitLengthSidewallJctCap * DrainPerimeter;
                czbssw= model->B1unitLengthSidewallJctCap * SourcePerimeter;
                PhiB = model->B1bulkJctPotential;
                PhiBSW = model->B1sidewallJctPotential;
                MJ = model->B1bulkJctBotGradingCoeff;
                MJSW = model->B1bulkJctSideGradingCoeff;

                /* Source Bulk Junction */
                if( vbs < 0 ) {  
                    arg = 1 - vbs / PhiB;
                    argsw = 1 - vbs / PhiBSW;
                    sarg = exp(-MJ*log(arg));
                    sargsw = exp(-MJSW*log(argsw));
                    *(ckt->CKTstate0 + here->B1qbs) =
                        PhiB * czbs * (1-arg*sarg)/(1-MJ) + PhiBSW * 
                    czbssw * (1-argsw*sargsw)/(1-MJSW);
                    capbs = czbs * sarg + czbssw * sargsw ;
                } else {  
                    *(ckt->CKTstate0+here->B1qbs) =
                        vbs*(czbs+czbssw)+ vbs*vbs*(czbs*MJ*0.5/PhiB 
                        + czbssw * MJSW * 0.5/PhiBSW);
                    capbs = czbs + czbssw + vbs *(czbs*MJ/PhiB+
                        czbssw * MJSW / PhiBSW );
                }

                /* Drain Bulk Junction */
                if( vbd < 0 ) {  
                    arg = 1 - vbd / PhiB;
                    argsw = 1 - vbd / PhiBSW;
                    sarg = exp(-MJ*log(arg));
                    sargsw = exp(-MJSW*log(argsw));
                    *(ckt->CKTstate0 + here->B1qbd) =
                        PhiB * czbd * (1-arg*sarg)/(1-MJ) + PhiBSW * 
                    czbdsw * (1-argsw*sargsw)/(1-MJSW);
                    capbd = czbd * sarg + czbdsw * sargsw ;
                } else {  
                    *(ckt->CKTstate0+here->B1qbd) =
                        vbd*(czbd+czbdsw)+ vbd*vbd*(czbd*MJ*0.5/PhiB 
                        + czbdsw * MJSW * 0.5/PhiBSW);
                    capbd = czbd + czbdsw + vbd *(czbd*MJ/PhiB+
                        czbdsw * MJSW / PhiBSW );
                }

            }




            /*
             *  check convergence
             */
            if ( (here->B1off == 0)  || (!(ckt->CKTmode & MODEINITFIX)) ){
                if (Check == 1) {
                    ckt->CKTnoncon++;
		    ckt->CKTtroubleElt = (GENinstance *) here;
                }
            }
            *(ckt->CKTstate0 + here->B1vbs) = vbs;
            *(ckt->CKTstate0 + here->B1vbd) = vbd;
            *(ckt->CKTstate0 + here->B1vgs) = vgs;
            *(ckt->CKTstate0 + here->B1vds) = vds;
            *(ckt->CKTstate0 + here->B1cd) = cd;
            *(ckt->CKTstate0 + here->B1cbs) = cbs;
            *(ckt->CKTstate0 + here->B1cbd) = cbd;
            *(ckt->CKTstate0 + here->B1gm) = gm;
            *(ckt->CKTstate0 + here->B1gds) = gds;
            *(ckt->CKTstate0 + here->B1gmbs) = gmbs;
            *(ckt->CKTstate0 + here->B1gbd) = gbd;
            *(ckt->CKTstate0 + here->B1gbs) = gbs;

            *(ckt->CKTstate0 + here->B1cggb) = cggb;
            *(ckt->CKTstate0 + here->B1cgdb) = cgdb;
            *(ckt->CKTstate0 + here->B1cgsb) = cgsb;

            *(ckt->CKTstate0 + here->B1cbgb) = cbgb;
            *(ckt->CKTstate0 + here->B1cbdb) = cbdb;
            *(ckt->CKTstate0 + here->B1cbsb) = cbsb;

            *(ckt->CKTstate0 + here->B1cdgb) = cdgb;
            *(ckt->CKTstate0 + here->B1cddb) = cddb;
            *(ckt->CKTstate0 + here->B1cdsb) = cdsb;

            *(ckt->CKTstate0 + here->B1capbs) = capbs;
            *(ckt->CKTstate0 + here->B1capbd) = capbd;

           /* bulk and channel charge plus overlaps */

            if((!(ckt->CKTmode & (MODETRAN | MODEAC))) &&
                    ((!(ckt->CKTmode & MODETRANOP)) ||
                    (!(ckt->CKTmode & MODEUIC)))  && (!(ckt->CKTmode 
                    &  MODEINITSMSIG))) goto line850; 
         
line755:
            if( here->B1mode > 0 ) {

		args[0] = GateDrainOverlapCap;
		args[1] = GateSourceOverlapCap;
		args[2] = GateBulkOverlapCap;
		args[3] = capbd;
		args[4] = capbs;
		args[5] = cggb;
		args[6] = cgdb;
		args[7] = cgsb;

                B1mosCap(ckt,vgd,vgs,vgb,
			args,
			/*
			GateDrainOverlapCap,
			GateSourceOverlapCap,GateBulkOverlapCap,
			capbd,capbs,
                        cggb,cgdb,cgsb,
			*/
			cbgb,cbdb,cbsb,
			cdgb,cddb,cdsb,
                        &gcggb,&gcgdb,&gcgsb,
			&gcbgb,&gcbdb,&gcbsb,
			&gcdgb,&gcddb,&gcdsb,&gcsgb,&gcsdb,&gcssb,
			&qgate,&qbulk,
                        &qdrn,&qsrc);
            } else {

		args[0] = GateSourceOverlapCap;
		args[1] = GateDrainOverlapCap;
		args[2] = GateBulkOverlapCap;
		args[3] = capbs;
		args[4] = capbd;
		args[5] = cggb;
		args[6] = cgsb;
		args[7] = cgdb;

                B1mosCap(ckt,vgs,vgd,vgb,
			args,
			/*
			GateSourceOverlapCap,
			GateDrainOverlapCap,GateBulkOverlapCap,
			capbs,capbd,
			cggb,cgsb,cgdb,
			*/
			cbgb,cbsb,cbdb,
			csgb,cssb,csdb,
			&gcggb,&gcgsb,&gcgdb,
			&gcbgb,&gcbsb,&gcbdb,
			&gcsgb,&gcssb,&gcsdb,&gcdgb,&gcdsb,&gcddb,
			&qgate,&qbulk,
			&qsrc,&qdrn);
            }
             
            if(ByPass) goto line860;
            *(ckt->CKTstate0 + here->B1qg) = qgate;
            *(ckt->CKTstate0 + here->B1qd) = qdrn -  
                    *(ckt->CKTstate0 + here->B1qbd);
            *(ckt->CKTstate0 + here->B1qb) = qbulk +  
                    *(ckt->CKTstate0 + here->B1qbd) +  
                    *(ckt->CKTstate0 + here->B1qbs); 

            /* store small signal parameters */
            if((!(ckt->CKTmode & (MODEAC | MODETRAN))) &&
                    (ckt->CKTmode & MODETRANOP ) && (ckt->CKTmode &
                    MODEUIC ))   goto line850;
            if(ckt->CKTmode & MODEINITSMSIG ) {  
                *(ckt->CKTstate0+here->B1cggb) = cggb;
                *(ckt->CKTstate0+here->B1cgdb) = cgdb;
                *(ckt->CKTstate0+here->B1cgsb) = cgsb;
                *(ckt->CKTstate0+here->B1cbgb) = cbgb;
                *(ckt->CKTstate0+here->B1cbdb) = cbdb;
                *(ckt->CKTstate0+here->B1cbsb) = cbsb;
                *(ckt->CKTstate0+here->B1cdgb) = cdgb;
                *(ckt->CKTstate0+here->B1cddb) = cddb;
                *(ckt->CKTstate0+here->B1cdsb) = cdsb;     
                *(ckt->CKTstate0+here->B1capbd) = capbd;
                *(ckt->CKTstate0+here->B1capbs) = capbs;

                goto line1000;
            }
       
            if(ckt->CKTmode & MODEINITTRAN ) { 
                *(ckt->CKTstate1+here->B1qb) =
                    *(ckt->CKTstate0+here->B1qb) ;
                *(ckt->CKTstate1+here->B1qg) =
                    *(ckt->CKTstate0+here->B1qg) ;
                *(ckt->CKTstate1+here->B1qd) =
                    *(ckt->CKTstate0+here->B1qd) ;
            }
       
       
            error = NIintegrate(ckt,&geq,&ceq,0.0,here->B1qb);
            if(error) return(error);
            error = NIintegrate(ckt,&geq,&ceq,0.0,here->B1qg);
            if(error) return(error);
            error = NIintegrate(ckt,&geq,&ceq,0.0,here->B1qd);
            if(error) return(error);
      
            goto line860;

line850:
            /* initialize to zero charge conductance and current */
            ceqqg = ceqqb = ceqqd = 0.0;
            gcdgb = gcddb = gcdsb = 0.0;
            gcsgb = gcsdb = gcssb = 0.0;
            gcggb = gcgdb = gcgsb = 0.0;
            gcbgb = gcbdb = gcbsb = 0.0;
            goto line900;
            
line860:
            /* evaluate equivalent charge current */
            cqgate = *(ckt->CKTstate0 + here->B1iqg);
            cqbulk = *(ckt->CKTstate0 + here->B1iqb);
            cqdrn = *(ckt->CKTstate0 + here->B1iqd);
            ceqqg = cqgate - gcggb * vgb + gcgdb * vbd + gcgsb * vbs;
            ceqqb = cqbulk - gcbgb * vgb + gcbdb * vbd + gcbsb * vbs;
            ceqqd = cqdrn - gcdgb * vgb + gcddb * vbd + gcdsb * vbs;

            if(ckt->CKTmode & MODEINITTRAN ) {  
                *(ckt->CKTstate1 + here->B1iqb) =  
                    *(ckt->CKTstate0 + here->B1iqb);
                *(ckt->CKTstate1 + here->B1iqg) =  
                    *(ckt->CKTstate0 + here->B1iqg);
                *(ckt->CKTstate1 + here->B1iqd) =  
                    *(ckt->CKTstate0 + here->B1iqd);
            }

            /*
             *  load current vector
             */
line900:
            m = here->B1m;

            ceqbs = model->B1type * (cbs-(gbs-ckt->CKTgmin)*vbs);
            ceqbd = model->B1type * (cbd-(gbd-ckt->CKTgmin)*vbd);
     
            ceqqg = model->B1type * ceqqg;
            ceqqb = model->B1type * ceqqb;
            ceqqd =  model->B1type * ceqqd;
            if (here->B1mode >= 0) {
                xnrm=1;
                xrev=0;
                cdreq=model->B1type*(cdrain-gds*vds-gm*vgs-gmbs*vbs);
            } else {
                xnrm=0;
                xrev=1;
                cdreq = -(model->B1type)*(cdrain+gds*vds-gm*vgd-gmbs*vbd);
            }

            *(ckt->CKTrhs + here->B1gNode) -= m * ceqqg;
            *(ckt->CKTrhs + here->B1bNode) -= m * (ceqbs+ceqbd+ceqqb);
            *(ckt->CKTrhs + here->B1dNodePrime) +=
                    m * (ceqbd-cdreq-ceqqd);
            *(ckt->CKTrhs + here->B1sNodePrime) += 
                   m * (cdreq+ceqbs+ceqqg+ceqqb+ceqqd);

            /*
             *  load y matrix
             */

            *(here->B1DdPtr) += m * (here->B1drainConductance);
            *(here->B1GgPtr) += m * (gcggb);
            *(here->B1SsPtr) += m * (here->B1sourceConductance);
            *(here->B1BbPtr) += m * (gbd+gbs-gcbgb-gcbdb-gcbsb);
            *(here->B1DPdpPtr) += 
                 m * (here->B1drainConductance+gds+gbd+xrev*(gm+gmbs)+gcddb);
            *(here->B1SPspPtr) += 
                m * (here->B1sourceConductance+gds+gbs+xnrm*(gm+gmbs)+gcssb);
            *(here->B1DdpPtr) += m * (-here->B1drainConductance);
            *(here->B1GbPtr) += m * (-gcggb-gcgdb-gcgsb);
            *(here->B1GdpPtr) += m * (gcgdb);
            *(here->B1GspPtr) += m * (gcgsb);
            *(here->B1SspPtr) += m * (-here->B1sourceConductance);
            *(here->B1BgPtr) += m * (gcbgb);
            *(here->B1BdpPtr) += m * (-gbd+gcbdb);
            *(here->B1BspPtr) += m * (-gbs+gcbsb);
            *(here->B1DPdPtr) += m * (-here->B1drainConductance);
            *(here->B1DPgPtr) += m * ((xnrm-xrev)*gm+gcdgb);
            *(here->B1DPbPtr) += m * (-gbd+(xnrm-xrev)*gmbs-gcdgb-gcddb-gcdsb);
            *(here->B1DPspPtr) += m * (-gds-xnrm*(gm+gmbs)+gcdsb);
            *(here->B1SPgPtr) += m * (-(xnrm-xrev)*gm+gcsgb);
            *(here->B1SPsPtr) += m * (-here->B1sourceConductance);
            *(here->B1SPbPtr) += m * (-gbs-(xnrm-xrev)*gmbs-gcsgb-gcsdb-gcssb);
            *(here->B1SPdpPtr) += m * (-gds-xrev*(gm+gmbs)+gcsdb);


line1000:  ;

        }   /* End of Mosfet Instance */

    }       /* End of Model Instance */
    return(OK);
}
Exemplo n.º 2
0
int
BJTload(GENmodel *inModel, CKTcircuit *ckt)
        /* actually load the current resistance value into the 
      * sparse matrix previously provided 
      */
{
    BJTmodel *model = (BJTmodel*)inModel;
    BJTinstance *here;
    double arg1;
    double arg2;
    double arg3;
    double arg;
    double argtf;
    double c2;
    double c4;
    double capbc;
    double capbe;
    double capbx=0;
    double capcs=0;
    double cb;
    double cbc;
    double cbcn;
    double cbe;
    double cben;
    double cbhat;
    double cc;
    double cchat;
    double cdis;
    double ceq;
    double ceqbc;
    double ceqbe;
    double ceqbx;
    double ceqcs;
    double cex;
    double csat;
    double ctot;
    double czbc;
    double czbcf2;
    double czbe;
    double czbef2;
    double czbx;
    double czbxf2;
    double czcs;
    double delvbc;
    double delvbe;
    double denom;
    double dqbdvc;
    double dqbdve;
    double evbc;
    double evbcn;
    double evbe;
    double evben;
    double f1;
    double f2;
    double f3;
    double fcpc;
    double fcpe;
    double gbc;
    double gbcn;
    double gbe;
    double gben;
    double gccs;
    double gcpr;
    double gepr;
    double geq;
    double geqbx;
    double geqcb;
    double gex;
    double gm;
    double gmu;
    double go;
    double gpi;
    double gx;
    double oik;
    double oikr;
    double ovtf;
    double pc;
    double pe;
    double ps;
    double q1;
    double q2;
    double qb;
    double rbpi;
    double rbpr;
    double sarg;
    double sqarg;
    double td;
    double temp;
    double tf;
    double tr;
    double vbc;
    double vbe;
    double vbx=0;
    double vce;
    double vcs=0;
    double vt;
    double vtc;
    double vte;
    double vtn;
    double xfact;
    double xjrb;
    double xjtf;
    double xmc;
    double xme;
    double xms;
    double xtf;
    int icheck;
    int ichk1;
    int error;
    int SenCond=0;
    double m;
    
    /*  loop through all the models */
    for( ; model != NULL; model = model->BJTnextModel ) {

        /* loop through all the instances of the model */
        for (here = model->BJTinstances; here != NULL ;
                here=here->BJTnextInstance) {
	    if (here->BJTowner != ARCHme) continue;

            vt = here->BJTtemp * CONSTKoverQ;
	    
	    m = here->BJTm;
	    
            if(ckt->CKTsenInfo){
#ifdef SENSDEBUG
                printf("BJTload \n");
#endif /* SENSDEBUG */

                if((ckt->CKTsenInfo->SENstatus == PERTURBATION)&&
                    (here->BJTsenPertFlag == OFF)) continue;
                SenCond = here->BJTsenPertFlag;
            }


            gccs=0;
            ceqcs=0;
            geqbx=0;
            ceqbx=0;
            geqcb=0;
            /*
             *   dc model paramters
             */
            csat=here->BJTtSatCur*here->BJTarea;
            rbpr=model->BJTminBaseResist/here->BJTarea;
            rbpi=model->BJTbaseResist/here->BJTarea-rbpr;
            gcpr=model->BJTcollectorConduct*here->BJTarea;
            gepr=model->BJTemitterConduct*here->BJTarea;
            oik=model->BJTinvRollOffF/here->BJTarea;
            c2=here->BJTtBEleakCur*here->BJTarea;
            vte=model->BJTleakBEemissionCoeff*vt;
            oikr=model->BJTinvRollOffR/here->BJTarea;
            c4=here->BJTtBCleakCur*here->BJTareab;
            vtc=model->BJTleakBCemissionCoeff*vt;
            td=model->BJTexcessPhaseFactor;
            xjrb=model->BJTbaseCurrentHalfResist*here->BJTarea;

            if(SenCond){
#ifdef SENSDEBUG
                printf("BJTsenPertFlag = ON \n");
#endif /* SENSDEBUG */

                if((ckt->CKTsenInfo->SENmode == TRANSEN)&&
                    (ckt->CKTmode & MODEINITTRAN)) {
                    vbe = *(ckt->CKTstate1 + here->BJTvbe);
                    vbc = *(ckt->CKTstate1 + here->BJTvbc);
                    vbx=model->BJTtype*(
                        *(ckt->CKTrhsOp+here->BJTbaseNode)-
                        *(ckt->CKTrhsOp+here->BJTcolPrimeNode));
                    vcs=model->BJTtype*(
                      *(ckt->CKTrhsOp+here->BJTsubstNode)-
                      *(ckt->CKTrhsOp+here->BJTcolPrimeNode));
                }
                else{
                    vbe = *(ckt->CKTstate0 + here->BJTvbe);
                    vbc = *(ckt->CKTstate0 + here->BJTvbc);
                    if((ckt->CKTsenInfo->SENmode == DCSEN)||
                        (ckt->CKTsenInfo->SENmode == TRANSEN)){
                        vbx=model->BJTtype*(
                            *(ckt->CKTrhsOld+here->BJTbaseNode)-
                            *(ckt->CKTrhsOld+here->BJTcolPrimeNode));
                        vcs=model->BJTtype*(
                            *(ckt->CKTrhsOld+here->BJTsubstNode)-
                            *(ckt->CKTrhsOld+here->BJTcolPrimeNode));
                    }
                    if(ckt->CKTsenInfo->SENmode == ACSEN){
                        vbx=model->BJTtype*(
                            *(ckt->CKTrhsOp+here->BJTbaseNode)-
                            *(ckt->CKTrhsOp+here->BJTcolPrimeNode));
                        vcs=model->BJTtype*(
                            *(ckt->CKTrhsOp+here->BJTsubstNode)-
                            *(ckt->CKTrhsOp+here->BJTcolPrimeNode));
                    }
                }
                goto next1;
            }

            /*
             *   initialization
             */
            icheck=1;
            if(ckt->CKTmode & MODEINITSMSIG) {
                vbe= *(ckt->CKTstate0 + here->BJTvbe);
                vbc= *(ckt->CKTstate0 + here->BJTvbc);
                vbx=model->BJTtype*(
                    *(ckt->CKTrhsOld+here->BJTbaseNode)-
                    *(ckt->CKTrhsOld+here->BJTcolPrimeNode));
                vcs=model->BJTtype*(
                    *(ckt->CKTrhsOld+here->BJTsubstNode)-
                    *(ckt->CKTrhsOld+here->BJTcolPrimeNode));
            } else if(ckt->CKTmode & MODEINITTRAN) {
                vbe = *(ckt->CKTstate1 + here->BJTvbe);
                vbc = *(ckt->CKTstate1 + here->BJTvbc);
                vbx=model->BJTtype*(
                    *(ckt->CKTrhsOld+here->BJTbaseNode)-
                    *(ckt->CKTrhsOld+here->BJTcolPrimeNode));
                vcs=model->BJTtype*(
                    *(ckt->CKTrhsOld+here->BJTsubstNode)-
                    *(ckt->CKTrhsOld+here->BJTcolPrimeNode));
                if( (ckt->CKTmode & MODETRAN) && (ckt->CKTmode & MODEUIC) ) {
                    vbx=model->BJTtype*(here->BJTicVBE-here->BJTicVCE);
                    vcs=0;
                }
            } else if((ckt->CKTmode & MODEINITJCT) && 
                    (ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)){
                vbe=model->BJTtype*here->BJTicVBE;
                vce=model->BJTtype*here->BJTicVCE;
                vbc=vbe-vce;
                vbx=vbc;
                vcs=0;
            } else if((ckt->CKTmode & MODEINITJCT) && (here->BJToff==0)) {
                vbe=here->BJTtVcrit;
                vbc=0;
                /* ERROR:  need to initialize VCS, VBX here */
                vcs=vbx=0;
            } else if((ckt->CKTmode & MODEINITJCT) ||
                    ( (ckt->CKTmode & MODEINITFIX) && (here->BJToff!=0))) {
                vbe=0;
                vbc=0;
                /* ERROR:  need to initialize VCS, VBX here */
                vcs=vbx=0;
            } else {
#ifndef PREDICTOR
                if(ckt->CKTmode & MODEINITPRED) {
                    xfact = ckt->CKTdelta/ckt->CKTdeltaOld[1];
                    *(ckt->CKTstate0 + here->BJTvbe) = 
                            *(ckt->CKTstate1 + here->BJTvbe);
                    vbe = (1+xfact)**(ckt->CKTstate1 + here->BJTvbe)-
                            xfact* *(ckt->CKTstate2 + here->BJTvbe);
                    *(ckt->CKTstate0 + here->BJTvbc) = 
                            *(ckt->CKTstate1 + here->BJTvbc);
                    vbc = (1+xfact)**(ckt->CKTstate1 + here->BJTvbc)-
                            xfact* *(ckt->CKTstate2 + here->BJTvbc);
                    *(ckt->CKTstate0 + here->BJTcc) = 
                            *(ckt->CKTstate1 + here->BJTcc);
                    *(ckt->CKTstate0 + here->BJTcb) = 
                            *(ckt->CKTstate1 + here->BJTcb);
                    *(ckt->CKTstate0 + here->BJTgpi) = 
                            *(ckt->CKTstate1 + here->BJTgpi);
                    *(ckt->CKTstate0 + here->BJTgmu) = 
                            *(ckt->CKTstate1 + here->BJTgmu);
                    *(ckt->CKTstate0 + here->BJTgm) = 
                            *(ckt->CKTstate1 + here->BJTgm);
                    *(ckt->CKTstate0 + here->BJTgo) = 
                            *(ckt->CKTstate1 + here->BJTgo);
                    *(ckt->CKTstate0 + here->BJTgx) = 
                            *(ckt->CKTstate1 + here->BJTgx);
                } else {
#endif /* PREDICTOR */
                    /*
                     *   compute new nonlinear branch voltages
                     */
                    vbe=model->BJTtype*(
                        *(ckt->CKTrhsOld+here->BJTbasePrimeNode)-
                        *(ckt->CKTrhsOld+here->BJTemitPrimeNode));
                    vbc=model->BJTtype*(
                        *(ckt->CKTrhsOld+here->BJTbasePrimeNode)-
                        *(ckt->CKTrhsOld+here->BJTcolPrimeNode));
#ifndef PREDICTOR
                }
#endif /* PREDICTOR */
                delvbe=vbe- *(ckt->CKTstate0 + here->BJTvbe);
                delvbc=vbc- *(ckt->CKTstate0 + here->BJTvbc);
                vbx=model->BJTtype*(
                    *(ckt->CKTrhsOld+here->BJTbaseNode)-
                    *(ckt->CKTrhsOld+here->BJTcolPrimeNode));
                vcs=model->BJTtype*(
                    *(ckt->CKTrhsOld+here->BJTsubstNode)-
                    *(ckt->CKTrhsOld+here->BJTcolPrimeNode));
                cchat= *(ckt->CKTstate0 + here->BJTcc)+(*(ckt->CKTstate0 + 
                        here->BJTgm)+ *(ckt->CKTstate0 + here->BJTgo))*delvbe-
                        (*(ckt->CKTstate0 + here->BJTgo)+*(ckt->CKTstate0 +
                        here->BJTgmu))*delvbc;
                cbhat= *(ckt->CKTstate0 + here->BJTcb)+ *(ckt->CKTstate0 + 
                        here->BJTgpi)*delvbe+ *(ckt->CKTstate0 + here->BJTgmu)*
                        delvbc;
#ifndef NOBYPASS
                /*
                 *    bypass if solution has not changed
                 */
                /* the following collections of if's would be just one
                 * if the average compiler could handle it, but many
                 * find the expression too complicated, thus the split.
                 */
                if( (ckt->CKTbypass) &&
                        (!(ckt->CKTmode & MODEINITPRED)) &&
                        (fabs(delvbe) < (ckt->CKTreltol*MAX(fabs(vbe),
                            fabs(*(ckt->CKTstate0 + here->BJTvbe)))+
                            ckt->CKTvoltTol)) )
                    if( (fabs(delvbc) < ckt->CKTreltol*MAX(fabs(vbc),
                            fabs(*(ckt->CKTstate0 + here->BJTvbc)))+
                            ckt->CKTvoltTol) )
                    if( (fabs(cchat-*(ckt->CKTstate0 + here->BJTcc)) < 
                            ckt->CKTreltol* MAX(fabs(cchat),
                            fabs(*(ckt->CKTstate0 + here->BJTcc)))+
                            ckt->CKTabstol) )
                    if( (fabs(cbhat-*(ckt->CKTstate0 + here->BJTcb)) < 
                            ckt->CKTreltol* MAX(fabs(cbhat),
                            fabs(*(ckt->CKTstate0 + here->BJTcb)))+
                            ckt->CKTabstol) ) {
                    /*
                     * bypassing....
                     */
                    vbe = *(ckt->CKTstate0 + here->BJTvbe);
                    vbc = *(ckt->CKTstate0 + here->BJTvbc);
                    cc = *(ckt->CKTstate0 + here->BJTcc);
                    cb = *(ckt->CKTstate0 + here->BJTcb);
                    gpi = *(ckt->CKTstate0 + here->BJTgpi);
                    gmu = *(ckt->CKTstate0 + here->BJTgmu);
                    gm = *(ckt->CKTstate0 + here->BJTgm);
                    go = *(ckt->CKTstate0 + here->BJTgo);
                    gx = *(ckt->CKTstate0 + here->BJTgx);
                    geqcb = *(ckt->CKTstate0 + here->BJTgeqcb);
                    gccs = *(ckt->CKTstate0 + here->BJTgccs);
                    geqbx = *(ckt->CKTstate0 + here->BJTgeqbx);
                    goto load;
                }
#endif /*NOBYPASS*/
                /*
                 *   limit nonlinear branch voltages
                 */
                ichk1=1;
                vbe = DEVpnjlim(vbe,*(ckt->CKTstate0 + here->BJTvbe),vt,
                        here->BJTtVcrit,&icheck);
                vbc = DEVpnjlim(vbc,*(ckt->CKTstate0 + here->BJTvbc),vt,
                        here->BJTtVcrit,&ichk1);
                if (ichk1 == 1) icheck=1;
            }
            /*
             *   determine dc current and derivitives
             */
next1:      vtn=vt*model->BJTemissionCoeffF;

            if(vbe >= -3*vtn){
                evbe=exp(vbe/vtn);
                cbe=csat*(evbe-1);
                gbe=csat*evbe/vtn;
            } else {
                arg=3*vtn/(vbe*CONSTe);
                arg = arg * arg * arg;
                cbe = -csat*(1+arg);
                gbe = csat*3*arg/vbe;
            }
            if (c2 == 0) {
                cben=0;
                gben=0;
            } else {
                if(vbe >= -3*vte){
                    evben=exp(vbe/vte);
                    cben=c2*(evben-1);
                    gben=c2*evben/vte;
                } else {
                    arg=3*vte/(vbe*CONSTe);
                    arg = arg * arg * arg;
                    cben = -c2*(1+arg);
                    gben = c2*3*arg/vbe;
                }
            }
            gben+=ckt->CKTgmin;
            cben+=ckt->CKTgmin*vbe;
            
            vtn=vt*model->BJTemissionCoeffR;
            
              if(vbc >= -3*vtn) {
                evbc=exp(vbc/vtn);
                cbc=csat*(evbc-1);
                gbc=csat*evbc/vtn;
            } else {
                arg=3*vtn/(vbc*CONSTe);
                arg = arg * arg * arg;
                cbc = -csat*(1+arg);
                gbc = csat*3*arg/vbc;
            }
            if (c4 == 0) {
                cbcn=0;
                gbcn=0;
            } else {
                if(vbc >= -3*vtc) {
                    evbcn=exp(vbc/vtc);
                    cbcn=c4*(evbcn-1);
                    gbcn=c4*evbcn/vtc;
                } else {
                    arg=3*vtc/(vbc*CONSTe);
                    arg = arg * arg * arg;
                    cbcn = -c4*(1+arg);
                    gbcn = c4*3*arg/vbc;
                }
            }
            gbcn+=ckt->CKTgmin;
            cbcn+=ckt->CKTgmin*vbc;
            
            /*
             *   determine base charge terms
             */
            q1=1/(1-model->BJTinvEarlyVoltF*vbc-model->BJTinvEarlyVoltR*vbe);
            if(oik == 0 && oikr == 0) {
                qb=q1;
                dqbdve=q1*qb*model->BJTinvEarlyVoltR;
                dqbdvc=q1*qb*model->BJTinvEarlyVoltF;
            } else {
                q2=oik*cbe+oikr*cbc;
                arg=MAX(0,1+4*q2);
                sqarg=1;
                if(arg != 0) sqarg=sqrt(arg);
                qb=q1*(1+sqarg)/2;
                dqbdve=q1*(qb*model->BJTinvEarlyVoltR+oik*gbe/sqarg);
                dqbdvc=q1*(qb*model->BJTinvEarlyVoltF+oikr*gbc/sqarg);
            }
            /*
             *   weil's approx. for excess phase applied with backward-
             *   euler integration
             */
            cc=0;
            cex=cbe;
            gex=gbe;
            if(ckt->CKTmode & (MODETRAN | MODEAC) && td != 0) {
                arg1=ckt->CKTdelta/td;
                arg2=3*arg1;
                arg1=arg2*arg1;
                denom=1+arg1+arg2;
                arg3=arg1/denom;
                if(ckt->CKTmode & MODEINITTRAN) {
                    *(ckt->CKTstate1 + here->BJTcexbc)=cbe/qb;
                    *(ckt->CKTstate2 + here->BJTcexbc)=
                            *(ckt->CKTstate1 + here->BJTcexbc);
                }
                cc=(*(ckt->CKTstate1 + here->BJTcexbc)*(1+ckt->CKTdelta/
                        ckt->CKTdeltaOld[1]+arg2)-
                        *(ckt->CKTstate2 + here->BJTcexbc)*ckt->CKTdelta/
                        ckt->CKTdeltaOld[1])/denom;
                cex=cbe*arg3;
                gex=gbe*arg3;
                *(ckt->CKTstate0 + here->BJTcexbc)=cc+cex/qb;
            }
            /*
             *   determine dc incremental conductances
             */
            cc=cc+(cex-cbc)/qb-cbc/here->BJTtBetaR-cbcn;
            cb=cbe/here->BJTtBetaF+cben+cbc/here->BJTtBetaR+cbcn;
            gx=rbpr+rbpi/qb;
            if(xjrb != 0) {
                arg1=MAX(cb/xjrb,1e-9);
                arg2=(-1+sqrt(1+14.59025*arg1))/2.4317/sqrt(arg1);
                arg1=tan(arg2);
                gx=rbpr+3*rbpi*(arg1-arg2)/arg2/arg1/arg1;
            }
            if(gx != 0) gx=1/gx;
            gpi=gbe/here->BJTtBetaF+gben;
            gmu=gbc/here->BJTtBetaR+gbcn;
            go=(gbc+(cex-cbc)*dqbdvc/qb)/qb;
            gm=(gex-(cex-cbc)*dqbdve/qb)/qb-go;
            if( (ckt->CKTmode & (MODETRAN | MODEAC)) ||
                    ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) ||
                    (ckt->CKTmode & MODEINITSMSIG)) {
                /*
                 *   charge storage elements
                 */
                tf=model->BJTtransitTimeF;
                tr=model->BJTtransitTimeR;
                czbe=here->BJTtBEcap*here->BJTarea;
                pe=here->BJTtBEpot;
                xme=model->BJTjunctionExpBE;
                cdis=model->BJTbaseFractionBCcap;
                ctot=here->BJTtBCcap*here->BJTarea;
                czbc=ctot*cdis;
                czbx=ctot-czbc;
                pc=here->BJTtBCpot;
                xmc=model->BJTjunctionExpBC;
                fcpe=here->BJTtDepCap;
                czcs=model->BJTcapCS*here->BJTareac;
                ps=model->BJTpotentialSubstrate;
                xms=model->BJTexponentialSubstrate;
                xtf=model->BJTtransitTimeBiasCoeffF;
                ovtf=model->BJTtransitTimeVBCFactor;
                xjtf=model->BJTtransitTimeHighCurrentF*here->BJTarea;
                if(tf != 0 && vbe >0) {
                    argtf=0;
                    arg2=0;
                    arg3=0;
                    if(xtf != 0){
                        argtf=xtf;
                        if(ovtf != 0) {
                            argtf=argtf*exp(vbc*ovtf);
                        }
                        arg2=argtf;
                        if(xjtf != 0) {
                            temp=cbe/(cbe+xjtf);
                            argtf=argtf*temp*temp;
                            arg2=argtf*(3-temp-temp);
                        }
                        arg3=cbe*argtf*ovtf;
                    }
                    cbe=cbe*(1+argtf)/qb;
                    gbe=(gbe*(1+arg2)-cbe*dqbdve)/qb;
                    geqcb=tf*(arg3-cbe*dqbdvc)/qb;
                }
                if (vbe < fcpe) {
                    arg=1-vbe/pe;
                    sarg=exp(-xme*log(arg));
                    *(ckt->CKTstate0 + here->BJTqbe)=tf*cbe+pe*czbe*
                            (1-arg*sarg)/(1-xme);
                    capbe=tf*gbe+czbe*sarg;
                } else {
                    f1=here->BJTtf1;
                    f2=model->BJTf2;
                    f3=model->BJTf3;
                    czbef2=czbe/f2;
                    *(ckt->CKTstate0 + here->BJTqbe) = tf*cbe+czbe*f1+czbef2*
                            (f3*(vbe-fcpe) +(xme/(pe+pe))*(vbe*vbe-fcpe*fcpe));
                    capbe=tf*gbe+czbef2*(f3+xme*vbe/pe);
                }
                fcpc=here->BJTtf4;
                f1=here->BJTtf5;
                f2=model->BJTf6;
                f3=model->BJTf7;
                if (vbc < fcpc) {
                    arg=1-vbc/pc;
                    sarg=exp(-xmc*log(arg));
                    *(ckt->CKTstate0 + here->BJTqbc) = tr*cbc+pc*czbc*(
                            1-arg*sarg)/(1-xmc);
                    capbc=tr*gbc+czbc*sarg;
                } else {
                    czbcf2=czbc/f2;
                    *(ckt->CKTstate0 + here->BJTqbc) = tr*cbc+czbc*f1+czbcf2*
                            (f3*(vbc-fcpc) +(xmc/(pc+pc))*(vbc*vbc-fcpc*fcpc));
                    capbc=tr*gbc+czbcf2*(f3+xmc*vbc/pc);
                }
                if(vbx < fcpc) {
                    arg=1-vbx/pc;
                    sarg=exp(-xmc*log(arg));
                    *(ckt->CKTstate0 + here->BJTqbx)= 
                        pc*czbx* (1-arg*sarg)/(1-xmc);
                    capbx=czbx*sarg;
                } else {
                    czbxf2=czbx/f2;
                    *(ckt->CKTstate0 + here->BJTqbx)=czbx*f1+czbxf2*
                            (f3*(vbx-fcpc)+(xmc/(pc+pc))*(vbx*vbx-fcpc*fcpc));
                    capbx=czbxf2*(f3+xmc*vbx/pc);
                }
                if(vcs < 0){
                    arg=1-vcs/ps;
                    sarg=exp(-xms*log(arg));
                    *(ckt->CKTstate0 + here->BJTqcs) = ps*czcs*(1-arg*sarg)/
                            (1-xms);
                    capcs=czcs*sarg;
                } else {
                    *(ckt->CKTstate0 + here->BJTqcs) = vcs*czcs*(1+xms*vcs/
                            (2*ps));
                    capcs=czcs*(1+xms*vcs/ps);
		}
		here->BJTcapbe = capbe;
		here->BJTcapbc = capbc;
		here->BJTcapcs = capcs;
		here->BJTcapbx = capbx;

                /*
                 *   store small-signal parameters
                 */
                if ( (!(ckt->CKTmode & MODETRANOP))||
                        (!(ckt->CKTmode & MODEUIC)) ) {
                    if(ckt->CKTmode & MODEINITSMSIG) {
                        *(ckt->CKTstate0 + here->BJTcqbe) = capbe;
                        *(ckt->CKTstate0 + here->BJTcqbc) = capbc;
                        *(ckt->CKTstate0 + here->BJTcqcs) = capcs;
                        *(ckt->CKTstate0 + here->BJTcqbx) = capbx;
                        *(ckt->CKTstate0 + here->BJTcexbc) = geqcb;
                        if(SenCond){
                            *(ckt->CKTstate0 + here->BJTcc) = cc;
                            *(ckt->CKTstate0 + here->BJTcb) = cb;
                            *(ckt->CKTstate0 + here->BJTgpi) = gpi;
                            *(ckt->CKTstate0 + here->BJTgmu) = gmu;
                            *(ckt->CKTstate0 + here->BJTgm) = gm;
                            *(ckt->CKTstate0 + here->BJTgo) = go;
                            *(ckt->CKTstate0 + here->BJTgx) = gx;
                            *(ckt->CKTstate0 + here->BJTgccs) = gccs;
                            *(ckt->CKTstate0 + here->BJTgeqbx) = geqbx;
                        }
#ifdef SENSDEBUG
                        printf("storing small signal parameters for op\n");
                        printf("capbe = %.7e ,capbc = %.7e\n",capbe,capbc);
                        printf("capcs = %.7e ,capbx = %.7e\n",capcs,capbx);
                        printf("geqcb = %.7e ,gpi = %.7e\n",geqcb,gpi);
                        printf("gmu = %.7e ,gm = %.7e\n",gmu,gm);
                        printf("go = %.7e ,gx = %.7e\n",go,gx);
                        printf("gccs = %.7e ,geqbx = %.7e\n",gccs,geqbx);
                        printf("cc = %.7e ,cb = %.7e\n",cc,cb);
#endif /* SENSDEBUG */
                        continue; /* go to 1000 */
                    }
                    /*
                     *   transient analysis
                     */
                    if(SenCond && ckt->CKTsenInfo->SENmode == TRANSEN){
                        *(ckt->CKTstate0 + here->BJTcc) = cc;
                        *(ckt->CKTstate0 + here->BJTcb) = cb;
                        *(ckt->CKTstate0 + here->BJTgx) = gx;
                        continue;
                    }

                    if(ckt->CKTmode & MODEINITTRAN) {
                        *(ckt->CKTstate1 + here->BJTqbe) =
                                *(ckt->CKTstate0 + here->BJTqbe) ;
                        *(ckt->CKTstate1 + here->BJTqbc) =
                                *(ckt->CKTstate0 + here->BJTqbc) ;
                        *(ckt->CKTstate1 + here->BJTqbx) =
                                *(ckt->CKTstate0 + here->BJTqbx) ;
                        *(ckt->CKTstate1 + here->BJTqcs) =
                                *(ckt->CKTstate0 + here->BJTqcs) ;
                    }
                    error = NIintegrate(ckt,&geq,&ceq,capbe,here->BJTqbe);
                    if(error) return(error);
                    geqcb=geqcb*ckt->CKTag[0];
                    gpi=gpi+geq;
                    cb=cb+*(ckt->CKTstate0 + here->BJTcqbe);
                    error = NIintegrate(ckt,&geq,&ceq,capbc,here->BJTqbc);
                    if(error) return(error);
                    gmu=gmu+geq;
                    cb=cb+*(ckt->CKTstate0 + here->BJTcqbc);
                    cc=cc-*(ckt->CKTstate0 + here->BJTcqbc);
                    if(ckt->CKTmode & MODEINITTRAN) {
                        *(ckt->CKTstate1 + here->BJTcqbe) =
                                *(ckt->CKTstate0 + here->BJTcqbe);
                        *(ckt->CKTstate1 + here->BJTcqbc) =
                                *(ckt->CKTstate0 + here->BJTcqbc);
                    }
                }
            }

            if(SenCond) goto next2;

            /*
             *   check convergence
             */
            if ( (!(ckt->CKTmode & MODEINITFIX))||(!(here->BJToff))) {
                if (icheck == 1) {
                    ckt->CKTnoncon++;
		    ckt->CKTtroubleElt = (GENinstance *) here;
                }
            }

            /*
             *      charge storage for c-s and b-x junctions
             */
            if(ckt->CKTmode & (MODETRAN | MODEAC)) {
                error = NIintegrate(ckt,&gccs,&ceq,capcs,here->BJTqcs);
                if(error) return(error);
                error = NIintegrate(ckt,&geqbx,&ceq,capbx,here->BJTqbx);
                if(error) return(error);
                if(ckt->CKTmode & MODEINITTRAN) {
                    *(ckt->CKTstate1 + here->BJTcqbx) =
                            *(ckt->CKTstate0 + here->BJTcqbx);
                    *(ckt->CKTstate1 + here->BJTcqcs) =
                            *(ckt->CKTstate0 + here->BJTcqcs);
                }
            }
next2:
            *(ckt->CKTstate0 + here->BJTvbe) = vbe;
            *(ckt->CKTstate0 + here->BJTvbc) = vbc;
            *(ckt->CKTstate0 + here->BJTcc) = cc;
            *(ckt->CKTstate0 + here->BJTcb) = cb;
            *(ckt->CKTstate0 + here->BJTgpi) = gpi;
            *(ckt->CKTstate0 + here->BJTgmu) = gmu;
            *(ckt->CKTstate0 + here->BJTgm) = gm;
            *(ckt->CKTstate0 + here->BJTgo) = go;
            *(ckt->CKTstate0 + here->BJTgx) = gx;
            *(ckt->CKTstate0 + here->BJTgeqcb) = geqcb;
            *(ckt->CKTstate0 + here->BJTgccs) = gccs;
            *(ckt->CKTstate0 + here->BJTgeqbx) = geqbx;

            /* Do not load the Jacobian and the rhs if
               perturbation is being carried out */

            if(SenCond)continue;
load:
            /*
         *  load current excitation vector
         */
            ceqcs=model->BJTtype * (*(ckt->CKTstate0 + here->BJTcqcs) - 
                    vcs * gccs);
            ceqbx=model->BJTtype * (*(ckt->CKTstate0 + here->BJTcqbx) -
                    vbx * geqbx);
            ceqbe=model->BJTtype * (cc + cb - vbe * (gm + go + gpi) + vbc * 
                    (go - geqcb));
            ceqbc=model->BJTtype * (-cc + vbe * (gm + go) - vbc * (gmu + go));

            *(ckt->CKTrhs + here->BJTbaseNode) +=  m * (-ceqbx);
            *(ckt->CKTrhs + here->BJTcolPrimeNode) += 
                    m * (ceqcs+ceqbx+ceqbc);
            *(ckt->CKTrhs + here->BJTbasePrimeNode) += 
                    m * (-ceqbe-ceqbc);
            *(ckt->CKTrhs + here->BJTemitPrimeNode) += m * (ceqbe);
            *(ckt->CKTrhs + here->BJTsubstNode) += m * (-ceqcs);
            /*
             *  load y matrix
             */
            *(here->BJTcolColPtr) +=  m * (gcpr);
            *(here->BJTbaseBasePtr) +=  m * (gx+geqbx);
            *(here->BJTemitEmitPtr) += m * (gepr);
            *(here->BJTcolPrimeColPrimePtr) += m * (gmu+go+gcpr+gccs+geqbx);
            *(here->BJTbasePrimeBasePrimePtr) += m * (gx +gpi+gmu+geqcb);
            *(here->BJTemitPrimeEmitPrimePtr) += m * (gpi+gepr+gm+go);
            *(here->BJTcolColPrimePtr) += m * (-gcpr);
            *(here->BJTbaseBasePrimePtr) += m * (-gx);
            *(here->BJTemitEmitPrimePtr) += m * (-gepr);
            *(here->BJTcolPrimeColPtr) += m * (-gcpr);
            *(here->BJTcolPrimeBasePrimePtr) += m * (-gmu+gm);
            *(here->BJTcolPrimeEmitPrimePtr) += m * (-gm-go);
            *(here->BJTbasePrimeBasePtr) += m * (-gx);
            *(here->BJTbasePrimeColPrimePtr) += m * (-gmu-geqcb);
            *(here->BJTbasePrimeEmitPrimePtr) += m * (-gpi);
            *(here->BJTemitPrimeEmitPtr) += m * (-gepr);
            *(here->BJTemitPrimeColPrimePtr) += m * (-go+geqcb);
            *(here->BJTemitPrimeBasePrimePtr) += m * (-gpi-gm-geqcb);
            *(here->BJTsubstSubstPtr) += m * (gccs);
            *(here->BJTcolPrimeSubstPtr) += m * (-gccs);
            *(here->BJTsubstColPrimePtr) += m * (-gccs);
            *(here->BJTbaseColPrimePtr) += m * (-geqbx);
            *(here->BJTcolPrimeBasePtr) += m * (-geqbx);
        }
    }
    return(OK);
}
Exemplo n.º 3
0
int
VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
/* actually load the current value into the
 * sparse matrix previously provided
 */
{
    VDMOSmodel *model = (VDMOSmodel *)inModel;
    VDMOSinstance *here;
    double Beta;
    double DrainSatCur;
    double SourceSatCur;
    double arg;
    double cdhat;
    double cdrain;
    double cdreq;
    double ceq;
    double ceqgd;
    double ceqgs;
    double delvds;
    double delvgd;
    double delvgs;
    double gcgd;
    double gcgs;
    double geq;
    double sarg;
    double vds;
    double vdsat;
    double vgd1;
    double vgd;
    double vgdo;
    double vgs1;
    double vgs;
    double von;
    double vt;
#ifndef PREDICTOR
    double xfact = 0.0;
#endif
    int xnrm;
    int xrev;
    double capgs = 0.0;   /* total gate-source capacitance */
    double capgd = 0.0;   /* total gate-drain capacitance */
    int Check;
    int error;

    double CGBdummy;

    /*  loop through all the VDMOS device models */
    for (; model != NULL; model = VDMOSnextModel(model)) {
        /* VDMOS capacitance parameters */
        const double cgdmin = model->VDMOScgdmin;
        const double cgdmax = model->VDMOScgdmax;
        const double a = model->VDMOSa;
        const double cgs = model->VDMOScgs;

        /* loop through all the instances of the model */
        for (here = VDMOSinstances(model); here != NULL;
                here = VDMOSnextInstance(here)) {

            vt = CONSTKoverQ * here->VDMOStemp;
            Check = 1;

            /* first, we compute a few useful values - these could be
             * pre-computed, but for historical reasons are still done
             * here.  They may be moved at the expense of instance size
             */

            DrainSatCur = here->VDMOSm * here->VDMOStSatCur;
            SourceSatCur = here->VDMOSm * here->VDMOStSatCur;
            Beta = here->VDMOStTransconductance * here->VDMOSm *
                   here->VDMOSw / here->VDMOSl;

            /*
             * ok - now to do the start-up operations
             *
             * we must get values for vbs, vds, and vgs from somewhere
             * so we either predict them or recover them from last iteration
             * These are the two most common cases - either a prediction
             * step or the general iteration step and they
             * share some code, so we put them first - others later on
             */

            if ((ckt->CKTmode & (MODEINITFLOAT | MODEINITPRED | MODEINITSMSIG
                                 | MODEINITTRAN)) ||
                    ((ckt->CKTmode & MODEINITFIX) && (!here->VDMOSoff))) {
#ifndef PREDICTOR
                if (ckt->CKTmode & (MODEINITPRED | MODEINITTRAN)) {

                    /* predictor step */

                    xfact = ckt->CKTdelta / ckt->CKTdeltaOld[1];
                    *(ckt->CKTstate0 + here->VDMOSvgs) =
                        *(ckt->CKTstate1 + here->VDMOSvgs);
                    vgs = (1 + xfact)* (*(ckt->CKTstate1 + here->VDMOSvgs))
                          - (xfact * (*(ckt->CKTstate2 + here->VDMOSvgs)));
                    *(ckt->CKTstate0 + here->VDMOSvds) =
                        *(ckt->CKTstate1 + here->VDMOSvds);
                    vds = (1 + xfact)* (*(ckt->CKTstate1 + here->VDMOSvds))
                          - (xfact * (*(ckt->CKTstate2 + here->VDMOSvds)));
                } else {
#endif /* PREDICTOR */

                    /* general iteration */

                    vgs = model->VDMOStype * (
                              *(ckt->CKTrhsOld + here->VDMOSgNodePrime) -
                              *(ckt->CKTrhsOld + here->VDMOSsNodePrime));
                    vds = model->VDMOStype * (
                              *(ckt->CKTrhsOld + here->VDMOSdNodePrime) -
                              *(ckt->CKTrhsOld + here->VDMOSsNodePrime));
#ifndef PREDICTOR
                }
#endif /* PREDICTOR */

                /* now some common crunching for some more useful quantities */

                vgd = vgs - vds;
                vgdo = *(ckt->CKTstate0 + here->VDMOSvgs) -
                       *(ckt->CKTstate0 + here->VDMOSvds);
                delvgs = vgs - *(ckt->CKTstate0 + here->VDMOSvgs);
                delvds = vds - *(ckt->CKTstate0 + here->VDMOSvds);
                delvgd = vgd - vgdo;

                /* these are needed for convergence testing */

                if (here->VDMOSmode >= 0) {
                    cdhat =
                            here->VDMOScd
                          + here->VDMOSgm * delvgs
                          + here->VDMOSgds * delvds;
                } else {
                    cdhat =
                            here->VDMOScd
                          - here->VDMOSgm * delvgd
                          + here->VDMOSgds * delvds;
                }

#ifndef NOBYPASS
                /* now lets see if we can bypass (ugh) */
                if ((!(ckt->CKTmode &
                        (MODEINITPRED | MODEINITTRAN | MODEINITSMSIG))) &&
                        (ckt->CKTbypass) &&
                        (fabs(delvgs) < (ckt->CKTreltol *
                                         MAX(fabs(vgs),
                                             fabs(*(ckt->CKTstate0 +
                                                    here->VDMOSvgs))) +
                                         ckt->CKTvoltTol)) &&
                        (fabs(delvds) < (ckt->CKTreltol *
                                         MAX(fabs(vds),
                                             fabs(*(ckt->CKTstate0 +
                                                    here->VDMOSvds))) +
                                         ckt->CKTvoltTol)) &&
                        (fabs(cdhat - here->VDMOScd) < (ckt->CKTreltol *
                                                        MAX(fabs(cdhat),
                                                                fabs(here->VDMOScd)) +
                                                        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
                     */
                    vgs = *(ckt->CKTstate0 + here->VDMOSvgs);
                    vds = *(ckt->CKTstate0 + here->VDMOSvds);
                    vgd = vgs - vds;
                    cdrain = here->VDMOSmode * (here->VDMOScd);
                    if (ckt->CKTmode & (MODETRAN | MODETRANOP)) {
                        capgs = (*(ckt->CKTstate0 + here->VDMOScapgs) +
                                 *(ckt->CKTstate1 + here->VDMOScapgs));
                        capgd = (*(ckt->CKTstate0 + here->VDMOScapgd) +
                                 *(ckt->CKTstate1 + here->VDMOScapgd));

                    }
                    goto bypass;
                }
#endif /*NOBYPASS*/


                /* ok - bypass is out, do it the hard way */

                von = model->VDMOStype * here->VDMOSvon;

#ifndef NODELIMITING
                /*
                 * limiting
                 *  we want to keep device voltages from changing
                 * so fast that the exponentials churn out overflows
                 * and similar rudeness
                 */

                if (*(ckt->CKTstate0 + here->VDMOSvds) >= 0) {
                    vgs = DEVfetlim(vgs, *(ckt->CKTstate0 + here->VDMOSvgs)
                                    , von);
                    vds = vgs - vgd;
                    vds = DEVlimvds(vds, *(ckt->CKTstate0 + here->VDMOSvds));
                    vgd = vgs - vds;
                } else {
                    vgd = DEVfetlim(vgd, vgdo, von);
                    vds = vgs - vgd;
                    if (!(ckt->CKTfixLimit)) {
                        vds = -DEVlimvds(-vds, -(*(ckt->CKTstate0 +
                                                   here->VDMOSvds)));
                    }
                    vgs = vgd + vds;
                }
#endif /*NODELIMITING*/


            } else {

                /* ok - not one of the simple cases, so we have to
                 * look at all of the possibilities for why we were
                 * called.  We still just initialize the three voltages
                 */

                if ((ckt->CKTmode & MODEINITJCT) && !here->VDMOSoff) {
                    vds = model->VDMOStype * here->VDMOSicVDS;
                    vgs = model->VDMOStype * here->VDMOSicVGS;
                    if ((vds == 0) && (vgs == 0) &&
                            ((ckt->CKTmode &
                              (MODETRAN | MODEDCOP | MODEDCTRANCURVE)) ||
                             (!(ckt->CKTmode & MODEUIC)))) {
                        vgs = model->VDMOStype * here->VDMOStVto;
                        vds = 0;
                    }
                } else {
                    vgs = vds = 0;
                }
            }


            /*
             * now all the preliminaries are over - we can start doing the
             * real work
             */
            vgd = vgs - vds;


            /* now to determine whether the user was able to correctly
             * identify the source and drain of his device
             */
            if (vds >= 0) {
                /* normal mode */
                here->VDMOSmode = 1;
            } else {
                /* inverse mode */
                here->VDMOSmode = -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 2 variables are local to this code block until
                 * it is obvious that they can be made global
                 */
                double betap;
                double vgst;

                von = (model->VDMOSvt0*model->VDMOStype);
                vgst = (here->VDMOSmode == 1 ? vgs : vgd) - von;
                vdsat = MAX(vgst, 0);
                if (model->VDMOSksubthresGiven) {
                /* Alternative simple weak inversion model, according to https://www.anasoft.co.uk/MOS1Model.htm
                 * Scale the voltage overdrive vgst logarithmically in weak inversion.
                 * Best fits LTSPICE curves with shift=0
                 * Drain current including subthreshold current */

                    double slope = model->VDMOSksubthres;
                    double lambda = model->VDMOSlambda;
                    double theta = model->VDMOStheta;
                    double shift = model->VDMOSsubshift;
                    double mtr = model->VDMOSmtr;

                    /* scale vds with mtr (except with lambda) */
                    double vdss = vds*mtr*here->VDMOSmode;
                    double t0 = 1 + lambda*vds;
                    double t1 = 1 + theta*vgs;
                    betap = Beta*t0/t1;
                    double dbetapdvgs = -Beta*theta*t0/(t1*t1);
                    double dbetapdvds = Beta*lambda/t1;

                    double t2 = exp((vgst-shift)/slope);
                    vgst = slope * log(1 + t2);
                    double dvgstdvgs = t2/(t2+1);

                    if (vgst <= vdss) {
                        /* saturation region */
                        cdrain = betap*vgst*vgst*.5;
                        here->VDMOSgm = betap*vgst*dvgstdvgs + 0.5*dbetapdvgs*vgst*vgst;
                        here->VDMOSgds = .5*dbetapdvds*vgst*vgst;
                    }
                    else {
                        /* linear region */
                        cdrain = betap * vdss * (vgst - .5 * vdss);
                        here->VDMOSgm = betap*vdss*dvgstdvgs + vdss*dbetapdvgs*(vgst-.5*vdss);
                        here->VDMOSgds = vdss*dbetapdvds*(vgst-.5*vdss) + betap*mtr*(vgst-.5*vdss) - .5*vdss*betap*mtr;
                    }
                }
                else if (model->VDMOSsubslGiven) {
                    /* numerical differentiation for gd and gm with a delta of 2 mV */
                    double vdsm = vds * here->VDMOSmode;
                    double delta = 0.001;
                    cdrain = cweakinv2(model->VDMOSsubsl, model->VDMOSsubshift, vgst, vdsm, model->VDMOSlambda,
                        Beta, vt, model->VDMOSmtr, model->VDMOStheta);
                    /* gd */
                    double vds1 = vdsm + delta;
                    double cdrp = cweakinv2(model->VDMOSsubsl, model->VDMOSsubshift, vgst, vds1, model->VDMOSlambda,
                        Beta, vt, model->VDMOSmtr, model->VDMOStheta);
                    vds1 = vdsm - delta;
                    double cdrm = cweakinv2(model->VDMOSsubsl, model->VDMOSsubshift, vgst, vds1, model->VDMOSlambda,
                        Beta, vt, model->VDMOSmtr, model->VDMOStheta);
                    here->VDMOSgds = (cdrp - cdrm) / (2. * delta);
                    /* gm */
                    double vgst1 = vgst + delta;
                    cdrp = cweakinv2(model->VDMOSsubsl, model->VDMOSsubshift, vgst1, vdsm, model->VDMOSlambda,
                        Beta, vt, model->VDMOSmtr, model->VDMOStheta);
                    vgst1 = vgst - delta;
                    cdrm = cweakinv2(model->VDMOSsubsl, model->VDMOSsubshift, vgst1, vdsm, model->VDMOSlambda,
                        Beta, vt, model->VDMOSmtr, model->VDMOStheta);
                    here->VDMOSgm = (cdrp - cdrm) / (2. * delta);
                } else {
                    double onfg, fgate, Betam, dfgdvg;
                    onfg = 1.0+model->VDMOStheta*vgst;
                    fgate = 1.0/onfg;
                    Betam = Beta * fgate;
                    dfgdvg = -model->VDMOStheta*fgate*fgate;
                    if (vgst <= 0) {
                        /*
                         *     cutoff region
                         */
                        cdrain = 0;
                        here->VDMOSgm = 0;
                        here->VDMOSgds = 0;
                    } else {
                        /* scale vds with mtr */
                        double mtr = model->VDMOSmtr;
                        betap = Betam*(1 + model->VDMOSlambda*(vds*here->VDMOSmode));
                        if (vgst <= (vds * here->VDMOSmode) * mtr) {
                            /*
                             *     saturation region
                             */
                            cdrain = betap*vgst*vgst*.5;
                            here->VDMOSgm = betap*vgst * fgate + dfgdvg * cdrain;
                            here->VDMOSgds = model->VDMOSlambda*Betam*vgst*vgst*.5;
                        } else {
                            /*
                             *     linear region
                             */
                            cdrain = betap * (vds * here->VDMOSmode) * mtr *
                                     (vgst - .5 * (vds*here->VDMOSmode) * mtr);
                            here->VDMOSgm = betap * (vds * here->VDMOSmode) * mtr  * fgate + dfgdvg * cdrain;
                            here->VDMOSgds = betap * (vgst - (vds * here->VDMOSmode) * mtr) +
                                             model->VDMOSlambda * Betam *
                                             (vds * here->VDMOSmode) * mtr *
                                             (vgst - .5 * (vds * here->VDMOSmode) * mtr);
                        }
                    }
                }
            }


            /* now deal with n vs p polarity */

            here->VDMOSvon = model->VDMOStype * von;
            here->VDMOSvdsat = model->VDMOStype * vdsat;

            /*
             *  COMPUTE EQUIVALENT DRAIN CURRENT SOURCE
             */
            here->VDMOScd = here->VDMOSmode * cdrain;

            /* save things away for next time */

            *(ckt->CKTstate0 + here->VDMOSvgs) = vgs;
            *(ckt->CKTstate0 + here->VDMOSvds) = vds;


            /*
             * vdmos capacitor model
             */
            if (ckt->CKTmode & (MODETRAN | MODETRANOP | MODEINITSMSIG)) {
                /*
                 * calculate gate - drain, gate - source capacitors
                 * drain-source capacitor is evaluated with the bulk diode below
                 */
                /*
                 * this just evaluates at the current time,
                 * expects you to remember values from previous time
                 * returns 1/2 of non-constant portion of capacitance
                 * you must add in the other half from previous time
                 * and the constant part
                 */
                DevCapVDMOS(vgd, cgdmin, cgdmax, a, cgs,
                            (ckt->CKTstate0 + here->VDMOScapgs),
                            (ckt->CKTstate0 + here->VDMOScapgd),
                             &CGBdummy);

                vgs1 = *(ckt->CKTstate1 + here->VDMOSvgs);
                vgd1 = vgs1 - *(ckt->CKTstate1 + here->VDMOSvds);
                if (ckt->CKTmode & (MODETRANOP | MODEINITSMSIG)) {
                    capgs = 2 * *(ckt->CKTstate0 + here->VDMOScapgs);
                    capgd = 2 * *(ckt->CKTstate0 + here->VDMOScapgd);
                } else {
                    capgs = (*(ckt->CKTstate0 + here->VDMOScapgs) +
                             *(ckt->CKTstate1 + here->VDMOScapgs));
                    capgd = (*(ckt->CKTstate0 + here->VDMOScapgd) +
                             *(ckt->CKTstate1 + here->VDMOScapgd));
                }
                /*

                */

#ifndef PREDICTOR
                if (ckt->CKTmode & (MODEINITPRED | MODEINITTRAN)) {
                    *(ckt->CKTstate0 + here->VDMOSqgs) =
                        (1 + xfact) * *(ckt->CKTstate1 + here->VDMOSqgs)
                        - xfact * *(ckt->CKTstate2 + here->VDMOSqgs);
                    *(ckt->CKTstate0 + here->VDMOSqgd) =
                        (1 + xfact) * *(ckt->CKTstate1 + here->VDMOSqgd)
                        - xfact * *(ckt->CKTstate2 + here->VDMOSqgd);
                } else {
#endif /*PREDICTOR*/
                    if (ckt->CKTmode & MODETRAN) {
                        *(ckt->CKTstate0 + here->VDMOSqgs) = (vgs - vgs1)*capgs +
                                                             *(ckt->CKTstate1 + here->VDMOSqgs);
                        *(ckt->CKTstate0 + here->VDMOSqgd) = (vgd - vgd1)*capgd +
                                                             *(ckt->CKTstate1 + here->VDMOSqgd);
                    } else {
                        /* TRANOP only */
                        *(ckt->CKTstate0 + here->VDMOSqgs) = vgs*capgs;
                        *(ckt->CKTstate0 + here->VDMOSqgd) = vgd*capgd;
                    }
#ifndef PREDICTOR
                }
#endif /*PREDICTOR*/
            }
#ifndef NOBYPASS
bypass :
#endif

            if ((ckt->CKTmode & (MODEINITTRAN)) ||
                    (!(ckt->CKTmode & (MODETRAN)))) {
                /*
                 *  initialize to zero charge conductances
                 *  and current
                 */
                gcgs = 0;
                ceqgs = 0;
                gcgd = 0;
                ceqgd = 0;
            } else {
                if (capgs == 0) *(ckt->CKTstate0 + here->VDMOScqgs) = 0;
                if (capgd == 0) *(ckt->CKTstate0 + here->VDMOScqgd) = 0;
                /*
                 *    calculate equivalent conductances and currents for
                 *    meyer"s capacitors
                 */
                error = NIintegrate(ckt, &gcgs, &ceqgs, capgs, here->VDMOSqgs);
                if (error) return(error);
                error = NIintegrate(ckt, &gcgd, &ceqgd, capgd, here->VDMOSqgd);
                if (error) return(error);
                ceqgs = ceqgs - gcgs*vgs + ckt->CKTag[0] *
                        *(ckt->CKTstate0 + here->VDMOSqgs);
                ceqgd = ceqgd - gcgd*vgd + ckt->CKTag[0] *
                        *(ckt->CKTstate0 + here->VDMOSqgd);
            }

            /*
             *  load current vector
             */
            if (here->VDMOSmode >= 0) {
                xnrm = 1;
                xrev = 0;
                cdreq = model->VDMOStype*(cdrain - here->VDMOSgds*vds -
                                          here->VDMOSgm*vgs);
            } else {
                xnrm = 0;
                xrev = 1;
                cdreq = -(model->VDMOStype)*(cdrain - here->VDMOSgds*(-vds) -
                                             here->VDMOSgm*vgd);
            }
            *(ckt->CKTrhs + here->VDMOSgNodePrime) -=
                (model->VDMOStype * (ceqgs + ceqgd));
            *(ckt->CKTrhs + here->VDMOSdNodePrime) +=
                (-cdreq + model->VDMOStype * ceqgd);
            *(ckt->CKTrhs + here->VDMOSsNodePrime) +=
                cdreq + model->VDMOStype * ceqgs;


            /* quasi saturation
             * according to Vincenzo d'Alessandro's Quasi-Saturation Model, simplified:
             V. D'Alessandro, F. Frisina, N. Rinaldi: A New SPICE Model of VDMOS Transistors
             Including Thermal and Quasi-saturation Effects, 9th European Conference on Power
             Electronics and applications (EPE), Graz, Austria, August 2001, pp. P.1 − P.10.
             */
            if (model->VDMOSqsGiven && (here->VDMOSmode == 1)) {
                double vdsn = model->VDMOStype * (
                    *(ckt->CKTrhsOld + here->VDMOSdNode) -
                    *(ckt->CKTrhsOld + here->VDMOSsNode));
                double rd = model->VDMOSdrainResistance + model->VDMOSqsResistance *
                    (vdsn / (vdsn + fabs(model->VDMOSqsVoltage)));
                here->VDMOSdrainConductance = 1 / rd;
            }


            /*
             *  load y matrix
             */
            *(here->VDMOSDdPtr) += (here->VDMOSdrainConductance + here->VDMOSdsConductance);
            *(here->VDMOSGgPtr) += (here->VDMOSgateConductance); //((gcgd + gcgs + gcgb));
            *(here->VDMOSSsPtr) += (here->VDMOSsourceConductance + here->VDMOSdsConductance);
            *(here->VDMOSDPdpPtr) +=
                (here->VDMOSdrainConductance + here->VDMOSgds +
                 xrev*(here->VDMOSgm) + gcgd);
            *(here->VDMOSSPspPtr) +=
                (here->VDMOSsourceConductance + here->VDMOSgds +
                 xnrm*(here->VDMOSgm) + gcgs);
            *(here->VDMOSGPgpPtr) +=
                (here->VDMOSgateConductance) + (gcgd + gcgs);
            *(here->VDMOSGgpPtr) += (-here->VDMOSgateConductance);
            *(here->VDMOSDdpPtr) += (-here->VDMOSdrainConductance);
            *(here->VDMOSGPgPtr) += (-here->VDMOSgateConductance);
            *(here->VDMOSGPdpPtr) -= gcgd;
            *(here->VDMOSGPspPtr) -= gcgs;
            *(here->VDMOSSspPtr) += (-here->VDMOSsourceConductance);
            *(here->VDMOSDPdPtr) += (-here->VDMOSdrainConductance);
            *(here->VDMOSDPgpPtr) += ((xnrm - xrev)*here->VDMOSgm - gcgd);
            *(here->VDMOSDPspPtr) += (-here->VDMOSgds - xnrm*
                                      (here->VDMOSgm));
            *(here->VDMOSSPgpPtr) += (-(xnrm - xrev)*here->VDMOSgm - gcgs);
            *(here->VDMOSSPsPtr) += (-here->VDMOSsourceConductance);
            *(here->VDMOSSPdpPtr) += (-here->VDMOSgds - xrev*
                                      (here->VDMOSgm));

            *(here->VDMOSDsPtr) += (-here->VDMOSdsConductance);
            *(here->VDMOSSdPtr) += (-here->VDMOSdsConductance);


            /* bulk diode model
             * Delivers reverse conduction and forward breakdown
             * of VDMOS transistor
             */

            double vd;      /* current diode voltage */
            double vdtemp;
            double vte;
            double vtebrk, vbrknp;
            double cd, cdb, csat, cdeq;
            double czero;
            double czof2;
            double capd;
            double gd, gdb, gspr;
            double delvd;   /* change in diode voltage temporary */
            double diffcharge, deplcharge, diffcap, deplcap;
            double evd, evrev;
#ifndef NOBYPASS
            double tol;     /* temporary for tolerence calculations */
#endif

            cd = 0.0;
            cdb = 0.0;
            gd = 0.0;
            gdb = 0.0;
            csat = here->VDIOtSatCur;
            gspr = here->VDIOtConductance;
            vte = model->VDMOSDn * vt;
            vtebrk = model->VDIObrkdEmissionCoeff * vt;
            vbrknp = here->VDIOtBrkdwnV;

            Check = 1;
            if (ckt->CKTmode & MODEINITSMSIG) {
                vd = *(ckt->CKTstate0 + here->VDIOvoltage);
            } else if (ckt->CKTmode & MODEINITTRAN) {
                vd = *(ckt->CKTstate1 + here->VDIOvoltage);
            } else if ((ckt->CKTmode & MODEINITJCT) &&
                       (ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) {
                vd = here->VDIOinitCond;
            } else if (ckt->CKTmode & MODEINITJCT) {
                vd = here->VDIOtVcrit;
            } else {
#ifndef PREDICTOR
                if (ckt->CKTmode & MODEINITPRED) {
                    *(ckt->CKTstate0 + here->VDIOvoltage) =
                        *(ckt->CKTstate1 + here->VDIOvoltage);
                    vd = DEVpred(ckt, here->VDIOvoltage);
                    *(ckt->CKTstate0 + here->VDIOcurrent) =
                        *(ckt->CKTstate1 + here->VDIOcurrent);
                    *(ckt->CKTstate0 + here->VDIOconduct) =
                        *(ckt->CKTstate1 + here->VDIOconduct);
                } else {
#endif /* PREDICTOR */
                    vd = model->VDMOStype * (*(ckt->CKTrhsOld + here->VDIOposPrimeNode) -
                                             *(ckt->CKTrhsOld + here->VDMOSdNode));
#ifndef PREDICTOR
                }
#endif /* PREDICTOR */
                delvd = vd - *(ckt->CKTstate0 + here->VDIOvoltage);
                cdhat = *(ckt->CKTstate0 + here->VDIOcurrent) +
                        *(ckt->CKTstate0 + here->VDIOconduct) * delvd;
                /*
                *   bypass if solution has not changed
                */
#ifndef NOBYPASS
                if ((!(ckt->CKTmode & MODEINITPRED)) && (ckt->CKTbypass)) {
                    tol = ckt->CKTvoltTol + ckt->CKTreltol*
                          MAX(fabs(vd), fabs(*(ckt->CKTstate0 + here->VDIOvoltage)));
                    if (fabs(delvd) < tol) {
                        tol = ckt->CKTreltol* MAX(fabs(cdhat),
                                                  fabs(*(ckt->CKTstate0 + here->VDIOcurrent))) +
                              ckt->CKTabstol;
                        if (fabs(cdhat - *(ckt->CKTstate0 + here->VDIOcurrent))
                                < tol) {
                            vd = *(ckt->CKTstate0 + here->VDIOvoltage);
                            cd = *(ckt->CKTstate0 + here->VDIOcurrent);
                            gd = *(ckt->CKTstate0 + here->VDIOconduct);
                            goto load;
                        }
                    }
                }
#endif /* NOBYPASS */
                /*
                *   limit new junction voltage
                */
                if ((model->VDMOSDbvGiven) &&
                        (vd < MIN(0, -vbrknp + 10 * vtebrk))) {
                    vdtemp = -(vd + vbrknp);
                    vdtemp = DEVpnjlim(vdtemp,
                                       -(*(ckt->CKTstate0 + here->VDIOvoltage) +
                                         vbrknp), vtebrk,
                                       here->VDIOtVcrit, &Check);
                    vd = -(vdtemp + vbrknp);
                } else {
                    vd = DEVpnjlim(vd, *(ckt->CKTstate0 + here->VDIOvoltage),
                                   vte, here->VDIOtVcrit, &Check);
                }
            }
            /*
            *   compute dc current and derivatives
            */
            if (vd >= -3 * vte) {                 /* bottom current forward */

                evd = exp(vd / vte);
                cdb = csat*(evd - 1);
                gdb = csat*evd / vte;

            } else if ((!(model->VDMOSDbvGiven)) ||
                       vd >= -vbrknp) { /* reverse */

                arg = 3 * vte / (vd*CONSTe);
                arg = arg * arg * arg;
                cdb = -csat*(1 + arg);
                gdb = csat * 3 * arg / vd;

            } else {                          /* breakdown */

                evrev = exp(-(vbrknp + vd) / vtebrk);
                cdb = -csat*evrev;
                gdb = csat*evrev / vtebrk;

            }


            cd = cdb;
            gd = gdb;

            gd = gd + ckt->CKTgmin;
            cd = cd + ckt->CKTgmin*vd;

            if ((ckt->CKTmode & (MODEDCTRANCURVE | MODETRAN | MODEAC | MODEINITSMSIG)) ||
                    ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC))) {
                /*
                *   charge storage elements
                */
                czero = here->VDIOtJctCap;
                if (vd < here->VDIOtDepCap) {
                    arg = 1 - vd / here->VDIOtJctPot;
                    sarg = exp(-here->VDIOtGradingCoeff*log(arg));
                    deplcharge = here->VDIOtJctPot*czero*(1 - arg*sarg) / (1 - here->VDIOtGradingCoeff);
                    deplcap = czero*sarg;
                } else {
                    czof2 = czero / here->VDIOtF2;
                    deplcharge = czero*here->VDIOtF1 + czof2*(here->VDIOtF3*(vd - here->VDIOtDepCap) +
                                 (here->VDIOtGradingCoeff / (here->VDIOtJctPot + here->VDIOtJctPot))*(vd*vd - here->VDIOtDepCap*here->VDIOtDepCap));
                    deplcap = czof2*(here->VDIOtF3 + here->VDIOtGradingCoeff*vd / here->VDIOtJctPot);
                }
                diffcharge = here->VDIOtTransitTime*cdb;
                *(ckt->CKTstate0 + here->VDIOcapCharge) =
                    diffcharge +  deplcharge;

                diffcap = here->VDIOtTransitTime*gdb;
                capd = diffcap + deplcap;

                here->VDIOcap = capd;

                /*
                *   store small-signal parameters
                */
                if ((!(ckt->CKTmode & MODETRANOP)) ||
                        (!(ckt->CKTmode & MODEUIC))) {
                    if (ckt->CKTmode & MODEINITSMSIG) {
                        *(ckt->CKTstate0 + here->VDIOcapCurrent) = capd;

                        continue;
                    }

                    /*
                    *   transient analysis
                    */

                    if (ckt->CKTmode & MODEINITTRAN) {
                        *(ckt->CKTstate1 + here->VDIOcapCharge) =
                            *(ckt->CKTstate0 + here->VDIOcapCharge);
                    }
                    error = NIintegrate(ckt, &geq, &ceq, capd, here->VDIOcapCharge);
                    if (error) return(error);
                    gd = gd + geq;
                    cd = cd + *(ckt->CKTstate0 + here->VDIOcapCurrent);
                    if (ckt->CKTmode & MODEINITTRAN) {
                        *(ckt->CKTstate1 + here->VDIOcapCurrent) =
                            *(ckt->CKTstate0 + here->VDIOcapCurrent);
                    }
                }
            }

            /*
            *   check convergence
            */

            if (Check == 1) {
                ckt->CKTnoncon++;
                ckt->CKTtroubleElt = (GENinstance *)here;
            }

            *(ckt->CKTstate0 + here->VDIOvoltage) = vd;
            *(ckt->CKTstate0 + here->VDIOcurrent) = cd;
            *(ckt->CKTstate0 + here->VDIOconduct) = gd;

#ifndef NOBYPASS
load :
#endif
            /*
            *   load current vector
            */
            cdeq = cd - gd*vd;
            if (model->VDMOStype == 1) {
                *(ckt->CKTrhs + here->VDMOSdNode) += cdeq;
                *(ckt->CKTrhs + here->VDIOposPrimeNode) -= cdeq;
            } else {
                *(ckt->CKTrhs + here->VDMOSdNode) -= cdeq;
                *(ckt->CKTrhs + here->VDIOposPrimeNode) += cdeq;
            }

            /*
            *   load matrix
            */
            *(here->VDMOSSsPtr) += gspr;
            *(here->VDMOSDdPtr) += gd;
            *(here->VDIORPrpPtr) += (gd + gspr);
            *(here->VDIOSrpPtr) -= gspr;
            *(here->VDIODrpPtr) -= gd;
            *(here->VDIORPsPtr) -= gspr;
            *(here->VDIORPdPtr) -= gd;
        }
    }
    return(OK);
}
Exemplo n.º 4
0
int
JFETload(GENmodel *inModel, CKTcircuit *ckt)
        /* actually load the current resistance value into the 
         * sparse matrix previously provided 
         */
{
    JFETmodel *model = (JFETmodel*)inModel;
    JFETinstance *here;
    double beta;
    double betap;
    double capgd;
    double capgs;
    double cd;
    double cdhat = 0.0;
    double cdrain;
    double cdreq;
    double ceq;
    double ceqgd;
    double ceqgs;
    double cg;
    double cgd;
    double cghat = 0.0;
    double csat;
    double czgd;
    double czgdf2;
    double czgs;
    double czgsf2;
    double delvds;
    double delvgd;
    double delvgs;
    double evgd;
    double evgs;
    double fcpb2;
    double gdpr;
    double gds;
    double geq;
    double ggd;
    double ggs;
    double gm;
    double gspr;
    double sarg;
    double twop;
    double vds;
    double vgd;
    double vgdt;
    double vgs;
    double vgst;
#ifndef PREDICTOR
    double xfact;
#endif
    /* Modification for Sydney University JFET model */
    double vto;
    double apart,cpart;
    double Bfac;
    /* end Sydney University mod. */
    int icheck;
    int ichk1;
    int error;
    
    double arg, vt_temp;

    double m;

    /*  loop through all the models */
    for( ; model != NULL; model = JFETnextModel(model)) {

        /* loop through all the instances of the model */
        for (here = JFETinstances(model); here != NULL ;
                here=JFETnextInstance(here)) {

            /*
             *  dc model parameters 
             */
            beta = here->JFETtBeta * here->JFETarea;
            gdpr=model->JFETdrainConduct*here->JFETarea;
            gspr=model->JFETsourceConduct*here->JFETarea;
            csat=here->JFETtSatCur*here->JFETarea;
            /*
             *    initialization
             */
            icheck=1;
            if( ckt->CKTmode & MODEINITSMSIG) {
                vgs= *(ckt->CKTstate0 + here->JFETvgs);
                vgd= *(ckt->CKTstate0 + here->JFETvgd);
            } else if (ckt->CKTmode & MODEINITTRAN) {
                vgs= *(ckt->CKTstate1 + here->JFETvgs);
                vgd= *(ckt->CKTstate1 + here->JFETvgd);
            } else if ( (ckt->CKTmode & MODEINITJCT) &&
                    (ckt->CKTmode & MODETRANOP) &&
                    (ckt->CKTmode & MODEUIC) ) {
                vds=model->JFETtype*here->JFETicVDS;
                vgs=model->JFETtype*here->JFETicVGS;
                vgd=vgs-vds;
            } else if ( (ckt->CKTmode & MODEINITJCT) &&
                    (here->JFEToff == 0)  ) {
                vgs = -1;
                vgd = -1;
            } else if( (ckt->CKTmode & MODEINITJCT) ||
                    ((ckt->CKTmode & MODEINITFIX) && (here->JFEToff))) {
                vgs = 0;
                vgd = 0;
            } else {
#ifndef PREDICTOR
                if(ckt->CKTmode & MODEINITPRED) {
                    xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1];
                    *(ckt->CKTstate0 + here->JFETvgs)= 
                            *(ckt->CKTstate1 + here->JFETvgs);
                    vgs=(1+xfact)* *(ckt->CKTstate1 + here->JFETvgs)-xfact*
                            *(ckt->CKTstate2 + here->JFETvgs);
                    *(ckt->CKTstate0 + here->JFETvgd)= 
                            *(ckt->CKTstate1 + here->JFETvgd);
                    vgd=(1+xfact)* *(ckt->CKTstate1 + here->JFETvgd)-xfact*
                            *(ckt->CKTstate2 + here->JFETvgd);
                    *(ckt->CKTstate0 + here->JFETcg)= 
                            *(ckt->CKTstate1 + here->JFETcg);
                    *(ckt->CKTstate0 + here->JFETcd)= 
                            *(ckt->CKTstate1 + here->JFETcd);
                    *(ckt->CKTstate0 + here->JFETcgd)=
                            *(ckt->CKTstate1 + here->JFETcgd);
                    *(ckt->CKTstate0 + here->JFETgm)=
                            *(ckt->CKTstate1 + here->JFETgm);
                    *(ckt->CKTstate0 + here->JFETgds)=
                            *(ckt->CKTstate1 + here->JFETgds);
                    *(ckt->CKTstate0 + here->JFETggs)=
                            *(ckt->CKTstate1 + here->JFETggs);
                    *(ckt->CKTstate0 + here->JFETggd)=
                            *(ckt->CKTstate1 + here->JFETggd);
                } else {
#endif /*PREDICTOR*/
                    /*
                     *  compute new nonlinear branch voltages 
                     */
                    vgs=model->JFETtype*
                        (*(ckt->CKTrhsOld+ here->JFETgateNode)-
                        *(ckt->CKTrhsOld+ 
                        here->JFETsourcePrimeNode));
                    vgd=model->JFETtype*
                        (*(ckt->CKTrhsOld+here->JFETgateNode)-
                        *(ckt->CKTrhsOld+
                        here->JFETdrainPrimeNode));
#ifndef PREDICTOR
                }
#endif /*PREDICTOR*/
                delvgs=vgs- *(ckt->CKTstate0 + here->JFETvgs);
                delvgd=vgd- *(ckt->CKTstate0 + here->JFETvgd);
                delvds=delvgs-delvgd;
                cghat= *(ckt->CKTstate0 + here->JFETcg)+ 
                        *(ckt->CKTstate0 + here->JFETggd)*delvgd+
                        *(ckt->CKTstate0 + here->JFETggs)*delvgs;
                cdhat= *(ckt->CKTstate0 + here->JFETcd)+
                        *(ckt->CKTstate0 + here->JFETgm)*delvgs+
                        *(ckt->CKTstate0 + here->JFETgds)*delvds-
                        *(ckt->CKTstate0 + here->JFETggd)*delvgd;
                /*
                 *   bypass if solution has not changed 
                 */
                if((ckt->CKTbypass) &&
                    (!(ckt->CKTmode & MODEINITPRED)) &&
                    (fabs(delvgs) < ckt->CKTreltol*MAX(fabs(vgs),
                        fabs(*(ckt->CKTstate0 + here->JFETvgs)))+
                        ckt->CKTvoltTol) )
                if ( (fabs(delvgd) < ckt->CKTreltol*MAX(fabs(vgd),
                        fabs(*(ckt->CKTstate0 + here->JFETvgd)))+
                        ckt->CKTvoltTol))
                if ( (fabs(cghat-*(ckt->CKTstate0 + here->JFETcg)) 
                        < ckt->CKTreltol*MAX(fabs(cghat),
                        fabs(*(ckt->CKTstate0 + here->JFETcg)))+
                        ckt->CKTabstol) ) 
                if ( /* hack - expression too big */
                    (fabs(cdhat-*(ckt->CKTstate0 + here->JFETcd))
                        < ckt->CKTreltol*MAX(fabs(cdhat),
                        fabs(*(ckt->CKTstate0 + here->JFETcd)))+
                        ckt->CKTabstol) ) {

                    /* we can do a bypass */
                    vgs= *(ckt->CKTstate0 + here->JFETvgs);
                    vgd= *(ckt->CKTstate0 + here->JFETvgd);
                    vds= vgs-vgd;
                    cg= *(ckt->CKTstate0 + here->JFETcg);
                    cd= *(ckt->CKTstate0 + here->JFETcd);
                    cgd= *(ckt->CKTstate0 + here->JFETcgd);
                    gm= *(ckt->CKTstate0 + here->JFETgm);
                    gds= *(ckt->CKTstate0 + here->JFETgds);
                    ggs= *(ckt->CKTstate0 + here->JFETggs);
                    ggd= *(ckt->CKTstate0 + here->JFETggd);
                    goto load;
                }
                /*
                 *  limit nonlinear branch voltages 
                 */
                ichk1=1;
                vgs = DEVpnjlim(vgs,*(ckt->CKTstate0 + here->JFETvgs),
                        (here->JFETtemp*CONSTKoverQ), here->JFETvcrit, &icheck);
                vgd = DEVpnjlim(vgd,*(ckt->CKTstate0 + here->JFETvgd),
                        (here->JFETtemp*CONSTKoverQ), here->JFETvcrit,&ichk1);
                if (ichk1 == 1) {
                    icheck=1;
                }
                vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->JFETvgs),
                        here->JFETtThreshold);
                vgd = DEVfetlim(vgd,*(ckt->CKTstate0 + here->JFETvgd),
                        here->JFETtThreshold);
            }
            /*
             *   determine dc current and derivatives 
             */
            vds=vgs-vgd;
            
            vt_temp=here->JFETtemp*CONSTKoverQ;
            if (vgs < -3*vt_temp) {
                arg=3*vt_temp/(vgs*CONSTe);
                arg = arg * arg * arg;
                cg = -csat*(1+arg)+ckt->CKTgmin*vgs;
                ggs = csat*3*arg/vgs+ckt->CKTgmin;
            } else {
                evgs = exp(vgs/vt_temp);
                ggs = csat*evgs/vt_temp+ckt->CKTgmin;
                cg = csat*(evgs-1)+ckt->CKTgmin*vgs;
            }
            
            if (vgd < -3*vt_temp) {
                arg=3*vt_temp/(vgd*CONSTe);
                arg = arg * arg * arg;
                cgd = -csat*(1+arg)+ckt->CKTgmin*vgd;
                ggd = csat*3*arg/vgd+ckt->CKTgmin;
            } else {
                evgd = exp(vgd/vt_temp);
                ggd = csat*evgd/vt_temp+ckt->CKTgmin;
                cgd = csat*(evgd-1)+ckt->CKTgmin*vgd;
            }
            
            cg = cg+cgd;

            /* Modification for Sydney University JFET model */
            vto = here->JFETtThreshold;
            if (vds >= 0) {
                vgst = vgs - vto;
                /*
                 * compute drain current and derivatives for normal mode
                 */
                if (vgst <= 0) {
                    /*
                     * normal mode, cutoff region
                     */
                    cdrain = 0;
                    gm = 0;
                    gds = 0;
                } else {
                    betap = beta*(1 + model->JFETlModulation*vds);
                    Bfac = model->JFETbFac;
                    if (vgst >= vds) {
                        /*
                         * normal mode, linear region
                         */
                        apart = 2*model->JFETb + 3*Bfac*(vgst - vds);
                        cpart = vds*(vds*(Bfac*vds - model->JFETb)+vgst*apart);
                        cdrain = betap*cpart;
                        gm = betap*vds*(apart + 3*Bfac*vgst);
                        gds = betap*(vgst - vds)*apart
                              + beta*model->JFETlModulation*cpart;
                    } else {
                        Bfac = vgst*Bfac;
                        gm = betap*vgst*(2*model->JFETb+3*Bfac);
                        /*
                         * normal mode, saturation region
                         */
                        cpart=vgst*vgst*(model->JFETb+Bfac);
                        cdrain = betap*cpart;
                        gds = model->JFETlModulation*beta*cpart;
                    }
                }
            } else {
                vgdt = vgd - vto;
                /*
                 * compute drain current and derivatives for inverse mode
                 */
                if (vgdt <= 0) {
                    /*
                     * inverse mode, cutoff region
                     */
                    cdrain = 0;
                    gm = 0;
                    gds = 0;
                } else {
                    betap = beta*(1 - model->JFETlModulation*vds);
                    Bfac = model->JFETbFac;
                    if (vgdt + vds >= 0) {
                        /*
                         * inverse mode, linear region
                         */
                        apart = 2*model->JFETb + 3*Bfac*(vgdt + vds);
                        cpart = vds*(-vds*(-Bfac*vds-model->JFETb)+vgdt*apart);
                        cdrain = betap*cpart;
                        gm = betap*vds*(apart + 3*Bfac*vgdt);
                        gds = betap*(vgdt + vds)*apart
                             - beta*model->JFETlModulation*cpart - gm;
                    } else {
                        Bfac = vgdt*Bfac;
                        gm = -betap*vgdt*(2*model->JFETb+3*Bfac);
                        /*
                         * inverse mode, saturation region
                         */
                        cpart=vgdt*vgdt*(model->JFETb+Bfac);
                        cdrain = - betap*cpart;
                        gds = model->JFETlModulation*beta*cpart-gm;
                    }
                }
            }

#ifdef notdef
            /* The original section is now commented out */
            /* end Sydney University mod */
            /*
             *   compute drain current and derivitives for normal mode 
             */
            if (vds >= 0) {
                vgst=vgs-here->JFETtThreshold;
                /*
                 *   normal mode, cutoff region 
                 */
                if (vgst <= 0) {
                    cdrain=0;
                    gm=0;
                    gds=0;
                } else {
                    betap=beta*(1+model->JFETlModulation*vds);
                    twob=betap+betap;
                    if (vgst <= vds) {
                        /*
                         *   normal mode, saturation region 
                         */
                        cdrain=betap*vgst*vgst;
                        gm=twob*vgst;
                        gds=model->JFETlModulation*beta*vgst*vgst;
                    } else {
                        /*
                         *   normal mode, linear region 
                         */
                        cdrain=betap*vds*(vgst+vgst-vds);
                        gm=twob*vds;
                        gds=twob*(vgst-vds)+model->JFETlModulation*beta*
                                vds*(vgst+vgst-vds);
                    }
                }
            } else {
                /*
                 *   compute drain current and derivitives for inverse mode 
                 */
                vgdt=vgd-here->JFETtThreshold;
                if (vgdt <= 0) {
                    /*
                     *   inverse mode, cutoff region 
                     */
                    cdrain=0;
                    gm=0;
                    gds=0;
                } else {
                    /*
                     *   inverse mode, saturation region 
                     */
                    betap=beta*(1-model->JFETlModulation*vds);
                    twob=betap+betap;
                    if (vgdt <= -vds) {
                        cdrain = -betap*vgdt*vgdt;
                        gm = -twob*vgdt;
                        gds = model->JFETlModulation*beta*vgdt*vgdt-gm;
                    } else {
                        /*
                         *  inverse mode, linear region 
                         */
                        cdrain=betap*vds*(vgdt+vgdt+vds);
                        gm=twob*vds;
                        gds=twob*vgdt-model->JFETlModulation*beta*vds*
                                (vgdt+vgdt+vds);
                    }
                }
            }
            /* end of original section, now deleted (replaced w/SU mod */
#endif

            /*
             *   compute equivalent drain current source 
             */
            cd=cdrain-cgd;
            if ( (ckt->CKTmode & (MODEDCTRANCURVE | MODETRAN | MODEAC | MODEINITSMSIG) ) ||
                    ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) ){
                /* 
                 *    charge storage elements 
                 */
                czgs=here->JFETtCGS*here->JFETarea;
                czgd=here->JFETtCGD*here->JFETarea;
                twop=here->JFETtGatePot+here->JFETtGatePot;
                fcpb2=here->JFETcorDepCap*here->JFETcorDepCap;
                czgsf2=czgs/model->JFETf2;
                czgdf2=czgd/model->JFETf2;
                if (vgs < here->JFETcorDepCap) {
                    sarg=sqrt(1-vgs/here->JFETtGatePot);
                    *(ckt->CKTstate0 + here->JFETqgs) = twop*czgs*(1-sarg);
                    capgs=czgs/sarg;
                } else {
                    *(ckt->CKTstate0 + here->JFETqgs) = czgs*here->JFETf1 +
                            czgsf2*(model->JFETf3 *(vgs-
                            here->JFETcorDepCap)+(vgs*vgs-fcpb2)/
                            (twop+twop));
                    capgs=czgsf2*(model->JFETf3+vgs/twop);
                }
                if (vgd < here->JFETcorDepCap) {
                    sarg=sqrt(1-vgd/here->JFETtGatePot);
                    *(ckt->CKTstate0 + here->JFETqgd) = twop*czgd*(1-sarg);
                    capgd=czgd/sarg;
                } else {
                    *(ckt->CKTstate0 + here->JFETqgd) = czgd*here->JFETf1+
                            czgdf2*(model->JFETf3* (vgd-
                            here->JFETcorDepCap)+(vgd*vgd-fcpb2)/
                            (twop+twop));
                    capgd=czgdf2*(model->JFETf3+vgd/twop);
                }
                /*
                 *   store small-signal parameters 
                 */
                if( (!(ckt->CKTmode & MODETRANOP)) || 
                        (!(ckt->CKTmode & MODEUIC)) ) {
                    if(ckt->CKTmode & MODEINITSMSIG) {
                        *(ckt->CKTstate0 + here->JFETqgs) = capgs;
                        *(ckt->CKTstate0 + here->JFETqgd) = capgd;
                        continue; /*go to 1000*/
                    }
                    /*
                     *   transient analysis 
                     */
                    if(ckt->CKTmode & MODEINITTRAN) {
                        *(ckt->CKTstate1 + here->JFETqgs) =
                                *(ckt->CKTstate0 + here->JFETqgs);
                        *(ckt->CKTstate1 + here->JFETqgd) =
                                *(ckt->CKTstate0 + here->JFETqgd);
                    }
                    error = NIintegrate(ckt,&geq,&ceq,capgs,here->JFETqgs);
                    if(error) return(error);
                    ggs = ggs + geq;
                    cg = cg + *(ckt->CKTstate0 + here->JFETcqgs);
                    error = NIintegrate(ckt,&geq,&ceq,capgd,here->JFETqgd);
                    if(error) return(error);
                    ggd = ggd + geq;
                    cg = cg + *(ckt->CKTstate0 + here->JFETcqgd);
                    cd = cd - *(ckt->CKTstate0 + here->JFETcqgd);
                    cgd = cgd + *(ckt->CKTstate0 + here->JFETcqgd);
                    if (ckt->CKTmode & MODEINITTRAN) {
                        *(ckt->CKTstate1 + here->JFETcqgs) =
                                *(ckt->CKTstate0 + here->JFETcqgs);
                        *(ckt->CKTstate1 + here->JFETcqgd) =
                                *(ckt->CKTstate0 + here->JFETcqgd);
                    }
                }
            }
            /*
             *  check convergence 
             */
            if( (!(ckt->CKTmode & MODEINITFIX)) |
                (!(ckt->CKTmode & MODEUIC))) {
                if((icheck == 1) ||
                   (fabs(cghat-cg) >= ckt->CKTreltol *
                    MAX(fabs(cghat), fabs(cg)) + ckt->CKTabstol) ||
                   (fabs(cdhat-cd) > ckt->CKTreltol *
                    MAX(fabs(cdhat), fabs(cd)) + ckt->CKTabstol)) {
                    ckt->CKTnoncon++;
                    ckt->CKTtroubleElt = (GENinstance *) here;
                }
            }
            *(ckt->CKTstate0 + here->JFETvgs) = vgs;
            *(ckt->CKTstate0 + here->JFETvgd) = vgd;
            *(ckt->CKTstate0 + here->JFETcg) = cg;
            *(ckt->CKTstate0 + here->JFETcd) = cd;
            *(ckt->CKTstate0 + here->JFETcgd) = cgd;
            *(ckt->CKTstate0 + here->JFETgm) = gm;
            *(ckt->CKTstate0 + here->JFETgds) = gds;
            *(ckt->CKTstate0 + here->JFETggs) = ggs;
            *(ckt->CKTstate0 + here->JFETggd) = ggd;
            /*
             *    load current vector
             */
load:

            m = here->JFETm;

            ceqgd=model->JFETtype*(cgd-ggd*vgd);
            ceqgs=model->JFETtype*((cg-cgd)-ggs*vgs);
            cdreq=model->JFETtype*((cd+cgd)-gds*vds-gm*vgs);
            *(ckt->CKTrhs + here->JFETgateNode) += m * (-ceqgs-ceqgd);
            *(ckt->CKTrhs + here->JFETdrainPrimeNode) +=
                    m * (-cdreq+ceqgd);
            *(ckt->CKTrhs + here->JFETsourcePrimeNode) +=
                    m * (cdreq+ceqgs);
            /*
             *    load y matrix 
             */
            *(here->JFETdrainDrainPrimePtr)        += m * (-gdpr);
            *(here->JFETgateDrainPrimePtr)         += m * (-ggd);
            *(here->JFETgateSourcePrimePtr)        += m * (-ggs);
            *(here->JFETsourceSourcePrimePtr)      += m * (-gspr);
            *(here->JFETdrainPrimeDrainPtr)        += m * (-gdpr);
            *(here->JFETdrainPrimeGatePtr)         += m * (gm-ggd);
            *(here->JFETdrainPrimeSourcePrimePtr)  += m * (-gds-gm);
            *(here->JFETsourcePrimeGatePtr)        += m * (-ggs-gm);
            *(here->JFETsourcePrimeSourcePtr)      += m * (-gspr);
            *(here->JFETsourcePrimeDrainPrimePtr)  += m * (-gds);
            *(here->JFETdrainDrainPtr)             += m * (gdpr);
            *(here->JFETgateGatePtr)               += m * (ggd+ggs);
            *(here->JFETsourceSourcePtr)           += m * (gspr);
            *(here->JFETdrainPrimeDrainPrimePtr)   += m * (gdpr+gds+ggd);
            *(here->JFETsourcePrimeSourcePrimePtr) += m * (gspr+gds+gm+ggs);
        }
    }
    return(OK);
}
Exemplo n.º 5
0
int
JFET2load(GENmodel *inModel, CKTcircuit *ckt)
        /* actually load the current resistance value into the 
         * sparse matrix previously provided 
         */
{
    JFET2model *model = (JFET2model*)inModel;
    JFET2instance *here;
    double capgd;
    double capgs;
    double cd;
    double cdhat = 0.0;
    double cdreq;
    double ceq;
    double ceqgd;
    double ceqgs;
    double cg;
    double cgd;
    double cghat = 0.0;
    double delvds;
    double delvgd;
    double delvgs;
    double gdpr;
    double gds;
    double geq;
    double ggd;
    double ggs;
    double gm;
    double gspr;
    double vds;
    double vgd;
    double vgs;
    double xfact;
    int icheck;
    int ichk1;
    int error;

    double m;

    /*  loop through all the models */
    for( ; model != NULL; model = model->JFET2nextModel ) {

        /* loop through all the instances of the model */
        for (here = model->JFET2instances; here != NULL ;
                here=here->JFET2nextInstance) {
             if (here->JFET2owner != ARCHme) continue;
            /*
             *  dc model parameters 
             */
            gdpr=model->JFET2drainConduct*here->JFET2area;
            gspr=model->JFET2sourceConduct*here->JFET2area;
            /*
             *    initialization
             */
            icheck=1;
            if( ckt->CKTmode & MODEINITSMSIG) {
                vgs= *(ckt->CKTstate0 + here->JFET2vgs);
                vgd= *(ckt->CKTstate0 + here->JFET2vgd);
            } else if (ckt->CKTmode & MODEINITTRAN) {
                vgs= *(ckt->CKTstate1 + here->JFET2vgs);
                vgd= *(ckt->CKTstate1 + here->JFET2vgd);
            } else if ( (ckt->CKTmode & MODEINITJCT) &&
                    (ckt->CKTmode & MODETRANOP) &&
                    (ckt->CKTmode & MODEUIC) ) {
                vds=model->JFET2type*here->JFET2icVDS;
                vgs=model->JFET2type*here->JFET2icVGS;
                vgd=vgs-vds;
            } else if ( (ckt->CKTmode & MODEINITJCT) &&
                    (here->JFET2off == 0)  ) {
                vgs = -1;
                vgd = -1;
            } else if( (ckt->CKTmode & MODEINITJCT) ||
                    ((ckt->CKTmode & MODEINITFIX) && (here->JFET2off))) {
                vgs = 0;
                vgd = 0;
            } else {
#ifndef PREDICTOR
                if(ckt->CKTmode & MODEINITPRED) {
                    xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1];
                    *(ckt->CKTstate0 + here->JFET2vgs)= 
                            *(ckt->CKTstate1 + here->JFET2vgs);
                    vgs=(1+xfact)* *(ckt->CKTstate1 + here->JFET2vgs)-xfact*
                            *(ckt->CKTstate2 + here->JFET2vgs);
                    *(ckt->CKTstate0 + here->JFET2vgd)= 
                            *(ckt->CKTstate1 + here->JFET2vgd);
                    vgd=(1+xfact)* *(ckt->CKTstate1 + here->JFET2vgd)-xfact*
                            *(ckt->CKTstate2 + here->JFET2vgd);
                    *(ckt->CKTstate0 + here->JFET2cg)= 
                            *(ckt->CKTstate1 + here->JFET2cg);
                    *(ckt->CKTstate0 + here->JFET2cd)= 
                            *(ckt->CKTstate1 + here->JFET2cd);
                    *(ckt->CKTstate0 + here->JFET2cgd)=
                            *(ckt->CKTstate1 + here->JFET2cgd);
                    *(ckt->CKTstate0 + here->JFET2gm)=
                            *(ckt->CKTstate1 + here->JFET2gm);
                    *(ckt->CKTstate0 + here->JFET2gds)=
                            *(ckt->CKTstate1 + here->JFET2gds);
                    *(ckt->CKTstate0 + here->JFET2ggs)=
                            *(ckt->CKTstate1 + here->JFET2ggs);
                    *(ckt->CKTstate0 + here->JFET2ggd)=
                            *(ckt->CKTstate1 + here->JFET2ggd);
                } else {
#endif /*PREDICTOR*/
                    /*
                     *  compute new nonlinear branch voltages 
                     */
                    vgs=model->JFET2type*
                        (*(ckt->CKTrhsOld+ here->JFET2gateNode)-
                        *(ckt->CKTrhsOld+ 
                        here->JFET2sourcePrimeNode));
                    vgd=model->JFET2type*
                        (*(ckt->CKTrhsOld+here->JFET2gateNode)-
                        *(ckt->CKTrhsOld+
                        here->JFET2drainPrimeNode));
#ifndef PREDICTOR
                }
#endif /*PREDICTOR*/
                delvgs=vgs- *(ckt->CKTstate0 + here->JFET2vgs);
                delvgd=vgd- *(ckt->CKTstate0 + here->JFET2vgd);
                delvds=delvgs-delvgd;
                cghat= *(ckt->CKTstate0 + here->JFET2cg)+ 
                        *(ckt->CKTstate0 + here->JFET2ggd)*delvgd+
                        *(ckt->CKTstate0 + here->JFET2ggs)*delvgs;
                cdhat= *(ckt->CKTstate0 + here->JFET2cd)+
                        *(ckt->CKTstate0 + here->JFET2gm)*delvgs+
                        *(ckt->CKTstate0 + here->JFET2gds)*delvds-
                        *(ckt->CKTstate0 + here->JFET2ggd)*delvgd;
                /*
                 *   bypass if solution has not changed 
                 */
                if((ckt->CKTbypass) &&
                    (!(ckt->CKTmode & MODEINITPRED)) &&
                    (fabs(delvgs) < ckt->CKTreltol*MAX(fabs(vgs),
                        fabs(*(ckt->CKTstate0 + here->JFET2vgs)))+
                        ckt->CKTvoltTol) )
        if ( (fabs(delvgd) < ckt->CKTreltol*MAX(fabs(vgd),
                        fabs(*(ckt->CKTstate0 + here->JFET2vgd)))+
                        ckt->CKTvoltTol))
        if ( (fabs(cghat-*(ckt->CKTstate0 + here->JFET2cg)) 
                        < ckt->CKTreltol*MAX(fabs(cghat),
                        fabs(*(ckt->CKTstate0 + here->JFET2cg)))+
                        ckt->CKTabstol) ) if ( /* hack - expression too big */
                    (fabs(cdhat-*(ckt->CKTstate0 + here->JFET2cd))
                        < ckt->CKTreltol*MAX(fabs(cdhat),
                        fabs(*(ckt->CKTstate0 + here->JFET2cd)))+
                        ckt->CKTabstol) ) {

                    /* we can do a bypass */
                    vgs= *(ckt->CKTstate0 + here->JFET2vgs);
                    vgd= *(ckt->CKTstate0 + here->JFET2vgd);
                    vds= vgs-vgd;
                    cg= *(ckt->CKTstate0 + here->JFET2cg);
                    cd= *(ckt->CKTstate0 + here->JFET2cd);
                    cgd= *(ckt->CKTstate0 + here->JFET2cgd);
                    gm= *(ckt->CKTstate0 + here->JFET2gm);
                    gds= *(ckt->CKTstate0 + here->JFET2gds);
                    ggs= *(ckt->CKTstate0 + here->JFET2ggs);
                    ggd= *(ckt->CKTstate0 + here->JFET2ggd);
                    goto load;
                }
                /*
                 *  limit nonlinear branch voltages 
                 */
                ichk1=1;
                vgs = DEVpnjlim(vgs,*(ckt->CKTstate0 + here->JFET2vgs),
                        (here->JFET2temp*CONSTKoverQ), here->JFET2vcrit, &icheck);
                vgd = DEVpnjlim(vgd,*(ckt->CKTstate0 + here->JFET2vgd),
                        (here->JFET2temp*CONSTKoverQ), here->JFET2vcrit,&ichk1);
                if (ichk1 == 1) {
                    icheck=1;
                }
                vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->JFET2vgs),
                        model->JFET2vto);
                vgd = DEVfetlim(vgd,*(ckt->CKTstate0 + here->JFET2vgd),
                        model->JFET2vto);
            }
            /*
             *   determine dc current and derivatives 
             */
            vds=vgs-vgd;
            if (vds < 0.0) {
               cd = -PSids(ckt, model, here, vgd, vgs,
                            &cgd, &cg, &ggd, &ggs, &gm, &gds);
               gds += gm;
               gm  = -gm;
            } else {
               cd =  PSids(ckt, model, here, vgs, vgd, 
                            &cg, &cgd, &ggs, &ggd, &gm, &gds);
            }
            cg = cg + cgd;
            cd = cd - cgd;

            if ( (ckt->CKTmode & (MODETRAN | MODEAC | MODEINITSMSIG) ) ||
                    ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) ){
                /* 
                 *    charge storage elements 
                 */
                double capds = model->JFET2capds*here->JFET2area;

                PScharge(ckt, model, here, vgs, vgd, &capgs, &capgd);

                *(ckt->CKTstate0 + here->JFET2qds) = capds * vds;
            
                /*
                 *   store small-signal parameters 
                 */
                if( (!(ckt->CKTmode & MODETRANOP)) || 
                        (!(ckt->CKTmode & MODEUIC)) ) {
                    if(ckt->CKTmode & MODEINITSMSIG) {
                        *(ckt->CKTstate0 + here->JFET2qgs) = capgs;
                        *(ckt->CKTstate0 + here->JFET2qgd) = capgd;
                        *(ckt->CKTstate0 + here->JFET2qds) = capds;
                        continue; /*go to 1000*/
                    }
                    /*
                     *   transient analysis 
                     */
                    if(ckt->CKTmode & MODEINITTRAN) {
                        *(ckt->CKTstate1 + here->JFET2qgs) =
                                *(ckt->CKTstate0 + here->JFET2qgs);
                        *(ckt->CKTstate1 + here->JFET2qgd) =
                                *(ckt->CKTstate0 + here->JFET2qgd);
                        *(ckt->CKTstate1 + here->JFET2qds) =
                                *(ckt->CKTstate0 + here->JFET2qds);
                    }
                    error = NIintegrate(ckt,&geq,&ceq,capgs,here->JFET2qgs);
                    if(error) return(error);
                    ggs = ggs + geq;
                    cg = cg + *(ckt->CKTstate0 + here->JFET2cqgs);
                    error = NIintegrate(ckt,&geq,&ceq,capgd,here->JFET2qgd);
                    if(error) return(error);
                    ggd = ggd + geq;
                    cg = cg + *(ckt->CKTstate0 + here->JFET2cqgd);
                    cd = cd - *(ckt->CKTstate0 + here->JFET2cqgd);
                    cgd = cgd + *(ckt->CKTstate0 + here->JFET2cqgd);
                    error = NIintegrate(ckt,&geq,&ceq,capds,here->JFET2qds);
                    cd = cd + *(ckt->CKTstate0 + here->JFET2cqds);
                    if(error) return(error);
                    if (ckt->CKTmode & MODEINITTRAN) {
                        *(ckt->CKTstate1 + here->JFET2cqgs) =
                                *(ckt->CKTstate0 + here->JFET2cqgs);
                        *(ckt->CKTstate1 + here->JFET2cqgd) =
                                *(ckt->CKTstate0 + here->JFET2cqgd);
                        *(ckt->CKTstate1 + here->JFET2cqds) =
                                *(ckt->CKTstate0 + here->JFET2cqds);
                    }
                }
            }
            /*
             *  check convergence 
             */
            if( (!(ckt->CKTmode & MODEINITFIX)) | (!(ckt->CKTmode & MODEUIC))) {
                if((icheck == 1) ||
		   (fabs(cghat-cg) >= ckt->CKTreltol*
		    MAX(fabs(cghat),fabs(cg))+ckt->CKTabstol) ||
		   (fabs(cdhat-cd) > ckt->CKTreltol*
		    MAX(fabs(cdhat),fabs(cd))+ckt->CKTabstol)) {
                    ckt->CKTnoncon++;
		    ckt->CKTtroubleElt = (GENinstance *) here;
                }
            }
            *(ckt->CKTstate0 + here->JFET2vgs) = vgs;
            *(ckt->CKTstate0 + here->JFET2vgd) = vgd;
            *(ckt->CKTstate0 + here->JFET2cg) = cg;
            *(ckt->CKTstate0 + here->JFET2cd) = cd;
            *(ckt->CKTstate0 + here->JFET2cgd) = cgd;
            *(ckt->CKTstate0 + here->JFET2gm) = gm;
            *(ckt->CKTstate0 + here->JFET2gds) = gds;
            *(ckt->CKTstate0 + here->JFET2ggs) = ggs;
            *(ckt->CKTstate0 + here->JFET2ggd) = ggd;
            /*
             *    load current vector
             */
load:

            m = here->JFET2m;

            ceqgd=model->JFET2type*(cgd-ggd*vgd);
            ceqgs=model->JFET2type*((cg-cgd)-ggs*vgs);
            cdreq=model->JFET2type*((cd+cgd)-gds*vds-gm*vgs);
            *(ckt->CKTrhs + here->JFET2gateNode) += m * (-ceqgs-ceqgd);
            *(ckt->CKTrhs + here->JFET2drainPrimeNode) +=
                    m * (-cdreq+ceqgd);
            *(ckt->CKTrhs + here->JFET2sourcePrimeNode) +=
                    m * (cdreq+ceqgs);
            /*
             *    load y matrix 
             */
            *(here->JFET2drainDrainPrimePtr)        += m * (-gdpr);
            *(here->JFET2gateDrainPrimePtr)         += m * (-ggd);
            *(here->JFET2gateSourcePrimePtr)        += m * (-ggs);
            *(here->JFET2sourceSourcePrimePtr)      += m * (-gspr);
            *(here->JFET2drainPrimeDrainPtr)        += m * (-gdpr);
            *(here->JFET2drainPrimeGatePtr)         += m * (gm-ggd);
            *(here->JFET2drainPrimeSourcePrimePtr)  += m * (-gds-gm);
            *(here->JFET2sourcePrimeGatePtr)        += m * (-ggs-gm);
            *(here->JFET2sourcePrimeSourcePtr)      += m * (-gspr);
            *(here->JFET2sourcePrimeDrainPrimePtr)  += m * (-gds);
            *(here->JFET2drainDrainPtr)             += m * (gdpr);
            *(here->JFET2gateGatePtr)               += m * (ggd+ggs);
            *(here->JFET2sourceSourcePtr)           += m * (gspr);
            *(here->JFET2drainPrimeDrainPrimePtr)   += m * (gdpr+gds+ggd);
            *(here->JFET2sourcePrimeSourcePrimePtr) += m * (gspr+gds+gm+ggs);
        }
    }
    return(OK);
}
Exemplo n.º 6
0
int
MOS1load(GENmodel *inModel, CKTcircuit *ckt)
        /* actually load the current value into the 
         * sparse matrix previously provided 
         */
{
    MOS1model *model = (MOS1model *) inModel;
    MOS1instance *here;
    double Beta;
    double DrainSatCur;
    double EffectiveLength;
    double GateBulkOverlapCap;
    double GateDrainOverlapCap;
    double GateSourceOverlapCap;
    double OxideCap;
    double SourceSatCur;
    double arg;
    double cbhat;
    double cdhat;
    double cdrain;
    double cdreq;
    double ceq;
    double ceqbd;
    double ceqbs;
    double ceqgb;
    double ceqgd;
    double ceqgs;
    double delvbd;
    double delvbs;
    double delvds;
    double delvgd;
    double delvgs;
    double evbd;
    double evbs;
    double gcgb;
    double gcgd;
    double gcgs;
    double geq;
    double sarg;
    double sargsw;
    double vbd;
    double vbs;
    double vds;
    double vdsat;
    double vgb1;
    double vgb;
    double vgd1;
    double vgd;
    double vgdo;
    double vgs1;
    double vgs;
    double von;
    double vt;
    double xfact = 0.0;
    int xnrm;
    int xrev;
    double capgs = 0.0;   /* total gate-source capacitance */
    double capgd = 0.0;   /* total gate-drain capacitance */
    double capgb = 0.0;   /* total gate-bulk capacitance */
    int Check;
#ifndef NOBYPASS    
    double tempv;
#endif /*NOBYPASS*/    
    int error;
 #ifdef CAPBYPASS
    int senflag;
#endif /*CAPBYPASS*/           
    int SenCond;



#ifdef CAPBYPASS
    senflag = 0;
    if(ckt->CKTsenInfo && ckt->CKTsenInfo->SENstatus == PERTURBATION &&
        (ckt->CKTsenInfo->SENmode & (ACSEN | TRANSEN))) {
        senflag = 1;
    }
#endif /* CAPBYPASS */ 

    /*  loop through all the MOS1 device models */
    for( ; model != NULL; model = model->MOS1nextModel ) {

        /* loop through all the instances of the model */
        for (here = model->MOS1instances; here != NULL ;
	     here=here->MOS1nextInstance) {
	    if (here->MOS1owner != ARCHme) continue;

            vt = CONSTKoverQ * here->MOS1temp;
            Check=1;
            if(ckt->CKTsenInfo){
#ifdef SENSDEBUG
                printf("MOS1load \n");
#endif /* SENSDEBUG */

                if((ckt->CKTsenInfo->SENstatus == PERTURBATION)&&
		   (here->MOS1senPertFlag == OFF))continue;

            }
            SenCond = ckt->CKTsenInfo && here->MOS1senPertFlag;

/*
  
*/

            /* first, we compute a few useful values - these could be
             * pre-computed, but for historical reasons are still done
             * here.  They may be moved at the expense of instance size
             */

            EffectiveLength=here->MOS1l - 2*model->MOS1latDiff;
            
            if( (here->MOS1tSatCurDens == 0) || 
                    (here->MOS1drainArea == 0) ||
                    (here->MOS1sourceArea == 0)) {
                DrainSatCur = here->MOS1m * here->MOS1tSatCur;
                SourceSatCur = here->MOS1m * here->MOS1tSatCur;
            } else {
                DrainSatCur = here->MOS1tSatCurDens * 
                        here->MOS1m * here->MOS1drainArea;
                SourceSatCur = here->MOS1tSatCurDens * 
                        here->MOS1m * here->MOS1sourceArea;
            }
            GateSourceOverlapCap = model->MOS1gateSourceOverlapCapFactor * 
                    here->MOS1m * here->MOS1w;
            GateDrainOverlapCap = model->MOS1gateDrainOverlapCapFactor * 
                    here->MOS1m * here->MOS1w;
            GateBulkOverlapCap = model->MOS1gateBulkOverlapCapFactor * 
                    here->MOS1m * EffectiveLength;
            Beta = here->MOS1tTransconductance * here->MOS1m *
                    here->MOS1w/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
             * so we either predict them or recover them from last iteration
             * These are the two most common cases - either a prediction
             * step or the general iteration step and they
             * share some code, so we put them first - others later on
             */

            if(SenCond){
#ifdef SENSDEBUG
                printf("MOS1senPertFlag = ON \n");
#endif /* SENSDEBUG */
                if((ckt->CKTsenInfo->SENmode == TRANSEN) &&
		   (ckt->CKTmode & MODEINITTRAN)) {
                    vgs = *(ckt->CKTstate1 + here->MOS1vgs);
                    vds = *(ckt->CKTstate1 + here->MOS1vds);
                    vbs = *(ckt->CKTstate1 + here->MOS1vbs);
                    vbd = *(ckt->CKTstate1 + here->MOS1vbd);
                    vgb = vgs - vbs;
                    vgd = vgs - vds;
                }
                else if (ckt->CKTsenInfo->SENmode == ACSEN){
                    vgb = model->MOS1type * ( 
                        *(ckt->CKTrhsOp+here->MOS1gNode) -
                        *(ckt->CKTrhsOp+here->MOS1bNode));
                    vbs = *(ckt->CKTstate0 + here->MOS1vbs);
                    vbd = *(ckt->CKTstate0 + here->MOS1vbd);
                    vgd = vgb + vbd ;
                    vgs = vgb + vbs ;
                    vds = vbs - vbd ;
                }
                else{
                    vgs = *(ckt->CKTstate0 + here->MOS1vgs);
                    vds = *(ckt->CKTstate0 + here->MOS1vds);
                    vbs = *(ckt->CKTstate0 + here->MOS1vbs);
                    vbd = *(ckt->CKTstate0 + here->MOS1vbd);
                    vgb = vgs - vbs;
                    vgd = vgs - vds;
                }
#ifdef SENSDEBUG
                printf(" vbs = %.7e ,vbd = %.7e,vgb = %.7e\n",vbs,vbd,vgb);
                printf(" vgs = %.7e ,vds = %.7e,vgd = %.7e\n",vgs,vds,vgd);
#endif /* SENSDEBUG */
                goto next1;
            }


            if((ckt->CKTmode & (MODEINITFLOAT | MODEINITPRED | MODEINITSMSIG
				| 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);
                    vbs = (1+xfact)* (*(ckt->CKTstate1 + here->MOS1vbs))
			-(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);
                    vds = (1+xfact)* (*(ckt->CKTstate1 + 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 * ( 
                        *(ckt->CKTrhsOld+here->MOS1gNode) -
                        *(ckt->CKTrhsOld+here->MOS1sNodePrime));
                    vds = model->MOS1type * ( 
                        *(ckt->CKTrhsOld+here->MOS1dNodePrime) -
                        *(ckt->CKTrhsOld+here->MOS1sNodePrime));
#ifndef PREDICTOR
                }
#endif /* PREDICTOR */

                /* now some common crunching for some more useful quantities */

                vbd=vbs-vds;
                vgd=vgs-vds;
                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);
                delvds = vds - *(ckt->CKTstate0 + here->MOS1vds);
                delvgd = vgd-vgdo;

                /* these are needed for convergence testing */

                if (here->MOS1mode >= 0) {
                    cdhat=
                        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->MOS1gds * delvds ;
                }
                cbhat=
                    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);
                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;
		}
#endif /*NOBYPASS*/

/*
  
*/

                /* ok - bypass is out, do it the hard way */

                von = model->MOS1type * here->MOS1von;

#ifndef NODELIMITING
                /* 
                 * limiting
                 *  we want to keep device voltages from changing
                 * so fast that the exponentials churn out overflows
                 * and similar rudeness
                 */

                if(*(ckt->CKTstate0 + here->MOS1vds) >=0) {
                    vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->MOS1vgs)
				    ,von);
                    vds = vgs - vgd;
                    vds = DEVlimvds(vds,*(ckt->CKTstate0 + here->MOS1vds));
                    vgd = vgs - vds;
                } else {
                    vgd = DEVfetlim(vgd,vgdo,von);
                    vds = vgs - vgd;
                    if(!(ckt->CKTfixLimit)) {
                        vds = -DEVlimvds(-vds,-(*(ckt->CKTstate0 + 
						  here->MOS1vds)));
                    }
                    vgs = vgd + vds;
                }
                if(vds >= 0) {
                    vbs = DEVpnjlim(vbs,*(ckt->CKTstate0 + here->MOS1vbs),
				    vt,here->MOS1sourceVcrit,&Check);
                    vbd = vbs-vds;
                } else {
                    vbd = DEVpnjlim(vbd,*(ckt->CKTstate0 + here->MOS1vbd),
				    vt,here->MOS1drainVcrit,&Check);
                    vbs = vbd + vds;
                }
#endif /*NODELIMITING*/
/*
  
*/

            } else {

                /* ok - not one of the simple cases, so we have to
                 * look at all of the possibilities for why we were
                 * called.  We still just initialize the three voltages
                 */

                if((ckt->CKTmode & MODEINITJCT) && !here->MOS1off) {
                    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)))) {
                        vbs = -1;
                        vgs = model->MOS1type * here->MOS1tVto;
                        vds = 0;
                    }
                } else {
                    vbs=vgs=vds=0;
                } 
            }
/*
  
*/

            /*
             * now all the preliminaries are over - we can start doing the
             * real work
             */
            vbd = vbs - vds;
            vgd = vgs - vds;
            vgb = vgs - vbs;


            /*
             * bulk-source and bulk-drain diodes
             *   here we just evaluate the ideal diode current and the
             *   corresponding derivative (conductance).
             */
next1:      if(vbs <= -3*vt) {
                here->MOS1gbs = ckt->CKTgmin;
                here->MOS1cbs = here->MOS1gbs*vbs-SourceSatCur;
            } else {
                evbs = exp(MIN(MAX_EXP_ARG,vbs/vt));
                here->MOS1gbs = SourceSatCur*evbs/vt + ckt->CKTgmin;
                here->MOS1cbs = SourceSatCur*(evbs-1) + ckt->CKTgmin*vbs;
            }
            if(vbd <= -3*vt) {
                here->MOS1gbd = ckt->CKTgmin;
                here->MOS1cbd = here->MOS1gbd*vbd-DrainSatCur;
            } else {
                evbd = exp(MIN(MAX_EXP_ARG,vbd/vt));
                here->MOS1gbd = DrainSatCur*evbd/vt + ckt->CKTgmin;
                here->MOS1cbd = DrainSatCur*(evbd-1) + ckt->CKTgmin*vbd;
            }
            /* now to determine whether the user was able to correctly
             * identify the source and drain of his device
             */
            if(vds >= 0) {
                /* normal mode */
                here->MOS1mode = 1;
            } else {
                /* inverse mode */
                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;

                if ((here->MOS1mode==1?vbs:vbd) <= 0 ) {
                    sarg=sqrt(here->MOS1tPhi-(here->MOS1mode==1?vbs:vbd));
                } else {
                    sarg=sqrt(here->MOS1tPhi);
                    sarg=sarg-(here->MOS1mode==1?vbs:vbd)/(sarg+sarg);
                    sarg=MAX(0,sarg);
                }
                von=(here->MOS1tVbi*model->MOS1type)+model->MOS1gamma*sarg;
                vgst=(here->MOS1mode==1?vgs:vgd)-von;
                vdsat=MAX(vgst,0);
                if (sarg <= 0) {
                    arg=0;
                } else {
                    arg=model->MOS1gamma/(sarg+sarg);
                }
                if (vgst <= 0) {
                    /*
                     *     cutoff region
                     */
                    cdrain=0;
                    here->MOS1gm=0;
                    here->MOS1gds=0;
                    here->MOS1gmbs=0;
                } else{
                    /*
                     *     saturation region
                     */
                    betap=Beta*(1+model->MOS1lambda*(vds*here->MOS1mode));
                    if (vgst <= (vds*here->MOS1mode)){
                        cdrain=betap*vgst*vgst*.5;
                        here->MOS1gm=betap*vgst;
                        here->MOS1gds=model->MOS1lambda*Beta*vgst*vgst*.5;
                        here->MOS1gmbs=here->MOS1gm*arg;
                    } else {
			/*
			 *     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;
                    }
                }
                /*
                 *     finished
                 */
            }
/*
  
*/

            /* now deal with n vs p polarity */

            here->MOS1von = model->MOS1type * von;
            here->MOS1vdsat = model->MOS1type * vdsat;
            /* line 490 */
            /*
             *  COMPUTE EQUIVALENT DRAIN CURRENT SOURCE
             */
            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
                 *
                 * the basic equations are not hard, but the implementation
                 * is somewhat long in an attempt to avoid log/exponential
                 * evaluations
                 */
                /*
                 *  charge storage elements
                 *
                 *.. bulk-drain and bulk-source depletion capacitances
                 */
#ifdef CAPBYPASS
                if(((ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) ||
                        fabs(delvbs) >= ckt->CKTreltol * MAX(fabs(vbs),
                        fabs(*(ckt->CKTstate0+here->MOS1vbs)))+
                        ckt->CKTvoltTol)|| senflag)
#endif /*CAPBYPASS*/
		 
                {
                    /* can't bypass the diode capacitance calculations */
#ifdef CAPZEROBYPASS		    
                    if(here->MOS1Cbs != 0 || here->MOS1Cbssw != 0 ) {
#endif /*CAPZEROBYPASS*/		    
			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!)
			     */
#ifndef NOSQRT
			    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 {
#endif /*NOSQRT*/
				    sarg = exp(-model->MOS1bulkJctBotGradingCoeff*
					       log(arg));
#ifndef NOSQRT
				}
				if(model->MOS1bulkJctSideGradingCoeff == .5) {
				    sargsw = 1/sqrt(arg);
				} else {
#endif /*NOSQRT*/
				    sargsw =exp(-model->MOS1bulkJctSideGradingCoeff*
						log(arg));
#ifndef NOSQRT
				}
			    }
#endif /*NOSQRT*/
			    *(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;
			}
#ifdef CAPZEROBYPASS						
                    } else {
			*(ckt->CKTstate0 + here->MOS1qbs) = 0;
                        here->MOS1capbs=0;
                    }
#endif /*CAPZEROBYPASS*/		    
                }
#ifdef CAPBYPASS
                    if(((ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) ||
                        fabs(delvbd) >= ckt->CKTreltol * MAX(fabs(vbd),
                        fabs(*(ckt->CKTstate0+here->MOS1vbd)))+
                        ckt->CKTvoltTol)|| senflag)
#endif /*CAPBYPASS*/		    	
	
                    /* can't bypass the diode capacitance calculations */
                {
#ifdef CAPZEROBYPASS					
                    if(here->MOS1Cbd != 0 || here->MOS1Cbdsw != 0 ) {
#endif /*CAPZEROBYPASS*/		    		    
			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!)
			     */
#ifndef NOSQRT
			    if(model->MOS1bulkJctBotGradingCoeff == .5 &&
			       model->MOS1bulkJctSideGradingCoeff == .5) {
				sarg = sargsw = 1/sqrt(arg);
			    } else {
				if(model->MOS1bulkJctBotGradingCoeff == .5) {
				    sarg = 1/sqrt(arg);
				} else {
#endif /*NOSQRT*/
				    sarg = exp(-model->MOS1bulkJctBotGradingCoeff*
					       log(arg));
#ifndef NOSQRT
				}
				if(model->MOS1bulkJctSideGradingCoeff == .5) {
				    sargsw = 1/sqrt(arg);
				} else {
#endif /*NOSQRT*/
				    sargsw =exp(-model->MOS1bulkJctSideGradingCoeff*
						log(arg));
#ifndef NOSQRT
				}
			    }
#endif /*NOSQRT*/
			    *(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;
			}
#ifdef CAPZEROBYPASS						
		    } else {
			*(ckt->CKTstate0 + here->MOS1qbd) = 0;
			here->MOS1capbd = 0;
		    }
#endif /*CAPZEROBYPASS*/		    		    
                }
/*
  
*/

                if(SenCond && (ckt->CKTsenInfo->SENmode==TRANSEN)) goto next2;

                if ( (ckt->CKTmode & MODETRAN) || ( (ckt->CKTmode&MODEINITTRAN)
						    && !(ckt->CKTmode&MODEUIC)) ) {
                    /* (above only excludes tranop, since we're only at this
                     * point if tran or tranop )
                     */

                    /*
                     *    calculate equivalent conductances and currents for
                     *    depletion capacitors
                     */

                    /* integrate the capacitors and save results */

                    error = NIintegrate(ckt,&geq,&ceq,here->MOS1capbd,
					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);
                    if(error) return(error);
                    here->MOS1gbs += geq;
                    here->MOS1cbs += *(ckt->CKTstate0 + here->MOS1cqbs);
                }
            }
/*
  
*/

            if(SenCond) goto next2;


            /*
             *  check convergence
             */
            if ( (here->MOS1off == 0)  || 
		 (!(ckt->CKTmode & (MODEINITFIX|MODEINITSMSIG))) ){
                if (Check == 1) {
                    ckt->CKTnoncon++;
		    ckt->CKTtroubleElt = (GENinstance *) here;
                }
            }
/*
  
*/

            /* save things away for next time */

	next2:      *(ckt->CKTstate0 + here->MOS1vbs) = vbs;
            *(ckt->CKTstate0 + here->MOS1vbd) = vbd;
            *(ckt->CKTstate0 + here->MOS1vgs) = vgs;
            *(ckt->CKTstate0 + here->MOS1vds) = vds;

/*
  
*/

            /*
             *     meyer's capacitor model
             */
            if ( ckt->CKTmode & (MODETRAN | MODETRANOP | MODEINITSMSIG) ) {
                /*
                 *     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
                 * you must add in the other half from previous time
                 * and the constant part
                 */
                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);
                } else {
                    DEVqmeyer (vgd,vgs,vgb,von,vdsat,
			       (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 ;
                } 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 );
                }
                if(ckt->CKTsenInfo){
                    here->MOS1cgs = capgs;
                    here->MOS1cgd = capgd;
                    here->MOS1cgb = capgb;
                }
/*
  
*/

                /*
                 *     store small-signal parameters (for meyer's model)
                 *  all parameters already stored, so done...
                 */
                if(SenCond){
                    if((ckt->CKTsenInfo->SENmode == DCSEN)||
		       (ckt->CKTsenInfo->SENmode == ACSEN)){
                        continue;
                    }
                }

#ifndef PREDICTOR
                if (ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) {
                    *(ckt->CKTstate0 + 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);
                    *(ckt->CKTstate0 + here->MOS1qgb) =
                        (1+xfact) * *(ckt->CKTstate1 + here->MOS1qgb)
                        - xfact * *(ckt->CKTstate2 + here->MOS1qgb);
                } else {
#endif /*PREDICTOR*/
                    if(ckt->CKTmode & MODETRAN) {
                        *(ckt->CKTstate0 + here->MOS1qgs) = (vgs-vgs1)*capgs +
                            *(ckt->CKTstate1 + here->MOS1qgs) ;
                        *(ckt->CKTstate0 + here->MOS1qgd) = (vgd-vgd1)*capgd +
                            *(ckt->CKTstate1 + here->MOS1qgd) ;
                        *(ckt->CKTstate0 + here->MOS1qgb) = (vgb-vgb1)*capgb +
                            *(ckt->CKTstate1 + here->MOS1qgb) ;
                    } else {
                        /* TRANOP only */
                        *(ckt->CKTstate0 + here->MOS1qgs) = vgs*capgs;
                        *(ckt->CKTstate0 + here->MOS1qgd) = vgd*capgd;
                        *(ckt->CKTstate0 + here->MOS1qgb) = vgb*capgb;
                    }
#ifndef PREDICTOR
                }
#endif /*PREDICTOR*/
            }
	bypass:
            if(SenCond) continue;

            if ( (ckt->CKTmode & (MODEINITTRAN)) || 
		 (! (ckt->CKTmode & (MODETRAN)) )  ) {
                /*
                 *  initialize to zero charge conductances 
                 *  and current
                 */
                gcgs=0;
                ceqgs=0;
                gcgd=0;
                ceqgd=0;
                gcgb=0;
                ceqgb=0;
            } else {
                if(capgs == 0) *(ckt->CKTstate0 + here->MOS1cqgs) =0;
                if(capgd == 0) *(ckt->CKTstate0 + here->MOS1cqgd) =0;
                if(capgb == 0) *(ckt->CKTstate0 + here->MOS1cqgb) =0;
                /*
                 *    calculate equivalent conductances and currents for
                 *    meyer"s capacitors
                 */
                error = NIintegrate(ckt,&gcgs,&ceqgs,capgs,here->MOS1qgs);
                if(error) return(error);
                error = NIintegrate(ckt,&gcgd,&ceqgd,capgd,here->MOS1qgd);
                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);
                ceqgd=ceqgd-gcgd*vgd+ckt->CKTag[0]*
		    *(ckt->CKTstate0 + here->MOS1qgd);
                ceqgb=ceqgb-gcgb*vgb+ckt->CKTag[0]*
		    *(ckt->CKTstate0 + here->MOS1qgb);
            }
            /*
             *     store charge storage info for meyer's cap in lx table
             */

            /*
             *  load current vector
             */
            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);
            } else {
                xnrm=0;
                xrev=1;
                cdreq = -(model->MOS1type)*(cdrain-here->MOS1gds*(-vds)-
					    here->MOS1gm*vgd-here->MOS1gmbs*vbd);
            }
            *(ckt->CKTrhs + here->MOS1gNode) -= 
                (model->MOS1type * (ceqgs + ceqgb + ceqgd));
            *(ckt->CKTrhs + here->MOS1bNode) -=
                (ceqbs + ceqbd - model->MOS1type * ceqgb);
            *(ckt->CKTrhs + here->MOS1dNodePrime) +=
		(ceqbd - cdreq + model->MOS1type * ceqgd);
            *(ckt->CKTrhs + here->MOS1sNodePrime) += 
		cdreq + ceqbs + model->MOS1type * ceqgs;
            /*
             *  load y matrix
             */

            *(here->MOS1DdPtr) += (here->MOS1drainConductance);
            *(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->MOS1DdpPtr) += (-here->MOS1drainConductance);
            *(here->MOS1GbPtr) -= gcgb;
            *(here->MOS1GdpPtr) -= gcgd;
            *(here->MOS1GspPtr) -= gcgs;
            *(here->MOS1SspPtr) += (-here->MOS1sourceConductance);
            *(here->MOS1BgPtr) -= gcgb;
            *(here->MOS1BdpPtr) -= here->MOS1gbd;
            *(here->MOS1BspPtr) -= here->MOS1gbs;
            *(here->MOS1DPdPtr) += (-here->MOS1drainConductance);
            *(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->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));
        }
    }
    return(OK);
}
Exemplo n.º 7
0
int
MESAload(GENmodel *inModel, CKTcircuit *ckt)
{
    MESAmodel *model = (MESAmodel*)inModel;
    MESAinstance *here;
    double capgd;
    double capgs;
    double cd;
    double cdhat = 0.0;
    double cdrain;
    double cdreq;
    double ceq;
    double ceqgd;
    double ceqgs;
    double cg;
    double cgd;
    double cgs;
    double cghat = 0.0;
    double arg;
    double earg;
    double delvds;
    double delvgd;
    double delvgs;
    double delvgspp=0;
    double delvgdpp=0;
    double evgd;
    double evgs;
    double gds;                            
    double geq;
    double ggd;
    double ggs;
    double gm;
    double ggspp=0;
    double cgspp=0;
    double ggdpp=0;
    double cgdpp=0;
    double vcrits;
    double vcritd;
    double vds=0;
    double vgd=0;
    double vgs=0;
    double vgspp=0;
    double vgdpp=0;    
    double vgs1=0;
    double vgd1=0;
    double xfact;
    double temp;
    double vted;
    double vtes;
    double vtd;
    double vts;
    double von;
    double ccorr;
    int inverse=FALSE;
    int icheck;
    int ichk1;
    int error;

    double m;

    /*  loop through all the models */
    for( ; model != NULL; model = model->MESAnextModel ) {

        /* loop through all the instances of the model */
        for (here = model->MESAinstances; here != NULL ;
                here=here->MESAnextInstance) {
            if (here->MESAowner != ARCHme) continue;

            /*
             *  dc model parameters 
             */
            vcrits = here->MESAvcrits;
            vcritd = here->MESAvcritd;
            vtd  = CONSTKoverQ * here->MESAtd;
            vts  = CONSTKoverQ * here->MESAts;
            vted = model->MESAn*vtd;
            vtes = model->MESAn*vts;
            /*
             *    initialization
             */
            icheck = 1;
            if( ckt->CKTmode & MODEINITSMSIG) {
                vgs = *(ckt->CKTstate0 + here->MESAvgs);
                vgd = *(ckt->CKTstate0 + here->MESAvgd);
                vgspp = *(ckt->CKTstate0 + here->MESAvgspp);
                vgdpp = *(ckt->CKTstate0 + here->MESAvgdpp);
            } else if (ckt->CKTmode & MODEINITTRAN) {
                vgs = *(ckt->CKTstate1 + here->MESAvgs);
                vgd = *(ckt->CKTstate1 + here->MESAvgd);
                vgspp = *(ckt->CKTstate1 + here->MESAvgspp);
                vgdpp = *(ckt->CKTstate1 + here->MESAvgdpp);
            } else if ( (ckt->CKTmode & MODEINITJCT) &&
                    (ckt->CKTmode & MODETRANOP) &&
                    (ckt->CKTmode & MODEUIC) ) {
                vds = here->MESAicVDS;
                vgs = here->MESAicVGS;
                vgd = vgs-vds;
                vgspp = vgs;
                vgdpp = vgd;
            } else if ( (ckt->CKTmode & MODEINITJCT) &&
                    (here->MESAoff == 0)  ) {
                vgs = -1;
                vgd = -1;
                vgspp = 0;
                vgdpp = 0;
            } else if( (ckt->CKTmode & MODEINITJCT) ||
                    ((ckt->CKTmode & MODEINITFIX) && (here->MESAoff))) {
                vgs = 0;
                vgd = 0;
                vgspp = 0;
                vgdpp = 0;
            } else {
#ifndef PREDICTOR
                if(ckt->CKTmode & MODEINITPRED) {
                    xfact = ckt->CKTdelta/ckt->CKTdeltaOld[2];
                    *(ckt->CKTstate0 + here->MESAvgs) = 
                            *(ckt->CKTstate1 + here->MESAvgs);
                    vgs = (1+xfact) * *(ckt->CKTstate1 + here->MESAvgs) -
                           xfact * *(ckt->CKTstate2 + here->MESAvgs);
                    *(ckt->CKTstate0 + here->MESAvgspp) =
                            *(ckt->CKTstate1 + here->MESAvgspp);
                    vgspp = (1+xfact) * *(ckt->CKTstate1 + here->MESAvgspp) -
                           xfact * *(ckt->CKTstate2 + here->MESAvgspp);
                    *(ckt->CKTstate0 + here->MESAvgd) = 
                            *(ckt->CKTstate1 + here->MESAvgd);
                    vgd = (1+xfact)* *(ckt->CKTstate1 + here->MESAvgd) -
                           xfact * *(ckt->CKTstate2 + here->MESAvgd);
                    *(ckt->CKTstate0 + here->MESAvgdpp) =
                            *(ckt->CKTstate1 + here->MESAvgdpp);
                    vgdpp = (1+xfact) * *(ckt->CKTstate1 + here->MESAvgdpp) -
                           xfact * *(ckt->CKTstate2 + here->MESAvgdpp);
                    *(ckt->CKTstate0 + here->MESAcg) = 
                            *(ckt->CKTstate1 + here->MESAcg);
                    *(ckt->CKTstate0 + here->MESAcd) = 
                            *(ckt->CKTstate1 + here->MESAcd);
                    *(ckt->CKTstate0 + here->MESAcgd) =
                            *(ckt->CKTstate1 + here->MESAcgd);
                    *(ckt->CKTstate0 + here->MESAcgs) =
                            *(ckt->CKTstate1 + here->MESAcgs);                            
                    *(ckt->CKTstate0 + here->MESAgm) =
                            *(ckt->CKTstate1 + here->MESAgm);
                    *(ckt->CKTstate0 + here->MESAgds) =
                            *(ckt->CKTstate1 + here->MESAgds);
                    *(ckt->CKTstate0 + here->MESAggs) =
                            *(ckt->CKTstate1 + here->MESAggs);
                    *(ckt->CKTstate0 + here->MESAggd) =
                            *(ckt->CKTstate1 + here->MESAggd);
                    *(ckt->CKTstate0 + here->MESAggspp) =
                            *(ckt->CKTstate1 + here->MESAggspp);
                    *(ckt->CKTstate0 + here->MESAcgspp) =
                            *(ckt->CKTstate1 + here->MESAcgspp);
                    *(ckt->CKTstate0 + here->MESAggdpp) =
                            *(ckt->CKTstate1 + here->MESAggdpp);
                    *(ckt->CKTstate0 + here->MESAcgdpp) =
                            *(ckt->CKTstate1 + here->MESAcgdpp);
                } else {
#endif /* PREDICTOR */
                    /*
                     *  compute new nonlinear branch voltages 
                     */
                    vgs = (*(ckt->CKTrhsOld+ here->MESAgatePrimeNode)-
                        *(ckt->CKTrhsOld+here->MESAsourcePrimeNode));
                    vgd = (*(ckt->CKTrhsOld+here->MESAgatePrimeNode)-
                        *(ckt->CKTrhsOld+here->MESAdrainPrimeNode));
                    vgspp = (*(ckt->CKTrhsOld+here->MESAgatePrimeNode)-
                        *(ckt->CKTrhsOld+here->MESAsourcePrmPrmNode));
                    vgdpp = (*(ckt->CKTrhsOld+here->MESAgatePrimeNode)-
                        *(ckt->CKTrhsOld+here->MESAdrainPrmPrmNode));
                        
#ifndef PREDICTOR
                }
#endif /* PREDICTOR */
                delvgs=vgs - *(ckt->CKTstate0 + here->MESAvgs);
                delvgd=vgd - *(ckt->CKTstate0 + here->MESAvgd);
                delvds=delvgs - delvgd;
                delvgspp = vgspp - *(ckt->CKTstate0 + here->MESAvgspp);
                delvgdpp = vgdpp - *(ckt->CKTstate0 + here->MESAvgdpp);
                cghat= *(ckt->CKTstate0 + here->MESAcg) + 
                        *(ckt->CKTstate0 + here->MESAggd)*delvgd +
                        *(ckt->CKTstate0 + here->MESAggs)*delvgs +
                        *(ckt->CKTstate0 + here->MESAggspp)*delvgspp+
                        *(ckt->CKTstate0 + here->MESAggdpp)*delvgdpp;
                cdhat= *(ckt->CKTstate0 + here->MESAcd) +
                        *(ckt->CKTstate0 + here->MESAgm)*delvgs +
                        *(ckt->CKTstate0 + here->MESAgds)*delvds -
                        *(ckt->CKTstate0 + here->MESAggd)*delvgd;
                /*
                 *   bypass if solution has not changed 
                 */
                if((ckt->CKTbypass) &&
                    (!(ckt->CKTmode & MODEINITPRED)) &&
                    (fabs(delvgs) < ckt->CKTreltol*MAX(fabs(vgs),
                        fabs(*(ckt->CKTstate0 + here->MESAvgs)))+
                        ckt->CKTvoltTol) )
                if((fabs(delvgd) < ckt->CKTreltol*MAX(fabs(vgd),
                        fabs(*(ckt->CKTstate0 + here->MESAvgd)))+
                        ckt->CKTvoltTol))
                if((fabs(delvgspp) < ckt->CKTreltol*MAX(fabs(vgspp),
                        fabs(*(ckt->CKTstate0 + here->MESAvgspp)))+
                        ckt->CKTvoltTol))
                if((fabs(delvgdpp) < ckt->CKTreltol*MAX(fabs(vgdpp),
                        fabs(*(ckt->CKTstate0 + here->MESAvgdpp)))+
                        ckt->CKTvoltTol))
                if((fabs(cghat-*(ckt->CKTstate0 + here->MESAcg)) 
                        < ckt->CKTreltol*MAX(fabs(cghat),
                        fabs(*(ckt->CKTstate0 + here->MESAcg)))+
                        ckt->CKTabstol))
                if((fabs(cdhat-*(ckt->CKTstate0 + here->MESAcd))
                        < ckt->CKTreltol*MAX(fabs(cdhat),
                        fabs(*(ckt->CKTstate0 + here->MESAcd)))+
                        ckt->CKTabstol)) {

                    /* we can do a bypass */
                    vgs= *(ckt->CKTstate0 + here->MESAvgs);
                    vgd= *(ckt->CKTstate0 + here->MESAvgd);
                    vds= vgs-vgd;
                    vgspp = *(ckt->CKTstate0 + here->MESAvgspp);
                    vgdpp = *(ckt->CKTstate0 + here->MESAvgdpp);
                    cg= *(ckt->CKTstate0 + here->MESAcg);
                    cd= *(ckt->CKTstate0 + here->MESAcd);
                    cgs= *(ckt->CKTstate0 + here->MESAcgs);
                    cgd= *(ckt->CKTstate0 + here->MESAcgd);
                    gm= *(ckt->CKTstate0 + here->MESAgm);
                    gds= *(ckt->CKTstate0 + here->MESAgds);
                    ggs= *(ckt->CKTstate0 + here->MESAggs);
                    ggd= *(ckt->CKTstate0 + here->MESAggd);
                    ggspp = *(ckt->CKTstate0 + here->MESAggspp);
                    cgspp = *(ckt->CKTstate0 + here->MESAcgspp);
                    ggdpp = *(ckt->CKTstate0 + here->MESAggdpp);
                    cgdpp = *(ckt->CKTstate0 + here->MESAcgdpp);
                    goto load;
                }
                /*
                 *  limit nonlinear branch voltages 
                 */
                ichk1=1;
                vgs = DEVpnjlim(vgs,*(ckt->CKTstate0 + here->MESAvgs),vtes,
                        vcrits, &icheck);
                vgd = DEVpnjlim(vgd,*(ckt->CKTstate0 + here->MESAvgd),vted,
                        vcritd,&ichk1);
                if (ichk1 == 1) {
                    icheck=1;
                }
                vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->MESAvgs),
                        here->MESAtVto);
                vgd = DEVfetlim(vgd,*(ckt->CKTstate0 + here->MESAvgd),
                        here->MESAtVto);
                if(here->MESAsourcePrmPrmNode == here->MESAsourcePrimeNode)
                  vgspp = vgs;
                if(here->MESAdrainPrmPrmNode == here->MESAdrainPrimeNode)
                  vgdpp = vgd;
            }
            /*
             *   determine dc current and derivatives 
             */
            vds = vgs-vgd;
                      
            arg = -vgs*model->MESAdel/vts;
            earg = exp(arg);
            evgs = exp(vgs/vtes);
            ggs  = here->MESAcsatfs*evgs/vtes+here->MESAggrwl*earg*(1-arg)+ckt->CKTgmin;
            cgs  = here->MESAcsatfs*(evgs-1)+here->MESAggrwl*vgs*earg+
                   ckt->CKTgmin*vgs;
            cg   = cgs;
             
            arg = -vgd*model->MESAdel/vtd;
            earg = exp(arg);
            evgd = exp(vgd/vted);
            ggd  = here->MESAcsatfd*evgd/vted+here->MESAggrwl*earg*(1-arg)+ckt->CKTgmin;
            cgd  = here->MESAcsatfd*(evgd-1)+here->MESAggrwl*vgd*earg+
                   ckt->CKTgmin*vgd;
            cg = cg+cgd;
            
            if(vds < 0) {
              vds = -vds;
              inverse = TRUE;
            }
            von = here->MESAtVto+model->MESAks*(*(ckt->CKTrhsOld+here->MESAsourcePrimeNode)-model->MESAvsg);
            if(model->MESAlevel == 2)
              mesa1(model,here,inverse?vgd:vgs,vds,von,&cdrain,&gm,&gds,&capgs,&capgd);
            else if(model->MESAlevel == 3)
              mesa2(model,here,inverse?vgd:vgs,vds,von,&cdrain,&gm,&gds,&capgs,&capgd);
            else if(model->MESAlevel == 4)
              mesa3(model,here,inverse?vgd:vgs,vds,von,&cdrain,&gm,&gds,&capgs,&capgd);
            if(inverse) {
              cdrain = -cdrain;
              vds = -vds;
              temp = capgs;
              capgs = capgd;
              capgd = temp;
            }
            /*
             *   compute equivalent drain current source 
             */
            cd = cdrain - cgd;
            if ( (ckt->CKTmode & (MODETRAN|MODEINITSMSIG)) ||
                    ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) ){
                /* 
                 *    charge storage elements 
                 */
                vgs1 = *(ckt->CKTstate1 + here->MESAvgspp);
                vgd1 = *(ckt->CKTstate1 + here->MESAvgdpp);

                if(ckt->CKTmode & MODEINITTRAN) {
                    *(ckt->CKTstate1 + here->MESAqgs) = capgs*vgspp;
                    *(ckt->CKTstate1 + here->MESAqgd) = capgd*vgdpp;
                }
                *(ckt->CKTstate0+here->MESAqgs) = *(ckt->CKTstate1 + here->MESAqgs) +
                                                   capgs*(vgspp-vgs1);
                *(ckt->CKTstate0+here->MESAqgd) = *(ckt->CKTstate1 + here->MESAqgd) +
                                                   capgd*(vgdpp-vgd1);

                /*
                 *   store small-signal parameters 
                 */
                if( (!(ckt->CKTmode & MODETRANOP)) || 
                        (!(ckt->CKTmode & MODEUIC)) ) {
                    if(ckt->CKTmode & MODEINITSMSIG) {
                        *(ckt->CKTstate0 + here->MESAqgs) = capgs;
                        *(ckt->CKTstate0 + here->MESAqgd) = capgd;
                        continue; /*go to 1000*/
                    }
                    /*
                     *   transient analysis 
                     */
                    if(ckt->CKTmode & MODEINITTRAN) {
                        *(ckt->CKTstate1 + here->MESAqgs) =
                                *(ckt->CKTstate0 + here->MESAqgs);
                        *(ckt->CKTstate1 + here->MESAqgd) =
                                *(ckt->CKTstate0 + here->MESAqgd);
                    }
                    error = NIintegrate(ckt,&geq,&ceq,capgs,here->MESAqgs);
                    if(error) return(error);
                    ggspp = geq;
                    cgspp = *(ckt->CKTstate0 + here->MESAcqgs);
                    cg = cg + cgspp;
                    error = NIintegrate(ckt,&geq,&ceq,capgd,here->MESAqgd);
                    if(error) return(error);
                    ggdpp = geq;
                    cgdpp = *(ckt->CKTstate0 + here->MESAcqgd);
                    cg = cg + cgdpp;
                    cd = cd - cgdpp;
                    if (ckt->CKTmode & MODEINITTRAN) {
                        *(ckt->CKTstate1 + here->MESAcqgs) =
                                *(ckt->CKTstate0 + here->MESAcqgs);
                        *(ckt->CKTstate1 + here->MESAcqgd) =
                                *(ckt->CKTstate0 + here->MESAcqgd);
                    }
                }
            }
            /*
             *  check convergence 
             */
            if( (!(ckt->CKTmode & MODEINITFIX)) | (!(ckt->CKTmode & MODEUIC))) {
                if( (icheck == 1) 
                        || (fabs(cghat-cg) >= ckt->CKTreltol*
                            MAX(fabs(cghat),fabs(cg))+ckt->CKTabstol) ||
                        (fabs(cdhat-cd) > ckt->CKTreltol*
                            MAX(fabs(cdhat),fabs(cd))+ckt->CKTabstol) 
                        ) {
                    ckt->CKTnoncon++;
                }
            }
            *(ckt->CKTstate0 + here->MESAvgs) = vgs;
            *(ckt->CKTstate0 + here->MESAvgspp) = vgspp;
            *(ckt->CKTstate0 + here->MESAvgd) = vgd;
            *(ckt->CKTstate0 + here->MESAvgdpp) = vgdpp;
            *(ckt->CKTstate0 + here->MESAcg) = cg;
            *(ckt->CKTstate0 + here->MESAcd) = cd;
            *(ckt->CKTstate0 + here->MESAcgd) = cgd;
            *(ckt->CKTstate0 + here->MESAcgs) = cgs;
            *(ckt->CKTstate0 + here->MESAgm) = gm;
            *(ckt->CKTstate0 + here->MESAgds) = gds;
            *(ckt->CKTstate0 + here->MESAggs) = ggs;
            *(ckt->CKTstate0 + here->MESAggd) = ggd;
            *(ckt->CKTstate0 + here->MESAggspp) = ggspp;
            *(ckt->CKTstate0 + here->MESAcgspp) = cgspp;
            *(ckt->CKTstate0 + here->MESAggdpp) = ggdpp;
            *(ckt->CKTstate0 + here->MESAcgdpp) = cgdpp;
            
            /*
             *    load current vector
             */
load:

            m = here->MESAm;

            ccorr = model->MESAag*(cgs-cgd);
            ceqgd = cgd + cgdpp - ggd*vgd - ggdpp*vgdpp;
            ceqgs = cgs + cgspp - ggs*vgs - ggspp*vgspp;
            cdreq=((cd+cgd+cgdpp)-gds*vds-gm*vgs);
            *(ckt->CKTrhs + here->MESAgatePrimeNode) += m * (-ceqgs-ceqgd);
            ceqgd = (cgd-ggd*vgd);
            *(ckt->CKTrhs + here->MESAdrainPrimeNode) += m * (-cdreq+ceqgd+ccorr);
            ceqgd = (cgdpp-ggdpp*vgdpp);
            *(ckt->CKTrhs + here->MESAdrainPrmPrmNode) += ceqgd;
            ceqgs = (cgs-ggs*vgs);
            *(ckt->CKTrhs + here->MESAsourcePrimeNode) += m * (cdreq+ceqgs-ccorr);
            ceqgs = (cgspp-ggspp*vgspp);
            *(ckt->CKTrhs + here->MESAsourcePrmPrmNode) += ceqgs;

            /*
             *    load y matrix 
             */
            *(here->MESAdrainDrainPtr)               += m * (here->MESAdrainConduct);
            *(here->MESAsourceSourcePtr)             += m * (here->MESAsourceConduct);
            *(here->MESAgateGatePtr)                 += m * (here->MESAgateConduct);
            *(here->MESAsourcePrmPrmSourcePrmPrmPtr) += m * (here->MESAtGi+ggspp);
            *(here->MESAdrainPrmPrmDrainPrmPrmPtr)   += m * (here->MESAtGf+ggdpp);
            *(here->MESAgatePrimeGatePrimePtr)       += m * (ggd+ggs+here->MESAgateConduct+ggspp+ggdpp);
            *(here->MESAdrainPrimeDrainPrimePtr)     += m * (gds+ggd+here->MESAdrainConduct+here->MESAtGf);
            *(here->MESAsourcePrimeSourcePrimePtr)   += m * (gds+gm+ggs+here->MESAsourceConduct+here->MESAtGi);
            *(here->MESAdrainDrainPrimePtr)          -= m * (here->MESAdrainConduct);
            *(here->MESAdrainPrimeDrainPtr)          -= m * (here->MESAdrainConduct);
            *(here->MESAsourceSourcePrimePtr)        -= m * (here->MESAsourceConduct);
            *(here->MESAsourcePrimeSourcePtr)        -= m * (here->MESAsourceConduct);
            *(here->MESAgateGatePrimePtr)            -= m * (here->MESAgateConduct);
            *(here->MESAgatePrimeGatePtr)            -= m * (here->MESAgateConduct);
            *(here->MESAgatePrimeDrainPrimePtr)      -= m * (ggd);
            *(here->MESAgatePrimeSourcePrimePtr)     -= m * (ggs);
            *(here->MESAdrainPrimeGatePrimePtr)      += m * (gm-ggd);
            *(here->MESAdrainPrimeSourcePrimePtr)    += m * (-gds-gm);
            *(here->MESAsourcePrimeGatePrimePtr)     += m * (-ggs-gm);
            *(here->MESAsourcePrimeDrainPrimePtr)    -= m * (gds);
            *(here->MESAsourcePrimeSourcePrmPrmPtr)  -= m * (here->MESAtGi);
            *(here->MESAsourcePrmPrmSourcePrimePtr)  -= m * (here->MESAtGi);
            *(here->MESAgatePrimeSourcePrmPrmPtr)    -= m * (ggspp);
            *(here->MESAsourcePrmPrmGatePrimePtr)    -= m * (ggspp);
            *(here->MESAdrainPrimeDrainPrmPrmPtr)    -= m * (here->MESAtGf);
            *(here->MESAdrainPrmPrmDrainPrimePtr)    -= m * (here->MESAtGf);
            *(here->MESAgatePrimeDrainPrmPrmPtr)     -= m * (ggdpp);
            *(here->MESAdrainPrmPrmGatePrimePtr)     -= m * (ggdpp);
        }
    }
    return(OK);
}