/********** Copyright 1999 Regents of the University of California. All rights reserved. Author: Weidong Liu and Pin Su Feb 1999 Author: 1998 Samuel Fung, Dennis Sinitsky and Stephen Tang Modified by Pin Su, Wei Jin 99/9/27 Modified by Paolo Nenzi 2002 File: b3soifdld.c 98/5/01 **********/ /* * Revision 2.1 99/9/27 Pin Su * BSIMFD2.1 release */ #include "ngspice.h" #include "cktdefs.h" #include "b3soifddef.h" #include "trandefs.h" #include "const.h" #include "sperror.h" #include "devdefs.h" #include "suffix.h" #ifdef _MSC_VER extern int _isnan(double); #endif #define MAX_EXP 5.834617425e14 #define MIN_EXP 1.713908431e-15 #define EXP_THRESHOLD 34.0 #define EPSOX 3.453133e-11 #define EPSSI 1.03594e-10 #define Charge_q 1.60219e-19 #define KboQ 8.617087e-5 /* Kb / q */ #define Eg300 1.115 /* energy gap at 300K */ #define DELTA_1 0.02 #define DELTA_2 0.02 #define DELTA_3 0.02 #define DELTA_4 0.02 #define DELT_Vbs0eff 0.02 #define DELT_Vbsmos 0.005 #define DELT_Vbseff 0.005 #define DELT_Xcsat 0.2 #define DELT_Vbs0dio 1e-7 #define DELTA_VFB 0.02 #define DELTA_Vcscv 0.0004 #define DELT_Vbsdio 0.01 #define CONST_2OV3 0.6666666666 #define OFF_Vbsdio 2e-2 #define OFF_Vbs0_dio 2.02e-2 #define QEX_FACT 20 /* B3SOIFDSmartVbs(Vbs, Old, here, check) * Smart Vbs guess. */ double B3SOIFDSmartVbs(double New, double Old, B3SOIFDinstance *here, CKTcircuit *ckt, int *check) { /* only do it for floating body and DC */ if (here->B3SOIFDfloat && (ckt->CKTmode & (MODEDC | MODEDCOP))) { /* Vbs cannot be negative in DC */ if (New < 0.0) New = 0.0; } return(New); } /* B3SOIFDlimit(vnew,vold) * limits the per-iteration change of any absolute voltage value */ double B3SOIFDlimit(double vnew, double vold, double limit, int *check) { double T0, T1; if (isnan (vnew) || isnan (vold)) { fprintf(stderr, "Alberto says: YOU TURKEY! The limiting function received NaN.\n"); fprintf(stderr, "New prediction returns to 0.0!\n"); vnew = 0.0; *check = 1; } T0 = vnew - vold; T1 = fabs(T0); if (T1 > limit) { if (T0 > 0.0) vnew = vold + limit; else vnew = vold - limit; *check = 1; } return vnew; } int B3SOIFDload(GENmodel *inModel, CKTcircuit *ckt) { B3SOIFDmodel *model = (B3SOIFDmodel*)inModel; B3SOIFDinstance *here; int selfheat; double ag0, qgd, qgs, von, cbhat, VgstNVt, ExpVgst = 0.0; double cdhat, cdreq, ceqbd, ceqbs, ceqqb, ceqqd, ceqqg, ceq, geq; double delvbd, delvbs, delvds, delvgd, delvgs; double Vfbeff, dVfbeff_dVd, dVfbeff_dVb, V3, V4; double gcgdb, gcggb, gcgsb, gcgeb, gcgT; double gcsdb, gcsgb, gcssb, gcseb, gcsT; double gcddb, gcdgb, gcdsb, gcdeb, gcdT; double gcbdb, gcbgb, gcbsb, gcbeb, gcbT; double gcedb, gcegb, gcesb, gceeb, gceT; double gcTt, gTtg, gTtb, gTte, gTtdp, gTtt, gTtsp; double vbd, vbs, vds, vgb, vgd, vgs, vgdo, xfact; double vg, vd, vs, vp, ve, vb; double Vds, Vgs, Vbs, Gmbs, FwdSum, RevSum; double Vgs_eff, Vfb, dVfb_dVb, dVfb_dVd, dVfb_dT; double Phis, dPhis_dVb, sqrtPhis, dsqrtPhis_dVb, Vth = 0.0, dVth_dVb; double dVth_dVd, dVth_dT; double Vgst, dVgs_eff_dVg; double n, dn_dVb, Vtm; double ExpArg, V0; double ueff = 0.0, dueff_dVg, dueff_dVd, dueff_dVb, dueff_dT; double Esat, Vdsat = 0.0; double EsatL, dEsatL_dVg, dEsatL_dVd, dEsatL_dVb, dEsatL_dT; double dVdsat_dVg, dVdsat_dVb, dVdsat_dVd, dVdsat_dT, Vasat; double dVasat_dVg, dVasat_dVb, dVasat_dVd, dVasat_dT; double Va, dVa_dVd, dVa_dVg, dVa_dVb, dVa_dT; double Vbseff, dVbseff_dVb; double One_Third_CoxWL, Two_Third_CoxWL, CoxWL; double T0, dT0_dVg, dT0_dVd, dT0_dVb, dT0_dVc, dT0_dVe, dT0_dT; double T1, dT1_dVg, dT1_dVd, dT1_dVb, dT1_dVc, dT1_dVe, dT1_dT; double T2, dT2_dVg, dT2_dVd, dT2_dVb, dT2_dVc, dT2_dVe, dT2_dT; double T3, dT3_dVg, dT3_dVd, dT3_dVb, dT3_dVc, dT3_dVe, dT3_dT; double T4, dT4_dVg, dT4_dVd, dT4_dVb, dT4_dVe, dT4_dT; double T5, dT5_dVe; double T6, dT6_dVe, dT6_dT; double T7; double T8; double T9; double T10; double T11; double Abulk, dAbulk_dVb, Abulk0, dAbulk0_dVb; double VACLM, dVACLM_dVg, dVACLM_dVd, dVACLM_dVb, dVACLM_dT; double VADIBL, dVADIBL_dVg, dVADIBL_dVd, dVADIBL_dVb, dVADIBL_dT; double Xdep, dXdep_dVb, lt1, dlt1_dVb, ltw, dltw_dVb; double Delt_vth, dDelt_vth_dVb, dDelt_vth_dT; double Theta0, dTheta0_dVb; double TempRatio, tmp1, tmp2, tmp3, tmp4; double DIBL_Sft, dDIBL_Sft_dVd, Lambda, dLambda_dVg; double a1; double Vgsteff = 0.0, dVgsteff_dVg, dVgsteff_dVd, dVgsteff_dVb; double dVgsteff_dVe, dVgsteff_dT; double Vdseff = 0.0, dVdseff_dVg, dVdseff_dVd, dVdseff_dVb, dVdseff_dT; double VdseffCV, dVdseffCV_dVg, dVdseffCV_dVd, dVdseffCV_dVb; double diffVds; double dAbulk_dVg, dn_dVd ; double beta, dbeta_dVg, dbeta_dVd, dbeta_dVb, dbeta_dT; double gche, dgche_dVg, dgche_dVd, dgche_dVb, dgche_dT; double fgche1, dfgche1_dVg, dfgche1_dVd, dfgche1_dVb, dfgche1_dT; double fgche2, dfgche2_dVg, dfgche2_dVd, dfgche2_dVb, dfgche2_dT; double Idl, dIdl_dVg, dIdl_dVd, dIdl_dVb, dIdl_dT; double Ids = 0.0, Gm, Gds = 0.0, Gmb; double CoxWovL; double Rds, dRds_dVg, dRds_dVb, dRds_dT, WVCox, WVCoxRds; double Vgst2Vtm, dVgst2Vtm_dT, VdsatCV, dVdsatCV_dVg, dVdsatCV_dVb; double Leff, Weff, dWeff_dVg, dWeff_dVb; double AbulkCV, dAbulkCV_dVb; double qgdo, qgso, cgdo, cgso; double dxpart, sxpart; struct b3soifdSizeDependParam *pParam; int ByPass, Check, ChargeComputationNeeded = 0, error; double gbbsp, gbbdp, gbbg, gbbb, gbbe, gbbp, gbbT; double gddpsp, gddpdp, gddpg, gddpb, gddpe, gddpT; double gsspsp, gsspdp, gsspg, gsspb, gsspe, gsspT; double Gbpbs, Gbpgs, Gbpds, Gbpes, Gbpps, GbpT; double ves, ved, veb, vge = 0.0, delves, vedo, delved; double vps, vpd, Vps, delvps; double Vbd, Ves, Vesfb, sqrtXdep, DeltVthtemp, dDeltVthtemp_dT; double Vbp, dVbp_dVp, dVbp_dVb, dVbp_dVg, dVbp_dVd, dVbp_dVe, dVbp_dT; double Vpsdio, dVpsdio_dVg, dVpsdio_dVd, dVpsdio_dVe, dVpsdio_dVp, dVpsdio_dT; double DeltVthw, dDeltVthw_dVb, dDeltVthw_dT; double dVbseff_dVd, dVbseff_dVe, dVbseff_dT; double dVdsat_dVc, dVasat_dVc, dVACLM_dVc, dVADIBL_dVc, dVa_dVc; double dfgche1_dVc, dfgche2_dVc, dgche_dVc, dVdseff_dVc, dIdl_dVc; double Gm0, Gds0, Gmb0, GmT0, Gmc, Gme, GmT, dVbseff_dVg; double dDIBL_Sft_dVb; double diffVdsii ; double Idgidl = 0.0, Gdgidld, Gdgidlg, Isgidl = 0.0, Gsgidlg; double Gjsd, Gjsb, GjsT, Gjdd, Gjdb, GjdT; double Ibp = 0.0, Iii = 0.0, Giid, Giig, Giib, Giie, GiiT, Gcd, Gcb, GcT; double ceqbody, ceqbodcon = 0.0; double gppg = 0.0, gppdp = 0.0, gppb = 0.0, gppe = 0.0; double gppp = 0.0, gppsp = 0.0, gppT; double delTemp, deldelTemp, Temp; double ceqth, ceqqth; double K1; double qjs = 0.0, gcjsbs, gcjsT; double qjd = 0.0, gcjdbs, gcjdds, gcjdT; double qge; double ceqqe; double ni, Eg, Cbox, Nfb, CboxWL; double dVfbeff_dVrg, Cbe = 0.0; double qinv = 0.0, qgate = 0.0, qbody = 0.0, qdrn = 0.0, qsrc, qsub = 0.0; double cqgate, cqbody = 0.0, cqdrn = 0.0, cqsub, cqtemp; double Cgg, Cgd, Cgb, Cge; double Csg, Csd, Csb, Cse, Cbg = 0.0, Cbd = 0.0, Cbb = 0.0; double Cgg1, Cgb1, Cgd1, Csg1, Csd1, Csb1; double Vbs0t = 0.0, dVbs0t_dT ; double Vbs0 = 0.0,dVbs0_dVe, dVbs0_dT; double Vbs0eff = 0.0 ,dVbs0eff_dVg ,dVbs0eff_dVd ,dVbs0eff_dVe, dVbs0eff_dT; double Vbs0teff = 0.0, dVbs0teff_dVg, dVbs0teff_dVd; double dVbs0teff_dVe, dVbs0teff_dT; double dVbsdio_dVg, dVbsdio_dVd, dVbsdio_dVe; double dVbsdio_dVb, dVbsdio_dT; double Vthfd = 0.0,dVthfd_dVd ,dVthfd_dVe, dVthfd_dT; double Vbs0mos = 0.0 ,dVbs0mos_dVe, dVbs0mos_dT; double Vbsmos ,dVbsmos_dVg ,dVbsmos_dVb ,dVbsmos_dVd, dVbsmos_dVe, dVbsmos_dT; double Abeff ,dAbeff_dVg ,dAbeff_dVb, dAbeff_dVc; double Vcs ,dVcs_dVg ,dVcs_dVb ,dVcs_dVd ,dVcs_dVe, dVcs_dT; double Xcsat = 0.0 ,dXcsat_dVg , dXcsat_dVc; double Vdsatii ,dVdsatii_dVg ,dVdsatii_dVd, dVdsatii_dVb, dVdsatii_dT; double Vdseffii ,dVdseffii_dVg ,dVdseffii_dVd, dVdseffii_dVb, dVdseffii_dT; double VcsCV = 0.0; double VdsCV = 0.0, dVdsCV_dVg = 0.0, dVdsCV_dVb = 0.0; double dVdsCV_dVd = 0.0, dVdsCV_dVc = 0.0; double Phisd ,dPhisd_dVg ,dPhisd_dVb ,dPhisd_dVd, dPhisd_dVc; double sqrtPhisd; double Xc = 0.0; double Ic = 0.0; double Ibs = 0.0; double Ibd = 0.0; double Denomi ,dDenomi_dVg ,dDenomi_dVd ,dDenomi_dVb , dDenomi_dT; double Qbf = 0.0; double Qsubs1 = 0.0; double Qsubs2 = 0.0; double Qsub0 = 0.0 ,dQsub0_dVg ,dQsub0_dVb ,dQsub0_dVd ; double Qac0 = 0.0 ,dQac0_dVb ,dQac0_dVd; double Qdep0 ,dQdep0_dVb; double Qe1 = 0.0; double Ce1g ,Ce1b ,Ce1d ,Ce1e, Ce1T; double Ce2g ,Ce2b ,Ce2d ,Ce2e, Ce2T; double Qe2 = 0.0; double dQac0_dVrg, Vbsdio = 0.0, dQsub0_dVrg; /* for self-heating */ double vbi, vfbb, phi, sqrtPhi, Xdep0, jbjt, jdif, jrec, jtun, u0temp, vsattemp; double rds0, ua, ub, uc; double dvbi_dT, dvfbb_dT, djbjt_dT, djdif_dT, djrec_dT, djtun_dT, du0temp_dT; double dvsattemp_dT, drds0_dT, dua_dT, dub_dT, duc_dT, dni_dT, dVtm_dT; double dVfbeff_dT, dQac0_dT, dQsub0_dT, dVdsCV_dT = 0.0, dPhisd_dT; double CbT, CsT, CgT; double Qex, dQex_dVg, dQex_dVb, dQex_dVd, dQex_dVe, dQex_dT; /* clean up last */ FILE *fpdebug = NULL; /* end clean up */ int nandetect; static int nanfound = 0; char nanmessage [12]; double m; for (; model != NULL; model = model->B3SOIFDnextModel) { for (here = model->B3SOIFDinstances; here != NULL; here = here->B3SOIFDnextInstance) { if (here->B3SOIFDowner != ARCHme) continue; Check = 0; ByPass = 0; selfheat = (model->B3SOIFDshMod == 1) && (here->B3SOIFDrth0 != 0.0); pParam = here->pParam; if (here->B3SOIFDdebugMod > 3) { if (model->B3SOIFDtype > 0) fpdebug = fopen("b3soifdn.log", "a"); else fpdebug = fopen("b3soifdp.log", "a"); fprintf(fpdebug, "******* Time : %.5e ******* Device: %s Iteration: %d\n", ckt->CKTtime, here->B3SOIFDname, here->B3SOIFDiterations); } if ((ckt->CKTmode & MODEINITSMSIG)) { vbs = *(ckt->CKTstate0 + here->B3SOIFDvbs); vgs = *(ckt->CKTstate0 + here->B3SOIFDvgs); ves = *(ckt->CKTstate0 + here->B3SOIFDves); vps = *(ckt->CKTstate0 + here->B3SOIFDvps); vds = *(ckt->CKTstate0 + here->B3SOIFDvds); delTemp = *(ckt->CKTstate0 + here->B3SOIFDdeltemp); vg = *(ckt->CKTrhsOld + here->B3SOIFDgNode); vd = *(ckt->CKTrhsOld + here->B3SOIFDdNodePrime); vs = *(ckt->CKTrhsOld + here->B3SOIFDsNodePrime); vp = *(ckt->CKTrhsOld + here->B3SOIFDpNode); ve = *(ckt->CKTrhsOld + here->B3SOIFDeNode); vb = *(ckt->CKTrhsOld + here->B3SOIFDbNode); if (here->B3SOIFDdebugMod > 2) { fprintf(fpdebug, "... INIT SMSIG ...\n"); } if (here->B3SOIFDdebugMod > 0) { fprintf(stderr, "DC op. point converge with %d iterations\n", here->B3SOIFDiterations); } } else if ((ckt->CKTmode & MODEINITTRAN)) { vbs = *(ckt->CKTstate1 + here->B3SOIFDvbs); vgs = *(ckt->CKTstate1 + here->B3SOIFDvgs); ves = *(ckt->CKTstate1 + here->B3SOIFDves); vps = *(ckt->CKTstate1 + here->B3SOIFDvps); vds = *(ckt->CKTstate1 + here->B3SOIFDvds); delTemp = *(ckt->CKTstate1 + here->B3SOIFDdeltemp); vg = *(ckt->CKTrhsOld + here->B3SOIFDgNode); vd = *(ckt->CKTrhsOld + here->B3SOIFDdNodePrime); vs = *(ckt->CKTrhsOld + here->B3SOIFDsNodePrime); vp = *(ckt->CKTrhsOld + here->B3SOIFDpNode); ve = *(ckt->CKTrhsOld + here->B3SOIFDeNode); vb = *(ckt->CKTrhsOld + here->B3SOIFDbNode); if (here->B3SOIFDdebugMod > 2) { fprintf(fpdebug, "... Init Transient ....\n"); } if (here->B3SOIFDdebugMod > 0) { fprintf(stderr, "Transient operation point converge with %d iterations\n", here->B3SOIFDiterations); } here->B3SOIFDiterations = 0; } else if ((ckt->CKTmode & MODEINITJCT) && !here->B3SOIFDoff) { vds = model->B3SOIFDtype * here->B3SOIFDicVDS; vgs = model->B3SOIFDtype * here->B3SOIFDicVGS; ves = model->B3SOIFDtype * here->B3SOIFDicVES; vbs = model->B3SOIFDtype * here->B3SOIFDicVBS; vps = model->B3SOIFDtype * here->B3SOIFDicVPS; vg = vd = vs = vp = ve = 0.0; here->B3SOIFDiterations = 0; /* initialize iteration number */ delTemp = 0.0; here->B3SOIFDphi = pParam->B3SOIFDphi; if (here->B3SOIFDdebugMod > 2) fprintf(fpdebug, "... INIT JCT ...\n"); if ((vds == 0.0) && (vgs == 0.0) && (vbs == 0.0) && ((ckt->CKTmode & (MODETRAN | MODEAC|MODEDCOP | MODEDCTRANCURVE)) || (!(ckt->CKTmode & MODEUIC)))) { vbs = 0.0; vgs = model->B3SOIFDtype*0.1 + pParam->B3SOIFDvth0; vds = 0.0; ves = 0.0; vps = 0.0; } } else if ((ckt->CKTmode & (MODEINITJCT | MODEINITFIX)) && (here->B3SOIFDoff)) { delTemp = vps = vbs = vgs = vds = ves = 0.0; vg = vd = vs = vp = ve = 0.0; here->B3SOIFDiterations = 0; /* initialize iteration number */ } else { #ifndef PREDICTOR if ((ckt->CKTmode & MODEINITPRED)) { xfact = ckt->CKTdelta / ckt->CKTdeltaOld[1]; *(ckt->CKTstate0 + here->B3SOIFDvbs) = *(ckt->CKTstate1 + here->B3SOIFDvbs); vbs = (1.0 + xfact)* (*(ckt->CKTstate1 + here->B3SOIFDvbs)) - (xfact * (*(ckt->CKTstate2 + here->B3SOIFDvbs))); *(ckt->CKTstate0 + here->B3SOIFDvgs) = *(ckt->CKTstate1 + here->B3SOIFDvgs); vgs = (1.0 + xfact)* (*(ckt->CKTstate1 + here->B3SOIFDvgs)) - (xfact * (*(ckt->CKTstate2 + here->B3SOIFDvgs))); *(ckt->CKTstate0 + here->B3SOIFDves) = *(ckt->CKTstate1 + here->B3SOIFDves); ves = (1.0 + xfact)* (*(ckt->CKTstate1 + here->B3SOIFDves)) - (xfact * (*(ckt->CKTstate2 + here->B3SOIFDves))); *(ckt->CKTstate0 + here->B3SOIFDvps) = *(ckt->CKTstate1 + here->B3SOIFDvps); vps = (1.0 + xfact)* (*(ckt->CKTstate1 + here->B3SOIFDvps)) - (xfact * (*(ckt->CKTstate2 + here->B3SOIFDvps))); *(ckt->CKTstate0 + here->B3SOIFDvds) = *(ckt->CKTstate1 + here->B3SOIFDvds); vds = (1.0 + xfact)* (*(ckt->CKTstate1 + here->B3SOIFDvds)) - (xfact * (*(ckt->CKTstate2 + here->B3SOIFDvds))); *(ckt->CKTstate0 + here->B3SOIFDvbd) = *(ckt->CKTstate0 + here->B3SOIFDvbs) - *(ckt->CKTstate0 + here->B3SOIFDvds); *(ckt->CKTstate0 + here->B3SOIFDvg) = *(ckt->CKTstate1 + here->B3SOIFDvg); *(ckt->CKTstate0 + here->B3SOIFDvd) = *(ckt->CKTstate1 + here->B3SOIFDvd); *(ckt->CKTstate0 + here->B3SOIFDvs) = *(ckt->CKTstate1 + here->B3SOIFDvs); *(ckt->CKTstate0 + here->B3SOIFDvp) = *(ckt->CKTstate1 + here->B3SOIFDvp); *(ckt->CKTstate0 + here->B3SOIFDve) = *(ckt->CKTstate1 + here->B3SOIFDve); /* Only predict ve */ ve = (1.0 + xfact)* (*(ckt->CKTstate1 + here->B3SOIFDve)) - (xfact * (*(ckt->CKTstate2 + here->B3SOIFDve))); /* Then update vg, vs, vb, vd, vp base on ve */ vs = ve - model->B3SOIFDtype * ves; vg = model->B3SOIFDtype * vgs + vs; vd = model->B3SOIFDtype * vds + vs; vb = model->B3SOIFDtype * vbs + vs; vp = model->B3SOIFDtype * vps + vs; delTemp = (1.0 + xfact)* (*(ckt->CKTstate1 + here->B3SOIFDdeltemp))-(xfact * (*(ckt->CKTstate2 + here->B3SOIFDdeltemp))); if (selfheat) { here->B3SOIFDphi = 2.0 * here->B3SOIFDvtm * log (pParam->B3SOIFDnpeak / here->B3SOIFDni); } if (here->B3SOIFDdebugMod > 0) { fprintf(stderr, "Time = %.6e converge with %d iterations\n", ckt->CKTtime, here->B3SOIFDiterations); } if (here->B3SOIFDdebugMod > 2) { fprintf(fpdebug, "... PREDICTOR calculation ....\n"); } here->B3SOIFDiterations = 0; } else { #endif /* PREDICTOR */ vg = B3SOIFDlimit(*(ckt->CKTrhsOld + here->B3SOIFDgNode), *(ckt->CKTstate0 + here->B3SOIFDvg), 3.0, &Check); vd = B3SOIFDlimit(*(ckt->CKTrhsOld + here->B3SOIFDdNodePrime), *(ckt->CKTstate0 + here->B3SOIFDvd), 3.0, &Check); vs = B3SOIFDlimit(*(ckt->CKTrhsOld + here->B3SOIFDsNodePrime), *(ckt->CKTstate0 + here->B3SOIFDvs), 3.0, &Check); vp = B3SOIFDlimit(*(ckt->CKTrhsOld + here->B3SOIFDpNode), *(ckt->CKTstate0 + here->B3SOIFDvp), 3.0, &Check); ve = B3SOIFDlimit(*(ckt->CKTrhsOld + here->B3SOIFDeNode), *(ckt->CKTstate0 + here->B3SOIFDve), 3.0, &Check); delTemp = *(ckt->CKTrhsOld + here->B3SOIFDtempNode); vbs = model->B3SOIFDtype * (*(ckt->CKTrhsOld+here->B3SOIFDbNode) - *(ckt->CKTrhsOld+here->B3SOIFDsNodePrime)); vps = model->B3SOIFDtype * (vp - vs); vgs = model->B3SOIFDtype * (vg - vs); ves = model->B3SOIFDtype * (ve - vs); vds = model->B3SOIFDtype * (vd - vs); if (here->B3SOIFDdebugMod > 2) { fprintf(fpdebug, "... DC calculation ....\n"); fprintf(fpdebug, "Vg = %.10f; Vb = %.10f; Vs = %.10f\n", *(ckt->CKTrhsOld + here->B3SOIFDgNode), *(ckt->CKTrhsOld + here->B3SOIFDbNode), *(ckt->CKTrhsOld + here->B3SOIFDsNode)); fprintf(fpdebug, "Vd = %.10f; Vsp = %.10f; Vdp = %.10f\n", *(ckt->CKTrhsOld + here->B3SOIFDdNode), *(ckt->CKTrhsOld + here->B3SOIFDsNodePrime), *(ckt->CKTrhsOld + here->B3SOIFDdNodePrime)); fprintf(fpdebug, "Ve = %.10f; Vp = %.10f; delTemp = %.10f\n", *(ckt->CKTrhsOld + here->B3SOIFDeNode), *(ckt->CKTrhsOld + here->B3SOIFDpNode), *(ckt->CKTrhsOld + here->B3SOIFDtempNode)); } #ifndef PREDICTOR } #endif /* PREDICTOR */ vbd = vbs - vds; vgd = vgs - vds; ved = ves - vds; vgdo = *(ckt->CKTstate0 + here->B3SOIFDvgs) - *(ckt->CKTstate0 + here->B3SOIFDvds); vedo = *(ckt->CKTstate0 + here->B3SOIFDves) - *(ckt->CKTstate0 + here->B3SOIFDvds); delvbs = vbs - *(ckt->CKTstate0 + here->B3SOIFDvbs); delvbd = vbd - *(ckt->CKTstate0 + here->B3SOIFDvbd); delvgs = vgs - *(ckt->CKTstate0 + here->B3SOIFDvgs); delves = ves - *(ckt->CKTstate0 + here->B3SOIFDves); delvps = vps - *(ckt->CKTstate0 + here->B3SOIFDvps); deldelTemp = delTemp - *(ckt->CKTstate0 + here->B3SOIFDdeltemp); delvds = vds - *(ckt->CKTstate0 + here->B3SOIFDvds); delvgd = vgd - vgdo; delved = ved - vedo; if (here->B3SOIFDmode >= 0) { cdhat = here->B3SOIFDcd + (here->B3SOIFDgm-here->B3SOIFDgjdg) * delvgs + (here->B3SOIFDgds - here->B3SOIFDgjdd) * delvds + (here->B3SOIFDgmbs - here->B3SOIFDgjdb) * delvbs + (here->B3SOIFDgme - here->B3SOIFDgjde) * delves + (here->B3SOIFDgmT - here->B3SOIFDgjdT) * deldelTemp; } else { cdhat = here->B3SOIFDcd + (here->B3SOIFDgm-here->B3SOIFDgjdg) * delvgd - (here->B3SOIFDgds - here->B3SOIFDgjdd) * delvds + (here->B3SOIFDgmbs - here->B3SOIFDgjdb) * delvbd + (here->B3SOIFDgme - here->B3SOIFDgjde) * delved + (here->B3SOIFDgmT - here->B3SOIFDgjdT) * deldelTemp; } cbhat = here->B3SOIFDcb + here->B3SOIFDgbgs * delvgs + here->B3SOIFDgbbs * delvbs + here->B3SOIFDgbds * delvds + here->B3SOIFDgbes * delves + here->B3SOIFDgbps * delvps + here->B3SOIFDgbT * deldelTemp; #ifndef NOBYPASS /* 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 */ if (here->B3SOIFDdebugMod > 3) { fprintf(fpdebug, "Convergent Criteria : vbs %d vds %d vgs %d ves %d vps %d temp %d\n", ((fabs(delvbs) < (ckt->CKTreltol * MAX(fabs(vbs), fabs(*(ckt->CKTstate0+here->B3SOIFDvbs))) + ckt->CKTvoltTol))) ? 1 : 0, ((fabs(delvds) < (ckt->CKTreltol * MAX(fabs(vds), fabs(*(ckt->CKTstate0+here->B3SOIFDvds))) + ckt->CKTvoltTol))) ? 1 : 0, ((fabs(delvgs) < (ckt->CKTreltol * MAX(fabs(vgs), fabs(*(ckt->CKTstate0+here->B3SOIFDvgs))) + ckt->CKTvoltTol))) ? 1 : 0, ((fabs(delves) < (ckt->CKTreltol * MAX(fabs(ves), fabs(*(ckt->CKTstate0+here->B3SOIFDves))) + ckt->CKTvoltTol))) ? 1 : 0, ((fabs(delvps) < (ckt->CKTreltol * MAX(fabs(vps), fabs(*(ckt->CKTstate0+here->B3SOIFDvps))) + ckt->CKTvoltTol))) ? 1 : 0, ((fabs(deldelTemp) < (ckt->CKTreltol * MAX(fabs(delTemp), fabs(*(ckt->CKTstate0+here->B3SOIFDdeltemp))) + ckt->CKTvoltTol*1e4))) ? 1 : 0); fprintf(fpdebug, "delCd %.4e, delCb %.4e\n", fabs(cdhat - here->B3SOIFDcd) , fabs(cbhat - here->B3SOIFDcb)); } if ((!(ckt->CKTmode & MODEINITPRED)) && (ckt->CKTbypass) && Check == 0) if ((fabs(delvbs) < (ckt->CKTreltol * MAX(fabs(vbs), fabs(*(ckt->CKTstate0+here->B3SOIFDvbs))) + ckt->CKTvoltTol)) ) if ((fabs(delvbd) < (ckt->CKTreltol * MAX(fabs(vbd), fabs(*(ckt->CKTstate0+here->B3SOIFDvbd))) + ckt->CKTvoltTol)) ) if ((fabs(delvgs) < (ckt->CKTreltol * MAX(fabs(vgs), fabs(*(ckt->CKTstate0+here->B3SOIFDvgs))) + ckt->CKTvoltTol))) if ((fabs(delves) < (ckt->CKTreltol * MAX(fabs(ves), fabs(*(ckt->CKTstate0+here->B3SOIFDves))) + ckt->CKTvoltTol))) if ( (here->B3SOIFDbodyMod == 0) || (here->B3SOIFDbodyMod == 2) || (fabs(delvps) < (ckt->CKTreltol * MAX(fabs(vps), fabs(*(ckt->CKTstate0+here->B3SOIFDvps))) + ckt->CKTvoltTol)) ) if ( (here->B3SOIFDtempNode == 0) || (fabs(deldelTemp) < (ckt->CKTreltol * MAX(fabs(delTemp), fabs(*(ckt->CKTstate0+here->B3SOIFDdeltemp))) + ckt->CKTvoltTol*1e4))) if ((fabs(delvds) < (ckt->CKTreltol * MAX(fabs(vds), fabs(*(ckt->CKTstate0+here->B3SOIFDvds))) + ckt->CKTvoltTol))) if ((fabs(cdhat - here->B3SOIFDcd) < ckt->CKTreltol * MAX(fabs(cdhat),fabs(here->B3SOIFDcd)) + ckt->CKTabstol)) if ((fabs(cbhat - here->B3SOIFDcb) < ckt->CKTreltol * MAX(fabs(cbhat),fabs(here->B3SOIFDcb)) + ckt->CKTabstol) ) { /* bypass code */ vbs = *(ckt->CKTstate0 + here->B3SOIFDvbs); vbd = *(ckt->CKTstate0 + here->B3SOIFDvbd); vgs = *(ckt->CKTstate0 + here->B3SOIFDvgs); ves = *(ckt->CKTstate0 + here->B3SOIFDves); vps = *(ckt->CKTstate0 + here->B3SOIFDvps); vds = *(ckt->CKTstate0 + here->B3SOIFDvds); delTemp = *(ckt->CKTstate0 + here->B3SOIFDdeltemp); /* calculate Vds for temperature conductance calculation in bypass (used later when filling Temp node matrix) */ Vds = here->B3SOIFDmode > 0 ? vds : -vds; vgd = vgs - vds; vgb = vgs - vbs; veb = ves - vbs; if (here->B3SOIFDdebugMod > 2) { fprintf(stderr, "Bypass for %s...\n", here->B3SOIFDname); fprintf(fpdebug, "... By pass ....\n"); fprintf(fpdebug, "vgs=%.4f, vds=%.4f, vbs=%.4f, ", vgs, vds, vbs); fprintf(fpdebug, "ves=%.4f, vps=%.4f\n", ves, vps); } if ((ckt->CKTmode & (MODETRAN | MODEAC)) || ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC))) { ByPass = 1; goto line755; } else { goto line850; } } #endif /*NOBYPASS*/ von = here->B3SOIFDvon; if ((here->B3SOIFDdebugMod > 1) || (here->B3SOIFDdebugMod == -1)) { here->B3SOIFDdum1 = here->B3SOIFDdum2 = here->B3SOIFDdum3 = 0.0; here->B3SOIFDdum4 = here->B3SOIFDdum5 = 0.0; Qac0 = Qsub0 = Qsubs1 = Qsubs2 = Qbf = Qe1 = Qe2 = 0.0; qjs = qjd = Cbg = Cbb = Cbd = Cbe = Xc = qdrn = qgate = 0.0; qbody = qsub = 0.0; } if (here->B3SOIFDdebugMod > 2) { fprintf(fpdebug, "Limited : vgs = %.8f\n", vgs); fprintf(fpdebug, "Limited : vds = %.8f\n", vds); } if (*(ckt->CKTstate0 + here->B3SOIFDvds) >= 0.0) T0 = *(ckt->CKTstate0 + here->B3SOIFDvbs); else T0 = *(ckt->CKTstate0 + here->B3SOIFDvbd); if (here->B3SOIFDdebugMod > 2) fprintf(fpdebug, "Before lim : vbs = %.8f, after = ", T0); if (vds >= 0.0) { vbs = B3SOIFDlimit(vbs, T0, 0.2, &Check); vbs = B3SOIFDSmartVbs(vbs, T0, here, ckt, &Check); vbd = vbs - vds; vb = model->B3SOIFDtype * vbs + vs; if (here->B3SOIFDdebugMod > 2) fprintf(fpdebug, "%.8f\n", vbs); } else { vbd = B3SOIFDlimit(vbd, T0, 0.2, &Check); vbd = B3SOIFDSmartVbs(vbd, T0, here, ckt, &Check); vbs = vbd + vds; vb = model->B3SOIFDtype * vbs + vd; if (here->B3SOIFDdebugMod > 2) fprintf(fpdebug, "%.8f\n", vbd); } delTemp =B3SOIFDlimit(delTemp, *(ckt->CKTstate0 + here->B3SOIFDdeltemp),5.0,&Check); } /* Calculate temperature dependent values for self-heating effect */ Temp = delTemp + ckt->CKTtemp; /* for debugging Temp = ckt->CKTtemp; selfheat = 1; if (here->B3SOIFDname[1] == '2') { Temp += 0.01; } */ TempRatio = Temp / model->B3SOIFDtnom; if (selfheat) { Vtm = KboQ * Temp; T0 = 1108.0 + Temp; T5 = Temp * Temp; Eg = 1.16 - 7.02e-4 * T5 / T0; T1 = ((7.02e-4 * T5) - T0 * (14.04e-4 * Temp)) / T0 / T0; /* T1 = dEg / dT */ T2 = 1.9230584e-4; /* T2 = 1 / 300.15^(3/2) */ T5 = sqrt(Temp); T3 = 1.45e10 * Temp * T5 * T2; T4 = exp(21.5565981 - Eg / (2.0 * Vtm)); ni = T3 * T4; dni_dT = 2.175e10 * T2 * T5 * T4 + T3 * T4 * (-Vtm * T1 + Eg * KboQ) / (2.0 * Vtm * Vtm); T0 = log(1.0e20 * pParam->B3SOIFDnpeak / (ni * ni)); vbi = Vtm * T0; dvbi_dT = KboQ * T0 + Vtm * (-2.0 * dni_dT / ni); if (pParam->B3SOIFDnsub > 0) { T0 = log(pParam->B3SOIFDnpeak / pParam->B3SOIFDnsub); vfbb = -model->B3SOIFDtype * Vtm*T0; dvfbb_dT = -model->B3SOIFDtype * KboQ*T0; } else { T0 = log(-pParam->B3SOIFDnpeak*pParam->B3SOIFDnsub/ni/ni); vfbb = -model->B3SOIFDtype * Vtm*T0; dvfbb_dT = -model->B3SOIFDtype * (KboQ * T0 + Vtm * 2.0 * dni_dT / ni); } /* phi = 2.0 * Vtm * log(pParam->B3SOIFDnpeak / ni); */ phi = here->B3SOIFDphi; sqrtPhi = sqrt(phi); Xdep0 = sqrt(2.0 * EPSSI / (Charge_q * pParam->B3SOIFDnpeak * 1.0e6)) * sqrtPhi; /* Save the values below for phi calculation in B3SOIFDaccept() */ here->B3SOIFDvtm = Vtm; here->B3SOIFDni = ni; /* Use dTx_dVe variables to act as dTx_dT variables */ T8 = 1 / model->B3SOIFDtnom; T7 = model->B3SOIFDxbjt / pParam->B3SOIFDndiode; T0 = pow(TempRatio, T7); dT0_dVe = T7 * pow(TempRatio, T7 - 1.0) * T8; T7 = model->B3SOIFDxdif / pParam->B3SOIFDndiode; T1 = pow(TempRatio, T7); dT1_dVe = T7 * pow(TempRatio, T7 - 1.0) * T8; T7 = model->B3SOIFDxrec / pParam->B3SOIFDndiode / 2.0; T2 = pow(TempRatio, T7); dT2_dVe = T7 * pow(TempRatio, T7 - 1.0) * T8; T3 = TempRatio - 1.0; T4 = Eg300 / pParam->B3SOIFDndiode / Vtm * T3; dT4_dVe = Eg300 / pParam->B3SOIFDndiode / Vtm / Vtm * (Vtm * T8 - T3 * KboQ); T5 = exp(T4); dT5_dVe = dT4_dVe * T5; T6 = sqrt(T5); dT6_dVe = 0.5 / T6 * dT5_dVe; jbjt = pParam->B3SOIFDisbjt * T0 * T5; jdif = pParam->B3SOIFDisdif * T1 * T5; jrec = pParam->B3SOIFDisrec * T2 * T6; djbjt_dT = pParam->B3SOIFDisbjt * (T0 * dT5_dVe + T5 * dT0_dVe); djdif_dT = pParam->B3SOIFDisdif * (T1 * dT5_dVe + T5 * dT1_dVe); djrec_dT = pParam->B3SOIFDisrec * (T2 * dT6_dVe + T6 * dT2_dVe); T7 = model->B3SOIFDxtun / pParam->B3SOIFDntun; T0 = pow(TempRatio, T7); jtun = pParam->B3SOIFDistun * T0; djtun_dT = pParam->B3SOIFDistun * T7 * pow(TempRatio, T7 - 1.0) * T8; u0temp = pParam->B3SOIFDu0 * pow(TempRatio, pParam->B3SOIFDute); du0temp_dT = pParam->B3SOIFDu0 * pParam->B3SOIFDute * pow(TempRatio, pParam->B3SOIFDute - 1.0) * T8; vsattemp = pParam->B3SOIFDvsat - pParam->B3SOIFDat * T3; dvsattemp_dT = -pParam->B3SOIFDat * T8; rds0 = (pParam->B3SOIFDrdsw + pParam->B3SOIFDprt * T3) / pParam->B3SOIFDrds0denom; drds0_dT = pParam->B3SOIFDprt / pParam->B3SOIFDrds0denom * T8; ua = pParam->B3SOIFDuatemp + pParam->B3SOIFDua1 * T3; ub = pParam->B3SOIFDubtemp + pParam->B3SOIFDub1 * T3; uc = pParam->B3SOIFDuctemp + pParam->B3SOIFDuc1 * T3; dua_dT = pParam->B3SOIFDua1 * T8; dub_dT = pParam->B3SOIFDub1 * T8; duc_dT = pParam->B3SOIFDuc1 * T8; } else { vbi = pParam->B3SOIFDvbi; vfbb = pParam->B3SOIFDvfbb; phi = pParam->B3SOIFDphi; sqrtPhi = pParam->B3SOIFDsqrtPhi; Xdep0 = pParam->B3SOIFDXdep0; jbjt = pParam->B3SOIFDjbjt; jdif = pParam->B3SOIFDjdif; jrec = pParam->B3SOIFDjrec; jtun = pParam->B3SOIFDjtun; u0temp = pParam->B3SOIFDu0temp; vsattemp = pParam->B3SOIFDvsattemp; rds0 = pParam->B3SOIFDrds0; ua = pParam->B3SOIFDua; ub = pParam->B3SOIFDub; uc = pParam->B3SOIFDuc; dni_dT = dvbi_dT = dvfbb_dT = djbjt_dT = djdif_dT = 0.0; djrec_dT = djtun_dT = du0temp_dT = dvsattemp_dT = 0.0; drds0_dT = dua_dT = dub_dT = duc_dT = 0.0; } /* TempRatio used for Vth and mobility */ if (selfheat) { TempRatio = Temp / model->B3SOIFDtnom - 1.0; } else { TempRatio = ckt->CKTtemp / model->B3SOIFDtnom - 1.0; } /* determine DC current and derivatives */ vbd = vbs - vds; vgd = vgs - vds; vgb = vgs - vbs; ved = ves - vds; veb = ves - vbs; vge = vgs - ves; vpd = vps - vds; if (vds >= 0.0) { /* normal mode */ here->B3SOIFDmode = 1; Vds = vds; Vgs = vgs; Vbs = vbs; Vbd = vbd; Ves = ves; Vps = vps; } else { /* inverse mode */ here->B3SOIFDmode = -1; Vds = -vds; Vgs = vgd; Vbs = vbd; Vbd = vbs; Ves = ved; Vps = vpd; } if (here->B3SOIFDdebugMod > 2) { fprintf(fpdebug, "Vgs=%.4f, Vds=%.4f, Vbs=%.4f, ", Vgs, Vds, Vbs); fprintf(fpdebug, "Ves=%.4f, Vps=%.4f, Temp=%.1f\n", Ves, Vps, Temp); } Vesfb = Ves - vfbb; Cbox = model->B3SOIFDcbox; K1 = pParam->B3SOIFDk1; ChargeComputationNeeded = ((ckt->CKTmode & (MODEAC | MODETRAN | MODEINITSMSIG)) || ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC))) ? 1 : 0; if (here->B3SOIFDdebugMod == -1) ChargeComputationNeeded = 1; /* Poly Gate Si Depletion Effect */ T0 = pParam->B3SOIFDvfb + phi; if ((pParam->B3SOIFDngate > 1.e18) && (pParam->B3SOIFDngate < 1.e25) && (Vgs > T0)) /* added to avoid the problem caused by ngate */ { T1 = 1.0e6 * Charge_q * EPSSI * pParam->B3SOIFDngate / (model->B3SOIFDcox * model->B3SOIFDcox); T4 = sqrt(1.0 + 2.0 * (Vgs - T0) / T1); T2 = T1 * (T4 - 1.0); T3 = 0.5 * T2 * T2 / T1; /* T3 = Vpoly */ T7 = 1.12 - T3 - 0.05; T6 = sqrt(T7 * T7 + 0.224); T5 = 1.12 - 0.5 * (T7 + T6); Vgs_eff = Vgs - T5; dVgs_eff_dVg = 1.0 - (0.5 - 0.5 / T4) * (1.0 + T7 / T6); } else { Vgs_eff = Vgs; dVgs_eff_dVg = 1.0; } Leff = pParam->B3SOIFDleff; if (selfheat) { Vtm = KboQ * Temp; dVtm_dT = KboQ; } else { Vtm = model->B3SOIFDvtm; dVtm_dT = 0.0; } V0 = vbi - phi; /* Prepare Vbs0t */ T0 = -pParam->B3SOIFDdvbd1 * pParam->B3SOIFDleff / pParam->B3SOIFDlitl; T1 = pParam->B3SOIFDdvbd0 * (exp(0.5*T0) + 2*exp(T0)); T2 = T1 * (vbi - phi); T3 = 0.5 * model->B3SOIFDqsi / model->B3SOIFDcsi; Vbs0t = phi - T3 + pParam->B3SOIFDvbsa + T2; if (selfheat) dVbs0t_dT = T1 * dvbi_dT; else dVbs0t_dT = 0.0; /* Prepare Vbs0 */ T0 = 1 + model->B3SOIFDcsieff / Cbox; T1 = pParam->B3SOIFDkb1 / T0; T2 = T1 * (Vbs0t - Vesfb); /* T6 is Vbs0 before limiting */ T6 = Vbs0t - T2; dT6_dVe = T1; if (selfheat) dT6_dT = dVbs0t_dT - T1 * (dVbs0t_dT + dvfbb_dT); else dT6_dT = 0.0; /* limit Vbs0 to below phi */ T1 = phi - pParam->B3SOIFDdelp; T2 = T1 - T6 - DELT_Vbseff; T3 = sqrt(T2 * T2 + 4.0 * DELT_Vbseff); Vbs0 = T1 - 0.5 * (T2 + T3); T4 = 0.5 * (1 + T2/T3); dVbs0_dVe = T4 * dT6_dVe; if (selfheat) dVbs0_dT = T4 * dT6_dT; else dVbs0_dT = 0.0; T1 = Vbs0t - Vbs0 - DELT_Vbsmos; T2 = sqrt(T1 * T1 + DELT_Vbsmos * DELT_Vbsmos); T3 = 0.5 * (T1 + T2); T4 = T3 * model->B3SOIFDcsieff / model->B3SOIFDqsieff; Vbs0mos = Vbs0 - 0.5 * T3 * T4; T5 = 0.5 * T4 * (1 + T1 / T2); dVbs0mos_dVe = dVbs0_dVe * (1 + T5); if (selfheat) dVbs0mos_dT = dVbs0_dT - (dVbs0t_dT - dVbs0_dT) * T5; else dVbs0mos_dT = 0.0; /* Prepare Vthfd - treat Vbs0mos as if it were independent variable Vb */ Phis = phi - Vbs0mos; dPhis_dVb = -1; sqrtPhis = sqrt(Phis); dsqrtPhis_dVb = -0.5 / sqrtPhis; Xdep = Xdep0 * sqrtPhis / sqrtPhi; dXdep_dVb = (Xdep0 / sqrtPhi) * dsqrtPhis_dVb; sqrtXdep = sqrt(Xdep); T0 = pParam->B3SOIFDdvt2 * Vbs0mos; if (T0 >= - 0.5) { T1 = 1.0 + T0; T2 = pParam->B3SOIFDdvt2; } else /* Added to avoid any discontinuity problems caused by dvt2*/ { T4 = 1.0 / (3.0 + 8.0 * T0); T1 = (1.0 + 3.0 * T0) * T4; T2 = pParam->B3SOIFDdvt2 * T4 * T4; } lt1 = model->B3SOIFDfactor1 * sqrtXdep * T1; dlt1_dVb = model->B3SOIFDfactor1 * (0.5 / sqrtXdep * T1 * dXdep_dVb + sqrtXdep * T2); T0 = pParam->B3SOIFDdvt2w * Vbs0mos; if (T0 >= - 0.5) { T1 = 1.0 + T0; T2 = pParam->B3SOIFDdvt2w; } else /* Added to avoid any discontinuity problems caused by dvt2w */ { T4 = 1.0 / (3.0 + 8.0 * T0); T1 = (1.0 + 3.0 * T0) * T4; T2 = pParam->B3SOIFDdvt2w * T4 * T4; } ltw= model->B3SOIFDfactor1 * sqrtXdep * T1; dltw_dVb = model->B3SOIFDfactor1 * (0.5 / sqrtXdep * T1 * dXdep_dVb + sqrtXdep * T2); T0 = -0.5 * pParam->B3SOIFDdvt1 * Leff / lt1; if (T0 > -EXP_THRESHOLD) { T1 = exp(T0); dT1_dVb = -T0 / lt1 * T1 * dlt1_dVb; Theta0 = T1 * (1.0 + 2.0 * T1); dTheta0_dVb = (1.0 + 4.0 * T1) * dT1_dVb; } else { T1 = MIN_EXP; Theta0 = T1 * (1.0 + 2.0 * T1); dTheta0_dVb = 0.0; } here->B3SOIFDthetavth = pParam->B3SOIFDdvt0 * Theta0; Delt_vth = here->B3SOIFDthetavth * V0; dDelt_vth_dVb = pParam->B3SOIFDdvt0 * dTheta0_dVb * V0; if (selfheat) dDelt_vth_dT = here->B3SOIFDthetavth * dvbi_dT; else dDelt_vth_dT = 0.0; T0 = -0.5*pParam->B3SOIFDdvt1w * pParam->B3SOIFDweff*Leff/ltw; if (T0 > -EXP_THRESHOLD) { T1 = exp(T0); T2 = T1 * (1.0 + 2.0 * T1); dT1_dVb = -T0 / ltw * T1 * dltw_dVb; dT2_dVb = (1.0 + 4.0 * T1) * dT1_dVb; } else { T1 = MIN_EXP; T2 = T1 * (1.0 + 2.0 * T1); dT2_dVb = 0.0; } T0 = pParam->B3SOIFDdvt0w * T2; DeltVthw = T0 * V0; dDeltVthw_dVb = pParam->B3SOIFDdvt0w * dT2_dVb * V0; if (selfheat) dDeltVthw_dT = T0 * dvbi_dT; else dDeltVthw_dT = 0.0; T0 = sqrt(1.0 + pParam->B3SOIFDnlx / Leff); T1 = (pParam->B3SOIFDkt1 + pParam->B3SOIFDkt1l / Leff + pParam->B3SOIFDkt2 * Vbs0mos); DeltVthtemp = pParam->B3SOIFDk1 * (T0 - 1.0) * sqrtPhi + T1 * TempRatio; if (selfheat) dDeltVthtemp_dT = T1 / model->B3SOIFDtnom; else dDeltVthtemp_dT = 0.0; tmp2 = model->B3SOIFDtox * phi / (pParam->B3SOIFDweff + pParam->B3SOIFDw0); T3 = pParam->B3SOIFDeta0 + pParam->B3SOIFDetab * Vbs0mos; if (T3 < 1.0e-4) /* avoid discontinuity problems caused by etab */ { T9 = 1.0 / (3.0 - 2.0e4 * T3); T3 = (2.0e-4 - T3) * T9; T4 = T9 * T9 * pParam->B3SOIFDetab; dT3_dVb = T4; } else { dT3_dVb = pParam->B3SOIFDetab; } DIBL_Sft = T3 * pParam->B3SOIFDtheta0vb0 * Vds; dDIBL_Sft_dVd = T3 * pParam->B3SOIFDtheta0vb0; dDIBL_Sft_dVb = pParam->B3SOIFDtheta0vb0 * Vds * dT3_dVb; Vthfd = model->B3SOIFDtype * pParam->B3SOIFDvth0 + pParam->B3SOIFDk1 * (sqrtPhis - sqrtPhi) - pParam->B3SOIFDk2 * Vbs0mos-Delt_vth-DeltVthw +(pParam->B3SOIFDk3 +pParam->B3SOIFDk3b * Vbs0mos) * tmp2 + DeltVthtemp - DIBL_Sft; T6 = pParam->B3SOIFDk3b * tmp2 - pParam->B3SOIFDk2 + pParam->B3SOIFDkt2 * TempRatio; dVthfd_dVd = -dDIBL_Sft_dVd; T7 = pParam->B3SOIFDk1 * dsqrtPhis_dVb - dDelt_vth_dVb - dDeltVthw_dVb + T6 - dDIBL_Sft_dVb; dVthfd_dVe = T7 * dVbs0mos_dVe; if (selfheat) dVthfd_dT = dDeltVthtemp_dT - dDelt_vth_dT - dDeltVthw_dT + T7 * dVbs0mos_dT; else dVthfd_dT = 0.0; /* Effective Vbs0 and Vbs0t for all Vgs */ T1 = Vthfd - Vgs_eff - DELT_Vbs0eff; T2 = sqrt(T1 * T1 + DELT_Vbs0eff * DELT_Vbs0eff ); Vbs0teff = Vbs0t - 0.5 * (T1 + T2); dVbs0teff_dVg = 0.5 * (1 + T1/T2) * dVgs_eff_dVg; dVbs0teff_dVd = - 0.5 * (1 + T1 / T2) * dVthfd_dVd; dVbs0teff_dVe = - 0.5 * (1 + T1 / T2) * dVthfd_dVe; if (selfheat) dVbs0teff_dT = dVbs0t_dT - 0.5 * (1 + T1 / T2) * dVthfd_dT; else dVbs0teff_dT = 0.0; /* Calculate nfb */ T3 = 1 / (K1 * K1); T4 = pParam->B3SOIFDkb3 * Cbox / model->B3SOIFDcox; T8 = sqrt(phi - Vbs0mos); T5 = sqrt(1 + 4 * T3 * (phi + K1 * T8 - Vbs0mos)); T6 = 1 + T4 * T5; Nfb = model->B3SOIFDnfb = 1 / T6; T7 = 2 * T3 * T4 * Nfb * Nfb / T5 * (0.5 * K1 / T8 + 1); Vbs0eff = Vbs0 - Nfb * 0.5 * (T1 + T2); dVbs0eff_dVg = Nfb * 0.5 * (1 + T1/T2) * dVgs_eff_dVg; dVbs0eff_dVd = - Nfb * 0.5 * (1 + T1 / T2) * dVthfd_dVd; dVbs0eff_dVe = dVbs0_dVe - Nfb * 0.5 * (1 + T1 / T2) * dVthfd_dVe - T7 * 0.5 * (T1 + T2) * dVbs0mos_dVe; if (selfheat) dVbs0eff_dT = dVbs0_dT - Nfb * 0.5 * (1 + T1 / T2) * dVthfd_dT - T7 * 0.5 * (T1 + T2) * dVbs0mos_dT; else dVbs0eff_dT = 0.0; /* Simple check of Vbs */ /* Prepare Vbsdio */ Vbs = Vbsdio = Vbs0eff; dVbsdio_dVg = dVbs0eff_dVg; dVbsdio_dVd = dVbs0eff_dVd; dVbsdio_dVe = dVbs0eff_dVe; dVbsdio_dT = dVbs0eff_dT; dVbsdio_dVb = 0.0; /* Prepare Vbseff */ T1 = Vbs0teff - Vbsdio - DELT_Vbsmos; T2 = sqrt(T1 * T1 + DELT_Vbsmos * DELT_Vbsmos); T3 = 0.5 * (T1 + T2); T5 = 0.5 * (1 + T1/T2); dT3_dVg = T5 * (dVbs0teff_dVg - dVbsdio_dVg); dT3_dVd = T5 * (dVbs0teff_dVd - dVbsdio_dVd); dT3_dVb = - T5 * dVbsdio_dVb; dT3_dVe = T5 * (dVbs0teff_dVe - dVbsdio_dVe); if (selfheat) dT3_dT = T5 * (dVbs0teff_dT - dVbsdio_dT); else dT3_dT = 0.0; T4 = T3 * model->B3SOIFDcsieff / model->B3SOIFDqsieff; Vbsmos = Vbsdio - 0.5 * T3 * T4; dVbsmos_dVg = dVbsdio_dVg - T4 * dT3_dVg; dVbsmos_dVd = dVbsdio_dVd - T4 * dT3_dVd; dVbsmos_dVb = dVbsdio_dVb - T4 * dT3_dVb; dVbsmos_dVe = dVbsdio_dVe - T4 * dT3_dVe; if (selfheat) dVbsmos_dT = dVbsdio_dT - T4 * dT3_dT; else dVbsmos_dT = 0.0; /* Prepare Vcs */ Vcs = Vbsdio - Vbs0eff; dVcs_dVb = dVbsdio_dVb; dVcs_dVg = dVbsdio_dVg - dVbs0eff_dVg; dVcs_dVd = dVbsdio_dVd - dVbs0eff_dVd; dVcs_dVe = dVbsdio_dVe - dVbs0eff_dVe; dVcs_dT = dVbsdio_dT - dVbs0eff_dT; /* Check Vps */ /* Note : if Vps is less Vbs0eff => non-physical */ T1 = Vps - Vbs0eff + DELT_Vbs0dio; T2 = sqrt(T1 * T1 + DELT_Vbs0dio * DELT_Vbs0dio); T3 = 0.5 * (1 + T1/T2); Vpsdio = Vbs0eff + 0.5 * (T1 + T2); dVpsdio_dVg = (1 - T3) * dVbs0eff_dVg; dVpsdio_dVd = (1 - T3) * dVbs0eff_dVd; dVpsdio_dVe = (1 - T3) * dVbs0eff_dVe; if (selfheat) dVpsdio_dT = (1 - T3) * dVbs0eff_dT; else dVpsdio_dT = 0.0; dVpsdio_dVp = T3; Vbp = Vbsdio - Vpsdio; dVbp_dVb = dVbsdio_dVb; dVbp_dVg = dVbsdio_dVg - dVpsdio_dVg; dVbp_dVd = dVbsdio_dVd - dVpsdio_dVd; dVbp_dVe = dVbsdio_dVe - dVpsdio_dVe; dVbp_dT = dVbsdio_dT - dVpsdio_dT; dVbp_dVp = - dVpsdio_dVp; here->B3SOIFDvbsdio = Vbsdio; here->B3SOIFDvbs0eff = Vbs0eff; T1 = phi - pParam->B3SOIFDdelp; T2 = T1 - Vbsmos - DELT_Vbseff; T3 = sqrt(T2 * T2 + 4.0 * DELT_Vbseff * T1); Vbseff = T1 - 0.5 * (T2 + T3); T4 = 0.5 * (1 + T2/T3); dVbseff_dVg = T4 * dVbsmos_dVg; dVbseff_dVd = T4 * dVbsmos_dVd; dVbseff_dVb = T4 * dVbsmos_dVb; dVbseff_dVe = T4 * dVbsmos_dVe; if (selfheat) dVbseff_dT = T4 * dVbsmos_dT; else dVbseff_dT = 0.0; here->B3SOIFDvbseff = Vbseff; Phis = phi - Vbseff; dPhis_dVb = -1; sqrtPhis = sqrt(Phis); dsqrtPhis_dVb = -0.5 / sqrtPhis ; Xdep = Xdep0 * sqrtPhis / sqrtPhi; dXdep_dVb = (Xdep0 / sqrtPhi) * dsqrtPhis_dVb; /* Vth Calculation */ T3 = sqrt(Xdep); T0 = pParam->B3SOIFDdvt2 * Vbseff; if (T0 >= - 0.5) { T1 = 1.0 + T0; T2 = pParam->B3SOIFDdvt2 ; } else /* Added to avoid any discontinuity problems caused by dvt2 */ { T4 = 1.0 / (3.0 + 8.0 * T0); T1 = (1.0 + 3.0 * T0) * T4; T2 = pParam->B3SOIFDdvt2 * T4 * T4 ; } lt1 = model->B3SOIFDfactor1 * T3 * T1; dlt1_dVb =model->B3SOIFDfactor1 * (0.5 / T3 * T1 * dXdep_dVb + T3 * T2); T0 = pParam->B3SOIFDdvt2w * Vbseff; if (T0 >= - 0.5) { T1 = 1.0 + T0; T2 = pParam->B3SOIFDdvt2w ; } else /* Added to avoid any discontinuity problems caused by dvt2w */ { T4 = 1.0 / (3.0 + 8.0 * T0); T1 = (1.0 + 3.0 * T0) * T4; T2 = pParam->B3SOIFDdvt2w * T4 * T4 ; } ltw= model->B3SOIFDfactor1 * T3 * T1; dltw_dVb=model->B3SOIFDfactor1*(0.5 / T3 * T1 * dXdep_dVb + T3 * T2); T0 = -0.5 * pParam->B3SOIFDdvt1 * Leff / lt1; if (T0 > -EXP_THRESHOLD) { T1 = exp(T0); Theta0 = T1 * (1.0 + 2.0 * T1); dT1_dVb = -T0 / lt1 * T1 * dlt1_dVb; dTheta0_dVb = (1.0 + 4.0 * T1) * dT1_dVb; } else { T1 = MIN_EXP; Theta0 = T1 * (1.0 + 2.0 * T1); dTheta0_dVb = 0.0; } here->B3SOIFDthetavth = pParam->B3SOIFDdvt0 * Theta0; Delt_vth = here->B3SOIFDthetavth * V0; dDelt_vth_dVb = pParam->B3SOIFDdvt0 * dTheta0_dVb * V0; if (selfheat) dDelt_vth_dT = here->B3SOIFDthetavth * dvbi_dT; else dDelt_vth_dT = 0.0; T0 = -0.5 * pParam->B3SOIFDdvt1w * pParam->B3SOIFDweff * Leff / ltw; if (T0 > -EXP_THRESHOLD) { T1 = exp(T0); T2 = T1 * (1.0 + 2.0 * T1); dT1_dVb = -T0 / ltw * T1 * dltw_dVb; dT2_dVb = (1.0 + 4.0 * T1) * dT1_dVb; } else { T1 = MIN_EXP; T2 = T1 * (1.0 + 2.0 * T1); dT2_dVb = 0.0; } T0 = pParam->B3SOIFDdvt0w * T2; DeltVthw = T0 * V0; dDeltVthw_dVb = pParam->B3SOIFDdvt0w * dT2_dVb * V0; if (selfheat) dDeltVthw_dT = T0 * dvbi_dT; else dDeltVthw_dT = 0.0; T0 = sqrt(1.0 + pParam->B3SOIFDnlx / Leff); T1 = (pParam->B3SOIFDkt1 + pParam->B3SOIFDkt1l / Leff + pParam->B3SOIFDkt2 * Vbseff); DeltVthtemp = pParam->B3SOIFDk1 * (T0 - 1.0) * sqrtPhi + T1 * TempRatio; if (selfheat) dDeltVthtemp_dT = T1 / model->B3SOIFDtnom; else dDeltVthtemp_dT = 0.0; tmp2 = model->B3SOIFDtox * phi / (pParam->B3SOIFDweff + pParam->B3SOIFDw0); T3 = pParam->B3SOIFDeta0 + pParam->B3SOIFDetab * Vbseff; if (T3 < 1.0e-4) /* avoid discontinuity problems caused by etab */ { T9 = 1.0 / (3.0 - 2.0e4 * T3); T3 = (2.0e-4 - T3) * T9; T4 = T9 * T9 * pParam->B3SOIFDetab; dT3_dVb = T4 ; } else { dT3_dVb = pParam->B3SOIFDetab ; } DIBL_Sft = T3 * pParam->B3SOIFDtheta0vb0 * Vds; dDIBL_Sft_dVd = pParam->B3SOIFDtheta0vb0 * T3; dDIBL_Sft_dVb = pParam->B3SOIFDtheta0vb0 * Vds * dT3_dVb; Vth = model->B3SOIFDtype * pParam->B3SOIFDvth0 + pParam->B3SOIFDk1 * (sqrtPhis - sqrtPhi) - pParam->B3SOIFDk2 * Vbseff- Delt_vth - DeltVthw +(pParam->B3SOIFDk3 + pParam->B3SOIFDk3b * Vbseff) * tmp2 + DeltVthtemp - DIBL_Sft; here->B3SOIFDvon = Vth; T6 = pParam->B3SOIFDk3b * tmp2 - pParam->B3SOIFDk2 + pParam->B3SOIFDkt2 * TempRatio; dVth_dVb = pParam->B3SOIFDk1 * dsqrtPhis_dVb - dDelt_vth_dVb - dDeltVthw_dVb + T6 - dDIBL_Sft_dVb; /* this is actually dVth_dVbseff */ dVth_dVd = -dDIBL_Sft_dVd; if (selfheat) dVth_dT = dDeltVthtemp_dT - dDelt_vth_dT - dDeltVthw_dT; else dVth_dT = 0.0; /* Calculate n */ T2 = pParam->B3SOIFDnfactor * EPSSI / Xdep; dT2_dVb = - T2 / Xdep * dXdep_dVb; T3 = pParam->B3SOIFDcdsc + pParam->B3SOIFDcdscb * Vbseff + pParam->B3SOIFDcdscd * Vds; dT3_dVb = pParam->B3SOIFDcdscb; dT3_dVd = pParam->B3SOIFDcdscd; T4 = (T2 + T3 * Theta0 + pParam->B3SOIFDcit) / model->B3SOIFDcox; dT4_dVb = (dT2_dVb + Theta0 * dT3_dVb + dTheta0_dVb * T3) / model->B3SOIFDcox; dT4_dVd = Theta0 * dT3_dVd / model->B3SOIFDcox; if (T4 >= -0.5) { n = 1.0 + T4; dn_dVb = dT4_dVb; dn_dVd = dT4_dVd; } else /* avoid discontinuity problems caused by T4 */ { T0 = 1.0 / (3.0 + 8.0 * T4); n = (1.0 + 3.0 * T4) * T0; T0 *= T0; dn_dVb = T0 * dT4_dVb; dn_dVd = T0 * dT4_dVd; } /* Effective Vgst (Vgsteff) Calculation */ Vgst = Vgs_eff - Vth; T10 = 2.0 * n * Vtm; VgstNVt = Vgst / T10; ExpArg = (2.0 * pParam->B3SOIFDvoff - Vgst) / T10; /* MCJ: Very small Vgst */ if (VgstNVt > EXP_THRESHOLD) { Vgsteff = Vgst; /* T0 is dVgsteff_dVbseff */ T0 = -dVth_dVb; dVgsteff_dVg = dVgs_eff_dVg + T0 * dVbseff_dVg; dVgsteff_dVd = -dVth_dVd + T0 * dVbseff_dVd; dVgsteff_dVb = T0 * dVbseff_dVb; dVgsteff_dVe = T0 * dVbseff_dVe; if (selfheat) dVgsteff_dT = -dVth_dT + T0 * dVbseff_dT; else dVgsteff_dT = 0.0; } else if (ExpArg > EXP_THRESHOLD) { T0 = (Vgst - pParam->B3SOIFDvoff) / (n * Vtm); ExpVgst = exp(T0); Vgsteff = Vtm * pParam->B3SOIFDcdep0 / model->B3SOIFDcox * ExpVgst; T3 = Vgsteff / (n * Vtm) ; /* T1 is dVgsteff_dVbseff */ T1 = -T3 * (dVth_dVb + T0 * Vtm * dn_dVb); dVgsteff_dVg = T3 * dVgs_eff_dVg + T1 * dVbseff_dVg; dVgsteff_dVd = -T3 * (dVth_dVd + T0 * Vtm * dn_dVd) + T1 * dVbseff_dVd; dVgsteff_dVe = T1 * dVbseff_dVe; dVgsteff_dVb = T1 * dVbseff_dVb; if (selfheat) dVgsteff_dT = -T3 * (dVth_dT + T0 * dVtm_dT * n) + Vgsteff / Temp + T1 * dVbseff_dT; else dVgsteff_dT = 0.0; } else { ExpVgst = exp(VgstNVt); T1 = T10 * log(1.0 + ExpVgst); dT1_dVg = ExpVgst / (1.0 + ExpVgst); dT1_dVb = -dT1_dVg * (dVth_dVb + Vgst / n * dn_dVb) + T1 / n * dn_dVb; dT1_dVd = -dT1_dVg * (dVth_dVd + Vgst / n * dn_dVd) + T1 / n * dn_dVd; T3 = (1.0 / Temp); if (selfheat) dT1_dT = -dT1_dVg * (dVth_dT + Vgst * T3) + T1 * T3; else dT1_dT = 0.0; dT2_dVg = -model->B3SOIFDcox / (Vtm * pParam->B3SOIFDcdep0) * exp(ExpArg); T2 = 1.0 - T10 * dT2_dVg; dT2_dVd = -dT2_dVg * (dVth_dVd - 2.0 * Vtm * ExpArg * dn_dVd) + (T2 - 1.0) / n * dn_dVd; dT2_dVb = -dT2_dVg * (dVth_dVb - 2.0 * Vtm * ExpArg * dn_dVb) + (T2 - 1.0) / n * dn_dVb; if (selfheat) dT2_dT = -dT2_dVg * (dVth_dT - ExpArg * T10 * T3); else dT2_dT = 0.0; Vgsteff = T1 / T2; T3 = T2 * T2; /* T4 is dVgsteff_dVbseff */ T4 = (T2 * dT1_dVb - T1 * dT2_dVb) / T3; dVgsteff_dVb = T4 * dVbseff_dVb; dVgsteff_dVe = T4 * dVbseff_dVe; dVgsteff_dVg = (T2 * dT1_dVg - T1 * dT2_dVg) / T3 * dVgs_eff_dVg + T4 * dVbseff_dVg; dVgsteff_dVd = (T2 * dT1_dVd - T1 * dT2_dVd) / T3 + T4 * dVbseff_dVd; if (selfheat) dVgsteff_dT = (T2 * dT1_dT - T1 * dT2_dT) / T3 + T4 * dVbseff_dT; else dVgsteff_dT = 0.0; } Vgst2Vtm = Vgsteff + 2.0 * Vtm; if (selfheat) dVgst2Vtm_dT = 2.0 * dVtm_dT; else dVgst2Vtm_dT = 0.0; /* Calculate Effective Channel Geometry */ T9 = sqrtPhis - sqrtPhi; Weff = pParam->B3SOIFDweff - 2.0 * (pParam->B3SOIFDdwg * Vgsteff + pParam->B3SOIFDdwb * T9); dWeff_dVg = -2.0 * pParam->B3SOIFDdwg; dWeff_dVb = -2.0 * pParam->B3SOIFDdwb * dsqrtPhis_dVb; if (Weff < 2.0e-8) /* to avoid the discontinuity problem due to Weff*/ { T0 = 1.0 / (6.0e-8 - 2.0 * Weff); Weff = 2.0e-8 * (4.0e-8 - Weff) * T0; T0 *= T0 * 4.0e-16; dWeff_dVg *= T0; dWeff_dVb *= T0; } T0 = pParam->B3SOIFDprwg * Vgsteff + pParam->B3SOIFDprwb * T9; if (T0 >= -0.9) { Rds = rds0 * (1.0 + T0); dRds_dVg = rds0 * pParam->B3SOIFDprwg; dRds_dVb = rds0 * pParam->B3SOIFDprwb * dsqrtPhis_dVb; if (selfheat) dRds_dT = (1.0 + T0) * drds0_dT; else dRds_dT = 0.0; } else /* to avoid the discontinuity problem due to prwg and prwb*/ { T1 = 1.0 / (17.0 + 20.0 * T0); Rds = rds0 * (0.8 + T0) * T1; T1 *= T1; dRds_dVg = rds0 * pParam->B3SOIFDprwg * T1; dRds_dVb = rds0 * pParam->B3SOIFDprwb * dsqrtPhis_dVb * T1; if (selfheat) dRds_dT = (0.8 + T0) * T1 * drds0_dT; else dRds_dT = 0.0; } /* Calculate Abulk */ if (pParam->B3SOIFDa0 == 0.0) { Abulk0 = Abulk = dAbulk0_dVb = dAbulk_dVg = dAbulk_dVb = 0.0; } else { T1 = 0.5 * pParam->B3SOIFDk1 / sqrtPhi; T9 = sqrt(model->B3SOIFDxj * Xdep); tmp1 = Leff + 2.0 * T9; T5 = Leff / tmp1; tmp2 = pParam->B3SOIFDa0 * T5; tmp3 = pParam->B3SOIFDweff + pParam->B3SOIFDb1; tmp4 = pParam->B3SOIFDb0 / tmp3; T2 = tmp2 + tmp4; dT2_dVb = -T9 * tmp2 / tmp1 / Xdep * dXdep_dVb; T6 = T5 * T5; T7 = T5 * T6; Abulk0 = T1 * T2; dAbulk0_dVb = T1 * dT2_dVb; T8 = pParam->B3SOIFDags * pParam->B3SOIFDa0 * T7; dAbulk_dVg = -T1 * T8; Abulk = Abulk0 + dAbulk_dVg * Vgsteff; dAbulk_dVb = dAbulk0_dVb - T8 * Vgsteff * 3.0 * T1 * dT2_dVb / tmp2; } if (Abulk0 < 0.01) { T9 = 1.0 / (3.0 - 200.0 * Abulk0); Abulk0 = (0.02 - Abulk0) * T9; dAbulk0_dVb *= T9 * T9; } if (Abulk < 0.01) { T9 = 1.0 / (3.0 - 200.0 * Abulk); Abulk = (0.02 - Abulk) * T9; dAbulk_dVb *= T9 * T9; } T2 = pParam->B3SOIFDketa * Vbseff; if (T2 >= -0.9) { T0 = 1.0 / (1.0 + T2); dT0_dVb = -pParam->B3SOIFDketa * T0 * T0 ; } else /* added to avoid the problems caused by Keta */ { T1 = 1.0 / (0.8 + T2); T0 = (17.0 + 20.0 * T2) * T1; dT0_dVb = -pParam->B3SOIFDketa * T1 * T1 ; } dAbulk_dVg *= T0; dAbulk_dVb = dAbulk_dVb * T0 + Abulk * dT0_dVb; dAbulk0_dVb = dAbulk0_dVb * T0 + Abulk0 * dT0_dVb; Abulk *= T0; Abulk0 *= T0; Abulk += 1; Abulk0 += 1; /* Prepare Abeff */ T0 = pParam->B3SOIFDabp * Vgst2Vtm; T1 = 1 - Vcs / T0 - DELT_Xcsat; T2 = sqrt(T1 * T1 + DELT_Xcsat * DELT_Xcsat); T3 = 1 - 0.5 * (T1 + T2); T5 = -0.5 * (1 + T1 / T2); dT1_dVg = Vcs / Vgst2Vtm / T0; dT3_dVg = T5 * dT1_dVg; dT1_dVc = - 1 / T0; dT3_dVc = T5 * dT1_dVc; Xcsat = pParam->B3SOIFDmxc * T3 * T3 + (1 - pParam->B3SOIFDmxc)*T3; T4 = 2 * pParam->B3SOIFDmxc * T3 + (1 - pParam->B3SOIFDmxc); dXcsat_dVg = T4 * dT3_dVg; dXcsat_dVc = T4 * dT3_dVc; Abeff = Xcsat * Abulk + (1 - Xcsat) * model->B3SOIFDadice; T0 = Xcsat * dAbulk_dVg + Abulk * dXcsat_dVg; dAbeff_dVg = T0 - model->B3SOIFDadice * dXcsat_dVg; dAbeff_dVb = Xcsat * dAbulk_dVb; dAbeff_dVc = (Abulk - model->B3SOIFDadice) * dXcsat_dVc; here->B3SOIFDabeff = Abeff; /* Mobility calculation */ if (model->B3SOIFDmobMod == 1) { T0 = Vgsteff + Vth + Vth; T2 = ua + uc * Vbseff; T3 = T0 / model->B3SOIFDtox; T5 = T3 * (T2 + ub * T3); dDenomi_dVg = (T2 + 2.0 * ub * T3) / model->B3SOIFDtox; dDenomi_dVd = dDenomi_dVg * 2 * dVth_dVd; dDenomi_dVb = dDenomi_dVg * 2 * dVth_dVb + uc * T3 ; if (selfheat) dDenomi_dT = dDenomi_dVg * 2 * dVth_dT + (dua_dT + Vbseff * duc_dT + dub_dT * T3 ) * T3; else dDenomi_dT = 0.0; } else if (model->B3SOIFDmobMod == 2) { T5 = Vgsteff / model->B3SOIFDtox * (ua + uc * Vbseff + ub * Vgsteff / model->B3SOIFDtox); dDenomi_dVg = (ua + uc * Vbseff + 2.0 * ub * Vgsteff / model->B3SOIFDtox) / model->B3SOIFDtox; dDenomi_dVd = 0.0; dDenomi_dVb = Vgsteff * uc / model->B3SOIFDtox ; if (selfheat) dDenomi_dT = Vgsteff / model->B3SOIFDtox * (dua_dT + Vbseff * duc_dT + dub_dT * Vgsteff / model->B3SOIFDtox); else dDenomi_dT = 0.0; } else /* mobMod == 3 */ { T0 = Vgsteff + Vth + Vth; T2 = 1.0 + uc * Vbseff; T3 = T0 / model->B3SOIFDtox; T4 = T3 * (ua + ub * T3); T5 = T4 * T2; dDenomi_dVg = (ua + 2.0 * ub * T3) * T2 / model->B3SOIFDtox; dDenomi_dVd = dDenomi_dVg * 2.0 * dVth_dVd; dDenomi_dVb = dDenomi_dVg * 2.0 * dVth_dVb + uc * T4 ; if (selfheat) dDenomi_dT = dDenomi_dVg * 2.0 * dVth_dT + (dua_dT + dub_dT * T3) * T3 * T2 + T4 * Vbseff * duc_dT; else dDenomi_dT = 0.0; } if (T5 >= -0.8) { Denomi = 1.0 + T5; } else /* Added to avoid the discontinuity problem caused by ua and ub*/ { T9 = 1.0 / (7.0 + 10.0 * T5); Denomi = (0.6 + T5) * T9; T9 *= T9; dDenomi_dVg *= T9; dDenomi_dVd *= T9; dDenomi_dVb *= T9; if (selfheat) dDenomi_dT *= T9; else dDenomi_dT = 0.0; } here->B3SOIFDueff = ueff = u0temp / Denomi; T9 = -ueff / Denomi; dueff_dVg = T9 * dDenomi_dVg; dueff_dVd = T9 * dDenomi_dVd; dueff_dVb = T9 * dDenomi_dVb; if (selfheat) dueff_dT = T9 * dDenomi_dT + du0temp_dT / Denomi; else dueff_dT = 0.0; /* Saturation Drain Voltage Vdsat */ WVCox = Weff * vsattemp * model->B3SOIFDcox; WVCoxRds = WVCox * Rds; /* dWVCoxRds_dT = WVCox * dRds_dT + Weff * model->B3SOIFDcox * Rds * dvsattemp_dT; */ Esat = 2.0 * vsattemp / ueff; EsatL = Esat * Leff; T0 = -EsatL /ueff; dEsatL_dVg = T0 * dueff_dVg; dEsatL_dVd = T0 * dueff_dVd; dEsatL_dVb = T0 * dueff_dVb; if (selfheat) dEsatL_dT = T0 * dueff_dT + EsatL / vsattemp * dvsattemp_dT; else dEsatL_dT = 0.0; /* Sqrt() */ a1 = pParam->B3SOIFDa1; if (a1 == 0.0) { Lambda = pParam->B3SOIFDa2; dLambda_dVg = 0.0; } else if (a1 > 0.0) /* Added to avoid the discontinuity problem caused by a1 and a2 (Lambda) */ { T0 = 1.0 - pParam->B3SOIFDa2; T1 = T0 - pParam->B3SOIFDa1 * Vgsteff - 0.0001; T2 = sqrt(T1 * T1 + 0.0004 * T0); Lambda = pParam->B3SOIFDa2 + T0 - 0.5 * (T1 + T2); dLambda_dVg = 0.5 * pParam->B3SOIFDa1 * (1.0 + T1 / T2); } else { T1 = pParam->B3SOIFDa2 + pParam->B3SOIFDa1 * Vgsteff - 0.0001; T2 = sqrt(T1 * T1 + 0.0004 * pParam->B3SOIFDa2); Lambda = 0.5 * (T1 + T2); dLambda_dVg = 0.5 * pParam->B3SOIFDa1 * (1.0 + T1 / T2); } if (Rds > 0) { tmp2 = dRds_dVg / Rds + dWeff_dVg / Weff; tmp3 = dRds_dVb / Rds + dWeff_dVb / Weff; } else { tmp2 = dWeff_dVg / Weff; tmp3 = dWeff_dVb / Weff; } if ((Rds == 0.0) && (Lambda == 1.0)) { T0 = 1.0 / (Abeff * EsatL + Vgst2Vtm); tmp1 = 0.0; T1 = T0 * T0; T2 = Vgst2Vtm * T0; T3 = EsatL * Vgst2Vtm; Vdsat = T3 * T0; dT0_dVg = -(Abeff * dEsatL_dVg + EsatL * dAbeff_dVg + 1.0) * T1; dT0_dVd = -(Abeff * dEsatL_dVd) * T1; dT0_dVb = -(Abeff * dEsatL_dVb + EsatL * dAbeff_dVb) * T1; dT0_dVc = 0.0; if (selfheat) dT0_dT = -(Abeff * dEsatL_dT + dVgst2Vtm_dT) * T1; else dT0_dT = 0.0; dVdsat_dVg = T3 * dT0_dVg + T2 * dEsatL_dVg + EsatL * T0; dVdsat_dVd = T3 * dT0_dVd + T2 * dEsatL_dVd; dVdsat_dVb = T3 * dT0_dVb + T2 * dEsatL_dVb; dVdsat_dVc = 0.0; if (selfheat) dVdsat_dT = T3 * dT0_dT + T2 * dEsatL_dT + EsatL * T0 * dVgst2Vtm_dT; else dVdsat_dT = 0.0; } else { tmp1 = dLambda_dVg / (Lambda * Lambda); T9 = Abeff * WVCoxRds; T8 = Abeff * T9; T7 = Vgst2Vtm * T9; T6 = Vgst2Vtm * WVCoxRds; T0 = 2.0 * Abeff * (T9 - 1.0 + 1.0 / Lambda); dT0_dVg = 2.0 * (T8 * tmp2 - Abeff * tmp1 + (2.0 * T9 + 1.0 / Lambda - 1.0) * dAbeff_dVg); /* dT0_dVb = 2.0 * (T8 * tmp3 this is equivalent to one below, but simpler + (2.0 * T9 + 1.0 / Lambda - 1.0) * dAbeff_dVg); */ dT0_dVb = 2.0 * (T8 * (2.0 / Abeff * dAbeff_dVb + tmp3) + (1.0 / Lambda - 1.0) * dAbeff_dVb); dT0_dVd = 0.0; dT0_dVc = 0.0; if (selfheat) { tmp4 = dRds_dT / Rds + dvsattemp_dT / vsattemp; dT0_dT = 2.0 * T8 * tmp4; } else tmp4 = dT0_dT = 0.0; T1 = Vgst2Vtm * (2.0 / Lambda - 1.0) + Abeff * EsatL + 3.0 * T7; dT1_dVg = (2.0 / Lambda - 1.0) - 2.0 * Vgst2Vtm * tmp1 + Abeff * dEsatL_dVg + EsatL * dAbeff_dVg + 3.0 * (T9 + T7 * tmp2 + T6 * dAbeff_dVg); dT1_dVb = Abeff * dEsatL_dVb + EsatL * dAbeff_dVb + 3.0 * (T6 * dAbeff_dVb + T7 * tmp3); dT1_dVd = Abeff * dEsatL_dVd; dT1_dVc = 0.0; if (selfheat) { tmp4 += dVgst2Vtm_dT / Vgst2Vtm; dT1_dT = (2.0 / Lambda - 1.0) * dVgst2Vtm_dT + Abeff * dEsatL_dT + 3.0 * T7 * tmp4; } else dT1_dT = 0.0; T2 = Vgst2Vtm * (EsatL + 2.0 * T6); dT2_dVg = EsatL + Vgst2Vtm * dEsatL_dVg + T6 * (4.0 + 2.0 * Vgst2Vtm * tmp2); dT2_dVb = Vgst2Vtm * (dEsatL_dVb + 2.0 * T6 * tmp3); dT2_dVd = Vgst2Vtm * dEsatL_dVd; if (selfheat) dT2_dT = Vgst2Vtm * dEsatL_dT + EsatL * dVgst2Vtm_dT + 2.0 * T6 * (dVgst2Vtm_dT + Vgst2Vtm * tmp4); else dT2_dT = 0.0; T3 = sqrt(T1 * T1 - 2.0 * T0 * T2); Vdsat = (T1 - T3) / T0; dVdsat_dVg = (dT1_dVg - (T1 * dT1_dVg - dT0_dVg * T2 - T0 * dT2_dVg) / T3 - Vdsat * dT0_dVg) / T0; dVdsat_dVb = (dT1_dVb - (T1 * dT1_dVb - dT0_dVb * T2 - T0 * dT2_dVb) / T3 - Vdsat * dT0_dVb) / T0; dVdsat_dVd = (dT1_dVd - (T1 * dT1_dVd - T0 * dT2_dVd) / T3) / T0; dVdsat_dVc = 0.0; if (selfheat) dVdsat_dT = (dT1_dT - (T1 * dT1_dT - dT0_dT * T2 - T0 * dT2_dT) / T3 - Vdsat * dT0_dT) / T0; else dVdsat_dT = 0.0; } here->B3SOIFDvdsat = Vdsat; /* Vdsatii for impact ionization */ if (pParam->B3SOIFDaii > 0.0) { if (pParam->B3SOIFDcii != 0.0) { T0 = pParam->B3SOIFDcii / sqrt(3.0) + pParam->B3SOIFDdii; /* Hard limit Vds to T0 => T4 i.e. limit T0 to 3.0 */ T1 = Vds - T0 - 0.1; T2 = sqrt(T1 * T1 + 0.4); T3 = T0 + 0.5 * (T1 + T2); dT3_dVd = 0.5 * (1.0 + T1/T2); T4 = T3 - pParam->B3SOIFDdii; T5 = pParam->B3SOIFDcii / T4; T0 = T5 * T5; dT0_dVd = - 2 * T0 / T4 * dT3_dVd; } else { T0 = dT0_dVd = 0.0; } T0 += 1.0; T3 = pParam->B3SOIFDaii + pParam->B3SOIFDbii / Leff; T4 = 1.0 / (T0 * Vgsteff + T3 * EsatL); T5 = -T4 * T4; T6 = Vgsteff * T4; T7 = EsatL * Vgsteff; Vdsatii = T7 * T4; dT4_dVg = T5 * (T0 + T3 * dEsatL_dVg); dT4_dVb = T5 * T3 * dEsatL_dVb; dT4_dVd = T5 * (Vgsteff * dT0_dVd + T3 * dEsatL_dVd); if (selfheat) dT4_dT = T5 * (T3 * dEsatL_dT); else dT4_dT = 0.0; T8 = T4 * Vgsteff; dVdsatii_dVg = T7 * dT4_dVg + T4 * (EsatL + Vgsteff * dEsatL_dVg); dVdsatii_dVb = T7 * dT4_dVb + T8 * dEsatL_dVb; dVdsatii_dVd = T7 * dT4_dVd + T8 * dEsatL_dVd; if (selfheat) dVdsatii_dT = T7 * dT4_dT + T8 * dEsatL_dT; else dVdsatii_dT = 0.0; } else { Vdsatii = Vdsat; dVdsatii_dVg = dVdsat_dVg; dVdsatii_dVb = dVdsat_dVb; dVdsatii_dVd = dVdsat_dVd; dVdsatii_dT = dVdsat_dT; } /* Effective Vds (Vdseff) Calculation */ T1 = Vdsat - Vds - pParam->B3SOIFDdelta; dT1_dVg = dVdsat_dVg; dT1_dVd = dVdsat_dVd - 1.0; dT1_dVb = dVdsat_dVb; dT1_dVc = dVdsat_dVc; dT1_dT = dVdsat_dT; T2 = sqrt(T1 * T1 + 4.0 * pParam->B3SOIFDdelta * Vdsat); T0 = T1 / T2; T3 = 2.0 * pParam->B3SOIFDdelta / T2; dT2_dVg = T0 * dT1_dVg + T3 * dVdsat_dVg; dT2_dVd = T0 * dT1_dVd + T3 * dVdsat_dVd; dT2_dVb = T0 * dT1_dVb + T3 * dVdsat_dVb; dT2_dVc = 0.0; if (selfheat) dT2_dT = T0 * dT1_dT + T3 * dVdsat_dT; else dT2_dT = 0.0; Vdseff = Vdsat - 0.5 * (T1 + T2); dVdseff_dVg = dVdsat_dVg - 0.5 * (dT1_dVg + dT2_dVg); dVdseff_dVd = dVdsat_dVd - 0.5 * (dT1_dVd + dT2_dVd); dVdseff_dVb = dVdsat_dVb - 0.5 * (dT1_dVb + dT2_dVb); dVdseff_dVc = 0.0; if (selfheat) dVdseff_dT = dVdsat_dT - 0.5 * (dT1_dT + dT2_dT); else dVdseff_dT = 0.0; if (Vdseff > Vds) Vdseff = Vds; /* This code is added to fixed the problem caused by computer precision when Vds is very close to Vdseff. */ diffVds = Vds - Vdseff; /* Effective Vdsii for Iii calculation */ T1 = Vdsatii - Vds - pParam->B3SOIFDdelta; T2 = sqrt(T1 * T1 + 4.0 * pParam->B3SOIFDdelta * Vdsatii); T0 = T1 / T2; T3 = 2.0 * pParam->B3SOIFDdelta / T2; T4 = T0 + T3; dT2_dVg = T4 * dVdsatii_dVg; dT2_dVd = T4 * dVdsatii_dVd - T0; dT2_dVb = T4 * dVdsatii_dVb; if (selfheat) dT2_dT = T4*dVdsatii_dT; else dT2_dT = 0.0; Vdseffii = Vdsatii - 0.5 * (T1 + T2); dVdseffii_dVg = 0.5 * (dVdsatii_dVg - dT2_dVg); dVdseffii_dVd = 0.5 * (dVdsatii_dVd - dT2_dVd + 1.0); dVdseffii_dVb = 0.5 * (dVdsatii_dVb - dT2_dVb); if (selfheat) dVdseffii_dT = 0.5 * (dVdsatii_dT - dT2_dT); else dVdseffii_dT = 0.0; diffVdsii = Vds - Vdseffii; /* Calculate VAsat */ tmp4 = 1.0 - 0.5 * Abeff * Vdsat / Vgst2Vtm; T9 = WVCoxRds * Vgsteff; T8 = T9 / Vgst2Vtm; T0 = EsatL + Vdsat + 2.0 * T9 * tmp4; T7 = 2.0 * WVCoxRds * tmp4; dT0_dVg = dEsatL_dVg + dVdsat_dVg + T7 * (1.0 + tmp2 * Vgsteff) - T8 * (Abeff * dVdsat_dVg - Abeff * Vdsat / Vgst2Vtm + Vdsat * dAbeff_dVg); dT0_dVb = dEsatL_dVb + dVdsat_dVb + T7 * tmp3 * Vgsteff - T8 * (dAbeff_dVb * Vdsat + Abeff * dVdsat_dVb); dT0_dVd = dEsatL_dVd + dVdsat_dVd - T8 * Abeff * dVdsat_dVd; dT0_dVc = 0.0; if (selfheat) { tmp4 = dRds_dT / Rds + dvsattemp_dT / vsattemp; dT0_dT = dEsatL_dT + dVdsat_dT + T7 * tmp4 * Vgsteff - T8 * (Abeff * dVdsat_dT - Abeff * Vdsat * dVgst2Vtm_dT / Vgst2Vtm); } else dT0_dT = 0.0; T9 = WVCoxRds * Abeff; T1 = 2.0 / Lambda - 1.0 + T9; dT1_dVg = -2.0 * tmp1 + WVCoxRds * (Abeff * tmp2 + dAbeff_dVg); dT1_dVb = dAbeff_dVb * WVCoxRds + T9 * tmp3; dT1_dVc = 0.0; if (selfheat) dT1_dT = T9 * tmp4; else dT1_dT = 0.0; Vasat = T0 / T1; dVasat_dVg = (dT0_dVg - Vasat * dT1_dVg) / T1; dVasat_dVb = (dT0_dVb - Vasat * dT1_dVb) / T1; dVasat_dVd = dT0_dVd / T1; dVasat_dVc = 0.0; if (selfheat) dVasat_dT = (dT0_dT - Vasat * dT1_dT) / T1; else dVasat_dT = 0.0; /* Calculate VACLM */ if ((pParam->B3SOIFDpclm > 0.0) && (diffVds > 1.0e-10)) { T0 = 1.0 / (pParam->B3SOIFDpclm * Abeff * pParam->B3SOIFDlitl); dT0_dVb = -T0 / Abeff * dAbeff_dVb; dT0_dVg = -T0 / Abeff * dAbeff_dVg; dT0_dVc = 0.0; T2 = Vgsteff / EsatL; T1 = Leff * (Abeff + T2); dT1_dVg = Leff * ((1.0 - T2 * dEsatL_dVg) / EsatL + dAbeff_dVg); dT1_dVb = Leff * (dAbeff_dVb - T2 * dEsatL_dVb / EsatL); dT1_dVd = -T2 * dEsatL_dVd / Esat; dT1_dVc = 0.0; if (selfheat) dT1_dT = -T2 * dEsatL_dT / Esat; else dT1_dT = 0.0; T9 = T0 * T1; VACLM = T9 * diffVds; dVACLM_dVg = T0 * dT1_dVg * diffVds - T9 * dVdseff_dVg + T1 * diffVds * dT0_dVg; dVACLM_dVb = (dT0_dVb * T1 + T0 * dT1_dVb) * diffVds - T9 * dVdseff_dVb; dVACLM_dVd = T0 * dT1_dVd * diffVds + T9 * (1.0 - dVdseff_dVd); dVACLM_dVc = 0.0; if (selfheat) dVACLM_dT = T0 * dT1_dT * diffVds - T9 * dVdseff_dT; else dVACLM_dT = 0.0; } else { VACLM = MAX_EXP; dVACLM_dVd = dVACLM_dVg = dVACLM_dVb = dVACLM_dVc = dVACLM_dT = 0.0; } /* Calculate VADIBL */ if (pParam->B3SOIFDthetaRout > 0.0) { T8 = Abeff * Vdsat; T0 = Vgst2Vtm * T8; T1 = Vgst2Vtm + T8; dT0_dVg = Vgst2Vtm * Abeff * dVdsat_dVg + T8 + Vgst2Vtm * Vdsat * dAbeff_dVg; dT1_dVg = 1.0 + Abeff * dVdsat_dVg + Vdsat * dAbeff_dVg; dT1_dVb = dAbeff_dVb * Vdsat + Abeff * dVdsat_dVb; dT0_dVb = Vgst2Vtm * dT1_dVb; dT1_dVd = Abeff * dVdsat_dVd; dT0_dVd = Vgst2Vtm * dT1_dVd; dT0_dVc = dT1_dVc = 0.0; if (selfheat) { dT0_dT = dVgst2Vtm_dT * T8 + Abeff * Vgst2Vtm * dVdsat_dT; dT1_dT = dVgst2Vtm_dT + Abeff * dVdsat_dT; } else dT0_dT = dT1_dT = 0.0; T9 = T1 * T1; T2 = pParam->B3SOIFDthetaRout; VADIBL = (Vgst2Vtm - T0 / T1) / T2; dVADIBL_dVg = (1.0 - dT0_dVg / T1 + T0 * dT1_dVg / T9) / T2; dVADIBL_dVb = (-dT0_dVb / T1 + T0 * dT1_dVb / T9) / T2; dVADIBL_dVd = (-dT0_dVd / T1 + T0 * dT1_dVd / T9) / T2; dVADIBL_dVc = 0.0; if (selfheat) dVADIBL_dT = (dVgst2Vtm_dT - dT0_dT/T1 + T0*dT1_dT/T9) / T2; else dVADIBL_dT = 0.0; T7 = pParam->B3SOIFDpdiblb * Vbseff; if (T7 >= -0.9) { T3 = 1.0 / (1.0 + T7); VADIBL *= T3; dVADIBL_dVg *= T3; dVADIBL_dVb = (dVADIBL_dVb - VADIBL * pParam->B3SOIFDpdiblb) * T3; dVADIBL_dVd *= T3; dVADIBL_dVc *= T3; if (selfheat) dVADIBL_dT *= T3; else dVADIBL_dT = 0.0; } else /* Added to avoid the discontinuity problem caused by pdiblcb */ { T4 = 1.0 / (0.8 + T7); T3 = (17.0 + 20.0 * T7) * T4; dVADIBL_dVg *= T3; dVADIBL_dVb = dVADIBL_dVb * T3 - VADIBL * pParam->B3SOIFDpdiblb * T4 * T4; dVADIBL_dVd *= T3; dVADIBL_dVc *= T3; if (selfheat) dVADIBL_dT *= T3; else dVADIBL_dT = 0.0; VADIBL *= T3; } } else { VADIBL = MAX_EXP; dVADIBL_dVd = dVADIBL_dVg = dVADIBL_dVb = dVADIBL_dVc = dVADIBL_dT = 0.0; } /* Calculate VA */ T8 = pParam->B3SOIFDpvag / EsatL; T9 = T8 * Vgsteff; if (T9 > -0.9) { T0 = 1.0 + T9; dT0_dVg = T8 * (1.0 - Vgsteff * dEsatL_dVg / EsatL); dT0_dVb = -T9 * dEsatL_dVb / EsatL; dT0_dVd = -T9 * dEsatL_dVd / EsatL; if (selfheat) dT0_dT = -T9 * dEsatL_dT / EsatL; else dT0_dT = 0.0; } else /* Added to avoid the discontinuity problems caused by pvag */ { T1 = 1.0 / (17.0 + 20.0 * T9); T0 = (0.8 + T9) * T1; T1 *= T1; dT0_dVg = T8 * (1.0 - Vgsteff * dEsatL_dVg / EsatL) * T1; T9 *= T1 / EsatL; dT0_dVb = -T9 * dEsatL_dVb; dT0_dVd = -T9 * dEsatL_dVd; if (selfheat) dT0_dT = -T9 * dEsatL_dT; else dT0_dT = 0.0; } tmp1 = VACLM * VACLM; tmp2 = VADIBL * VADIBL; tmp3 = VACLM + VADIBL; T1 = VACLM * VADIBL / tmp3; tmp3 *= tmp3; dT1_dVg = (tmp1 * dVADIBL_dVg + tmp2 * dVACLM_dVg) / tmp3; dT1_dVd = (tmp1 * dVADIBL_dVd + tmp2 * dVACLM_dVd) / tmp3; dT1_dVb = (tmp1 * dVADIBL_dVb + tmp2 * dVACLM_dVb) / tmp3; dT1_dVc = 0.0; if (selfheat) dT1_dT = (tmp1 * dVADIBL_dT + tmp2 * dVACLM_dT ) / tmp3; else dT1_dT = 0.0; Va = Vasat + T0 * T1; dVa_dVg = dVasat_dVg + T1 * dT0_dVg + T0 * dT1_dVg; dVa_dVd = dVasat_dVd + T1 * dT0_dVd + T0 * dT1_dVd; dVa_dVb = dVasat_dVb + T1 * dT0_dVb + T0 * dT1_dVb; dVa_dVc = 0.0; if (selfheat) dVa_dT = dVasat_dT + T1 * dT0_dT + T0 * dT1_dT; else dVa_dT = 0.0; /* Calculate Ids */ CoxWovL = model->B3SOIFDcox * Weff / Leff; beta = ueff * CoxWovL; dbeta_dVg = CoxWovL * dueff_dVg + beta * dWeff_dVg / Weff; dbeta_dVd = CoxWovL * dueff_dVd; dbeta_dVb = CoxWovL * dueff_dVb + beta * dWeff_dVb / Weff; if (selfheat) dbeta_dT = CoxWovL * dueff_dT; else dbeta_dT = 0.0; T0 = 1.0 - 0.5 * Abeff * Vdseff / Vgst2Vtm; dT0_dVg = -0.5 * (Abeff * dVdseff_dVg - Abeff * Vdseff / Vgst2Vtm + Vdseff * dAbeff_dVg) / Vgst2Vtm; dT0_dVd = -0.5 * Abeff * dVdseff_dVd / Vgst2Vtm; dT0_dVb = -0.5 * (Abeff * dVdseff_dVb + dAbeff_dVb * Vdseff) / Vgst2Vtm; dT0_dVc = 0.0; if (selfheat) dT0_dT = -0.5 * (Abeff * dVdseff_dT - Abeff * Vdseff / Vgst2Vtm * dVgst2Vtm_dT) / Vgst2Vtm; else dT0_dT = 0.0; fgche1 = Vgsteff * T0; dfgche1_dVg = Vgsteff * dT0_dVg + T0; dfgche1_dVd = Vgsteff * dT0_dVd; dfgche1_dVb = Vgsteff * dT0_dVb; dfgche1_dVc = 0.0; if (selfheat) dfgche1_dT = Vgsteff * dT0_dT; else dfgche1_dT = 0.0; T9 = Vdseff / EsatL; fgche2 = 1.0 + T9; dfgche2_dVg = (dVdseff_dVg - T9 * dEsatL_dVg) / EsatL; dfgche2_dVd = (dVdseff_dVd - T9 * dEsatL_dVd) / EsatL; dfgche2_dVb = (dVdseff_dVb - T9 * dEsatL_dVb) / EsatL; dfgche2_dVc = 0.0; if (selfheat) dfgche2_dT = (dVdseff_dT - T9 * dEsatL_dT) / EsatL; else dfgche2_dT = 0.0; gche = beta * fgche1 / fgche2; dgche_dVg = (beta * dfgche1_dVg + fgche1 * dbeta_dVg - gche * dfgche2_dVg) / fgche2; dgche_dVd = (beta * dfgche1_dVd + fgche1 * dbeta_dVd - gche * dfgche2_dVd) / fgche2; dgche_dVb = (beta * dfgche1_dVb + fgche1 * dbeta_dVb - gche * dfgche2_dVb) / fgche2; dgche_dVc = 0.0; if (selfheat) dgche_dT = (beta * dfgche1_dT + fgche1 * dbeta_dT - gche * dfgche2_dT) / fgche2; else dgche_dT = 0.0; T0 = 1.0 + gche * Rds; T9 = Vdseff / T0; Idl = gche * T9; /* Whoa, these formulas for the derivatives of Idl are convoluted, but I verified them to be correct */ dIdl_dVg = (gche * dVdseff_dVg + T9 * dgche_dVg) / T0 - Idl * gche / T0 * dRds_dVg ; dIdl_dVd = (gche * dVdseff_dVd + T9 * dgche_dVd) / T0; dIdl_dVb = (gche * dVdseff_dVb + T9 * dgche_dVb - Idl * dRds_dVb * gche) / T0; dIdl_dVc = 0.0; if (selfheat) dIdl_dT = (gche * dVdseff_dT + T9 * dgche_dT - Idl * dRds_dT * gche) / T0; else dIdl_dT = 0.0; T9 = diffVds / Va; T0 = 1.0 + T9; here->B3SOIFDids = Ids = Idl * T0; Gm0 = T0 * dIdl_dVg - Idl * (dVdseff_dVg + T9 * dVa_dVg) / Va; Gds0 = T0 * dIdl_dVd + Idl * (1.0 - dVdseff_dVd - T9 * dVa_dVd) / Va; Gmb0 = T0 * dIdl_dVb - Idl * (dVdseff_dVb + T9 * dVa_dVb) / Va; Gmc = 0.0; if (selfheat) GmT0 = T0 * dIdl_dT - Idl * (dVdseff_dT + T9 * dVa_dT) / Va; else GmT0 = 0.0; /* This includes all dependencies from Vgsteff, Vbseff, Vcs */ Gm = Gm0 * dVgsteff_dVg + Gmb0 * dVbseff_dVg + Gmc * dVcs_dVg; Gmb = Gm0 * dVgsteff_dVb + Gmb0 * dVbseff_dVb + Gmc * dVcs_dVb; Gds = Gm0 * dVgsteff_dVd + Gmb0 * dVbseff_dVd + Gmc * dVcs_dVd + Gds0; Gme = Gm0 * dVgsteff_dVe + Gmb0 * dVbseff_dVe + Gmc * dVcs_dVe; if (selfheat) GmT = Gm0 * dVgsteff_dT + Gmb0 * dVbseff_dT + Gmc * dVcs_dT + GmT0; else GmT = 0.0; /* calculate substrate current Iii */ Giig = Giib = Giid = Giie = GiiT = 0.0; here->B3SOIFDiii = Iii = 0.0; Idgidl = Gdgidld = Gdgidlg = 0.0; Isgidl = Gsgidlg = 0; here->B3SOIFDibs = Ibs = 0.0; here->B3SOIFDibd = Ibd = 0.0; here->B3SOIFDic = Ic = 0.0; Gjsb = Gjsd = GjsT = 0.0; Gjdb = Gjdd = GjdT = 0.0; Gcd = Gcb = GcT = 0.0; here->B3SOIFDibp = Ibp = 0.0; here->B3SOIFDgbpbs = here->B3SOIFDgbpgs = here->B3SOIFDgbpds = 0.0; here->B3SOIFDgbpes = here->B3SOIFDgbpps = here->B3SOIFDgbpT = here->B3SOIFDcbodcon = 0.0; Gbpbs = Gbpgs = Gbpds = Gbpes = Gbpps = GbpT = 0.0; /* Current going out of drainprime node into the drain of device */ /* "node" means the SPICE circuit node */ here->B3SOIFDcdrain = Ids + Ic; here->B3SOIFDcd = Ids + Ic - Ibd + Iii + Idgidl; here->B3SOIFDcb = Ibs + Ibd + Ibp - Iii - Idgidl - Isgidl; here->B3SOIFDgds = Gds + Gcd; here->B3SOIFDgm = Gm; here->B3SOIFDgmbs = Gmb + Gcb; here->B3SOIFDgme = Gme; if (selfheat) here->B3SOIFDgmT = GmT + GcT; else here->B3SOIFDgmT = 0.0; /* note that sign is switched because power flows out of device into the temperature node. Currently ommit self-heating due to bipolar current because it can cause convergence problem*/ here->B3SOIFDgtempg = -Gm * Vds; here->B3SOIFDgtempb = -Gmb * Vds; here->B3SOIFDgtempe = -Gme * Vds; here->B3SOIFDgtempT = -GmT * Vds; here->B3SOIFDgtempd = -Gds * Vds - Ids; here->B3SOIFDcth = - Ids * Vds - model->B3SOIFDtype * (here->B3SOIFDgtempg * Vgs + here->B3SOIFDgtempb * Vbs + here->B3SOIFDgtempe * Ves + here->B3SOIFDgtempd * Vds) - here->B3SOIFDgtempT * delTemp; /* Body current which flows into drainprime node from the drain of device */ here->B3SOIFDgjdb = Gjdb - Giib; here->B3SOIFDgjdd = Gjdd - (Giid + Gdgidld); here->B3SOIFDgjdg = - (Giig + Gdgidlg); here->B3SOIFDgjde = - Giie; if (selfheat) here->B3SOIFDgjdT = GjdT - GiiT; else here->B3SOIFDgjdT = 0.0; here->B3SOIFDcjd = Ibd - Iii - Idgidl - here->B3SOIFDminIsub/2 - (here->B3SOIFDgjdb * Vbs + here->B3SOIFDgjdd * Vds + here->B3SOIFDgjdg * Vgs + here->B3SOIFDgjde * Ves + here->B3SOIFDgjdT * delTemp); /* Body current which flows into sourceprime node from the source of device */ here->B3SOIFDgjsb = Gjsb; here->B3SOIFDgjsd = Gjsd; here->B3SOIFDgjsg = - Gsgidlg; if (selfheat) here->B3SOIFDgjsT = GjsT; else here->B3SOIFDgjsT = 0.0; here->B3SOIFDcjs = Ibs - Isgidl - here->B3SOIFDminIsub/2 - (here->B3SOIFDgjsb * Vbs + here->B3SOIFDgjsd * Vds + here->B3SOIFDgjsg * Vgs + here->B3SOIFDgjsT * delTemp); /* Current flowing into body node */ here->B3SOIFDgbbs = Giib - Gjsb - Gjdb - Gbpbs; here->B3SOIFDgbgs = Giig + Gdgidlg + Gsgidlg - Gbpgs; here->B3SOIFDgbds = Giid + Gdgidld - Gjsd - Gjdd - Gbpds; here->B3SOIFDgbes = Giie - Gbpes; here->B3SOIFDgbps = - Gbpps; if (selfheat) here->B3SOIFDgbT = GiiT - GjsT - GjdT - GbpT; else here->B3SOIFDgbT = 0.0; here->B3SOIFDcbody = Iii + Idgidl + Isgidl - Ibs - Ibd - Ibp + here->B3SOIFDminIsub - (here->B3SOIFDgbbs * Vbs + here->B3SOIFDgbgs * Vgs + here->B3SOIFDgbds * Vds + here->B3SOIFDgbps * Vps + here->B3SOIFDgbes * Ves + here->B3SOIFDgbT * delTemp); /* Calculate Qinv for Noise analysis */ T1 = Vgsteff * (1.0 - 0.5 * Abeff * Vdseff / Vgst2Vtm); here->B3SOIFDqinv = -model->B3SOIFDcox * pParam->B3SOIFDweff * Leff * T1; /* Begin CV (charge) model */ if ((model->B3SOIFDxpart < 0) || (!ChargeComputationNeeded)) { qgate = qdrn = qsrc = qbody = 0.0; here->B3SOIFDcggb = here->B3SOIFDcgsb = here->B3SOIFDcgdb = 0.0; here->B3SOIFDcdgb = here->B3SOIFDcdsb = here->B3SOIFDcddb = 0.0; here->B3SOIFDcbgb = here->B3SOIFDcbsb = here->B3SOIFDcbdb = 0.0; goto finished; } else { CoxWL = model->B3SOIFDcox * pParam->B3SOIFDweffCV * pParam->B3SOIFDleffCV; /* By using this Vgsteff,cv, discontinuity in moderate inversion charges can be avoid. However, in capMod=3, Vdsat from IV is used. The dVdsat_dVg is referred to the IV Vgsteff and therefore induces error in the charges derivatives. Fortunately, Vgsteff,iv and Vgsteff,cv are different only in subthreshold where Qsubs is neglectible. So the errors in derivatives is not a serious problem */ if ((VgstNVt > -EXP_THRESHOLD) && (VgstNVt < EXP_THRESHOLD)) { ExpVgst *= ExpVgst; Vgsteff = n * Vtm * log(1.0 + ExpVgst); T0 = ExpVgst / (1.0 + ExpVgst); T1 = -T0 * (dVth_dVb + Vgst / n * dn_dVb) + Vgsteff / n * dn_dVb; dVgsteff_dVd = -T0 * (dVth_dVd + Vgst / n * dn_dVd) + Vgsteff / n * dn_dVd + T1 * dVbseff_dVd; dVgsteff_dVg = T0 * dVgs_eff_dVg + T1 * dVbseff_dVg; dVgsteff_dVb = T1 * dVbseff_dVb; dVgsteff_dVe = T1 * dVbseff_dVe; if (selfheat) dVgsteff_dT = -T0 * (dVth_dT + Vgst / Temp) + Vgsteff / Temp + T1 * dVbseff_dT; else dVgsteff_dT = 0.0; } Vfb = Vth - phi - pParam->B3SOIFDk1 * sqrtPhis; dVfb_dVb = dVth_dVb - pParam->B3SOIFDk1 * dsqrtPhis_dVb; dVfb_dVd = dVth_dVd; dVfb_dT = dVth_dT; if ((model->B3SOIFDcapMod == 2) || (model->B3SOIFDcapMod == 3)) { /* Necessary because charge behaviour very strange at Vgsteff = 0 */ Vgsteff += 1e-4; /* Something common in capMod 2 and 3 */ V3 = Vfb - Vgs_eff + Vbseff - DELTA_3; if (Vfb <= 0.0) { T0 = sqrt(V3 * V3 - 4.0 * DELTA_3 * Vfb); T2 = -DELTA_3 / T0; } else { T0 = sqrt(V3 * V3 + 4.0 * DELTA_3 * Vfb); T2 = DELTA_3 / T0; } T1 = 0.5 * (1.0 + V3 / T0); Vfbeff = Vfb - 0.5 * (V3 + T0); dVfbeff_dVd = (1.0 - T1 - T2) * dVfb_dVd; dVfbeff_dVb = (1.0 - T1 - T2) * dVfb_dVb - T1; dVfbeff_dVrg = T1 * dVgs_eff_dVg; if (selfheat) dVfbeff_dT = (1.0 - T1 - T2) * dVfb_dT; else dVfbeff_dT = 0.0; Qac0 = -CoxWL * (Vfbeff - Vfb); dQac0_dVrg = -CoxWL * dVfbeff_dVrg; dQac0_dVd = -CoxWL * (dVfbeff_dVd - dVfb_dVd); dQac0_dVb = -CoxWL * (dVfbeff_dVb - dVfb_dVb); if (selfheat) dQac0_dT = -CoxWL * (dVfbeff_dT - dVfb_dT); else dQac0_dT = 0.0; T0 = 0.5 * K1; T3 = Vgs_eff - Vfbeff - Vbseff - Vgsteff; if (pParam->B3SOIFDk1 == 0.0) { T1 = 0.0; T2 = 0.0; } else if (T3 < 0.0) { T1 = T0 + T3 / pParam->B3SOIFDk1; T2 = CoxWL; } else { T1 = sqrt(T0 * T0 + T3); T2 = CoxWL * T0 / T1; } Qsub0 = CoxWL * K1 * (T0 - T1); dQsub0_dVrg = T2 * (dVfbeff_dVrg - dVgs_eff_dVg); dQsub0_dVg = T2; dQsub0_dVd = T2 * dVfbeff_dVd; dQsub0_dVb = T2 * (dVfbeff_dVb + 1); if (selfheat) dQsub0_dT = T2 * dVfbeff_dT; else dQsub0_dT = 0.0; One_Third_CoxWL = CoxWL / 3.0; Two_Third_CoxWL = 2.0 * One_Third_CoxWL; AbulkCV = Abulk0 * pParam->B3SOIFDabulkCVfactor; dAbulkCV_dVb = pParam->B3SOIFDabulkCVfactor * dAbulk0_dVb; /* This is actually capMod=2 calculation */ VdsatCV = Vgsteff / AbulkCV; dVdsatCV_dVg = 1.0 / AbulkCV; dVdsatCV_dVb = -VdsatCV * dAbulkCV_dVb / AbulkCV; VdsatCV += 1e-5; V4 = VdsatCV - Vds - DELTA_4; T0 = sqrt(V4 * V4 + 4.0 * DELTA_4 * VdsatCV); VdseffCV = VdsatCV - 0.5 * (V4 + T0); T1 = 0.5 * (1.0 + V4 / T0); T2 = DELTA_4 / T0; T3 = (1.0 - T1 - T2) / AbulkCV; dVdseffCV_dVg = T3; dVdseffCV_dVd = T1; dVdseffCV_dVb = -T3 * VdsatCV * dAbulkCV_dVb; if (model->B3SOIFDcapMod == 2) { /* VdsCV Make it compatible with capMod 3 */ VdsCV = VdseffCV; dVdsCV_dVg = dVdseffCV_dVg; dVdsCV_dVd = dVdseffCV_dVd; dVdsCV_dVb = dVdseffCV_dVb; } else if (model->B3SOIFDcapMod == 3) { /* Front gate strong inversion depletion charge */ /* VdssatCV calculation */ T1 = Vgsteff + K1*sqrtPhis + 0.5*K1*K1; T2 = Vgsteff + K1*sqrtPhis + Phis + 0.25*K1*K1; dT1_dVb = K1*dsqrtPhis_dVb; dT2_dVb = dT1_dVb + dPhis_dVb; dT1_dVg = dT2_dVg = 1; /* Note VdsatCV is redefined in capMod = 3 */ VdsatCV = T1 - K1*sqrt(T2); dVdsatCV_dVb = dT1_dVb - K1/2/sqrt(T2)*dT2_dVb; dVdsatCV_dVg = dT1_dVg - K1/2/sqrt(T2)*dT2_dVg; T1 = VdsatCV - Vdsat; dT1_dVg = dVdsatCV_dVg - dVdsat_dVg; dT1_dVb = dVdsatCV_dVb - dVdsat_dVb; dT1_dVd = - dVdsat_dVd; dT1_dVc = - dVdsat_dVc; dT1_dT = - dVdsat_dT; if (!(T1 == 0.0)) { T3 = -0.5 * Vdsat / T1; /* Vdsmax */ T2 = T3 * Vdsat; T4 = T2 + T1 * T3 * T3; /* fmax */ if ((Vdseff > T2) && (T1 < 0)) { VdsCV = T4; T5 = -0.5 / (T1 * T1); dT3_dVg = T5 * (T1 * dVdsat_dVg - Vdsat * dT1_dVg); dT3_dVb = T5 * (T1 * dVdsat_dVb - Vdsat * dT1_dVb); dT3_dVd = T5 * (T1 * dVdsat_dVd - Vdsat * dT1_dVd); dT3_dVc=0.0; if (selfheat) dT3_dT=T5 * (T1 * dVdsat_dT - Vdsat * dT1_dT); else dT3_dT=0.0; dVdsCV_dVd = T3 * dVdsat_dVd + Vdsat * dT3_dVd + T3 * (2 * T1 * dT3_dVd + T3 * dT1_dVd); dVdsCV_dVg = T3 * dVdsat_dVg + Vdsat * dT3_dVg + T3 * (2 * T1 * dT3_dVg + T3 * dT1_dVg); dVdsCV_dVb = T3 * dVdsat_dVb + Vdsat * dT3_dVb + T3 * (2 * T1 * dT3_dVb + T3 * dT1_dVb); dVdsCV_dVc = 0.0; if (selfheat) dVdsCV_dT = T3 * dVdsat_dT + Vdsat * dT3_dT + T3 * (2 * T1 * dT3_dT + T3 * dT1_dT ); else dVdsCV_dT = 0.0; } else { T5 = Vdseff / Vdsat; T6 = T5 * T5; T7 = 2 * T1 * T5 / Vdsat; T8 = T7 / Vdsat; VdsCV = Vdseff + T1 * T6; dVdsCV_dVd = dVdseff_dVd + T8 * ( Vdsat * dVdseff_dVd - Vdseff * dVdsat_dVd) + T6 * dT1_dVd; dVdsCV_dVb = dVdseff_dVb + T8 * ( Vdsat * dVdseff_dVb - Vdseff * dVdsat_dVb) + T6 * dT1_dVb; dVdsCV_dVg = dVdseff_dVg + T8 * ( Vdsat * dVdseff_dVg - Vdseff * dVdsat_dVg) + T6 * dT1_dVg; dVdsCV_dVc = 0.0; if (selfheat) dVdsCV_dT = dVdseff_dT + T8 * ( Vdsat * dVdseff_dT - Vdseff * dVdsat_dT ) + T6 * dT1_dT ; else dVdsCV_dT = 0.0; } } else { VdsCV = Vdseff; dVdsCV_dVb = dVdseff_dVb; dVdsCV_dVd = dVdseff_dVd; dVdsCV_dVg = dVdseff_dVg; dVdsCV_dVc = dVdseff_dVc; dVdsCV_dT = dVdseff_dT; } if (VdsCV < 0.0) VdsCV = 0.0; VdsCV += 1e-4; if (VdsCV > (VdsatCV - 1e-7)) { VdsCV = VdsatCV - 1e-7; } Phisd = Phis + VdsCV; dPhisd_dVb = dPhis_dVb + dVdsCV_dVb; dPhisd_dVd = dVdsCV_dVd; dPhisd_dVg = dVdsCV_dVg; dPhisd_dVc = dVdsCV_dVc; dPhisd_dT = dVdsCV_dT; sqrtPhisd = sqrt(Phisd); /* Qdep0 - Depletion charge at Vgs=Vth */ T10 = CoxWL * K1; Qdep0 = T10 * sqrtPhis; dQdep0_dVb = T10 * dsqrtPhis_dVb; } /* End of if capMod == 3 */ /* Something common in both capMod 2 or 3 */ /* Backgate charge */ CboxWL = pParam->B3SOIFDkb3 * Cbox * pParam->B3SOIFDweffCV * pParam->B3SOIFDleffCV; Cbg = Cbb = Cbd = Cbe = CbT = 0.0; Ce2g = Ce2b = Ce2d = Ce2e = Ce2T = 0.0; Qbf = Qe2 = 0.0; T2 = - 0.5 * model->B3SOIFDcboxt * pParam->B3SOIFDweffCV * pParam->B3SOIFDleffCV; Qe1 = T2 * VdsCV - CboxWL * (Vbs0eff - Vesfb); Ce1g = T2 * (dVdsCV_dVg * dVgsteff_dVg + dVdsCV_dVb * dVbseff_dVg + dVdsCV_dVc * dVcs_dVg) - CboxWL * dVbs0eff_dVg; Ce1d = T2 * (dVdsCV_dVg * dVgsteff_dVd + dVdsCV_dVb * dVbseff_dVd + dVdsCV_dVc * dVcs_dVd + dVdsCV_dVd) - CboxWL * dVbs0eff_dVd; Ce1b = 0.0; Ce1e = T2 * (dVdsCV_dVg * dVgsteff_dVe + dVdsCV_dVb * dVbseff_dVe + dVdsCV_dVc * dVcs_dVe) - CboxWL * (dVbs0eff_dVe - 1.0); if (selfheat) Ce1T = T2 * (dVdsCV_dVg * dVgsteff_dT + dVdsCV_dVb * dVbseff_dT + dVdsCV_dVc * dVcs_dT + dVdsCV_dT) - CboxWL * (dVbs0eff_dT + dvfbb_dT); else Ce1T = 0.0; /* Total inversion charge */ T0 = AbulkCV * VdseffCV; T1 = 12.0 * (Vgsteff - 0.5 * T0 + 1e-20); T2 = VdseffCV / T1; T3 = T0 * T2; T4 = (1.0 - 12.0 * T2 * T2 * AbulkCV); T5 = (6.0 * T0 * (4.0 * Vgsteff - T0) / (T1 * T1) - 0.5); T6 = 12.0 * T2 * T2 * Vgsteff; qinv = CoxWL * (Vgsteff - 0.5 * VdseffCV + T3); Cgg1 = CoxWL * (T4 + T5 * dVdseffCV_dVg); Cgd1 = CoxWL * T5 * dVdseffCV_dVd; Cgb1 = CoxWL * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb); /* Inversion charge partitioning into S / D */ if (model->B3SOIFDxpart > 0.5) { /* 0/100 Charge partition model */ T1 = T1 + T1; qsrc = -CoxWL * (0.5 * Vgsteff + 0.25 * T0 - T0 * T0 / T1); T7 = (4.0 * Vgsteff - T0) / (T1 * T1); T4 = -(0.5 + 24.0 * T0 * T0 / (T1 * T1)); T5 = -(0.25 * AbulkCV - 12.0 * AbulkCV * T0 * T7); T6 = -(0.25 * VdseffCV - 12.0 * T0 * VdseffCV * T7); Csg1 = CoxWL * (T4 + T5 * dVdseffCV_dVg); Csd1 = CoxWL * T5 * dVdseffCV_dVd; Csb1 = CoxWL * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb); } else if (model->B3SOIFDxpart < 0.5) { /* 40/60 Charge partition model */ T1 = T1 / 12.0; T2 = 0.5 * CoxWL / (T1 * T1); T3 = Vgsteff * (2.0 * T0 * T0 / 3.0 + Vgsteff * (Vgsteff - 4.0 * T0 / 3.0)) - 2.0 * T0 * T0 * T0 / 15.0; qsrc = -T2 * T3; T7 = 4.0 / 3.0 * Vgsteff * (Vgsteff - T0) + 0.4 * T0 * T0; T4 = -2.0 * qsrc / T1 - T2 * (Vgsteff * (3.0 * Vgsteff - 8.0 * T0 / 3.0) + 2.0 * T0 * T0 / 3.0); T5 = (qsrc / T1 + T2 * T7) * AbulkCV; T6 = (qsrc / T1 * VdseffCV + T2 * T7 * VdseffCV); Csg1 = T4 + T5 * dVdseffCV_dVg; Csd1 = T5 * dVdseffCV_dVd; Csb1 = T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb; } else { /* 50/50 Charge partition model */ qsrc = - 0.5 * qinv; Csg1 = - 0.5 * Cgg1; Csb1 = - 0.5 * Cgb1; Csd1 = - 0.5 * Cgd1; } Csg = Csg1 * dVgsteff_dVg + Csb1 * dVbseff_dVg; Csd = Csd1 + Csg1 * dVgsteff_dVd + Csb1 * dVbseff_dVd; Csb = Csg1 * dVgsteff_dVb + Csb1 * dVbseff_dVb; Cse = Csg1 * dVgsteff_dVe + Csb1 * dVbseff_dVe; if (selfheat) CsT = Csg1 * dVgsteff_dT + Csb1 * dVbseff_dT; else CsT = 0.0; Qex=dQex_dVg=dQex_dVb=dQex_dVd=dQex_dVe=dQex_dT=0.0; qgate = qinv - (Qbf + Qe2); qbody = (Qbf - Qe1 + Qex); qsub = Qe1 + Qe2 - Qex; qdrn = -(qinv + qsrc); Cgg = (Cgg1 * dVgsteff_dVg + Cgb1 * dVbseff_dVg) - Cbg ; Cgd = (Cgd1 + Cgg1 * dVgsteff_dVd + Cgb1 * dVbseff_dVd)-Cbd; Cgb = (Cgb1 * dVbseff_dVb + Cgg1 * dVgsteff_dVb) - Cbb; Cge = (Cgg1 * dVgsteff_dVe + Cgb1 * dVbseff_dVe) - Cbe; if (selfheat) CgT = (Cgg1 * dVgsteff_dT + Cgb1 * dVbseff_dT ) - CbT; else CgT = 0.0; here->B3SOIFDcggb = Cgg - Ce2g; here->B3SOIFDcgsb = - (Cgg + Cgd + Cgb + Cge) + (Ce2g + Ce2d + Ce2b + Ce2e); here->B3SOIFDcgdb = Cgd - Ce2d; here->B3SOIFDcgeb = Cge - Ce2e; here->B3SOIFDcgT = CgT - Ce2T; here->B3SOIFDcbgb = Cbg - Ce1g + dQex_dVg; here->B3SOIFDcbsb = -(Cbg + Cbd + Cbb + Cbe) + (Ce1g + Ce1d + Ce1b + Ce1e) - (dQex_dVg + dQex_dVd + dQex_dVb + dQex_dVe); here->B3SOIFDcbdb = Cbd - Ce1d + dQex_dVd; here->B3SOIFDcbeb = Cbe - Ce1e + dQex_dVe; here->B3SOIFDcbT = CbT - Ce1T + dQex_dT; here->B3SOIFDcegb = Ce1g + Ce2g - dQex_dVg; here->B3SOIFDcesb = -(Ce1g + Ce1d + Ce1b + Ce1e) -(Ce2g + Ce2d + Ce2b + Ce2e) +(dQex_dVg + dQex_dVd + dQex_dVb + dQex_dVe); here->B3SOIFDcedb = Ce1d + Ce2d - dQex_dVd; here->B3SOIFDceeb = Ce1e + Ce2e - dQex_dVe; here->B3SOIFDceT = Ce1T + Ce2T - dQex_dT; here->B3SOIFDcdgb = -(Cgg + Cbg + Csg); here->B3SOIFDcddb = -(Cgd + Cbd + Csd); here->B3SOIFDcdeb = -(Cge + Cbe + Cse); here->B3SOIFDcdT = -(CgT + CbT + CsT); here->B3SOIFDcdsb = (Cgg + Cgd + Cgb + Cge + Cbg + Cbd + Cbb + Cbe + Csg + Csd + Csb + Cse); } /* End of if capMod == 2 or capMod ==3 */ } finished: /* returning Values to Calling Routine */ /* * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE */ if (ChargeComputationNeeded) { qjs = qjd = 0.0; gcjdds = gcjdbs = gcjdT = 0.0; gcjsbs = gcjsT = 0.0; qdrn -= qjd; qbody += (qjs + qjd); qsrc = -(qgate + qbody + qdrn + qsub); /* Update the conductance */ here->B3SOIFDcddb -= gcjdds; here->B3SOIFDcdT -= gcjdT; here->B3SOIFDcdsb += gcjdds + gcjdbs; here->B3SOIFDcbdb += (gcjdds); here->B3SOIFDcbT += (gcjdT + gcjsT); here->B3SOIFDcbsb -= (gcjdds + gcjdbs + gcjsbs); /* Extrinsic Bottom S/D to substrate charge */ T10 = -model->B3SOIFDtype * ves; /* T10 is vse without type conversion */ if ( ((pParam->B3SOIFDnsub > 0) && (model->B3SOIFDtype > 0)) || ((pParam->B3SOIFDnsub < 0) && (model->B3SOIFDtype < 0)) ) { if (T10 < pParam->B3SOIFDvsdfb) { here->B3SOIFDqse = here->B3SOIFDcsbox * (T10 - pParam->B3SOIFDvsdfb); here->B3SOIFDgcse = here->B3SOIFDcsbox; } else if (T10 < pParam->B3SOIFDsdt1) { T0 = T10 - pParam->B3SOIFDvsdfb; T1 = T0 * T0; here->B3SOIFDqse = T0 * (here->B3SOIFDcsbox - pParam->B3SOIFDst2 / 3 * T1) ; here->B3SOIFDgcse = here->B3SOIFDcsbox - pParam->B3SOIFDst2 * T1; } else if (T10 < pParam->B3SOIFDvsdth) { T0 = T10 - pParam->B3SOIFDvsdth; T1 = T0 * T0; here->B3SOIFDqse = here->B3SOIFDcsmin * T10 + here->B3SOIFDst4 + pParam->B3SOIFDst3 / 3 * T0 * T1; here->B3SOIFDgcse = here->B3SOIFDcsmin + pParam->B3SOIFDst3 * T1; } else { here->B3SOIFDqse = here->B3SOIFDcsmin * T10 + here->B3SOIFDst4; here->B3SOIFDgcse = here->B3SOIFDcsmin; } } else { if (T10 < pParam->B3SOIFDvsdth) { here->B3SOIFDqse = here->B3SOIFDcsmin * (T10 - pParam->B3SOIFDvsdth); here->B3SOIFDgcse = here->B3SOIFDcsmin; } else if (T10 < pParam->B3SOIFDsdt1) { T0 = T10 - pParam->B3SOIFDvsdth; T1 = T0 * T0; here->B3SOIFDqse = T0 * (here->B3SOIFDcsmin - pParam->B3SOIFDst2 / 3 * T1) ; here->B3SOIFDgcse = here->B3SOIFDcsmin - pParam->B3SOIFDst2 * T1; } else if (T10 < pParam->B3SOIFDvsdfb) { T0 = T10 - pParam->B3SOIFDvsdfb; T1 = T0 * T0; here->B3SOIFDqse = here->B3SOIFDcsbox * T10 + here->B3SOIFDst4 + pParam->B3SOIFDst3 / 3 * T0 * T1; here->B3SOIFDgcse = here->B3SOIFDcsbox + pParam->B3SOIFDst3 * T1; } else { here->B3SOIFDqse = here->B3SOIFDcsbox * T10 + here->B3SOIFDst4; here->B3SOIFDgcse = here->B3SOIFDcsbox; } } /* T11 is vde without type conversion */ T11 = model->B3SOIFDtype * (vds - ves); if ( ((pParam->B3SOIFDnsub > 0) && (model->B3SOIFDtype > 0)) || ((pParam->B3SOIFDnsub < 0) && (model->B3SOIFDtype < 0)) ) { if (T11 < pParam->B3SOIFDvsdfb) { here->B3SOIFDqde = here->B3SOIFDcdbox * (T11 - pParam->B3SOIFDvsdfb); here->B3SOIFDgcde = here->B3SOIFDcdbox; } else if (T11 < pParam->B3SOIFDsdt1) { T0 = T11 - pParam->B3SOIFDvsdfb; T1 = T0 * T0; here->B3SOIFDqde = T0 * (here->B3SOIFDcdbox - pParam->B3SOIFDdt2 / 3 * T1) ; here->B3SOIFDgcde = here->B3SOIFDcdbox - pParam->B3SOIFDdt2 * T1; } else if (T11 < pParam->B3SOIFDvsdth) { T0 = T11 - pParam->B3SOIFDvsdth; T1 = T0 * T0; here->B3SOIFDqde = here->B3SOIFDcdmin * T11 + here->B3SOIFDdt4 + pParam->B3SOIFDdt3 / 3 * T0 * T1; here->B3SOIFDgcde = here->B3SOIFDcdmin + pParam->B3SOIFDdt3 * T1; } else { here->B3SOIFDqde = here->B3SOIFDcdmin * T11 + here->B3SOIFDdt4; here->B3SOIFDgcde = here->B3SOIFDcdmin; } } else { if (T11 < pParam->B3SOIFDvsdth) { here->B3SOIFDqde = here->B3SOIFDcdmin * (T11 - pParam->B3SOIFDvsdth); here->B3SOIFDgcde = here->B3SOIFDcdmin; } else if (T11 < pParam->B3SOIFDsdt1) { T0 = T11 - pParam->B3SOIFDvsdth; T1 = T0 * T0; here->B3SOIFDqde = T0 * (here->B3SOIFDcdmin - pParam->B3SOIFDdt2 / 3 * T1) ; here->B3SOIFDgcde = here->B3SOIFDcdmin - pParam->B3SOIFDdt2 * T1; } else if (T11 < pParam->B3SOIFDvsdfb) { T0 = T11 - pParam->B3SOIFDvsdfb; T1 = T0 * T0; here->B3SOIFDqde = here->B3SOIFDcdbox * T11 + here->B3SOIFDdt4 + pParam->B3SOIFDdt3 / 3 * T0 * T1; here->B3SOIFDgcde = here->B3SOIFDcdbox + pParam->B3SOIFDdt3 * T1; } else { here->B3SOIFDqde = here->B3SOIFDcdbox * T11 + here->B3SOIFDdt4; here->B3SOIFDgcde = here->B3SOIFDcdbox; } } /* Extrinsic : Sidewall fringing S/D charge */ here->B3SOIFDqse += pParam->B3SOIFDcsesw * T10; here->B3SOIFDgcse += pParam->B3SOIFDcsesw; here->B3SOIFDqde += pParam->B3SOIFDcdesw * T11; here->B3SOIFDgcde += pParam->B3SOIFDcdesw; /* All charge are mutliplied with type at the end, but qse and qde have true polarity => so pre-mutliplied with type */ here->B3SOIFDqse *= model->B3SOIFDtype; here->B3SOIFDqde *= model->B3SOIFDtype; } here->B3SOIFDxc = Xc; here->B3SOIFDcbb = Cbb; here->B3SOIFDcbd = Cbd; here->B3SOIFDcbg = Cbg; here->B3SOIFDqbf = Qbf; here->B3SOIFDqjs = qjs; here->B3SOIFDqjd = qjd; if (here->B3SOIFDdebugMod == -1) ChargeComputationNeeded = 0; /* * check convergence */ if ((here->B3SOIFDoff == 0) || (!(ckt->CKTmode & MODEINITFIX))) { if (Check == 1) { ckt->CKTnoncon++; if (here->B3SOIFDdebugMod > 2) fprintf(fpdebug, "Check is on, noncon=%d\n", ckt->CKTnoncon++); } } *(ckt->CKTstate0 + here->B3SOIFDvg) = vg; *(ckt->CKTstate0 + here->B3SOIFDvd) = vd; *(ckt->CKTstate0 + here->B3SOIFDvs) = vs; *(ckt->CKTstate0 + here->B3SOIFDvp) = vp; *(ckt->CKTstate0 + here->B3SOIFDve) = ve; *(ckt->CKTstate0 + here->B3SOIFDvbs) = vbs; *(ckt->CKTstate0 + here->B3SOIFDvbd) = vbd; *(ckt->CKTstate0 + here->B3SOIFDvgs) = vgs; *(ckt->CKTstate0 + here->B3SOIFDvds) = vds; *(ckt->CKTstate0 + here->B3SOIFDves) = ves; *(ckt->CKTstate0 + here->B3SOIFDvps) = vps; *(ckt->CKTstate0 + here->B3SOIFDdeltemp) = delTemp; /* bulk and channel charge plus overlaps */ if (!ChargeComputationNeeded) goto line850; line755: ag0 = ckt->CKTag[0]; T0 = vgd + DELTA_1; T1 = sqrt(T0 * T0 + 4.0 * DELTA_1); T2 = 0.5 * (T0 - T1); T3 = pParam->B3SOIFDweffCV * pParam->B3SOIFDcgdl; T4 = sqrt(1.0 - 4.0 * T2 / pParam->B3SOIFDckappa); cgdo = pParam->B3SOIFDcgdo + T3 - T3 * (1.0 - 1.0 / T4) * (0.5 - 0.5 * T0 / T1); qgdo = (pParam->B3SOIFDcgdo + T3) * vgd - T3 * (T2 + 0.5 * pParam->B3SOIFDckappa * (T4 - 1.0)); T0 = vgs + DELTA_1; T1 = sqrt(T0 * T0 + 4.0 * DELTA_1); T2 = 0.5 * (T0 - T1); T3 = pParam->B3SOIFDweffCV * pParam->B3SOIFDcgsl; T4 = sqrt(1.0 - 4.0 * T2 / pParam->B3SOIFDckappa); cgso = pParam->B3SOIFDcgso + T3 - T3 * (1.0 - 1.0 / T4) * (0.5 - 0.5 * T0 / T1); qgso = (pParam->B3SOIFDcgso + T3) * vgs - T3 * (T2 + 0.5 * pParam->B3SOIFDckappa * (T4 - 1.0)); if (here->B3SOIFDmode > 0) { gcdgb = (here->B3SOIFDcdgb - cgdo) * ag0; gcddb = (here->B3SOIFDcddb + cgdo + here->B3SOIFDgcde) * ag0; gcdsb = here->B3SOIFDcdsb * ag0; gcdeb = (here->B3SOIFDcdeb - here->B3SOIFDgcde) * ag0; gcdT = model->B3SOIFDtype * here->B3SOIFDcdT * ag0; gcsgb = -(here->B3SOIFDcggb + here->B3SOIFDcbgb + here->B3SOIFDcdgb + here->B3SOIFDcegb + cgso) * ag0; gcsdb = -(here->B3SOIFDcgdb + here->B3SOIFDcbdb + here->B3SOIFDcddb + here->B3SOIFDcedb) * ag0; gcssb = (cgso + here->B3SOIFDgcse - (here->B3SOIFDcgsb + here->B3SOIFDcbsb + here->B3SOIFDcdsb + here->B3SOIFDcesb)) * ag0; gcseb = -(here->B3SOIFDgcse + here->B3SOIFDcgeb + here->B3SOIFDcbeb + here->B3SOIFDcdeb + here->B3SOIFDceeb) * ag0; gcsT = - model->B3SOIFDtype * (here->B3SOIFDcgT + here->B3SOIFDcbT + here->B3SOIFDcdT + here->B3SOIFDceT) * ag0; gcggb = (here->B3SOIFDcggb + cgdo + cgso + pParam->B3SOIFDcgeo) * ag0; gcgdb = (here->B3SOIFDcgdb - cgdo) * ag0; gcgsb = (here->B3SOIFDcgsb - cgso) * ag0; gcgeb = (here->B3SOIFDcgeb - pParam->B3SOIFDcgeo) * ag0; gcgT = model->B3SOIFDtype * here->B3SOIFDcgT * ag0; gcbgb = here->B3SOIFDcbgb * ag0; gcbdb = here->B3SOIFDcbdb * ag0; gcbsb = here->B3SOIFDcbsb * ag0; gcbeb = here->B3SOIFDcbeb * ag0; gcbT = model->B3SOIFDtype * here->B3SOIFDcbT * ag0; gcegb = (here->B3SOIFDcegb - pParam->B3SOIFDcgeo) * ag0; gcedb = (here->B3SOIFDcedb - here->B3SOIFDgcde) * ag0; gcesb = (here->B3SOIFDcesb - here->B3SOIFDgcse) * ag0; gceeb = (here->B3SOIFDgcse + here->B3SOIFDgcde + here->B3SOIFDceeb + pParam->B3SOIFDcgeo) * ag0; gceT = model->B3SOIFDtype * here->B3SOIFDceT * ag0; gcTt = pParam->B3SOIFDcth * ag0; sxpart = 0.6; dxpart = 0.4; /* Lump the overlap capacitance and S/D parasitics */ qgd = qgdo; qgs = qgso; qge = pParam->B3SOIFDcgeo * vge; qgate += qgd + qgs + qge; qdrn += here->B3SOIFDqde - qgd; qsub -= qge + here->B3SOIFDqse + here->B3SOIFDqde; qsrc = -(qgate + qbody + qdrn + qsub); } else { gcsgb = (here->B3SOIFDcdgb - cgso) * ag0; gcssb = (here->B3SOIFDcddb + cgso + here->B3SOIFDgcse) * ag0; gcsdb = here->B3SOIFDcdsb * ag0; gcseb = (here->B3SOIFDcdeb - here->B3SOIFDgcse) * ag0; gcsT = model->B3SOIFDtype * here->B3SOIFDcdT * ag0; gcdgb = -(here->B3SOIFDcggb + here->B3SOIFDcbgb + here->B3SOIFDcdgb + here->B3SOIFDcegb + cgdo) * ag0; gcdsb = -(here->B3SOIFDcgdb + here->B3SOIFDcbdb + here->B3SOIFDcddb + here->B3SOIFDcedb) * ag0; gcddb = (cgdo + here->B3SOIFDgcde - (here->B3SOIFDcgsb + here->B3SOIFDcbsb + here->B3SOIFDcdsb + here->B3SOIFDcesb)) * ag0; gcdeb = -(here->B3SOIFDgcde + here->B3SOIFDcgeb + here->B3SOIFDcbeb + here->B3SOIFDcdeb + here->B3SOIFDceeb) * ag0; gcdT = - model->B3SOIFDtype * (here->B3SOIFDcgT + here->B3SOIFDcbT + here->B3SOIFDcdT + here->B3SOIFDceT) * ag0; gcggb = (here->B3SOIFDcggb + cgdo + cgso + pParam->B3SOIFDcgeo) * ag0; gcgsb = (here->B3SOIFDcgdb - cgso) * ag0; gcgdb = (here->B3SOIFDcgsb - cgdo) * ag0; gcgeb = (here->B3SOIFDcgeb - pParam->B3SOIFDcgeo) * ag0; gcgT = model->B3SOIFDtype * here->B3SOIFDcgT * ag0; gcbgb = here->B3SOIFDcbgb * ag0; gcbsb = here->B3SOIFDcbdb * ag0; gcbdb = here->B3SOIFDcbsb * ag0; gcbeb = here->B3SOIFDcbeb * ag0; gcbT = model->B3SOIFDtype * here->B3SOIFDcbT * ag0; gcegb = (here->B3SOIFDcegb - pParam->B3SOIFDcgeo) * ag0; gcesb = (here->B3SOIFDcedb - here->B3SOIFDgcse) * ag0; gcedb = (here->B3SOIFDcesb - here->B3SOIFDgcde) * ag0; gceeb = (here->B3SOIFDceeb + pParam->B3SOIFDcgeo + here->B3SOIFDgcse + here->B3SOIFDgcde) * ag0; gceT = model->B3SOIFDtype * here->B3SOIFDceT * ag0; gcTt = pParam->B3SOIFDcth * ag0; dxpart = 0.6; sxpart = 0.4; /* Lump the overlap capacitance */ qgd = qgdo; qgs = qgso; qge = pParam->B3SOIFDcgeo * vge; qgate += qgd + qgs + qge; qsrc = qdrn - qgs + here->B3SOIFDqse; qsub -= qge + here->B3SOIFDqse + here->B3SOIFDqde; qdrn = -(qgate + qbody + qsrc + qsub); } here->B3SOIFDcgdo = cgdo; here->B3SOIFDcgso = cgso; if (ByPass) goto line860; *(ckt->CKTstate0 + here->B3SOIFDqe) = qsub; *(ckt->CKTstate0 + here->B3SOIFDqg) = qgate; *(ckt->CKTstate0 + here->B3SOIFDqd) = qdrn; *(ckt->CKTstate0 + here->B3SOIFDqb) = qbody; if ((model->B3SOIFDshMod == 1) && (here->B3SOIFDrth0!=0.0)) *(ckt->CKTstate0 + here->B3SOIFDqth) = pParam->B3SOIFDcth * delTemp; /* store small signal parameters */ if (ckt->CKTmode & MODEINITSMSIG) { goto line1000; } if (!ChargeComputationNeeded) goto line850; if (ckt->CKTmode & MODEINITTRAN) { *(ckt->CKTstate1 + here->B3SOIFDqb) = *(ckt->CKTstate0 + here->B3SOIFDqb); *(ckt->CKTstate1 + here->B3SOIFDqg) = *(ckt->CKTstate0 + here->B3SOIFDqg); *(ckt->CKTstate1 + here->B3SOIFDqd) = *(ckt->CKTstate0 + here->B3SOIFDqd); *(ckt->CKTstate1 + here->B3SOIFDqe) = *(ckt->CKTstate0 + here->B3SOIFDqe); *(ckt->CKTstate1 + here->B3SOIFDqth) = *(ckt->CKTstate0 + here->B3SOIFDqth); } error = NIintegrate(ckt, &geq, &ceq,0.0,here->B3SOIFDqb); if (error) return(error); error = NIintegrate(ckt, &geq, &ceq, 0.0, here->B3SOIFDqg); if (error) return(error); error = NIintegrate(ckt,&geq, &ceq, 0.0, here->B3SOIFDqd); if (error) return(error); error = NIintegrate(ckt,&geq, &ceq, 0.0, here->B3SOIFDqe); if (error) return(error); if ((model->B3SOIFDshMod == 1) && (here->B3SOIFDrth0!=0.0)) { error = NIintegrate(ckt, &geq, &ceq, 0.0, here->B3SOIFDqth); if (error) return (error); } goto line860; line850: /* initialize to zero charge conductance and current */ ceqqe = ceqqg = ceqqb = ceqqd = ceqqth= 0.0; gcdgb = gcddb = gcdsb = gcdeb = gcdT = 0.0; gcsgb = gcsdb = gcssb = gcseb = gcsT = 0.0; gcggb = gcgdb = gcgsb = gcgeb = gcgT = 0.0; gcbgb = gcbdb = gcbsb = gcbeb = gcbT = 0.0; gcegb = gcedb = gceeb = gcesb = gceT = 0.0; gcTt = 0.0; sxpart = (1.0 - (dxpart = (here->B3SOIFDmode > 0) ? 0.4 : 0.6)); goto line900; line860: /* evaluate equivalent charge current */ cqgate = *(ckt->CKTstate0 + here->B3SOIFDcqg); cqbody = *(ckt->CKTstate0 + here->B3SOIFDcqb); cqdrn = *(ckt->CKTstate0 + here->B3SOIFDcqd); cqsub = *(ckt->CKTstate0 + here->B3SOIFDcqe); cqtemp = *(ckt->CKTstate0 + here->B3SOIFDcqth); here->B3SOIFDcb += cqbody; here->B3SOIFDcd += cqdrn; ceqqg = cqgate - gcggb * vgb + gcgdb * vbd + gcgsb * vbs - gcgeb * veb - gcgT * delTemp; ceqqb = cqbody - gcbgb * vgb + gcbdb * vbd + gcbsb * vbs - gcbeb * veb - gcbT * delTemp; ceqqd = cqdrn - gcdgb * vgb + gcddb * vbd + gcdsb * vbs - gcdeb * veb - gcdT * delTemp; ceqqe = cqsub - gcegb * vgb + gcedb * vbd + gcesb * vbs - gceeb * veb - gceT * delTemp;; ceqqth = cqtemp - gcTt * delTemp; if (ckt->CKTmode & MODEINITTRAN) { *(ckt->CKTstate1 + here->B3SOIFDcqe) = *(ckt->CKTstate0 + here->B3SOIFDcqe); *(ckt->CKTstate1 + here->B3SOIFDcqb) = *(ckt->CKTstate0 + here->B3SOIFDcqb); *(ckt->CKTstate1 + here->B3SOIFDcqg) = *(ckt->CKTstate0 + here->B3SOIFDcqg); *(ckt->CKTstate1 + here->B3SOIFDcqd) = *(ckt->CKTstate0 + here->B3SOIFDcqd); *(ckt->CKTstate1 + here->B3SOIFDcqth) = *(ckt->CKTstate0 + here->B3SOIFDcqth); } /* * load current vector */ line900: m = here->B3SOIFDm; if (here->B3SOIFDmode >= 0) { Gm = here->B3SOIFDgm; Gmbs = here->B3SOIFDgmbs; Gme = here->B3SOIFDgme; GmT = model->B3SOIFDtype * here->B3SOIFDgmT; FwdSum = Gm + Gmbs + Gme; RevSum = 0.0; cdreq = model->B3SOIFDtype * (here->B3SOIFDcdrain - here->B3SOIFDgds * vds - Gm * vgs - Gmbs * vbs - Gme * ves - GmT * delTemp); /* ceqbs now is compatible with cdreq, ie. going in is +ve */ /* Equivalent current source from the diode */ ceqbs = here->B3SOIFDcjs; ceqbd = here->B3SOIFDcjd; /* Current going in is +ve */ ceqbody = -here->B3SOIFDcbody; ceqth = here->B3SOIFDcth; ceqbodcon = here->B3SOIFDcbodcon; gbbg = -here->B3SOIFDgbgs; gbbdp = -here->B3SOIFDgbds; gbbb = -here->B3SOIFDgbbs; gbbe = -here->B3SOIFDgbes; gbbp = -here->B3SOIFDgbps; gbbT = -model->B3SOIFDtype * here->B3SOIFDgbT; gbbsp = - ( gbbg + gbbdp + gbbb + gbbe + gbbp); gddpg = -here->B3SOIFDgjdg; gddpdp = -here->B3SOIFDgjdd; gddpb = -here->B3SOIFDgjdb; gddpe = -here->B3SOIFDgjde; gddpT = -model->B3SOIFDtype * here->B3SOIFDgjdT; gddpsp = - ( gddpg + gddpdp + gddpb + gddpe); gsspg = -here->B3SOIFDgjsg; gsspdp = -here->B3SOIFDgjsd; gsspb = -here->B3SOIFDgjsb; gsspe = 0.0; gsspT = -model->B3SOIFDtype * here->B3SOIFDgjsT; gsspsp = - (gsspg + gsspdp + gsspb + gsspe); gppg = -here->B3SOIFDgbpgs; gppdp = -here->B3SOIFDgbpds; gppb = -here->B3SOIFDgbpbs; gppe = -here->B3SOIFDgbpes; gppp = -here->B3SOIFDgbpps; gppT = -model->B3SOIFDtype * here->B3SOIFDgbpT; gppsp = - (gppg + gppdp + gppb + gppe + gppp); gTtg = here->B3SOIFDgtempg; gTtb = here->B3SOIFDgtempb; gTte = here->B3SOIFDgtempe; gTtdp = here->B3SOIFDgtempd; gTtt = here->B3SOIFDgtempT; gTtsp = - (gTtg + gTtb + gTte + gTtdp); } else { Gm = -here->B3SOIFDgm; Gmbs = -here->B3SOIFDgmbs; Gme = -here->B3SOIFDgme; GmT = -model->B3SOIFDtype * here->B3SOIFDgmT; FwdSum = 0.0; RevSum = -(Gm + Gmbs + Gme); cdreq = -model->B3SOIFDtype * (here->B3SOIFDcdrain + here->B3SOIFDgds*vds + Gm * vgd + Gmbs * vbd + Gme * (ves - vds) + GmT * delTemp); ceqbs = here->B3SOIFDcjd; ceqbd = here->B3SOIFDcjs; /* Current going in is +ve */ ceqbody = -here->B3SOIFDcbody; ceqth = here->B3SOIFDcth; ceqbodcon = here->B3SOIFDcbodcon; gbbg = -here->B3SOIFDgbgs; gbbb = -here->B3SOIFDgbbs; gbbe = -here->B3SOIFDgbes; gbbp = -here->B3SOIFDgbps; gbbsp = -here->B3SOIFDgbds; gbbT = -model->B3SOIFDtype * here->B3SOIFDgbT; gbbdp = - ( gbbg + gbbsp + gbbb + gbbe + gbbp); gddpg = -here->B3SOIFDgjsg; gddpsp = -here->B3SOIFDgjsd; gddpb = -here->B3SOIFDgjsb; gddpe = 0.0; gddpT = -model->B3SOIFDtype * here->B3SOIFDgjsT; gddpdp = - (gddpg + gddpsp + gddpb + gddpe); gsspg = -here->B3SOIFDgjdg; gsspsp = -here->B3SOIFDgjdd; gsspb = -here->B3SOIFDgjdb; gsspe = -here->B3SOIFDgjde; gsspT = -model->B3SOIFDtype * here->B3SOIFDgjdT; gsspdp = - ( gsspg + gsspsp + gsspb + gsspe); gppg = -here->B3SOIFDgbpgs; gppsp = -here->B3SOIFDgbpds; gppb = -here->B3SOIFDgbpbs; gppe = -here->B3SOIFDgbpes; gppp = -here->B3SOIFDgbpps; gppT = -model->B3SOIFDtype * here->B3SOIFDgbpT; gppdp = - (gppg + gppsp + gppb + gppe + gppp); gTtg = here->B3SOIFDgtempg; gTtb = here->B3SOIFDgtempb; gTte = here->B3SOIFDgtempe; gTtsp = here->B3SOIFDgtempd; gTtt = here->B3SOIFDgtempT; gTtdp = - (gTtg + gTtb + gTte + gTtsp); } if (model->B3SOIFDtype > 0) { ceqqg = ceqqg; ceqqb = ceqqb; ceqqe = ceqqe; ceqqd = ceqqd; } else { ceqbodcon = -ceqbodcon; ceqbody = -ceqbody; ceqbs = -ceqbs; ceqbd = -ceqbd; ceqqg = -ceqqg; ceqqb = -ceqqb; ceqqd = -ceqqd; ceqqe = -ceqqe; } (*(ckt->CKTrhs + here->B3SOIFDgNode) -= m * ceqqg); (*(ckt->CKTrhs + here->B3SOIFDdNodePrime) += m * (ceqbd - cdreq - ceqqd)); (*(ckt->CKTrhs + here->B3SOIFDsNodePrime) += m * (cdreq + ceqbs + ceqqg + ceqqb + ceqqd + ceqqe)); (*(ckt->CKTrhs + here->B3SOIFDeNode) -= m * ceqqe); if (here->B3SOIFDbodyMod == 1) { (*(ckt->CKTrhs + here->B3SOIFDpNode) += m * ceqbodcon); } if (selfheat) { (*(ckt->CKTrhs + here->B3SOIFDtempNode) -= m * (ceqth + ceqqth)); } if ((here->B3SOIFDdebugMod > 1) || (here->B3SOIFDdebugMod == -1)) { *(ckt->CKTrhs + here->B3SOIFDvbsNode) = here->B3SOIFDvbsdio; *(ckt->CKTrhs + here->B3SOIFDidsNode) = here->B3SOIFDids; *(ckt->CKTrhs + here->B3SOIFDicNode) = here->B3SOIFDic; *(ckt->CKTrhs + here->B3SOIFDibsNode) = here->B3SOIFDibs; *(ckt->CKTrhs + here->B3SOIFDibdNode) = here->B3SOIFDibd; *(ckt->CKTrhs + here->B3SOIFDiiiNode) = here->B3SOIFDiii; *(ckt->CKTrhs + here->B3SOIFDigidlNode) = here->B3SOIFDigidl; *(ckt->CKTrhs + here->B3SOIFDitunNode) = here->B3SOIFDitun; *(ckt->CKTrhs + here->B3SOIFDibpNode) = here->B3SOIFDibp; *(ckt->CKTrhs + here->B3SOIFDabeffNode) = here->B3SOIFDabeff; *(ckt->CKTrhs + here->B3SOIFDvbs0effNode) = here->B3SOIFDvbs0eff; *(ckt->CKTrhs + here->B3SOIFDvbseffNode) = here->B3SOIFDvbseff; *(ckt->CKTrhs + here->B3SOIFDxcNode) = here->B3SOIFDxc; *(ckt->CKTrhs + here->B3SOIFDcbbNode) = here->B3SOIFDcbb; *(ckt->CKTrhs + here->B3SOIFDcbdNode) = here->B3SOIFDcbd; *(ckt->CKTrhs + here->B3SOIFDcbgNode) = here->B3SOIFDcbg; *(ckt->CKTrhs + here->B3SOIFDqbfNode) = here->B3SOIFDqbf; *(ckt->CKTrhs + here->B3SOIFDqjsNode) = here->B3SOIFDqjs; *(ckt->CKTrhs + here->B3SOIFDqjdNode) = here->B3SOIFDqjd; /* clean up last */ *(ckt->CKTrhs + here->B3SOIFDgmNode) = Gm; *(ckt->CKTrhs + here->B3SOIFDgmbsNode) = Gmbs; *(ckt->CKTrhs + here->B3SOIFDgdsNode) = Gds; *(ckt->CKTrhs + here->B3SOIFDgmeNode) = Gme; *(ckt->CKTrhs + here->B3SOIFDqdNode) = qdrn; *(ckt->CKTrhs + here->B3SOIFDcbeNode) = Cbe; *(ckt->CKTrhs + here->B3SOIFDvbs0teffNode) = Vbs0teff; *(ckt->CKTrhs + here->B3SOIFDvthNode) = here->B3SOIFDvon; *(ckt->CKTrhs + here->B3SOIFDvgsteffNode) = Vgsteff; *(ckt->CKTrhs + here->B3SOIFDxcsatNode) = Xcsat; *(ckt->CKTrhs + here->B3SOIFDqaccNode) = -Qac0; *(ckt->CKTrhs + here->B3SOIFDqsub0Node) = Qsub0; *(ckt->CKTrhs + here->B3SOIFDqsubs1Node) = Qsubs1; *(ckt->CKTrhs + here->B3SOIFDqsubs2Node) = Qsubs2; *(ckt->CKTrhs + here->B3SOIFDvdscvNode) = VdsCV; *(ckt->CKTrhs + here->B3SOIFDvcscvNode) = VcsCV; *(ckt->CKTrhs + here->B3SOIFDqgNode) = qgate; *(ckt->CKTrhs + here->B3SOIFDqbNode) = qbody; *(ckt->CKTrhs + here->B3SOIFDqeNode) = qsub; *(ckt->CKTrhs + here->B3SOIFDdum1Node) = here->B3SOIFDdum1; *(ckt->CKTrhs + here->B3SOIFDdum2Node) = here->B3SOIFDdum2; *(ckt->CKTrhs + here->B3SOIFDdum3Node) = here->B3SOIFDdum3; *(ckt->CKTrhs + here->B3SOIFDdum4Node) = here->B3SOIFDdum4; *(ckt->CKTrhs + here->B3SOIFDdum5Node) = here->B3SOIFDdum5; /* end clean up last */ } /* * load y matrix */ (*(here->B3SOIFDEgPtr) += m * gcegb); (*(here->B3SOIFDEdpPtr) += m * gcedb); (*(here->B3SOIFDEspPtr) += m * gcesb); (*(here->B3SOIFDGePtr) += m * gcgeb); (*(here->B3SOIFDDPePtr) += m * (Gme + gddpe + gcdeb)); (*(here->B3SOIFDSPePtr) += m * (gsspe - Gme + gcseb)); (*(here->B3SOIFDEePtr) += m * gceeb); (*(here->B3SOIFDGgPtr) += m * (gcggb + ckt->CKTgmin)); (*(here->B3SOIFDGdpPtr) += m * (gcgdb - ckt->CKTgmin)); (*(here->B3SOIFDGspPtr) += m * gcgsb ); (*(here->B3SOIFDDPgPtr) += m * ((Gm + gcdgb) + gddpg - ckt->CKTgmin)); (*(here->B3SOIFDDPdpPtr) += m * ((here->B3SOIFDdrainConductance + here->B3SOIFDgds + gddpdp + RevSum + gcddb) + ckt->CKTgmin)); (*(here->B3SOIFDDPspPtr) -= m * (-gddpsp + here->B3SOIFDgds + FwdSum - gcdsb)); (*(here->B3SOIFDDPdPtr) -= m * here->B3SOIFDdrainConductance); (*(here->B3SOIFDSPgPtr) += m * (gcsgb - Gm + gsspg)); (*(here->B3SOIFDSPdpPtr) -= m * (here->B3SOIFDgds - gsspdp + RevSum - gcsdb)); (*(here->B3SOIFDSPspPtr) += m * (here->B3SOIFDsourceConductance + here->B3SOIFDgds + gsspsp + FwdSum + gcssb)); (*(here->B3SOIFDSPsPtr) -= m * here->B3SOIFDsourceConductance); (*(here->B3SOIFDDdPtr) += m * here->B3SOIFDdrainConductance); (*(here->B3SOIFDDdpPtr) -= m * here->B3SOIFDdrainConductance); (*(here->B3SOIFDSsPtr) += m * here->B3SOIFDsourceConductance); (*(here->B3SOIFDSspPtr) -= m * here->B3SOIFDsourceConductance); if (here->B3SOIFDbodyMod == 1) { (*(here->B3SOIFDBpPtr) -= m * gppp); (*(here->B3SOIFDPbPtr) += m * gppb); (*(here->B3SOIFDPpPtr) += m * gppp); (*(here->B3SOIFDPgPtr) += m * gppg); (*(here->B3SOIFDPdpPtr) += m * gppdp); (*(here->B3SOIFDPspPtr) += m * gppsp); (*(here->B3SOIFDPePtr) += m * gppe); } if (selfheat) { (*(here->B3SOIFDDPtempPtr) += m * (GmT + gddpT + gcdT)); (*(here->B3SOIFDSPtempPtr) += m * (-GmT + gsspT + gcsT)); (*(here->B3SOIFDBtempPtr) += m * (gbbT + gcbT)); (*(here->B3SOIFDEtempPtr) += m * gceT); (*(here->B3SOIFDGtempPtr) += m * gcgT); if (here->B3SOIFDbodyMod == 1) { (*(here->B3SOIFDPtempPtr) += m * gppT); } (*(here->B3SOIFDTemptempPtr) += m * (gTtt + 1/pParam->B3SOIFDrth + gcTt)); (*(here->B3SOIFDTempgPtr) += m * gTtg); (*(here->B3SOIFDTempbPtr) += m * gTtb); (*(here->B3SOIFDTempePtr) += m * gTte); (*(here->B3SOIFDTempdpPtr) += m * gTtdp); (*(here->B3SOIFDTempspPtr) += m * gTtsp); } if ((here->B3SOIFDdebugMod > 1) || (here->B3SOIFDdebugMod == -1)) { *(here->B3SOIFDVbsPtr) += m * 1; *(here->B3SOIFDIdsPtr) += m * 1; *(here->B3SOIFDIcPtr) += m * 1; *(here->B3SOIFDIbsPtr) += m * 1; *(here->B3SOIFDIbdPtr) += m * 1; *(here->B3SOIFDIiiPtr) += m * 1; *(here->B3SOIFDIgidlPtr) += m * 1; *(here->B3SOIFDItunPtr) += m * 1; *(here->B3SOIFDIbpPtr) += m * 1; *(here->B3SOIFDAbeffPtr) += m * 1; *(here->B3SOIFDVbs0effPtr) += m * 1; *(here->B3SOIFDVbseffPtr) += m * 1; *(here->B3SOIFDXcPtr) += m * 1; *(here->B3SOIFDCbgPtr) += m * 1; *(here->B3SOIFDCbbPtr) += m * 1; *(here->B3SOIFDCbdPtr) += m * 1; *(here->B3SOIFDqbPtr) += m * 1; *(here->B3SOIFDQbfPtr) += m * 1; *(here->B3SOIFDQjsPtr) += m * 1; *(here->B3SOIFDQjdPtr) += m * 1; /* clean up last */ *(here->B3SOIFDGmPtr) += m * 1; *(here->B3SOIFDGmbsPtr) += m * 1; *(here->B3SOIFDGdsPtr) += m * 1; *(here->B3SOIFDGmePtr) += m * 1; *(here->B3SOIFDVbs0teffPtr) += m * 1; *(here->B3SOIFDVgsteffPtr) += m * 1; *(here->B3SOIFDCbePtr) += m * 1; *(here->B3SOIFDVthPtr) += m * 1; *(here->B3SOIFDXcsatPtr) += m * 1; *(here->B3SOIFDVdscvPtr) += m * 1; *(here->B3SOIFDVcscvPtr) += m * 1; *(here->B3SOIFDQaccPtr) += m * 1; *(here->B3SOIFDQsub0Ptr) += m * 1; *(here->B3SOIFDQsubs1Ptr) += m * 1; *(here->B3SOIFDQsubs2Ptr) += m * 1; *(here->B3SOIFDqgPtr) += m * 1; *(here->B3SOIFDqdPtr) += m * 1; *(here->B3SOIFDqePtr) += m * 1; *(here->B3SOIFDDum1Ptr) += m * 1; *(here->B3SOIFDDum2Ptr) += m * 1; *(here->B3SOIFDDum3Ptr) += m * 1; *(here->B3SOIFDDum4Ptr) += m * 1; *(here->B3SOIFDDum5Ptr) += m * 1; /* end clean up last */ } line1000: ; /* Here NaN will be detected in any conductance or equivalent current. Note that nandetect is initialized within the "if" statements */ if ((nandetect = isnan (*(here->B3SOIFDGgPtr)))) { strcpy (nanmessage, "GgPtr"); } else if ((nandetect = isnan (*(here->B3SOIFDGdpPtr)))) { strcpy (nanmessage, "GdpPtr"); } else if ((nandetect = isnan (*(here->B3SOIFDGspPtr)))) { strcpy (nanmessage, "GspPtr"); } else if ((nandetect = isnan (*(here->B3SOIFDDPgPtr)))) { strcpy (nanmessage, "DPgPtr"); } else if ((nandetect = isnan (*(here->B3SOIFDDPdpPtr)))) { strcpy (nanmessage, "DPdpPtr"); } else if ((nandetect = isnan (*(here->B3SOIFDDPspPtr)))) { strcpy (nanmessage, "DPspPtr"); } else if ((nandetect = isnan (*(here->B3SOIFDSPgPtr)))) { strcpy (nanmessage, "SPgPtr"); } else if ((nandetect = isnan (*(here->B3SOIFDSPdpPtr)))) { strcpy (nanmessage, "SPdpPtr"); } else if ((nandetect = isnan (*(here->B3SOIFDSPspPtr)))) { strcpy (nanmessage, "SPspPtr"); } else if ((nandetect = isnan (*(here->B3SOIFDEePtr)))) { strcpy (nanmessage, "EePtr"); } /* At this point, nandetect = 0 if none of the conductances checked so far are NaN */ if (nandetect == 0) { if ((nandetect = isnan (*(here->B3SOIFDEgPtr)))) { strcpy (nanmessage, "EgPtr"); } else if ((nandetect = isnan (*(here->B3SOIFDEdpPtr)))) { strcpy (nanmessage, "EdpPtr"); } else if ((nandetect = isnan (*(here->B3SOIFDEspPtr)))) { strcpy (nanmessage, "EspPtr"); } else if ((nandetect = isnan (*(here->B3SOIFDGePtr)))) { strcpy (nanmessage, "GePtr"); } else if ((nandetect = isnan (*(here->B3SOIFDDPePtr)))) { strcpy (nanmessage, "DPePtr"); } else if ((nandetect = isnan (*(here->B3SOIFDSPePtr)))) { strcpy (nanmessage, "SPePtr"); } } /* Now check if self-heating caused NaN if nothing else has so far (check tempnode current also) */ if (selfheat && nandetect == 0) { if ((nandetect = isnan (*(here->B3SOIFDTemptempPtr)))) { strcpy (nanmessage, "TemptempPtr"); } else if ((nandetect = isnan (*(here->B3SOIFDTempgPtr)))) { strcpy (nanmessage, "TempgPtr"); } else if ((nandetect = isnan (*(here->B3SOIFDTempbPtr)))) { strcpy (nanmessage, "TempbPtr"); } else if ((nandetect = isnan (*(here->B3SOIFDTempePtr)))) { strcpy (nanmessage, "TempePtr"); } else if ((nandetect = isnan (*(here->B3SOIFDTempdpPtr)))) { strcpy (nanmessage, "TempdpPtr"); } else if ((nandetect = isnan (*(here->B3SOIFDTempspPtr)))) { strcpy (nanmessage, "TempspPtr"); } else if ((nandetect = isnan (*(here->B3SOIFDGtempPtr)))) { strcpy (nanmessage, "GtempPtr"); } else if ((nandetect = isnan (*(here->B3SOIFDDPtempPtr)))) { strcpy (nanmessage, "DPtempPtr"); } else if ((nandetect = isnan (*(here->B3SOIFDSPtempPtr)))) { strcpy (nanmessage, "SPtempPtr"); } else if ((nandetect = isnan (*(here->B3SOIFDEtempPtr)))) { strcpy (nanmessage, "EtempPtr"); } else if ((nandetect = isnan (*(here->B3SOIFDBtempPtr)))) { strcpy (nanmessage, "BtempPtr"); } else if ((nandetect = isnan (*(ckt->CKTrhs + here->B3SOIFDtempNode)))) { strcpy (nanmessage, "tempNode"); } } /* Lastly, check all equivalent currents (tempnode is checked above */ if (nandetect == 0) { if ((nandetect = isnan (*(ckt->CKTrhs + here->B3SOIFDgNode)))) { strcpy (nanmessage, "gNode"); } else if ((nandetect = isnan (*(ckt->CKTrhs + here->B3SOIFDbNode)))) { strcpy (nanmessage, "bNode"); } else if ((nandetect = isnan (*(ckt->CKTrhs + here->B3SOIFDdNodePrime)))) { strcpy (nanmessage, "dpNode"); } else if ((nandetect = isnan (*(ckt->CKTrhs + here->B3SOIFDsNodePrime)))) { strcpy (nanmessage, "spNode"); } else if ((nandetect = isnan (*(ckt->CKTrhs + here->B3SOIFDeNode)))) { strcpy (nanmessage, "eNode"); } } /* Now print error message if NaN detected. Note that error will only be printed once (the first time it is encountered) each time SPICE is run since nanfound is static variable */ if (nanfound == 0 && nandetect) { fprintf(stderr, "Alberto says: YOU TURKEY! %s is NaN for instance %s at time %g!\n", nanmessage, here->B3SOIFDname, ckt->CKTtime); nanfound = nandetect; fprintf(stderr, " The program exit!\n"); exit(-1); } if (here->B3SOIFDdebugMod > 2) { fprintf(fpdebug, "Ids = %.4e, Ic = %.4e, cqdrn = %.4e, gmin=%.3e\n", Ids, Ic, cqdrn, ckt->CKTgmin); fprintf(fpdebug, "Iii = %.4e, Idgidl = %.4e, Ibs = %.14e\n", Iii, Idgidl, Ibs); fprintf(fpdebug, "Ibd = %.4e, Ibp = %.4e\n", Ibd, Ibp); fprintf(fpdebug, "qbody = %.5e, qbf = %.5e, qbe = %.5e\n", qbody, Qbf, -(Qe1+Qe2)); fprintf(fpdebug, "qbs = %.5e, qbd = %.5e\n", qjs, qjd); fprintf(fpdebug, "qdrn = %.5e, qinv = %.5e\n", qdrn, qinv); /* I am trying to debug the convergence problems here by printing out the entire Jacobian and equivalent current matrix */ if (here->B3SOIFDdebugMod > 4) { fprintf(fpdebug, "Ibtot = %.6e;\t Cbtot = %.6e;\n", Ibs+Ibp+Ibd-Iii-Idgidl-Isgidl, cqbody); fprintf(fpdebug, "ceqg = %.6e;\t ceqb = %.6e;\t ceqdp = %.6e;\t ceqsp = %.6e;\n", *(ckt->CKTrhs + here->B3SOIFDgNode), *(ckt->CKTrhs + here->B3SOIFDbNode), *(ckt->CKTrhs + here->B3SOIFDdNodePrime), *(ckt->CKTrhs + here->B3SOIFDsNodePrime)); fprintf(fpdebug, "ceqe = %.6e;\t ceqp = %.6e;\t ceqth = %.6e;\n", *(ckt->CKTrhs + here->B3SOIFDeNode), *(ckt->CKTrhs + here->B3SOIFDpNode), *(ckt->CKTrhs + here->B3SOIFDtempNode)); fprintf(fpdebug, "Eg = %.5e;\t Edp = %.5e;\t Esp = %.5e;\t Eb = %.5e;\n", *(here->B3SOIFDEgPtr), *(here->B3SOIFDEdpPtr), *(here->B3SOIFDEspPtr), *(here->B3SOIFDEbPtr)); fprintf(fpdebug, "Ee = %.5e;\t Gg = %.5e;\t Gdp = %.5e;\t Gsp = %.5e;\n", *(here->B3SOIFDEePtr), *(here->B3SOIFDGgPtr), *(here->B3SOIFDGdpPtr), *(here->B3SOIFDGspPtr)); fprintf(fpdebug, "Gb = %.5e;\t Ge = %.5e;\t DPg = %.5e;\t DPdp = %.5e;\n", *(here->B3SOIFDGbPtr), *(here->B3SOIFDGePtr), *(here->B3SOIFDDPgPtr), *(here->B3SOIFDDPdpPtr)); fprintf(fpdebug, "DPsp = %.5e;\t DPb = %.5e;\t DPe = %.5e;\t\n", *(here->B3SOIFDDPspPtr), *(here->B3SOIFDDPbPtr), *(here->B3SOIFDDPePtr)); fprintf(fpdebug, "DPd = %.5e;\t SPg = %.5e;\t SPdp = %.5e;\t SPsp = %.5e;\n", *(here->B3SOIFDDPdPtr), *(here->B3SOIFDSPgPtr), *(here->B3SOIFDSPdpPtr), *(here->B3SOIFDSPspPtr)); fprintf(fpdebug, "SPb = %.5e;\t SPe = %.5e;\t SPs = %.5e;\n", *(here->B3SOIFDSPbPtr), *(here->B3SOIFDSPePtr), *(here->B3SOIFDSPsPtr)); fprintf(fpdebug, "Dd = %.5e;\t Ddp = %.5e;\t Ss = %.5e;\t Ssp = %.5e;\n", *(here->B3SOIFDDdPtr), *(here->B3SOIFDDdpPtr), *(here->B3SOIFDSsPtr), *(here->B3SOIFDSspPtr)); fprintf(fpdebug, "Bg = %.5e;\t Bdp = %.5e;\t Bsp = %.5e;\t Bb = %.5e;\n", *(here->B3SOIFDBgPtr), *(here->B3SOIFDBdpPtr), *(here->B3SOIFDBspPtr), *(here->B3SOIFDBbPtr)); fprintf(fpdebug, "Be = %.5e;\t Btot = %.5e;\t DPtot = %.5e;\n", *(here->B3SOIFDBePtr), *(here->B3SOIFDBgPtr) + *(here->B3SOIFDBdpPtr) + *(here->B3SOIFDBspPtr) + *(here->B3SOIFDBbPtr) + *(here->B3SOIFDBePtr), *(here->B3SOIFDDPePtr) + *(here->B3SOIFDDPgPtr) + *(here->B3SOIFDDPdpPtr) + *(here->B3SOIFDDPspPtr) + *(here->B3SOIFDDPbPtr)); if (selfheat) { fprintf (fpdebug, "DPtemp = %.5e;\t SPtemp = %.5e;\t Btemp = %.5e;\n", *(here->B3SOIFDDPtempPtr), *(here->B3SOIFDSPtempPtr), *(here->B3SOIFDBtempPtr)); fprintf (fpdebug, "Gtemp = %.5e;\t Etemp = %.5e;\n", *(here->B3SOIFDGtempPtr), *(here->B3SOIFDEtempPtr)); fprintf (fpdebug, "Tempg = %.5e;\t Tempdp = %.5e;\t Tempsp = %.5e;\t Tempb = %.5e;\n", *(here->B3SOIFDTempgPtr), *(here->B3SOIFDTempdpPtr), *(here->B3SOIFDTempspPtr), *(here->B3SOIFDTempbPtr)); fprintf (fpdebug, "Tempe = %.5e;\t TempT = %.5e;\t Temptot = %.5e;\n", *(here->B3SOIFDTempePtr), *(here->B3SOIFDTemptempPtr), *(here->B3SOIFDTempgPtr) + *(here->B3SOIFDTempdpPtr) + *(here->B3SOIFDTempspPtr)+ *(here->B3SOIFDTempbPtr) + *(here->B3SOIFDTempePtr)); } if (here->B3SOIFDbodyMod == 1) { fprintf(fpdebug, "ceqbodcon=%.5e;\t", ceqbodcon); fprintf(fpdebug, "Bp = %.5e;\t Pb = %.5e;\t Pp = %.5e;\n", -gppp, gppb, gppp); fprintf(fpdebug, "Pg=%.5e;\t Pdp=%.5e;\t Psp=%.5e;\t Pe=%.5e;\n", gppg, gppdp, gppsp, gppe); } } if (here->B3SOIFDdebugMod > 3) { fprintf(fpdebug, "Vth = %.4f, Vbs0eff = %.8f, Vdsat = %.4f\n", Vth, Vbs0eff, Vdsat); fprintf(fpdebug, "ueff = %g, Vgsteff = %.4f, Vdseff = %.4f\n", ueff, Vgsteff, Vdseff); fprintf(fpdebug, "Vthfd = %.4f, Vbs0mos = %.4f, Vbs0 = %.4f\n", Vthfd, Vbs0mos, Vbs0); fprintf(fpdebug, "Vbs0t = %.4f, Vbsdio = %.8f\n", Vbs0t, Vbsdio); } fclose(fpdebug); } here->B3SOIFDiterations++; /* increment the iteration counter */ } /* End of Mosfet Instance */ } /* End of Model Instance */ return(OK); }