home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************/
- /* Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991 */
- /* By MicroSim Corporation, All Rights Reserved */
- /****************************************************************************/
- /* mos3.c
- * $Revision: 1.8 $
- * $Author: whb $
- * $Date: 04 Mar 1991 13:55:22 $ */
-
- #include "option1.h"
- #include "mos.fd"
-
- /* these are set in MOS3eval and used there, and later in MOS3cap */
-
- static double
- Cox,
- Eta,
- Short,
- Narrow,
- Qspof;
-
- #define PARAM(a) ((double)Model->a)
- #define DELTA_MOS PARAM(M_delta)
- #define ETA PARAM(M_eta)
- #define GAMMA PARAM(M_gamma)
- #define KAPPA PARAM(M_kappa)
- #define KP PARAM(M_kp)
- #define LAMBDA PARAM(M_lambda)
- #define LD PARAM(M_ld)
- #define NFS PARAM(M_nfs)
- #define PHI PARAM(M_phi)
- #define THETA PARAM(M_theta)
- #define TOX PARAM(M_tox)
- #define TYPE (Model->M_type)
- #define UO PARAM(M_uo)
- #define VBI PARAM(M_vbi)
- #define VMAX PARAM(M_vmax)
- #define XD PARAM(M_xd)
- #define XJ PARAM(M_xj)
- /**/
- #ifndef cc_noline
- #line 4 "MOS3eval"
- #endif
-
- void MOS3eval( /* evaluate MOS level 3 (semi-empirical, small geometry) model */
- Model, /* (pointer to) model */
- Len, Wid, Mdev, /* effective device size */
- Vgs, Vds, Vbs, /* terminal voltages */
- Von, Vdsat, /* (pointer to) device voltages (returned) */
- Id, /* (pointer to) drain current (returned) */
- Gds, Gm, Gmbs, /* (pointer to) device conductances (returned) */
- Charge, /* do charge calculations (YES/NO) */
- Cggb, Cgdb, Cgsb, /* (pointer to) device capacitances (returned) */
- Cbgb, Cbdb, Cbsb,
- Qgate, Qchan, Qbulk /* (pointer to) device charges (returned) */
- )
- struct M_ *Model;
- double Len, Wid, Mdev, Vgs, Vds, Vbs, *Von, *Vdsat, *Id, *Gds, *Gm, *Gmbs;
- int Charge;
- double *Cggb, *Cgdb, *Cgsb, *Cbgb, *Cbdb, *Cbsb, *Qgate, *Qchan, *Qbulk;
- /*
- 86-08-28 pwt - creation
- 87-10-10 pwt - re-work as part of BSIM addition
- 88-01-05 pwt - parameter M_tox now oxide thickness, not Cox
- 89-04-15 pwt - add device multiplier, to fix narrow-channel calculation
- 89-06-12 whjb - Made use of EXP() macro
- 90-02-12 sv - add local temperatures to models.
- * whjb - 04 Mar 91 - Corrected bug in weak inversion code
- */
- { double
- vgsx, vdsx, /* voltages */
- beta, gds0, gdsx, vdsat1,
- vth, /* threshold voltage & derivatives */
- dvtdvd, dvtdvb,
- vpof, /* pinch-off voltage */
- cdo, cd1, cdnorm, /* drain currents factors */
- dcodvb, /* & derivatives */
- onxl, /* = 1/Len */
- fgate, onfg, us, /* mobility vs. gate voltage factors */
- dfgdvg, dfgdvd, dfgdvb, /* & derivatives */
- vdsc, onvdsc, /* saturation voltage factors */
- dvsdvg, dvsdvd, dvsdvb, /* & derivatives */
- fdrain, /* Vmax related currents */
- dfddvg, dfddvd, dfddvb, /* & derivatives */
- xn, dxndvb, /* weak inversion: Von = Vth + xn*VT */
- dvodvb, dvodvd,
- dfsdvb, /* short-channel effect derivatives */
- fbody, onfbdy, dfbdvb, /* body effect & derivatives */
- qbonco, dqbdvb, /* bulk charge & derivatives */
- phibs, sqphbs, dsqdvb; /* factors & derivatives */
- #define vt VT
-
- static double /* empirical constants */
- coeff0 = 0.0631353,
- coeff1 = 0.8013292,
- coeff2 = -0.01110777;
-
-
- /* note: charge flag == NO ... charge calculations are never done!
- *
- * after tests are running, (maybe) use code similar to MOS2 flag setting
- * NOTE: I have noticed problems with the values of VPOF and VDSAT1
- */
-
- beta = KP*Wid/Len;
- Cox = Wid*Len*EPSOX/TOX;
- Narrow = DELTA_MOS/(Wid/Mdev);
-
- /* reference Id equations to source and charge equations to bulk */
-
- *Vdsat = *Qgate = *Qchan = *Qbulk = *Cgdb = *Cbdb = 0.;
-
- onxl = 1/Len;
- Eta = ETA*onxl*onxl*onxl;
-
- /* square root term */
-
- if ( Vbs > 0. ) {
- double sqphis = sqrt(PHI);
-
- sqphbs = sqphis/(1 + Vbs/(PHI+PHI) );
- phibs = sqphbs*sqphbs;
- dsqdvb = -.5*phibs/(PHI*sqphis);
- }
- else {
- phibs = PHI-Vbs;
- sqphbs = sqrt(phibs);
- dsqdvb = -.5/sqphbs;
- }
-
- /* short-channel effect factor */
-
- if ( XJ == 0. || XD == 0. ) {
- dfsdvb = 0.;
- Short = 1.;
- }
- else {
- double
- wps = XD*sqphbs,
- onxj = 1/XJ,
- xjonxl = XJ*onxl,
- djonxj = LD*onxj,
- wponxj = wps*onxj,
- wconxj = (coeff2*wponxj + coeff1)*wponxj + coeff0,
- arga = wconxj + djonxj,
- argc = wponxj/( 1 + wponxj ),
- argb = sqrt( 1 - argc*argc ),
- dwpdvb = XD*dsqdvb,
- dadvb = ( coeff1 + coeff2*( wponxj + wponxj ))*dwpdvb*onxj,
- dbdvb = -argc*argc*( 1 - argc )*dwpdvb/(argb*wps);
-
- dfsdvb = -xjonxl*( dadvb*argb + arga*dbdvb );
- Short = 1 - xjonxl*( arga*argb - djonxj );
- }
-
- { double /* threshold voltage effects */
- gammas, fbodys, vbix;
-
- /* body effect*/
-
- gammas = GAMMA*Short;
- fbodys = .25*gammas/sqphbs;
- fbody = fbodys + Narrow;
- onfbdy = 1/( 1 + fbody );
- dfbdvb = -fbodys*dsqdvb/sqphbs + fbodys*dfsdvb/Short;
- qbonco = gammas*sqphbs + Narrow*phibs;
- dqbdvb = gammas*dsqdvb + GAMMA*dfsdvb*sqphbs - Narrow;
-
- /* static feedback effect */
-
- vbix = TYPE*VBI - Eta*Vds;
-
- /* threshold voltage */
-
- vth = vbix + qbonco;
- dvtdvd = -Eta;
- dvtdvb = dqbdvb;
- }
-
- /* joint weak inversion and strong inversion */
-
- *Von = vth;
- if ( NFS == 0.) {
-
- if ( Vgs <= *Von ) { /* cut-off region */
- *Id = *Gm = *Gds = *Gmbs = 0.;
-
- if ( Charge == YES ) {
- MOS3cap(Model,Vds,Vbs,vpof,*Von,vdsat1,Cggb,Cgdb,Cgsb,Cbgb,Cbdb,Cbsb,Qgate,Qchan,Qbulk);
- /*** ^^^^ ^^^^^^ undefined here ***/
- }
- Qspof = 0.;
-
- return; /*** done ***/
- } }
- else {
- double
- /* csonco = CHARGE*NFS*Len*Wid/Cox,*/
- /* csonco = CHARGE*NFS/COX,*/
- csonco = CHARGE*NFS*TOX/EPSOX,
- cdonco = .5*qbonco/phibs;
-
- xn = 1 + csonco + cdonco;
- *Von = vth + vt*xn;
- dxndvb = .5*dqbdvb/phibs - qbonco*dsqdvb/(phibs*sqphbs);
- dvodvd = dvtdvd;
- dvodvb = dvtdvb + vt*dxndvb;
- }
-
- /* device is on */
-
- vgsx = MAX(Vgs,*Von);
-
- /* mobility modulation by gate voltage */
-
- onfg = 1 + THETA*(vgsx-vth);
- fgate = 1/onfg;
- us = UO*fgate;
- dfgdvg = -THETA*fgate*fgate;
- dfgdvd = -dfgdvg*dvtdvd;
- dfgdvb = -dfgdvg*dvtdvb;
-
- /* saturation voltage */
-
- *Vdsat =
- vpof = (vgsx-vth)*onfbdy;
-
- if ( VMAX > 0.) {
- double arga, argb, dvsdga;
-
- vdsc = Len*VMAX/us;
- onvdsc = 1/vdsc;
- arga = ( vgsx - vth )*onfbdy;
- argb = sqrt( arga*arga + vdsc*vdsc );
- *Vdsat = arga + vdsc - argb;
- dvsdga = ( 1 - arga/argb )*onfbdy;
- dvsdvg = dvsdga - ( 1 - vdsc/argb )*vdsc*dfgdvg*onfg;
- dvsdvd = -dvsdvg*dvtdvd;
- dvsdvb = -dvsdvg*dvtdvb - arga*dvsdga*dfbdvb;
- }
- else {
- dvsdvg = onfbdy;
- dvsdvd = -dvsdvg*dvtdvd;
- dvsdvb = -dvsdvg*dvtdvb - (*Vdsat)*dfbdvb*onfbdy;
- }
-
- /* current factors in linear region */
-
- vdsx = MIN(Vds,*Vdsat);
- if ( vdsx == 0. ) { /* special case of Vds = 0 */
- *Id = *Gm = *Gmbs = 0.;
- beta *= fgate;
- *Gds = beta*(vgsx-vth);
- if ( NFS != 0. && Vgs < *Von )
- *Gds *= EXP((Vgs - *Von)/(vt*xn));
-
- if ( Charge == YES )
- MOS3cap(Model,Vds,Vbs,vpof,*Von,vdsat1,Cggb,Cgdb,Cgsb,Cbgb,Cbdb,Cbsb,Qgate,Qchan,Qbulk);
- /*** ^^^^^^ undefined here ***/
- Qspof = 0.;
-
- return; /* done */
- }
-
- cdo = vgsx - vth - .5*( 1 + fbody )*vdsx;
- dcodvb = -dvtdvb - .5*dfbdvb*vdsx;
-
- /* normalized drain current */
-
- cdnorm = cdo*vdsx;
- *Gm = vdsx;
- *Gds = -dvtdvd*vdsx;
- gdsx = vgsx - vth - ( 1 + fbody )*vdsx;
- *Gmbs = dcodvb*vdsx;
-
- /* drain current without velocity saturation effect */
-
- cd1 = beta*cdnorm;
- beta *= fgate;
- *Id = beta*cdnorm;
- *Gm = beta*(*Gm) + dfgdvg*cd1;
- *Gds = beta*(*Gds);
- gdsx = beta*(gdsx) + dfgdvd*cd1;
- *Gmbs = beta*(*Gmbs);
-
- /* velocity saturation factor */
-
- if ( VMAX != 0.) {
- double arga, fd2;
-
- fdrain = 1/( 1 + vdsx*onvdsc );
- fd2 = fdrain*fdrain;
- arga = fd2*vdsx*onvdsc*onfg;
- dfddvg = -dfgdvg*arga;
- dfddvd = -dfgdvd*arga - fd2*onvdsc;
- dfddvb = -dfgdvb*arga;
-
- /* drain current with velocity saturation effect */
-
- *Gm = fdrain*(*Gm) + dfddvg**Id;
- *Gds = fdrain*(*Gds);
- gdsx = fdrain*(gdsx) + dfddvd**Id;
- *Gmbs = fdrain*(*Gmbs) + dfddvb**Id;
- *Id = fdrain*(*Id);
- beta *= fdrain;
- }
-
- /* channel length modulation */
-
- if ( Vds > *Vdsat && (VMAX == 0. || LAMBDA != 0.) ) {
- double delxl, dldvd, ddldvg, ddldvd, ddldvb;
-
- if ( VMAX == 0.) {
- delxl = sqrt(KAPPA*(Vds - *Vdsat)*LAMBDA);
- dldvd = .5*delxl/(Vds - *Vdsat);
- ddldvg = 0.;
- ddldvd = -dldvd;
- ddldvb = 0.;
- }
- else {
- double
- idsat,
- gdsat, gdoncd, gdonfd, gdonfg,
- emax, emoncd, emongd,
- dgdvg, dgdvd, dgdvb,
- demdvg, demdvd, demdvb, dldem,
- arga, argb, argc;
-
- idsat = *Id;
- gdsat = idsat*( 1 - fdrain )*onvdsc;
- gdsat = MAX(1E-12,gdsat);
- gdoncd = gdsat/idsat;
- gdonfd = gdsat/( 1 - fdrain );
- gdonfg = gdsat*onfg;
- dgdvg = gdoncd*(*Gm) - gdonfd*dfddvg + gdonfg*dfgdvg;
- dgdvd = gdoncd*(*Gds) - gdonfd*dfddvd + gdonfg*dfgdvd;
- dgdvb = gdoncd*(*Gmbs) - gdonfd*dfddvb + gdonfg*dfgdvb;
-
- emax = idsat*onxl/gdsat;
- emoncd = emax/idsat;
- emongd = emax/gdsat;
- demdvg = emoncd*(*Gm) - emongd*dgdvg;
- demdvd = emoncd*(*Gds) - emongd*dgdvd;
- demdvb = emoncd*(*Gmbs) - emongd*dgdvb;
-
- arga = .5*emax*LAMBDA;
- argc = KAPPA*LAMBDA;
- argb = sqrt( arga*arga + argc*(Vds - *Vdsat) );
- delxl = argb - arga;
- dldvd = argc/(argb+argb);
- dldem = .5*( arga/argb - 1 )*LAMBDA;
- ddldvg = dldem*demdvg;
- ddldvd = dldem*demdvd - dldvd;
- ddldvb = dldem*demdvb;
- }
-
- /* punch through approximation */
-
- if ( delxl > .5*Len ) {
- double arga;
-
- delxl = Len - .25*Len*Len/delxl;
- arga = 4*(Len-delxl)*(Len-delxl)/(Len*Len);
- ddldvg *= arga;
- ddldvd *= arga;
- ddldvb *= arga;
- dldvd *= arga;
- }
-
- /* saturation region */
-
- { double diddl,
- dlonxl = delxl*onxl,
- xlfact = 1/( 1 - dlonxl );
-
- *Id *= xlfact;
- diddl = *Id/(Len-delxl);
- *Gm = xlfact*(*Gm) + diddl*ddldvg;
- *Gds = xlfact*(*Gds);
- gds0 = xlfact*(gdsx) + diddl*ddldvd;
- *Gmbs = xlfact*(*Gmbs) + diddl*ddldvb;
- *Gm += gds0*dvsdvg;
- *Gmbs += gds0*dvsdvb;
- gdsx = gds0*dvsdvd + diddl*dldvd;
- }
-
- }
- *Gds += gdsx;
-
- /* finish strong inversion case */
-
- if ( Vgs < *Von ) { /* weak inversion */
- double gms, gmw,
- onxn = 1/xn,
- argg = onxn/vt,
- argt = (Vgs - *Von)*argg,
- expg = EXP(argt),
- cdson = *Id;
-
- *Id = cdson*expg;
- gmw = *Id*argg;
- gms = *Gm*expg;
- *Gm = gmw;
- if ( Vds > *Vdsat )
- *Gm += gds0*dvsdvg*(*Id/cdson);
-
- *Gds = (*Id/cdson)*(*Gds) + (gms-gmw)*dvodvd;
- *Gmbs = (*Id/cdson)*(*Gmbs) + (gms-gmw)*dvodvb - gmw*(Vgs - *Von)*onxn*dxndvb;
- }
-
- /* charge computation */
-
- if ( Charge == NO ) Qspof = 0.;
- else {
- if ( Vgs > vth ) {
- Mqspof(Model,Vds,Vbs,Vgs,vpof,*Von,*Vdsat,vdsat1,Cggb,Cgdb,Cgsb,Cbgb,Cbdb,Cbsb,Qgate,Qchan,Qbulk);
- /*** ^^^^^^ undefined here ***/
- }
- else {
- MOS3cap(Model,Vds,Vbs,vpof,*Von,vdsat1,Cggb,Cgdb,Cgsb,Cbgb,Cbdb,Cbsb,Qgate,Qchan,Qbulk);
- /*** ^^^^^^ undefined here ***/
- Qspof = 0.;
- } }
-
- } /* done */
-
- /**/
- #ifndef cc_noline
- #line 4 "MOS3cap"
- #endif
-
- void
- MOS3cap(Model, Vds, Vbs, Vgs, Von, Vdsat,
- Cggb, Cgdb, Cgsb,
- Cbgb, Cbdb, Cbsb,
- Qgate, Qchan, Qbulk
- )
-
- /* calculate MOS level 3 capacitance and charge */
-
- struct M_ *Model;
-
- double
- Vds, Vbs, Vgs, Von, Vdsat;
-
- double
- *Qgate, *Qchan, *Qbulk,
- *Cggb, *Cgdb, *Cgsb,
- *Cbgb, *Cbdb, *Cbsb;
-
- /* Author
- PWT 86-08-29 creation
- PWT 87-10-10 re-work as part of BSIM addition
- */
- { double vgb, vfb, phibs;
- double gammas, qbonco;
- double vbix, vth;
- double vbi = TYPE*VBI;
-
- /*** these are never initialized ***/
- double sqphbs, dsqdvb, dfsdvb;
-
- /* charge equations are referenced to bulk */
-
- vgb = Vgs - Vbs;
- vfb = vbi - PHI;
- /* onxl = 1/Len, not used */
- phibs = sqphbs*sqphbs;
-
- /* body effect */
-
- gammas = GAMMA*Short;
- qbonco = gammas*sqphbs + Narrow*phibs;
-
- /* static feedback effect */
-
- vbix = vbi - Eta*Vds;
-
- /* threshold voltage */
-
- vth = vbix + qbonco;
-
- /* branch according to region of operation */
-
- if ( Vgs > vth ) {
- double
- fbodys = .5*gammas/( sqphbs + sqphbs ),
- fbody = fbodys + Narrow,
- onfbdy = 1/( 1 + fbody ),
- dfbdvb = -fbodys*dsqdvb/sqphbs + fbodys*dfsdvb/Short,
- dqbdvb = gammas*dsqdvb + GAMMA*dfsdvb*sqphbs - Narrow,
- dvtdvd = -Eta,
- dvtdvb = dqbdvb,
- vgsx = MAX(Vgs,Von),
- vdsx = MIN(Vds,Vdsat);
-
- if ( vdsx == 0. ) { /* special case */
- *Qgate = Cox*(Vgs-vbi);
- *Qbulk = -Cox*qbonco;
- *Cggb = Cox;
- *Cgdb = -Cox*( .5 + dvtdvd );
- *Cgsb = -Cox*( .5 - dvtdvb );
- *Cbgb = 0.;
- *Cbdb = -.5*Cox*fbody;
- *Cbsb = Cox*( dqbdvb + .5*fbody );
- }
- else {
- double cdo, dcodvg, dcodvd, dcodvb;
- double arga, dadco, dadvd, dadfb;
-
- cdo = vgsx - vth - .5*(1+fbody)*vdsx;
- dcodvg = 1.;
- if ( Vds < Vdsat ) dcodvd = -dvtdvd - .5*(1+fbody);
- dcodvb = -dvtdvb - .5*dfbdvb*vdsx;
-
- /* charge terms */
-
- arga = (1+fbody)*vdsx*vdsx/(12*cdo);
- dadco = -arga/cdo;
- if ( Vds < Vdsat ) dadvd = arga/vdsx;
- dadfb = arga*onfbdy;
-
- /* gate charge */
-
- *Qgate = Cox*( Vgs - vbix - .5*vdsx + arga );
- *Cggb = Cox*( 1 + dadco*dcodvg );
- if ( Vds < Vdsat ) *Cgdb = Cox*( -dvtdvd - .5 + dadvd + dadco*dcodvd);
- *Cgsb = -*Cggb - *Cgdb - Cox*( dadco*dcodvb + dadfb*dfbdvb );
-
- /* bulk charge */
-
- arga = arga*fbody;
- dadco = dadco*fbody;
- if ( Vds < Vdsat ) dadvd = dadvd*fbody;
- dadfb = dadfb*( 1 + fbody + fbody );
-
- *Qbulk = -Cox*( qbonco + .5*fbody*vdsx - arga );
- *Cbgb = Cox*dadco*dcodvg;
- if ( Vds < Vdsat ) *Cbdb = -Cox*( .5*fbody - dadvd - dadco*dcodvd );
- *Cbsb = -*Cbgb - *Cbdb + Cox*( dqbdvb + ( .5*vdsx - dadfb )*dfbdvb - dadco*dcodvb );
- }
- }
- else { /* charge terms of Vgs < vth */
- if ( vgb > vfb ) {
- double
- gamma2 = .5*gammas,
- arga = sqrt( gamma2*gamma2 + (vgb-vfb) );
-
- *Qgate = gammas*Cox*( arga - gamma2 );
- *Cggb = .5*Cox*gammas/arga;
- }
- else {
- *Qgate = Cox*(vgb-vfb);
- *Cggb = Cox;
- }
- *Qbulk = -*Qgate;
- *Cbgb = -*Cggb;
- *Cgdb = *Cgsb = *Cbdb = *Cbsb = 0.;
- }
-
- *Qchan = -( *Qgate + *Qbulk );
-
- /* done */
-
- }