home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************/
- /* Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991 */
- /* By MicroSim Corporation, All Rights Reserved */
- /****************************************************************************/
- /* mos.c
- * $Revision: 1.23 $
- * $Author: pwt $
- * $Date: 21 Jun 1991 13:25:00 $ */
-
- /******************* USERS OF DEVICE EQUATIONS OPTION ***********************/
- /******** The definitions below access the device and model data **********/
- /******** structures that are defined in the file m.h. When the **********/
- /******** routine MOSfet is called, it is passed a pointer to the **********/
- /******** device structure. From the device structure is gotten **********/
- /******** a pointer to the model structure. The overall structure **********/
- /******** of the subroutines and model parameters is the same as **********/
- /******** the UC Berkeley Spice 2G.6.
-
- /******** To add a model parameter and equations that use that **********/
- /******** parameter, make the appropriate changes to the file m.h **********/
- /******** and to this file (mos.c). See the comments in m.h for **********/
- /******** instructions on making changes there. Then, recompile **********/
- /******** this file and relink the program using the link command **********/
- /******** file PSPICE.LNK. The command file CC.BAT contains the **********/
- /******** compile options you should use. **********/
-
- #define M_DEVICE
-
- #include "option1.h"
- #include "mos.fd"
-
- #define BYPASS YES /* NO disables bypass */
- #define BSIM YES /* NO disables BSIM code */
-
- static double
- Cox,
- Xqc;
-
- /* defines for device parameter access: simplify code appearance */
-
- #define PARAM_DEV(a) (Instance->a)
- #define DevAd PARAM_DEV(m_ad)
- #define DevAs PARAM_DEV(m_as)
- #define DevGbpr PARAM_DEV(m_rb) /* = 1/rb */
- #define DevGdpr PARAM_DEV(m_rd) /* = 1/rd */
- #define DevGgpr PARAM_DEV(m_rg) /* = 1/rg */
- #define DevGspr PARAM_DEV(m_rs) /* = 1/rs */
- #define DevIdsat PARAM_DEV(m_idsat)
- #define DevIssat PARAM_DEV(m_issat)
- #define DevL PARAM_DEV(m_l)
- #define DevMode PARAM_DEV(m_mode)
- #define DevM PARAM_DEV(m_m)
- #define DevOff PARAM_DEV(m_off)
- #define DevPd PARAM_DEV(m_pd)
- #define DevPs PARAM_DEV(m_ps)
- #define DevVbs PARAM_DEV(m_vbs)
- #define DevVds PARAM_DEV(m_vds)
- #define DevVdsat PARAM_DEV(m_vdsat)
- #define DevVgs PARAM_DEV(m_vgs)
- #define DevVon PARAM_DEV(m_von)
- #define DevW PARAM_DEV(m_w)
- #define DevXqc PARAM_DEV(m_xqc)
-
- /* defines for model parameter access: simplify code appearance
- * note: since the parameters are available to all routines in this file
- * they are preceeded with "Mod"
- */
- #define PARAM_MOD(a) ((double)Model->a)
- #define ModCbd PARAM_MOD(M_cbd)
- #define ModCbs PARAM_MOD(M_cbs)
- #define ModCgbo PARAM_MOD(M_cgbo)
- #define ModCgdo PARAM_MOD(M_cgdo)
- #define ModCgso PARAM_MOD(M_cgso)
- #define ModCj PARAM_MOD(M_cj)
- #define ModCjsw PARAM_MOD(M_cjsw)
- #define ModFc PARAM_MOD(M_fc)
- #define ModGamma PARAM_MOD(M_gamma)
- #define ModGdspr PARAM_MOD(M_rds) /* = 1/Rds */
- #define ModKp PARAM_MOD(M_kp)
- #define ModL PARAM_MOD(M_l)
- #define ModLambda PARAM_MOD(M_lambda)
- #define ModLd PARAM_MOD(M_ld)
- #define ModLevel NINT(PARAM_MOD(M_level))
- #define ModMj PARAM_MOD(M_mj)
- #define ModMjsw PARAM_MOD(M_mjsw)
- #define ModN PARAM_MOD(M_n)
- #define ModPb PARAM_MOD(M_pb)
- #define ModPbsw PARAM_MOD(M_pbsw)
- #define ModPhi PARAM_MOD(M_phi)
- #define ModTox PARAM_MOD(M_tox)
- #define ModTt PARAM_MOD(M_tt)
- #define ModVbi PARAM_MOD(M_vbi)
- #define ModVinit PARAM_MOD(M_vinit)
- #define ModVto PARAM_MOD(M_vto)
- #define ModW PARAM_MOD(M_w)
- #define ModWd PARAM_MOD(M_wd)
- #define ModXqc PARAM_MOD(M_xqc)
-
- /**/
- #ifndef cc_noline
- #line 4 "MOSfet"
- #endif
-
- #ifdef USE_DECL_ARGS
- int MOSfet(struct m_ *,int ,int ,int );
- #else
- int MOSfet();
- #endif
-
- int MOSfet( /* Process MOSFETs for DC and TRANSIENT analyses */
- Instance, /* a device to evaluate */
- ModeFl, /* mode control flag: see "tran.h" */
- InitFl, /* initialization flag: see "tran.h" */
- LoadFl /* NO: bypass MatPrm load if sol'n unchanged */
- ) /* return int: did not converge (YES/NO) */
- struct m_ *Instance;
- int ModeFl, InitFl, LoadFl;
-
- /*
- pwt 20 Aug 86 creation
- pwt ?? Oct 87 many changes to split MOS models into separate files
- pwt ?? Nov 87 re-do junction cap. using square-root if "mj" = .5
- pwt 29 Dec 87 re-do junction cap. using sidewall potential "pbsw"
- pwt 02 Mar 88 add transit time cap. and emission coef. to junctions
- pwt 16 Mar 88 add shared data area to M.H, change source to match
- pwt 21 Mar 88 protect PNJLIM calculations from IS==0.0
- pwt 06 Oct 88 add "M" (multiplier) to device calculations
- whjb 06 Apr 89 LoadFl==YES now forces full recalculation
- pwt 15 Apr 89 set T=0 cap. currents
- whjb 25 Aug 89 corrected cgs, cgd calculation just after CMeyer call
- sv 12 Feb 90 add local temperatures to models.
- pwt 04 May 90 remove values saved for bypass calculations
- pwt 08 Aug 90 apply LoadFl condition to parasitic resistors
- jmh 13 Jun 91 correct Ward-Dutton charge mapping re. bulk junctions
- */
- { struct M_ *Model; /* device's model */
- double
- vds, vgs, vbs, vgd, vbd, /* voltages */
- von, vdsat, vte,
- ibs, ibd, id, idr, /* currents */
- gbd, gbs, gds, gm, gmbs, /* conductances */
- cgd, cgs, cgb, /* Meyer's capacitances */
- cddb, cdgb, cdsb, /* non-reciprocal capacitances */
- cgdb, cggb, cgsb,
- csdb, csgb, cssb,
- cbdb, cbgb, cbsb,
- ieq_qg, ieq_qb, ieq_qd,
- qdrn, qgate, qsrc, qbulk, qchan,
- gcddb, gcdgb, gcdsb, /* non-rec. cap. equiv. conductances */
- gcgdb, gcggb, gcgsb,
- gcsdb, gcsgb, gcssb,
- gcbdb, gcbgb, gcbsb,
- id_hat, ib_hat, /* predicted currents */
- covlgs, covlgd, covlgb, /* overlap capacitances */
- xfact, /* extrapolation factor */
- type; /* NMOS=+1, PMOS=-1 */
-
- int level;
-
- #define vt VT
-
- int
- charge, /* flag that charge calc. be done */
- jlim_fl = YES, /* junction limiting flag: YES, NO */
- pred_fl = NO, /* pred. calculated flag: YES, NO */
- nonconv = NO; /* non-convergence flag: YES, NO */
-
- /* defines & declarations for state-vector access */
-
- struct msv_def *sv[MSTVCT];
-
- EVAL_SV(sv,Instance,m_sda.m_sv);
-
- #define ID0 (Instance->mcv_id)
- #define IBS0 (Instance->mcv_ibs)
- #define IBD0 (Instance->mcv_ibd)
-
- #define GM0 (Instance->mcv_gm)
- #define GDS0 (Instance->mcv_gds)
- #define GMBS0 (Instance->mcv_gmbs)
- #define GBD0 (Instance->mcv_gbd)
- #define GBS0 (Instance->mcv_gbs)
-
- #define CGGB0 (Instance->m_sda.m_ac.mac_cggb)
- #define CGDB0 (Instance->m_sda.m_ac.mac_cgdb)
- #define CGSB0 (Instance->m_sda.m_ac.mac_cgsb)
- #define CBGB0 (Instance->m_sda.m_ac.mac_cbgb)
- #define CBDB0 (Instance->m_sda.m_ac.mac_cbdb)
- #define CBSB0 (Instance->m_sda.m_ac.mac_cbsb)
- #define CDGB0 (Instance->m_sda.m_ac.mac_cdgb)
- #define CDDB0 (Instance->m_sda.m_ac.mac_cddb)
- #define CDSB0 (Instance->m_sda.m_ac.mac_cdsb)
- #define CBD0 (Instance->m_sda.m_ac.mac_cbd)
- #define CBS0 (Instance->m_sda.m_ac.mac_cbs)
- #define CGB0 (Instance->m_sda.m_ac.mac_cgbo)
- #define CGD0 (Instance->m_sda.m_ac.mac_cgdo)
- #define CGS0 (Instance->m_sda.m_ac.mac_cgso)
-
- /* initialization */
-
- Model = Instance->m_model; /* find the model */
-
- type = Model->M_type > 0 ? 1.: -1.;
-
- if ( InitFl==INSTV0 ) { /* use prev. iteration */
- double
- vs = VOLTAGE(m_s);
-
- vds = ( VOLTAGE(m_d) - vs )*type;
- vgs = ( VOLTAGE(m_g) - vs )*type;
- vbs = ( VOLTAGE(m_b) - vs )*type;
- }
- else if ( InitFl==INTRAN ) { /* use prev. time-step */
- vds = M_VDS(1);
- vgs = M_VGS(1);
- vbs = M_VBS(1);
- }
- else if ( InitFl==INOFF && /* set "off" devices */
- DevOff==YES)
- vds = vgs = vbs = 0.;
-
- else if ( InitFl==ININIT ) { /* use IC= values */
-
- if ( ModeFl==MDBPTR && NOSOLV==YES ) {
- vds = DevVds*type;
- vgs = DevVgs*type;
- vbs = DevVbs*type;
- }
- else if ( DevOff==NO ) {
- vds = 0.;
- vgs = ModVto*type;
- vbs = ModVinit;
- }
- else
- vds = vgs = vbs = 0.;
- }
- else {
- double del_vbs, del_vbd, del_vgs, del_vgd, del_vds, del_id, del_ib;
-
- if ( InitFl==INPRDCT ) { /* extrapolate value */
- xfact = DELTA/DELOLD[1];
-
- vds = xfact*( M_VDS(1) - M_VDS(2) ) + M_VDS(1);
- vgs = xfact*( M_VGS(1) - M_VGS(2) ) + M_VGS(1);
- vbs = xfact*( M_VBS(1) - M_VBS(2) ) + M_VBS(1);
- *sv[0] = *sv[1];
- }
- else { /* use current value */
- double
- vs = VOLTAGE(m_s);
-
- vds = ( VOLTAGE(m_d) - vs )*type;
- vgs = ( VOLTAGE(m_g) - vs )*type;
- vbs = ( VOLTAGE(m_b) - vs )*type;
- }
-
- /* compute new non-linear branch voltage */
-
- del_vds = vds - M_VDS(0);
- del_vgs = vgs - M_VGS(0);
- del_vgd = del_vgs - del_vds;
- del_vbs = vbs - M_VBS(0);
- del_vbd = del_vbs - del_vds;
-
- del_id = M_VDS(0) >= 0.
- ? del_vds*GDS0 + del_vgs*GM0 - del_vbd*GBD0 + del_vbs*GMBS0
- : del_vds*GDS0 - del_vgd*GM0 - del_vbd*GBD0 + del_vbd*GMBS0;
- id_hat = del_id + ID0;
-
- del_ib = del_vbd*GBD0 + del_vbs*GBS0;
- ib_hat = del_ib + IBS0 + IBD0;
-
- /* bypass if solution not changed */
- /* note: check order based on frequency analysis of test suite circuits */
-
- if ( LoadFl ) ;
- else if ( InitFl==INPRDCT && DELTA!=DELOLD[1] ) ;
- #if BYPASS==NO
- else if (YES);
- #endif
- else if ( fabs(del_vds) >= TOL( vds, M_VDS(0),RELTOL, VNTOL) ) ;
- else if ( fabs(del_vgd) >= TOL(vgs-vds,M_VGS(0)-M_VDS(0),RELTOL, VNTOL) ) ;
- else if ( fabs(del_vgs) >= TOL( vgs, M_VGS(0),RELTOL, VNTOL) ) ;
- else if ( fabs(del_vbd) >= TOL(vbs-vds,M_VBS(0)-M_VDS(0),RELTOL, VNTOL) ) ;
- else if ( fabs(del_vbs) >= TOL( vbs, M_VBS(0),RELTOL, VNTOL) ) ;
- else if ( fabs(del_id) >= TOL( id_hat, ID0,RELTOL,ABSTOL) ) ;
- else if ( fabs(del_ib) >= TOL( ib_hat, IBS0+IBD0,RELTOL,ABSTOL) ) ;
- else {
- goto done;
- }
- pred_fl = YES;
-
- /* solution changed: limit non-linear branch voltages */
-
- vgd = vgs-vds;
- vbd = vbs-vds;
- von = DevVon*type;
- FETlim(&vgs,M_VGS(0), von);
- FETlim(&vgd,M_VGS(0)-M_VDS(0),von);
- vds = vgs-vgd;
- vte = ModN*vt;
-
- if ( vds >= 0. ) {
- if ( DevIssat > 0. ) {
- double vcrit = vte*log(vte/(DevIssat*DevM*ROOT2));
-
- jlim_fl = PNJLIM(vbs,M_VBS(0),vte,vcrit);
- } }
- else {
- if ( DevIdsat > 0. ) {
- double vcrit = vte*log(vte/(DevIdsat*DevM*ROOT2));
-
- jlim_fl = PNJLIM(vbd,M_VBS(0)-M_VDS(0),vte,vcrit);
- vbs = vbd+vds;
- } }
- } /* end of initialization */
-
- /* compute DC current and derivatives */
-
- vgd = vgs-vds;
- vbd = vbs-vds;
- vte = ModN*vt;
- DevMode = vds >= 0. ? 1 : -1;
-
- if ( vbs > -10*vte ) {
- double evbs = EXP(vbs/vte);
-
- gbs = (evbs/vte)*DevIssat*DevM + GMIN;
- ibs = (evbs - 1)*DevIssat*DevM + vbs*GMIN;
- }
- else {
- gbs = GMIN;
- ibs = gbs*vbs - DevIssat*DevM;
- }
-
- if ( vbd > -10*vte ) {
- double evbd = EXP(vbd/vte);
-
- gbd = (evbd/vte)*DevIdsat*DevM + GMIN;
- ibd = (evbd - 1)*DevIdsat*DevM + vbd*GMIN;
- }
- else {
- gbd = GMIN;
- ibd = gbd*vbd - DevIdsat*DevM;
- }
-
- /* decide if models need to calculate device charges */
-
- level = ModLevel;
-
- if ( ModeFl==MDTRAN || InitFl==INSTV0 ) {
- if ( level==1 || /* when to use Meyer model */
- level==2 && ModXqc > .5 ||
- level==3 ||
- level==4 && PARAM_MOD(BSIM_xpart) < 0.)
- charge = NO;
- else
- charge = YES;
- }
- else
- charge = NO;
-
- /* compute drain current and derivatives (evaluate device models) */
-
- { double
- len = DevL - ModLd*( level==4 ? 1e-6 : 2.),
- wid = (DevW - ModWd*( level==4 ? 1e-6 : 2.))*DevM;
-
- Cox = ModTox==0. ? 0. : wid*len*EPSOX/ModTox; /* save for Cmeyer */
- covlgs = ModCgso*wid;
- covlgd = ModCgdo*wid;
- covlgb = ModCgbo*len;
-
- switch ( level ) {
- case 1: /* MOS1: Shichman-Hodges */
- if ( DevMode > 0 ) MOS1eval(
- Model,len,wid, vgs, vds,vbs,&von,&vdsat,&idr,&gds,&gm,&gmbs
- );
- else MOS1eval(
- Model,len,wid, vgd,-vds,vbd,&von,&vdsat,&idr,&gds,&gm,&gmbs
- );
- break;
- case 2: /* MOS2: analytic */
- Xqc = ModXqc;
- if ( DevMode > 0 ) MOS2eval(
- Model,len,wid,DevM, vgs, vds,vbs,&von,&vdsat,&idr,&gds,&gm,&gmbs,
- charge,&cggb,&cgdb,&cgsb,&cbgb,&cbdb,&cbsb,&qgate,&qchan,&qbulk
- );
- else MOS2eval(
- Model,len,wid,DevM, vgd,-vds,vbd,&von,&vdsat,&idr,&gds,&gm,&gmbs,
- charge,&cggb,&cgsb,&cgdb,&cbgb,&cbsb,&cbdb,&qgate,&qchan,&qbulk
- );
- break;
- case 3: /* MOS3: semi-empirical */
- if ( DevMode > 0 ) MOS3eval(
- Model,len,wid,DevM, vgs, vds,vbs,&von,&vdsat,&idr,&gds,&gm,&gmbs,
- charge,&cggb,&cgdb,&cgsb,&cbgb,&cbdb,&cbsb,&qgate,&qchan,&qbulk
- );
- else MOS3eval(
- Model,len,wid,DevM, vgd,-vds,vbd,&von,&vdsat,&idr,&gds,&gm,&gmbs,
- charge,&cggb,&cgsb,&cgdb,&cbgb,&cbsb,&cbdb,&qgate,&qchan,&qbulk
- );
- break;
- #if BSIM==YES
- case 4: /* MOS4: BSIM */
- if ( DevMode > 0 ) MOS4eval(
- Model,len,wid,DevM, vgs, vds,vbs,&von,&vdsat,&idr,&gds,&gm,&gmbs,
- charge,&cggb,&cgdb,&cgsb,&cdgb,&cddb,&cdsb,&cbgb,&cbdb,&cbsb,
- &qgate,&qdrn,&qbulk
- );
- else MOS4eval(
- Model,len,wid,DevM, vgd,-vds,vbd,&von,&vdsat,&idr,&gds,&gm,&gmbs,
- charge,&cggb,&cgsb,&cgdb,&csgb,&cssb,&csdb,&cbgb,&cbsb,&cbdb,
- &qgate,&qsrc,&qbulk
- );
- break;
- #endif
- default:;
- } }
-
- /* save values for next iteration */
-
- DevVon = von*type;
- DevVdsat = vdsat*type;
-
- if ( ModXqc <= .5 ) DevXqc = Xqc;
-
- /* compute equivalent drain current source */
-
- id = DevMode*idr + vds*ModGdspr*DevM - ibd;
- gds = gds + ModGdspr*DevM;
-
- /* charge calculations */
-
- if ( ModeFl==MDTRAN ||
- InitFl==INSTV0 ||
- ( ModeFl==MDBPTR && NOSOLV==YES ) ) {
- double
- cap_bd = 0., /* junction capacitances */
- cap_bs = 0.,
- vgb = vgs-vbs;
-
- M_QCBD(0) = M_QCBS(0) = 0.;
-
- /* calculate values for depletion capacitors */
-
- if ( ModCbd != 0.||
- ModCbs != 0.) {
- MOSpnjc(&M_QCBD(0),&cap_bd,ModCbd*DevM, vbd,ModPb, ModFc,ModMj);
- MOSpnjc(&M_QCBS(0),&cap_bs,ModCbs*DevM, vbs,ModPb, ModFc,ModMj);
- }
- else if ( ModCj != 0.) {
- MOSpnjc(&M_QCBD(0),&cap_bd,ModCj*DevAd*DevM, vbd,ModPb, ModFc,ModMj);
- MOSpnjc(&M_QCBS(0),&cap_bs,ModCj*DevAs*DevM, vbs,ModPb, ModFc,ModMj);
- }
-
- if ( ModCjsw != 0.) {
- MOSpnjc(&M_QCBD(0),&cap_bd,ModCjsw*DevPd*DevM,vbd,ModPbsw,ModFc,ModMjsw);
- MOSpnjc(&M_QCBS(0),&cap_bs,ModCjsw*DevPs*DevM,vbs,ModPbsw,ModFc,ModMjsw);
- }
-
- if ( ModTt!=0. ) { /* include transit time effects */
- M_QCBD(0) += ModTt*ibd; cap_bd += ModTt*gbd;
- M_QCBS(0) += ModTt*ibs; cap_bs += ModTt*gbs;
- }
-
- M_ICBD(0) = /* reset, so T=0 results (e.g. Probe) are correct */
- M_ICBS(0) = 0.;
-
- if ( !(ModeFl==MDBPTR && NOSOLV==NO) ) { /* transient analysis */
- double g_eq, i_eq;
-
- /* calculate equivalent conductances and currents for depletion capacitors */
-
- if ( InitFl==INTRAN ) { /* for 1st transient step: */
- M_QCBD(2) = M_QCBD(1) = M_QCBD(0); /* set "old" charges so */
- M_QCBS(2) = M_QCBS(1) = M_QCBS(0); /* integration works */
- }
-
- INTEGR8(g_eq,i_eq,cap_bd,M_QIBD(0),M_QIBD(1),M_QIBD(2));
- gbd += g_eq;
- ibd += M_ICBD(0);
- id -= M_ICBD(0);
-
- INTEGR8(g_eq,i_eq,cap_bs,M_QIBS(0),M_QIBS(1),M_QIBS(2));
- gbs += g_eq;
- ibs += M_ICBS(0);
-
- if ( InitFl==INTRAN ) { /* for 1st transient step: */
- M_ICBD(1) = M_ICBD(0); /* set "old" currents so */
- M_ICBS(1) = M_ICBS(0); /* time-step calc. works */
- }
- } /* end of junction charge calculations */
-
- if ( charge==NO ) { /*** Meyer capacitance model ***/
- double
- ieq_gs, gcgs,
- ieq_gd, gcgd,
- ieq_gb, gcgb;
-
- gcgs = ieq_gs =
- gcgd = ieq_gd =
- gcgb = ieq_gb = 0.;
-
- if ( DevMode==1 )
- Cmeyer(Model,&vgs,&vgd,&vgb,&von,&vdsat,&cgs,&cgd,&cgb);
- else
- Cmeyer(Model,&vgd,&vgs,&vgb,&von,&vdsat,&cgd,&cgs,&cgb);
-
- M_CGD(0) = cgd; /* save values for next time point */
- M_CGS(0) = cgs;
- M_CGB(0) = cgb;
-
- M_ICGD(0) = /* reset, so T=0 results (e.g. Probe) are correct */
- M_ICGS(0) =
- M_ICGB(0) = 0.;
-
- if ( ModeFl==MDTRAN && InitFl!=INTRAN ) {
- cgd = covlgd + .5*(cgd + M_CGD(1));
- cgs = covlgs + .5*(cgs + M_CGS(1));
- cgb = covlgb + .5*(cgb + M_CGB(1));
- }
- else {
- cgd += covlgd;
- cgs += covlgs;
- cgb += covlgb;
- }
-
- if ( InitFl==INSTV0) { /* store small-signal parameters */
- CGD0 = cgd; /* and update the state vector */
- CGS0 = cgs;
- CGB0 = cgb;
- CBD0 = cap_bd;
- CBS0 = cap_bs;
-
- gcdgb = gcddb = gcdsb =
- gcsgb = gcsdb = gcssb =
- gcggb = gcgdb = gcgsb =
- gcbgb = gcbdb = gcbsb =
- ieq_qg = ieq_qb = ieq_qd = 0.;
-
- goto load;
- }
-
- if ( !(ModeFl==MDBPTR && NOSOLV==NO) ) { /* transient analysis */
-
- if ( InitFl==INPRDCT ) {
- M_QCGD(0) = ( M_QCGD(1) - M_QCGD(2) )*xfact + M_QCGD(1);
- M_QCGS(0) = ( M_QCGS(1) - M_QCGS(2) )*xfact + M_QCGS(1);
- M_QCGB(0) = ( M_QCGB(1) - M_QCGB(2) )*xfact + M_QCGB(1);
- }
- else {
- double
- vgs1 = M_VGS(1),
- vgd1 = vgs1 - M_VDS(1),
- vgb1 = vgs1 - M_VBS(1);
-
- M_QCGD(0) = (vgd - vgd1)*cgd;
- M_QCGS(0) = (vgs - vgs1)*cgs;
- M_QCGB(0) = (vgb - vgb1)*cgb;
-
- if ( ModeFl==MDTRAN && InitFl!=INTRAN ) {
- M_QCGD(0) += M_QCGD(1);
- M_QCGS(0) += M_QCGS(1);
- M_QCGB(0) += M_QCGB(1);
- } }
-
- if ( InitFl==INTRAN ) { /* for 1st transient step: set */
- M_QCGD(2) = M_QCGD(1) = M_QCGD(0) = vgd*cgd; /* "old" charges so */
- M_QCGS(2) = M_QCGS(1) = M_QCGS(0) = vgs*cgs; /* integration works */
- M_QCGB(2) = M_QCGB(1) = M_QCGB(0) = vgb*cgb;
- }
-
- if ( M_CGD(0)==0. ) M_ICGD(0) = 0.;
- if ( M_CGS(0)==0. ) M_ICGS(0) = 0.;
- if ( M_CGB(0)==0. ) M_ICGB(0) = 0.;
-
- INTEGR8(gcgd,ieq_gd,cgd,M_QIGD(0),M_QIGD(1),M_QIGD(2));
- ieq_gd = M_ICGD(0) - gcgd*vgd;
-
- INTEGR8(gcgs,ieq_gs,cgs,M_QIGS(0),M_QIGS(1),M_QIGS(2));
- ieq_gs = M_ICGS(0) - gcgs*vgs;
-
- INTEGR8(gcgb,ieq_gb,cgb,M_QIGB(0),M_QIGB(1),M_QIGB(2));
- ieq_gb = M_ICGB(0) - gcgb*vgb;
-
- if ( InitFl==INTRAN ) { /* for 1st transient step: */
- M_ICGD(1) = M_ICGD(0); /* set "old" currents so */
- M_ICGS(1) = M_ICGS(0); /* time-step calc. works */
- M_ICGB(1) = M_ICGB(0);
- } }
-
- /* map Meyer's model to charge-oriented model */
-
- ieq_qg = ieq_gs + ieq_gb + ieq_gd;
- ieq_qb = -ieq_gb;
- ieq_qd = -ieq_gd;
-
- gcgdb = gcdgb = -( gcddb = gcgd );
- gcgsb = gcsgb = -( gcssb = gcgs );
-
- gcbgb = -gcgb;
-
- gcggb = gcgd + gcgs + gcgb;
-
- gcsdb = gcdsb =
- gcbdb = gcbsb = 0.;
-
- } /* end of Meyer charge calculations */
-
- #if BSIM==YES
- else if ( level==4 ) { /*** BSIM charge model ***/
-
- if ( DevMode > 0 )
- MOS4cap(vgd,vgs,vgb,
- covlgd,covlgs,covlgb,
- 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
- MOS4cap(vgs,vgd,vgb,
- covlgs,covlgd,covlgb,
- 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);
-
- M_QCG(0) = qgate;
- M_QCD(0) = qdrn;
- M_QCB(0) = qbulk;
-
- M_ICG(0) = /* reset, so T=0 results (e.g. Probe) are correct */
- M_ICD(0) =
- M_ICB(0) = 0.;
-
- if ( InitFl==INSTV0 ) { /* store small-signal parameters */
- CGDB0 = cgdb; /* and update the state vector */
- CGGB0 = cggb;
- CGSB0 = cgsb;
-
- CBDB0 = cbdb;
- CBGB0 = cbgb;
- CBSB0 = cbsb;
-
- if ( DevMode > 0 )
- CDDB0 = cddb,
- CDGB0 = cdgb,
- CDSB0 = cdsb;
- else
- CDDB0 = cssb,
- CDGB0 = csgb,
- CDSB0 = csdb;
-
- CBD0 = cap_bd;
- CBS0 = cap_bs;
-
- ieq_qg = ieq_qb = ieq_qd = 0.;
-
- goto load;
- }
-
- if ( !(ModeFl==MDBPTR && NOSOLV==NO) ) { /* transient analysis */
- double g_eq, i_eq;
-
- if ( InitFl==INTRAN ) { /* for 1st transient step: */
- M_QCG(2) = M_QCG(1) = M_QCG(0); /* set "old" charges so */
- M_QCD(2) = M_QCD(1) = M_QCD(0); /* integration works */
- M_QCB(2) = M_QCB(1) = M_QCB(0);
- }
-
- INTEGR8(g_eq,i_eq,0.,M_QICG(0),M_QICG(1),M_QICG(2));
- ieq_qg = M_ICG(0) - gcggb*vgb + gcgdb*vbd + gcgsb*vbs;
-
- INTEGR8(g_eq,i_eq,0.,M_QICD(0),M_QICD(1),M_QICD(2));
- ieq_qd = M_ICD(0) - gcdgb*vgb + gcddb*vbd + gcdsb*vbs;
-
- INTEGR8(g_eq,i_eq,0.,M_QICB(0),M_QICB(1),M_QICB(2));
- ieq_qb = M_ICB(0) - gcbgb*vgb + gcbdb*vbd + gcbsb*vbs;
-
- if ( InitFl==INTRAN ) { /* for 1st transient step: */
- M_ICG(1) = M_ICG(0); /* set "old" currents so */
- M_ICD(1) = M_ICD(0); /* time-step calc. works */
- M_ICB(1) = M_ICB(0);
- }
- } } /* end of BSIM charge calculations */
- #endif
-
- else { /*** Ward-Dutton charge model ***/
-
- if ( DevMode > 0 )
- MOScap(
- &vgd, &vgs, &vgb,
- &covlgd, &covlgs, &covlgb,
- &cggb, &cgdb, &cgsb,
- &cbgb, &cbdb, &cbsb,
- &gcggb, &gcgdb, &gcgsb,
- &gcbgb, &gcbdb, &gcbsb,
- &gcdgb, &gcddb, &gcdsb,
- &gcsgb, &gcsdb, &gcssb,
- &qdrn, &qgate, &qsrc, &qbulk, &qchan);
- else
- MOScap(
- &vgs, &vgd, &vgb,
- &covlgs, &covlgd, &covlgb,
- &cggb, &cgsb, &cgdb,
- &cbgb, &cbsb, &cbdb,
- &gcggb, &gcgsb, &gcgdb,
- &gcbgb, &gcbsb, &gcbdb,
- &gcsgb, &gcssb, &gcsdb,
- &gcdgb, &gcdsb, &gcddb,
- &qsrc, &qgate, &qdrn, &qbulk, &qchan);
-
- M_QCG(0) = qgate;
- M_QCD(0) = qdrn;
- M_QCB(0) = qbulk;
-
- M_ICG(0) = /* reset, so T=0 results (e.g. Probe) are correct */
- M_ICD(0) =
- M_ICB(0) = 0.;
-
- if ( InitFl==INSTV0 ) { /* store small-signal parameters */
- CGGB0 = cggb; /* and update the state vector */
- CGDB0 = cgdb;
- CGSB0 = cgsb;
- CBGB0 = cbgb;
- CBDB0 = cbdb;
- CBSB0 = cbsb;
- CBD0 = cap_bd;
- CBS0 = cap_bs;
-
- ieq_qg = ieq_qb = ieq_qd = 0.;
-
- goto load;
- }
-
- if ( !(ModeFl==MDBPTR && NOSOLV==NO) ) { /* transient analysis */
- double g_eq, i_eq;
-
- if ( InitFl==INTRAN ) { /* for 1st transient step: */
- M_QCG(2) = M_QCG(1) = M_QCG(0); /* set "old" charges so */
- M_QCD(2) = M_QCD(1) = M_QCD(0); /* integration works */
- M_QCB(2) = M_QCB(1) = M_QCB(0);
- }
-
- INTEGR8(g_eq,i_eq,0.,M_QICG(0),M_QICG(1),M_QICG(2));
- ieq_qg = M_ICG(0) - gcggb*vgb + gcgdb*vbd + gcgsb*vbs;
-
- INTEGR8(g_eq,i_eq,0.,M_QICD(0),M_QICD(1),M_QICD(2));
- ieq_qd = M_ICD(0) - gcdgb*vgb + gcddb*vbd + gcdsb*vbs;
-
- INTEGR8(g_eq,i_eq,0.,M_QICB(0),M_QICB(1),M_QICB(2));
- ieq_qb = M_ICB(0) - gcbgb*vgb + gcbdb*vbd + gcbsb*vbs;
-
- if ( InitFl==INTRAN ) { /* for 1st transient step: */
- M_ICG(1) = M_ICG(0); /* set "old" currents so */
- M_ICD(1) = M_ICD(0); /* time-step calc. works */
- M_ICB(1) = M_ICB(0);
- }
- } } /* end of Ward-Dutton charge calculations */
-
- } /* end of all charge calculations */
- else {
- gcdgb = gcddb = gcdsb =
- gcsgb = gcsdb = gcssb =
- gcggb = gcgdb = gcgsb =
- gcbgb = gcbdb = gcbsb =
- ieq_qg = ieq_qb = ieq_qd = 0.;
- }
-
- /* check convergence */
-
- if ( pred_fl && (
- jlim_fl ||
- fabs(id_hat-id) > TOL(id_hat, id,RELTOL,ABSTOL) ||
- fabs(ib_hat-(ibs+ibd)) > TOL(ib_hat,(ibs+ibd),RELTOL,ABSTOL)
- )
- ) nonconv = YES;
-
- load:
- { int fwd = ( DevMode > 0 ? YES : NO );
- double
- ggpr, gdpr, gspr, gbpr,
- ieq_bs = ibs - gbs*vbs,
- ieq_bd = ibd - gbd*vbd,
- idr_eq = fwd
- ? idr - (gm*vgs + (gds-ModGdspr*DevM)*vds + gmbs*vbs)
- :-(idr - (gm*vgd - (gds-ModGdspr*DevM)*vds + gmbs*vbd) );
-
- /* load current vector */
-
- Y_MATRIX(m_ig) = -type*ieq_qg;
- Y_MATRIX(m_ib) = -type*(ieq_bs + ieq_bd + ieq_qb);
- Y_MATRIX(m_id) = -type*(idr_eq - ieq_bd + ieq_qd);
- Y_MATRIX(m_is) = type*(idr_eq + ieq_bs + ieq_qd + ieq_qb + ieq_qg);
-
- /* load conductance matrix */
-
- Y_MATRIX(m_gd) = gcgdb;
- Y_MATRIX(m_gs) = gcgsb;
- Y_MATRIX(m_gb) = -gcggb - gcgdb - gcgsb;
- Y_MATRIX(m_gg) = gcggb
- + ( ggpr = DevGgpr*DevM );
-
- Y_MATRIX(m_dg) = ( fwd ? gm : -gm ) + gcdgb;
- Y_MATRIX(m_ds) = ( fwd ? -gm-gmbs : 0. ) + gcdsb - gds;
- Y_MATRIX(m_db) = ( fwd ? gmbs : -gmbs ) - gcddb - gcdgb - gcdsb - gbd;
- Y_MATRIX(m_dd) = ( fwd ? 0.: gm+gmbs ) + gcddb + gds + gbd
- + ( gdpr = DevGdpr*DevM ) ;
-
- Y_MATRIX(m_sg) = ( fwd ? -gm : gm ) + gcsgb;
- Y_MATRIX(m_sd) = ( fwd ? 0.: -gm-gmbs ) + gcsdb - gds;
- Y_MATRIX(m_sb) = ( fwd ? -gmbs : gmbs ) - gcssb - gcsgb - gcsdb - gbs;
- Y_MATRIX(m_ss) = ( fwd ? gm+gmbs : 0. ) + gcssb + gds + gbs
- + ( gspr = DevGspr*DevM );
-
- Y_MATRIX(m_bg) = gcbgb;
- Y_MATRIX(m_bd) = gcbdb - gbd;
- Y_MATRIX(m_bs) = gcbsb - gbs;
- Y_MATRIX(m_bb) = gbd + gbs - gcbgb - gcbdb - gcbsb
- + ( gbpr = DevGbpr*DevM );
-
- if ( LoadFl ) {
- Y_MATRIX(m_gG) = Y_MATRIX(m_Gg) = - ( Y_MATRIX(m_GG) = ggpr );
- Y_MATRIX(m_dD) = Y_MATRIX(m_Dd) = - ( Y_MATRIX(m_DD) = gdpr );
- Y_MATRIX(m_sS) = Y_MATRIX(m_Ss) = - ( Y_MATRIX(m_SS) = gspr );
- Y_MATRIX(m_bB) = Y_MATRIX(m_Bb) = - ( Y_MATRIX(m_BB) = gbpr );
- } }
-
- M_VDS(0) = vds;
- M_VGS(0) = vgs;
- M_VBS(0) = vbs;
-
- ID0 = id;
- IBS0 = ibs;
- IBD0 = ibd;
-
- GM0 = gm;
- GDS0 = gds;
- GMBS0 = gmbs;
- GBD0 = gbd;
- GBS0 = gbs;
-
- done:
- return nonconv;
- }
-
- /**/
- #ifndef cc_noline
- #line 4 "MOSpnjc"
- #endif
-
- void MOSpnjc( /* calc. p-n junction charge and capacitance */
- chg, /* (pointer to) charge */
- cap, /* (pointer to) capacitance */
- cjo, /* zero-bias capacitance */
- vj, /* junction bias */
- pb, /* p-n potential */
- fc, /* forward-bias capacitance coefficient */
- mj /* junction grading coefficient */
- )
- double *chg, *cap, cjo, vj, pb, fc, mj;
-
- /* Discussion:
- Charge and capacitance is calculated and added to the pointed-to value,
- so be sure to initialize these values. This is done so sidewall values
- may be added to the area values.
- */
- /*
- 29 Dec 87 pwt creation
- 12 Aug 88 pwt allow grading coefficient, mj, to be 1.0 (and beyond).
- */
- { if ( vj <= fc*pb ) {
- double
- arg = 1 - vj/pb,
- sarg = mj==.5 ? 1/sqrt(arg) : pow(arg,-mj);
-
- *chg += cjo*pb*( mj==1.? -log(arg) : (1-arg*sarg)/(1-mj) );
- *cap += cjo*sarg;
- }
- else {
- double
- arg = 1-fc,
- varg = (vj - fc*pb)/arg,
- xarg = varg/pb,
- sarg = mj==.5 ? sqrt(arg) : pow(arg,1-mj);
-
- *chg += cjo*( pb*( mj==1.? -log(arg) : (1-sarg)/(1-mj) )
- + (1 +.5*xarg*mj)*varg*sarg );
- *cap += cjo*(1 + xarg*mj)*sarg/arg;
- } }
- /**/
- #ifndef cc_noline
- #line 4 "MOS1eval"
- #endif
-
- void MOS1eval( /* evaluate MOS level 1 (Shichman-Hodges) model */
- Model, /* device model */
- Len, Wid, /* device size */
- Vgs, Vds, Vbs,/* terminal voltages */
- Von, Vdsat, /* return: device characteristic voltages */
- Id, /* return: drain current */
- Gds, Gm, Gmbs /* return: device conductances */
- )
- struct M_ *Model;
- double Len, Wid, Vgs, Vds, Vbs, *Von, *Vdsat, *Id, *Gds, *Gm, *Gmbs;
-
- /*
- pwt 22 Aug 86 creation
- pwt 10 Oct 87 re-work as part of BSIM addition
- */
- { double
- sarg, vgst,
- beta = ModKp*Wid/Len;
-
- if ( Vbs > 0. ) {
- sarg = sqrt(ModPhi);
- sarg = sarg - .5*Vbs/sarg;
- sarg = MAX(sarg,0.);
- }
- else
- sarg = sqrt(ModPhi-Vbs);
-
- *Von = ModGamma*sarg + ModVbi*(Model->M_type);
- vgst = Vgs - *Von;
- *Vdsat = MAX(vgst,0.);
-
- if ( vgst > 0. ) {
- double betap = beta*(ModLambda*Vds + 1);
-
- if ( vgst > Vds ) { /* linear region */
- *Gm = betap*Vds;
- *Id = *Gm*(vgst-.5*Vds);
- *Gds = betap*(vgst-Vds) + beta*ModLambda*Vds*(vgst-.5*Vds);
- }
- else { /* saturated region */
- *Gm = betap*vgst;
- *Id = *Gm*.5*vgst;
- *Gds = .5*ModLambda*beta*vgst*vgst;
- }
- *Gmbs = ( sarg > 0. ? *Gm*.5*ModGamma/sarg : 0. );
- }
- else /* cut-off region */
- *Gm = *Gds = *Gmbs = *Id = 0.;
-
- } /* done */
-
- /**/
- #ifndef cc_noline
- #line 4 "MOScap"
- #endif
-
- void MOScap( /* evaluate MOS capacitor equivalent conductances */
- Vgd, Vgs, Vgb, /* terminal voltages */
- Covlgd, Covlgs, Covlgb, /* overlap capacitances */
- Cggb, Cgdb, Cgsb, /* gate capacitances */
- Cbgb, Cbdb, Cbsb, /* bulk capacitances */
- Gcggb, Gcgdb, Gcgsb, /* return: gate conductances */
- Gcbgb, Gcbdb, Gcbsb, /* return: bulk conductances */
- Gcdgb, Gcddb, Gcdsb, /* return: drain conductances */
- Gcsgb, Gcsdb, Gcssb, /* return: source conductances */
- Qdrn, Qgate, Qsrc, /* return: device charges */
- Qbulk, Qchan
- )
- double
- *Vgd, *Vgs, *Vgb,
- *Covlgd, *Covlgs, *Covlgb,
- *Cggb, *Cgdb, *Cgsb,
- *Cbgb, *Cbdb, *Cbsb,
- *Gcggb, *Gcgdb, *Gcgsb,
- *Gcbgb, *Gcbdb, *Gcbsb,
- *Gcdgb, *Gcddb, *Gcdsb,
- *Gcsgb, *Gcsdb, *Gcssb,
- *Qdrn, *Qgate, *Qsrc,
- *Qbulk, *Qchan;
-
- /* Discussion: divide up the channel charge (1-xqc)/xqc to source and drain */
-
- /*
- pwt 28 Aug 86 creation
- pwt 29 Dec 86 housekeeping
- pwt 19 Feb 88 bug (dating to SPICE2G.6):
- remove junction caps from calculations (these are
- already accounted for in I-vector and G-matrix load)
- pwt 18 Mar 88 re-write for clarity
- */
- { double
- cg = -(*Cggb + *Cbgb),
- cgxd = cg*Xqc,
- cgxs = cg-cgxd;
- double
- cd = -(*Cgdb + *Cbdb),
- cdxd = cd*Xqc,
- cdxs = cd-cdxd;
- double
- cs = -(*Cgsb + *Cbsb),
- csxd = cs*Xqc,
- csxs = cs-csxd;
-
- *Gcdsb = AG1*csxd;
- *Gcdgb = AG1*(cgxd - *Covlgd);
- *Gcddb = AG1*(cdxd + *Covlgd);
-
- *Gcsdb = AG1*cdxs;
- *Gcsgb = AG1*(cgxs - *Covlgs);
- *Gcssb = AG1*(csxs + *Covlgs);
-
- *Gcggb = AG1*(*Cggb + *Covlgd + *Covlgs + *Covlgb);
- *Gcgdb = AG1*(*Cgdb - *Covlgd);
- *Gcgsb = AG1*(*Cgsb - *Covlgs);
-
- *Gcbgb = AG1*(*Cbgb - *Covlgb);
- *Gcbdb = AG1*(*Cbdb);
- *Gcbsb = AG1*(*Cbsb);
-
- /* compute total terminal charges */
-
- { double
- qgd = *Covlgd * *Vgd,
- qgs = *Covlgs * *Vgs,
- qgb = *Covlgb * *Vgb;
-
- *Qgate += qgd + qgs + qgb;
- *Qbulk -= qgb;
-
- *Qdrn = *Qchan*Xqc - qgd;
- *Qsrc = *Qchan*(1-Xqc) - qgs;
- }
- } /* done */
-
- /**/
- #ifndef cc_noline
- #line 4 "Cmeyer"
- #endif
-
- void Cmeyer( /* evaluate MOS capacitances (Meyer model) */
- Model, /* device model */
- Vgs, Vgd, Vgb,/* device voltages */
- Von, Vdsat,
- Cgs, Cgd, Cgb /* return: device capacitances */
- )
- struct M_ *Model;
- double *Vgs, *Vgd, *Vgb, *Von, *Vdsat, *Cgs, *Cgd, *Cgb;
-
- /*
- pwt 86-08-28 creation
- pwt 87-09-15 re-written to do one set of calc's at a time
- and use pointers instead of copying d.p. floats
- pwt 87-12-21 correction for Microsoft optimization
- */
- { double
- vds = *Vgs - *Vgd,
- vgbt = *Von - *Vgs; /* gate: voltage "below" threshold */
-
- *Cgs = *Cgd = *Cgb = 0.;
-
- if ( vgbt >= ModPhi )
- *Cgb = Cox;
-
- else if ( vgbt >= .5*ModPhi )
- *Cgb = Cox*vgbt/ModPhi;
-
- else if ( vgbt >= 0. ) {
- *Cgb = Cox*vgbt/ModPhi;
- *Cgs = (.5*Cox - *Cgb)/.75;
- }
- else {
- double
- vbs = *Vgs - *Vgb,
- vdbsat = *Vdsat - vbs,
- vdb = MAX( *Vgb - *Vgd, 0.0);
-
- if ( vdbsat <= vdb )
- *Cgs = Cox/1.5;
-
- else {
- double
- vddif = 2*vdbsat - vdb,
- vddif1 = vdbsat - vdb - 1E-12,
- vddif2 = vddif*vddif;
-
- *Cgd = Cox*(1 - vdbsat*vdbsat/vddif2)/1.5;
- *Cgs = Cox*(1 - vddif1*vddif1/vddif2)/1.5;
- } }
-
- /* insure that cgd and cgs become equal for small Vds */
-
- if ( vds < .1 ) {
- double
- cgs = *Cgs,
- cgd = *Cgd,
- fact = (vds/.1 + 1)/2;
-
- *Cgs = (cgs - cgd)*fact + cgd,
- *Cgd = (cgd - cgs)*fact + cgs;
- }
- } /* done */
-
- /**/
- #ifndef cc_noline
- #line 4 "Mqspof"
- #endif
-
- void Mqspof( /* calc. "on" capacitances and charges for MOS levels 2 & 3 */
- Model,
- Vds, Vbs, Vgs,
- Vpof, Von,
- Vdsat, Vdsat1,
- Cggb, Cgdb, Cgsb,
- Cbgb, Cbdb, Cbsb,
- Qgate, Qchan, Qbulk
- )
- struct M_ *Model;
- double Vds, Vbs, Vgs, Vpof, Von, Vdsat, Vdsat1;
- double
- *Cggb, *Cgdb, *Cgsb,
- *Cbgb, *Cbdb, *Cbsb,
- *Qgate, *Qchan, *Qbulk;
-
- /*
- pwt 86-08-29 creation
- pwt 87-10-10 re-work as part of BSIM addition
- */
- {
- double qcpof,
- qgate1, qcpof1, qbulk1, cggb1, cgdb1, cgsb1, cbgb1, cbdb1, cbsb1,
- qgate2, qcpof2, qbulk2, cggb2, cgdb2, cgsb2, cbgb2, cbdb2, cbsb2;
-
- /* Vdsat1 = MAX(Vds,Vdsat1)+1E-3;
- */
-
- switch ( ModLevel ) {
- case 2:
- MOS2cap(Model,Vds,Vbs,Vgs, Vdsat, Cggb, Cgdb, Cgsb, Cbgb, Cbdb, Cbsb, Qgate, Qchan,Qbulk);
- if ( Vds > Vdsat ) return;
- MOS2cap(Model,Vds, Vbs,Vpof,Vdsat1,&cggb1,&cgdb1,&cgsb1,&cbgb1,&cbdb1,&cbsb1,&qgate1,&qcpof1,&qbulk1);
- MOS2cap(Model,Vdsat,Vbs, Vgs,Vdsat, &cggb2,&cgdb2,&cgsb2,&cbgb2,&cbdb2,&cbsb2,&qgate2,&qcpof2,&qbulk2);
- break;
- case 3:
- MOS3cap(Model,Vds,Vbs,Vpof,Von,Vdsat1,&cggb1,&cgdb1,&cgsb1,&cbgb1,&cbdb1,&cbsb1,Qgate,&qcpof,Qbulk);
- MOS3cap(Model,Vds,Vbs,Vgs, Von,Vdsat, Cggb, Cgdb, Cgsb, Cbgb, Cbdb, Cbsb, Qgate, Qchan,Qbulk);
- break;
- default:
- return;
- }
-
- /* tangential limiting of qs */
-
- if ( Vgs > Vpof ||
- Vds < Vdsat ) {
- double qd,
- csgb1 = -(1-ModXqc)*(cggb1+cbgb1),
- qs = csgb1*(Vgs-Vpof) + (1-ModXqc)*qcpof1,
- qspof2 = (1-ModXqc)*qcpof2;
-
- if ( fabs(qs) < fabs(qspof2) ) qs = qspof2;
-
- if ( fabs(qs) < .5*fabs(*Qchan) ) {
- Xqc = .5;
- return;
- }
-
- /* csdb = -.25*(cgdb+cbdb);
- * qs = qs + csdb*(Vdsat-Vds);
- * Xqc = MIN(.5,(*Qchan-qs)/(*Qchan));
- */
- qd = *Qchan - qs;
- Xqc = qd/(*Qchan);
-
- /* insure that Xqc = .5 @ Vds = 0 */
-
- if ( Vds < Vdsat ) Xqc = Xqc + ((Vdsat-Vds)/Vdsat)*(.5-Xqc);
-
- /* constant limiting of qs */
-
- /* qdpof = qcpof*ModXqc;
- * qspof = qcpof - qdpof;
- *
- * if ( fabs(qspof) > .5*fabs(*Qchan) ) {
- * qd = *Qchan - qspof;
- * qs = qspof;
- * Xqc = qd/(*Qchan);
- * }
- * else Xqc = .5;
- */
- }
- else Xqc = ModXqc;
-
- } /* done */