From 6df3c202409984cd41fbcd2266249603825c6f84 Mon Sep 17 00:00:00 2001 From: pnenzi Date: Mon, 11 Aug 2003 20:13:47 +0000 Subject: [PATCH] Hisim model import. --- src/spicelib/devices/hisim/Makefile.am | 37 + src/spicelib/devices/hisim/hisim.h | 357 ++ src/spicelib/devices/hisim/hsm1.c | 166 + src/spicelib/devices/hisim/hsm1acld.c | 183 + src/spicelib/devices/hisim/hsm1ask.c | 231 ++ src/spicelib/devices/hisim/hsm1cvtest.c | 106 + src/spicelib/devices/hisim/hsm1def.h | 694 ++++ src/spicelib/devices/hisim/hsm1del.c | 41 + src/spicelib/devices/hisim/hsm1dest.c | 41 + src/spicelib/devices/hisim/hsm1eval1_0.c | 4572 +++++++++++++++++++++ src/spicelib/devices/hisim/hsm1eval1_1.c | 4758 ++++++++++++++++++++++ src/spicelib/devices/hisim/hsm1evalenv.h | 84 + src/spicelib/devices/hisim/hsm1ext.h | 37 + src/spicelib/devices/hisim/hsm1getic.c | 56 + src/spicelib/devices/hisim/hsm1init.c | 82 + src/spicelib/devices/hisim/hsm1init.h | 13 + src/spicelib/devices/hisim/hsm1itf.h | 13 + src/spicelib/devices/hisim/hsm1ld.c | 1036 +++++ src/spicelib/devices/hisim/hsm1mask.c | 379 ++ src/spicelib/devices/hisim/hsm1mdel.c | 48 + src/spicelib/devices/hisim/hsm1mpar.c | 495 +++ src/spicelib/devices/hisim/hsm1noi.c | 284 ++ src/spicelib/devices/hisim/hsm1par.c | 105 + src/spicelib/devices/hisim/hsm1pzld.c | 211 + src/spicelib/devices/hisim/hsm1set.c | 347 ++ src/spicelib/devices/hisim/hsm1temp.c | 35 + src/spicelib/devices/hisim/hsm1trunc.c | 53 + 27 files changed, 14464 insertions(+) create mode 100644 src/spicelib/devices/hisim/Makefile.am create mode 100644 src/spicelib/devices/hisim/hisim.h create mode 100644 src/spicelib/devices/hisim/hsm1.c create mode 100644 src/spicelib/devices/hisim/hsm1acld.c create mode 100644 src/spicelib/devices/hisim/hsm1ask.c create mode 100644 src/spicelib/devices/hisim/hsm1cvtest.c create mode 100644 src/spicelib/devices/hisim/hsm1def.h create mode 100644 src/spicelib/devices/hisim/hsm1del.c create mode 100644 src/spicelib/devices/hisim/hsm1dest.c create mode 100644 src/spicelib/devices/hisim/hsm1eval1_0.c create mode 100644 src/spicelib/devices/hisim/hsm1eval1_1.c create mode 100644 src/spicelib/devices/hisim/hsm1evalenv.h create mode 100644 src/spicelib/devices/hisim/hsm1ext.h create mode 100644 src/spicelib/devices/hisim/hsm1getic.c create mode 100644 src/spicelib/devices/hisim/hsm1init.c create mode 100644 src/spicelib/devices/hisim/hsm1init.h create mode 100644 src/spicelib/devices/hisim/hsm1itf.h create mode 100644 src/spicelib/devices/hisim/hsm1ld.c create mode 100644 src/spicelib/devices/hisim/hsm1mask.c create mode 100644 src/spicelib/devices/hisim/hsm1mdel.c create mode 100644 src/spicelib/devices/hisim/hsm1mpar.c create mode 100644 src/spicelib/devices/hisim/hsm1noi.c create mode 100644 src/spicelib/devices/hisim/hsm1par.c create mode 100644 src/spicelib/devices/hisim/hsm1pzld.c create mode 100644 src/spicelib/devices/hisim/hsm1set.c create mode 100644 src/spicelib/devices/hisim/hsm1temp.c create mode 100644 src/spicelib/devices/hisim/hsm1trunc.c diff --git a/src/spicelib/devices/hisim/Makefile.am b/src/spicelib/devices/hisim/Makefile.am new file mode 100644 index 000000000..654c7661a --- /dev/null +++ b/src/spicelib/devices/hisim/Makefile.am @@ -0,0 +1,37 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libhisim.a + +libhisim_a_SOURCES = \ + hsm1.c \ + hsm1acld.c \ + hsm1ask.c \ + hsm1cvtest.c \ + hsm1del.c \ + hsm1dest.c \ + hsm1eval1_0.c \ + hsm1eval1_1.c \ + hsm1getic.c \ + hsm1ld.c \ + hsm1mask.c \ + hsm1mdel.c \ + hsm1mpar.c \ + hsm1noi.c \ + hsm1par.c \ + hsm1pzld.c \ + hsm1set.c \ + hsm1temp.c \ + hsm1trunc.c \ + hisim1.h \ + hsm1evalenv.h \ + hsm1def.h \ + hsm1ext.h \ + hsm1init.c \ + hsm1init.h \ + hsm1itf.h + + + +INCLUDES = -I$(top_srcdir)/src/include + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/hisim/hisim.h b/src/spicelib/devices/hisim/hisim.h new file mode 100644 index 000000000..d22417c8c --- /dev/null +++ b/src/spicelib/devices/hisim/hisim.h @@ -0,0 +1,357 @@ +/*********************************************************************** + HiSIM v1.1.0 + File: hisim.h of HiSIM v1.1.0 + + Copyright (C) 2002 STARC + + June 30, 2002: developed by Hiroshima University and STARC + June 30, 2002: posted by Keiichi MORIKAWA, STARC Physical Design Group +***********************************************************************/ + +/* + * Modified by Paolo Nenzi 2002 + * ngspice integration + */ + +#ifndef _HiSIM_H +#define _HiSIM_H + +/*#define HiSIM_TIME 0*/ + +/* return value */ +#ifndef OK +#define HiSIM_OK 0 +#define HiSIM_ERROR 1 +#else +#define HiSIM_OK OK +#define HiSIM_ERROR E_PANIC +#endif + +/* MOS type */ +#ifndef NMOS +#define NMOS 1 +#define PMOS -1 +#endif + +/* device working mode */ +#ifndef CMI_NORMAL_MODE +#define HiSIM_NORMAL_MODE 1 +#define HiSIM_REVERSE_MODE -1 +#else +#define HiSIM_NORMAL_MODE CMI_NORMAL_MODE +#define HiSIM_REVERSE_MODE CMI_REVERSE_MODE +#endif + +/* others */ +#ifndef NULL +#define NULL 0 +#endif + +#define HiSIM_FALSE 0 +#define HiSIM_TRUE 1 + + +/*-------------------------------------------------------------------* +* Structure for inputs of hisim. +*----------------*/ +typedef struct sHiSIM_input { + + /* Flags that must be set in parent routines. */ + int type ; /* MOS type (1:NMOS, -1:PMOS) */ + int mode ; /* MOS mode (1:normal, -1:reverse) */ + int qflag ; /* qflag (toggle for charge calc. Unused!) */ + int has_prv ; /* 1 if previous values are held. */ + + /* Bias conditions */ + double vbs ; /* Vbs [V] */ + double vds ; /* Vds [V] */ + double vgs ; /* Vgs [V] */ + + /* frequency [Hz] */ + double freq ; + + /* Control options that can be set in a model parameter set. */ + int info ; /* information level (for debug, etc.) */ + int corsrd ; /* solve equations accounting Rs and Rd. */ + int coiprv ; /* use ids_prv as initial guess of Ids */ + int copprv ; /* use ps{0/l}_prv as initial guess of Ps{0/l} */ + int cocgso ; /* calculate cgso */ + int cocgdo ; /* calculate cgdo */ + int cocgbo ; /* calculate cgbo */ + int coadov ; /* add overlap to intrisic */ + int coxx08 ; /* spare */ + int coxx09 ; /* spare */ + int coisub ; /* calculate isub */ + int coiigs ; /* calculate igs */ + int cogidl ; /* calculate ilg */ + int coovlp ; /* calculate overlap charge */ + int conois ; /* calculate 1/f noise */ + int coisti ; /* calculate STI */ + + /* Previous values that may be used as initial guesses */ + /* - derivatives are ones w.r.t. internal biases. */ + double vbsc_prv ; + double vdsc_prv ; + double vgsc_prv ; + double ps0_prv ; + double ps0_dvbs_prv ; + double ps0_dvds_prv ; + double ps0_dvgs_prv ; + double pds_prv ; + double pds_dvbs_prv ; + double pds_dvds_prv ; + double pds_dvgs_prv ; + double ids_prv ; + double ids_dvbs_prv ; + double ids_dvds_prv ; + double ids_dvgs_prv ; + + /* for noise calc. */ + double nfc ; + + /* Device instances */ + double xl ; /* channel length [m] (L=xl-xld) */ + double xw ; /* channel width [m] (W=xw-xwd) */ + double ad ; /* area of drain diffusion [m^2] */ + double as ; /* area of source diffusion [m^2] */ + double pd ; /* perimeter of drain junction [m] */ + double ps ; /* perimeter of source junction [m] */ + double nrd ; /* equivalent num of squares of drain [-] (unused) */ + double nrs ; /* equivalent num of squares of source [-] (unused) */ + double temp ; /* lattice temperature [K] */ + + /* Model parameters */ + double vmax ; /* saturation velocity [cm/s] */ + double bgtmp1 ; /* first order temp. coeff. for band gap [V/K] */ + double bgtmp2 ; /* second order temp. coeff. for band gap [V/K^2] */ + double tox ; /* oxide thickness [m] */ + double xld ; /* lateral diffusion of S/D under the gate [m] */ + double xwd ; /* lateral diffusion along the width dir. [m] */ + double xj ; /* HiSIM1.0 [m] */ + double xqy ; /* HiSIM1.1 [m] */ + /*--*/ + double rd ; /* drain contact resistance [ohm m] */ + double rs ; /* source contact resistance [ohm m] */ +/**/ + double vfbc ; /* constant part of Vfb [V] */ + double nsubc ; /* constant part of Nsub [1/cm^3] */ + double parl1 ; /* factor for L dependency of dVthSC [-] */ + double parl2 ; /* under diffusion [m] */ + double lp ; /* length of pocket potential [m] */ + double nsubp ; /* [1/cm^3] */ + double scp1 ; /* parameter for pocket [1/V] */ + double scp2 ; /* parameter for pocket [1/V^2] */ + double scp3 ; /* parameter for pocket [m/V^2] */ + double sc1 ; /* parameter for SCE [1/V] */ + double sc2 ; /* parameter for SCE [1/V^2] */ + double sc3 ; /* parameter for SCE [m/V^2] */ + double pgd1 ; /* parameter for gate-poly depletion [V] */ + double pgd2 ; /* parameter for gate-poly depletion [V] */ + double pgd3 ; /* parameter for gate-poly depletion [-] */ +/**/ + double ndep ; /* coeff. of Qbm for Eeff [-] */ + double ninv ; /* coeff. of Qnm for Eeff [-] */ + double ninvd ; /* parameter for universal mobility [1/V] */ + double muecb0 ; /* const. part of coulomb scattering [cm^2/Vs] */ + double muecb1 ; /* coeff. for coulomb scattering [cm^2/Vs] */ + double mueph0 ; /* power of Eeff for phonon scattering [-] */ + double mueph1 ; + double mueph2 ; + double w0 ; + double muesr0 ; /* power of Eeff for S.R. scattering [-] */ + double muesr1 ; /* coeff. for S.R. scattering [-] */ + double muetmp ; /* parameter for mobility [-] */ + double bb ; /* empirical mobility model coefficient [-] */ + double vds0 ; /* Vds0 used for low field mobility [V] */ + double bc0 ; /* coeff. for BC */ + double bc1 ; /* power of L for BC */ +/**/ + double sub1 ; /* parameter for Isub [1/V] */ + double sub2 ; /* parameter for Isub [V] */ + double sub3 ; /* parameter for Isub [-] */ +/**/ + double wvthsc ; /* parameter for STI [-] HiSIM1.1 */ + double nsti ; /* parameter for STI [1/cm^3] HiSIM1.1 */ + double wsti ; /* parameter for STI [m] HiSIM1.1 */ +/**/ + double cgso ; /* G-S overlap capacitance per unit W [F/m] */ + double cgdo ; /* G-D overlap capacitance per unit W [F/m] */ + double cgbo ; /* G-B overlap capacitance per unit L [F/m] */ +/**/ + double tpoly ; /* hight of poly gate [m] */ +/**/ + double js0 ; /* Saturation current density [A/m^2] */ + double js0sw ; /* Side wall saturation current density [A/m] */ + double nj ; /* Emission coefficient */ + double njsw ; /* Emission coefficient (sidewall) */ + double xti ; /* Junction current temparature exponent coefficient */ + double cj ; /* Bottom junction capacitance per unit area + at zero bias [F/m^2]*/ + double cjsw ; /* Source/drain sidewall junction capacitance grading + coefficient per unit length at zero bias [F/m] */ + double cjswg ; /* Source/drain gate sidewall junction capacitance + per unit length at zero bias [F/m] */ + double mj ; /* Bottom junction capacitance grading coefficient */ + double mjsw ; /* Source/drain sidewall junction capacitance grading + coefficient */ + double mjswg ; /* Source/drain gate sidewall junction capacitance grading + coefficient */ + double pb ; /* Bottom junction build-in potential [V] */ + double pbsw ; /* Source/drain sidewall junction build-in potential [V] */ + double pbswg ; /* Source/drain gate sidewall junction build-in potential [V] */ + double xpolyd ; /* parameter for Cov [m] */ +/**/ + double clm1 ; /* parameter for CLM [-] */ + double clm2 ; /* parameter for CLM [1/m] */ + double clm3 ; /* parameter for CLM [-] */ +/**/ + double rpock1 ; /* parameter for Ids [V] */ + double rpock2 ; /* parameter for Ids [V^2 sqrt(m)/A] */ + double rpocp1 ; /* parameter for Ids [-] HiSIM1.1 */ + double rpocp2 ; /* parameter for Ids [-] HiSIM1.1 */ + +/**/ + double vover ; /* parameter for overshoot [m^{voverp}]*/ + double voverp ; /* parameter for overshoot [-] */ + double wfc ; /* parameter for narrow channel effect [m*F/(cm^2)]*/ + double qme1 ; /* parameter for quantum effect [mV]*/ + double qme2 ; /* parameter for quantum effect [V]*/ + double qme3 ; /* parameter for quantum effect [m]*/ + double gidl1 ; /* parameter for GIDL [?] */ + double gidl2 ; /* parameter for GIDL [?] */ + double gidl3 ; /* parameter for GIDL [?] */ + double gleak1 ; /* parameter for gate current [?] */ + double gleak2 ; /* parameter for gate current [?] */ + double gleak3 ; /* parameter for gate current [?] */ +/**/ + double vzadd0 ; /* Vzadd at Vds=0 [V] */ + double pzadd0 ; /* Pzadd at Vds=0 [V] */ + + double nftrp ; + double nfalp ; + double cit ; + + double gmin ; /* gmin = minimam conductance of SPICE3 K.M. */ +} HiSIM_input ; + +/*-------------------------------------------------------------------* +* structure for outputs of hisim. +*----------------*/ +typedef struct sHiSIM_output { + double ids ; /* channel current [A] */ + double gds ; /* channel conductance (dIds/dVds) [S] */ + double gm ; /* trans conductance (dIds/dVgs) [S] */ + double gmbs ; /* substrate trans conductance (dIds/dVbs) [S] */ +/**/ + double gd ; /* parasitic drain conductance [S] */ + double gs ; /* parasitic source conductance [S] */ +/**/ + double cgso ; /* G-S overlap capacitance [F] */ + double cgdo ; /* G-D overlap capacitance [F] */ + double cgbo ; /* G-B overlap capacitance [F] */ +/**/ + double von ; /* Vth [V] */ + double vdsat ; /* saturation voltage [V] */ +/**/ + double capgs ; /* Meyer's gate capacitance (dQg/dVgs+cgso) [S] */ + double capgd ; /* Meyer's gate capacitance (dQg/dVgs+cgso) [S] */ + double capgb ; /* Meyer's gate capacitance (dQg/dVgs+cgso) [S] */ +/**/ + double ibs ; /* substrate source leakage current [A] */ + double ibd ; /* substrate drain leakage current [A] */ + double gbs ; /* substrate source conductance [S] */ + double gbd ; /* substrate drain conductance [S] */ +/**/ + double capbs ; /* substrate source capacitance [F] */ + double capbd ; /* substrate drain capacitance [F] */ + double qbs ; /* substrate source charge [C] */ + double qbd ; /* substrate drain charge [C] */ +/**/ + double isub ; /* substrate impact ionization current [A] */ + double gbgs ; /* substrate trans conductance (dIsub/dVgs) [S] */ + double gbds ; /* substrate trans conductance (dIsub/dVds) [S] */ + double gbbs ; /* substrate trans conductance (dIsub/dVbs) [S] */ +/**/ + double qg ; /* intrinsic gate charge [C] */ + double qd ; /* intrinsic drain charge [C] */ + double qs ; /* intrinsic source charge [C] */ +/**/ + double cggb ; /* intrinsic gate capacitance w.r.t. gate [F] */ + double cgdb ; /* intrinsic gate capacitance w.r.t. drain [F] */ + double cgsb ; /* intrinsic gate capacitance w.r.t. source [F] */ + double cbgb ; /* intrinsic bulk capacitance w.r.t. gate [F] */ + double cbdb ; /* intrinsic bulk capacitance w.r.t. drain [F] */ + double cbsb ; /* intrinsic bulk capacitance w.r.t. source [F] */ + double cdgb ; /* intrinsic drain capacitance w.r.t. gate [F] */ + double cddb ; /* intrinsic drain capacitance w.r.t. drain [F] */ + double cdsb ; /* intrinsic drain capacitance w.r.t. source [F] */ +/**/ + double igs ; /* gate current due to tunneling [A] */ + double gggs ; /* trans conductance (dIgs/dVgs) [S] */ + double ggds ; /* trans conductance (dIgs/dVds) [S] */ + double ggbs ; /* trans conductance (dIgs/dVbs) [S] */ +/**/ + double ilg ; /* gate induced drain leakage [A] */ + double glgs ; /* trans conductance (dIlg/dVgs) [S] */ + double glds ; /* trans conductance (dIlg/dVds) [S] */ + double glbs ; /* trans conductance (dIlg/dVbs) [S] */ +/**/ + double nois_idsfl ; + double nois_ird ; + double nois_irs ; + double nois_idsth ; +/**/ + /* Outputs that may be used as initial guesses in the next calling */ + double vbsc ; + double vdsc ; + double vgsc ; + double ps0 ; + double ps0_dvbs ; + double ps0_dvds ; + double ps0_dvgs ; + double pds ; + double pds_dvbs ; + double pds_dvds ; + double pds_dvgs ; + double ids_dvbs ; + double ids_dvds ; + double ids_dvgs ; + + /* for noise calc. */ + double nf ; + + /* mobility added by K.M. */ + double mu ; +} HiSIM_output ; + +/*-------------------------------------------------------------------* +* structure for messengers to/from hisim. +*----------------*/ +typedef struct sHiSIM_messenger { + int ims[20] ; + double dms[50] ; + /* Control options for alpha versions */ + int opt_ntn ; + int opt_psl ; + int opt_rsc ; + int opt_sce ; + int opt_mbl ; + int opt_dp0 ; + int opt_inv ; + int opt_bas ; + int opt_01 ; + int opt_02 ; + int opt_03 ; + int opt_04 ; + int opt_05 ; +} HiSIM_messenger ; +/* note: ----------------------------------- +* if HiSIM_TEST is defined. +* ims[ 1 ] :(in) =1: output physical capacitances instead of ones +* referenced to bulk. +* ims[11-12] , dms[11-39] :(ot) additional outputs. +* if CMI_OK is defined. +* dms[ 1 ] :(in) timepoint. +-------------------------------------------*/ + +#endif /* _HiSIM_H */ diff --git a/src/spicelib/devices/hisim/hsm1.c b/src/spicelib/devices/hisim/hsm1.c new file mode 100644 index 000000000..4687acf70 --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1.c @@ -0,0 +1,166 @@ +/*********************************************************************** + HiSIM v1.1.0 + File: hsm1.c of HiSIM v1.1.0 + + Copyright (C) 2002 STARC + + June 30, 2002: developed by Hiroshima University and STARC + June 30, 2002: posted by Keiichi MORIKAWA, STARC Physical Design Group +***********************************************************************/ + +/* + * Modified by Paolo Nenzi 2002 + * ngspice integration + */ + +#include "ngspice.h" +#include "devdefs.h" +#include "hsm1def.h" +#include "suffix.h" + +IFparm HSM1pTable[] = { /* parameters */ + IOP( "l", HSM1_L, IF_REAL , "Length"), + IOP( "w", HSM1_W, IF_REAL , "Width"), + IOP( "m", HSM1_M, IF_REAL , "Parallel multiplier"), + IOP( "ad", HSM1_AD, IF_REAL , "Drain area"), + IOP( "as", HSM1_AS, IF_REAL , "Source area"), + IOP( "pd", HSM1_PD, IF_REAL , "Drain perimeter"), + IOP( "ps", HSM1_PS, IF_REAL , "Source perimeter"), + IOP( "nrd", HSM1_NRD, IF_REAL , "Number of squares in drain"), + IOP( "nrs", HSM1_NRS, IF_REAL , "Number of squares in source"), + IOP( "temp", HSM1_TEMP, IF_REAL , "Lattice temperature"), + IOP( "dtemp", HSM1_DTEMP,IF_REAL , ""), + IOP( "off", HSM1_OFF, IF_FLAG , "Device is initially off"), + IP ( "ic", HSM1_IC, IF_REALVEC , "Vector of DS,GS,BS initial voltages") +}; + +IFparm HSM1mPTable[] = { /* model parameters */ + IP("nmos", HSM1_MOD_NMOS, IF_FLAG, ""), + IP("pmos", HSM1_MOD_PMOS, IF_FLAG, ""), + IOP("level", HSM1_MOD_LEVEL, IF_INTEGER, ""), + IOP("info", HSM1_MOD_INFO, IF_INTEGER, "information level (for debug, etc.)"), + IOP("noise", HSM1_MOD_NOISE, IF_INTEGER, "noise model selector"), + IOP("version", HSM1_MOD_VERSION, IF_INTEGER, "model version 100 or 110"), + IOP("show", HSM1_MOD_SHOW, IF_INTEGER, "show physical value"), + IOP("corsrd", HSM1_MOD_CORSRD, IF_INTEGER, "solve equations accounting Rs and Rd."), + IOP("coiprv", HSM1_MOD_COIPRV, IF_INTEGER, "use ids_prv as initial guess of Ids"), + IOP("copprv", HSM1_MOD_COPPRV, IF_INTEGER, "use ps{0/l}_prv as initial guess of Ps{0/l}"), + IOP("cocgso", HSM1_MOD_COCGSO, IF_INTEGER, "calculate cgso"), + IOP("cocgdo", HSM1_MOD_COCGDO, IF_INTEGER, "calculate cgdo"), + IOP("cocgbo", HSM1_MOD_COCGBO, IF_INTEGER, "calculate cgbo"), + IOP("coadov", HSM1_MOD_COADOV, IF_INTEGER, "add overlap to intrisic"), + IOP("coxx08", HSM1_MOD_COXX08, IF_INTEGER, "spare"), + IOP("coxx09", HSM1_MOD_COXX09, IF_INTEGER, "spare"), + IOP("coisub", HSM1_MOD_COISUB, IF_INTEGER, "calculate isub"), + IOP("coiigs", HSM1_MOD_COIIGS, IF_INTEGER, "calculate igs"), + IOP("cogidl", HSM1_MOD_COGIDL, IF_INTEGER, "calculate ilg"), + IOP("coovlp", HSM1_MOD_COOVLP, IF_INTEGER, "calculate overlap charge"), + IOP("conois", HSM1_MOD_CONOIS, IF_INTEGER, "calculate 1/f noise"), + IOP("coisti", HSM1_MOD_COISTI, IF_INTEGER, "calculate STI HiSIM1.1"), + IOP("vmax", HSM1_MOD_VMAX, IF_REAL, "saturation velocity [cm/s"), + IOP("bgtmp1", HSM1_MOD_BGTMP1, IF_REAL, "first order temp. coeff. for band gap [V/K]"), + IOP("bgtmp2", HSM1_MOD_BGTMP2, IF_REAL, "second order temp. coeff. for band gap [V/K^2]"), + IOP("tox", HSM1_MOD_TOX, IF_REAL, "oxide thickness [m]"), + IOP("dl", HSM1_MOD_DL, IF_REAL, "lateral diffusion of S/D under the gate [m]"), + IOP("dw", HSM1_MOD_DW, IF_REAL, "lateral diffusion along the width dir. [m]"), + IOP("xld", HSM1_MOD_DL, IF_REAL, "lateral diffusion of S/D under the gate [m]"), + IOP("xwd", HSM1_MOD_DW, IF_REAL, "lateral diffusion along the width dir. [m]"), + IOP("xj", HSM1_MOD_XJ, IF_REAL, "HiSIM1.0 [m]"), + IOP("xqy", HSM1_MOD_XQY, IF_REAL, "HiSIM1.1 [m]"), + IOP("rs", HSM1_MOD_RS, IF_REAL, "source contact resistance [ohm m]"), + IOP("rd", HSM1_MOD_RD, IF_REAL, "drain contact resistance [ohm m]"), + IOP("vfbc", HSM1_MOD_VFBC, IF_REAL, "constant part of Vfb [V]"), + IOP("nsubc", HSM1_MOD_NSUBC, IF_REAL, "constant part of Nsub [1/cm^3]"), + IOP("parl1", HSM1_MOD_PARL1, IF_REAL, "factor for L dependency of dVthSC [-]"), + IOP("parl2", HSM1_MOD_PARL2, IF_REAL, "under diffusion [m]"), + IOP("lp", HSM1_MOD_LP, IF_REAL, "length of pocket potential [m]"), + IOP("nsubp", HSM1_MOD_NSUBP, IF_REAL, "[1/cm^3]"), + IOP("scp1", HSM1_MOD_SCP1, IF_REAL, "parameter for pocket [1/V]"), + IOP("scp2", HSM1_MOD_SCP2, IF_REAL, "parameter for pocket [1/V^2]"), + IOP("scp3", HSM1_MOD_SCP3, IF_REAL, "parameter for pocket [m/V^2]"), + IOP("sc1", HSM1_MOD_SC1, IF_REAL, "parameter for SCE [1/V]"), + IOP("sc2", HSM1_MOD_SC2, IF_REAL, "parameter for SCE [1/V^2]"), + IOP("sc3", HSM1_MOD_SC3, IF_REAL, "parameter for SCE [m/V^2]"), + IOP("pgd1", HSM1_MOD_PGD1, IF_REAL, "parameter for gate-poly depletion [V]"), + IOP("pgd2", HSM1_MOD_PGD2, IF_REAL, "parameter for gate-poly depletion [V]"), + IOP("pgd3", HSM1_MOD_PGD3, IF_REAL, "parameter for gate-poly depletion [-]"), + IOP("ndep", HSM1_MOD_NDEP, IF_REAL, "coeff. of Qbm for Eeff [-]"), + IOP("ninv", HSM1_MOD_NINV, IF_REAL, "coeff. of Qnm for Eeff [-]"), + IOP("ninvd", HSM1_MOD_NINVD, IF_REAL, "parameter for universal mobility [1/V]"), + IOP("muecb0", HSM1_MOD_MUECB0, IF_REAL, "const. part of coulomb scattering [cm^2/Vs]"), + IOP("muecb1", HSM1_MOD_MUECB1, IF_REAL, "coeff. for coulomb scattering [cm^2/Vs]"), + IOP("mueph0", HSM1_MOD_MUEPH0, IF_REAL, "power of Eeff for phonon scattering [-]"), + IOP("mueph1", HSM1_MOD_MUEPH1, IF_REAL, ""), + IOP("mueph2", HSM1_MOD_MUEPH2, IF_REAL, ""), + IOP("w0", HSM1_MOD_W0, IF_REAL, ""), + IOP("muesr0", HSM1_MOD_MUESR0, IF_REAL, "power of Eeff for S.R. scattering [-]"), + IOP("muesr1", HSM1_MOD_MUESR1, IF_REAL, "coeff. for S.R. scattering [-]"), + IOP("muetmp", HSM1_MOD_MUETMP, IF_REAL, "parameter for mobility [-]"), + IOP("bb", HSM1_MOD_BB, IF_REAL, "empirical mobility model coefficient [-]"), + IOP("vds0", HSM1_MOD_VDS0, IF_REAL, "Vds0 used for low field mobility [V]"), + IOP("sub1", HSM1_MOD_SUB1, IF_REAL, "parameter for Isub [1/V]"), + IOP("sub2", HSM1_MOD_SUB2, IF_REAL, "parameter for Isub [V]"), + IOP("sub3", HSM1_MOD_SUB3, IF_REAL, "parameter for Isub [-]"), + IOP("wvthsc", HSM1_MOD_WVTHSC, IF_REAL, "parameter for STI [-] HiSIM1.1"), + IOP("nsti", HSM1_MOD_NSTI, IF_REAL, "parameter for STI [1/cm^3] HiSIM1.1"), + IOP("wsti", HSM1_MOD_WSTI, IF_REAL, "parameter for STI [m] HiSIM1.1"), + IOP("cgso", HSM1_MOD_CGSO, IF_REAL, "G-S overlap capacitance per unit W [F/m]"), + IOP("cgdo", HSM1_MOD_CGDO, IF_REAL, "G-D overlap capacitance per unit W [F/m]"), + IOP("cgbo", HSM1_MOD_CGBO, IF_REAL, "G-B overlap capacitance per unit L [F/m]"), + IOP("tpoly", HSM1_MOD_TPOLY, IF_REAL, "hight of poly gate [m]"), + IOP("js0", HSM1_MOD_JS0, IF_REAL, "Saturation current density [A/m^2]"), + IOP("js0sw", HSM1_MOD_JS0SW, IF_REAL, "Side wall saturation current density [A/m]"), + IOP("nj", HSM1_MOD_NJ, IF_REAL, "Emission coefficient"), + IOP("njsw", HSM1_MOD_NJSW, IF_REAL, "Emission coefficient (sidewall)"), + IOP("xti", HSM1_MOD_XTI, IF_REAL, "Junction current temparature exponent coefficient"), + IOP("cj", HSM1_MOD_CJ, IF_REAL, "Bottom junction capacitance per unit area at zero bias [F/m^2]"), + IOP("cjsw", HSM1_MOD_CJSW, IF_REAL, "Source/drain sidewall junction capacitance grading coefficient per unit length at zero bias [F/m]"), + IOP("cjswg", HSM1_MOD_CJSWG, IF_REAL, "Source/drain gate sidewall junction capacitance per unit length at zero bias [F/m]"), + IOP("mj", HSM1_MOD_MJ, IF_REAL, "Bottom junction capacitance grading coefficient"), + IOP("mjsw", HSM1_MOD_MJSW, IF_REAL, "Source/drain sidewall junction capacitance grading coefficient"), + IOP("mjswg", HSM1_MOD_MJSWG, IF_REAL, "Source/drain gate sidewall junction capacitance grading coefficient"), + IOP("pb", HSM1_MOD_PB, IF_REAL, "Bottom junction build-in potential [V]"), + IOP("pbsw", HSM1_MOD_PBSW, IF_REAL, "Source/drain sidewall junction build-in potential [V]"), + IOP("pbswg", HSM1_MOD_PBSWG, IF_REAL, "Source/drain gate sidewall junction build-in potential [V]"), + IOP("xpolyd", HSM1_MOD_XPOLYD, IF_REAL, "parameter for Cov [m]"), + IOP("clm1", HSM1_MOD_CLM1, IF_REAL, "parameter for CLM [-]"), + IOP("clm2", HSM1_MOD_CLM2, IF_REAL, "parameter for CLM [1/m]"), + IOP("clm3", HSM1_MOD_CLM3, IF_REAL, "parameter for CLM [-]"), + IOP("rpock1", HSM1_MOD_RPOCK1, IF_REAL, "parameter for Ids [V^2 sqrt(m)/A]"), + IOP("rpock2", HSM1_MOD_RPOCK2, IF_REAL, "parameter for Ids [V]"), + IOP("rpocp1", HSM1_MOD_RPOCP1, IF_REAL, "parameter for Ids [-] HiSIM1.1"), + IOP("rpocp2", HSM1_MOD_RPOCP2, IF_REAL, "parameter for Ids [-] HiSIM1.1"), + IOP("vover", HSM1_MOD_VOVER, IF_REAL, "parameter for overshoot [m^{voverp}]"), + IOP("voverp", HSM1_MOD_VOVERP, IF_REAL, "parameter for overshoot [-]"), + IOP("wfc", HSM1_MOD_WFC, IF_REAL, "parameter for narrow channel effect [m*F/(cm^2)]"), + IOP("qme1", HSM1_MOD_QME1, IF_REAL, "parameter for quantum effect [mV]"), + IOP("qme2", HSM1_MOD_QME2, IF_REAL, "parameter for quantum effect [V]"), + IOP("qme3", HSM1_MOD_QME3, IF_REAL, "parameter for quantum effect [m]"), + IOP("gidl1", HSM1_MOD_GIDL1, IF_REAL, "parameter for GIDL [?]"), + IOP("gidl2", HSM1_MOD_GIDL2, IF_REAL, "parameter for GIDL [?]"), + IOP("gidl3", HSM1_MOD_GIDL3, IF_REAL, "parameter for GIDL [?]"), + IOP("gleak1", HSM1_MOD_GLEAK1, IF_REAL, "parameter for gate current [?]"), + IOP("gleak2", HSM1_MOD_GLEAK2, IF_REAL, "parameter for gate current [?]"), + IOP("gleak3", HSM1_MOD_GLEAK3, IF_REAL, "parameter for gate current [?]"), + IOP("vzadd0", HSM1_MOD_VZADD0, IF_REAL, "Vzadd at Vds=0 [V]"), + IOP("pzadd0", HSM1_MOD_PZADD0, IF_REAL, "Pzadd at Vds=0 [V]"), + IOP("nftrp", HSM1_MOD_NFTRP, IF_REAL, ""), + IOP("nfalp", HSM1_MOD_NFALP, IF_REAL, ""), + IOP("cit", HSM1_MOD_CIT, IF_REAL, ""), + IOP( "ef", HSM1_MOD_EF, IF_REAL, "flicker noise frequency exponent"), + IOP( "af", HSM1_MOD_AF, IF_REAL, "flicker noise exponent"), + IOP( "kf", HSM1_MOD_KF, IF_REAL, "flicker noise coefficient") +}; + +char *HSM1names[] = { + "Drain", + "Gate", + "Source", + "Bulk" +}; + +int HSM1nSize = NUMELEMS(HSM1names); +int HSM1pTSize = NUMELEMS(HSM1pTable); +int HSM1mPTSize = NUMELEMS(HSM1mPTable); +int HSM1iSize = sizeof(HSM1instance); +int HSM1mSize = sizeof(HSM1model); diff --git a/src/spicelib/devices/hisim/hsm1acld.c b/src/spicelib/devices/hisim/hsm1acld.c new file mode 100644 index 000000000..97aa95eb4 --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1acld.c @@ -0,0 +1,183 @@ +/*********************************************************************** + HiSIM v1.1.0 + File: hsm1acld.c of HiSIM v1.1.0 + + Copyright (C) 2002 STARC + + June 30, 2002: developed by Hiroshima University and STARC + June 30, 2002: posted by Keiichi MORIKAWA, STARC Physical Design Group +***********************************************************************/ + +/* + * Modified by Paolo Nenzi 2002 + * ngspice integration + */ + +#include "ngspice.h" +#include "cktdefs.h" +#include "hsm1def.h" +#include "sperror.h" +#include "suffix.h" + + +int HSM1acLoad(GENmodel *inModel, CKTcircuit *ckt) +{ + HSM1model *model = (HSM1model*)inModel; + HSM1instance *here; + double xcggb, xcgdb, xcgsb, xcbgb, xcbdb, xcbsb, xcddb, xcssb, xcdgb; + double gdpr, gspr, gds, gbd, gbs, capbd, capbs, xcsgb, xcdsb, xcsdb; + double cggb, cgdb, cgsb, cbgb, cbdb, cbsb, cddb, cdgb, cdsb, omega; + double cgso, cgdo, cgbo, FwdSum, RevSum, gm, gmbs; + double gbspsp, gbbdp, gbbsp, gbspg, gbspb; + double gbspdp, gbdpdp, gbdpg, gbdpb, gbdpsp; + + double m; + + omega = ckt->CKTomega; + for ( ; model != NULL; model = model->HSM1nextModel ) { + for ( here = model->HSM1instances; here!= NULL; + here = here->HSM1nextInstance ) { + + if (here->HSM1owner != ARCHme) + continue; + + if ( here->HSM1_mode >= 0 ) { + gm = here->HSM1_gm; + gmbs = here->HSM1_gmbs; + FwdSum = gm + gmbs; + RevSum = 0.0; + + gbbdp = -here->HSM1_gbds; + gbbsp = here->HSM1_gbds + here->HSM1_gbgs + here->HSM1_gbbs; + + gbdpg = here->HSM1_gbgs; + gbdpb = here->HSM1_gbbs; + gbdpdp = here->HSM1_gbds; + gbdpsp = -(gbdpg + gbdpb + gbdpdp); + + gbspdp = 0.0; + gbspg = 0.0; + gbspb = 0.0; + gbspsp = 0.0; + + cggb = here->HSM1_cggb; + cgsb = here->HSM1_cgsb; + cgdb = here->HSM1_cgdb; + + cbgb = here->HSM1_cbgb; + cbsb = here->HSM1_cbsb; + cbdb = here->HSM1_cbdb; + + cdgb = here->HSM1_cdgb; + cdsb = here->HSM1_cdsb; + cddb = here->HSM1_cddb; + } + else { + gm = -here->HSM1_gm; + gmbs = -here->HSM1_gmbs; + FwdSum = 0.0; + RevSum = -(gm + gmbs); + + gbbsp = -here->HSM1_gbds; + gbbdp = here->HSM1_gbds + here->HSM1_gbgs + here->HSM1_gbbs; + + gbdpg = 0.0; + gbdpsp = 0.0; + gbdpb = 0.0; + gbdpdp = 0.0; + + gbspg = here->HSM1_gbgs; + gbspsp = here->HSM1_gbds; + gbspb = here->HSM1_gbbs; + gbspdp = -(gbspg + gbspsp + gbspb); + + cggb = here->HSM1_cggb; + cgsb = here->HSM1_cgdb; + cgdb = here->HSM1_cgsb; + + cbgb = here->HSM1_cbgb; + cbsb = here->HSM1_cbdb; + cbdb = here->HSM1_cbsb; + + cdgb = -(here->HSM1_cdgb + cggb + cbgb); + cdsb = -(here->HSM1_cddb + cgsb + cbsb); + cddb = -(here->HSM1_cdsb + cgdb + cbdb); + } + + gdpr = here->HSM1drainConductance; + gspr = here->HSM1sourceConductance; + gds = here->HSM1_gds; + gbd = here->HSM1_gbd; + gbs = here->HSM1_gbs; + capbd = here->HSM1_capbd; + capbs = here->HSM1_capbs; + + cgso = here->HSM1_cgso; + cgdo = here->HSM1_cgdo; + cgbo = here->HSM1_cgbo; + + xcdgb = (cdgb - cgdo) * omega; + xcddb = (cddb + capbd + cgdo) * omega; + xcdsb = cdsb * omega; + xcsgb = -(cggb + cbgb + cdgb + cgso) * omega; + xcsdb = -(cgdb + cbdb + cddb) * omega; + xcssb = (capbs + cgso - (cgsb + cbsb + cdsb)) * omega; + xcggb = (cggb + cgdo + cgso + cgbo) * omega; + xcgdb = (cgdb - cgdo) * omega; + xcgsb = (cgsb - cgso) * omega; + xcbgb = (cbgb - cgbo) * omega; + xcbdb = (cbdb - capbd) * omega; + xcbsb = (cbsb - capbs) * omega; + + *(here->HSM1GgPtr +1) += m * xcggb; + *(here->HSM1BbPtr +1) -= m * (xcbgb + xcbdb + xcbsb); + *(here->HSM1DPdpPtr +1) += m * xcddb; + *(here->HSM1SPspPtr +1) += m * xcssb; + *(here->HSM1GbPtr +1) -= m * (xcggb + xcgdb + xcgsb); + *(here->HSM1GdpPtr +1) += m * xcgdb; + *(here->HSM1GspPtr +1) += m * xcgsb; + *(here->HSM1BgPtr +1) += m * xcbgb; + *(here->HSM1BdpPtr +1) += m * xcbdb; + *(here->HSM1BspPtr +1) += m * xcbsb; + *(here->HSM1DPgPtr +1) += m * xcdgb; + *(here->HSM1DPbPtr +1) -= m * (xcdgb + xcddb + xcdsb); + *(here->HSM1DPspPtr +1) += m * xcdsb; + *(here->HSM1SPgPtr +1) += m * xcsgb; + *(here->HSM1SPbPtr +1) -= m * (xcsgb + xcsdb + xcssb); + *(here->HSM1SPdpPtr +1) += m * xcsdb; + + *(here->HSM1DdPtr) += m * gdpr; + *(here->HSM1SsPtr) += m * gspr; + *(here->HSM1BbPtr) += m * (gbd + gbs - here->HSM1_gbbs); + *(here->HSM1DPdpPtr) += m * (gdpr + gds + gbd + RevSum + gbdpdp); + *(here->HSM1SPspPtr) += m * (gspr + gds + gbs + FwdSum + gbspsp); + + *(here->HSM1DdpPtr) -= m * gdpr; + *(here->HSM1SspPtr) -= m * gspr; + + *(here->HSM1BgPtr) -= m * here->HSM1_gbgs; + *(here->HSM1BdpPtr) -= m * (gbd - gbbdp); + *(here->HSM1BspPtr) -= m * (gbs - gbbsp); + + *(here->HSM1DPdPtr) -= m * gdpr; + *(here->HSM1DPgPtr) += m * (gm + gbdpg); + *(here->HSM1DPbPtr) -= m * (gbd - gmbs - gbdpb); + *(here->HSM1DPspPtr) -= m * (gds + FwdSum - gbdpsp); + + *(here->HSM1SPgPtr) -= m * (gm - gbspg); + *(here->HSM1SPsPtr) -= m * gspr; + *(here->HSM1SPbPtr) -= m * (gbs + gmbs - gbspb); + *(here->HSM1SPdpPtr) -= m * (gds + RevSum - gbspdp); + + /* + ... just for the case ... + *(here->HSM1GgPtr) -= m * xgtg; + *(here->HSM1GbPtr) -= m * xgtb; + *(here->HSM1GdpPtr) -= m * xgtd; + *(here->HSM1GspPtr) -= m * xgts; + */ + + } + } + return(OK); +} diff --git a/src/spicelib/devices/hisim/hsm1ask.c b/src/spicelib/devices/hisim/hsm1ask.c new file mode 100644 index 000000000..24bf7f41f --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1ask.c @@ -0,0 +1,231 @@ +/*********************************************************************** + HiSIM v1.1.0 + File: hsm1ask.c of HiSIM v1.1.0 + + Copyright (C) 2002 STARC + + June 30, 2002: developed by Hiroshima University and STARC + June 30, 2002: posted by Keiichi MORIKAWA, STARC Physical Design Group +***********************************************************************/ + +/* + * Modified by Paolo Nenzi 2002 + * ngspice integration + */ + +#include "ngspice.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "hsm1def.h" +#include "sperror.h" +#include "suffix.h" + +int HSM1ask(CKTcircuit *ckt, GENinstance *inst, int which, IFvalue *value, + IFvalue *select) +{ + HSM1instance *here = (HSM1instance*)inst; + + switch (which) { + case HSM1_L: + value->rValue = here->HSM1_l; + return(OK); + case HSM1_W: + value->rValue = here->HSM1_w; + return(OK); + case HSM1_M: + value->rValue = here->HSM1_m; + return(OK); + case HSM1_AS: + value->rValue = here->HSM1_as; + return(OK); + case HSM1_AD: + value->rValue = here->HSM1_ad; + return(OK); + case HSM1_PS: + value->rValue = here->HSM1_ps; + return(OK); + case HSM1_PD: + value->rValue = here->HSM1_pd; + return(OK); + case HSM1_NRS: + value->rValue = here->HSM1_nrs; + return(OK); + case HSM1_NRD: + value->rValue = here->HSM1_nrd; + return(OK); + case HSM1_TEMP: + value->rValue = here->HSM1_temp; + return(OK); + case HSM1_DTEMP: + value->rValue = here->HSM1_dtemp; + return(OK); + case HSM1_OFF: + value->iValue = here->HSM1_off; + return(OK); + case HSM1_IC_VBS: + value->rValue = here->HSM1_icVBS; + return(OK); + case HSM1_IC_VDS: + value->rValue = here->HSM1_icVDS; + return(OK); + case HSM1_IC_VGS: + value->rValue = here->HSM1_icVGS; + return(OK); + case HSM1_DNODE: + value->iValue = here->HSM1dNode; + return(OK); + case HSM1_GNODE: + value->iValue = here->HSM1gNode; + return(OK); + case HSM1_SNODE: + value->iValue = here->HSM1sNode; + return(OK); + case HSM1_BNODE: + value->iValue = here->HSM1bNode; + return(OK); + case HSM1_DNODEPRIME: + value->iValue = here->HSM1dNodePrime; + return(OK); + case HSM1_SNODEPRIME: + value->iValue = here->HSM1sNodePrime; + return(OK); + case HSM1_SOURCECONDUCT: + value->rValue = here->HSM1sourceConductance; + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_DRAINCONDUCT: + value->rValue = here->HSM1drainConductance; + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_VBD: + value->rValue = *(ckt->CKTstate0 + here->HSM1vbd); + return(OK); + case HSM1_VBS: + value->rValue = *(ckt->CKTstate0 + here->HSM1vbs); + return(OK); + case HSM1_VGS: + value->rValue = *(ckt->CKTstate0 + here->HSM1vgs); + return(OK); + case HSM1_VDS: + value->rValue = *(ckt->CKTstate0 + here->HSM1vds); + return(OK); + case HSM1_CD: + value->rValue = here->HSM1_ids; + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_CBS: + value->rValue = here->HSM1_ibs; + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_CBD: + value->rValue = here->HSM1_ibs; + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_GM: + value->rValue = here->HSM1_gm; + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_GDS: + value->rValue = here->HSM1_gds; + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_GMBS: + value->rValue = here->HSM1_gmbs; + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_GBD: + value->rValue = here->HSM1_gbd; + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_GBS: + value->rValue = here->HSM1_gbs; + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_QB: + value->rValue = *(ckt->CKTstate0 + here->HSM1qb); + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_CQB: + value->rValue = *(ckt->CKTstate0 + here->HSM1cqb); + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_QG: + value->rValue = *(ckt->CKTstate0 + here->HSM1qg); + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_CQG: + value->rValue = *(ckt->CKTstate0 + here->HSM1cqg); + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_QD: + value->rValue = *(ckt->CKTstate0 + here->HSM1qd); + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_CQD: + value->rValue = *(ckt->CKTstate0 + here->HSM1cqd); + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_CGG: + value->rValue = here->HSM1_cggb; + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_CGD: + value->rValue = here->HSM1_cgdb; + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_CGS: + value->rValue = here->HSM1_cgsb; + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_CDG: + value->rValue = here->HSM1_cdgb; + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_CDD: + value->rValue = here->HSM1_cddb; + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_CDS: + value->rValue = here->HSM1_cdsb; + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_CBG: + value->rValue = here->HSM1_cbgb; + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_CBDB: + value->rValue = here->HSM1_cbdb; + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_CBSB: + value->rValue = here->HSM1_cbsb; + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_CAPBD: + value->rValue = here->HSM1_capbd; + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_CAPBS: + value->rValue = here->HSM1_capbs; + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_VON: + value->rValue = here->HSM1_von; + return(OK); + case HSM1_VDSAT: + value->rValue = here->HSM1_vdsat; + return(OK); + case HSM1_QBS: + value->rValue = *(ckt->CKTstate0 + here->HSM1qbs); + value->rValue *= here->HSM1_m; + return(OK); + case HSM1_QBD: + value->rValue = *(ckt->CKTstate0 + here->HSM1qbd); + value->rValue *= here->HSM1_m; + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/hisim/hsm1cvtest.c b/src/spicelib/devices/hisim/hsm1cvtest.c new file mode 100644 index 000000000..9910d3125 --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1cvtest.c @@ -0,0 +1,106 @@ +/*********************************************************************** + HiSIM v1.1.0 + File: hsm1cvtest.c of HiSIM v1.1.0 + + Copyright (C) 2002 STARC + + June 30, 2002: developed by Hiroshima University and STARC + June 30, 2002: posted by Keiichi MORIKAWA, STARC Physical Design Group +***********************************************************************/ + +/* + * Modified by Paolo Nenzi 2002 + * ngspice integration + */ + +#include "ngspice.h" +#include "cktdefs.h" +#include "hsm1def.h" +#include "trandefs.h" +#include "const.h" +#include "devdefs.h" +#include "sperror.h" +#include "suffix.h" + +int HSM1convTest(GENmodel *inModel, CKTcircuit *ckt) +{ + HSM1model *model = (HSM1model*)inModel; + HSM1instance *here; + double delvbd, delvbs, delvds, delvgd, delvgs, vbd, vbs, vds; + double cbd, cbhat, cbs, cd, cdhat, tol, vgd, vgdo, vgs; + + /* loop through all the HSM1 device models */ + for ( ; model != NULL; model = model->HSM1nextModel ) { + /* loop through all the instances of the model */ + for ( here = model->HSM1instances; here != NULL ; + here = here->HSM1nextInstance ) { + + + if (here->HSM1owner != ARCHme) + continue; + + vbs = model->HSM1_type * + (*(ckt->CKTrhsOld+here->HSM1bNode) - + *(ckt->CKTrhsOld+here->HSM1sNodePrime)); + vgs = model->HSM1_type * + (*(ckt->CKTrhsOld+here->HSM1gNode) - + *(ckt->CKTrhsOld+here->HSM1sNodePrime)); + vds = model->HSM1_type * + (*(ckt->CKTrhsOld+here->HSM1dNodePrime) - + *(ckt->CKTrhsOld+here->HSM1sNodePrime)); + vbd = vbs - vds; + vgd = vgs - vds; + vgdo = *(ckt->CKTstate0 + here->HSM1vgs) - + *(ckt->CKTstate0 + here->HSM1vds); + delvbs = vbs - *(ckt->CKTstate0 + here->HSM1vbs); + delvbd = vbd - *(ckt->CKTstate0 + here->HSM1vbd); + delvgs = vgs - *(ckt->CKTstate0 + here->HSM1vgs); + delvds = vds - *(ckt->CKTstate0 + here->HSM1vds); + delvgd = vgd - vgdo; + + cd = here->HSM1_ids - here->HSM1_ibd; + if ( here->HSM1_mode >= 0 ) { + cd += here->HSM1_isub; + cdhat = cd - here->HSM1_gbd * delvbd + + (here->HSM1_gmbs + here->HSM1_gbbs) * delvbs + + (here->HSM1_gm + here->HSM1_gbgs) * delvgs + + (here->HSM1_gds + here->HSM1_gbds) * delvds; + } + else { + cdhat = cd + (here->HSM1_gmbs - here->HSM1_gbd) * delvbd + + here->HSM1_gm * delvgd - here->HSM1_gds * delvds; + } + + /* + * check convergence + */ + if ( here->HSM1_off == 0 || !(ckt->CKTmode & MODEINITFIX) ) { + tol = ckt->CKTreltol * MAX(fabs(cdhat), fabs(cd)) + ckt->CKTabstol; + if ( fabs(cdhat - cd) >= tol ) { + ckt->CKTnoncon++; + return(OK); + } + cbs = here->HSM1_ibs; + cbd = here->HSM1_ibd; + if ( here->HSM1_mode >= 0 ) { + cbhat = cbs + cbd - here->HSM1_isub + here->HSM1_gbd * delvbd + + (here->HSM1_gbs - here->HSM1_gbbs) * delvbs + - here->HSM1_gbgs * delvgs - here->HSM1_gbds * delvds; + } + else { + cbhat = cbs + cbd - here->HSM1_isub + + here->HSM1_gbs * delvbs + + (here->HSM1_gbd - here->HSM1_gbbs) * delvbd + - here->HSM1_gbgs * delvgd + here->HSM1_gbds * delvds; + } + tol = ckt->CKTreltol * + MAX(fabs(cbhat), fabs(cbs + cbd - here->HSM1_isub)) + ckt->CKTabstol; + if ( fabs(cbhat - (cbs + cbd - here->HSM1_isub)) > tol ) { + ckt->CKTnoncon++; + return(OK); + } + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/hisim/hsm1def.h b/src/spicelib/devices/hisim/hsm1def.h new file mode 100644 index 000000000..c0c389fed --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1def.h @@ -0,0 +1,694 @@ +/*********************************************************************** + HiSIM v1.1.0 + File: hsm1def.h of HiSIM v1.1.0 + + Copyright (C) 2002 STARC + + June 30, 2002: developed by Hiroshima University and STARC + June 30, 2002: posted by Keiichi MORIKAWA, STARC Physical Design Group +***********************************************************************/ + +/* + * Modified by Paolo Nenzi 2002 + * ngspice integration + */ + +#ifndef HSM1 +#define HSM1 + +#include "ifsim.h" +#include "gendefs.h" +#include "cktdefs.h" +#include "complex.h" +#include "noisedef.h" + +/* declarations for HiSIM1 MOSFETs */ + +/* information needed for each instance */ +typedef struct sHSM1instance { + struct sHSM1model *HSM1modPtr; /* pointer to model */ + struct sHSM1instance *HSM1nextInstance; /* pointer to next instance of + current model*/ + IFuid HSM1name; /* pointer to character string naming this instance */ + int HSM1owner; /* number of owner process */ + int HSM1states; /* index into state table for this device */ + + int HSM1dNode; /* number of the drain node of the mosfet */ + int HSM1gNode; /* number of the gate node of the mosfet */ + int HSM1sNode; /* number of the source node of the mosfet */ + int HSM1bNode; /* number of the bulk node of the mosfet */ + int HSM1dNodePrime; /* number od the inner drain node */ + int HSM1sNodePrime; /* number od the inner source node */ + + char HSM1_called[4]; /* string to check the first call */ + + /* previous values to evaluate initial guess */ + double HSM1_vbsc_prv; + double HSM1_vdsc_prv; + double HSM1_vgsc_prv; + double HSM1_ps0_prv; + double HSM1_ps0_dvbs_prv; + double HSM1_ps0_dvds_prv; + double HSM1_ps0_dvgs_prv; + double HSM1_pds_prv; + double HSM1_pds_dvbs_prv; + double HSM1_pds_dvds_prv; + double HSM1_pds_dvgs_prv; + double HSM1_ids_prv; + double HSM1_ids_dvbs_prv; + double HSM1_ids_dvds_prv; + double HSM1_ids_dvgs_prv; + + double HSM1_nfc; /* for noise calc. */ + + /* instance */ + double HSM1_l; /* the length of the channel region */ + double HSM1_w; /* the width of the channel region */ + double HSM1_m; /* Parallel multiplier */ + double HSM1_ad; /* the area of the drain diffusion */ + double HSM1_as; /* the area of the source diffusion */ + double HSM1_pd; /* perimeter of drain junction [m] */ + double HSM1_ps; /* perimeter of source junction [m] */ + double HSM1_nrd; /* equivalent num of squares of drain [-] (unused) */ + double HSM1_nrs; /* equivalent num of squares of source [-] (unused) */ + double HSM1_temp; /* lattice temperature [K] */ + double HSM1_dtemp; + + /* added by K.M. */ + double HSM1_weff; /* the effectiv width of the channel region */ + double HSM1_leff; /* the effectiv length of the channel region */ + + /* output */ + int HSM1_capop; + double HSM1_gd; + double HSM1_gs; + double HSM1_cgso; + double HSM1_cgdo; + double HSM1_cgbo; + double HSM1_von; /* vth */ + double HSM1_vdsat; + double HSM1_ids; /* cdrain, HSM1_cd */ + double HSM1_gds; + double HSM1_gm; + double HSM1_gmbs; + double HSM1_ibs; /* HSM1_cbs */ + double HSM1_ibd; /* HSM1_cbd */ + double HSM1_gbs; + double HSM1_gbd; + double HSM1_capbs; + double HSM1_capbd; + /* + double HSM1_qbs; + double HSM1_qbd; + */ + double HSM1_capgs; + double HSM1_capgd; + double HSM1_capgb; + double HSM1_isub; /* HSM1_csub */ + double HSM1_gbgs; + double HSM1_gbds; + double HSM1_gbbs; + double HSM1_qg; + double HSM1_qd; + /* double HSM1_qs; */ + double HSM1_qb; /* bulk charge qb = -(qg + qd + qs) */ + double HSM1_cggb; + double HSM1_cgdb; + double HSM1_cgsb; + double HSM1_cbgb; + double HSM1_cbdb; + double HSM1_cbsb; + double HSM1_cdgb; + double HSM1_cddb; + double HSM1_cdsb; + /* no use in SPICE3f5 + double HSM1_nois_irs; + double HSM1_nois_ird; + double HSM1_nois_idsth; + double HSM1_nois_idsfl; + double HSM1_freq; + */ + + /* added by K.M. */ + double HSM1_mu; /* mobility */ + + /* no use in SPICE3f5 + double HSM1drainSquares; the length of the drain in squares + double HSM1sourceSquares; the length of the source in squares */ + double HSM1sourceConductance; /* cond. of source (or 0): set in setup */ + double HSM1drainConductance; /* cond. of drain (or 0): set in setup */ + + double HSM1_icVBS; /* initial condition B-S voltage */ + double HSM1_icVDS; /* initial condition D-S voltage */ + double HSM1_icVGS; /* initial condition G-S voltage */ + int HSM1_off; /* non-zero to indicate device is off for dc analysis */ + int HSM1_mode; /* device mode : 1 = normal, -1 = inverse */ + + unsigned HSM1_l_Given :1; + unsigned HSM1_w_Given :1; + unsigned HSM1_m_Given :1; + unsigned HSM1_ad_Given :1; + unsigned HSM1_as_Given :1; + /* unsigned HSM1drainSquaresGiven :1; + unsigned HSM1sourceSquaresGiven :1;*/ + unsigned HSM1_pd_Given :1; + unsigned HSM1_ps_Given :1; + unsigned HSM1_nrd_Given :1; + unsigned HSM1_nrs_Given :1; + unsigned HSM1_temp_Given :1; + unsigned HSM1_dtemp_Given :1; + unsigned HSM1dNodePrimeSet :1; + unsigned HSM1sNodePrimeSet :1; + unsigned HSM1_icVBS_Given :1; + unsigned HSM1_icVDS_Given :1; + unsigned HSM1_icVGS_Given :1; + + /* pointer to sparse matrix */ + double *HSM1DdPtr; /* pointer to sparse matrix element at + (Drain node,drain node) */ + double *HSM1GgPtr; /* pointer to sparse matrix element at + (gate node,gate node) */ + double *HSM1SsPtr; /* pointer to sparse matrix element at + (source node,source node) */ + double *HSM1BbPtr; /* pointer to sparse matrix element at + (bulk node,bulk node) */ + double *HSM1DPdpPtr; /* pointer to sparse matrix element at + (drain prime node,drain prime node) */ + double *HSM1SPspPtr; /* pointer to sparse matrix element at + (source prime node,source prime node) */ + double *HSM1DdpPtr; /* pointer to sparse matrix element at + (drain node,drain prime node) */ + double *HSM1GbPtr; /* pointer to sparse matrix element at + (gate node,bulk node) */ + double *HSM1GdpPtr; /* pointer to sparse matrix element at + (gate node,drain prime node) */ + double *HSM1GspPtr; /* pointer to sparse matrix element at + (gate node,source prime node) */ + double *HSM1SspPtr; /* pointer to sparse matrix element at + (source node,source prime node) */ + double *HSM1BdpPtr; /* pointer to sparse matrix element at + (bulk node,drain prime node) */ + double *HSM1BspPtr; /* pointer to sparse matrix element at + (bulk node,source prime node) */ + double *HSM1DPspPtr; /* pointer to sparse matrix element at + (drain prime node,source prime node) */ + double *HSM1DPdPtr; /* pointer to sparse matrix element at + (drain prime node,drain node) */ + double *HSM1BgPtr; /* pointer to sparse matrix element at + (bulk node,gate node) */ + double *HSM1DPgPtr; /* pointer to sparse matrix element at + (drain prime node,gate node) */ + double *HSM1SPgPtr; /* pointer to sparse matrix element at + (source prime node,gate node) */ + double *HSM1SPsPtr; /* pointer to sparse matrix element at + (source prime node,source node) */ + double *HSM1DPbPtr; /* pointer to sparse matrix element at + (drain prime node,bulk node) */ + double *HSM1SPbPtr; /* pointer to sparse matrix element at + (source prime node,bulk node) */ + double *HSM1SPdpPtr; /* pointer to sparse matrix element at + (source prime node,drain prime node) */ + + /* common state values in hisim1 module */ +#define HSM1vbd HSM1states+ 0 +#define HSM1vbs HSM1states+ 1 +#define HSM1vgs HSM1states+ 2 +#define HSM1vds HSM1states+ 3 + +#define HSM1qb HSM1states+ 4 +#define HSM1cqb HSM1states+ 5 +#define HSM1qg HSM1states+ 6 +#define HSM1cqg HSM1states+ 7 +#define HSM1qd HSM1states+ 8 +#define HSM1cqd HSM1states+ 9 + +#define HSM1qbs HSM1states+ 10 +#define HSM1qbd HSM1states+ 11 + +#define HSM1numStates 12 + + /* indices to the array of HiSIM1 NOISE SOURCES (the same as BSIM3) */ +#define HSM1RDNOIZ 0 +#define HSM1RSNOIZ 1 +#define HSM1IDNOIZ 2 +#define HSM1FLNOIZ 3 +#define HSM1TOTNOIZ 4 + +#define HSM1NSRCS 5 /* the number of HiSIM1 MOSFET noise sources */ + +#ifndef NONOISE + double HSM1nVar[NSTATVARS][HSM1NSRCS]; +#else /* NONOISE */ + double **HSM1nVar; +#endif /* NONOISE */ + +} HSM1instance ; + + +/* per model data */ + +typedef struct sHiSIM1model { /* model structure for a resistor */ + int HSM1modType; /* type index of this device type */ + struct sHiSIM1model *HSM1nextModel; /* pointer to next possible model + in linked list */ + HSM1instance * HSM1instances; /* pointer to list of instances + that have this model */ + IFuid HSM1modName; /* pointer to the name of this model */ + int HSM1_type; /* device type: 1 = nmos, -1 = pmos */ + int HSM1_level; /* level */ + int HSM1_info; /* information */ + int HSM1_noise; /* noise model selecter see hsm1noi.c */ + int HSM1_version; /* model version 100/110 */ + int HSM1_show; /* show physical value 1, 2, ... , 11 */ + + /* flags for initial guess */ + int HSM1_corsrd ; + int HSM1_coiprv ; + int HSM1_copprv ; + int HSM1_cocgso ; + int HSM1_cocgdo ; + int HSM1_cocgbo ; + int HSM1_coadov ; + int HSM1_coxx08 ; + int HSM1_coxx09 ; + int HSM1_coisub ; + int HSM1_coiigs ; + int HSM1_cogidl ; + int HSM1_coovlp ; + int HSM1_conois ; + int HSM1_coisti ; /* HiSIM1.1 */ + /* HiSIM original */ + double HSM1_vmax ; + double HSM1_bgtmp1 ; + double HSM1_bgtmp2 ; + double HSM1_tox ; + double HSM1_dl ; + double HSM1_dw ; + double HSM1_xj ; /* HiSIM1.0 */ + double HSM1_xqy ; /* HiSIM1.1 */ + double HSM1_rs; /* source contact resistance */ + double HSM1_rd; /* drain contact resistance */ + double HSM1_vfbc ; + double HSM1_nsubc ; + double HSM1_parl1 ; + double HSM1_parl2 ; + double HSM1_lp ; + double HSM1_nsubp ; + double HSM1_scp1 ; + double HSM1_scp2 ; + double HSM1_scp3 ; + double HSM1_sc1 ; + double HSM1_sc2 ; + double HSM1_sc3 ; + double HSM1_pgd1 ; + double HSM1_pgd2 ; + double HSM1_pgd3 ; + double HSM1_ndep ; + double HSM1_ninv ; + double HSM1_ninvd ; + double HSM1_muecb0 ; + double HSM1_muecb1 ; + double HSM1_mueph1 ; + double HSM1_mueph0 ; + double HSM1_mueph2 ; + double HSM1_w0 ; + double HSM1_muesr1 ; + double HSM1_muesr0 ; + double HSM1_bb ; + double HSM1_vds0 ; + double HSM1_bc0 ; + double HSM1_bc1 ; + double HSM1_sub1 ; + double HSM1_sub2 ; + double HSM1_sub3 ; + double HSM1_wvthsc ; /* HiSIM1.1 */ + double HSM1_nsti ; /* HiSIM1.1 */ + double HSM1_wsti ; /* HiSIM1.1 */ + double HSM1_cgso ; + double HSM1_cgdo ; + double HSM1_cgbo ; + double HSM1_tpoly ; + double HSM1_js0 ; + double HSM1_js0sw ; + double HSM1_nj ; + double HSM1_njsw ; + double HSM1_xti ; + double HSM1_cj ; + double HSM1_cjsw ; + double HSM1_cjswg ; + double HSM1_mj ; + double HSM1_mjsw ; + double HSM1_mjswg ; + double HSM1_pb ; + double HSM1_pbsw ; + double HSM1_pbswg ; + double HSM1_xpolyd ; + double HSM1_clm1 ; + double HSM1_clm2 ; + double HSM1_clm3 ; + double HSM1_muetmp ; + double HSM1_rpock1 ; + double HSM1_rpock2 ; + double HSM1_rpocp1 ; /* HiSIM 1.1 */ + double HSM1_rpocp2 ; /* HiSIM 1.1 */ + double HSM1_vover ; + double HSM1_voverp ; + double HSM1_wfc ; + double HSM1_qme1 ; + double HSM1_qme2 ; + double HSM1_qme3 ; + double HSM1_gidl1 ; + double HSM1_gidl2 ; + double HSM1_gidl3 ; + double HSM1_gleak1 ; + double HSM1_gleak2 ; + double HSM1_gleak3 ; + double HSM1_vzadd0 ; + double HSM1_pzadd0 ; + double HSM1_nftrp ; + double HSM1_nfalp ; + double HSM1_cit ; + + /* for flicker noise of SPICE3 added by K.M. */ + double HSM1_ef; + double HSM1_af; + double HSM1_kf; + + /* flag for model */ + unsigned HSM1_type_Given :1; + unsigned HSM1_level_Given :1; + unsigned HSM1_info_Given :1; + unsigned HSM1_noise_Given :1; + unsigned HSM1_version_Given :1; + unsigned HSM1_show_Given :1; + unsigned HSM1_corsrd_Given :1; + unsigned HSM1_coiprv_Given :1; + unsigned HSM1_copprv_Given :1; + unsigned HSM1_cocgso_Given :1; + unsigned HSM1_cocgdo_Given :1; + unsigned HSM1_cocgbo_Given :1; + unsigned HSM1_coadov_Given :1; + unsigned HSM1_coxx08_Given :1; + unsigned HSM1_coxx09_Given :1; + unsigned HSM1_coisub_Given :1; + unsigned HSM1_coiigs_Given :1; + unsigned HSM1_cogidl_Given :1; + unsigned HSM1_coovlp_Given :1; + unsigned HSM1_conois_Given :1; + unsigned HSM1_coisti_Given :1; /* HiSIM1.1 */ + unsigned HSM1_vmax_Given :1; + unsigned HSM1_bgtmp1_Given :1; + unsigned HSM1_bgtmp2_Given :1; + unsigned HSM1_tox_Given :1; + unsigned HSM1_dl_Given :1; + unsigned HSM1_dw_Given :1; + unsigned HSM1_xj_Given :1; /* HiSIM1.0 */ + unsigned HSM1_xqy_Given :1; /* HiSIM1.1 */ + unsigned HSM1_rs_Given :1; + unsigned HSM1_rd_Given :1; + unsigned HSM1_vfbc_Given :1; + unsigned HSM1_nsubc_Given :1; + unsigned HSM1_parl1_Given :1; + unsigned HSM1_parl2_Given :1; + unsigned HSM1_lp_Given :1; + unsigned HSM1_nsubp_Given :1; + unsigned HSM1_scp1_Given :1; + unsigned HSM1_scp2_Given :1; + unsigned HSM1_scp3_Given :1; + unsigned HSM1_sc1_Given :1; + unsigned HSM1_sc2_Given :1; + unsigned HSM1_sc3_Given :1; + unsigned HSM1_pgd1_Given :1; + unsigned HSM1_pgd2_Given :1; + unsigned HSM1_pgd3_Given :1; + unsigned HSM1_ndep_Given :1; + unsigned HSM1_ninv_Given :1; + unsigned HSM1_ninvd_Given :1; + unsigned HSM1_muecb0_Given :1; + unsigned HSM1_muecb1_Given :1; + unsigned HSM1_mueph1_Given :1; + unsigned HSM1_mueph0_Given :1; + unsigned HSM1_mueph2_Given :1; + unsigned HSM1_w0_Given :1; + unsigned HSM1_muesr1_Given :1; + unsigned HSM1_muesr0_Given :1; + unsigned HSM1_bb_Given :1; + unsigned HSM1_vds0_Given :1; + unsigned HSM1_bc0_Given :1; + unsigned HSM1_bc1_Given :1; + unsigned HSM1_sub1_Given :1; + unsigned HSM1_sub2_Given :1; + unsigned HSM1_sub3_Given :1; + unsigned HSM1_wvthsc_Given :1; /* HiSIM1.1 */ + unsigned HSM1_nsti_Given :1; /* HiSIM1.1 */ + unsigned HSM1_wsti_Given :1; /* HiSIM1.1 */ + unsigned HSM1_cgso_Given :1; + unsigned HSM1_cgdo_Given :1; + unsigned HSM1_cgbo_Given :1; + unsigned HSM1_tpoly_Given :1; + unsigned HSM1_js0_Given :1; + unsigned HSM1_js0sw_Given :1; + unsigned HSM1_nj_Given :1; + unsigned HSM1_njsw_Given :1; + unsigned HSM1_xti_Given :1; + unsigned HSM1_cj_Given :1; + unsigned HSM1_cjsw_Given :1; + unsigned HSM1_cjswg_Given :1; + unsigned HSM1_mj_Given :1; + unsigned HSM1_mjsw_Given :1; + unsigned HSM1_mjswg_Given :1; + unsigned HSM1_pb_Given :1; + unsigned HSM1_pbsw_Given :1; + unsigned HSM1_pbswg_Given :1; + unsigned HSM1_xpolyd_Given :1; + unsigned HSM1_clm1_Given :1; + unsigned HSM1_clm2_Given :1; + unsigned HSM1_clm3_Given :1; + unsigned HSM1_muetmp_Given :1; + unsigned HSM1_rpock1_Given :1; + unsigned HSM1_rpock2_Given :1; + unsigned HSM1_rpocp1_Given :1; /* HiSIM1.1 */ + unsigned HSM1_rpocp2_Given :1; /* HiSIM1.1 */ + unsigned HSM1_vover_Given :1; + unsigned HSM1_voverp_Given :1; + unsigned HSM1_wfc_Given :1; + unsigned HSM1_qme1_Given :1; + unsigned HSM1_qme2_Given :1; + unsigned HSM1_qme3_Given :1; + unsigned HSM1_gidl1_Given :1; + unsigned HSM1_gidl2_Given :1; + unsigned HSM1_gidl3_Given :1; + unsigned HSM1_gleak1_Given :1; + unsigned HSM1_gleak2_Given :1; + unsigned HSM1_gleak3_Given :1; + unsigned HSM1_vzadd0_Given :1; + unsigned HSM1_pzadd0_Given :1; + unsigned HSM1_nftrp_Given :1; + unsigned HSM1_nfalp_Given :1; + unsigned HSM1_cit_Given :1; + + unsigned HSM1_ef_Given :1; + unsigned HSM1_af_Given :1; + unsigned HSM1_kf_Given :1; + +} HSM1model; + +#ifndef NMOS +#define NMOS 1 +#define PMOS -1 +#endif /*NMOS*/ + +#define HSM1_BAD_PARAM -1 + +/* flags */ +#define HSM1_MOD_NMOS 1 +#define HSM1_MOD_PMOS 2 +#define HSM1_MOD_LEVEL 3 +#define HSM1_MOD_INFO 4 +#define HSM1_MOD_NOISE 5 +#define HSM1_MOD_VERSION 6 +#define HSM1_MOD_SHOW 7 +#define HSM1_MOD_CORSRD 11 +#define HSM1_MOD_COIPRV 12 +#define HSM1_MOD_COPPRV 13 +#define HSM1_MOD_COCGSO 14 +#define HSM1_MOD_COCGDO 15 +#define HSM1_MOD_COCGBO 16 +#define HSM1_MOD_COADOV 17 +#define HSM1_MOD_COXX08 18 +#define HSM1_MOD_COXX09 19 +#define HSM1_MOD_COISUB 21 +#define HSM1_MOD_COIIGS 22 +#define HSM1_MOD_COGIDL 23 +#define HSM1_MOD_COOVLP 24 +#define HSM1_MOD_CONOIS 25 +#define HSM1_MOD_COISTI 26 /* HiSIM1.1 */ +/* device parameters */ +#define HSM1_L 51 +#define HSM1_W 52 +#define HSM1_M 66 +#define HSM1_AD 53 +#define HSM1_AS 54 +#define HSM1_PD 55 +#define HSM1_PS 56 +#define HSM1_NRD 57 +#define HSM1_NRS 58 +#define HSM1_TEMP 59 +#define HSM1_DTEMP 60 +#define HSM1_OFF 61 +#define HSM1_IC_VBS 62 +#define HSM1_IC_VDS 63 +#define HSM1_IC_VGS 64 +#define HSM1_IC 65 + +/* model parameters */ +#define HSM1_MOD_VMAX 101 +#define HSM1_MOD_BGTMP1 103 +#define HSM1_MOD_BGTMP2 104 +#define HSM1_MOD_TOX 105 +#define HSM1_MOD_DL 106 +#define HSM1_MOD_DW 107 +#define HSM1_MOD_XJ 996 /* HiSIM1.0 */ +#define HSM1_MOD_XQY 997 /* HiSIM1.1 */ +#define HSM1_MOD_RS 108 +#define HSM1_MOD_RD 109 +#define HSM1_MOD_VFBC 110 +#define HSM1_MOD_NSUBC 113 +#define HSM1_MOD_PARL1 122 +#define HSM1_MOD_PARL2 123 +#define HSM1_MOD_SC1 124 +#define HSM1_MOD_SC2 125 +#define HSM1_MOD_SC3 126 +#define HSM1_MOD_NDEP 129 +#define HSM1_MOD_NINV 130 +#define HSM1_MOD_MUECB0 131 +#define HSM1_MOD_MUECB1 132 +#define HSM1_MOD_MUEPH1 133 +#define HSM1_MOD_MUEPH0 134 +#define HSM1_MOD_MUEPH2 999 +#define HSM1_MOD_W0 998 +#define HSM1_MOD_MUESR1 135 +#define HSM1_MOD_MUESR0 136 +#define HSM1_MOD_BB 137 +#define HSM1_MOD_VDS0 138 +#define HSM1_MOD_BC0 139 +#define HSM1_MOD_BC1 140 +#define HSM1_MOD_SUB1 141 +#define HSM1_MOD_SUB2 142 +#define HSM1_MOD_SUB3 143 +#define HSM1_MOD_CGSO 144 +#define HSM1_MOD_CGDO 145 +#define HSM1_MOD_CGBO 146 +#define HSM1_MOD_JS0 147 +#define HSM1_MOD_JS0SW 148 +#define HSM1_MOD_NJ 149 +#define HSM1_MOD_NJSW 150 +#define HSM1_MOD_XTI 151 +#define HSM1_MOD_CJ 152 +#define HSM1_MOD_CJSW 156 +#define HSM1_MOD_CJSWG 157 +#define HSM1_MOD_MJ 160 +#define HSM1_MOD_MJSW 161 +#define HSM1_MOD_MJSWG 163 +#define HSM1_MOD_PB 166 +#define HSM1_MOD_PBSW 168 +#define HSM1_MOD_PBSWG 169 +#define HSM1_MOD_XPOLYD 170 +#define HSM1_MOD_TPOLY 171 +#define HSM1_MOD_LP 172 +#define HSM1_MOD_NSUBP 173 +#define HSM1_MOD_SCP1 174 +#define HSM1_MOD_SCP2 175 +#define HSM1_MOD_SCP3 176 +#define HSM1_MOD_PGD1 177 +#define HSM1_MOD_PGD2 178 +#define HSM1_MOD_PGD3 179 +#define HSM1_MOD_CLM1 180 +#define HSM1_MOD_CLM2 181 +#define HSM1_MOD_CLM3 182 +#define HSM1_MOD_NINVD 183 +#define HSM1_MOD_MUETMP 190 +#define HSM1_MOD_RPOCK1 191 +#define HSM1_MOD_RPOCK2 192 +#define HSM1_MOD_VOVER 193 +#define HSM1_MOD_VOVERP 194 +#define HSM1_MOD_WFC 195 +#define HSM1_MOD_QME1 196 +#define HSM1_MOD_QME2 197 +#define HSM1_MOD_QME3 198 +#define HSM1_MOD_GIDL1 199 +#define HSM1_MOD_GIDL2 200 +#define HSM1_MOD_GIDL3 201 +#define HSM1_MOD_GLEAK1 202 +#define HSM1_MOD_GLEAK2 203 +#define HSM1_MOD_GLEAK3 204 +#define HSM1_MOD_VZADD0 205 +#define HSM1_MOD_PZADD0 206 +#define HSM1_MOD_WVTHSC 207 /* HiSIM1.1 */ +#define HSM1_MOD_NSTI 208 /* HiSIM1.1 */ +#define HSM1_MOD_WSTI 209 /* HiSIM1.1 */ +#define HSM1_MOD_RPOCP1 210 /* HiSIM1.1 */ +#define HSM1_MOD_RPOCP2 211 /* HiSIM1.1 */ +#define HSM1_MOD_NFTRP 401 +#define HSM1_MOD_NFALP 402 +#define HSM1_MOD_CIT 403 +#define HSM1_MOD_EF 500 +#define HSM1_MOD_AF 501 +#define HSM1_MOD_KF 502 + +/* device questions */ +#define HSM1_DNODE 341 +#define HSM1_GNODE 342 +#define HSM1_SNODE 343 +#define HSM1_BNODE 344 +#define HSM1_DNODEPRIME 345 +#define HSM1_SNODEPRIME 346 +#define HSM1_VBD 347 +#define HSM1_VBS 348 +#define HSM1_VGS 349 +#define HSM1_VDS 350 +#define HSM1_CD 351 +#define HSM1_CBS 352 +#define HSM1_CBD 353 +#define HSM1_GM 354 +#define HSM1_GDS 355 +#define HSM1_GMBS 356 +#define HSM1_GBD 357 +#define HSM1_GBS 358 +#define HSM1_QB 359 +#define HSM1_CQB 360 +#define HSM1_QG 361 +#define HSM1_CQG 362 +#define HSM1_QD 363 +#define HSM1_CQD 364 +#define HSM1_CGG 365 +#define HSM1_CGD 366 +#define HSM1_CGS 367 +#define HSM1_CBG 368 +#define HSM1_CAPBD 369 +#define HSM1_CQBD 370 +#define HSM1_CAPBS 371 +#define HSM1_CQBS 372 +#define HSM1_CDG 373 +#define HSM1_CDD 374 +#define HSM1_CDS 375 +#define HSM1_VON 376 +#define HSM1_VDSAT 377 +#define HSM1_QBS 378 +#define HSM1_QBD 379 +#define HSM1_SOURCECONDUCT 380 +#define HSM1_DRAINCONDUCT 381 +#define HSM1_CBDB 382 +#define HSM1_CBSB 383 + +#include "hsm1ext.h" + +/* +extern void HSM1evaluate(double,double,double,HSM1instance*,HSM1model*, + double*,double*,double*, double*, double*, double*, double*, + double*, double*, double*, double*, double*, double*, double*, + double*, double*, double*, double*, CKTcircuit*); +*/ + +#endif /*HSM1*/ + diff --git a/src/spicelib/devices/hisim/hsm1del.c b/src/spicelib/devices/hisim/hsm1del.c new file mode 100644 index 000000000..e8059cf5e --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1del.c @@ -0,0 +1,41 @@ +/*********************************************************************** + HiSIM v1.1.0 + File: hsm1del.c of HiSIM v1.1.0 + + Copyright (C) 2002 STARC + + June 30, 2002: developed by Hiroshima University and STARC + June 30, 2002: posted by Keiichi MORIKAWA, STARC Physical Design Group +***********************************************************************/ + +/* + * Modified by Paolo Nenzi 2002 + * ngspice integration + */ + +#include "ngspice.h" +#include "hsm1def.h" +#include "sperror.h" +#include "gendefs.h" +#include "suffix.h" + +int HSM1delete(GENmodel *inModel, IFuid name, GENinstance **inInst) +{ + HSM1instance **fast = (HSM1instance**)inInst; + HSM1model *model = (HSM1model*)inModel; + HSM1instance **prev = NULL; + HSM1instance *here; + + for( ;model ;model = model->HSM1nextModel ) { + prev = &(model->HSM1instances); + for ( here = *prev ;here ;here = *prev ) { + if ( here->HSM1name == name || (fast && here==*fast) ) { + *prev= here->HSM1nextInstance; + FREE(here); + return(OK); + } + prev = &(here->HSM1nextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/hisim/hsm1dest.c b/src/spicelib/devices/hisim/hsm1dest.c new file mode 100644 index 000000000..c319af6b6 --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1dest.c @@ -0,0 +1,41 @@ +/*********************************************************************** + HiSIM v1.1.0 + File: hsm1dest.c of HiSIM v1.1.0 + + Copyright (C) 2002 STARC + + June 30, 2002: developed by Hiroshima University and STARC + June 30, 2002: posted by Keiichi MORIKAWA, STARC Physical Design Group +***********************************************************************/ + +/* + * Modified by Paolo Nenzi 2002 + * ngspice integration + */ + +#include "ngspice.h" +#include "hsm1def.h" +#include "suffix.h" + +void HSM1destroy(GENmodel **inModel) +{ + HSM1model **model = (HSM1model**)inModel; + HSM1instance *here; + HSM1instance *prev = NULL; + HSM1model *mod = *model; + HSM1model *oldmod = NULL; + + for ( ;mod ;mod = mod->HSM1nextModel ) { + if (oldmod) FREE(oldmod); + oldmod = mod; + prev = (HSM1instance *)NULL; + for ( here = mod->HSM1instances ;here ;here = here->HSM1nextInstance ) { + if (prev) FREE(prev); + prev = here; + } + if (prev) FREE(prev); + } + if (oldmod) FREE(oldmod); + *model = NULL; +} + diff --git a/src/spicelib/devices/hisim/hsm1eval1_0.c b/src/spicelib/devices/hisim/hsm1eval1_0.c new file mode 100644 index 000000000..a2cab9c66 --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1eval1_0.c @@ -0,0 +1,4572 @@ +/*********************************************************************** + HiSIM v1.1.0 + File: hsm1eval1_0.c of HiSIM v1.1.0 + + Copyright (C) 2002 STARC + + June 30, 2002: developed by Hiroshima University and STARC + June 30, 2002: posted by Keiichi MORIKAWA, STARC Physical Design Group +***********************************************************************/ + +/* + * Modified by Paolo Nenzi 2002 + * ngspice integration + */ + +/********************************************************************* +* Memorandum on programming +* +* (1) Bias (x: b|d|g) +* . sIN.vxs : Input argument. +* . Vxse: External bias taking account device type (pMOS->nMOS). +* . Vxsc: Confined bias within a specified region. +* . Vxs : Internal bias taking account Rs/Rd. +* . Y_dVxs denotes the partial derivative of Y w.r.t. Vxs. +* +* (2) Device Mode +* . Normal mode (Vds>0 for nMOS) is assumed. +* . In case of reverse mode, parent routines have to properly +* transform or interchange inputs and outputs except ones +* related to junction diodes, which are regarded as being +* fixed to the nodal S/D. +* +* (3) Modification for symmetry at Vds=0 +* . Vxsz: Modified bias. +* . Ps0z: Modified Ps0. +* . The following variables are calculated as a function of +* modified biases or potential. +* Tox, Cox, (-- with quantum effect) +* Vth*, dVth*, dPpg, Qnm, Qbm, Igs, Ilg. +* . The following variables are calculated using a transform +* function. +* Lred, rp1(<-sIN.rpock1). +* +* (4) Zones and Cases (terminology) +* +* Chi:=beta*(Ps0-Vbs)= 0 3 5 +* +* Zone: A | D1 | D2 | D3 +* | +* (accumulation)|(depletion) +* | +* Vgs = Vgs_fb Vth +* / / +* Case: Nonconductive / Conductive +* / +* VgVt:=Qn0/Cox= VgVt_small +* +* . Ids is regarded as zero in zone-A and -D1. +* . Procedure to calculate Psl and dependent variables is +* omitted in the nonconductive case. Ids and Qi are regarded +* as zero in this case. +* +*********************************************************************/ + +/*===========================================================* +* Preamble. +*=================*/ +/*---------------------------------------------------* +* Header files. +*-----------------*/ +#include +#include +#include +#include + +/*-----------------------------------* +* HiSIM macros and structures. +* - All inputs and outputs are defined here. +*-----------------*/ +#include "hisim.h" +#include "hsm1evalenv.h" + +/*===========================================================* +* Function hsm1eval. (HiSIM1.0.x) +*=================*/ +int HSM1evaluate1_0( HiSIM_input sIN, HiSIM_output *pOT, + HiSIM_messenger *pMS) +{ + +/*---------------------------------------------------* +* Local variables. +*-----------------*/ +/* Constans ----------------------- */ +int lp_s0_max = 20 ; +int lp_sl_max = 20 ; +int lp_bs_max = 10 ; +double Ids_tol = 1.0e-10 ; +double Ids_maxvar = 1.0e-1 ; +double dP_max = 0.1e0 ; +double ps_conv = 5.0e-13 ; +double gs_conv = 1.0e-8 ; +/*-----*/ +/** depletion **/ +double znbd3 = 3.0e0 ; +double znbd5 = 5.0e0 ; +double cn_nc3 = C_SQRT_2 / 108e0 ; +/* 5-degree, contact:Chi=5 */ +double cn_nc51 = 0.707106781186548 ; /* sqrt(2)/2 */ +double cn_nc52 = -0.117851130197758 ; /* -sqrt(2)/12 */ +double cn_nc53 = 0.0178800506338833 ; /* (187 - 112*sqrt(2))/1600 */ +double cn_nc54 = -0.00163730162779191 ; /* (-131 + 88*sqrt(2))/4000 */ +double cn_nc55 = 6.36964918866352e-5; /*(1509-1040*sqrt(2))/600000*/ +/** inversion **/ +/* 3-dgree polynomial approx for ( exp[Chi]-1 )^{1/2} */ +double cn_im53 = 2.9693154855770998e-1 ; +double cn_im54 = -7.0536542840097616e-2 ; +double cn_im55 = 6.1152888951331797e-3 ; +/* 3-dgree polynomial approx for ( exp[Chi]-Chi-1 )^{1/2} */ +double cn_ik53 = 2.6864599830664019e-1 ; +double cn_ik54 = -6.1399531828413338e-2 ; +double cn_ik55 = 5.3528499428744690e-3 ; +/** initial guess **/ +double c_ps0ini_2 = 8.0e-4 ; +double c_pslini_1 = 0.3e0 ; +double c_pslini_2 = 3.0e-2 ; +double VgVt_small = 1.0e-12 ; +double Vbs_max = 0.5e0 ; +double Vbs_min = -10.5e0 ; +double Vds_max = 10.5e0 ; +double Vgs_max = 10.5e0 ; +/*-----*/ +double Vbd_max = 20.0e0 ; +double Vbd_min = -10.0e0 ; +/*-----*/ +double epsm10 = 10.0e0 * C_EPS_M ; +double small = 1.0e-50 ; +/*-----*/ +double Vz_dlt = 5.0e-3 ; +/*-----*/ +double Gdsmin = 1.0e-12 ; +/*-----*/ +/* double Gjmin = 1.0e-12 ; */ +double Gjmin = sIN.gmin; /* modified by K.M. for SPICE3f5 */ +/*-----*/ +double cclmmdf = 1.0e-1 ; +/*-----*/ +double qme_dlt = 1.0e-2 ; +double eef_dlt = 1.0e-2 ; +double sti_dlt = -3.0e-3 ; +double pol_dlt = 1.0e-2 ; + +/* Internal flags --------------------*/ +int flg_err = 0 ; /* error level */ +int flg_ncnv = 0 ; /* Flag for negative conductance */ +int flg_rsrd ; /* Flag for bias loop accounting Rs and Rd */ +int flg_iprv ; /* Flag for initial guess of Ids */ +int flg_pprv ; /* Flag for initial guesses of Ps0 and Pds */ +int flg_noqi ; /* Flag for the cases regarding Qi=Qd=0 */ +int flg_vbsc = 0 ; /* Flag for Vbs confining */ +int flg_vdsc = 0 ; /* Flag for Vds confining */ +int flg_vgsc = 0 ; /* Flag for Vgs confining */ +int flg_vbdc = 0 ; /* Flag for Vgs confining */ +int flg_vxxc = 0 ; /* Flag whether some bias was confined */ +int flg_info = 0 ; + +/* Important Variables in HiSIM -------*/ +/* external bias */ +double Vbse , Vdse , Vgse , Vbde ; +/* confine bias */ +double Vbsc , Vdsc , Vgsc , Vbdc ; +double Vbsc_dVbse = 1.0 ; +/* internal bias */ +double Vbs , Vds , Vgs ; +double Vbs_dVbse = 1.0 , Vbs_dVdse = 0.0 , Vbs_dVgse = 0.0 ; +double Vds_dVbse = 0.0 , Vds_dVdse = 1.0 , Vds_dVgse = 0.0 ; +double Vgs_dVbse = 0.0 , Vgs_dVdse = 0.0 , Vgs_dVgse = 1.0 ; +double Vgp ; +double Vgp_dVbs , Vgp_dVds , Vgp_dVgs ; +double Vgs_fb ; +/* Ps0 : surface potential at the source side */ +double Ps0 ; +double Ps0_dVbs , Ps0_dVds , Ps0_dVgs ; +double Ps0_ini , Ps0_iniA , Ps0_iniB ; +/* Psl : surface potential at the drain side */ +double Psl ; +double Psl_dVbs , Psl_dVds , Psl_dVgs ; +double Psl_lim ; +/* Pds := Psl - Ps0 */ +double Pds ; +double Pds_dVbs , Pds_dVds , Pds_dVgs ; +double Pds_ini ; +double Pds_max ; +/* iteration numbers of Ps0 and Psl equations. */ +int lp_s0 , lp_sl ; +/* Xi0 := beta * ( Ps0 - Vbs ) - 1. */ +double Xi0 ; +double Xi0_dVbs , Xi0_dVds , Xi0_dVgs ; +double Xi0p12 ; +double Xi0p12_dVbs , Xi0p12_dVds , Xi0p12_dVgs ; +double Xi0p32 ; +double Xi0p32_dVbs , Xi0p32_dVds , Xi0p32_dVgs ; +/* Xil := beta * ( Psl - Vbs ) - 1. */ +double Xilp12 ; +double Xilp32 ; +double Xil ; +/* modified bias and potential for sym.*/ +double Vbsz , Vdsz , Vgsz ; +double Vbsz_dVbs , Vbsz_dVds ; +double Vdsz_dVds ; +double Vgsz_dVgs , Vgsz_dVds ; +double Vbszm ; +double Vbszm_dVbs , Vbszm_dVds ; +double Vbs1 , Vbs2 , Vbsd ; +double Vbsd_dVbs , Vbsd_dVds ; +double Vzadd , Vzadd_dVds , Vzadd_dA ; +double VzaddA , VzaddA_dVds ; +double Ps0z , Ps0z_dVbs , Ps0z_dVds , Ps0z_dVgs ; +double Pzadd , Pzadd_dVbs , Pzadd_dVds , Pzadd_dVgs ; +double Ps0Vbsz , Ps0Vbsz_dVbs , Ps0Vbsz_dVds , Ps0Vbsz_dVgs ; +double Vgpz , Vgpz_dVbs , Vgpz_dVds , Vgpz_dVgs ; +double Xi0z ; +double Xi0z_dVbs , Xi0z_dVds , Xi0z_dVgs ; +double Xi0zp12 ; +double Xi0zp12_dVbs , Xi0zp12_dVds , Xi0zp12_dVgs ; +/* Chi := beta * ( Ps{0/l} - Vbs ) */ +double Chi ; +double Chi_dVbs , Chi_dVds , Chi_dVgs ; +/* Rho := beta * ( Psl - Vds ) */ +double Rho ; +/* threshold voltage */ +double Vth ; +double Vth0 ; +double Vth0_dVbs , Vth0_dVds , Vth0_dVgs ; +/* variation of threshold voltage */ +double dVth ; +double dVth_dVbs , dVth_dVds , dVth_dVgs ; +double dVth0 ; +double dVth0_dVbs , dVth0_dVds , dVth0_dVgs ; +double dVthSC ; +double dVthSC_dVbs , dVthSC_dVds , dVthSC_dVgs ; +double dVthW ; +double dVthW_dVbs , dVthW_dVds , dVthW_dVgs ; +/* Alpha and related parameters */ +double Alpha ; +double Alpha_dVbs , Alpha_dVds , Alpha_dVgs ; +double Achi ; +double Achi_dVbs , Achi_dVds , Achi_dVgs ; +double VgVt = 0.0 ; +double VgVt_dVbs , VgVt_dVds , VgVt_dVgs ; +double Delta , Vdsat ; +/*-----*/ +/* Q_B and capacitances */ +double Qb , Qb_dVbs , Qb_dVds , Qb_dVgs ; +double Qb_dVbse , Qb_dVdse , Qb_dVgse ; +/* Q_I and capacitances */ +double Qi , Qi_dVbs , Qi_dVds , Qi_dVgs ; +double Qi_dVbse , Qi_dVdse , Qi_dVgse ; +/* Q_D and capacitances */ +double Qd , Qd_dVbs , Qd_dVds , Qd_dVgs ; +double Qd_dVbse , Qd_dVdse , Qd_dVgse ; +/* channel current */ +double Ids ; +double Ids_dVbs , Ids_dVds , Ids_dVgs ; +double Ids_dVbse , Ids_dVdse , Ids_dVgse ; +double Ids0 ; +double Ids0_dVbs , Ids0_dVds , Ids0_dVgs ; +/* (for debug) */ +double user1 , user2 , user3 , user4 ; + +/* constants ------- */ +double beta ; +double beta2 ; +/* device instances */ +double Leff , Leff_inv ; +double Weff ; +double Ldby ; +double Nsub , q_Nsub ; +double Nin ; +double Pb2 ; +double Pb20 ; +double Pb2c ; +double Eg , Eg300 ; +double Vfb ; +/* PART-1 ---------- */ +double Psum ; +double Psum_dVbs ; +double Psum_dVds ; +double sqrt_Psum ; +double cnst0 , cnst1 ; +double fac1 ; +double fac1_dVbs , fac1_dVds , fac1_dVgs ; +double fac1p2 ; +/*-----*/ +double fs01 ; +double fs01_dPs0 , fs01_dChi ; +double fs01_dVbs , fs01_dVds , fs01_dVgs ; +double fs02 ; +double fs02_dPs0 , fs02_dChi ; +double fs02_dVbs , fs02_dVds , fs02_dVgs ; +double fsl1 ; +double fsl1_dPsl ; +double fsl1_dVbs , fsl1_dVds ; +double fsl2 ; +double fsl2_dPsl ; +double fsl2_dVbs , fsl2_dVds ; +double cfs1 ; +double fb , fb_dChi ; +double fi , fi_dChi ; +double exp_Chi , exp_Rho , exp_bVbs , exp_bVbsVds ; +double Fs0, Fsl ; +double Fs0_dPs0 , Fsl_dPsl ; +double dPs0 , dPsl ; +/*-----*/ +double Qn0 ; +double Qn0_dVbs , Qn0_dVds , Qn0_dVgs ; +double Qb0 ; +double Qb0_dVbs , Qb0_dVds , Qb0_dVgs ; +double Qn00 ; +double Qn00_dVbs , Qn00_dVds , Qn00_dVgs ; +/* unused: +* double Qnl ; +*/ +/*-----*/ +double Qbnm ; +double Qbnm_dVbs , Qbnm_dVds , Qbnm_dVgs ; +double DtPds ; +double DtPds_dVbs , DtPds_dVds , DtPds_dVgs ; +/*-----*/ +double Fid2 ; +double Fid2_dVbs , Fid2_dVds , Fid2_dVgs ; +double Fid3 ; +double Fid3_dVbs , Fid3_dVds , Fid3_dVgs ; +double Fid4 ; +double Fid4_dVbs , Fid4_dVds , Fid4_dVgs ; +double Fid5 ; +double Fid5_dVbs , Fid5_dVds , Fid5_dVgs ; +/*-----*/ +double PVds0 ; +double XiVds0 ; +double XiVds0p12 ; +double XiVds0p12_dVbs , XiVds0p12_dVds , XiVds0p12_dVgs ; +double XiVds0p32 ; +double XiVds0p32_dVbs , XiVds0p32_dVds , XiVds0p32_dVgs ; +double Qbm ; +double Qbm_dVbs , Qbm_dVds , Qbm_dVgs ; +/*-----*/ +double Qinm ; +double Qinm_dVbs , Qinm_dVds , Qinm_dVgs ; +double Qidn ; +double Qidn_dVbs , Qidn_dVds , Qidn_dVgs ; +double Qdnm ; +double Qdnm_dVbs , Qdnm_dVds , Qdnm_dVgs ; +double Qddn ; +double Qddn_dVbs , Qddn_dVds , Qddn_dVgs ; +double Quot ; +double Qdrat ; +double Qdrat_dVbs , Qdrat_dVds , Qdrat_dVgs ; +double Idd ; +double Idd_dVbs , Idd_dVds , Idd_dVgs ; +double Qnm ; +double Qnm_dVbs , Qnm_dVds , Qnm_dVgs ; +/*-----*/ +double Fdd ; +double Fdd_dVbs , Fdd_dVds , Fdd_dVgs ; +/*-----*/ +double Eeff ; +double Eeff_dVbs , Eeff_dVds , Eeff_dVgs ; +double Rns ; +double Mu ; +double Mu_dVbs , Mu_dVds , Mu_dVgs ; +double Muun , Muun_dVbs , Muun_dVds , Muun_dVgs ; +double Ey ; +double Ey_dVbs , Ey_dVds , Ey_dVgs ; +double Em ; +double Em_dVbs , Em_dVds , Em_dVgs ; +double Vmax ; +/*-----*/ +double Eta ; +double Eta_dVbs , Eta_dVds , Eta_dVgs ; +double Eta1 , Eta1p12 , Eta1p32 , Eta1p52 ; +double Zeta12 , Zeta32 , Zeta52 ; +/*-----*/ +double F00 ; +double F00_dVbs , F00_dVds , F00_dVgs ; +double F10 ; +double F10_dVbs , F10_dVds , F10_dVgs ; +double F30 ; +double F30_dVbs , F30_dVds , F30_dVgs ; +double F11 ; +double F11_dVbs , F11_dVds , F11_dVgs ; +/*-----*/ +double Ps0_min ; +double Acn , Acd , Ac1 , Ac2 , Ac3 , Ac4 , Ac31 , Ac41 ; +double Acn_dVbs , Acn_dVds , Acn_dVgs ; +double Acd_dVbs , Acd_dVds , Acd_dVgs ; +double Ac1_dVbs , Ac1_dVds , Ac1_dVgs ; +double Ac2_dVbs , Ac2_dVds , Ac2_dVgs ; +double Ac3_dVbs , Ac3_dVds , Ac3_dVgs ; +double Ac4_dVbs , Ac4_dVds , Ac4_dVgs ; +double Ac31_dVbs , Ac31_dVds , Ac31_dVgs ; +/* PART-2 (Isub)---------- */ +double Isub ; +double Isub_dVbs , Isub_dVds , Isub_dVgs ; +double Isub_dVbse , Isub_dVdse , Isub_dVgse ; +double Vdep ; +double Vdep_dVbs , Vdep_dVds , Vdep_dVgs ; +double Epkf ; +double Epkf_dVbs , Epkf_dVds , Epkf_dVgs ; +/**/ +/*-----*/ +/* PART-3 (overlap) */ +double yn , yn2 , yn3 ; +double yn_dVbs , yn_dVds , yn_dVgs ; +double yned , yned2 ; +double yned_dVbs , yned_dVds , yned_dVgs ; +double Lov , Lov2 , Lov23 ; +double Ndsat , Gjnp; +double Qgos , Qgos_dVbs , Qgos_dVds , Qgos_dVgs ; +double Qgos_dVbse , Qgos_dVdse , Qgos_dVgse ; +double Qgod , Qgod_dVbs , Qgod_dVds , Qgod_dVgs ; +double Qgod_dVbse , Qgod_dVdse , Qgod_dVgse ; +double Cggo , Cgdo , Cgso , Cgbo ; +/* fringing capacitance */ +double Cf ; +double Qfd , Qfs ; +/* PART-4 (junction diode) */ +double Ibs , Ibd , Gbs , Gbd , Gbse , Gbde ; +double js ; +double jssw ; +double isbs ; +double isbd ; +double Nvtm ; +/* junction capacitance */ +double Qbs , Qbd , Capbs , Capbd , Capbse , Capbde ; +double czbd , czbdsw , czbdswg , czbs , czbssw , czbsswg ; +double arg , sarg ; +/* PART-5 (noise) */ +/* matsu */ +double NFalp , NFtrp , Freq , Cit , Nflic ; +/* Bias iteration accounting Rs/Rd */ +int lp_bs ; +double Ids_last ; +double vtol_iprv = 2.0e-1 ; +double vtol_pprv = 5.0e-2 ; +double Vbsc_dif , Vdsc_dif , Vgsc_dif , sum_vdif ; +double Rs , Rd ; +double Fbs , Fds , Fgs ; +double DJ , DJI ; +double JI11 , JI12 , JI13 , JI21 , JI22 , JI23 , JI31 , JI32 , JI33 ; +double dVbs , dVds , dVgs ; +double dV_sum ; +/* Junction Bias */ +double Vbsj, Vbdj; +/* Accumulation zone */ +double Psa ; +double Psa_dVbs , Psa_dVds , Psa_dVgs ; +/* CLM */ +double Psdl , Psdl_dVbs , Psdl_dVds , Psdl_dVgs ; +double Ed , Ed_dVbs , Ed_dVds , Ed_dVgs ; +double Ec , Ec_dVbs , Ec_dVds , Ec_dVgs ; +double Lred , Lred_dVbs , Lred_dVds , Lred_dVgs ; +double Wd , Wd_dVbs , Wd_dVds , Wd_dVgs ; +double Aclm ; +/* Pocket Implant */ +double Vthp, Vthp_dVbs, Vthp_dVds, Vthp_dVgs ; +double dVthLP,dVthLP_dVbs,dVthLP_dVds,dVthLP_dVgs ; +double LEY ; +/* Poly-Depletion Effect */ +double dPpg , dPpg_dVds , dPpg_dVgs ; +/* Quantum Effect */ +double Tox , Tox_dVbs , Tox_dVds , Tox_dVgs ; +double dTox , dTox_dVbs , dTox_dVds , dTox_dVgs ; +double Cox , Cox_dVbs , Cox_dVds , Cox_dVgs ; +double Cox_inv , Cox_inv_dVbs , Cox_inv_dVds , Cox_inv_dVgs ; +double Vthq, Vthq_dVbs , Vthq_dVds ; +/* Igs , Ilg */ +double Egp12 , Egp32 ; +double E0 ; +double E1 , E1_dVbs , E1_dVds , E1_dVgs ; +double E2 , E2_dVbs , E2_dVds , E2_dVgs ; +double Etun , Etun_dVbs , Etun_dVds , Etun_dVgs ; +double Egidl , Egidl_dVbs , Egidl_dVds , Egidl_dVgs ; +double Igs , Igs_dVbs , Igs_dVds , Igs_dVgs ; +double Igs_dVbse , Igs_dVdse , Igs_dVgse ; +double Ilg , Ilg_dVbs , Ilg_dVds , Ilg_dVgs ; +double Ilg_dVbse , Ilg_dVdse , Ilg_dVgse ; +double Cox0 ; +double Lgate ; +double rp1 , rp1_dVds ; +/* connecting function */ +double FD2 , FD2_dVbs , FD2_dVds , FD2_dVgs ; +double FMD , FMD_dVds ; +/* Phonon scattering */ +double Wgate ; +double mueph ; +/* temporary vars.-- */ +double T0 , T1 , T2 , T3 , T4 , T5 , T6 , T7 , T8 , T9 ; +double TX , TX_dVbs , TX_dVds , TX_dVgs ; +double TY , TY_dVbs , TY_dVds , TY_dVgs ; +double T1_dVbs , T1_dVds , T1_dVgs ; +double T2_dVbs , T2_dVds , T2_dVgs ; +double T3_dVbs , T3_dVds , T3_dVgs ; +double T4_dVbs , T4_dVds , T4_dVgs ; +double T5_dVbs , T5_dVds , T5_dVgs ; +double T6_dVbs , T6_dVds , T6_dVgs ; +double T7_dVbs , T7_dVds , T7_dVgs ; +double T8_dVbs , T8_dVds , T8_dVgs ; +double T9_dVbs , T9_dVds , T9_dVgs ; +double T10 , T20 , T21 , T30 , T31 ; + +/* intrinsic finging capacitance */ +double Cgdf, Cgdfring; + + +/*================ Start of executable code.=================*/ + + flg_info = sIN.info ; + +/*-----------------------------------------------------------* +* Change units into CGS. +* - This section may be moved to an interface routine. +*-----------------*/ + +/* device instances */ + sIN.xl *= C_m2cm ; + sIN.xw *= C_m2cm ; + sIN.as *= C_m2cm_p2 ; + sIN.ad *= C_m2cm_p2 ; + sIN.ps *= C_m2cm ; + sIN.pd *= C_m2cm ; + +/* model parameters */ + sIN.tox *= C_m2cm ; + sIN.xld *= C_m2cm ; + sIN.xwd *= C_m2cm ; + + sIN.xj *= C_m2cm ; + + sIN.lp *= C_m2cm ; + sIN.xpolyd *= C_m2cm ; + sIN.tpoly *= C_m2cm ; + + sIN.rs *= C_m2cm ; + sIN.rd *= C_m2cm ; + + sIN.sc3 *= C_m2cm ; + sIN.scp3 *= C_m2cm ; + sIN.parl2 *= C_m2cm ; + + sIN.wfc *= C_m2cm ; + sIN.clm2 /= C_m2cm ; + + sIN.rpock1 *= C_m2cm_p1o2 ; + + sIN.qme1 *= C_m2cm ; + sIN.qme3 *= C_m2cm ; + + sIN.gidl1 /= C_m2cm ; + + sIN.gleak1 /= C_m2cm ; + + sIN.cgso /= C_m2cm ; + sIN.cgdo /= C_m2cm ; + sIN.cgbo /= C_m2cm ; + + sIN.js0 /= C_m2cm_p2 ; + sIN.js0sw /= C_m2cm ; + + sIN.cj /= C_m2cm_p2 ; + sIN.cjsw /= C_m2cm ; + sIN.cjswg /= C_m2cm ; + +/*-----------------------------------------------------------* +* Start of the routine. (label) +*-----------------*/ +start_of_routine: + + + +/*-----------------------------------------------------------* +* Temperature dependent constants. +*-----------------*/ + +/* Inverse of the thermal voltage */ + beta = C_QE / ( C_KB * sIN.temp ) ; + beta2 = beta * beta ; + +/* Band gap */ + Eg = C_Eg0 - sIN.temp + * ( sIN.bgtmp1 + sIN.temp * sIN.bgtmp2 ) ; + + Eg300 = C_Eg0 - C_T300 + * ( sIN.bgtmp1 + C_T300 * sIN.bgtmp2 ) ; + +/* Intrinsic carrier concentration */ + Nin = C_Nin0 * pow( sIN.temp / C_T300 , 1.5e0 ) + * exp( - Eg / 2.0e0 * beta + Eg300 / 2.0e0 * C_b300 ) ; + +/*-----------------------------------------------------------* +* Fixed part. +*-----------------*/ + + +/* Lgate in [cm] / [m] */ + Lgate = sIN.xl ; + Wgate = sIN.xw ; + +/* Phonon Scattering */ + T1 = log( Wgate ) ; + T2 = sIN.w0 - T1 - sti_dlt ; + T3 = T2 * T2 ; + T4 = sqrt( T3 + 4.0 * sti_dlt * sIN.w0 ) ; + T5 = sIN.w0 - ( T2 - T4 ) / 2 ; + mueph = sIN.mueph1 + sIN.mueph2 * T5 ; + +/* Metallurgical channel geometry */ + Weff = sIN.xw - 2.0e0 * sIN.xwd ; + Leff = sIN.xl - 2.0e0 * sIN.xld ; + Leff_inv = 1.0e0 / Leff ; + +/* Flat band voltage */ + Vfb = sIN.vfbc ; + +/* Surface impurity profile */ + + if( Lgate > sIN.lp ){ + Nsub = ( sIN.nsubc * ( Lgate - sIN.lp ) + + sIN.nsubp * sIN.lp ) / Lgate ; + } else { + Nsub = sIN.nsubp + + ( sIN.nsubp - sIN.nsubc ) * ( sIN.lp - Lgate ) / sIN.lp ; + } + + q_Nsub = C_QE * Nsub ; + +/* 2 phi_B */ + /* @temp, with pocket */ + Pb2 = 2.0e0 / beta * log( Nsub / Nin ); + /* @300K, with pocket */ + Pb20 = 2.0e0 / C_b300 * log( Nsub / C_Nin0 ) ; + /* @300K, w/o pocket */ + Pb2c = 2.0e0 / C_b300 * log( sIN.nsubc / C_Nin0 ) ; + +/* Debye length */ + Ldby = sqrt( C_ESI / beta / q_Nsub ) ; + +/* Coefficient of the F function for bulk charge */ + cnst0 = q_Nsub * Ldby * C_SQRT_2 ; + +/* cnst1: n_{p0} / p_{p0} */ + T1 = Nin / Nsub ; + cnst1 = T1 * T1 ; +/* Cox (clasical) */ + Cox0 = C_EOX / sIN.tox ; + + + +/*-----------------------------------------------------------* +* Exchange bias conditions according to MOS type. +* - Vxse are external biases for HiSIM. ( type=NMOS , Vds >= 0 +* are assumed.) +*-----------------*/ + + /* + Vbse = sIN.type * sIN.vbs ; + Vdse = sIN.type * sIN.vds ; + Vgse = sIN.type * sIN.vgs ; + Vbde = Vbse - Vdse ; + */ + /* modified by K. M. for SPICE3f5 */ + Vbse = sIN.vbs; + Vdse = sIN.vds; + Vgse = sIN.vgs; + Vbde = Vbse - Vdse; + + +/*---------------------------------------------------* +* Cramp too large biases. +* -note: Quantities are extrapolated in PART-5. +*-----------------*/ + + if ( Vbse < Vbs_min ) { + flg_vbsc = -1 ; + Vbsc = Vbs_min ; + } else if ( Vbse > 0.0 ) { + flg_vbsc = 1 ; + T1 = Vbse / Vbs_max ; + T2 = sqrt ( 1.0 + ( T1 * T1 ) ) ; + Vbsc = Vbse / T2 ; + Vbsc_dVbse = Vbs_max * Vbs_max + / ( ( Vbs_max * Vbs_max + Vbse * Vbse ) * T2 ) ; + } else { + flg_vbsc = 0 ; + Vbsc = Vbse ; + } + + + if ( Vdse > Vds_max ) { + flg_vdsc = 1 ; + Vdsc = Vds_max ; + } else { + flg_vdsc = 0 ; + Vdsc = Vdse ; + } + + if ( Vgse > Vgs_max ) { + flg_vgsc = 1 ; + Vgsc = Vgs_max ; + } else { + flg_vgsc = 0 ; + Vgsc = Vgse ; + } + + if ( Vbde < Vbd_min ) { + flg_vbdc = -1 ; + Vbdc = Vbd_min ; + } else if ( Vbde > Vbd_max ) { + Vbdc = Vbd_max ; + flg_vbdc = 1 ; + } else { + Vbdc = Vbde ; + flg_vbdc = 0 ; + } + + if ( flg_vbsc == -1 || flg_vdsc != 0 || flg_vgsc != 0 || + flg_vbdc != 0 ) { + flg_vxxc = 1 ; + } + + +/*-------------------------------------------------------------------* +* Set flags. +*-----------------*/ + + flg_rsrd = 0 ; + flg_iprv = 0 ; + flg_pprv = 0 ; + + Rs = sIN.rs / Weff ; + Rd = sIN.rd / Weff ; + + if ( Rs + Rd >= epsm10 && sIN.corsrd >= 1 ) { + flg_rsrd = 1 ; + } + + if ( sIN.has_prv == 1 ) { + + Vbsc_dif = Vbsc - sIN.vbsc_prv ; + Vdsc_dif = Vdsc - sIN.vdsc_prv ; + Vgsc_dif = Vgsc - sIN.vgsc_prv ; + + sum_vdif = fabs( Vbsc_dif ) + fabs( Vdsc_dif ) + + fabs( Vgsc_dif ) ; + + if ( sIN.coiprv >= 1 && sum_vdif <= vtol_iprv ) { flg_iprv = 1 ;} + if ( sIN.copprv >= 1 && sum_vdif <= vtol_pprv ) { flg_pprv = 1 ;} + } + + if ( flg_rsrd == 0 ) { + lp_bs_max = 1 ; + flg_iprv = 0 ; + } + + + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++* +* Bias loop: iteration to solve the system of equations of +* the small circuit taking account Rs and Rd. +* - Vxs are internal (or effective) biases. +* - Equations: +* Vbs = Vbsc - Rs * Ids +* Vds = Vdsc - ( Rs + Rd ) * Ids +* Vgs = Vgsc - Rs * Ids +*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + +/*-----------------------------------------------------------* +* Initial guesses for biases. +*-----------------*/ + + if ( flg_iprv == 1 ) { + + sIN.ids_dvbs_prv = Fn_Max( 0.0 , sIN.ids_dvbs_prv ) ; + sIN.ids_dvds_prv = Fn_Max( 0.0 , sIN.ids_dvds_prv ) ; + sIN.ids_dvgs_prv = Fn_Max( 0.0 , sIN.ids_dvgs_prv ) ; + + dVbs = Vbsc_dif * ( 1.0 - + 1.0 / ( 1.0 + Rs * sIN.ids_dvbs_prv ) ) ; + dVds = Vdsc_dif * ( 1.0 - + 1.0 / ( 1.0 + ( Rs + Rd ) * sIN.ids_dvds_prv ) ) ; + dVgs = Vgsc_dif * ( 1.0 - + 1.0 / ( 1.0 + Rs * sIN.ids_dvgs_prv ) ) ; + + /* + Ids = sIN.type * sIN.ids_prv + + sIN.ids_dvbs_prv * dVbs + + sIN.ids_dvds_prv * dVds + + sIN.ids_dvgs_prv * dVgs ; + */ + Ids = sIN.ids_prv + + sIN.ids_dvbs_prv * dVbs + + sIN.ids_dvds_prv * dVds + + sIN.ids_dvgs_prv * dVgs ; + + T1 = ( Ids - sIN.ids_prv ) ; + T2 = fabs( T1 ) ; + if ( Ids_maxvar * sIN.ids_prv < T2 ) { + Ids = sIN.ids_prv * ( 1.0 + Fn_Sgn( T1 ) * Ids_maxvar ) ; + } + + if ( Ids < 0 ) { + Ids = 0.0 ; + } + + } else { + Ids = 0.0 ; + + if ( flg_pprv == 1 ) { + dVbs = Vbsc_dif ; + dVds = Vdsc_dif ; + dVgs = Vgsc_dif ; + } + } + + Vbs = Vbsc - Ids * Rs ; + + Vds = Vdsc - Ids * ( Rs + Rd ) ; + if ( Vds * Vdsc <= 0.0 ) { Vds = 0.0 ; } + + Vgs = Vgsc - Ids * Rs ; + + if ( flg_pprv == 1 ) { + + Ps0 = sIN.ps0_prv ; + + Ps0_dVbs = sIN.ps0_dvbs_prv ; + Ps0_dVds = sIN.ps0_dvds_prv ; + Ps0_dVgs = sIN.ps0_dvgs_prv ; + + Pds = sIN.pds_prv ; + + Pds_dVbs = sIN.pds_dvbs_prv ; + Pds_dVds = sIN.pds_dvds_prv ; + Pds_dVgs = sIN.pds_dvgs_prv ; + } + + +/*-----------------------------------------------------------* +* start of the loop. +*-----------------*/ + + for ( lp_bs = 1 ; lp_bs <= lp_bs_max ; lp_bs ++ ) { + + + Ids_last = Ids ; + + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +* PART-1: Basic device characteristics. +*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + +/*-----------------------------------------------------------* +* Initialization. +*-----------------*/ + /* Initialization of counters is needed for restart. */ + lp_s0 = 0 ; + lp_sl = 0 ; + +/*-----------------------------------------------------------* +* Vxsz: Modified bias introduced to realize symmetry at Vds=0. +*-----------------*/ + + T1 = exp( - Vbsc_dVbse * Vds / ( 2.0 * sIN.vzadd0 ) ) ; + Vzadd = sIN.vzadd0 * T1 ; + Vzadd_dVds = - 0.5 * Vbsc_dVbse * T1 ; + + + if ( Vzadd < ps_conv ) { + Vzadd = 0.0 ; + Vzadd_dVds = 0.0 ; + } + + Vbsz = Vbs + Vzadd ; + Vbsz_dVbs = 1.0 ; + Vbsz_dVds = Vzadd_dVds ; + + Vdsz = Vds + 2 * Vzadd ; + Vdsz_dVds = 1.0 + 2 * Vzadd_dVds ; + + Vgsz = Vgs + Vzadd ; + Vgsz_dVgs = 1.0 ; + Vgsz_dVds = Vzadd_dVds ; + + +/*-----------------------------------------------------------* +* Quantum effect +*-----------------*/ + + T1 = 2.0 * q_Nsub * C_ESI ; + T2 = sqrt( T1 * ( Pb20 - Vbsz ) ) ; + + Vthq = Pb20 + Vfb + sIN.tox / C_EOX * T2 + sIN.qme2 ; + + T3 = - 0.5 * sIN.tox / C_EOX * T1 / T2 ; + Vthq_dVbs = T3 * Vbsz_dVbs ; + Vthq_dVds = T3 * Vbsz_dVds ; + + + T1 = - Vfb - sIN.qme2 ; + T2 = Vgsz - Vthq ; + T3 = sIN.qme1 * T1 * T1 + sIN.qme3 ; + T4 = sIN.qme1 * T2 * T2 + sIN.qme3 ; + + T5 = T4 - T3 - qme_dlt ; + + T6 = sqrt( T5 * T5 + 4.0 * qme_dlt * T4 ) ; + + dTox = T4 - 0.5 * ( T5 + T6 ) ; + + /* dTox_dT4 */ + T7 = 1.0 - 0.5 * ( 1.0 + ( T4 - T3 + qme_dlt ) / T6 ) ; + + T8 = 2.0 * sIN.qme1 * T2 * T7 ; + + dTox_dVbs = T8 * ( - Vthq_dVbs ) ; + dTox_dVds = T8 * ( Vgsz_dVds - Vthq_dVds ) ; + dTox_dVgs = T8 * ( Vgsz_dVgs ) ; + + Tox = sIN.tox + dTox ; + Tox_dVbs = dTox_dVbs ; + Tox_dVds = dTox_dVds ; + Tox_dVgs = dTox_dVgs ; + + Cox = C_EOX / Tox ; + T1 = - C_EOX / ( Tox * Tox ) ; + Cox_dVbs = T1 * Tox_dVbs ; + Cox_dVds = T1 * Tox_dVds ; + Cox_dVgs = T1 * Tox_dVgs ; + + Cox_inv = Tox / C_EOX ; + T1 = 1.0 / C_EOX ; + Cox_inv_dVbs = T1 * Tox_dVbs ; + Cox_inv_dVds = T1 * Tox_dVds ; + Cox_inv_dVgs = T1 * Tox_dVgs ; + + +/*-----------------------------------------------------------* +* Threshold voltage. +*-----------------*/ + + Delta = 0.1 ; + + Vbs1 = 2.0 - 0.25 * Vbsz ; + Vbs2 = - Vbsz ; + + Vbsd = Vbs1 - Vbs2 - Delta ; + Vbsd_dVbs = 0.75 * Vbsz_dVbs ; + Vbsd_dVds = 0.75 * Vbsz_dVds ; + + T1 = sqrt( Vbsd * Vbsd + 4.0 * Delta ) ; + + Vbszm = - Vbs1 + 0.5 * ( Vbsd + T1 ) ; + Vbszm_dVbs = 0.25 * Vbsz_dVbs + + 0.5 * ( Vbsd_dVbs + Vbsd * Vbsd_dVbs / T1 ) ; + Vbszm_dVds = 0.25 * Vbsz_dVds + + 0.5 * ( Vbsd_dVds + Vbsd * Vbsd_dVds / T1 ) ; + + Psum = ( Pb20 - Vbsz ) ; + + if ( Psum >= epsm10 ) { + Psum_dVbs = - Vbsz_dVbs ; + Psum_dVds = - Vbsz_dVds ; + } else { + Psum = epsm10 ; + Psum_dVbs = 0.0e0 ; + Psum_dVds = 0.0e0 ; + } + + sqrt_Psum = sqrt( Psum ) ; + + + +/*---------------------------------------------------* +* Vthp : Vth with pocket. +*-----------------*/ + + T1 = 2.0 * q_Nsub * C_ESI ; + Qb0 = sqrt( T1 * ( Pb20 - Vbsz ) ) ; + + Qb0_dVbs = 0.5 * T1 / Qb0 * ( - Vbsz_dVbs ) ; + Qb0_dVds = 0.5 * T1 / Qb0 * ( - Vbsz_dVds ) ; + + Vthp = Pb20 + Vfb + Qb0 * Cox_inv ; + + Vthp_dVbs = Qb0_dVbs * Cox_inv + Qb0 * Cox_inv_dVbs ; + Vthp_dVds = Qb0_dVds * Cox_inv + Qb0 * Cox_inv_dVds ; + Vthp_dVgs = Qb0 * Cox_inv_dVgs ; + +/*-------------------------------------------* +* dVthLP : Short-channel effect induced by pocket. +* - Vth0 : Vth without pocket. +*-----------------*/ + + if ( sIN.lp != 0.0 ) { + + T1 = 2.0 * C_QE * sIN.nsubc * C_ESI ; + T2 = sqrt( T1 * ( Pb2c - Vbsz ) ) ; + + Vth0 = Pb2c + Vfb + T2 * Cox_inv ; + + Vth0_dVbs = 0.5 * T1 / T2 * ( - Vbsz_dVbs ) * Cox_inv + + T2 * Cox_inv_dVbs ; + Vth0_dVds = 0.5 * T1 / T2 * ( - Vbsz_dVds ) * Cox_inv + + T2 * Cox_inv_dVds ; + Vth0_dVgs = T2 * Cox_inv_dVgs ; + + LEY = sIN.parl1 * sIN.lp ; + + T1 = C_ESI * Cox_inv ; + T2 = sqrt( 2.0e0 * C_ESI / C_QE / sIN.nsubp ) ; + T4 = 1.0e0 / ( LEY * LEY ) ; + T5 = 2.0e0 * ( C_Vbi - Pb20 ) * T1 * T2 * T4 ; + + dVth0 = T5 * sqrt_Psum ; + + T6 = 0.5 * T5 / sqrt_Psum ; + T7 = 2.0e0 * ( C_Vbi - Pb20 ) * C_ESI * T2 * T4 * sqrt_Psum ; + dVth0_dVbs = T6 * Psum_dVbs + T7 * Cox_inv_dVbs ; + dVth0_dVds = T6 * Psum_dVds + T7 * Cox_inv_dVds ; + dVth0_dVgs = T7 * Cox_inv_dVgs ; + + T1 = Vthp - Vth0 ; + T2 = sIN.scp1 + sIN.scp3 * Psum / sIN.lp ; + T3 = T2 + sIN.scp2 * Vdsz ; + + dVthLP = T1 * dVth0 * T3 ; + + dVthLP_dVbs = ( Vthp_dVbs - Vth0_dVbs ) * dVth0 * T3 + + T1 * dVth0_dVbs * T3 + + T1 * dVth0 * sIN.scp3 * Psum_dVbs / sIN.lp ; + dVthLP_dVds = ( Vthp_dVds - Vth0_dVds ) * dVth0 * T3 + + T1 * dVth0_dVds * T3 + + T1 * dVth0 + * ( sIN.scp3 * Psum_dVds / sIN.lp + + sIN.scp2 * Vdsz_dVds ) ; + + dVthLP_dVgs = ( Vthp_dVgs - Vth0_dVgs ) * dVth0 * T3 + + T1 * dVth0_dVgs * T3 ; + + } else { + dVthLP = 0.0e0 ; + dVthLP_dVbs = 0.0e0 ; + dVthLP_dVds = 0.0e0 ; + dVthLP_dVgs = 0.0e0 ; + } + +/*---------------------------------------------------* +* dVthSC : Short-channel effect induced by Vds. +*-----------------*/ + + T1 = C_ESI * Cox_inv ; + T2 = sqrt( 2.0e0 * C_ESI / q_Nsub ) ; + T3 = sIN.parl1 * ( Lgate - sIN.parl2 ) ; + T4 = 1.0e0 / ( T3 * T3 ) ; + T5 = 2.0e0 * ( C_Vbi - Pb20 ) * T1 * T2 * T4 ; + + dVth0 = T5 * sqrt_Psum ; + T6 = T5 / 2 / sqrt_Psum ; + T7 = 2.0e0 * ( C_Vbi - Pb20 ) * C_ESI * T2 * T4 * sqrt_Psum ; + dVth0_dVbs = T6 * Psum_dVbs + T7 * Cox_inv_dVbs ; + dVth0_dVds = T6 * Psum_dVds + T7 * Cox_inv_dVds ; + dVth0_dVgs = T7 * Cox_inv_dVgs ; + + + T4 = sIN.sc1 + sIN.sc3 * Psum / Lgate ; + T4_dVbs = sIN.sc3 * Psum_dVbs / Lgate ; + T4_dVds = sIN.sc3 * Psum_dVds / Lgate ; + + T5 = sIN.sc2 ; + + dVthSC = dVth0 * ( T4 + T5 * Vdsz ) ; + + dVthSC_dVbs = dVth0_dVbs * ( T4 + T5 * Vdsz ) + + dVth0 * ( T4_dVbs ) ; + + dVthSC_dVds = dVth0_dVds * ( T4 + T5 * Vdsz ) + + dVth0 * ( T4_dVds + T5 * Vdsz_dVds ) ; + + dVthSC_dVgs = dVth0_dVgs * ( T4 + T5 * Vdsz ) ; + +/*---------------------------------------------------* +* dVthW : narrow-channel effect. +*-----------------*/ + + T1 = 1.0 / Cox ; + T2 = T1 * T1 ; + T3 = 1.0 / ( Cox + sIN.wfc / Weff ) ; + T4 = T3 * T3 ; + + dVthW = Qb0 * ( T1 - T3 ) ; + + dVthW_dVbs = Qb0_dVbs * ( T1 - T3 ) + - Qb0 * Cox_dVbs * ( T2 - T4 ) ; + dVthW_dVds = Qb0_dVds * ( T1 - T3 ) + - Qb0 * Cox_dVds * ( T2 - T4 ) ; + dVthW_dVgs = - Qb0 * Cox_dVgs * ( T2 - T4 ) ; + +/*---------------------------------------------------* +* dVth : Total variation. +* - Positive dVth means the decrease in Vth. +*-----------------*/ + + dVth = dVthSC + dVthLP + dVthW ; + dVth_dVbs = dVthSC_dVbs + dVthLP_dVbs + dVthW_dVbs ; + dVth_dVds = dVthSC_dVds + dVthLP_dVds + dVthW_dVds ; + dVth_dVgs = dVthSC_dVgs + dVthLP_dVgs + dVthW_dVgs ; + + + +/*---------------------------------------------------* +* Vth : Threshold voltage. +*-----------------*/ + + Vth = Vthp - dVth ; + +/*---------------------------------------------------* +* Poly-Depletion Effect +*-----------------*/ + + +/*---------------------------------------------------* +* Poly-Depletion Effect +*-----------------*/ + + dPpg = Nsub / sIN.nsubc * sIN.pgd1 + * exp( Vgsz - sIN.pgd2 - sIN.pgd3 * Vdsz ) ; + dPpg_dVds = - sIN.pgd3 * dPpg * Vdsz_dVds + + dPpg * Vgsz_dVds ; + dPpg_dVgs = dPpg * Vgsz_dVgs ; + + T1 = 1.0e0 - dPpg - pol_dlt ; + T1_dVds = - dPpg_dVds ; + T1_dVgs = - dPpg_dVgs ; + T2 = sqrt( T1 * T1 + 4.0e0 * pol_dlt ) ; + + dPpg = 1.0e0 - 0.5e0 * ( T1 + T2 ) ; + dPpg_dVds = - 0.5e0 * ( T1_dVds + T1 * T1_dVds / T2 ) ; + dPpg_dVgs = - 0.5e0 * ( T1_dVgs + T1 * T1_dVgs / T2 ) ; + + + +/*---------------------------------------------------* +* Vgp : Effective gate bias with SCE & RSCE & flatband. +*-----------------*/ + + Vgp = Vgs - Vfb + dVth - dPpg ; + + Vgp_dVbs = dVth_dVbs ; + Vgp_dVds = dVth_dVds - dPpg_dVds ; + Vgp_dVgs = 1.0e0 + dVth_dVgs - dPpg_dVgs ; + +/*---------------------------------------------------* +* Vgs_fb : Actual flatband voltage taking account Vbs. +* - note: if Vgs == Vgs_fb then Vgp == Ps0 == Vbs . +*------------------*/ + + Vgs_fb = Vfb - dVth + dPpg + Vbs ; + + + +/*-----------------------------------------------------------* +* Constants in the equation of Ps0 . +*-----------------*/ + + fac1 = cnst0 * Cox_inv ; + fac1_dVbs = cnst0 * Cox_inv_dVbs ; + fac1_dVds = cnst0 * Cox_inv_dVds ; + fac1_dVgs = cnst0 * Cox_inv_dVgs ; + + fac1p2 = fac1 * fac1 ; + +/*-----------------------------------------------------------* +* Accumulation zone. (zone-A) +* - evaluate basic characteristics and exit from this part. +*-----------------*/ + + if ( Vgs < Vgs_fb ) { + + +/*---------------------------------------------------* +* Evaluation of Ps0. +* - Psa : Analytical solution of +* Cox( Vgp - Psa ) = cnst0 * Qacc +* where Qacc is the 3-dgree series of (fdep)^{1/2}. +* The unkown is transformed to Chi=beta(Ps0-Vbs). +* - Ps0_min : |Ps0_min| when Vbs=0. +*-----------------*/ + + Ps0_min = Eg - Pb2 ; + + TX = beta * ( Vgp - Vbs ) ; + + TX_dVbs = beta * ( Vgp_dVbs - 1.0 ) ; + TX_dVds = beta * Vgp_dVds ; + TX_dVgs = beta * Vgp_dVgs ; + + TY = Cox / ( beta * cnst0 ) ; + + T1 = 1.0 / ( beta * cnst0 ) ; + TY_dVbs = T1 * Cox_dVbs ; + TY_dVds = T1 * Cox_dVds ; + TY_dVgs = T1 * Cox_dVgs ; + + Ac41 = 2.0 + 3.0 * C_SQRT_2 * TY ; + + Ac4 = 8.0 * Ac41 * Ac41 * Ac41 ; + + T1 = 72.0 * Ac41 * Ac41 * C_SQRT_2 ; + Ac4_dVbs = T1 * TY_dVbs ; + Ac4_dVds = T1 * TY_dVds ; + Ac4_dVgs = T1 * TY_dVgs ; + + Ac31 = 7.0 * C_SQRT_2 - 9.0 * TY * ( TX - 2.0 ) ; + Ac31_dVbs = - 9.0 * ( TY_dVbs * ( TX - 2.0 ) + TY * TX_dVbs ) ; + Ac31_dVds = - 9.0 * ( TY_dVds * ( TX - 2.0 ) + TY * TX_dVds ) ; + Ac31_dVgs = - 9.0 * ( TY_dVgs * ( TX - 2.0 ) + TY * TX_dVgs ) ; + + Ac3 = Ac31 * Ac31 ; + + Ac3_dVbs = 2.0 * Ac31 * Ac31_dVbs ; + Ac3_dVds = 2.0 * Ac31 * Ac31_dVds ; + Ac3_dVgs = 2.0 * Ac31 * Ac31_dVgs ; + + Ac2 = sqrt( Ac4 + Ac3 ) ; + Ac2_dVbs = 0.5 * ( Ac4_dVbs + Ac3_dVbs ) / Ac2 ; + Ac2_dVds = 0.5 * ( Ac4_dVds + Ac3_dVds ) / Ac2 ; + Ac2_dVgs = 0.5 * ( Ac4_dVgs + Ac3_dVgs ) / Ac2 ; + + Ac1 = -7.0 * C_SQRT_2 + + Ac2 + 9.0 * TY * ( TX - 2.0 ) ; + + Ac1_dVbs = Ac2_dVbs + + 9.0 * ( TY_dVbs * ( TX - 2.0 ) + TY * TX_dVbs ) ; + Ac1_dVds = Ac2_dVds + + 9.0 * ( TY_dVds * ( TX - 2.0 ) + TY * TX_dVds ) ; + Ac1_dVgs = Ac2_dVgs + + 9.0 * ( TY_dVgs * ( TX - 2.0 ) + TY * TX_dVgs ) ; + + Acd = pow( Ac1 , C_1o3 ) ; + + T1 = C_1o3 / ( Acd * Acd ) ; + Acd_dVbs = Ac1_dVbs * T1 ; + Acd_dVds = Ac1_dVds * T1 ; + Acd_dVgs = Ac1_dVgs * T1 ; + + Acn = -4.0 * C_SQRT_2 - 12.0 * TY + + 2.0 * Acd + C_SQRT_2 * Acd * Acd ; + + Acn_dVbs = - 12.0 * TY_dVbs + + ( 2.0 + 2.0 * C_SQRT_2 * Acd ) * Acd_dVbs ; + Acn_dVds = - 12.0 * TY_dVds + + ( 2.0 + 2.0 * C_SQRT_2 * Acd ) * Acd_dVds ; + Acn_dVgs = - 12.0 * TY_dVgs + + ( 2.0 + 2.0 * C_SQRT_2 * Acd ) * Acd_dVgs ; + + Chi = Acn / Acd ; + + T1 = 1.0 / ( Acd * Acd ) ; + + Chi_dVbs = ( Acn_dVbs * Acd - Acn * Acd_dVbs ) * T1 ; + Chi_dVds = ( Acn_dVds * Acd - Acn * Acd_dVds ) * T1 ; + Chi_dVgs = ( Acn_dVgs * Acd - Acn * Acd_dVgs ) * T1 ; + + Psa = Chi / beta + Vbs ; + + Psa_dVbs = Chi_dVbs / beta + 1.0 ; + Psa_dVds = Chi_dVds / beta ; + Psa_dVgs = Chi_dVgs / beta ; + + T1 = Psa - Vbs ; + T2 = T1 / Ps0_min ; + T3 = sqrt( 1.0 + ( T2 * T2 ) ) ; + + T9 = T2 / T3 / Ps0_min ; + T3_dVbs = T9 * ( Psa_dVbs - 1.0 ) ; + T3_dVds = T9 * ( Psa_dVds ) ; + T3_dVgs = T9 * ( Psa_dVgs ) ; + + Ps0 = T1 / T3 + Vbs ; + + T9 = 1.0 / ( T3 * T3 ) ; + + Ps0_dVbs = T9 * ( ( Psa_dVbs - 1.0 ) * T3 - T1 * T3_dVbs ) + + 1.0 ; + Ps0_dVds = T9 * ( Psa_dVds * T3 - T1 * T3_dVds ) ; + Ps0_dVgs = T9 * ( Psa_dVgs * T3 - T1 * T3_dVgs ) ; + + + +/*---------------------------------------------------* +* Characteristics. +*-----------------*/ + + T0 = - Weff * Leff ; + T1 = T0 * Cox ; + T2 = ( Vgp - Ps0 ) ; + + Qb = T1 * T2 ; + + Qb_dVbs = T1 * ( Vgp_dVbs - Ps0_dVbs ) + + T0 * Cox_dVbs * T2 ; + Qb_dVds = T1 * ( Vgp_dVds - Ps0_dVds ) + + T0 * Cox_dVds * T2 ; + Qb_dVgs = T1 * ( Vgp_dVgs - Ps0_dVgs ) + + T0 * Cox_dVgs * T2 ; + + Psl = Ps0 ; + Psl_dVbs = Ps0_dVbs ; + Psl_dVds = Ps0_dVds ; + Psl_dVgs = Ps0_dVgs ; + + Psdl = Psl ; + Psdl_dVbs = Psl_dVbs ; + Psdl_dVds = Psl_dVds ; + Psdl_dVgs = Psl_dVgs ; + + Qi = 0.0e0 ; + Qi_dVbs = 0.0e0 ; + Qi_dVds = 0.0e0 ; + Qi_dVgs = 0.0e0 ; + + Qd = 0.0e0 ; + Qd_dVbs = 0.0e0 ; + Qd_dVds = 0.0e0 ; + Qd_dVgs = 0.0e0 ; + + Ids = 0.0e0 ; + Ids_dVbs = 0.0e0 ; + Ids_dVds = 0.0e0 ; + Ids_dVgs = 0.0e0 ; + + VgVt = 0.0 ; + + flg_noqi = 1 ; + + goto end_of_part_1 ; + + } + +/*-----------------------------------------------------------* +* Initial guess for Ps0. +*-----------------*/ + +/*---------------------------------------------------* +* Ps0_iniA: solution of subthreshold equation assuming zone-D1/D2. +*-----------------*/ + + TX = 1.0e0 + 4.0e0 + * ( beta * ( Vgp - Vbs ) - 1.0e0 ) / ( fac1p2 * beta2 ) ; + TX = Fn_Max( TX , epsm10 ) ; + + Ps0_iniA = Vgp + + fac1p2 * beta / 2.0e0 * ( 1.0e0 - sqrt( TX ) ) ; + + +/*---------------------------------------------------* +* Use previous value. +*-----------------*/ + if ( flg_pprv == 1 ) { + + Ps0_ini = Ps0 + Ps0_dVbs * dVbs + + Ps0_dVds * dVds + Ps0_dVgs * dVgs ; + + T1 = Ps0_ini - Ps0 ; + + if ( T1 < - dP_max || T1 > dP_max ) { + flg_pprv = 0 ; + } else { + Ps0_iniA = Fn_Max( Ps0_ini , Ps0_iniA ) ; + } + + } + +/*---------------------------------------------------* +* Analytical initial guess. +*-----------------*/ + if ( flg_pprv == 0 ) { +/*-------------------------------------------* +* Common part. +*-----------------*/ + + Chi = beta * ( Ps0_iniA - Vbs ) ; + +/*-----------------------------------* +* zone-D1/D2 +* - Ps0_ini is the analytical solution of Qs=Qb0 with +* Qb0 being approximated to 3-degree polynomial. +*-----------------*/ + if ( Chi < znbd3 ) { + + TY = beta * ( Vgp - Vbs ) ; + T1 = 1.0e0 / ( cn_nc3 * beta * fac1 ) ; + T2 = 81 + 3 * T1 ; + T3 = -2916 - 81 * T1 + 27 * T1 * TY ; + T4 = 1458 - 81 * ( 54 + T1 ) + 27 * T1 * TY ; + T4 = T4 * T4 ; + T5 = pow( T3 + sqrt( 4 * T2 * T2 * T2 + T4 ) , C_1o3 ) ; + TX = 3 + - ( C_2p_1o3 * T2 ) / ( 3 * T5 ) + + 1 / ( 3 * C_2p_1o3 ) * T5 ; + + Ps0_iniA = TX / beta + Vbs ; + + Ps0_ini = Ps0_iniA ; + + +/*-----------------------------------* +* Weak inversion zone. +*-----------------*/ + } else if ( Vgs <= Vth ) { + + Ps0_ini = Ps0_iniA ; + + +/*-----------------------------------* +* Strong inversion zone. +* - Ps0_iniB : upper bound. +*-----------------*/ + } else { + + T1 = ( Cox * Cox ) / ( cnst0 * cnst0 ) / cnst1 ; + T2 = T1 * Vgp * Vgp ; + T3 = beta + 2.0 / Vgp ; + + Ps0_iniB = log( T2 ) / T3 ; + + T1 = Ps0_iniB - Ps0_iniA - c_ps0ini_2 ; + T2 = sqrt( T1 * T1 + 4.0e0 * c_ps0ini_2 * Ps0_iniB ) ; + + Ps0_ini = Ps0_iniB - ( T1 + T2 ) / 2 ; + + } + } + + if ( Ps0_ini < Vbs ) { + Ps0_ini = Vbs ; + } + + + +/*---------------------------------------------------* +* Assign initial guess. +*-----------------*/ + + Ps0 = Ps0_ini ; + + Psl_lim = Ps0_iniA ; + +/*---------------------------------------------------* +* Calculation of Ps0. (beginning of Newton loop) +* - Fs0 : Fs0 = 0 is the equation to be solved. +* - dPs0 : correction value. +*-----------------*/ + + + exp_bVbs = exp( beta * Vbs ) ; + + cfs1 = cnst1 * exp_bVbs ; + + for ( lp_s0 = 1 ; lp_s0 <= lp_s0_max ; lp_s0 ++ ) { + + Chi = beta * ( Ps0 - Vbs ) ; + + exp_Chi = exp( Chi ) ; + + fs01 = cfs1 * ( exp_Chi - 1.0e0 ) ; + fs01_dPs0 = cfs1 * beta * ( exp_Chi ) ; + + + if ( fs01 < epsm10 * cfs1 ) { + fs01 = 0.0 ; + fs01_dPs0 = 0.0 ; + } + +/*-------------------------------------------* +* zone-D1/D2. (Ps0) +* - Qb0 is approximated to 5-dgree polynomial. +*-----------------*/ + + if ( Chi < znbd5 ) { + + fi = Chi * Chi * Chi + * ( cn_im53 + Chi * ( cn_im54 + Chi * cn_im55 ) ) ; + fi_dChi = Chi * Chi + * ( 3 * cn_im53 + + Chi * ( 4 * cn_im54 + Chi * 5 * cn_im55 ) ) ; + + + + fs01 = cfs1 * fi * fi ; + fs01_dPs0 = cfs1 * beta * 2 * fi * fi_dChi ; + + + fb = Chi * ( cn_nc51 + Chi * ( cn_nc52 + + Chi * ( cn_nc53 + + Chi * ( cn_nc54 + Chi * cn_nc55 ) ) ) ) ; + fb_dChi = cn_nc51 + Chi * ( 2 * cn_nc52 + + Chi * ( 3 * cn_nc53 + + Chi * ( 4 * cn_nc54 + Chi * 5 * cn_nc55 ) ) ) ; + + + fs02 = sqrt( fb * fb + fs01 ) ; + + if ( fs02 >= epsm10 ) { + fs02_dPs0 = ( beta * fb_dChi * 2 * fb + fs01_dPs0 ) + / ( fs02 + fs02 ) ; + } else { + fs02 = sqrt( fb * fb + fs01 ) ; + fs02_dPs0 = beta * fb_dChi ; + } + + Fs0 = Vgp - Ps0 - fac1 * fs02 ; + + Fs0_dPs0 = - 1.0e0 - fac1 * fs02_dPs0 ; + + dPs0 = - Fs0 / Fs0_dPs0 ; + +/*-------------------------------------------* +* zone-D3. (Ps0) +*-----------------*/ + } else { + + Xi0 = Chi - 1.0e0 ; + + Xi0p12 = sqrt( Xi0 ) ; + + fs02 = sqrt( Xi0 + fs01 ) ; + + fs02_dPs0 = ( beta + fs01_dPs0 ) / ( fs02 + fs02 ) ; + + Fs0 = Vgp - Ps0 - fac1 * fs02 ; + + Fs0_dPs0 = - 1.0e0 - fac1 * fs02_dPs0 ; + + dPs0 = - Fs0 / Fs0_dPs0 ; + + } /* end of if ( Chi ... ) else block */ + +/*-------------------------------------------* +* Update Ps0 . +* - cramped to Vbs if Ps0 < Vbs . +*-----------------*/ + + if ( fabs( dPs0 ) > dP_max ) { + dPs0 = fabs( dP_max ) * Fn_Sgn( dPs0 ) ; + } + + Ps0 = Ps0 + dPs0 ; + + if ( Ps0 < Vbs ) { + Ps0 = Vbs ; + } + + +/*-------------------------------------------* +* Check convergence. +* NOTE: This condition may be too rigid. +*-----------------*/ + + if ( fabs( dPs0 ) <= ps_conv && fabs( Fs0 ) <= gs_conv ) { + break ; + } + + } /* end of Ps0 Newton loop */ + + + +/*-------------------------------------------* +* Procedure for diverged case. +*-----------------*/ + if ( lp_s0 > lp_s0_max ) { + fprintf( stderr , + "*** warning(HiSIM): Went Over Iteration Maximum (Ps0)\n" ) ; + fprintf( stderr , + " Vbse = %7.3f Vdse = %7.3f Vgse = %7.3f\n" , + Vbse , Vdse , Vgse ) ; + if ( flg_info >= 2 ) { + printf( + "*** warning(HiSIM): Went Over Iteration Maximum (Ps0)\n" ) ; + } + } + +/*---------------------------------------------------* +* Evaluate derivatives of Ps0. +* - note: Here, fs01_dVbs and fs02_dVbs are derivatives +* w.r.t. explicit Vbs. So, Ps0 in the fs01 and fs02 +* expressions is regarded as a constant. +*-----------------*/ + + Chi = beta * ( Ps0 - Vbs ) ; + + exp_Chi = exp( Chi ) ; + + cfs1 = cnst1 * exp_bVbs ; + if ( fs01 < epsm10 * cfs1 ) { + fs01 = 0.0 ; + fs01_dPs0 = 0.0 ; + fs01_dVbs = 0.0 ; + } + +/*-------------------------------------------* +* zone-D1/D2. (Ps0) +*-----------------*/ + + if ( Chi < znbd5 ) { + + fi = Chi * Chi * Chi + * ( cn_im53 + Chi * ( cn_im54 + Chi * cn_im55 ) ) ; + fi_dChi = Chi * Chi + * ( 3 * cn_im53 + + Chi * ( 4 * cn_im54 + Chi * 5 * cn_im55 ) ) ; + + + fs01 = cfs1 * fi * fi ; + fs01_dPs0 = cfs1 * beta * 2 * fi * fi_dChi ; + fs01_dVbs = cfs1 * beta * fi * ( fi - 2 * fi_dChi ) ; + + + fb = Chi * ( cn_nc51 + Chi * ( cn_nc52 + + Chi * ( cn_nc53 + + Chi * ( cn_nc54 + Chi * cn_nc55 ) ) ) ) ; + fb_dChi = cn_nc51 + Chi * ( 2 * cn_nc52 + + Chi * ( 3 * cn_nc53 + + Chi * ( 4 * cn_nc54 + Chi * 5 * cn_nc55 ) ) ) ; + + fs02 = sqrt( fb * fb + fs01 ) ; + + T2 = 1.0e0 / ( fs02 + fs02 ) ; + + if ( fs02 >= epsm10 ) { + fs02_dPs0 = ( beta * fb_dChi * 2 * fb + fs01_dPs0 ) * T2 ; + fs02_dVbs = ( - beta * fb_dChi * 2 * fb + fs01_dVbs ) + * T2 ; + } else { + fs02_dPs0 = beta * fb_dChi ; + fs02_dVbs = - beta * fb_dChi ; + } + + /* memo: Fs0 = Vgp - Ps0 - fac1 * fs02 */ + + Fs0_dPs0 = - 1.0e0 - fac1 * fs02_dPs0 ; + + Ps0_dVbs = - ( Vgp_dVbs + - ( fac1 * fs02_dVbs + fac1_dVbs * fs02 ) + ) / Fs0_dPs0 ; + Ps0_dVds = - ( Vgp_dVds + - fac1_dVds * fs02 + ) / Fs0_dPs0 ; + Ps0_dVgs = - ( Vgp_dVgs + - fac1_dVgs * fs02 + ) / Fs0_dPs0 ; + + + T1 = cnst0 ; + + Qb0 = T1 * fb ; + Qb0_dVbs = ( Ps0_dVbs - 1.0e0 ) * T1 * beta * fb_dChi ; + Qb0_dVds = Ps0_dVds * T1 * beta * fb_dChi ; + Qb0_dVgs = Ps0_dVgs * T1 * beta * fb_dChi ; + + fs01_dVbs = Ps0_dVbs * fs01_dPs0 + fs01_dVbs ; + fs01_dVds = Ps0_dVds * fs01_dPs0 ; + fs01_dVgs = Ps0_dVgs * fs01_dPs0 ; + fs02_dVbs = Ps0_dVbs * fs02_dPs0 + fs02_dVbs ; + fs02_dVds = Ps0_dVds * fs02_dPs0 ; + fs02_dVgs = Ps0_dVgs * fs02_dPs0 ; + + T1 = 1.0 / ( fs02 + fb * fb ) ; + T2 = T1 * T1 ; + + Qn0 = cnst0 * fs01 * T1 ; + + T3 = 2.0 * fb_dChi * fb * beta ; + + Qn0_dVbs = cnst0 * ( + fs01_dVbs * T1 + - fs01 * ( fs02_dVbs + + T3 * ( Ps0_dVbs - 1.0 ) ) * T2 ) ; + Qn0_dVds = cnst0 * ( + fs01_dVds * T1 + - fs01 * ( fs02_dVds + T3 * Ps0_dVds ) * T2 ) ; + Qn0_dVgs = cnst0 * ( + fs01_dVgs * T1 + - fs01 * ( fs02_dVgs + T3 * Ps0_dVgs ) * T2 ) ; + + +/*-------------------------------------------* +* zone-D1. (Ps0) +* - Evaluate basic characteristics and exit from this part. +*-----------------*/ + if ( Chi < znbd3 ) { + + + Psl = Ps0 ; + Psl_dVbs = Ps0_dVbs ; + Psl_dVds = Ps0_dVds ; + Psl_dVgs = Ps0_dVgs ; + + Pds = 0.0 ; + Pds_dVbs = 0.0 ; + Pds_dVds = 0.0 ; + Pds_dVgs = 0.0 ; + + T1 = - Weff * Leff ; + + Qb = T1 * Qb0 ; + Qb_dVbs = T1 * Qb0_dVbs ; + Qb_dVds = T1 * Qb0_dVds ; + Qb_dVgs = T1 * Qb0_dVgs ; + + if ( Qn0 < Cox * VgVt_small ) { + Qn0 = 0.0 ; + Qn0_dVbs = 0.0 ; + Qn0_dVds = 0.0 ; + Qn0_dVgs = 0.0 ; + } + + Qi = T1 * Qn0 ; + Qi_dVbs = T1 * Qn0_dVbs ; + Qi_dVds = T1 * Qn0_dVds ; + Qi_dVgs = T1 * Qn0_dVgs ; + + Qd = 0.0e0 ; + Qd_dVbs = 0.0e0 ; + Qd_dVds = 0.0e0 ; + Qd_dVgs = 0.0e0 ; + + Ids = 0.0e0 ; + Ids_dVbs = 0.0e0 ; + Ids_dVds = 0.0e0 ; + Ids_dVgs = 0.0e0 ; + + VgVt = 0.0 ; + + flg_noqi = 1 ; + + goto end_of_part_1 ; + } + +/*-------------------------------------------* +* zone-D2 +*-----------------*/ + + Xi0 = Chi - 1.0e0 ; + + Xi0_dVbs = beta * ( Ps0_dVbs - 1.0e0 ) ; + Xi0_dVds = beta * Ps0_dVds ; + Xi0_dVgs = beta * Ps0_dVgs ; + + Xi0p12 = sqrt( Xi0 ) ; + Xi0p32 = Xi0 * Xi0p12 ; + + Xi0p12_dVbs = 0.5e0 * Xi0_dVbs / Xi0p12 ; + Xi0p12_dVds = 0.5e0 * Xi0_dVds / Xi0p12 ; + Xi0p12_dVgs = 0.5e0 * Xi0_dVgs / Xi0p12 ; + + Xi0p32_dVbs = 1.5e0 * Xi0_dVbs * Xi0p12 ; + Xi0p32_dVds = 1.5e0 * Xi0_dVds * Xi0p12 ; + Xi0p32_dVgs = 1.5e0 * Xi0_dVgs * Xi0p12 ; + + Qn00 = Qn0 ; + Qn00_dVbs = Qn0_dVbs ; + Qn00_dVds = Qn0_dVds ; + Qn00_dVgs = Qn0_dVgs ; + + fs01 = cfs1 * ( exp_Chi - 1.0 ) ; + + fs01_dPs0 = cfs1 * beta * ( exp_Chi ) ; + fs01_dVbs = - cfs1 * beta ; + + + fs02 = sqrt( Xi0 + fs01 ) ; + + T2 = 0.5e0 / fs02 ; + + fs02_dPs0 = ( beta + fs01_dPs0 ) * T2 ; + + fs02_dVbs = ( - beta + fs01_dVbs ) * T2 ; + + + flg_noqi = 0 ; + + +/*-------------------------------------------* +* zone-D3. (Ps0) +*-----------------*/ + } else { + + fs01 = cfs1 * ( exp_Chi - 1.0 ) ; + + fs01_dPs0 = cfs1 * beta * ( exp_Chi ) ; + fs01_dVbs = - cfs1 * beta ; + + + Xi0 = Chi - 1.0e0 ; + + Xi0p12 = sqrt( Xi0 ) ; + Xi0p32 = Xi0 * Xi0p12 ; + + fs02 = sqrt( Xi0 + fs01 ) ; + + T2 = 0.5e0 / fs02 ; + + fs02_dPs0 = ( beta + fs01_dPs0 ) * T2 ; + + fs02_dVbs = ( - beta + fs01_dVbs ) * T2 ; + + /* memo: Fs0 = Vgp - Ps0 - fac1 * fs02 */ + + T2 = 0.5e0 / Xi0p12 ; + + Fs0_dPs0 = - 1.0e0 - fac1 * fs02_dPs0 ; + + Ps0_dVbs = - ( Vgp_dVbs + - ( fac1 * fs02_dVbs + fac1_dVbs * fs02 ) + ) / Fs0_dPs0 ; + + Ps0_dVds = - ( Vgp_dVds + - fac1_dVds * fs02 + ) / Fs0_dPs0 ; + Ps0_dVgs = - ( Vgp_dVgs + - fac1_dVgs * fs02 + ) / Fs0_dPs0 ; + + Xi0_dVbs = beta * ( Ps0_dVbs - 1.0e0 ) ; + Xi0_dVds = beta * Ps0_dVds ; + Xi0_dVgs = beta * Ps0_dVgs ; + + Xi0p12_dVbs = 0.5e0 * Xi0_dVbs / Xi0p12 ; + Xi0p12_dVds = 0.5e0 * Xi0_dVds / Xi0p12 ; + Xi0p12_dVgs = 0.5e0 * Xi0_dVgs / Xi0p12 ; + + Xi0p32_dVbs = 1.5e0 * Xi0_dVbs * Xi0p12 ; + Xi0p32_dVds = 1.5e0 * Xi0_dVds * Xi0p12 ; + Xi0p32_dVgs = 1.5e0 * Xi0_dVgs * Xi0p12 ; + + flg_noqi = 0 ; + + + } /* end of if ( Chi ... ) block */ + + + +/*-----------------------------------------------------------* +* NOTE: The following sections of this part are only for +* the conductive case. +*-----------------*/ + +/*-----------------------------------------------------------* +* Xi0 : beta * ( Ps0 - Vbs ) - 1 = Chi - 1 . +*-----------------*/ +/*-----------------------------------------------------------* +* Qn0 : Qi at source side. +* - Qn0 := cnst0 * ( ( Xi0 + fs01 )^(1/2) - ( Xi0 )^(1/2) ) +* - Derivatives of fs01 are redefined here. +*-----------------*/ +/* note:------------------------ +* fs01 = cnst1 * exp( Vbs ) * ( exp( Chi ) - Chi - 1.0e0 ) ; +* fs02 = sqrt( Xi0 + fs01 ) ; +*-------------------------------*/ + + Qn0 = cnst0 * fs01 / ( fs02 + Xi0p12 ) ; + + fs01_dVbs = Ps0_dVbs * fs01_dPs0 + fs01_dVbs ; + fs01_dVds = Ps0_dVds * fs01_dPs0 ; + fs01_dVgs = Ps0_dVgs * fs01_dPs0 ; + fs02_dVbs = Ps0_dVbs * fs02_dPs0 + fs02_dVbs ; + fs02_dVds = Ps0_dVds * fs02_dPs0 ; + fs02_dVgs = Ps0_dVgs * fs02_dPs0 ; + + Qn0_dVbs = Qn0 + * ( fs01_dVbs / fs01 + - ( fs02_dVbs + Xi0p12_dVbs ) / ( fs02 + Xi0p12 ) ) ; + Qn0_dVds = Qn0 + * ( fs01_dVds / fs01 + - ( fs02_dVds + Xi0p12_dVds ) / ( fs02 + Xi0p12 ) ) ; + Qn0_dVgs = Qn0 + * ( fs01_dVgs / fs01 + - ( fs02_dVgs + Xi0p12_dVgs ) / ( fs02 + Xi0p12 ) ) ; + +/*-----------------------------------------------------------* +* Qb0 : Qb at source side. +*-----------------*/ + + if ( Chi > znbd5 ) { + + Qb0 = cnst0 * Xi0p12 ; + Qb0_dVbs = cnst0 * Xi0p12_dVbs ; + Qb0_dVds = cnst0 * Xi0p12_dVds ; + Qb0_dVgs = cnst0 * Xi0p12_dVgs ; + + } + +/*-----------------------------------------------------------* +* FD2 : connecting function for zone-D2. +*-----------------*/ + + if ( Chi < znbd5 ) { + + T1 = 1.0 / ( znbd5 - znbd3 ) ; + + TX = T1 * ( Chi - znbd3 ) ; + TX_dVbs = beta * T1 * ( Ps0_dVbs - 1.0 ) ; + TX_dVds = beta * T1 * Ps0_dVds ; + TX_dVgs = beta * T1 * Ps0_dVgs ; + + FD2 = TX * TX * TX * ( 10.0 + TX * ( -15.0 + TX * 6.0 ) ) ; + T4 = TX * TX * ( 30.0 + TX * ( -60.0 + TX * 30.0 ) ) ; + + FD2_dVbs = T4 * TX_dVbs ; + FD2_dVds = T4 * TX_dVds ; + FD2_dVgs = T4 * TX_dVgs ; + } + +/*-----------------------------------------------------------* +* Modify Qn0 for zone-D2. +*-----------------*/ + + if ( Chi < znbd5 ) { + + Qn0_dVbs = FD2 * Qn0_dVbs + FD2_dVbs * Qn0 + + ( 1.0 - FD2 ) * Qn00_dVbs - FD2_dVbs * Qn00 ; + Qn0_dVds = FD2 * Qn0_dVds + FD2_dVds * Qn0 + + ( 1.0 - FD2 ) * Qn00_dVds - FD2_dVds * Qn00 ; + Qn0_dVgs = FD2 * Qn0_dVgs + FD2_dVgs * Qn0 + + ( 1.0 - FD2 ) * Qn00_dVgs - FD2_dVgs * Qn00 ; + + Qn0 = FD2 * Qn0 + ( 1.0 - FD2 ) * Qn00 ; + + if ( Qn0 < 0.0 ) { + Qn0 = 0.0 ; + Qn0_dVbs = 0.0 ; + Qn0_dVds = 0.0 ; + Qn0_dVgs = 0.0 ; + } + + } + + + +/*---------------------------------------------------* +* VgVt : Vgp - Vth_qi. ( Vth_qi is Vth for Qi evaluation. ) +*-----------------*/ + + VgVt = Qn0 * Cox_inv ; + VgVt_dVbs = Qn0_dVbs * Cox_inv + Qn0 * Cox_inv_dVbs ; + VgVt_dVds = Qn0_dVds * Cox_inv + Qn0 * Cox_inv_dVds ; + VgVt_dVgs = Qn0_dVgs * Cox_inv + Qn0 * Cox_inv_dVgs ; + +/*-----------------------------------------------------------* +* make Qi=Qd=Ids=0 if VgVt <= VgVt_small +*-----------------*/ + + + if ( VgVt <= VgVt_small ) { + + + Psl = Ps0 ; + Psl_dVbs = Ps0_dVbs ; + Psl_dVds = Ps0_dVds ; + Psl_dVgs = Ps0_dVgs ; + + Psdl = Psl ; + Psdl_dVbs = Psl_dVbs ; + Psdl_dVds = Psl_dVds ; + Psdl_dVgs = Psl_dVgs ; + + Pds = 0.0 ; + Pds_dVbs = 0.0 ; + Pds_dVds = 0.0 ; + Pds_dVgs = 0.0 ; + + T1 = - Leff * Weff ; + Qb = T1 * Qb0 ; + Qb_dVbs = T1 * Qb0_dVbs ; + Qb_dVds = T1 * Qb0_dVds ; + Qb_dVgs = T1 * Qb0_dVgs ; + + Qi = 0.0 ; + Qi_dVbs = 0.0 ; + Qi_dVds = 0.0 ; + Qi_dVgs = 0.0 ; + + Qd = 0.0 ; + Qd_dVbs = 0.0 ; + Qd_dVds = 0.0 ; + Qd_dVgs = 0.0 ; + + Ids = 0.0e0 ; + Ids_dVbs = 0.0e0 ; + Ids_dVds = 0.0e0 ; + Ids_dVgs = 0.0e0 ; + + flg_noqi = 1 ; + + goto end_of_part_1 ; + } + + + +/*-----------------------------------------------------------* +* Start point of Psl (= Ps0 + Pds) calculation. (label) +*-----------------*/ +start_of_Psl: ; + + exp_bVbsVds = exp( beta * ( Vbs - Vds ) ) ; + +/*---------------------------------------------------* +* Skip Psl calculation when Vds is very small. +*-----------------*/ + if ( Vds <= epsm10 ) { + Pds = 0.0 ; + Psl = Ps0 ; + goto end_of_loopl ; + } + +/*-----------------------------------------------------------* +* Initial guess for Pds ( = Psl - Ps0 ). +*-----------------*/ + +/*---------------------------------------------------* +* Use previous value. +*-----------------*/ + if ( flg_pprv == 1 ) { + + Pds_ini = Pds + Pds_dVbs * dVbs + + Pds_dVds * dVds + Pds_dVgs * dVgs ; + + T1 = Pds_ini - Pds ; + + if ( T1 < - dP_max || T1 > dP_max ) { + flg_pprv = 0 ; + } + + } + +/*---------------------------------------------------* +* Analytical initial guess. +*-----------------*/ + if ( flg_pprv == 0 ) { + Pds_max = Fn_Max( Psl_lim - Ps0 , 0.0e0 ); + + T1 = ( 1.0e0 + c_pslini_1 ) * Pds_max ; + T2 = T1 - Vds - c_pslini_2 ; + T3 = sqrt( T2 * T2 + 4.0e0 * T1 * c_pslini_2 ) ; + + Pds_ini = T1 - ( T2 + T3 ) / 2 ; + + Pds_ini = Fn_Min( Pds_ini , Pds_max ) ; + } + + if ( Pds_ini < 0.0 ) { + Pds_ini = 0.0 ; + } else if ( Pds_ini > Vds ) { + Pds_ini = Vds ; + } + + + +/*---------------------------------------------------* +* Assign initial guess. +*-----------------*/ + + Pds = Pds_ini ; + Psl = Ps0 + Pds ; + + +/*---------------------------------------------------* +* Calculation of Psl by solving Poisson eqn. +* (beginning of Newton loop) +* - Fsl : Fsl = 0 is the equation to be solved. +* - dPsl : correction value. +*-----------------*/ + + + for ( lp_sl = 1 ; lp_sl <= lp_sl_max ; lp_sl ++ ) { + + Chi = beta * ( Psl - Vbs ) ; + +/*-------------------------------------------* +* zone-D2. (Psl) +* - Qb0 is approximated to 5-dgree polynomial. +*-----------------*/ + + if ( Chi < znbd5 ) { + + fi = Chi * Chi * Chi + * ( cn_im53 + Chi * ( cn_im54 + Chi * cn_im55 ) ) ; + fi_dChi = Chi * Chi + * ( 3 * cn_im53 + + Chi * ( 4 * cn_im54 + Chi * 5 * cn_im55 ) ) ; + + + cfs1 = cnst1 * exp_bVbsVds ; + + fsl1 = cfs1 * fi * fi ; + fsl1_dPsl = cfs1 * beta * 2 * fi * fi_dChi ; + + + fb = Chi * ( cn_nc51 + Chi * ( cn_nc52 + + Chi * ( cn_nc53 + + Chi * ( cn_nc54 + Chi * cn_nc55 ) ) ) ) ; + fb_dChi = cn_nc51 + Chi * ( 2 * cn_nc52 + + Chi * ( 3 * cn_nc53 + + Chi * ( 4 * cn_nc54 + Chi * 5 * cn_nc55 ) ) ) ; + + + fsl2 = sqrt( fb * fb + fsl1 ) ; + + if ( fsl2 >= epsm10 ) { + fsl2_dPsl = ( beta * fb_dChi * 2 * fb + fsl1_dPsl ) + / ( fsl2 + fsl2 ) ; + } else { + fsl2 = sqrt( fb * fb + fsl1 ) ; + fsl2_dPsl = beta * fb_dChi ; + } + + Fsl = Vgp - Psl - fac1 * fsl2 ; + + Fsl_dPsl = - 1.0e0 - fac1 * fsl2_dPsl ; + + dPsl = - Fsl / Fsl_dPsl ; + +/*-------------------------------------------* +* zone-D3. (Psl) +*-----------------*/ + } else { + + Rho = beta * ( Psl - Vds ) ; + + exp_Rho = exp( Rho ) ; + + fsl1 = cnst1 * ( exp_Rho - exp_bVbsVds ) ; + fsl1_dPsl = cnst1 * beta * ( exp_Rho ) ; + + + if ( fsl1 < epsm10 * cnst1 ) { + fsl1 = 0.0 ; + fsl1_dPsl = 0.0 ; + } + + Xil = Chi - 1.0e0 ; + + Xilp12 = sqrt( Xil ) ; + + fsl2 = sqrt( Xil + fsl1 ) ; + + fsl2_dPsl = ( beta + fsl1_dPsl ) / ( fsl2 + fsl2 ) ; + + Fsl = Vgp - Psl - fac1 * fsl2 ; + + Fsl_dPsl = - 1.0e0 - fac1 * fsl2_dPsl ; + + dPsl = - Fsl / Fsl_dPsl ; + + + } + +/*-------------------------------------------* +* Update Psl . +* - cramped to Vbs if Psl < Vbs . +*-----------------*/ + + if ( fabs( dPsl ) > dP_max ) { + dPsl = fabs( dP_max ) * Fn_Sgn( dPsl ) ; + } + + Psl = Psl + dPsl ; + + if ( Psl < Vbs ) { + Psl = Vbs ; + } + +/*-------------------------------------------* +* Check convergence. +* NOTE: This condition may be too rigid. +*-----------------*/ + + if ( fabs( dPsl ) <= ps_conv && fabs( Fsl ) <= gs_conv ) { + break ; + } + + } /* end of Psl Newton loop */ + +/*-------------------------------------------* +* Procedure for diverged case. +*-----------------*/ + if ( lp_sl > lp_sl_max ) { + fprintf( stderr , + "*** warning(HiSIM): Went Over Iteration Maximum (Psl)\n" ) ; + fprintf( stderr , + " Vbse = %7.3f Vdse = %7.3f Vgse = %7.3f\n" , + Vbse , Vdse , Vgse ) ; + if ( flg_info >= 2 ) { + printf( + "*** warning(HiSIM): Went Over Iteration Maximum (Psl)\n" ) ; + } + } + + +/*---------------------------------------------------* +* End of Psl calculation. (label) +*-----------------*/ +end_of_loopl: ; + +/*---------------------------------------------------* +* Assign Pds. +*-----------------*/ + + Pds = Psl - Ps0 ; + + if ( Pds < ps_conv ) { + Pds = 0.0 ; + Psl = Ps0 ; + } + + + +/*---------------------------------------------------* +* Evaluate derivatives of Psl. +* - note: Here, fsl1_dVbs and fsl2_dVbs are derivatives +* w.r.t. explicit Vbs. So, Psl in the fsl1 and fsl2 +* expressions is regarded as a constant. +*-----------------*/ + + Chi = beta * ( Psl - Vbs ) ; + +/*-------------------------------------------* +* zone-D2. (Psl) +*-----------------*/ + + if ( Chi < znbd5 ) { + + fi = Chi * Chi * Chi + * ( cn_im53 + Chi * ( cn_im54 + Chi * cn_im55 ) ) ; + fi_dChi = Chi * Chi + * ( 3 * cn_im53 + + Chi * ( 4 * cn_im54 + Chi * 5 * cn_im55 ) ) ; + + + /*note: cfs1 = cnst1 * exp_bVbsVds */ + fsl1 = cfs1 * fi * fi ; + fsl1_dPsl = cfs1 * beta * 2 * fi * fi_dChi ; + fsl1_dVbs = cfs1 * beta * fi * ( fi - 2 * fi_dChi ) ; + fsl1_dVds = - cfs1 * beta * fi * fi ; + + + fb = Chi * ( cn_nc51 + Chi * ( cn_nc52 + + Chi * ( cn_nc53 + + Chi * ( cn_nc54 + Chi * cn_nc55 ) ) ) ) ; + fb_dChi = cn_nc51 + Chi * ( 2 * cn_nc52 + + Chi * ( 3 * cn_nc53 + + Chi * ( 4 * cn_nc54 + Chi * 5 * cn_nc55 ) ) ) ; + + fsl2 = sqrt( fb * fb + fsl1 ) ; + + T2 = 0.5 / fsl2 ; + + if ( fsl2 >= epsm10 ) { + fsl2_dPsl = ( beta * fb_dChi * 2 * fb + fsl1_dPsl ) * T2 ; + fsl2_dVbs = ( - beta * fb_dChi * 2 * fb + fsl1_dVbs ) * T2 ; + fsl2_dVds = fsl1_dVds * T2 ; + } else { + fsl2_dPsl = beta * fb_dChi ; + fsl2_dVbs = - beta * fb_dChi ; + fsl2_dVds = 0.0 ; + } + + /* memo: Fsl = Vgp - Psl - fac1 * fsl2 */ + + Fsl_dPsl = - 1.0e0 - fac1 * fsl2_dPsl ; + + Psl_dVbs = - ( Vgp_dVbs + - ( fac1 * fsl2_dVbs + fac1_dVbs * fsl2 ) + ) / Fsl_dPsl ; + Psl_dVds = - ( Vgp_dVds + - ( fac1 * fsl2_dVds + fac1_dVds * fsl2 ) + ) / Fsl_dPsl ; + Psl_dVgs = - ( Vgp_dVgs + - fac1_dVgs * fsl2 + ) / Fsl_dPsl ; + + Pds_dVbs = Psl_dVbs - Ps0_dVbs ; + Pds_dVds = Psl_dVds - Ps0_dVds ; + Pds_dVgs = Psl_dVgs - Ps0_dVgs ; + + Xil = Chi - 1.0e0 ; + + Xilp12 = sqrt( Xil ) ; + Xilp32 = Xil * Xilp12 ; + +/*-------------------------------------------* +* zone-D3. (Psl) +*-----------------*/ + } else { + + Rho = beta * ( Psl - Vds ) ; + + exp_Rho = exp( Rho ) ; + + fsl1 = cnst1 * ( exp_Rho - exp_bVbsVds ) ; + + fsl1_dPsl = cnst1 * beta * ( exp_Rho ) ; + + fsl1_dVbs = - cnst1 * beta * exp_bVbsVds ; + fsl1_dVds = - beta * fsl1 ; + + + if ( fsl1 < epsm10 * T1 ) { + fsl1 = 0.0 ; + fsl1_dPsl = 0.0 ; + fsl1_dVds = 0.0 ; + } + + + Xil = Chi - 1.0e0 ; + + Xilp12 = sqrt( Xil ) ; + Xilp32 = Xil * Xilp12 ; + + fsl2 = sqrt( Xil + fsl1 ) ; + + T2 = 0.5e0 / fsl2 ; + + fsl2_dPsl = ( beta + fsl1_dPsl ) * T2 ; + + fsl2_dVbs = ( - beta + fsl1_dVbs ) * T2 ; + fsl2_dVds = ( fsl1_dVds ) * T2 ; + + /* memo: Fsl = Vgp - Psl - fac1 * fsl2 */ + + T2 = 0.5e0 / Xilp12 ; + + Fsl_dPsl = - 1.0e0 - fac1 * fsl2_dPsl ; + + Psl_dVbs = - ( Vgp_dVbs + - ( fac1 * fsl2_dVbs + fac1_dVbs * fsl2 ) + ) / Fsl_dPsl ; + + Psl_dVds = - ( Vgp_dVds + - ( fac1 * fsl2_dVds + fac1_dVds * fsl2 ) + ) / Fsl_dPsl ; + Psl_dVgs = - ( Vgp_dVgs + - fac1_dVgs * fsl2 + ) / Fsl_dPsl ; + + Pds_dVbs = Psl_dVbs - Ps0_dVbs ; + Pds_dVds = Psl_dVds - Ps0_dVds ; + Pds_dVgs = Psl_dVgs - Ps0_dVgs ; + } + + if ( Pds < ps_conv ) { + Pds_dVbs = 0.0 ; + Pds_dVgs = 0.0 ; + Psl_dVbs = Ps0_dVbs ; + Psl_dVgs = Ps0_dVgs ; + } + + + +/*-----------------------------------------------------------* +* Evaluate Qb and Idd. +* - Eta : substantial variable of QB'/Pds and Idd/Pds. +* - note: Eta = 4 * GAMMA_{hisim_0} +*-----------------*/ + + Eta = beta * Pds / Xi0 ; + + Eta_dVbs = beta * ( Pds_dVbs - ( Ps0_dVbs - 1.0e0 ) * Eta ) + / Xi0 ; + Eta_dVds = beta * ( Pds_dVds - Ps0_dVds * Eta ) / Xi0 ; + Eta_dVgs = beta * ( Pds_dVgs - Ps0_dVgs * Eta ) / Xi0 ; + + + /* ( Eta + 1 )^n */ + Eta1 = Eta + 1.0e0 ; + Eta1p12 = sqrt( Eta1 ) ; + Eta1p32 = Eta1p12 * Eta1 ; + Eta1p52 = Eta1p32 * Eta1 ; + + /* 1 / ( ( Eta + 1 )^n + 1 ) */ + Zeta12 = 1.0e0 / ( Eta1p12 + 1.0e0 ) ; + Zeta32 = 1.0e0 / ( Eta1p32 + 1.0e0 ) ; + Zeta52 = 1.0e0 / ( Eta1p52 + 1.0e0 ) ; + +/*---------------------------------------------------* +* F00 := PS00/Pds (n=1/2) +*-----------------*/ + + F00 = Zeta12 / Xi0p12 ; + + T3 = - 0.5e0 / Xi0p32 ; + T4 = - 0.5e0 / Eta1p12 * F00 ; + + F00_dVbs = Zeta12 * ( Xi0_dVbs * T3 + Eta_dVbs * T4 ) ; + F00_dVds = Zeta12 * ( Xi0_dVds * T3 + Eta_dVds * T4 ) ; + F00_dVgs = Zeta12 * ( Xi0_dVgs * T3 + Eta_dVgs * T4 ) ; + + +/*---------------------------------------------------* +* F10 := PS10/Pds (n=3/2) +*-----------------*/ + + T1 = 3.0e0 + Eta * ( 3.0e0 + Eta ) ; + + F10 = C_2o3 * Xi0p12 * Zeta32 * T1 ; + + T2 = 3.0e0 + Eta * 2.0e0 ; + T3 = C_1o3 / Xi0p12 * T1 ; + T4 = - 1.5e0 * Eta1p12 * F10 + C_2o3 * Xi0p12 * T2 ; + + F10_dVbs = Zeta32 * ( Xi0_dVbs * T3 + Eta_dVbs * T4 ) ; + F10_dVds = Zeta32 * ( Xi0_dVds * T3 + Eta_dVds * T4 ) ; + F10_dVgs = Zeta32 * ( Xi0_dVgs * T3 + Eta_dVgs * T4 ) ; + +/*---------------------------------------------------* +* F30 := PS30/Pds (n=5/2) +*-----------------*/ + + T1 = 5e0 + + Eta * ( 10e0 + Eta * ( 10e0 + Eta * ( 5e0 + Eta ) ) ) ; + + F30 = 4e0 / ( 15e0 * beta ) * Xi0p32 * Zeta52 * T1 ; + + T2 = 10e0 + Eta * ( 20e0 + Eta * ( 15e0 + Eta * 4e0 ) ) ; + T3 = 2e0 / ( 5e0 * beta ) * Xi0p12 * T1 ; + T4 = - ( 5e0 / 2e0 ) * Eta1p32 * F30 + + 4e0 / ( 15e0 * beta ) * Xi0p32 * T2 ; + + F30_dVbs = Zeta52 * ( Xi0_dVbs * T3 + Eta_dVbs * T4 ) ; + F30_dVds = Zeta52 * ( Xi0_dVds * T3 + Eta_dVds * T4 ) ; + F30_dVgs = Zeta52 * ( Xi0_dVgs * T3 + Eta_dVgs * T4 ) ; + +/*---------------------------------------------------* +* F11 := PS11/Pds. +*-----------------*/ + + F11 = Ps0 * F10 + C_2o3 / beta * Xilp32 - F30 ; + + F11_dVbs = Ps0_dVbs * F10 + Ps0 * F10_dVbs + + ( Xi0_dVbs / beta + Pds_dVbs ) * Xilp12 + - F30_dVbs ; + F11_dVds = Ps0_dVds * F10 + Ps0 * F10_dVds + + ( Xi0_dVds / beta + Pds_dVds ) * Xilp12 + - F30_dVds ; + F11_dVgs = Ps0_dVgs * F10 + Ps0 * F10_dVgs + + ( Xi0_dVgs / beta + Pds_dVgs ) * Xilp12 + - F30_dVgs ; + +/*---------------------------------------------------* +* Fdd := Idd/Pds. +*-----------------*/ + + T1 = Vgp + 1.0e0 / beta - 0.5e0 * ( 2.0e0 * Ps0 + Pds ) ; + T2 = - F10 + F00 ; + T3 = beta * Cox ; + T4 = beta * cnst0 ; + + Fdd = T3 * T1 + T4 * T2 ; + + Fdd_dVbs = T3 * ( Vgp_dVbs - Ps0_dVbs - 0.5e0 * Pds_dVbs ) + + beta * Cox_dVbs * T1 + + T4 * ( - F10_dVbs + F00_dVbs ) ; + Fdd_dVds = T3 * ( Vgp_dVds - Ps0_dVds - 0.5e0 * Pds_dVds ) + + beta * Cox_dVds * T1 + + T4 * ( - F10_dVds + F00_dVds ) ; + Fdd_dVgs = T3 * ( Vgp_dVgs - Ps0_dVgs - 0.5e0 * Pds_dVgs ) + + beta * Cox_dVgs * T1 + + T4 * ( - F10_dVgs + F00_dVgs ) ; + +/*---------------------------------------------------* +* Q_B : bulk charge. +*-----------------*/ + + T1 = Vgp + 1.0e0 / beta ; + T2 = T1 * F10 - F11 ; + + Qbnm = cnst0 + * ( cnst0 * ( 1.5e0 - ( Xi0 + 1.0e0 ) - 0.5e0 * beta * Pds ) + + Cox * T2 ) ; + + Qbnm_dVbs = cnst0 + * ( cnst0 * ( - Xi0_dVbs - 0.5e0 * beta * Pds_dVbs ) + + Cox * ( Vgp_dVbs * F10 + T1 * F10_dVbs - F11_dVbs ) + + Cox_dVbs * T2 ) ; + Qbnm_dVds = cnst0 + * ( cnst0 * ( - Xi0_dVds - 0.5e0 * beta * Pds_dVds ) + + Cox * ( Vgp_dVds * F10 + T1 * F10_dVds - F11_dVds ) + + Cox_dVds * T2 ) ; + Qbnm_dVgs = cnst0 + * ( cnst0 * ( - Xi0_dVgs - 0.5e0 * beta * Pds_dVgs ) + + Cox * ( Vgp_dVgs * F10 + T1 * F10_dVgs - F11_dVgs ) + + Cox_dVgs * T2 ) ; + + T1 = - Weff * beta * Leff ; + + Qb = T1 * Qbnm / Fdd ; + + T2 = T1 / ( Fdd * Fdd ) ; + + Qb_dVbs = T2 * ( Fdd * Qbnm_dVbs - Qbnm * Fdd_dVbs ) ; + Qb_dVds = T2 * ( Fdd * Qbnm_dVds - Qbnm * Fdd_dVds ) ; + Qb_dVgs = T2 * ( Fdd * Qbnm_dVgs - Qbnm * Fdd_dVgs ) ; + +/*---------------------------------------------------* +* Breaking point for Qi=Qd=0. +*-----------------*/ + + if ( flg_noqi != 0 ) { + goto end_of_part_1 ; + } + +/*---------------------------------------------------* +* Idd: +*-----------------*/ + + Idd = Pds * Fdd ; + + Idd_dVbs = Pds_dVbs * Fdd + Pds * Fdd_dVbs ; + Idd_dVds = Pds_dVds * Fdd + Pds * Fdd_dVds ; + Idd_dVgs = Pds_dVgs * Fdd + Pds * Fdd_dVgs ; + + + +/*-----------------------------------------------------------* +* Channel Length Modulation. Lred: \Delta L +*-----------------*/ + + if( sIN.clm2 < epsm10 && sIN.clm3 < epsm10 ) { + + Lred = 0.0e0 ; + Lred_dVbs = 0.0e0 ; + Lred_dVds = 0.0e0 ; + Lred_dVgs = 0.0e0 ; + + Psdl = Psl ; + Psdl_dVbs = Psl_dVbs ; + Psdl_dVds = Psl_dVds ; + Psdl_dVgs = Psl_dVgs ; + + if ( Psdl > Ps0 + Vds - epsm10 ) { + Psdl = Ps0 + Vds - epsm10 ; + } + + goto end_of_CLM ; + } + + + Ec = Idd / beta / Qn0 / Leff ; + Ec_dVbs = 1.0e0 / beta / Leff + * ( Idd_dVbs / Qn0 - Idd * Qn0_dVbs / Qn0 / Qn0 ) ; + Ec_dVds = ( Idd_dVds / Qn0 - Idd * Qn0_dVds / Qn0 / Qn0 ) + / beta / Leff ; + Ec_dVgs = 1.0e0 / beta / Leff + * ( Idd_dVgs / Qn0 - Idd * Qn0_dVgs / Qn0 / Qn0 ) ; + + T2 = Vds + Ps0 ; + T2_dVbs = Ps0_dVbs ; + T2_dVds = 1.0 + Ps0_dVds ; + T2_dVgs = Ps0_dVgs ; + Aclm = sIN.clm1 ; + + Psdl = Aclm * T2 + ( 1.0e0 - Aclm ) * Psl ; + Psdl_dVbs = Aclm * T2_dVbs + ( 1.0e0 - Aclm ) * Psl_dVbs ; + Psdl_dVds = Aclm * T2_dVds + ( 1.0e0 - Aclm ) * Psl_dVds ; + Psdl_dVgs = Aclm * T2_dVgs + ( 1.0e0 - Aclm ) * Psl_dVgs ; + + if ( Psdl > Ps0 + Vds - epsm10 ) { + Psdl = Ps0 + Vds - epsm10 ; + } + T1 = sqrt( 2.0e0 * C_ESI / q_Nsub ) ; + T9 = sqrt( Psl - Vbs ) ; + Wd = T1 * T9 ; + Wd_dVbs = 0.5e0 * T1 / T9 * ( Psl_dVbs - 1.0e0 ) ; + Wd_dVds = 0.5e0 * T1 / T9 * Psl_dVds ; + Wd_dVgs = 0.5e0 * T1 / T9 * Psl_dVgs ; + + T7 = Qn0 / Wd ; + T7_dVbs = ( Qn0_dVbs / Wd - Qn0 / Wd / Wd * Wd_dVbs ) ; + T7_dVds = ( Qn0_dVds / Wd - Qn0 / Wd / Wd * Wd_dVds ) ; + T7_dVgs = ( Qn0_dVgs / Wd - Qn0 / Wd / Wd * Wd_dVgs ) ; + + T8 = Ec * Ec + 2.0e0 / C_ESI * q_Nsub * ( Psdl - Psl ) + 1.0e3 ; + T8_dVbs = 2.0e0 * Ec * Ec_dVbs + + 2.0e0 / C_ESI * q_Nsub * ( Psdl_dVbs - Psl_dVbs ) ; + T8_dVds = 2.0e0 * Ec * Ec_dVds + + 2.0e0 / C_ESI * q_Nsub * ( Psdl_dVds - Psl_dVds ) ; + T8_dVgs = 2.0e0 * Ec * Ec_dVgs + + 2.0e0 / C_ESI * q_Nsub * ( Psdl_dVgs - Psl_dVgs ) ; + + Ed = sqrt( T8 ) ; + Ed_dVbs = 0.5e0 / Ed * T8_dVbs ; + Ed_dVds = 0.5e0 / Ed * T8_dVds ; + Ed_dVgs = 0.5e0 / Ed * T8_dVgs ; + + + Lred = ( Ed - Ec ) + / ( sIN.clm2 * q_Nsub + sIN.clm3 * T7 ) * C_ESI ; + T1 = 1.0 / ( sIN.clm2 * q_Nsub + sIN.clm3 * T7 ) ; + T2 = T1 * T1 ; + Lred_dVbs = ( ( Ed_dVbs - Ec_dVbs ) * T1 + - ( Ed - Ec ) * T2 * sIN.clm3 * T7_dVbs ) * C_ESI ; + Lred_dVds = ( ( Ed_dVds - Ec_dVds ) * T1 + - ( Ed - Ec ) * T2 * sIN.clm3 * T7_dVds ) * C_ESI ; + Lred_dVgs = ( ( Ed_dVgs - Ec_dVgs ) * T1 + - ( Ed - Ec ) * T2 * sIN.clm3 * T7_dVgs ) * C_ESI ; + +/*---------------------------------------------------* +* Modify Lred for symmetry. +*-----------------*/ + + end_of_CLM2: ; + + TX = Vds / cclmmdf ; + T2 = TX * TX ; + T5 = 1.0 + T2 ; + + FMD = 1.0 - 1.0 / T5 ; + FMD_dVds = 2.0 * Vds / ( T5 * T5 * cclmmdf * cclmmdf ) ; + + T6 = Lred ; + + Lred = FMD * T6 ; + Lred_dVbs *= FMD ; + Lred_dVds = FMD_dVds * ( T6 ) + FMD * Lred_dVds ; + Lred_dVgs *= FMD ; + +/*-------------------------------------------* +* End point of CLM. (label) +*-----------------*/ +end_of_CLM: ; + + +/*---------------------------------------------------* +* preparation for Qi and Qd. +*-----------------*/ + + T1 = 2.0e0 * fac1 ; + + DtPds = T1 * ( F10 - Xi0p12 ) ; + + T2 = 2.0 * ( F10 - Xi0p12 ) ; + + DtPds_dVbs = T1 * ( F10_dVbs + - 0.5 * beta * ( Ps0_dVbs - 1.0e0 ) / Xi0p12 ) + + T2 * fac1_dVbs ; + DtPds_dVds = T1 * ( F10_dVds + - 0.5 * beta * Ps0_dVds / Xi0p12 ) + + T2 * fac1_dVds ; + DtPds_dVgs = T1 * ( F10_dVgs + - 0.5 * beta * Ps0_dVgs / Xi0p12 ) + + T2 * fac1_dVgs ; + + + Achi = Pds + DtPds ; + Achi_dVbs = Pds_dVbs + DtPds_dVbs ; + Achi_dVds = Pds_dVds + DtPds_dVds ; + Achi_dVgs = Pds_dVgs + DtPds_dVgs ; + + +/*-----------------------------------------------------------* +* Alpha : parameter to evaluate charges. +* - cramped to 0 if Alpha < 0. +*-----------------*/ + + Alpha = 1.0e0 - Achi / VgVt ; + + if ( Alpha >= 0.0e0 ) { + + Alpha_dVbs = - Achi_dVbs / VgVt + ( Achi / VgVt ) + * ( VgVt_dVbs / VgVt ) ; + Alpha_dVds = - Achi_dVds / VgVt + ( Achi / VgVt ) + * ( VgVt_dVds / VgVt ) ; + Alpha_dVgs = - Achi_dVgs / VgVt + ( Achi / VgVt ) + * ( VgVt_dVgs / VgVt ) ; + + } else { + + Alpha = 0.0e0 ; + Alpha_dVbs = 0.0e0 ; + Alpha_dVds = 0.0e0 ; + Alpha_dVgs = 0.0e0 ; + } + +/*-----------------------------------------------------------* +* Q_I : inversion charge. +*-----------------*/ + + Qinm = 1.0e0 + Alpha * ( 1.0e0 + Alpha ) ; + Qinm_dVbs = Alpha_dVbs * ( 1.0e0 + Alpha + Alpha ) ; + Qinm_dVds = Alpha_dVds * ( 1.0e0 + Alpha + Alpha ) ; + Qinm_dVgs = Alpha_dVgs * ( 1.0e0 + Alpha + Alpha ) ; + + Qidn = Fn_Max( 1.0e0 + Alpha , epsm10 ) ; + Qidn_dVbs = Alpha_dVbs ; + Qidn_dVds = Alpha_dVds ; + Qidn_dVgs = Alpha_dVgs ; + + T1 = - Weff * ( Leff - Lred ) * C_2o3 * VgVt * Qinm / Qidn ; + + Qi = T1 * Cox ; + + Qi_dVbs = Qi * ( VgVt_dVbs / VgVt + + Qinm_dVbs / Qinm - Qidn_dVbs / Qidn + - Lred_dVbs/ ( Leff - Lred ) ) + + T1 * Cox_dVbs ; + Qi_dVds = Qi * ( VgVt_dVds / VgVt + + Qinm_dVds / Qinm - Qidn_dVds / Qidn + - Lred_dVds/ ( Leff - Lred ) ) + + T1 * Cox_dVds ; + Qi_dVgs = Qi * ( VgVt_dVgs / VgVt + + Qinm_dVgs / Qinm - Qidn_dVgs / Qidn + - Lred_dVgs/ ( Leff - Lred ) ) + + T1 * Cox_dVgs ; + +/*-----------------------------------------------------------* +* Q_D : drain charge. +*-----------------*/ + + Qdnm = 0.5e0 + Alpha ; + Qdnm_dVbs = Alpha_dVbs ; + Qdnm_dVds = Alpha_dVds ; + Qdnm_dVgs = Alpha_dVgs ; + + Qddn = Qidn * Qinm ; + Qddn_dVbs = Qidn_dVbs * Qinm + Qidn * Qinm_dVbs ; + Qddn_dVds = Qidn_dVds * Qinm + Qidn * Qinm_dVds ; + Qddn_dVgs = Qidn_dVgs * Qinm + Qidn * Qinm_dVgs ; + + Quot = 0.4e0 * Qdnm / Qddn ; + Qdrat = 0.6e0 - Quot ; + + if ( Qdrat <= 0.5e0 ) { + Qdrat_dVbs = Quot * ( Qddn_dVbs / Qddn - Qdnm_dVbs / Qdnm ) ; + Qdrat_dVds = Quot * ( Qddn_dVds / Qddn - Qdnm_dVds / Qdnm ) ; + Qdrat_dVgs = Quot * ( Qddn_dVgs / Qddn - Qdnm_dVgs / Qdnm ) ; + } else { + Qdrat = 0.5e0 ; + Qdrat_dVbs = 0.0e0 ; + Qdrat_dVds = 0.0e0 ; + Qdrat_dVgs = 0.0e0 ; + } + + Qd = Qi * Qdrat ; + Qd_dVbs = Qi_dVbs * Qdrat + Qi * Qdrat_dVbs ; + Qd_dVds = Qi_dVds * Qdrat + Qi * Qdrat_dVds ; + Qd_dVgs = Qi_dVgs * Qdrat + Qi * Qdrat_dVgs ; + +/*-----------------------------------------------------------* +* Modify charges for zone-D2. +* - FD2 must be defined previously. +*-----------------*/ + + Chi = beta * ( Ps0 - Vbs ) ; + + if ( Chi < znbd5 ) { + + T1 = 1.0 / ( znbd5 - znbd3 ) ; + + TX = T1 * ( Chi - znbd3 ) ; + TX_dVbs = beta * T1 * ( Ps0_dVbs - 1.0 ) ; + TX_dVds = beta * T1 * Ps0_dVds ; + TX_dVgs = beta * T1 * Ps0_dVgs ; + + T5 = - Leff * Weff ; + + Qb_dVbs = FD2 * Qb_dVbs + FD2_dVbs * Qb + + ( 1.0 - FD2 ) * T5 * Qb0_dVbs - FD2_dVbs * T5 * Qb0 ; + Qb_dVds = FD2 * Qb_dVds + FD2_dVds * Qb + + ( 1.0 - FD2 ) * T5 * Qb0_dVds - FD2_dVds * T5 * Qb0 ; + Qb_dVgs = FD2 * Qb_dVgs + FD2_dVgs * Qb + + ( 1.0 - FD2 ) * T5 * Qb0_dVgs - FD2_dVgs * T5 * Qb0 ; + + Qb = FD2 * Qb + ( 1.0 - FD2 ) * T5 * Qb0 ; + + if ( Qb > 0.0 ) { + Qb = 0.0 ; + Qb_dVbs = 0.0 ; + Qb_dVds = 0.0 ; + Qb_dVgs = 0.0 ; + } + + Qi_dVbs = FD2 * Qi_dVbs + FD2_dVbs * Qi + + ( 1.0 - FD2 ) * T5 * Qn0_dVbs - FD2_dVbs * T5 * Qn0 ; + Qi_dVds = FD2 * Qi_dVds + FD2_dVds * Qi + + ( 1.0 - FD2 ) * T5 * Qn0_dVds - FD2_dVds * T5 * Qn0 ; + Qi_dVgs = FD2 * Qi_dVgs + FD2_dVgs * Qi + + ( 1.0 - FD2 ) * T5 * Qn0_dVgs - FD2_dVgs * T5 * Qn0 ; + + Qi = FD2 * Qi + ( 1.0 - FD2 ) * T5 * Qn0 ; + + if ( Qi > 0.0 ) { + Qi = 0.0 ; + Qi_dVbs = 0.0 ; + Qi_dVds = 0.0 ; + Qi_dVgs = 0.0 ; + } + + Qd_dVbs = FD2 * Qd_dVbs + FD2_dVbs * Qd + + ( 1.0 - FD2 ) * T5 * Qi_dVbs / 2 + - FD2_dVbs * T5 * Qi / 2 ; + Qd_dVds = FD2 * Qd_dVds + FD2_dVds * Qd + + ( 1.0 - FD2 ) * T5 * Qi_dVds / 2 + - FD2_dVds * T5 * Qi / 2 ; + Qd_dVgs = FD2 * Qd_dVgs + FD2_dVgs * Qd + + ( 1.0 - FD2 ) * T5 * Qi_dVgs / 2 + - FD2_dVgs * T5 * Qi / 2 ; + + Qd = FD2 * Qd + ( 1.0 - FD2 ) * T5 * Qi / 2 ; + + if ( Qd > 0.0 ) { + Qd = 0.0 ; + Qd_dVbs = 0.0 ; + Qd_dVds = 0.0 ; + Qd_dVgs = 0.0 ; + } + + } + + + +/*-----------------------------------------------------------* +* Modified potential for symmetry. +*-----------------*/ + + T1 = exp( - ( Vds - Pds ) / ( 2.0 * sIN.pzadd0 ) ) ; + + Pzadd = sIN.pzadd0 * T1 ; + + T2 = - 0.5 * T1 ; + + Pzadd_dVbs = T2 * ( - Pds_dVbs ) ; + Pzadd_dVds = T2 * ( 1.0 - Pds_dVds ) ; + Pzadd_dVgs = T2 * ( - Pds_dVgs ) ; + + if ( fabs ( Pzadd ) < epsm10 ) { + Pzadd = 0.0 ; + Pzadd_dVbs = 0.0 ; + Pzadd_dVds = 0.0 ; + Pzadd_dVgs = 0.0 ; + } + + + Ps0z = Ps0 + Pzadd ; + Ps0z_dVbs = Ps0_dVbs + Pzadd_dVbs ; + Ps0z_dVds = Ps0_dVds + Pzadd_dVds ; + Ps0z_dVgs = Ps0_dVgs + Pzadd_dVgs ; + + +/*-----------------------------------------------------------* +* Evaluate universal mobility. +*-----------------*/ + + Ps0Vbsz = Ps0z - Vbsz ; + Ps0Vbsz_dVbs = Ps0z_dVbs - Vbsz_dVbs ; + Ps0Vbsz_dVds = Ps0z_dVds - Vbsz_dVds ; + Ps0Vbsz_dVgs = Ps0z_dVgs ; + + +/*-------------------------------------------* +* Qbm +*-----------------*/ + + T1 = cnst0 ; + T2 = sqrt( beta * Ps0Vbsz - 1.0 ) ; + + Qbm = T1 * T2 ; + + T3 = 0.5 * beta * T1 / T2 ; + + Qbm_dVbs = T3 * Ps0Vbsz_dVbs ; + Qbm_dVds = T3 * Ps0Vbsz_dVds ; + Qbm_dVgs = T3 * Ps0Vbsz_dVgs ; + +/*-------------------------------------------* +* Qnm +*-----------------*/ + + Chi = beta * Ps0Vbsz ; + + exp_Chi = exp( Chi ) ; + + exp_bVbs = exp( beta * Vbsz ) ; + + cfs1 = cnst1 * exp_bVbs ; + + fs01 = cfs1 * ( exp_Chi - 1.0 ) ; + + /* regard fs01 as a function of Chi and Vbs */ + fs01_dChi = cfs1 * ( exp_Chi ) ; + fs01_dVbs = beta * fs01 ; + + + if ( fs01 < epsm10 * cfs1 ) { + fs01 = 0.0 ; + fs01_dPs0 = 0.0 ; + fs01_dVbs = 0.0 ; + } + + Xi0z = Chi - 1.0e0 ; + + Xi0z_dVbs = beta * Ps0Vbsz_dVbs ; + Xi0z_dVds = beta * Ps0Vbsz_dVds ; + Xi0z_dVgs = beta * Ps0Vbsz_dVgs ; + + fs02 = sqrt( Xi0z + fs01 ) ; + + T2 = 0.5e0 / fs02 ; + + /* regard fs01 as a function of Chi and Vbs */ + fs02_dChi = ( 1.0 + fs01_dChi ) * T2 ; + fs02_dVbs = fs01_dVbs * T2 ; + + Xi0zp12 = sqrt( Xi0z ) ; + + Xi0zp12_dVbs = 0.5e0 * Xi0z_dVbs / Xi0zp12 ; + Xi0zp12_dVds = 0.5e0 * Xi0z_dVds / Xi0zp12 ; + Xi0zp12_dVgs = 0.5e0 * Xi0z_dVgs / Xi0zp12 ; + + T1 = 1.0 / ( fs02 + Xi0zp12 ) ; + + Qnm = cnst0 * fs01 * T1 ; + + fs01_dVds = beta * Ps0Vbsz_dVds * fs01_dChi + + fs01_dVbs * Vbsz_dVds ; + fs01_dVbs = beta * Ps0Vbsz_dVbs * fs01_dChi + fs01_dVbs ; + fs01_dVgs = beta * Ps0Vbsz_dVgs * fs01_dChi ; + + fs02_dVds = beta * Ps0Vbsz_dVds * fs02_dChi + + fs02_dVbs * Vbsz_dVds ; + fs02_dVbs = beta * Ps0Vbsz_dVbs * fs02_dChi + fs02_dVbs ; + fs02_dVgs = beta * Ps0Vbsz_dVgs * fs02_dChi ; + + Qnm_dVbs = Qnm + * ( fs01_dVbs / fs01 + - ( fs02_dVbs + Xi0zp12_dVbs ) * T1 ) ; + Qnm_dVds = Qnm + * ( fs01_dVds / fs01 + - ( fs02_dVds + Xi0zp12_dVds ) * T1 ) ; + Qnm_dVgs = Qnm + * ( fs01_dVgs / fs01 + - ( fs02_dVgs + Xi0zp12_dVgs ) * T1 ) ; + + if ( Qbm < 0.0 ) { + Qbm = 0.0 ; + } + if ( Qnm < 0.0 ) { + Qnm = 0.0 ; + } + + + +/*---------------------------------------------------* +* Muun : universal mobility. +*-----------------*/ + + /* removed Eqs. "Qbm = Qb0", "Qnm = Qn0", ... (4/Dec/01) */ + + T1 = sIN.ninv - sIN.ninvd * Vdsz ; + T1_dVds = - sIN.ninvd * Vdsz_dVds ; + + Eeff = ( sIN.ndep * Qbm + T1 * Qnm ) / C_ESI ; + Eeff_dVbs = ( sIN.ndep * Qbm_dVbs + T1 * Qnm_dVbs ) + / C_ESI ; + Eeff_dVds = ( sIN.ndep * Qbm_dVds + T1 * Qnm_dVds + + T1_dVds * Qnm ) + / C_ESI ; + Eeff_dVgs = ( sIN.ndep * Qbm_dVgs + T1 * Qnm_dVgs ) + / C_ESI ; + + Rns = Qnm / C_QE ; + + T10 = pow( sIN.temp / C_T300 , sIN.muetmp ) ; + T21 = pow( Eeff , sIN.mueph0 - 1.0e0 ) ; + T20 = T21 * Eeff ; + T31 = pow( Eeff , sIN.muesr0 - 1.0e0 ) ; + T30 = T31 * Eeff ; + + T1 = 1e0 / ( sIN.muecb0 + sIN.muecb1 * Rns / 1e11 ) + + T10 + * T20 / mueph + + T30 / sIN.muesr1 ; + + Muun = 1e0 / T1 ; + + T1 = 1e0 / ( T1 * T1 ) ; + T2 = sIN.muecb0 + sIN.muecb1 * Rns / 1e11 ; + T2 = 1e0 / ( T2 * T2 ) ; + T3 = T10 * sIN.mueph0 * T21 / mueph ; + T4 = sIN.muesr0 * T31 / sIN.muesr1 ; + + Muun_dVbs = - 1 * ( - 1e-11 * sIN.muecb1 * Qnm_dVbs / C_QE * T2 + + Eeff_dVbs * T3 + + Eeff_dVbs * T4 ) + * T1 ; + Muun_dVds = - 1 * ( - 1e-11 * sIN.muecb1 * Qnm_dVds / C_QE * T2 + + Eeff_dVds * T3 + + Eeff_dVds * T4 ) + * T1 ; + Muun_dVgs = - 1 * ( - 1e-11 * sIN.muecb1 * Qnm_dVgs / C_QE * T2 + + Eeff_dVgs * T3 + + Eeff_dVgs * T4 ) + * T1 ; + + +/*-----------------------------------------------------------* +* Mu : mobility +*-----------------*/ + + T1 = 1.0e0 / beta / ( Qn0 + small ) / ( Leff - Lred ) ; + T1_dVbs = 1.0e0 / beta * ( - Qn0_dVbs / ( Qn0 + small ) + / ( Qn0 + small ) / ( Leff - Lred ) + + Lred_dVbs / ( Qn0 + small ) / ( Leff - Lred ) + / ( Leff - Lred ) ) ; + T1_dVds = 1.0e0 / beta * ( - Qn0_dVds / ( Qn0 + small ) + / ( Qn0 + small ) / ( Leff - Lred ) + + Lred_dVds / ( Qn0 + small ) / ( Leff - Lred ) + / ( Leff - Lred ) ) ; + T1_dVgs = 1.0e0 / beta * ( - Qn0_dVgs / ( Qn0 + small ) + / ( Qn0 + small ) / ( Leff - Lred ) + + Lred_dVgs / ( Qn0 + small ) / ( Leff - Lred ) + / ( Leff - Lred ) ) ; + + Ey = Idd * T1 ; + Ey_dVbs = Idd_dVbs * T1 + Idd * T1_dVbs ; + Ey_dVds = Idd_dVds * T1 + Idd * T1_dVds ; + Ey_dVgs = Idd_dVgs * T1 + Idd * T1_dVgs ; + + + Em = Muun * Ey ; + Em_dVbs = Muun_dVbs * Ey + Muun * Ey_dVbs ; + Em_dVds = Muun_dVds * Ey + Muun * Ey_dVds ; + Em_dVgs = Muun_dVgs * Ey + Muun * Ey_dVgs ; + + T1 = sIN.temp / C_T300 ; + + Vmax = sIN.vmax / ( 1.8 + 0.4 * T1 + 0.1 * T1 * T1 ) ; + + T2 = 1.0 - sIN.vover / pow( Lgate , sIN.voverp ) ; + + if ( T2 < 0.01 ) { + fprintf( stderr , + "*** warning(HiSIM): Overshoot is too big.\n" ) ; + T2 = 0.01 ; + } + + Vmax = Vmax / T2 ; + + T1 = Em / Vmax ; + + /* note: sIN.bb = 2 (electron) ;1 (hole) */ + if ( 1.0e0 - epsm10 <= sIN.bb && sIN.bb <= 1.0e0 + epsm10 ) { + T3 = 1.0e0 ; + } else if ( 2.0e0 - epsm10 <= sIN.bb + && sIN.bb <= 2.0e0 + epsm10 ) { + T3 = T1 ; + } else { + T3 = pow( T1 , sIN.bb - 1.0e0 ) ; + } + T2 = T1 * T3 ; + T4 = 1.0e0 + T2 ; + T6 = pow( T4 , ( - 1.0e0 / sIN.bb - 1.0e0 ) ) ; + T5 = T4 * T6 ; + + Mu = Muun * T5 ; + Mu_dVbs = Muun_dVbs * T5 - Muun / Vmax * T6 * T3 * Em_dVbs ; + Mu_dVds = Muun_dVds * T5 - Muun / Vmax * T6 * T3 * Em_dVds ; + Mu_dVgs = Muun_dVgs * T5 - Muun / Vmax * T6 * T3 * Em_dVgs ; + + +end_of_mobility : ; + +/*-----------------------------------------------------------* +* Ids: channel current. +*-----------------*/ + + + T1 = Weff / beta / ( Leff - Lred ) ; + T1_dVbs = T1 / ( Leff - Lred ) * Lred_dVbs ; + T1_dVds = T1 / ( Leff - Lred ) * Lred_dVds ; + T1_dVgs = T1 / ( Leff - Lred ) * Lred_dVgs ; + + Ids0 = T1 * Idd * Mu ; + Ids0_dVbs = T1 * ( Mu * Idd_dVbs + Idd * Mu_dVbs ) + + T1_dVbs * Mu * Idd ; + Ids0_dVds = T1 * ( Mu * Idd_dVds + Idd * Mu_dVds ) + + T1_dVds * Mu * Idd ; + Ids0_dVgs = T1 * ( Mu * Idd_dVgs + Idd * Mu_dVgs ) + + T1_dVgs * Mu * Idd ; + + T1 = Vdsz + sIN.rpock2 ; + T2 = T1 * T1 + small ; + T2_dVbs = 0.0e0 ; + T2_dVds = 2.0 * T1 * Vdsz_dVds ; + T2_dVgs = 0.0e0 ; + + rp1 = FMD * sIN.rpock1 ; + rp1_dVds = FMD_dVds * sIN.rpock1 ; + + TX = Ids0 * sqrt( Leff ) / Weff ; + T3 = rp1 * TX ; + T4 = ( T3 + T2 ) * ( T3 + T2 ); + + Ids = Ids0 / ( 1.0 + T3 / T2 ) ; + + T5 = T2 * T2 / T4 ; + T6 = Ids0 * T3 / T4 ; + + Ids_dVbs = T5 * Ids0_dVbs + T6 * T2_dVbs ; + Ids_dVds = T5 * Ids0_dVds + T6 * T2_dVds + - Ids0 * T2 / T4 * rp1_dVds * TX ; + Ids_dVgs = T5 * Ids0_dVgs + T6 * T2_dVgs ; + + if ( Pds < ps_conv ) { + Ids_dVbs = 0.0 ; + Ids_dVgs = 0.0 ; + } + + Ids += Gdsmin * Vds ; + Ids_dVds += Gdsmin ; + + +/*-----------------------------------------------------------* +* Break point for the case of Rs=Rd=0. +*-----------------*/ + + if ( flg_rsrd == 0 ) { + DJI = 1.0 ; + break ; + } + + + +/*-----------------------------------------------------------* +* calculate corrections of biases. +* - Fbs = 0, etc. are the small ciucuit equations. +* - DJ, Jacobian of the small circuit matrix, is g.t. 1 +* provided Rs, Rd and conductances are positive. +*-----------------*/ + + Fbs = Vbs - Vbsc + Ids * Rs ; + Fds = Vds - Vdsc + Ids * ( Rs + Rd ) ; + Fgs = Vgs - Vgsc + Ids * Rs ; + + DJ = 1.0 + Rs * Ids_dVbs + ( Rs + Rd ) * Ids_dVds + Rs * Ids_dVgs ; + DJI = 1.0 / DJ ; + + JI11 = 1 + ( Rs + Rd ) * Ids_dVds + Rs * Ids_dVgs ; + JI12 = - Rs * Ids_dVds ; + JI13 = - Rs * Ids_dVgs ; + JI21 = - ( Rs + Rd ) * Ids_dVbs ; + JI22 = 1 + Rs * Ids_dVbs + Rs * Ids_dVgs ; + JI23 = - ( Rs + Rd ) * Ids_dVgs ; + JI31 = - Rs * Ids_dVbs ; + JI32 = - Rs * Ids_dVds ; + JI33 = 1 + Rs * Ids_dVbs + ( Rs + Rd ) * Ids_dVds ; + + dVbs = - DJI * ( JI11 * Fbs + JI12 * Fds + JI13 * Fgs ) ; + dVds = - DJI * ( JI21 * Fbs + JI22 * Fds + JI23 * Fgs ) ; + dVgs = - DJI * ( JI31 * Fbs + JI32 * Fds + JI33 * Fgs ) ; + + dV_sum = fabs( dVbs ) + fabs( dVds ) + fabs( dVgs ) ; + + +/*-----------------------------------------------------------* +* Break point for converged case. +* - Exit from the bias loop. +* - NOTE: Update of internal biases is avoided. +*-----------------*/ + + + if ( Ids_last * Ids_tol >= fabs( Ids_last - Ids ) || + dV_sum < ps_conv ) { + break ; + } + +/*-----------------------------------------------------------* +* Update the internal biases. +*-----------------*/ + + Vbs = Vbs + dVbs ; + Vds = Vds + dVds ; + Vgs = Vgs + dVgs ; + + if ( Vds < 0.0 ) { + Vds = 0.0 ; + dVds = 0.0 ; + } + +/*-----------------------------------------------------------* +* Bottom of bias loop. (label) +*-----------------*/ +bottom_of_bias_loop : ; + + + +/*-----------------------------------------------------------* +* Make initial guess flag of potential ON. +* - This effects for the 2nd and later iterations of bias loop. +*-----------------*/ + flg_pprv = 1 ; + + } /*++ End of the bias loop +++++++++++++++++++++++++++++*/ + + if ( lp_bs > lp_bs_max ) { lp_bs -- ; } + + +/*-----------------------------------------------------------* +* End of PART-1. (label) +*-----------------*/ +end_of_part_1: ; + + + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +* PART-2: Substrate / gate / leak currents +*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + +/*-----------------------------------------------------------* +* Isub : substrate current induced by impact ionization. +*-----------------*/ +/*-------------------------------------------* +* Accumulation zone or nonconductive case, in which Ids==0. +*-----------------*/ + + if ( Ids <= 0.0e0 || sIN.coisub >= 1 ) { + Isub = 0.0e0 ; + Isub_dVbs = 0.0e0 ; + Isub_dVds = 0.0e0 ; + Isub_dVgs = 0.0e0 ; + goto end_of_Isub ; + } + +/*-------------------------------------------* +* Conductive case. +*-----------------*/ + + if ( sIN.sub1 > 0.0e0 && sIN.vmax > 0.0e0 ) { + + Vdep = Vds + Ps0 - sIN.sub3 * Psl ; + Vdep_dVbs = Ps0_dVbs - sIN.sub3 * Psl_dVbs ; + Vdep_dVds = 1.0e0 + Ps0_dVds - sIN.sub3 * Psl_dVds ; + Vdep_dVgs = Ps0_dVgs - sIN.sub3 * Psl_dVgs ; + + TX = - sIN.sub2 / Vdep ; + + Epkf = exp( TX ) ; + Epkf_dVbs = - TX * Vdep_dVbs / Vdep * Epkf ; + Epkf_dVds = - TX * Vdep_dVds / Vdep * Epkf ; + Epkf_dVgs = - TX * Vdep_dVgs / Vdep * Epkf ; + + T1 = Ids * Epkf ; + T1_dVbs = Ids_dVbs * Epkf + Ids * Epkf_dVbs ; + T1_dVds = Ids_dVds * Epkf + Ids * Epkf_dVds ; + T1_dVgs = Ids_dVgs * Epkf + Ids * Epkf_dVgs ; + + if( T1 < 1.0e-25 ){ + T1 = 1.0e-25 ; + T1_dVbs = 0.0e0 ; + T1_dVds = 0.0e0 ; + T1_dVgs = 0.0e0 ; + } + + Isub = sIN.sub1 * Vdep * T1 ; + Isub_dVbs = sIN.sub1 * ( Vdep_dVbs * T1 + Vdep * T1_dVbs ) ; + Isub_dVds = sIN.sub1 * ( Vdep_dVds * T1 + Vdep * T1_dVds ) ; + Isub_dVgs = sIN.sub1 * ( Vdep_dVgs * T1 + Vdep * T1_dVgs ) ; + + } else { + + Isub = 0.0e0 ; + Isub_dVbs = 0.0e0 ; + Isub_dVds = 0.0e0 ; + Isub_dVgs = 0.0e0 ; + + } /* end of if ( sIN.sub1 ... ) else block. */ + +/*-------------------------------------------* +* End of Isub. (label) +*-----------------*/ +end_of_Isub: ; + +/*-----------------------------------------------------------* +* Igs : Gate current induced by tunneling. +* - Vzadd is used for symmetrizing. +*-----------------*/ + + if ( sIN.coiigs >= 1 ) { + Igs = 0.0e0 ; + Igs_dVbs = 0.0e0 ; + Igs_dVds = 0.0e0 ; + Igs_dVgs = 0.0e0 ; + goto end_of_Igs ; + } + + Egp12 = sqrt( Eg ) ; + Egp32 = Eg * Egp12 ; + + Vgpz = Vgp + Vzadd ; + + Vgpz_dVbs = Vgp_dVbs ; + Vgpz_dVds = Vgp_dVds + Vzadd_dVds ; + Vgpz_dVgs = Vgp_dVgs ; + + T1 = Vgpz - ( Psl + Ps0 + 2.0 * Vzadd ) * sIN.gleak3 ; + + E0 = 10.0 ; + + E2 = T1 / Tox ; + + E2_dVbs = E2 + * ( ( Vgpz_dVbs - ( Psl_dVbs + Ps0_dVbs ) * sIN.gleak3 ) + / T1 + - Tox_dVbs / Tox ) ; + E2_dVds = E2 + * ( ( Vgpz_dVds + - ( Psl_dVds + Ps0_dVds + 2.0 * Vzadd_dVds ) + * sIN.gleak3 + ) / T1 + - Tox_dVds / Tox ) ; + E2_dVgs = E2 + * ( ( Vgpz_dVgs - ( Psl_dVgs + Ps0_dVgs ) * sIN.gleak3 ) + / T1 + - Tox_dVgs / Tox ) ; + + T1 = E2 - E0 - eef_dlt ; + T2 = T1 * T1 ; + + T3 = sqrt( T2 + 4.0 * eef_dlt * E2 ) ; + + Etun = E2 - ( T1 - T3 ) / 2 ; + + T4 = 1.0 / ( 4.0 * T3 ) ; + T5 = 2.0 * T1 * T4 + 0.5 ; + + Etun_dVbs = T5 * E2_dVbs ; + Etun_dVds = T5 * E2_dVds ; + Etun_dVgs = T5 * E2_dVgs ; + + T1 = exp( - sIN.gleak2 * Egp32 / Etun ) ; + + T2 = sIN.gleak1 / Egp12 * C_QE * Weff * Leff ; + + Igs = T2 * Etun * Etun * T1 ; + + T3 = T2 * T1 * ( 2.0 * Etun + sIN.gleak2 * Egp32 ) ; + + Igs_dVbs = T3 * Etun_dVbs ; + Igs_dVds = T3 * Etun_dVds ; + Igs_dVgs = T3 * Etun_dVgs ; + + end_of_Igs: ; + +/*-----------------------------------------------------------* +* Ilg : GIDL +*-----------------*/ + + if ( sIN.cogidl >= 1 ) { + Ilg = 0.0e0 ; + Ilg_dVbs = 0.0e0 ; + Ilg_dVds = 0.0e0 ; + Ilg_dVgs = 0.0e0 ; + goto end_of_IGIDL ; + } + + T1 = sIN.gidl3 * Vdsz - Vgsz + dVth ; + + E1 = T1 / Tox ; + + E1_dVbs = E1 * ( dVth_dVbs / T1 - Tox_dVbs / Tox ) ; + E1_dVds = E1 * ( ( sIN.gidl3 * Vdsz_dVds - Vgsz_dVds + dVth_dVds ) + / T1 + - Tox_dVds / Tox ) ; + E1_dVgs = E1 * ( ( -1.0 + dVth_dVgs ) / T1 - Tox_dVgs / Tox ) ; + + T1 = E0 - E1 - eef_dlt ; + T2 = T1 * T1 ; + + T3 = sqrt( T2 + 4.0 * eef_dlt * E0 ) ; + + Egidl = E0 - ( T1 - T3 ) / 2 ; + + T4 = 1.0 / ( 4.0 * T3 ) ; + T5 = - 2.0 * T1 * T4 + 0.5 ; + + Egidl_dVbs = T5 * E1_dVbs ; + Egidl_dVds = T5 * E1_dVds ; + Egidl_dVgs = T5 * E1_dVgs ; + + T1 = exp( - sIN.gidl2 * Egp32 / Egidl ) ; + + T2 = sIN.gidl1 / Egp12 * C_QE * Weff ; + + Ilg = T2 * Egidl * Egidl * T1 ; + + T3 = T2 * T1 * ( 2.0 * Egidl + sIN.gidl2 * Egp32 ) ; + + Ilg_dVbs = T3 * Egidl_dVbs ; + Ilg_dVds = T3 * Egidl_dVds ; + Ilg_dVgs = T3 * Egidl_dVgs ; + + end_of_IGIDL: ; + +/*-----------------------------------------------------------* +* End of PART-2. (label) +*-----------------*/ +end_of_part_2: ; + + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +* PART-3: Overlap charge +*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + + +/*-------------------------------------------* +* Calculation of Psdl for cases of flg_noqi==1. +*-----------------*/ + + if ( flg_noqi != 0 ) { + + T2 = Vds + Ps0 ; + T2_dVbs = Ps0_dVbs ; + T2_dVds = 1.0e0 + Ps0_dVds ; + T2_dVgs = Ps0_dVgs ; + + Aclm = sIN.clm1 ; + + Psdl = Aclm * T2 + ( 1.0e0 - Aclm ) * Psl ; + Psdl_dVbs = Aclm * T2_dVbs + ( 1.0e0 - Aclm ) * Psl_dVbs ; + Psdl_dVds = Aclm * T2_dVds + ( 1.0e0 - Aclm ) * Psl_dVds ; + Psdl_dVgs = Aclm * T2_dVgs + ( 1.0e0 - Aclm ) * Psl_dVgs ; + + if ( Psdl > Ps0 + Vds - epsm10 ) { + Psdl = Ps0 + Vds - epsm10 ; + } + } + + +/*-------------------------------------------* +* Overlap charge (simple, default, CLM1 < 1.0) <-- changed 04/Dec/01 +* (orig. "CLM1 must be 1.0") +*-----------------*/ + if ( sIN.coovlp == 0 ){ + + T1 = Cox * Weff ; + Lov = sIN.xld + sIN.xpolyd ; + Qgos = Vgs * Lov * T1 ; + Qgos_dVbs = 0.0e0 ; + Qgos_dVds = 0.0e0 ; + Qgos_dVgs = Lov * T1 ; + + T2 = - 1.0e+11 ; + yn = sqrt ( ( Psdl - Ps0 - Vds) / T2 ) ; + yn2 = yn * yn ; + yn3 = yn2 * yn ; + T3 = 0.5e0 / yn / T2 ; + + yn_dVbs = T3 * ( Psdl_dVbs - Ps0_dVbs ) ; + yn_dVds = T3 * ( Psdl_dVds - Ps0_dVds - 1.0e0 ) ; + yn_dVgs = T3 * ( Psdl_dVgs - Ps0_dVgs ) ; + + if ( yn <= Lov ){ + Qgod = ( ( Vgs - Vds ) * Lov - T2 * yn3 / 3.0e0 ) * T1 ; + Qgod_dVbs = ( (-1.0e0) * T2 * yn2 * yn_dVbs ) * T1 ; + Qgod_dVds = ( (-1.0e0) * Lov - T2 * yn2 * yn_dVds ) * T1 ; + Qgod_dVgs = ( Lov - T2 * yn2 * yn_dVgs ) * T1 ; + }else{ + T4 = (Lov - yn ) * (Lov - yn ) ; + T5 = T4 * (Lov - yn ) ; + Qgod = ( ( Vgs - Vds ) * Lov - T2 / 3.0e0 * ( T5 + yn3 ) ) * T1 ; + Qgod_dVbs = ( (-1.0e0) * T2 * yn2 * yn_dVbs + + T2 * T4 * yn_dVbs ) * T1; + Qgod_dVds = ( (-1.0e0) * Lov - T2 * yn2 * yn_dVds + + T2 * T4 * yn_dVds ) * T1; + Qgod_dVgs = ( Lov - T2 * yn2 * yn_dVgs + + T2 * T4 * yn_dVgs ) * T1; + } + } +/*-------------------------------------------* +* Overlap charge (complete) +*-----------------*/ + + else if( sIN.coovlp > 0 ){ + + T1 = Cox * Weff ; + + Qgos = Vgs * ( sIN.xld + sIN.xpolyd ) * T1 ; + Qgos_dVbs = 0.0e0 ; + Qgos_dVds = 0.0e0 ; + Qgos_dVgs = ( sIN.xld + sIN.xpolyd ) * T1 ; + + T3 = 1e21 / pow( sIN.xld + sIN.xpolyd , 3e0) ; + T1 = C_QE * T3 / ( C_ESI * 4e0 ) ; + T2 = Cox * Weff ; + + Lov = sIN.xld + sIN.xpolyd ; + Lov2 = Lov * Lov ; + + yn = pow( C_ESI * 5e0 / ( C_QE * T3 ) + * ( Ps0 + Vds - Psdl ) + , 0.2e0 ) ; + yn2 = yn * yn ; + + if ( yn < Lov ) { + Qgod = ( ( Vgs - Vds ) * ( sIN.xld + sIN.xpolyd ) + + T1 / 3e0 * yn2 * yn2 * yn2 ) * T2 ; + Qgod_dVbs = ( yn / 2e0 * ( Ps0_dVbs - Psdl_dVbs ) ) * T2 ; + Qgod_dVds = ( - 1e0 * ( sIN.xld + sIN.xpolyd ) + + yn / 2e0 * ( Ps0_dVds + 1e0 - Psdl_dVds ) ) * T2 ; + Qgod_dVgs = ( 1e0 * ( sIN.xld + sIN.xpolyd ) + + yn / 2e0 * ( Ps0_dVgs - Psdl_dVgs ) ) * T2 ; + } else { + T3 = C_ESI * 5e0 / ( C_QE * T3 ) ; + + Qgod = ( ( Vgs + T1 * 4e0 / 5e0 * yn2 * yn2 * yn - Vds ) * Lov + + T1 / 30e0 * Lov2 * Lov2 * Lov2 + - T1 * yn2 * yn2 / 2e0 * Lov2 ) * T2 ; + Qgod_dVbs = ( ( T1 * 4e0 / 5e0 * T3 * ( Ps0_dVbs - Psdl_dVbs ) ) * Lov + - 2e0 * T1 / 5e0 * T3 / yn * ( Ps0_dVbs - Psdl_dVbs ) * Lov2 ) + * T2 ; + Qgod_dVds = ( ( T1 * 4e0 / 5e0 * T3 * ( Ps0_dVds + 1e0 - Psdl_dVds ) - 1e0 ) + * Lov + - 2e0 * T1 / 5e0 * T3 / yn * ( Ps0_dVds + 1e0 - Psdl_dVds ) + * Lov2 ) * T2 ; + Qgod_dVgs = ( ( 1e0 + T1 * 4e0 / 5e0 * T3 * ( Ps0_dVgs - Psdl_dVgs ) ) * Lov + - 2e0 * T1 / 5e0 * T3 / yn * ( Ps0_dVgs - Psdl_dVgs ) * Lov2 ) + * T2 ; + } + } + +/*-------------------------------------------* +* Overlap charge (off) +*-----------------*/ + + else if( sIN.coovlp < 0 ){ + + Qgos = 0.0e0 ; + Qgos_dVbs = 0.0e0 ; + Qgos_dVds = 0.0e0 ; + Qgos_dVgs = 0.0e0 ; + + Qgod = 0.0e0 ; + Qgod_dVbs = 0.0e0 ; + Qgod_dVds = 0.0e0 ; + Qgod_dVgs = 0.0e0 ; + + } + +/*-----------------------------------------------------------* +* End of PART-3. (label) +*-----------------*/ +end_of_part_3: ; + + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +* PART-4: Substrate-source/drain junction diode. +*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + + + +/*-----------------------------------------------------------* +* Cbsj, Cbdj: node-base S/D biases. +*-----------------*/ + + if (sIN.mode == HiSIM_NORMAL_MODE ){ + Vbdj = Vbde ; + Vbsj = Vbse ; + } else { + Vbdj = Vbse ; + Vbsj = Vbde ; + } + + /* Vbdc = Vbsc - Vdsc ;*/ + + js = sIN.js0 * exp( ( Eg300 * C_b300 - Eg * beta + + sIN.xti * log( sIN.temp / C_T300 ) ) / sIN.nj ) ; + jssw = sIN.js0sw * exp( ( Eg300 * C_b300 - Eg * beta + + sIN.xti * log( sIN.temp / C_T300 ) ) + / sIN.njsw ) ; + + Nvtm = sIN.nj / beta ; + + + /* ibd */ + isbd = sIN.ad * js + sIN.pd * jssw ; + + if ( Vbdj < 0.5 ) { + Ibd = isbd * ( exp( Vbdj / Nvtm ) - 1 ) ; + Gbd = isbd / Nvtm * exp( Vbdj / Nvtm ) ; + + } else { + Ibd = isbd * ( exp( 0.5 / Nvtm ) - 1 ) + + isbd / Nvtm * exp( 0.5 / Nvtm ) * ( Vbdj - 0.5 ) ; + Gbd = isbd / Nvtm * exp( 0.5 / Nvtm ) ; + } + + + /* ibs */ + isbs = sIN.as * js + sIN.ps * jssw ; + + if ( Vbsj < 0.5 ) { + Ibs = isbs * ( exp( Vbsj / Nvtm ) - 1 ) ; + Gbs = isbs / Nvtm * exp( Vbsj / Nvtm ) ; + + } else { + Ibs = isbs * ( exp( 0.5 / Nvtm ) - 1 ) + + isbs / Nvtm * exp( 0.5 / Nvtm ) * (Vbsj - 0.5 ) ; + Gbs = isbs / Nvtm * exp( 0.5 / Nvtm ) ; + } + +/*---------------------------------------------------* +* Add Gjmin. +*-----------------*/ + + Ibd += Gjmin * Vbdj ; + Ibs += Gjmin * Vbsj ; + + Gbd += Gjmin ; + Gbs += Gjmin ; + +/*-----------------------------------------------------------* +* Charges and Capacitances. +*-----------------*/ + /* charge storage elements + * bulk-drain and bulk-source depletion capacitances + * czbd : zero bias drain junction capacitance + * czbs : zero bias source junction capacitance + * czbdsw:zero bias drain junction sidewall capacitance + * czbssw:zero bias source junction sidewall capacitance + */ + + czbd = sIN.cj * sIN.ad ; + czbs = sIN.cj * sIN.as ; + + /* Source Bulk Junction */ + if (sIN.ps > Weff) { + czbssw = sIN.cjsw * ( sIN.ps - Weff ) ; + czbsswg = sIN.cjswg * Weff ; + if (Vbsj == 0.0) + { Qbs = 0.0 ; + Capbs = czbs + czbssw ; + } + else if (Vbsj < 0.0) + { if (czbs > 0.0) + { arg = 1.0 - Vbsj / sIN.pb ; + if (sIN.mj == 0.5) + sarg = 1.0 / sqrt(arg) ; + else + sarg = exp(-sIN.mj * log(arg)) ; + Qbs = sIN.pb * czbs + * (1.0 - arg * sarg) / (1.0 - sIN.mj) ; + Capbs = czbs * sarg ; + } + else + { Qbs = 0.0 ; + Capbs = 0.0; + } + if (czbssw > 0.0) + { arg = 1.0 - Vbsj / sIN.pbsw; + if (sIN.mjsw == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-sIN.mjsw * log(arg)); + Qbs += sIN.pbsw * czbssw + * (1.0 - arg * sarg) / (1.0 - sIN.mjsw); + Capbs += czbssw * sarg; + } + if (czbsswg > 0.0) + { arg = 1.0 - Vbsj / sIN.pbswg; + if (sIN.mjswg == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-sIN.mjswg * log(arg)); + Qbs += sIN.pbswg * czbsswg + * (1.0 - arg * sarg) / (1.0 - sIN.mjswg); + Capbs += czbsswg * sarg; + } + } + else + { Qbs = Vbsj * (czbs + czbssw + czbsswg) + + Vbsj * Vbsj * (czbs * sIN.mj * 0.5 / sIN.pb + + czbssw * sIN.mjsw * 0.5 / sIN.pbsw + + czbsswg * sIN.mjswg + * 0.5 / sIN.pbswg); + Capbs = czbs + + czbssw + czbsswg + Vbsj * (czbs * sIN.mj /sIN.pb + + czbssw * sIN.mjsw / sIN.pbsw + + czbsswg * sIN.mjswg / sIN.pbswg ); + } + + } else { + czbsswg = sIN.cjswg * sIN.ps ; + if (Vbsj == 0.0) + { Qbs = 0.0 ; + Capbs = czbs + czbsswg ; + } + else if (Vbsj < 0.0) + { if (czbs > 0.0) + { arg = 1.0 - Vbsj / sIN.pb ; + if (sIN.mj == 0.5) + sarg = 1.0 / sqrt(arg) ; + else + sarg = exp(-sIN.mj * log(arg)) ; + Qbs = sIN.pb * czbs + * (1.0 - arg * sarg) / (1.0 - sIN.mj) ; + Capbs = czbs * sarg ; + } + else + { Qbs = 0.0 ; + Capbs = 0.0; + } + if (czbsswg > 0.0) + { arg = 1.0 - Vbsj / sIN.pbswg; + if (sIN.mjswg == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-sIN.mjswg * log(arg)); + Qbs += sIN.pbswg * czbsswg + * (1.0 - arg * sarg) / (1.0 - sIN.mjswg); + Capbs += czbsswg * sarg; + } + } + else + { Qbs = Vbsj * (czbs + czbsswg) + + Vbsj * Vbsj * (czbs * sIN.mj * 0.5 / sIN.pb + + czbsswg * sIN.mjswg * 0.5 / sIN.pbswg); + Capbs = czbs + + czbsswg + Vbsj * (czbs * sIN.mj /sIN.pb + + czbsswg * sIN.mjswg / sIN.pbswg ); + } + } + + + /* Drain Bulk Junction */ + if (sIN.pd > Weff) { + czbdsw = sIN.cjsw * ( sIN.pd - Weff ) ; + czbdswg = sIN.cjswg * Weff ; + if (Vbdj == 0.0) + { Qbd = 0.0 ; + Capbd = czbd + czbdsw ; + } + else if (Vbdj < 0.0) + { if (czbd > 0.0) + { arg = 1.0 - Vbdj / sIN.pb ; + if (sIN.mj == 0.5) + sarg = 1.0 / sqrt(arg) ; + else + sarg = exp(-sIN.mj * log(arg)) ; + Qbd = sIN.pb * czbd + * (1.0 - arg * sarg) / (1.0 - sIN.mj) ; + Capbd = czbd * sarg ; + } + else + { Qbd = 0.0 ; + Capbd = 0.0; + } + if (czbdsw > 0.0) + { arg = 1.0 - Vbdj / sIN.pbsw; + if (sIN.mjsw == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-sIN.mjsw * log(arg)); + Qbd += sIN.pbsw * czbdsw + * (1.0 - arg * sarg) / (1.0 - sIN.mjsw); + Capbd += czbdsw * sarg; + } + if (czbdswg > 0.0) + { arg = 1.0 - Vbdj / sIN.pbswg; + if (sIN.mjswg == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-sIN.mjswg * log(arg)); + Qbd += sIN.pbswg * czbdswg + * (1.0 - arg * sarg) / (1.0 - sIN.mjswg); + Capbd += czbdswg * sarg; + } + } + else + { Qbd = Vbdj * (czbd + czbdsw + czbdswg) + + Vbdj * Vbdj * (czbd * sIN.mj * 0.5 / sIN.pb + + czbdsw * sIN.mjsw * 0.5 / sIN.pbsw + + czbdswg * sIN.mjswg + * 0.5 / sIN.pbswg); + Capbd = czbd + + czbdsw + czbdswg + Vbdj * (czbd * sIN.mj /sIN.pb + + czbdsw * sIN.mjsw / sIN.pbsw + + czbdswg * sIN.mjswg / sIN.pbswg ); + } + + } else { + czbdswg = sIN.cjswg * sIN.pd ; + if (Vbdj == 0.0) + { Qbd = 0.0 ; + Capbd = czbd + czbdswg ; + } + else if (Vbdj < 0.0) + { if (czbd > 0.0) + { arg = 1.0 - Vbdj / sIN.pb ; + if (sIN.mj == 0.5) + sarg = 1.0 / sqrt(arg) ; + else + sarg = exp(-sIN.mj * log(arg)) ; + Qbd = sIN.pb * czbd + * (1.0 - arg * sarg) / (1.0 - sIN.mj) ; + Capbd = czbd * sarg ; + } + else + { Qbd = 0.0 ; + Capbd = 0.0; + } + if (czbdswg > 0.0) + { arg = 1.0 - Vbdj / sIN.pbswg; + if (sIN.mjswg == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-sIN.mjswg * log(arg)); + Qbd += sIN.pbswg * czbdswg + * (1.0 - arg * sarg) / (1.0 - sIN.mjswg); + Capbd += czbdswg * sarg; + } + } + else + { Qbd = Vbdj * (czbd + czbdswg) + + Vbdj * Vbdj * (czbd * sIN.mj * 0.5 / sIN.pb + + czbdswg * sIN.mjswg * 0.5 / sIN.pbswg); + Capbd = czbd + + czbdswg + Vbdj * (czbd * sIN.mj /sIN.pb + + czbdswg * sIN.mjswg / sIN.pbswg ); + } + } + + + +/*-----------------------------------------------------------* +* End of PART-4. (label) +*-----------------*/ +end_of_part_4: ; + + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +* PART-5: Noise Calculation. +*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + + if ( sIN.conois != 0 ){ + + NFalp = sIN.nfalp ; + NFtrp = sIN.nftrp ; + Cit = sIN.cit ; + + T1 = Qn0 / C_QE ; + T2 = (Cox+Qn0/(Ps0-Vbs)+Cit)/beta/C_QE ; + T3 = 1.0E0/(T1+T2)+NFalp*Mu ; + Nflic = Ids*Ids*NFtrp/((Leff-Lred)*beta*Weff)*T3*T3 ; + + } else { + Nflic = 0.0 ; + } + + +/*-----------------------------------------------------------* +* End of PART-5. (label) +*-----------------*/ +end_of_part_5: ; + + + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +* PART-6: Evaluation of outputs. +*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + +/*-----------------------------------------------------------* +* Implicit quantities related to Alpha. +*-----------------*/ + + /* note: T1 = 1 + Delta */ + if ( flg_noqi == 0 && VgVt > VgVt_small && Pds > 0.0 ) { + T1 = Achi / Pds ; + Delta = T1 - 1.0e0 ; + Vdsat = VgVt / T1 ; + } else { + Alpha = 1.0 ; + Delta = 0.0 ; + Vdsat = 0.0 ; + Achi = 0.0 ; + } + +/*-----------------------------------------------------------* +* Evaluate the derivatives w.r.t. external biases. +* - All derivatives that influence outputs must be modified here. +*-----------------*/ + +/*---------------------------------------------------* +* Case ignoring Rs/Rd. +*-----------------*/ + if ( flg_rsrd == 0 || Ids <= 0.0 ) { + + Ids_dVbse = Ids_dVbs ; + Ids_dVdse = Ids_dVds ; + Ids_dVgse = Ids_dVgs ; + + Qb_dVbse = Qb_dVbs ; + Qb_dVdse = Qb_dVds ; + Qb_dVgse = Qb_dVgs ; + + Qi_dVbse = Qi_dVbs ; + Qi_dVdse = Qi_dVds ; + Qi_dVgse = Qi_dVgs ; + + Qd_dVbse = Qd_dVbs ; + Qd_dVdse = Qd_dVds ; + Qd_dVgse = Qd_dVgs ; + + Isub_dVbse = Isub_dVbs ; + Isub_dVdse = Isub_dVds ; + Isub_dVgse = Isub_dVgs ; + + Igs_dVbse = Igs_dVbs ; + Igs_dVdse = Igs_dVds ; + Igs_dVgse = Igs_dVgs ; + + Ilg_dVbse = Ilg_dVbs ; + Ilg_dVdse = Ilg_dVds ; + Ilg_dVgse = Ilg_dVgs ; + + Qgos_dVbse = Qgos_dVbs ; + Qgos_dVdse = Qgos_dVds ; + Qgos_dVgse = Qgos_dVgs ; + + Qgod_dVbse = Qgod_dVbs ; + Qgod_dVdse = Qgod_dVds ; + Qgod_dVgse = Qgod_dVgs ; + + +/*---------------------------------------------------* +* Case Rs>0 or Rd>0 +*-----------------*/ + } else { + +/*-------------------------------------------* +* Conductances w.r.t. confined biases. +*-----------------*/ + + Ids_dVbse = Ids_dVbs * DJI ; + Ids_dVdse = Ids_dVds * DJI ; + Ids_dVgse = Ids_dVgs * DJI ; + +/*-------------------------------------------* +* Derivatives of internal biases w.r.t. external biases. +*-----------------*/ + Vbs_dVbse = ( 1.0 - Rs * Ids_dVbse ) ; + Vbs_dVdse = - Rs * Ids_dVdse ; + Vbs_dVgse = - Rs * Ids_dVgse ; + + Vds_dVbse = - ( Rs + Rd ) * Ids_dVbse ; + Vds_dVdse = ( 1.0 - ( Rs + Rd ) * Ids_dVdse ) ; + Vds_dVgse = - ( Rs + Rd ) * Ids_dVgse ; + + Vgs_dVbse = - Rs * Ids_dVbse ; + Vgs_dVdse = - Rs * Ids_dVdse ; + Vgs_dVgse = ( 1.0 - Rs * Ids_dVgse ) ; + +/*-------------------------------------------* +* Derivatives of charges. +*-----------------*/ + + Qb_dVbse = Qb_dVbs * Vbs_dVbse + Qb_dVds * Vds_dVbse + + Qb_dVgs * Vgs_dVbse ; + Qb_dVdse = Qb_dVbs * Vbs_dVdse + Qb_dVds * Vds_dVdse + + Qb_dVgs * Vgs_dVdse ; + Qb_dVgse = Qb_dVbs * Vbs_dVgse + Qb_dVds * Vds_dVgse + + Qb_dVgs * Vgs_dVgse ; + + Qi_dVbse = Qi_dVbs * Vbs_dVbse + Qi_dVds * Vds_dVbse + + Qi_dVgs * Vgs_dVbse ; + Qi_dVdse = Qi_dVbs * Vbs_dVdse + Qi_dVds * Vds_dVdse + + Qi_dVgs * Vgs_dVdse ; + Qi_dVgse = Qi_dVbs * Vbs_dVgse + Qi_dVds * Vds_dVgse + + Qi_dVgs * Vgs_dVgse ; + + Qd_dVbse = Qd_dVbs * Vbs_dVbse + Qd_dVds * Vds_dVbse + + Qd_dVgs * Vgs_dVbse ; + Qd_dVdse = Qd_dVbs * Vbs_dVdse + Qd_dVds * Vds_dVdse + + Qd_dVgs * Vgs_dVdse ; + Qd_dVgse = Qd_dVbs * Vbs_dVgse + Qd_dVds * Vds_dVgse + + Qd_dVgs * Vgs_dVgse ; + +/*-------------------------------------------* +* Substrate/gate/leak conductances. +*-----------------*/ + + Isub_dVbse = Isub_dVbs * Vbs_dVbse + Isub_dVds * Vds_dVbse + + Isub_dVgs * Vgs_dVbse ; + Isub_dVdse = Isub_dVbs * Vbs_dVdse + Isub_dVds * Vds_dVdse + + Isub_dVgs * Vgs_dVdse ; + Isub_dVgse = Isub_dVbs * Vbs_dVgse + Isub_dVds * Vds_dVgse + + Isub_dVgs * Vgs_dVgse ; + + Igs_dVbse = Igs_dVbs * Vbs_dVbse + Igs_dVds * Vds_dVbse + + Igs_dVgs * Vgs_dVbse ; + Igs_dVdse = Igs_dVbs * Vbs_dVdse + Igs_dVds * Vds_dVdse + + Igs_dVgs * Vgs_dVdse ; + Igs_dVgse = Igs_dVbs * Vbs_dVgse + Igs_dVds * Vds_dVgse + + Igs_dVgs * Vgs_dVgse ; + + Ilg_dVbse = Ilg_dVbs * Vbs_dVbse + Ilg_dVds * Vds_dVbse + + Ilg_dVgs * Vgs_dVbse ; + Ilg_dVdse = Ilg_dVbs * Vbs_dVdse + Ilg_dVds * Vds_dVdse + + Ilg_dVgs * Vgs_dVdse ; + Ilg_dVgse = Ilg_dVbs * Vbs_dVgse + Ilg_dVds * Vds_dVgse + + Ilg_dVgs * Vgs_dVgse ; + +/*---------------------------------------------------* +* Derivatives of overlap charges. +*-----------------*/ + + Qgos_dVbse = Qgos_dVbs * Vbs_dVbse + Qgos_dVds * Vds_dVbse + + Qgos_dVgs * Vgs_dVbse ; + Qgos_dVdse = Qgos_dVbs * Vbs_dVdse + Qgos_dVds * Vds_dVdse + + Qgos_dVgs * Vgs_dVdse ; + Qgos_dVgse = Qgos_dVbs * Vbs_dVgse + Qgos_dVds * Vds_dVgse + + Qgos_dVgs * Vgs_dVgse ; + + Qgod_dVbse = Qgod_dVbs * Vbs_dVbse + Qgod_dVds * Vds_dVbse + + Qgod_dVgs * Vgs_dVbse ; + Qgod_dVdse = Qgod_dVbs * Vbs_dVdse + Qgod_dVds * Vds_dVdse + + Qgod_dVgs * Vgs_dVdse ; + Qgod_dVgse = Qgod_dVbs * Vbs_dVgse + Qgod_dVds * Vds_dVgse + + Qgod_dVgs * Vgs_dVgse ; + + } /* end of if ( flg_rsrd == 0 ) blocks */ + +/*---------------------------------------------------* +* Derivatives of junction diode currents and charges. +* - NOTE: These quantities are regarded as functions of +* external biases. +* - NOTE: node-base S/D +*-----------------*/ + Gbse = Gbs ; + Gbde = Gbd ; + Capbse = Capbs ; + Capbde = Capbd ; + +/*---------------------------------------------------* +* Extrapolate quantities if external biases are out of bounds. +*-----------------*/ + + if ( flg_vbsc == 1 ) { + Ids_dVbse *= Vbsc_dVbse ; + Qb_dVbse *= Vbsc_dVbse ; + Qi_dVbse *= Vbsc_dVbse ; + Qd_dVbse *= Vbsc_dVbse ; + Isub_dVbse *= Vbsc_dVbse ; + Igs_dVbse *= Vbsc_dVbse ; + Ilg_dVbse *= Vbsc_dVbse ; + Qgos_dVbse *= Vbsc_dVbse ; + Qgod_dVbse *= Vbsc_dVbse ; + } + + if ( flg_vxxc != 0 ) { + + if ( flg_vbsc == -1 ) { + T1 = Vbse - Vbsc ; + } else { + T1 = 0.0 ; + } + + + if ( flg_vdsc != 0 ) { + T2 = Vdse - Vdsc ; + } else { + T2 = 0.0 ; + } + + if ( flg_vgsc != 0 ) { + T3 = Vgse - Vgsc ; + } else { + T3 = 0.0 ; + } + + if ( flg_vbdc != 0 ) { + T4 = Vbde - Vbdc ; + } else { + T4 = 0.0 ; + } + + + TX = Ids + T1 * Ids_dVbse + T2 * Ids_dVdse + T3 * Ids_dVgse ; + if ( TX * Ids >= 0.0 ) { + Ids = TX ; + } else { + T7 = Ids / ( Ids - TX ) ; + Ids_dVbse *= T7 ; + Ids_dVdse *= T7 ; + Ids_dVgse *= T7 ; + Ids = 0.0 ; + } + + TX = Qb + T1 * Qb_dVbse + T2 * Qb_dVdse + T3 * Qb_dVgse ; + /*note: The sign of Qb can be changed.*/ + Qb = TX ; + + TX = Qd + T1 * Qd_dVbse + T2 * Qd_dVdse + T3 * Qd_dVgse ; + if ( TX * Qd >= 0.0 ) { + Qd = TX ; + } else { + T7 = Qd / ( Qd - TX ) ; + Qd_dVbse *= T7 ; + Qd_dVdse *= T7 ; + Qd_dVgse *= T7 ; + Qd = 0.0 ; + } + + TX = Qi + T1 * Qi_dVbse + T2 * Qi_dVdse + T3 * Qi_dVgse ; + if ( TX * Qi >= 0.0 ) { + Qi = TX ; + } else { + T7 = Qi / ( Qi - TX ) ; + Qi_dVbse *= T7 ; + Qi_dVdse *= T7 ; + Qi_dVgse *= T7 ; + Qi = 0.0 ; + } + + TX = Isub + T1 * Isub_dVbse + T2 * Isub_dVdse + T3 * Isub_dVgse ; + if ( TX * Isub >= 0.0 ) { + Isub = TX ; + } else { + T7 = Isub / ( Isub - TX ) ; + Isub_dVbse *= T7 ; + Isub_dVdse *= T7 ; + Isub_dVgse *= T7 ; + Isub = 0.0 ; + } + + TX = Igs + T1 * Igs_dVbse + T2 * Igs_dVdse + T3 * Igs_dVgse ; + if ( TX * Igs >= 0.0 ) { + Igs = TX ; + } else { + T7 = Igs / ( Igs - TX ) ; + Igs_dVbse *= T7 ; + Igs_dVdse *= T7 ; + Igs_dVgse *= T7 ; + Igs = 0.0 ; + } + + TX = Ilg + T1 * Ilg_dVbse + T2 * Ilg_dVdse + T3 * Ilg_dVgse ; + if ( TX * Ilg >= 0.0 ) { + Ilg = TX ; + } else { + T7 = Ilg / ( Ilg - TX ) ; + Ilg_dVbse *= T7 ; + Ilg_dVdse *= T7 ; + Ilg_dVgse *= T7 ; + Ilg = 0.0 ; + } + + TX = Qgod + T1 * Qgod_dVbse + T2 * Qgod_dVdse + T3 * Qgod_dVgse ; + if ( TX * Qgod >= 0.0 ) { + Qgod = TX ; + } else { + T7 = Qgod / ( Qgod - TX ) ; + Qgod_dVbse *= T7 ; + Qgod_dVdse *= T7 ; + Qgod_dVgse *= T7 ; + Qgod = 0.0 ; + } + + TX = Qgos + T1 * Qgos_dVbse + T2 * Qgos_dVdse + T3 * Qgos_dVgse ; + if ( TX * Qgos >= 0.0 ) { + Qgos = TX ; + } else { + T7 = Qgos / ( Qgos - TX ) ; + Qgos_dVbse *= T7 ; + Qgos_dVdse *= T7 ; + Qgos_dVgse *= T7 ; + Qgos = 0.0 ; + } + + + } + +/*-----------------------------------------------------------* +* Warn negative conductance. +* - T1 ( = d Ids / d Vds ) is the derivative w.r.t. circuit bias. +*-----------------*/ + + if ( sIN.mode == HiSIM_NORMAL_MODE ) { + T1 = Ids_dVdse ; + } else { + T1 = Ids_dVbse + Ids_dVdse + Ids_dVgse ; + } + + if ( Ids_dVbse < 0.0 || T1 < 0.0 || Ids_dVgse < 0.0 ) { + fprintf( stderr , + "*** warning(HiSIM): Negative Conductance\n" ) ; + fprintf( stderr , + " type = %d mode = %d\n" , sIN.type , sIN.mode ) ; + fprintf( stderr , + " Vbse = %12.5e Vdse = %12.5e Vgse = %12.5e\n" , + Vbse , Vdse , Vgse ) ; + if ( flg_info >= 1 ) { + printf( "*** warning(HiSIM): Negative Conductance\n" ) ; + printf( " type = %d mode = %d\n" , sIN.type , sIN.mode ) ; + printf( " Vbse = %12.5e Vdse = %12.5e Vgse = %12.5e\n" , + Vbse , Vdse , Vgse ) ; + printf( " Ids_dVbse = %12.5e\n" , Ids_dVbse ) ; + printf( " Ids_dVdse = %12.5e\n" , Ids_dVdse ) ; + printf( " Ids_dVgse = %12.5e\n" , Ids_dVgse ) ; + } + } + + if ( Ids_dVbse < 0.0e0 ) { + fprintf( stderr , " Ids_dVbse = %12.5e\n" , Ids_dVbse ) ; + flg_ncnv ++ ; + } + if ( T1 < 0.0e0 ) { + fprintf( stderr , " Ids_dVdse = %12.5e\n" , T1 ) ; + flg_ncnv ++ ; + } + if ( Ids_dVgse < 0.0e0 ) { + fprintf( stderr , " Ids_dVgse = %12.5e\n" , Ids_dVgse ) ; + flg_ncnv ++ ; + } + + + +/*-----------------------------------------------------------* +* Redefine overlap charges/capacitances. +*-----------------*/ + +/*---------------------------------------------------* +* Constant capacitance. +*-----------------*/ + + if ( sIN.cocgbo >= 1 ) { + Cgbo = sIN.cgbo * Lgate ; + } else { + Cgbo = 0.0 ; + } + + if ( sIN.cocgdo >= 1 ) { + Cgdo = - sIN.cgdo * Weff ; + Qgod = - Cgdo * ( Vgse - Vdse ) ; + Qgod_dVbse = 0.0 ; + Qgod_dVdse = Cgdo ; + Qgod_dVgse = - Qgod_dVdse ; + } else { + Cgdo = Qgos_dVdse + Qgod_dVdse ; + } + + if ( sIN.cocgso >= 1 ) { + Cgso = - sIN.cgso * Weff ; + Qgos = - Cgso * Vgse ; + Qgod_dVbse = 0.0 ; + Qgod_dVdse = 0.0 ; + Qgos_dVgse = - Cgso ; + } else { + Cgso = - ( Qgos_dVbse + Qgod_dVbse + + Qgos_dVdse + Qgod_dVdse + + Qgos_dVgse + Qgod_dVgse ) ; + } + + Cggo = Qgos_dVgse + Qgod_dVgse ; + +/*---------------------------------------------------* +* Fringing capacitance. +*-----------------*/ + + Cf = C_EOX / ( C_Pi / 2.0e0 ) * Weff + * log( 1.0e0 + sIN.tpoly / sIN. tox ) ; + + /* added 2 Eqs. below. (4/Dec/01) */ + + Qfd = Cf * ( Vgse - Vdse ) ; + Qfs = Cf * Vgse ; + + /* end of additional Eqs. */ + +/*---------------------------------------------------* +* Add fringing charge/capacitance to overlap. +*-----------------*/ + + /* added 2 Eqs. below. (4/Dec/01) */ + + Qgod += Qfd ; + Qgos += Qfs ; + + /* end of additional Eqs. */ + + Cggo += 2.0 * Cf ; + Cgdo += - Cf ; + Cgso += - Cf ; + +/*-----------------------------------------------------------* +* Assign outputs. +*-----------------*/ + +/*---------------------------------------------------* +* Channel current and conductances. +*-----------------*/ + + /* pOT->ids = sIN.type * Ids ; */ + pOT->ids = Ids ; + pOT->gmbs = Ids_dVbse ; + pOT->gds = Ids_dVdse ; + pOT->gm = Ids_dVgse ; + +/*---------------------------------------------------* +* Intrinsic charges/capacitances. +*-----------------*/ + + pOT->qg = - ( Qb + Qi ) ; + pOT->qd = Qd ; + pOT->qs = Qi - Qd ; + + pOT->cbgb = Qb_dVgse ; + pOT->cbdb = Qb_dVdse ; + pOT->cbsb = - ( Qb_dVbse + Qb_dVdse + Qb_dVgse ) ; + + pOT->cggb = - Qb_dVgse - Qi_dVgse ; + pOT->cgdb = - Qb_dVdse - Qi_dVdse ; + pOT->cgsb = Qb_dVbse + Qb_dVdse + Qb_dVgse + + Qi_dVbse + Qi_dVdse + Qi_dVgse ; + + pOT->cdgb = Qd_dVgse ; + pOT->cddb = Qd_dVdse ; + pOT->cdsb = - ( Qd_dVgse + Qd_dVdse + Qd_dVbse ) ; + + +/*---------------------------------------------------* +* Cramp capcitances. +*-----------------*/ + if ( pOT->cbsb > -1e-27 ) { pOT->cbsb = 0e0 ; } + if ( pOT->cgdb > -1e-27 ) { pOT->cgdb = 0e0 ; } + if ( pOT->cgsb > -1e-27 ) { pOT->cgsb = 0e0 ; } + +/*---------------------------------------------------* +* Overlap capacitances. +*-----------------*/ + + pOT->cgdo = Cgdo ; + pOT->cgso = Cgso ; + pOT->cgbo = Cgbo ; + +/* + * Intrinsic fringing capacitance. + */ + + T1 = 2 * C_ESI * Weff / C_Pi; + T2 = C_Pi * C_EOX / 2 / C_ESI; + T3 = sIN.xj / sIN.tox * sin( T2 ); + Cgdf = T1 * log( 1.0e0 + T3 ); + + T4 = (-1) * ( pOT->cgdb ); + T5 = 2 * T4 / Cox / Weff / Leff; + Cgdfring = Cgdf * ( 1.0e0 - T5 ); + + +/*---------------------------------------------------* +* Add S/D overlap charges/capacitances to intrinsic ones. +* - NOTE: This function depends on coadov, a control option. +*-----------------*/ + + if ( sIN.coadov == 1 ) { + pOT->qg += Qgod + Qgos ; + pOT->qd += - Qgod ; + pOT->qs += - Qgos ; + + pOT->cggb += Cggo ; + pOT->cgdb = pOT->cgdb + Cgdo + (-1) * Cgdfring ; + pOT->cgsb += Cgso ; + + pOT->cdgb += - Qgod_dVgse - Cf ; + pOT->cddb += - Qgod_dVdse + Cf ; + pOT->cdsb += Qgod_dVbse + Qgod_dVdse + Qgod_dVgse ; + + pOT->cgdo = 0.0 ; + pOT->cgso = 0.0 ; + + if ( pOT->cgdb > -1e-27 ) { pOT->cgdb = 0e0 ; } + if ( pOT->cgsb > -1e-27 ) { pOT->cgsb = 0e0 ; } + } + + +/*---------------------------------------------------* +* Substrate/gate/leak currents. +*-----------------*/ + + pOT->isub = Isub ; + + pOT->gbbs = Isub_dVbse ; + pOT->gbds = Isub_dVdse ; + pOT->gbgs = Isub_dVgse ; + + pOT->igs = Igs ; + + pOT->ggbs = Igs_dVbse ; + pOT->ggds = Igs_dVdse ; + pOT->gggs = Igs_dVgse ; + + pOT->ilg = Ilg ; + + pOT->glbs = Ilg_dVbse ; + pOT->glds = Ilg_dVdse ; + pOT->glgs = Ilg_dVgse ; + +/*---------------------------------------------------* +* Meyer's capacitances. +*-----------------*/ + + pOT->capgs = - pOT->cgsb - Cgso + Cf ; + pOT->capgd = - pOT->cgdb - Cgdo + Cf ; + pOT->capgb = pOT->cggb + pOT->cgdb + pOT->cgbo ; + +/*---------------------------------------------------* +* Von, Vdsat, +*-----------------*/ + + /* + pOT->von = sIN.type * Vth ; + pOT->vdsat = sIN.type * Vdsat ; + */ + pOT->von = Vth ; + pOT->vdsat = Vdsat ; + +/*---------------------------------------------------* +* Parasitic conductances. +*-----------------*/ + +/*:org: +* pOT->gd = 1.0e+50 ; +* pOT->gs = 1.0e+50 ; +* modified according to CMIxxxeval.c. +* I don't know the reason why these can be zero. +*/ + pOT->gd = 0.0e0 ; + pOT->gs = 0.0e0 ; + +/*---------------------------------------------------* +* Junction diode. +*-----------------*/ + + /* + pOT->ibs = sIN.type * Ibs ; + pOT->ibd = sIN.type * Ibd ; + */ + pOT->ibs = Ibs ; + pOT->ibd = Ibd ; + pOT->gbs = Gbse ; + pOT->gbd = Gbde ; + + pOT->qbs = Qbs ; + pOT->qbd = Qbd ; + pOT->capbs = Capbse ; + pOT->capbd = Capbde ; + + + +/*-----------------------------------------------------------* +* Warn floating-point exceptions. +* - Function finite() in libm is called. +* - Go to start with info==5. +*-----------------*/ + + T1 = pOT->ids + pOT->gmbs + pOT->gds + pOT->gm ; + T1 = T1 + pOT->qd + pOT->cdsb ; + if ( ! finite( T1 ) ) { + flg_err = 1 ; + fprintf( stderr , + "*** warning(HiSIM): FP-exception (PART-1)\n" ) ; + if ( flg_info >= 1 ) { + printf( "*** warning(HiSIM): FP-exception\n" ) ; + printf( "pOT->ids = %12.5e\n" , pOT->ids ) ; + printf( "pOT->gmbs = %12.5e\n" , pOT->gmbs ) ; + printf( "pOT->gds = %12.5e\n" , pOT->gds ) ; + printf( "pOT->gm = %12.5e\n" , pOT->gm ) ; + printf( "pOT->qd = %12.5e\n" , pOT->qd ) ; + printf( "pOT->cdsb = %12.5e\n" , pOT->cdsb ) ; + } + } + + T1 = pOT->isub + pOT->gbbs + pOT->gbds + pOT->gbgs ; + if ( ! finite( T1 ) ) { + flg_err = 1 ; + fprintf( stderr , + "*** warning(HiSIM): FP-exception (PART-2)\n" ) ; + if ( flg_info >= 1 ) { + printf( "*** warning(HiSIM): FP-exception\n" ) ; + } + } + + T1 = pOT->cgbo + Cgdo + Cgso + Cggo ; + if ( ! finite( T1 ) ) { + flg_err = 1 ; + fprintf( stderr , + "*** warning(HiSIM): FP-exception (PART-3)\n" ) ; + if ( flg_info >= 1 ) { + printf( "*** warning(HiSIM): FP-exception\n" ) ; + } + } + + T1 = pOT->ibs + pOT->ibd + pOT->gbs + pOT->gbd ; + T1 = T1 + pOT->qbs + pOT->qbd + pOT->capbs + pOT->capbd ; + if ( ! finite( T1 ) ) { + flg_err = 1 ; + fprintf( stderr , + "*** warning(HiSIM): FP-exception (PART-4)\n" ) ; + if ( flg_info >= 1 ) { + printf( "*** warning(HiSIM): FP-exception\n" ) ; + } + } + + + +/*-----------------------------------------------------------* +* Exit for error case. +*-----------------*/ + if ( flg_err != 0 ) { + return( HiSIM_ERROR ) ; + } + +/*-----------------------------------------------------------* +* Restore values for next calculation. +*-----------------*/ + + /* Confined biases */ + pOT->vbsc = Vbsc ; + pOT->vdsc = Vdsc ; + pOT->vgsc = Vgsc ; + /* Surface potentials and derivatives w.r.t. internal biases */ + pOT->ps0 = Ps0 ; + pOT->ps0_dvbs = Ps0_dVbs ; + pOT->ps0_dvds = Ps0_dVds ; + pOT->ps0_dvgs = Ps0_dVgs ; + pOT->pds = Pds ; + pOT->pds_dvbs = Pds_dVbs ; + pOT->pds_dvds = Pds_dVds ; + pOT->pds_dvgs = Pds_dVgs ; + /* Derivatives of channel current w.r.t. internal biases */ + pOT->ids_dvbs = Ids_dVbs ; + pOT->ids_dvds = Ids_dVds ; + pOT->ids_dvgs = Ids_dVgs ; + + pOT->nf = Nflic ; + + /* mobility added by K.M. */ + pOT->mu = Mu; + +/*-----------------------------------------------------------* +* End of PART-6. (label) +*-----------------*/ +end_of_part_6: ; + + +/*-----------------------------------------------------------* +* Bottom of hsm1eval. +*-----------------*/ + + + +return ( HiSIM_OK ) ; + +} /* end of hsm1eval1_0 */ diff --git a/src/spicelib/devices/hisim/hsm1eval1_1.c b/src/spicelib/devices/hisim/hsm1eval1_1.c new file mode 100644 index 000000000..72f02c221 --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1eval1_1.c @@ -0,0 +1,4758 @@ +/*********************************************************************** + HiSIM v1.1.0 + File: hsm1eval1_1.c of HiSIM v1.1.0 + + Copyright (C) 2002 STARC + + June 30, 2002: developed by Hiroshima University and STARC + June 30, 2002: posted by Keiichi MORIKAWA, STARC Physical Design Group +***********************************************************************/ + +/* + * Modified by Paolo Nenzi 2002 + * ngspice integration + */ + +/********************************************************************* +* Memorandum on programming +* +* (1) Bias (x: b|d|g) +* . sIN.vxs : Input argument. +* . Vxse: External bias taking account device type (pMOS->nMOS). +* . Vxsc: Confined bias within a specified region. +* . Vxs : Internal bias taking account Rs/Rd. +* . Y_dVxs denotes the partial derivative of Y w.r.t. Vxs. +* +* (2) Device Mode +* . Normal mode (Vds>0 for nMOS) is assumed. +* . In case of reverse mode, parent routines have to properly +* transform or interchange inputs and outputs except ones +* related to junction diodes, which are regarded as being +* fixed to the nodal S/D. +* +* (3) Modification for symmetry at Vds=0 +* . Vxsz: Modified bias. +* . Ps0z: Modified Ps0. +* . The following variables are calculated as a function of +* modified biases or potential. +* Tox, Cox, (-- with quantum effect) +* Vth*, dVth*, dPpg, Qnm, Qbm, Igs, Ilg. +* . The following variables are calculated using a transform +* function. +* Lred, rp1(<-sIN.rpock1). +* +* (4) Zones and Cases (terminology) +* +* Chi:=beta*(Ps0-Vbs)= 0 3 5 +* +* Zone: A | D1 | D2 | D3 +* | +* (accumulation)|(depletion) +* | +* Vgs = Vgs_fb Vth +* / / +* Case: Nonconductive / Conductive +* / +* VgVt:=Qn0/Cox= VgVt_small +* +* . Ids is regarded as zero in zone-A and -D1. +* . Procedure to calculate Psl and dependent variables is +* omitted in the nonconductive case. Ids and Qi are regarded +* as zero in this case. +* +*********************************************************************/ + +/*===========================================================* +* Preamble. +*=================*/ +/*---------------------------------------------------* +* Header files. +*-----------------*/ +#include +#include +#include +#include + +/*-----------------------------------* +* HiSIM macros and structures. +* - All inputs and outputs are defined here. +*-----------------*/ +#include "hisim.h" +#include "hsm1evalenv.h" + +/*===========================================================* +* Function hsm1eval. +*=================*/ + +int HSM1evaluate1_1( HiSIM_input sIN, HiSIM_output *pOT, + HiSIM_messenger *pMS) +{ + +/*---------------------------------------------------* +* Local variables. +*-----------------*/ +/* Constans ----------------------- */ +int lp_s0_max = 20 ; +int lp_sl_max = 20 ; +int lp_bs_max = 10 ; +double Ids_tol = 1.0e-10 ; +double Ids_maxvar = 1.0e-1 ; +double dP_max = 0.1e0 ; +double ps_conv = 5.0e-13 ; +double gs_conv = 1.0e-8 ; +/*-----*/ +/** depletion **/ +double znbd3 = 3.0e0 ; +double znbd5 = 5.0e0 ; +double cn_nc3 = C_SQRT_2 / 108e0 ; +/* 5-degree, contact:Chi=5 */ +double cn_nc51 = 0.707106781186548 ; /* sqrt(2)/2 */ +double cn_nc52 = -0.117851130197758 ; /* -sqrt(2)/12 */ +double cn_nc53 = 0.0178800506338833 ; /* (187 - 112*sqrt(2))/1600 */ +double cn_nc54 = -0.00163730162779191 ; /* (-131 + 88*sqrt(2))/4000 */ +double cn_nc55 = 6.36964918866352e-5; /*(1509-1040*sqrt(2))/600000*/ +/** inversion **/ +/* 3-dgree polynomial approx for ( exp[Chi]-1 )^{1/2} */ +double cn_im53 = 2.9693154855770998e-1 ; +double cn_im54 = -7.0536542840097616e-2 ; +double cn_im55 = 6.1152888951331797e-3 ; +/* 3-dgree polynomial approx for ( exp[Chi]-Chi-1 )^{1/2} */ +double cn_ik53 = 2.6864599830664019e-1 ; +double cn_ik54 = -6.1399531828413338e-2 ; +double cn_ik55 = 5.3528499428744690e-3 ; +/** initial guess **/ +double c_ps0ini_2 = 8.0e-4 ; +double c_pslini_1 = 0.3e0 ; +double c_pslini_2 = 3.0e-2 ; +double VgVt_small = 1.0e-12 ; +double Vbs_max = 0.5e0 ; +double Vbs_min = -10.5e0 ; +double Vds_max = 10.5e0 ; +double Vgs_max = 10.5e0 ; +/*-----*/ +double Vbd_max = 20.0e0 ; +double Vbd_min = -10.0e0 ; +/*-----*/ +double epsm10 = 10.0e0 * C_EPS_M ; +double small = 1.0e-50 ; +/*-----*/ +double Vz_dlt = 5.0e-3 ; +/*-----*/ +double Gdsmin = 1.0e-12 ; +/*-----*/ +/* double Gjmin = 1.0e-12 ; */ +double Gjmin = sIN.gmin; /* modified by K.M. for SPICE3f5 */ +/*-----*/ +double cclmmdf = 1.0e-1 ; +/*-----*/ +double qme_dlt = 1.0e-9 ; +double eef_dlt = 1.0e-2 ; +double sti1_dlt = -3.0e-3 ; +double sti2_dlt = 2.0e-3 ; +double pol_dlt = 2.0e-1 ; + +/* Internal flags --------------------*/ +int flg_err = 0 ; /* error level */ +int flg_ncnv = 0 ; /* Flag for negative conductance */ +int flg_rsrd ; /* Flag for bias loop accounting Rs and Rd */ +int flg_iprv ; /* Flag for initial guess of Ids */ +int flg_pprv ; /* Flag for initial guesses of Ps0 and Pds */ +int flg_noqi ; /* Flag for the cases regarding Qi=Qd=0 */ +int flg_vbsc = 0 ; /* Flag for Vbs confining */ +int flg_vdsc = 0 ; /* Flag for Vds confining */ +int flg_vgsc = 0 ; /* Flag for Vgs confining */ +int flg_vbdc = 0 ; /* Flag for Vgs confining */ +int flg_vxxc = 0 ; /* Flag whether some bias was confined */ +int flg_info = 0 ; + +/* Important Variables in HiSIM -------*/ +/* external bias */ +double Vbse , Vdse , Vgse , Vbde ; +/* confine bias */ +double Vbsc , Vdsc , Vgsc , Vbdc ; +double Vbsc_dVbse = 1.0 ; +/* internal bias */ +double Vbs , Vds , Vgs ; +double Vbs_dVbse = 1.0 , Vbs_dVdse = 0.0 , Vbs_dVgse = 0.0 ; +double Vds_dVbse = 0.0 , Vds_dVdse = 1.0 , Vds_dVgse = 0.0 ; +double Vgs_dVbse = 0.0 , Vgs_dVdse = 0.0 , Vgs_dVgse = 1.0 ; +double Vgp ; +double Vgp_dVbs , Vgp_dVds , Vgp_dVgs ; +double Vgs_fb ; +/* Ps0 : surface potential at the source side */ +double Ps0 ; +double Ps0_dVbs , Ps0_dVds , Ps0_dVgs ; +double Ps0_ini , Ps0_iniA , Ps0_iniB ; +/* Psl : surface potential at the drain side */ +double Psl ; +double Psl_dVbs , Psl_dVds , Psl_dVgs ; +double Psl_lim ; +/* Pds := Psl - Ps0 */ +double Pds ; +double Pds_dVbs , Pds_dVds , Pds_dVgs ; +double Pds_ini ; +double Pds_max ; +/* iteration numbers of Ps0 and Psl equations. */ +int lp_s0 , lp_sl ; +/* Xi0 := beta * ( Ps0 - Vbs ) - 1. */ +double Xi0 ; +double Xi0_dVbs , Xi0_dVds , Xi0_dVgs ; +double Xi0p12 ; +double Xi0p12_dVbs , Xi0p12_dVds , Xi0p12_dVgs ; +double Xi0p32 ; +double Xi0p32_dVbs , Xi0p32_dVds , Xi0p32_dVgs ; +/* Xil := beta * ( Psl - Vbs ) - 1. */ +double Xilp12 ; +double Xilp32 ; +double Xil ; +/* modified bias and potential for sym.*/ +double Vbsz , Vdsz , Vgsz ; +double Vbsz_dVbs , Vbsz_dVds ; +double Vdsz_dVds ; +double Vgsz_dVgs , Vgsz_dVds ; +double Vbszm ; +double Vbszm_dVbs , Vbszm_dVds ; +double Vbs1 , Vbs2 , Vbsd ; +double Vbsd_dVbs , Vbsd_dVds ; +double Vzadd , Vzadd_dVds , Vzadd_dA ; +double VzaddA , VzaddA_dVds ; +double Ps0z , Ps0z_dVbs , Ps0z_dVds , Ps0z_dVgs ; +double Pzadd , Pzadd_dVbs , Pzadd_dVds , Pzadd_dVgs ; +double Ps0Vbsz , Ps0Vbsz_dVbs , Ps0Vbsz_dVds , Ps0Vbsz_dVgs ; +double Vgpz , Vgpz_dVbs , Vgpz_dVds , Vgpz_dVgs ; +double Xi0z ; +double Xi0z_dVbs , Xi0z_dVds , Xi0z_dVgs ; +double Xi0zp12 ; +double Xi0zp12_dVbs , Xi0zp12_dVds , Xi0zp12_dVgs ; +/* Chi := beta * ( Ps{0/l} - Vbs ) */ +double Chi ; +double Chi_dVbs , Chi_dVds , Chi_dVgs ; +/* Rho := beta * ( Psl - Vds ) */ +double Rho ; +/* threshold voltage */ +double Vth ; +double Vth_dVbs , Vth_dVds , Vth_dVgs ; +double Vth0 ; +double Vth0_dVbs , Vth0_dVds , Vth0_dVgs ; +/* variation of threshold voltage */ +double dVth ; +double dVth_dVbs , dVth_dVds , dVth_dVgs ; +double dVth0 ; +double dVth0_dVbs , dVth0_dVds , dVth0_dVgs ; +double dVthSC ; +double dVthSC_dVbs , dVthSC_dVds , dVthSC_dVgs ; +double dVthW ; +double dVthW_dVbs , dVthW_dVds , dVthW_dVgs ; +/* Alpha and related parameters */ +double Alpha ; +double Alpha_dVbs , Alpha_dVds , Alpha_dVgs ; +double Achi ; +double Achi_dVbs , Achi_dVds , Achi_dVgs ; +double VgVt = 0.0 ; +double VgVt_dVbs , VgVt_dVds , VgVt_dVgs ; +double Delta , Vdsat ; +/*-----*/ +/* Q_B and capacitances */ +double Qb , Qb_dVbs , Qb_dVds , Qb_dVgs ; +double Qb_dVbse , Qb_dVdse , Qb_dVgse ; +/* Q_I and capacitances */ +double Qi , Qi_dVbs , Qi_dVds , Qi_dVgs ; +double Qi_dVbse , Qi_dVdse , Qi_dVgse ; +/* Q_D and capacitances */ +double Qd , Qd_dVbs , Qd_dVds , Qd_dVgs ; +double Qd_dVbse , Qd_dVdse , Qd_dVgse ; +/* channel current */ +double Ids ; +double Ids_dVbs , Ids_dVds , Ids_dVgs ; +double Ids_dVbse , Ids_dVdse , Ids_dVgse ; +double Ids0 ; +double Ids0_dVbs , Ids0_dVds , Ids0_dVgs ; +/* STI */ +double Vgssti ; +double Vgssti_dVbs , Vgssti_dVds , Vgssti_dVgs ; +double costi0 , costi1 , costi2 , costi3 ; +double costi4 , costi5 , costi6 , costi7 ; +double Psasti ; +double Psasti_dVbs , Psasti_dVds , Psasti_dVgs ; +double Asti ; +double Psbsti ; +double Psbsti_dVbs , Psbsti_dVds , Psbsti_dVgs ; +double Psab ; +double Psab_dVbs , Psab_dVds , Psab_dVgs ; +double Psti ; +double Psti_dVbs , Psti_dVds , Psti_dVgs ; +double expsti ; +double sq1sti ; +double sq1sti_dVbs , sq1sti_dVds , sq1sti_dVgs ; +double sq2sti ; +double sq2sti_dVbs , sq2sti_dVds , sq2sti_dVgs ; +double Qn0sti ; +double Qn0sti_dVbs , Qn0sti_dVds , Qn0sti_dVgs ; +double Idssti ; +double Idssti_dVbs , Idssti_dVds , Idssti_dVgs ; + +/* (for debug) */ +double user1 , user2 , user3 , user4 ; + +/* constants ------- */ +double beta ; +double beta2 ; +/* device instances */ +double Leff , Leff_inv ; +double Weff ; +double Ldby ; +double Nsub , q_Nsub ; +double Nin ; +double Pb2 ; +double Pb20 ; +double Pb2c ; +double Eg , Eg300 ; +double Vfb ; +/* PART-1 ---------- */ +double Psum ; +double Psum_dVbs ; +double Psum_dVds ; +double sqrt_Psum ; +double cnst0 , cnst1 ; +double fac1 ; +double fac1_dVbs , fac1_dVds , fac1_dVgs ; +double fac1p2 ; +/*-----*/ +double fs01 ; +double fs01_dPs0 , fs01_dChi ; +double fs01_dVbs , fs01_dVds , fs01_dVgs ; +double fs02 ; +double fs02_dPs0 , fs02_dChi ; +double fs02_dVbs , fs02_dVds , fs02_dVgs ; +double fsl1 ; +double fsl1_dPsl ; +double fsl1_dVbs , fsl1_dVds ; +double fsl2 ; +double fsl2_dPsl ; +double fsl2_dVbs , fsl2_dVds ; +double cfs1 ; +double fb , fb_dChi ; +double fi , fi_dChi ; +double exp_Chi , exp_Rho , exp_bVbs , exp_bVbsVds ; +double Fs0, Fsl ; +double Fs0_dPs0 , Fsl_dPsl ; +double dPs0 , dPsl ; +/*-----*/ +double Qn0 ; +double Qn0_dVbs , Qn0_dVds , Qn0_dVgs ; +double Qb0 ; +double Qb0_dVbs , Qb0_dVds , Qb0_dVgs ; +double Qn00 ; +double Qn00_dVbs , Qn00_dVds , Qn00_dVgs ; +/* unused: +* double Qnl ; +*/ +/*-----*/ +double Qbnm ; +double Qbnm_dVbs , Qbnm_dVds , Qbnm_dVgs ; +double DtPds ; +double DtPds_dVbs , DtPds_dVds , DtPds_dVgs ; +/*-----*/ +double Fid2 ; +double Fid2_dVbs , Fid2_dVds , Fid2_dVgs ; +double Fid3 ; +double Fid3_dVbs , Fid3_dVds , Fid3_dVgs ; +double Fid4 ; +double Fid4_dVbs , Fid4_dVds , Fid4_dVgs ; +double Fid5 ; +double Fid5_dVbs , Fid5_dVds , Fid5_dVgs ; +/*-----*/ +double PVds0 ; +double XiVds0 ; +double XiVds0p12 ; +double XiVds0p12_dVbs , XiVds0p12_dVds , XiVds0p12_dVgs ; +double XiVds0p32 ; +double XiVds0p32_dVbs , XiVds0p32_dVds , XiVds0p32_dVgs ; +double Qbm ; +double Qbm_dVbs , Qbm_dVds , Qbm_dVgs ; +/*-----*/ +double Qinm ; +double Qinm_dVbs , Qinm_dVds , Qinm_dVgs ; +double Qidn ; +double Qidn_dVbs , Qidn_dVds , Qidn_dVgs ; +double Qdnm ; +double Qdnm_dVbs , Qdnm_dVds , Qdnm_dVgs ; +double Qddn ; +double Qddn_dVbs , Qddn_dVds , Qddn_dVgs ; +double Quot ; +double Qdrat ; +double Qdrat_dVbs , Qdrat_dVds , Qdrat_dVgs ; +double Idd ; +double Idd_dVbs , Idd_dVds , Idd_dVgs ; +double Qnm ; +double Qnm_dVbs , Qnm_dVds , Qnm_dVgs ; +/*-----*/ +double Fdd ; +double Fdd_dVbs , Fdd_dVds , Fdd_dVgs ; +/*-----*/ +double Eeff ; +double Eeff_dVbs , Eeff_dVds , Eeff_dVgs ; +double Rns ; +double Mu ; +double Mu_dVbs , Mu_dVds , Mu_dVgs ; +double Muun , Muun_dVbs , Muun_dVds , Muun_dVgs ; +double Ey ; +double Ey_dVbs , Ey_dVds , Ey_dVgs ; +double Em ; +double Em_dVbs , Em_dVds , Em_dVgs ; +double Vmax ; +/*-----*/ +double Eta ; +double Eta_dVbs , Eta_dVds , Eta_dVgs ; +double Eta1 , Eta1p12 , Eta1p32 , Eta1p52 ; +double Zeta12 , Zeta32 , Zeta52 ; +/*-----*/ +double F00 ; +double F00_dVbs , F00_dVds , F00_dVgs ; +double F10 ; +double F10_dVbs , F10_dVds , F10_dVgs ; +double F30 ; +double F30_dVbs , F30_dVds , F30_dVgs ; +double F11 ; +double F11_dVbs , F11_dVds , F11_dVgs ; +/*-----*/ +double Ps0_min ; +double Acn , Acd , Ac1 , Ac2 , Ac3 , Ac4 , Ac31 , Ac41 ; +double Acn_dVbs , Acn_dVds , Acn_dVgs ; +double Acd_dVbs , Acd_dVds , Acd_dVgs ; +double Ac1_dVbs , Ac1_dVds , Ac1_dVgs ; +double Ac2_dVbs , Ac2_dVds , Ac2_dVgs ; +double Ac3_dVbs , Ac3_dVds , Ac3_dVgs ; +double Ac4_dVbs , Ac4_dVds , Ac4_dVgs ; +double Ac31_dVbs , Ac31_dVds , Ac31_dVgs ; +/* PART-2 (Isub)---------- */ +double Isub ; +double Isub_dVbs , Isub_dVds , Isub_dVgs ; +double Isub_dVbse , Isub_dVdse , Isub_dVgse ; +double Vdep ; +double Vdep_dVbs , Vdep_dVds , Vdep_dVgs ; +double Epkf ; +double Epkf_dVbs , Epkf_dVds , Epkf_dVgs ; +/**/ +/*-----*/ +/* PART-3 (overlap) */ +double yn , yn2 , yn3 ; +double yn_dVbs , yn_dVds , yn_dVgs ; +double yned , yned2 ; +double yned_dVbs , yned_dVds , yned_dVgs ; +double Lov , Lov2 , Lov23 ; +double Ndsat , Gjnp; +double Qgos , Qgos_dVbs , Qgos_dVds , Qgos_dVgs ; +double Qgos_dVbse , Qgos_dVdse , Qgos_dVgse ; +double Qgod , Qgod_dVbs , Qgod_dVds , Qgod_dVgs ; +double Qgod_dVbse , Qgod_dVdse , Qgod_dVgse ; +double Cggo , Cgdo , Cgso , Cgbo ; +/* fringing capacitance */ +double Cf ; +double Qfd , Qfs ; +/* Cqy */ +double Pslk , Pslk_dVbs , Pslk_dVds , Pslk_dVgs ; +double Qy ; +double Cqyd, Cqyg, Cqys, Cqyb ; +double qy_dlt ; +/* PART-4 (junction diode) */ +double Ibs , Ibd , Gbs , Gbd , Gbse , Gbde ; +double js ; +double jssw ; +double isbs ; +double isbd ; +double Nvtm ; +/* junction capacitance */ +double Qbs , Qbd , Capbs , Capbd , Capbse , Capbde ; +double czbd , czbdsw , czbdswg , czbs , czbssw , czbsswg ; +double arg , sarg ; +/* PART-5 (noise) */ +/* matsu */ +double NFalp , NFtrp , Freq , Cit , Nflic ; +/* Bias iteration accounting Rs/Rd */ +int lp_bs ; +double Ids_last ; +double vtol_iprv = 2.0e-1 ; +double vtol_pprv = 5.0e-2 ; +double Vbsc_dif , Vdsc_dif , Vgsc_dif , sum_vdif ; +double Rs , Rd ; +double Fbs , Fds , Fgs ; +double DJ , DJI ; +double JI11 , JI12 , JI13 , JI21 , JI22 , JI23 , JI31 , JI32 , JI33 ; +double dVbs , dVds , dVgs ; +double dV_sum ; +/* Junction Bias */ +double Vbsj, Vbdj; +/* Accumulation zone */ +double Psa ; +double Psa_dVbs , Psa_dVds , Psa_dVgs ; +/* CLM */ +double Psdl , Psdl_dVbs , Psdl_dVds , Psdl_dVgs ; +double Ed , Ed_dVbs , Ed_dVds , Ed_dVgs ; +double Ec , Ec_dVbs , Ec_dVds , Ec_dVgs ; +double Lred , Lred_dVbs , Lred_dVds , Lred_dVgs ; +double Wd , Wd_dVbs , Wd_dVds , Wd_dVgs ; +double Aclm ; +/* Pocket Implant */ +double Vthp, Vthp_dVbs, Vthp_dVds, Vthp_dVgs ; +double dVthLP,dVthLP_dVbs,dVthLP_dVds,dVthLP_dVgs ; +double LEY ; +/* Poly-Depletion Effect */ +double dPpg , dPpg_dVds , dPpg_dVgs ; +/* Quantum Effect */ +double Tox , Tox_dVbs , Tox_dVds , Tox_dVgs ; +double dTox , dTox_dVbs , dTox_dVds , dTox_dVgs ; +double Cox , Cox_dVbs , Cox_dVds , Cox_dVgs ; +double Cox_inv , Cox_inv_dVbs , Cox_inv_dVds , Cox_inv_dVgs ; +double Vthq, Vthq_dVbs , Vthq_dVds ; +/* Igs , Ilg */ +double Egp12 , Egp32 ; +double E0 ; +double E1 , E1_dVbs , E1_dVds , E1_dVgs ; +double E2 , E2_dVbs , E2_dVds , E2_dVgs ; +double Etun , Etun_dVbs , Etun_dVds , Etun_dVgs ; +double Egidl , Egidl_dVbs , Egidl_dVds , Egidl_dVgs ; +double Igs , Igs_dVbs , Igs_dVds , Igs_dVgs ; +double Igs_dVbse , Igs_dVdse , Igs_dVgse ; +double Ilg , Ilg_dVbs , Ilg_dVds , Ilg_dVgs ; +double Ilg_dVbse , Ilg_dVdse , Ilg_dVgse ; +double Cox0 ; +double Lgate ; +double rp1 , rp1_dVds ; +/* connecting function */ +double FD2 , FD2_dVbs , FD2_dVds , FD2_dVgs ; +double FMD , FMD_dVds ; +/* Phonon scattering */ +double Wgate ; +double mueph ; +/* temporary vars.-- */ +double T0 , T1 , T2 , T3 , T4 , T5 , T6 , T7 , T8 , T9 ; +double TX , TX_dVbs , TX_dVds , TX_dVgs ; +double TY , TY_dVbs , TY_dVds , TY_dVgs ; +double T1_dVbs , T1_dVds , T1_dVgs ; +double T2_dVbs , T2_dVds , T2_dVgs ; +double T3_dVbs , T3_dVds , T3_dVgs ; +double T4_dVbs , T4_dVds , T4_dVgs ; +double T5_dVbs , T5_dVds , T5_dVgs ; +double T6_dVbs , T6_dVds , T6_dVgs ; +double T7_dVbs , T7_dVds , T7_dVgs ; +double T8_dVbs , T8_dVds , T8_dVgs ; +double T9_dVbs , T9_dVds , T9_dVgs ; +double T10 , T20 , T21 , T30 , T31 ; + + +/*================ Start of executable code.=================*/ + + flg_info = sIN.info ; + +/*-----------------------------------------------------------* +* Change units into CGS. +* - This section may be moved to an interface routine. +*-----------------*/ + +/* device instances */ + sIN.xl *= C_m2cm ; + sIN.xw *= C_m2cm ; + sIN.as *= C_m2cm_p2 ; + sIN.ad *= C_m2cm_p2 ; + sIN.ps *= C_m2cm ; + sIN.pd *= C_m2cm ; + +/* model parameters */ + sIN.tox *= C_m2cm ; + sIN.xld *= C_m2cm ; + sIN.xwd *= C_m2cm ; + + sIN.xqy *= C_m2cm ; + + sIN.lp *= C_m2cm ; + sIN.xpolyd *= C_m2cm ; + sIN.tpoly *= C_m2cm ; + + sIN.rs *= C_m2cm ; + sIN.rd *= C_m2cm ; + + sIN.sc3 *= C_m2cm ; + sIN.scp3 *= C_m2cm ; + sIN.parl2 *= C_m2cm ; + + sIN.wfc *= C_m2cm ; + sIN.wsti *= C_m2cm ; + + sIN.rpock1 *= C_m2cm_p1o2 ; + + sIN.qme1 *= C_m2cm ; + sIN.qme3 *= C_m2cm ; + + sIN.gidl1 *= C_m2cm_p1o2 ; + + sIN.cgso /= C_m2cm ; + sIN.cgdo /= C_m2cm ; + sIN.cgbo /= C_m2cm ; + + sIN.js0 /= C_m2cm_p2 ; + sIN.js0sw /= C_m2cm ; + + sIN.cj /= C_m2cm_p2 ; + sIN.cjsw /= C_m2cm ; + sIN.cjswg /= C_m2cm ; + +/*-----------------------------------------------------------* +* Start of the routine. (label) +*-----------------*/ +start_of_routine: + + + +/*-----------------------------------------------------------* +* Temperature dependent constants. +*-----------------*/ + +/* Inverse of the thermal voltage */ + beta = C_QE / ( C_KB * sIN.temp ) ; + beta2 = beta * beta ; + +/* Band gap */ + Eg = C_Eg0 - sIN.temp + * ( sIN.bgtmp1 + sIN.temp * sIN.bgtmp2 ) ; + + Eg300 = C_Eg0 - C_T300 + * ( sIN.bgtmp1 + C_T300 * sIN.bgtmp2 ) ; + +/* Intrinsic carrier concentration */ + Nin = C_Nin0 * pow( sIN.temp / C_T300 , 1.5e0 ) + * exp( - Eg / 2.0e0 * beta + Eg300 / 2.0e0 * C_b300 ) ; + +/*-----------------------------------------------------------* +* Fixed part. +*-----------------*/ + + +/* Lgate in [cm] / [m] */ + Lgate = sIN.xl ; + Wgate = sIN.xw ; + +/* Phonon Scattering */ + T1 = log( Wgate ) ; + T2 = sIN.w0 - T1 - sti1_dlt ; + T3 = T2 * T2 ; + T4 = sqrt( T3 + 4.0 * sti1_dlt * sIN.w0 ) ; + T5 = sIN.w0 - ( T2 - T4 ) / 2 ; + mueph = sIN.mueph1 + sIN.mueph2 * T5 ; + +/* Metallurgical channel geometry */ + Weff = sIN.xw - 2.0e0 * sIN.xwd ; + Leff = sIN.xl - 2.0e0 * sIN.xld ; + Leff_inv = 1.0e0 / Leff ; + +/* Flat band voltage */ + Vfb = sIN.vfbc ; + +/* Surface impurity profile */ + + if( Lgate > sIN.lp ){ + Nsub = ( sIN.nsubc * ( Lgate - sIN.lp ) + + sIN.nsubp * sIN.lp ) / Lgate ; + } else { + Nsub = sIN.nsubp + + ( sIN.nsubp - sIN.nsubc ) * ( sIN.lp - Lgate ) / sIN.lp ; + } + + q_Nsub = C_QE * Nsub ; + +/* 2 phi_B */ + /* @temp, with pocket */ + Pb2 = 2.0e0 / beta * log( Nsub / Nin ); + /* @300K, with pocket */ + Pb20 = 2.0e0 / C_b300 * log( Nsub / C_Nin0 ) ; + /* @300K, w/o pocket */ + Pb2c = 2.0e0 / C_b300 * log( sIN.nsubc / C_Nin0 ) ; + +/* Debye length */ + Ldby = sqrt( C_ESI / beta / q_Nsub ) ; + +/* Coefficient of the F function for bulk charge */ + cnst0 = q_Nsub * Ldby * C_SQRT_2 ; + +/* cnst1: n_{p0} / p_{p0} */ + T1 = Nin / Nsub ; + cnst1 = T1 * T1 ; +/* Cox (clasical) */ + Cox0 = C_EOX / sIN.tox ; + + + +/*-----------------------------------------------------------* +* Exchange bias conditions according to MOS type. +* - Vxse are external biases for HiSIM. ( type=NMOS , Vds >= 0 +* are assumed.) +*-----------------*/ + + /* + Vbse = sIN.type * sIN.vbs ; + Vdse = sIN.type * sIN.vds ; + Vgse = sIN.type * sIN.vgs ; + Vbde = Vbse - Vdse ; + */ + /* modified by K. M. for SPICE3f5 */ + Vbse = sIN.vbs; + Vdse = sIN.vds; + Vgse = sIN.vgs; + Vbde = Vbse - Vdse; + + +/*---------------------------------------------------* +* Cramp too large biases. +* -note: Quantities are extrapolated in PART-5. +*-----------------*/ + + if ( Vbse < Vbs_min ) { + flg_vbsc = -1 ; + Vbsc = Vbs_min ; + } else if ( Vbse > 0.0 ) { + flg_vbsc = 1 ; + T1 = Vbse / Vbs_max ; + T2 = sqrt ( 1.0 + ( T1 * T1 ) ) ; + Vbsc = Vbse / T2 ; + Vbsc_dVbse = Vbs_max * Vbs_max + / ( ( Vbs_max * Vbs_max + Vbse * Vbse ) * T2 ) ; + } else { + flg_vbsc = 0 ; + Vbsc = Vbse ; + } + + + if ( Vdse > Vds_max ) { + flg_vdsc = 1 ; + Vdsc = Vds_max ; + } else { + flg_vdsc = 0 ; + Vdsc = Vdse ; + } + + if ( Vgse > Vgs_max ) { + flg_vgsc = 1 ; + Vgsc = Vgs_max ; + } else { + flg_vgsc = 0 ; + Vgsc = Vgse ; + } + + if ( Vbde < Vbd_min ) { + flg_vbdc = -1 ; + Vbdc = Vbd_min ; + } else if ( Vbde > Vbd_max ) { + Vbdc = Vbd_max ; + flg_vbdc = 1 ; + } else { + Vbdc = Vbde ; + flg_vbdc = 0 ; + } + + if ( flg_vbsc == -1 || flg_vdsc != 0 || flg_vgsc != 0 || + flg_vbdc != 0 ) { + flg_vxxc = 1 ; + } + + +/*-------------------------------------------------------------------* +* Set flags. +*-----------------*/ + + flg_rsrd = 0 ; + flg_iprv = 0 ; + flg_pprv = 0 ; + + Rs = sIN.rs / Weff ; + Rd = sIN.rd / Weff ; + + if ( Rs + Rd >= epsm10 && sIN.corsrd >= 1 ) { + flg_rsrd = 1 ; + } + + if ( sIN.has_prv == 1 ) { + + Vbsc_dif = Vbsc - sIN.vbsc_prv ; + Vdsc_dif = Vdsc - sIN.vdsc_prv ; + Vgsc_dif = Vgsc - sIN.vgsc_prv ; + + sum_vdif = fabs( Vbsc_dif ) + fabs( Vdsc_dif ) + + fabs( Vgsc_dif ) ; + + if ( sIN.coiprv >= 1 && sum_vdif <= vtol_iprv ) { flg_iprv = 1 ;} + if ( sIN.copprv >= 1 && sum_vdif <= vtol_pprv ) { flg_pprv = 1 ;} + } + + if ( flg_rsrd == 0 ) { + lp_bs_max = 1 ; + flg_iprv = 0 ; + } + + + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++* +* Bias loop: iteration to solve the system of equations of +* the small circuit taking account Rs and Rd. +* - Vxs are internal (or effective) biases. +* - Equations: +* Vbs = Vbsc - Rs * Ids +* Vds = Vdsc - ( Rs + Rd ) * Ids +* Vgs = Vgsc - Rs * Ids +*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + +/*-----------------------------------------------------------* +* Initial guesses for biases. +*-----------------*/ + + if ( flg_iprv == 1 ) { + + sIN.ids_dvbs_prv = Fn_Max( 0.0 , sIN.ids_dvbs_prv ) ; + sIN.ids_dvds_prv = Fn_Max( 0.0 , sIN.ids_dvds_prv ) ; + sIN.ids_dvgs_prv = Fn_Max( 0.0 , sIN.ids_dvgs_prv ) ; + + dVbs = Vbsc_dif * ( 1.0 - + 1.0 / ( 1.0 + Rs * sIN.ids_dvbs_prv ) ) ; + dVds = Vdsc_dif * ( 1.0 - + 1.0 / ( 1.0 + ( Rs + Rd ) * sIN.ids_dvds_prv ) ) ; + dVgs = Vgsc_dif * ( 1.0 - + 1.0 / ( 1.0 + Rs * sIN.ids_dvgs_prv ) ) ; + + /* + Ids = sIN.type * sIN.ids_prv + + sIN.ids_dvbs_prv * dVbs + + sIN.ids_dvds_prv * dVds + + sIN.ids_dvgs_prv * dVgs ; + */ + Ids = sIN.ids_prv + + sIN.ids_dvbs_prv * dVbs + + sIN.ids_dvds_prv * dVds + + sIN.ids_dvgs_prv * dVgs ; + + T1 = ( Ids - sIN.ids_prv ) ; + T2 = fabs( T1 ) ; + if ( Ids_maxvar * sIN.ids_prv < T2 ) { + Ids = sIN.ids_prv * ( 1.0 + Fn_Sgn( T1 ) * Ids_maxvar ) ; + } + + if ( Ids < 0 ) { + Ids = 0.0 ; + } + + } else { + Ids = 0.0 ; + + if ( flg_pprv == 1 ) { + dVbs = Vbsc_dif ; + dVds = Vdsc_dif ; + dVgs = Vgsc_dif ; + } + } + + Vbs = Vbsc - Ids * Rs ; + + Vds = Vdsc - Ids * ( Rs + Rd ) ; + if ( Vds * Vdsc <= 0.0 ) { Vds = 0.0 ; } + + Vgs = Vgsc - Ids * Rs ; + + if ( flg_pprv == 1 ) { + + Ps0 = sIN.ps0_prv ; + + Ps0_dVbs = sIN.ps0_dvbs_prv ; + Ps0_dVds = sIN.ps0_dvds_prv ; + Ps0_dVgs = sIN.ps0_dvgs_prv ; + + Pds = sIN.pds_prv ; + + Pds_dVbs = sIN.pds_dvbs_prv ; + Pds_dVds = sIN.pds_dvds_prv ; + Pds_dVgs = sIN.pds_dvgs_prv ; + } + + +/*-----------------------------------------------------------* +* start of the loop. +*-----------------*/ + + for ( lp_bs = 1 ; lp_bs <= lp_bs_max ; lp_bs ++ ) { + + + Ids_last = Ids ; + + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +* PART-1: Basic device characteristics. +*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + +/*-----------------------------------------------------------* +* Initialization. +*-----------------*/ + /* Initialization of counters is needed for restart. */ + lp_s0 = 0 ; + lp_sl = 0 ; + +/*-----------------------------------------------------------* +* Vxsz: Modified bias introduced to realize symmetry at Vds=0. +*-----------------*/ + + T1 = exp( - Vbsc_dVbse * Vds / ( 2.0 * sIN.vzadd0 ) ) ; + Vzadd = sIN.vzadd0 * T1 ; + Vzadd_dVds = - 0.5 * Vbsc_dVbse * T1 ; + + + if ( Vzadd < ps_conv ) { + Vzadd = 0.0 ; + Vzadd_dVds = 0.0 ; + } + + Vbsz = Vbs + Vzadd ; + Vbsz_dVbs = 1.0 ; + Vbsz_dVds = Vzadd_dVds ; + + Vdsz = Vds + 2 * Vzadd ; + Vdsz_dVds = 1.0 + 2 * Vzadd_dVds ; + + Vgsz = Vgs + Vzadd ; + Vgsz_dVgs = 1.0 ; + Vgsz_dVds = Vzadd_dVds ; + + +/*-----------------------------------------------------------* +* Quantum effect +*-----------------*/ + + T1 = 2.0 * q_Nsub * C_ESI ; + T2 = sqrt( T1 * ( Pb20 - Vbsz ) ) ; + + Vthq = Pb20 + Vfb + sIN.tox / C_EOX * T2 + sIN.qme2 ; + + T3 = - 0.5 * sIN.tox / C_EOX * T1 / T2 ; + Vthq_dVbs = T3 * Vbsz_dVbs ; + Vthq_dVds = T3 * Vbsz_dVds ; + + + T1 = - Vthq ; + T2 = Vgsz - Vthq ; + T3 = sIN.qme1 * T1 * T1 + sIN.qme3 ; + T4 = sIN.qme1 * T2 * T2 + sIN.qme3 ; + + T5 = T4 - T3 - qme_dlt ; + + T6 = sqrt( T5 * T5 + 4.0 * qme_dlt * T4 ) ; + + dTox = T4 - 0.5 * ( T5 + T6 ) ; + + /* dTox_dT4 */ + T7 = 1.0 - 0.5 * ( 1.0 + ( T4 - T3 + qme_dlt ) / T6 ) ; + + T8 = 2.0 * sIN.qme1 * T2 * T7 ; + + dTox_dVbs = T8 * ( - Vthq_dVbs ) ; + dTox_dVds = T8 * ( Vgsz_dVds - Vthq_dVds ) ; + dTox_dVgs = T8 * ( Vgsz_dVgs ) ; + + if ( Vgsz - Vthq > 0 ) { + T4 = sIN.qme3 ; + T5 = T4 - T3 - qme_dlt ; + + T6 = sqrt( T5 * T5 + 4.0 * qme_dlt * T4 ) ; + + dTox = T4 - 0.5 * ( T5 + T6 ); + + dTox_dVbs = 0.0 ; + dTox_dVds = 0.0 ; + dTox_dVgs = 0.0 ; + } + + Tox = sIN.tox + dTox ; + Tox_dVbs = dTox_dVbs ; + Tox_dVds = dTox_dVds ; + Tox_dVgs = dTox_dVgs ; + + Cox = C_EOX / Tox ; + T1 = - C_EOX / ( Tox * Tox ) ; + Cox_dVbs = T1 * Tox_dVbs ; + Cox_dVds = T1 * Tox_dVds ; + Cox_dVgs = T1 * Tox_dVgs ; + + Cox_inv = Tox / C_EOX ; + T1 = 1.0 / C_EOX ; + Cox_inv_dVbs = T1 * Tox_dVbs ; + Cox_inv_dVds = T1 * Tox_dVds ; + Cox_inv_dVgs = T1 * Tox_dVgs ; + + +/*-----------------------------------------------------------* +* Threshold voltage. +*-----------------*/ + + Delta = 0.1 ; + + Vbs1 = 2.0 - 0.25 * Vbsz ; + Vbs2 = - Vbsz ; + + Vbsd = Vbs1 - Vbs2 - Delta ; + Vbsd_dVbs = 0.75 * Vbsz_dVbs ; + Vbsd_dVds = 0.75 * Vbsz_dVds ; + + T1 = sqrt( Vbsd * Vbsd + 4.0 * Delta ) ; + + Vbszm = - Vbs1 + 0.5 * ( Vbsd + T1 ) ; + Vbszm_dVbs = 0.25 * Vbsz_dVbs + + 0.5 * ( Vbsd_dVbs + Vbsd * Vbsd_dVbs / T1 ) ; + Vbszm_dVds = 0.25 * Vbsz_dVds + + 0.5 * ( Vbsd_dVds + Vbsd * Vbsd_dVds / T1 ) ; + + Psum = ( Pb20 - Vbsz ) ; + + if ( Psum >= epsm10 ) { + Psum_dVbs = - Vbsz_dVbs ; + Psum_dVds = - Vbsz_dVds ; + } else { + Psum = epsm10 ; + Psum_dVbs = 0.0e0 ; + Psum_dVds = 0.0e0 ; + } + + sqrt_Psum = sqrt( Psum ) ; + + + +/*---------------------------------------------------* +* Vthp : Vth with pocket. +*-----------------*/ + + T1 = 2.0 * q_Nsub * C_ESI ; + Qb0 = sqrt( T1 * ( Pb20 - Vbsz ) ) ; + + Qb0_dVbs = 0.5 * T1 / Qb0 * ( - Vbsz_dVbs ) ; + Qb0_dVds = 0.5 * T1 / Qb0 * ( - Vbsz_dVds ) ; + + Vthp = Pb20 + Vfb + Qb0 * Cox_inv ; + + Vthp_dVbs = Qb0_dVbs * Cox_inv + Qb0 * Cox_inv_dVbs ; + Vthp_dVds = Qb0_dVds * Cox_inv + Qb0 * Cox_inv_dVds ; + Vthp_dVgs = Qb0 * Cox_inv_dVgs ; + +/*-------------------------------------------* +* dVthLP : Short-channel effect induced by pocket. +* - Vth0 : Vth without pocket. +*-----------------*/ + + if ( sIN.lp != 0.0 ) { + + T1 = 2.0 * C_QE * sIN.nsubc * C_ESI ; + T2 = sqrt( T1 * ( Pb2c - Vbsz ) ) ; + + Vth0 = Pb2c + Vfb + T2 * Cox_inv ; + + Vth0_dVbs = 0.5 * T1 / T2 * ( - Vbsz_dVbs ) * Cox_inv + + T2 * Cox_inv_dVbs ; + Vth0_dVds = 0.5 * T1 / T2 * ( - Vbsz_dVds ) * Cox_inv + + T2 * Cox_inv_dVds ; + Vth0_dVgs = T2 * Cox_inv_dVgs ; + + LEY = sIN.parl1 * sIN.lp ; + + T1 = C_ESI * Cox_inv ; + T2 = sqrt( 2.0e0 * C_ESI / C_QE / sIN.nsubp ) ; + T4 = 1.0e0 / ( LEY * LEY ) ; + T5 = 2.0e0 * ( C_Vbi - Pb20 ) * T1 * T2 * T4 ; + + dVth0 = T5 * sqrt_Psum ; + + T6 = 0.5 * T5 / sqrt_Psum ; + T7 = 2.0e0 * ( C_Vbi - Pb20 ) * C_ESI * T2 * T4 * sqrt_Psum ; + dVth0_dVbs = T6 * Psum_dVbs + T7 * Cox_inv_dVbs ; + dVth0_dVds = T6 * Psum_dVds + T7 * Cox_inv_dVds ; + dVth0_dVgs = T7 * Cox_inv_dVgs ; + + T1 = Vthp - Vth0 ; + T2 = sIN.scp1 + sIN.scp3 * Psum / sIN.lp ; + T3 = T2 + sIN.scp2 * Vdsz ; + + dVthLP = T1 * dVth0 * T3 ; + + dVthLP_dVbs = ( Vthp_dVbs - Vth0_dVbs ) * dVth0 * T3 + + T1 * dVth0_dVbs * T3 + + T1 * dVth0 * sIN.scp3 * Psum_dVbs / sIN.lp ; + dVthLP_dVds = ( Vthp_dVds - Vth0_dVds ) * dVth0 * T3 + + T1 * dVth0_dVds * T3 + + T1 * dVth0 + * ( sIN.scp3 * Psum_dVds / sIN.lp + + sIN.scp2 * Vdsz_dVds ) ; + + dVthLP_dVgs = ( Vthp_dVgs - Vth0_dVgs ) * dVth0 * T3 + + T1 * dVth0_dVgs * T3 ; + + } else { + dVthLP = 0.0e0 ; + dVthLP_dVbs = 0.0e0 ; + dVthLP_dVds = 0.0e0 ; + dVthLP_dVgs = 0.0e0 ; + } + +/*---------------------------------------------------* +* dVthSC : Short-channel effect induced by Vds. +*-----------------*/ + + T1 = C_ESI * Cox_inv ; + T2 = sqrt( 2.0e0 * C_ESI / q_Nsub ) ; + T3 = sIN.parl1 * ( Lgate - sIN.parl2 ) ; + T4 = 1.0e0 / ( T3 * T3 ) ; + T5 = 2.0e0 * ( C_Vbi - Pb20 ) * T1 * T2 * T4 ; + + dVth0 = T5 * sqrt_Psum ; + T6 = T5 / 2 / sqrt_Psum ; + T7 = 2.0e0 * ( C_Vbi - Pb20 ) * C_ESI * T2 * T4 * sqrt_Psum ; + dVth0_dVbs = T6 * Psum_dVbs + T7 * Cox_inv_dVbs ; + dVth0_dVds = T6 * Psum_dVds + T7 * Cox_inv_dVds ; + dVth0_dVgs = T7 * Cox_inv_dVgs ; + + + T4 = sIN.sc1 + sIN.sc3 * Psum / Lgate ; + T4_dVbs = sIN.sc3 * Psum_dVbs / Lgate ; + T4_dVds = sIN.sc3 * Psum_dVds / Lgate ; + + T5 = sIN.sc2 ; + + dVthSC = dVth0 * ( T4 + T5 * Vdsz ) ; + + dVthSC_dVbs = dVth0_dVbs * ( T4 + T5 * Vdsz ) + + dVth0 * ( T4_dVbs ) ; + + dVthSC_dVds = dVth0_dVds * ( T4 + T5 * Vdsz ) + + dVth0 * ( T4_dVds + T5 * Vdsz_dVds ) ; + + dVthSC_dVgs = dVth0_dVgs * ( T4 + T5 * Vdsz ) ; + +/*---------------------------------------------------* +* dVthW : narrow-channel effect. +*-----------------*/ + + T1 = 1.0 / Cox ; + T2 = T1 * T1 ; + T3 = 1.0 / ( Cox + sIN.wfc / Weff ) ; + T4 = T3 * T3 ; + + dVthW = Qb0 * ( T1 - T3 ) ; + + dVthW_dVbs = Qb0_dVbs * ( T1 - T3 ) + - Qb0 * Cox_dVbs * ( T2 - T4 ) ; + dVthW_dVds = Qb0_dVds * ( T1 - T3 ) + - Qb0 * Cox_dVds * ( T2 - T4 ) ; + dVthW_dVgs = - Qb0 * Cox_dVgs * ( T2 - T4 ) ; + +/*---------------------------------------------------* +* dVth : Total variation. +* - Positive dVth means the decrease in Vth. +*-----------------*/ + + dVth = dVthSC + dVthLP + dVthW ; + dVth_dVbs = dVthSC_dVbs + dVthLP_dVbs + dVthW_dVbs ; + dVth_dVds = dVthSC_dVds + dVthLP_dVds + dVthW_dVds ; + dVth_dVgs = dVthSC_dVgs + dVthLP_dVgs + dVthW_dVgs ; + + + +/*---------------------------------------------------* +* Vth : Threshold voltage. +*-----------------*/ + + Vth = Vthp - dVth ; + +/*---------------------------------------------------* +* Poly-Depletion Effect +*-----------------*/ + + +/*---------------------------------------------------* +* Poly-Depletion Effect +*-----------------*/ + + dPpg = Nsub / sIN.nsubc * sIN.pgd1 + * exp( Vgsz - sIN.pgd2 - sIN.pgd3 * Vdsz ) ; + dPpg_dVds = - sIN.pgd3 * dPpg * Vdsz_dVds + + dPpg * Vgsz_dVds ; + dPpg_dVgs = dPpg * Vgsz_dVgs ; + + T1 = 1.0e0 - dPpg - pol_dlt ; + T1_dVds = - dPpg_dVds ; + T1_dVgs = - dPpg_dVgs ; + T2 = sqrt( T1 * T1 + 4.0e0 * pol_dlt ) ; + + dPpg = 1.0e0 - 0.5e0 * ( T1 + T2 ) ; + dPpg_dVds = - 0.5e0 * ( T1_dVds + T1 * T1_dVds / T2 ) ; + dPpg_dVgs = - 0.5e0 * ( T1_dVgs + T1 * T1_dVgs / T2 ) ; + + + +/*---------------------------------------------------* +* Vgp : Effective gate bias with SCE & RSCE & flatband. +*-----------------*/ + + Vgp = Vgs - Vfb + dVth - dPpg ; + + Vgp_dVbs = dVth_dVbs ; + Vgp_dVds = dVth_dVds - dPpg_dVds ; + Vgp_dVgs = 1.0e0 + dVth_dVgs - dPpg_dVgs ; + +/*---------------------------------------------------* +* Vgs_fb : Actual flatband voltage taking account Vbs. +* - note: if Vgs == Vgs_fb then Vgp == Ps0 == Vbs . +*------------------*/ + + Vgs_fb = Vfb - dVth + dPpg + Vbs ; + + + +/*-----------------------------------------------------------* +* Constants in the equation of Ps0 . +*-----------------*/ + + fac1 = cnst0 * Cox_inv ; + fac1_dVbs = cnst0 * Cox_inv_dVbs ; + fac1_dVds = cnst0 * Cox_inv_dVds ; + fac1_dVgs = cnst0 * Cox_inv_dVgs ; + + fac1p2 = fac1 * fac1 ; + +/*-----------------------------------------------------------* +* Accumulation zone. (zone-A) +* - evaluate basic characteristics and exit from this part. +*-----------------*/ + + if ( Vgs < Vgs_fb ) { + + +/*---------------------------------------------------* +* Evaluation of Ps0. +* - Psa : Analytical solution of +* Cox( Vgp - Psa ) = cnst0 * Qacc +* where Qacc is the 3-dgree series of (fdep)^{1/2}. +* The unkown is transformed to Chi=beta(Ps0-Vbs). +* - Ps0_min : |Ps0_min| when Vbs=0. +*-----------------*/ + + Ps0_min = Eg - Pb2 ; + + TX = beta * ( Vgp - Vbs ) ; + + TX_dVbs = beta * ( Vgp_dVbs - 1.0 ) ; + TX_dVds = beta * Vgp_dVds ; + TX_dVgs = beta * Vgp_dVgs ; + + TY = Cox / ( beta * cnst0 ) ; + + T1 = 1.0 / ( beta * cnst0 ) ; + TY_dVbs = T1 * Cox_dVbs ; + TY_dVds = T1 * Cox_dVds ; + TY_dVgs = T1 * Cox_dVgs ; + + Ac41 = 2.0 + 3.0 * C_SQRT_2 * TY ; + + Ac4 = 8.0 * Ac41 * Ac41 * Ac41 ; + + T1 = 72.0 * Ac41 * Ac41 * C_SQRT_2 ; + Ac4_dVbs = T1 * TY_dVbs ; + Ac4_dVds = T1 * TY_dVds ; + Ac4_dVgs = T1 * TY_dVgs ; + + Ac31 = 7.0 * C_SQRT_2 - 9.0 * TY * ( TX - 2.0 ) ; + Ac31_dVbs = - 9.0 * ( TY_dVbs * ( TX - 2.0 ) + TY * TX_dVbs ) ; + Ac31_dVds = - 9.0 * ( TY_dVds * ( TX - 2.0 ) + TY * TX_dVds ) ; + Ac31_dVgs = - 9.0 * ( TY_dVgs * ( TX - 2.0 ) + TY * TX_dVgs ) ; + + Ac3 = Ac31 * Ac31 ; + + Ac3_dVbs = 2.0 * Ac31 * Ac31_dVbs ; + Ac3_dVds = 2.0 * Ac31 * Ac31_dVds ; + Ac3_dVgs = 2.0 * Ac31 * Ac31_dVgs ; + + Ac2 = sqrt( Ac4 + Ac3 ) ; + Ac2_dVbs = 0.5 * ( Ac4_dVbs + Ac3_dVbs ) / Ac2 ; + Ac2_dVds = 0.5 * ( Ac4_dVds + Ac3_dVds ) / Ac2 ; + Ac2_dVgs = 0.5 * ( Ac4_dVgs + Ac3_dVgs ) / Ac2 ; + + Ac1 = -7.0 * C_SQRT_2 + + Ac2 + 9.0 * TY * ( TX - 2.0 ) ; + + Ac1_dVbs = Ac2_dVbs + + 9.0 * ( TY_dVbs * ( TX - 2.0 ) + TY * TX_dVbs ) ; + Ac1_dVds = Ac2_dVds + + 9.0 * ( TY_dVds * ( TX - 2.0 ) + TY * TX_dVds ) ; + Ac1_dVgs = Ac2_dVgs + + 9.0 * ( TY_dVgs * ( TX - 2.0 ) + TY * TX_dVgs ) ; + + Acd = pow( Ac1 , C_1o3 ) ; + + T1 = C_1o3 / ( Acd * Acd ) ; + Acd_dVbs = Ac1_dVbs * T1 ; + Acd_dVds = Ac1_dVds * T1 ; + Acd_dVgs = Ac1_dVgs * T1 ; + + Acn = -4.0 * C_SQRT_2 - 12.0 * TY + + 2.0 * Acd + C_SQRT_2 * Acd * Acd ; + + Acn_dVbs = - 12.0 * TY_dVbs + + ( 2.0 + 2.0 * C_SQRT_2 * Acd ) * Acd_dVbs ; + Acn_dVds = - 12.0 * TY_dVds + + ( 2.0 + 2.0 * C_SQRT_2 * Acd ) * Acd_dVds ; + Acn_dVgs = - 12.0 * TY_dVgs + + ( 2.0 + 2.0 * C_SQRT_2 * Acd ) * Acd_dVgs ; + + Chi = Acn / Acd ; + + T1 = 1.0 / ( Acd * Acd ) ; + + Chi_dVbs = ( Acn_dVbs * Acd - Acn * Acd_dVbs ) * T1 ; + Chi_dVds = ( Acn_dVds * Acd - Acn * Acd_dVds ) * T1 ; + Chi_dVgs = ( Acn_dVgs * Acd - Acn * Acd_dVgs ) * T1 ; + + Psa = Chi / beta + Vbs ; + + Psa_dVbs = Chi_dVbs / beta + 1.0 ; + Psa_dVds = Chi_dVds / beta ; + Psa_dVgs = Chi_dVgs / beta ; + + T1 = Psa - Vbs ; + T2 = T1 / Ps0_min ; + T3 = sqrt( 1.0 + ( T2 * T2 ) ) ; + + T9 = T2 / T3 / Ps0_min ; + T3_dVbs = T9 * ( Psa_dVbs - 1.0 ) ; + T3_dVds = T9 * ( Psa_dVds ) ; + T3_dVgs = T9 * ( Psa_dVgs ) ; + + Ps0 = T1 / T3 + Vbs ; + + T9 = 1.0 / ( T3 * T3 ) ; + + Ps0_dVbs = T9 * ( ( Psa_dVbs - 1.0 ) * T3 - T1 * T3_dVbs ) + + 1.0 ; + Ps0_dVds = T9 * ( Psa_dVds * T3 - T1 * T3_dVds ) ; + Ps0_dVgs = T9 * ( Psa_dVgs * T3 - T1 * T3_dVgs ) ; + + + +/*---------------------------------------------------* +* Characteristics. +*-----------------*/ + + T0 = - Weff * Leff ; + T1 = T0 * Cox ; + T2 = ( Vgp - Ps0 ) ; + + Qb = T1 * T2 ; + + Qb_dVbs = T1 * ( Vgp_dVbs - Ps0_dVbs ) + + T0 * Cox_dVbs * T2 ; + Qb_dVds = T1 * ( Vgp_dVds - Ps0_dVds ) + + T0 * Cox_dVds * T2 ; + Qb_dVgs = T1 * ( Vgp_dVgs - Ps0_dVgs ) + + T0 * Cox_dVgs * T2 ; + + Psl = Ps0 ; + Psl_dVbs = Ps0_dVbs ; + Psl_dVds = Ps0_dVds ; + Psl_dVgs = Ps0_dVgs ; + + Psdl = Psl ; + Psdl_dVbs = Psl_dVbs ; + Psdl_dVds = Psl_dVds ; + Psdl_dVgs = Psl_dVgs ; + + Qi = 0.0e0 ; + Qi_dVbs = 0.0e0 ; + Qi_dVds = 0.0e0 ; + Qi_dVgs = 0.0e0 ; + + Qd = 0.0e0 ; + Qd_dVbs = 0.0e0 ; + Qd_dVds = 0.0e0 ; + Qd_dVgs = 0.0e0 ; + + Ids = 0.0e0 ; + Ids_dVbs = 0.0e0 ; + Ids_dVds = 0.0e0 ; + Ids_dVgs = 0.0e0 ; + + VgVt = 0.0 ; + + flg_noqi = 1 ; + + goto end_of_part_1 ; + + } + +/*-----------------------------------------------------------* +* Initial guess for Ps0. +*-----------------*/ + +/*---------------------------------------------------* +* Ps0_iniA: solution of subthreshold equation assuming zone-D1/D2. +*-----------------*/ + + TX = 1.0e0 + 4.0e0 + * ( beta * ( Vgp - Vbs ) - 1.0e0 ) / ( fac1p2 * beta2 ) ; + TX = Fn_Max( TX , epsm10 ) ; + + Ps0_iniA = Vgp + + fac1p2 * beta / 2.0e0 * ( 1.0e0 - sqrt( TX ) ) ; + + +/*---------------------------------------------------* +* Use previous value. +*-----------------*/ + if ( flg_pprv == 1 ) { + + Ps0_ini = Ps0 + Ps0_dVbs * dVbs + + Ps0_dVds * dVds + Ps0_dVgs * dVgs ; + + T1 = Ps0_ini - Ps0 ; + + if ( T1 < - dP_max || T1 > dP_max ) { + flg_pprv = 0 ; + } else { + Ps0_iniA = Fn_Max( Ps0_ini , Ps0_iniA ) ; + } + + } + +/*---------------------------------------------------* +* Analytical initial guess. +*-----------------*/ + if ( flg_pprv == 0 ) { +/*-------------------------------------------* +* Common part. +*-----------------*/ + + Chi = beta * ( Ps0_iniA - Vbs ) ; + +/*-----------------------------------* +* zone-D1/D2 +* - Ps0_ini is the analytical solution of Qs=Qb0 with +* Qb0 being approximated to 3-degree polynomial. +*-----------------*/ + if ( Chi < znbd3 ) { + + TY = beta * ( Vgp - Vbs ) ; + T1 = 1.0e0 / ( cn_nc3 * beta * fac1 ) ; + T2 = 81 + 3 * T1 ; + T3 = -2916 - 81 * T1 + 27 * T1 * TY ; + T4 = 1458 - 81 * ( 54 + T1 ) + 27 * T1 * TY ; + T4 = T4 * T4 ; + T5 = pow( T3 + sqrt( 4 * T2 * T2 * T2 + T4 ) , C_1o3 ) ; + TX = 3 + - ( C_2p_1o3 * T2 ) / ( 3 * T5 ) + + 1 / ( 3 * C_2p_1o3 ) * T5 ; + + Ps0_iniA = TX / beta + Vbs ; + + Ps0_ini = Ps0_iniA ; + + +/*-----------------------------------* +* Weak inversion zone. +*-----------------*/ + } else if ( Vgs <= Vth ) { + + Ps0_ini = Ps0_iniA ; + + +/*-----------------------------------* +* Strong inversion zone. +* - Ps0_iniB : upper bound. +*-----------------*/ + } else { + + T1 = ( Cox * Cox ) / ( cnst0 * cnst0 ) / cnst1 ; + T2 = T1 * Vgp * Vgp ; + T3 = beta + 2.0 / Vgp ; + + Ps0_iniB = log( T2 ) / T3 ; + + T1 = Ps0_iniB - Ps0_iniA - c_ps0ini_2 ; + T2 = sqrt( T1 * T1 + 4.0e0 * c_ps0ini_2 * Ps0_iniB ) ; + + Ps0_ini = Ps0_iniB - ( T1 + T2 ) / 2 ; + + } + } + + if ( Ps0_ini < Vbs ) { + Ps0_ini = Vbs ; + } + + + +/*---------------------------------------------------* +* Assign initial guess. +*-----------------*/ + + Ps0 = Ps0_ini ; + + Psl_lim = Ps0_iniA ; + +/*---------------------------------------------------* +* Calculation of Ps0. (beginning of Newton loop) +* - Fs0 : Fs0 = 0 is the equation to be solved. +* - dPs0 : correction value. +*-----------------*/ + + + exp_bVbs = exp( beta * Vbs ) ; + + cfs1 = cnst1 * exp_bVbs ; + + for ( lp_s0 = 1 ; lp_s0 <= lp_s0_max ; lp_s0 ++ ) { + + Chi = beta * ( Ps0 - Vbs ) ; + + exp_Chi = exp( Chi ) ; + + fs01 = cfs1 * ( exp_Chi - 1.0e0 ) ; + fs01_dPs0 = cfs1 * beta * ( exp_Chi ) ; + + + if ( fs01 < epsm10 * cfs1 ) { + fs01 = 0.0 ; + fs01_dPs0 = 0.0 ; + } + +/*-------------------------------------------* +* zone-D1/D2. (Ps0) +* - Qb0 is approximated to 5-dgree polynomial. +*-----------------*/ + + if ( Chi < znbd5 ) { + + fi = Chi * Chi * Chi + * ( cn_im53 + Chi * ( cn_im54 + Chi * cn_im55 ) ) ; + fi_dChi = Chi * Chi + * ( 3 * cn_im53 + + Chi * ( 4 * cn_im54 + Chi * 5 * cn_im55 ) ) ; + + + + fs01 = cfs1 * fi * fi ; + fs01_dPs0 = cfs1 * beta * 2 * fi * fi_dChi ; + + + fb = Chi * ( cn_nc51 + Chi * ( cn_nc52 + + Chi * ( cn_nc53 + + Chi * ( cn_nc54 + Chi * cn_nc55 ) ) ) ) ; + fb_dChi = cn_nc51 + Chi * ( 2 * cn_nc52 + + Chi * ( 3 * cn_nc53 + + Chi * ( 4 * cn_nc54 + Chi * 5 * cn_nc55 ) ) ) ; + + + fs02 = sqrt( fb * fb + fs01 ) ; + + if ( fs02 >= epsm10 ) { + fs02_dPs0 = ( beta * fb_dChi * 2 * fb + fs01_dPs0 ) + / ( fs02 + fs02 ) ; + } else { + fs02 = sqrt( fb * fb + fs01 ) ; + fs02_dPs0 = beta * fb_dChi ; + } + + Fs0 = Vgp - Ps0 - fac1 * fs02 ; + + Fs0_dPs0 = - 1.0e0 - fac1 * fs02_dPs0 ; + + dPs0 = - Fs0 / Fs0_dPs0 ; + +/*-------------------------------------------* +* zone-D3. (Ps0) +*-----------------*/ + } else { + + Xi0 = Chi - 1.0e0 ; + + Xi0p12 = sqrt( Xi0 ) ; + + fs02 = sqrt( Xi0 + fs01 ) ; + + fs02_dPs0 = ( beta + fs01_dPs0 ) / ( fs02 + fs02 ) ; + + Fs0 = Vgp - Ps0 - fac1 * fs02 ; + + Fs0_dPs0 = - 1.0e0 - fac1 * fs02_dPs0 ; + + dPs0 = - Fs0 / Fs0_dPs0 ; + + } /* end of if ( Chi ... ) else block */ + +/*-------------------------------------------* +* Update Ps0 . +* - cramped to Vbs if Ps0 < Vbs . +*-----------------*/ + + if ( fabs( dPs0 ) > dP_max ) { + dPs0 = fabs( dP_max ) * Fn_Sgn( dPs0 ) ; + } + + Ps0 = Ps0 + dPs0 ; + + if ( Ps0 < Vbs ) { + Ps0 = Vbs ; + } + + +/*-------------------------------------------* +* Check convergence. +* NOTE: This condition may be too rigid. +*-----------------*/ + + if ( fabs( dPs0 ) <= ps_conv && fabs( Fs0 ) <= gs_conv ) { + break ; + } + + } /* end of Ps0 Newton loop */ + + + +/*-------------------------------------------* +* Procedure for diverged case. +*-----------------*/ + if ( lp_s0 > lp_s0_max ) { + fprintf( stderr , + "*** warning(HiSIM): Went Over Iteration Maximum (Ps0)\n" ) ; + fprintf( stderr , + " Vbse = %7.3f Vdse = %7.3f Vgse = %7.3f\n" , + Vbse , Vdse , Vgse ) ; + if ( flg_info >= 2 ) { + printf( + "*** warning(HiSIM): Went Over Iteration Maximum (Ps0)\n" ) ; + } + } + +/*---------------------------------------------------* +* Evaluate derivatives of Ps0. +* - note: Here, fs01_dVbs and fs02_dVbs are derivatives +* w.r.t. explicit Vbs. So, Ps0 in the fs01 and fs02 +* expressions is regarded as a constant. +*-----------------*/ + + Chi = beta * ( Ps0 - Vbs ) ; + + exp_Chi = exp( Chi ) ; + + cfs1 = cnst1 * exp_bVbs ; + if ( fs01 < epsm10 * cfs1 ) { + fs01 = 0.0 ; + fs01_dPs0 = 0.0 ; + fs01_dVbs = 0.0 ; + } + +/*-------------------------------------------* +* zone-D1/D2. (Ps0) +*-----------------*/ + + if ( Chi < znbd5 ) { + + fi = Chi * Chi * Chi + * ( cn_im53 + Chi * ( cn_im54 + Chi * cn_im55 ) ) ; + fi_dChi = Chi * Chi + * ( 3 * cn_im53 + + Chi * ( 4 * cn_im54 + Chi * 5 * cn_im55 ) ) ; + + + fs01 = cfs1 * fi * fi ; + fs01_dPs0 = cfs1 * beta * 2 * fi * fi_dChi ; + fs01_dVbs = cfs1 * beta * fi * ( fi - 2 * fi_dChi ) ; + + + fb = Chi * ( cn_nc51 + Chi * ( cn_nc52 + + Chi * ( cn_nc53 + + Chi * ( cn_nc54 + Chi * cn_nc55 ) ) ) ) ; + fb_dChi = cn_nc51 + Chi * ( 2 * cn_nc52 + + Chi * ( 3 * cn_nc53 + + Chi * ( 4 * cn_nc54 + Chi * 5 * cn_nc55 ) ) ) ; + + fs02 = sqrt( fb * fb + fs01 ) ; + + T2 = 1.0e0 / ( fs02 + fs02 ) ; + + if ( fs02 >= epsm10 ) { + fs02_dPs0 = ( beta * fb_dChi * 2 * fb + fs01_dPs0 ) * T2 ; + fs02_dVbs = ( - beta * fb_dChi * 2 * fb + fs01_dVbs ) + * T2 ; + } else { + fs02_dPs0 = beta * fb_dChi ; + fs02_dVbs = - beta * fb_dChi ; + } + + /* memo: Fs0 = Vgp - Ps0 - fac1 * fs02 */ + + Fs0_dPs0 = - 1.0e0 - fac1 * fs02_dPs0 ; + + Ps0_dVbs = - ( Vgp_dVbs + - ( fac1 * fs02_dVbs + fac1_dVbs * fs02 ) + ) / Fs0_dPs0 ; + Ps0_dVds = - ( Vgp_dVds + - fac1_dVds * fs02 + ) / Fs0_dPs0 ; + Ps0_dVgs = - ( Vgp_dVgs + - fac1_dVgs * fs02 + ) / Fs0_dPs0 ; + + + T1 = cnst0 ; + + Qb0 = T1 * fb ; + Qb0_dVbs = ( Ps0_dVbs - 1.0e0 ) * T1 * beta * fb_dChi ; + Qb0_dVds = Ps0_dVds * T1 * beta * fb_dChi ; + Qb0_dVgs = Ps0_dVgs * T1 * beta * fb_dChi ; + + fs01_dVbs = Ps0_dVbs * fs01_dPs0 + fs01_dVbs ; + fs01_dVds = Ps0_dVds * fs01_dPs0 ; + fs01_dVgs = Ps0_dVgs * fs01_dPs0 ; + fs02_dVbs = Ps0_dVbs * fs02_dPs0 + fs02_dVbs ; + fs02_dVds = Ps0_dVds * fs02_dPs0 ; + fs02_dVgs = Ps0_dVgs * fs02_dPs0 ; + + T1 = 1.0 / ( fs02 + fb * fb ) ; + T2 = T1 * T1 ; + + Qn0 = cnst0 * fs01 * T1 ; + + T3 = 2.0 * fb_dChi * fb * beta ; + + Qn0_dVbs = cnst0 * ( + fs01_dVbs * T1 + - fs01 * ( fs02_dVbs + + T3 * ( Ps0_dVbs - 1.0 ) ) * T2 ) ; + Qn0_dVds = cnst0 * ( + fs01_dVds * T1 + - fs01 * ( fs02_dVds + T3 * Ps0_dVds ) * T2 ) ; + Qn0_dVgs = cnst0 * ( + fs01_dVgs * T1 + - fs01 * ( fs02_dVgs + T3 * Ps0_dVgs ) * T2 ) ; + + +/*-------------------------------------------* +* zone-D1. (Ps0) +* - Evaluate basic characteristics and exit from this part. +*-----------------*/ + if ( Chi < znbd3 ) { + + + Psl = Ps0 ; + Psl_dVbs = Ps0_dVbs ; + Psl_dVds = Ps0_dVds ; + Psl_dVgs = Ps0_dVgs ; + + Pds = 0.0 ; + Pds_dVbs = 0.0 ; + Pds_dVds = 0.0 ; + Pds_dVgs = 0.0 ; + + T1 = - Weff * Leff ; + + Qb = T1 * Qb0 ; + Qb_dVbs = T1 * Qb0_dVbs ; + Qb_dVds = T1 * Qb0_dVds ; + Qb_dVgs = T1 * Qb0_dVgs ; + + if ( Qn0 < Cox * VgVt_small ) { + Qn0 = 0.0 ; + Qn0_dVbs = 0.0 ; + Qn0_dVds = 0.0 ; + Qn0_dVgs = 0.0 ; + } + + Qi = T1 * Qn0 ; + Qi_dVbs = T1 * Qn0_dVbs ; + Qi_dVds = T1 * Qn0_dVds ; + Qi_dVgs = T1 * Qn0_dVgs ; + + Qd = 0.0e0 ; + Qd_dVbs = 0.0e0 ; + Qd_dVds = 0.0e0 ; + Qd_dVgs = 0.0e0 ; + + Ids = 0.0e0 ; + Ids_dVbs = 0.0e0 ; + Ids_dVds = 0.0e0 ; + Ids_dVgs = 0.0e0 ; + + VgVt = 0.0 ; + + flg_noqi = 1 ; + + goto end_of_part_1 ; + } + +/*-------------------------------------------* +* zone-D2 +*-----------------*/ + + Xi0 = Chi - 1.0e0 ; + + Xi0_dVbs = beta * ( Ps0_dVbs - 1.0e0 ) ; + Xi0_dVds = beta * Ps0_dVds ; + Xi0_dVgs = beta * Ps0_dVgs ; + + Xi0p12 = sqrt( Xi0 ) ; + Xi0p32 = Xi0 * Xi0p12 ; + + Xi0p12_dVbs = 0.5e0 * Xi0_dVbs / Xi0p12 ; + Xi0p12_dVds = 0.5e0 * Xi0_dVds / Xi0p12 ; + Xi0p12_dVgs = 0.5e0 * Xi0_dVgs / Xi0p12 ; + + Xi0p32_dVbs = 1.5e0 * Xi0_dVbs * Xi0p12 ; + Xi0p32_dVds = 1.5e0 * Xi0_dVds * Xi0p12 ; + Xi0p32_dVgs = 1.5e0 * Xi0_dVgs * Xi0p12 ; + + Qn00 = Qn0 ; + Qn00_dVbs = Qn0_dVbs ; + Qn00_dVds = Qn0_dVds ; + Qn00_dVgs = Qn0_dVgs ; + + fs01 = cfs1 * ( exp_Chi - 1.0 ) ; + + fs01_dPs0 = cfs1 * beta * ( exp_Chi ) ; + fs01_dVbs = - cfs1 * beta ; + + + fs02 = sqrt( Xi0 + fs01 ) ; + + T2 = 0.5e0 / fs02 ; + + fs02_dPs0 = ( beta + fs01_dPs0 ) * T2 ; + + fs02_dVbs = ( - beta + fs01_dVbs ) * T2 ; + + + flg_noqi = 0 ; + + +/*-------------------------------------------* +* zone-D3. (Ps0) +*-----------------*/ + } else { + + fs01 = cfs1 * ( exp_Chi - 1.0 ) ; + + fs01_dPs0 = cfs1 * beta * ( exp_Chi ) ; + fs01_dVbs = - cfs1 * beta ; + + + Xi0 = Chi - 1.0e0 ; + + Xi0p12 = sqrt( Xi0 ) ; + Xi0p32 = Xi0 * Xi0p12 ; + + fs02 = sqrt( Xi0 + fs01 ) ; + + T2 = 0.5e0 / fs02 ; + + fs02_dPs0 = ( beta + fs01_dPs0 ) * T2 ; + + fs02_dVbs = ( - beta + fs01_dVbs ) * T2 ; + + /* memo: Fs0 = Vgp - Ps0 - fac1 * fs02 */ + + T2 = 0.5e0 / Xi0p12 ; + + Fs0_dPs0 = - 1.0e0 - fac1 * fs02_dPs0 ; + + Ps0_dVbs = - ( Vgp_dVbs + - ( fac1 * fs02_dVbs + fac1_dVbs * fs02 ) + ) / Fs0_dPs0 ; + + Ps0_dVds = - ( Vgp_dVds + - fac1_dVds * fs02 + ) / Fs0_dPs0 ; + Ps0_dVgs = - ( Vgp_dVgs + - fac1_dVgs * fs02 + ) / Fs0_dPs0 ; + + Xi0_dVbs = beta * ( Ps0_dVbs - 1.0e0 ) ; + Xi0_dVds = beta * Ps0_dVds ; + Xi0_dVgs = beta * Ps0_dVgs ; + + Xi0p12_dVbs = 0.5e0 * Xi0_dVbs / Xi0p12 ; + Xi0p12_dVds = 0.5e0 * Xi0_dVds / Xi0p12 ; + Xi0p12_dVgs = 0.5e0 * Xi0_dVgs / Xi0p12 ; + + Xi0p32_dVbs = 1.5e0 * Xi0_dVbs * Xi0p12 ; + Xi0p32_dVds = 1.5e0 * Xi0_dVds * Xi0p12 ; + Xi0p32_dVgs = 1.5e0 * Xi0_dVgs * Xi0p12 ; + + flg_noqi = 0 ; + + + } /* end of if ( Chi ... ) block */ + + + +/*-----------------------------------------------------------* +* NOTE: The following sections of this part are only for +* the conductive case. +*-----------------*/ + +/*-----------------------------------------------------------* +* Xi0 : beta * ( Ps0 - Vbs ) - 1 = Chi - 1 . +*-----------------*/ +/*-----------------------------------------------------------* +* Qn0 : Qi at source side. +* - Qn0 := cnst0 * ( ( Xi0 + fs01 )^(1/2) - ( Xi0 )^(1/2) ) +* - Derivatives of fs01 are redefined here. +*-----------------*/ +/* note:------------------------ +* fs01 = cnst1 * exp( Vbs ) * ( exp( Chi ) - Chi - 1.0e0 ) ; +* fs02 = sqrt( Xi0 + fs01 ) ; +*-------------------------------*/ + + Qn0 = cnst0 * fs01 / ( fs02 + Xi0p12 ) ; + + fs01_dVbs = Ps0_dVbs * fs01_dPs0 + fs01_dVbs ; + fs01_dVds = Ps0_dVds * fs01_dPs0 ; + fs01_dVgs = Ps0_dVgs * fs01_dPs0 ; + fs02_dVbs = Ps0_dVbs * fs02_dPs0 + fs02_dVbs ; + fs02_dVds = Ps0_dVds * fs02_dPs0 ; + fs02_dVgs = Ps0_dVgs * fs02_dPs0 ; + + Qn0_dVbs = Qn0 + * ( fs01_dVbs / fs01 + - ( fs02_dVbs + Xi0p12_dVbs ) / ( fs02 + Xi0p12 ) ) ; + Qn0_dVds = Qn0 + * ( fs01_dVds / fs01 + - ( fs02_dVds + Xi0p12_dVds ) / ( fs02 + Xi0p12 ) ) ; + Qn0_dVgs = Qn0 + * ( fs01_dVgs / fs01 + - ( fs02_dVgs + Xi0p12_dVgs ) / ( fs02 + Xi0p12 ) ) ; + +/*-----------------------------------------------------------* +* Qb0 : Qb at source side. +*-----------------*/ + + if ( Chi > znbd5 ) { + + Qb0 = cnst0 * Xi0p12 ; + Qb0_dVbs = cnst0 * Xi0p12_dVbs ; + Qb0_dVds = cnst0 * Xi0p12_dVds ; + Qb0_dVgs = cnst0 * Xi0p12_dVgs ; + + } + +/*-----------------------------------------------------------* +* FD2 : connecting function for zone-D2. +*-----------------*/ + + if ( Chi < znbd5 ) { + + T1 = 1.0 / ( znbd5 - znbd3 ) ; + + TX = T1 * ( Chi - znbd3 ) ; + TX_dVbs = beta * T1 * ( Ps0_dVbs - 1.0 ) ; + TX_dVds = beta * T1 * Ps0_dVds ; + TX_dVgs = beta * T1 * Ps0_dVgs ; + + FD2 = TX * TX * TX * ( 10.0 + TX * ( -15.0 + TX * 6.0 ) ) ; + T4 = TX * TX * ( 30.0 + TX * ( -60.0 + TX * 30.0 ) ) ; + + FD2_dVbs = T4 * TX_dVbs ; + FD2_dVds = T4 * TX_dVds ; + FD2_dVgs = T4 * TX_dVgs ; + } + +/*-----------------------------------------------------------* +* Modify Qn0 for zone-D2. +*-----------------*/ + + if ( Chi < znbd5 ) { + + Qn0_dVbs = FD2 * Qn0_dVbs + FD2_dVbs * Qn0 + + ( 1.0 - FD2 ) * Qn00_dVbs - FD2_dVbs * Qn00 ; + Qn0_dVds = FD2 * Qn0_dVds + FD2_dVds * Qn0 + + ( 1.0 - FD2 ) * Qn00_dVds - FD2_dVds * Qn00 ; + Qn0_dVgs = FD2 * Qn0_dVgs + FD2_dVgs * Qn0 + + ( 1.0 - FD2 ) * Qn00_dVgs - FD2_dVgs * Qn00 ; + + Qn0 = FD2 * Qn0 + ( 1.0 - FD2 ) * Qn00 ; + + if ( Qn0 < 0.0 ) { + Qn0 = 0.0 ; + Qn0_dVbs = 0.0 ; + Qn0_dVds = 0.0 ; + Qn0_dVgs = 0.0 ; + } + + } + + + +/*---------------------------------------------------* +* VgVt : Vgp - Vth_qi. ( Vth_qi is Vth for Qi evaluation. ) +*-----------------*/ + + VgVt = Qn0 * Cox_inv ; + VgVt_dVbs = Qn0_dVbs * Cox_inv + Qn0 * Cox_inv_dVbs ; + VgVt_dVds = Qn0_dVds * Cox_inv + Qn0 * Cox_inv_dVds ; + VgVt_dVgs = Qn0_dVgs * Cox_inv + Qn0 * Cox_inv_dVgs ; + +/*-----------------------------------------------------------* +* make Qi=Qd=Ids=0 if VgVt <= VgVt_small +*-----------------*/ + + + if ( VgVt <= VgVt_small ) { + + + Psl = Ps0 ; + Psl_dVbs = Ps0_dVbs ; + Psl_dVds = Ps0_dVds ; + Psl_dVgs = Ps0_dVgs ; + + Psdl = Psl ; + Psdl_dVbs = Psl_dVbs ; + Psdl_dVds = Psl_dVds ; + Psdl_dVgs = Psl_dVgs ; + + Pds = 0.0 ; + Pds_dVbs = 0.0 ; + Pds_dVds = 0.0 ; + Pds_dVgs = 0.0 ; + + T1 = - Leff * Weff ; + Qb = T1 * Qb0 ; + Qb_dVbs = T1 * Qb0_dVbs ; + Qb_dVds = T1 * Qb0_dVds ; + Qb_dVgs = T1 * Qb0_dVgs ; + + Qi = 0.0 ; + Qi_dVbs = 0.0 ; + Qi_dVds = 0.0 ; + Qi_dVgs = 0.0 ; + + Qd = 0.0 ; + Qd_dVbs = 0.0 ; + Qd_dVds = 0.0 ; + Qd_dVgs = 0.0 ; + + Ids = 0.0e0 ; + Ids_dVbs = 0.0e0 ; + Ids_dVds = 0.0e0 ; + Ids_dVgs = 0.0e0 ; + + flg_noqi = 1 ; + + goto end_of_part_1 ; + } + + + +/*-----------------------------------------------------------* +* Start point of Psl (= Ps0 + Pds) calculation. (label) +*-----------------*/ +start_of_Psl: ; + + exp_bVbsVds = exp( beta * ( Vbs - Vds ) ) ; + +/*---------------------------------------------------* +* Skip Psl calculation when Vds is very small. +*-----------------*/ + if ( Vds <= epsm10 ) { + Pds = 0.0 ; + Psl = Ps0 ; + goto end_of_loopl ; + } + +/*-----------------------------------------------------------* +* Initial guess for Pds ( = Psl - Ps0 ). +*-----------------*/ + +/*---------------------------------------------------* +* Use previous value. +*-----------------*/ + if ( flg_pprv == 1 ) { + + Pds_ini = Pds + Pds_dVbs * dVbs + + Pds_dVds * dVds + Pds_dVgs * dVgs ; + + T1 = Pds_ini - Pds ; + + if ( T1 < - dP_max || T1 > dP_max ) { + flg_pprv = 0 ; + } + + } + +/*---------------------------------------------------* +* Analytical initial guess. +*-----------------*/ + if ( flg_pprv == 0 ) { + Pds_max = Fn_Max( Psl_lim - Ps0 , 0.0e0 ); + + T1 = ( 1.0e0 + c_pslini_1 ) * Pds_max ; + T2 = T1 - Vds - c_pslini_2 ; + T3 = sqrt( T2 * T2 + 4.0e0 * T1 * c_pslini_2 ) ; + + Pds_ini = T1 - ( T2 + T3 ) / 2 ; + + Pds_ini = Fn_Min( Pds_ini , Pds_max ) ; + } + + if ( Pds_ini < 0.0 ) { + Pds_ini = 0.0 ; + } else if ( Pds_ini > Vds ) { + Pds_ini = Vds ; + } + + + +/*---------------------------------------------------* +* Assign initial guess. +*-----------------*/ + + Pds = Pds_ini ; + Psl = Ps0 + Pds ; + + +/*---------------------------------------------------* +* Calculation of Psl by solving Poisson eqn. +* (beginning of Newton loop) +* - Fsl : Fsl = 0 is the equation to be solved. +* - dPsl : correction value. +*-----------------*/ + + + for ( lp_sl = 1 ; lp_sl <= lp_sl_max ; lp_sl ++ ) { + + Chi = beta * ( Psl - Vbs ) ; + +/*-------------------------------------------* +* zone-D2. (Psl) +* - Qb0 is approximated to 5-dgree polynomial. +*-----------------*/ + + if ( Chi < znbd5 ) { + + fi = Chi * Chi * Chi + * ( cn_im53 + Chi * ( cn_im54 + Chi * cn_im55 ) ) ; + fi_dChi = Chi * Chi + * ( 3 * cn_im53 + + Chi * ( 4 * cn_im54 + Chi * 5 * cn_im55 ) ) ; + + + cfs1 = cnst1 * exp_bVbsVds ; + + fsl1 = cfs1 * fi * fi ; + fsl1_dPsl = cfs1 * beta * 2 * fi * fi_dChi ; + + + fb = Chi * ( cn_nc51 + Chi * ( cn_nc52 + + Chi * ( cn_nc53 + + Chi * ( cn_nc54 + Chi * cn_nc55 ) ) ) ) ; + fb_dChi = cn_nc51 + Chi * ( 2 * cn_nc52 + + Chi * ( 3 * cn_nc53 + + Chi * ( 4 * cn_nc54 + Chi * 5 * cn_nc55 ) ) ) ; + + + fsl2 = sqrt( fb * fb + fsl1 ) ; + + if ( fsl2 >= epsm10 ) { + fsl2_dPsl = ( beta * fb_dChi * 2 * fb + fsl1_dPsl ) + / ( fsl2 + fsl2 ) ; + } else { + fsl2 = sqrt( fb * fb + fsl1 ) ; + fsl2_dPsl = beta * fb_dChi ; + } + + Fsl = Vgp - Psl - fac1 * fsl2 ; + + Fsl_dPsl = - 1.0e0 - fac1 * fsl2_dPsl ; + + dPsl = - Fsl / Fsl_dPsl ; + +/*-------------------------------------------* +* zone-D3. (Psl) +*-----------------*/ + } else { + + Rho = beta * ( Psl - Vds ) ; + + exp_Rho = exp( Rho ) ; + + fsl1 = cnst1 * ( exp_Rho - exp_bVbsVds ) ; + fsl1_dPsl = cnst1 * beta * ( exp_Rho ) ; + + + if ( fsl1 < epsm10 * cnst1 ) { + fsl1 = 0.0 ; + fsl1_dPsl = 0.0 ; + } + + Xil = Chi - 1.0e0 ; + + Xilp12 = sqrt( Xil ) ; + + fsl2 = sqrt( Xil + fsl1 ) ; + + fsl2_dPsl = ( beta + fsl1_dPsl ) / ( fsl2 + fsl2 ) ; + + Fsl = Vgp - Psl - fac1 * fsl2 ; + + Fsl_dPsl = - 1.0e0 - fac1 * fsl2_dPsl ; + + dPsl = - Fsl / Fsl_dPsl ; + + + } + +/*-------------------------------------------* +* Update Psl . +* - cramped to Vbs if Psl < Vbs . +*-----------------*/ + + if ( fabs( dPsl ) > dP_max ) { + dPsl = fabs( dP_max ) * Fn_Sgn( dPsl ) ; + } + + Psl = Psl + dPsl ; + + if ( Psl < Vbs ) { + Psl = Vbs ; + } + +/*-------------------------------------------* +* Check convergence. +* NOTE: This condition may be too rigid. +*-----------------*/ + + if ( fabs( dPsl ) <= ps_conv && fabs( Fsl ) <= gs_conv ) { + break ; + } + + } /* end of Psl Newton loop */ + +/*-------------------------------------------* +* Procedure for diverged case. +*-----------------*/ + if ( lp_sl > lp_sl_max ) { + fprintf( stderr , + "*** warning(HiSIM): Went Over Iteration Maximum (Psl)\n" ) ; + fprintf( stderr , + " Vbse = %7.3f Vdse = %7.3f Vgse = %7.3f\n" , + Vbse , Vdse , Vgse ) ; + if ( flg_info >= 2 ) { + printf( + "*** warning(HiSIM): Went Over Iteration Maximum (Psl)\n" ) ; + } + } + + +/*---------------------------------------------------* +* End of Psl calculation. (label) +*-----------------*/ +end_of_loopl: ; + +/*---------------------------------------------------* +* Assign Pds. +*-----------------*/ + + Pds = Psl - Ps0 ; + + if ( Pds < ps_conv ) { + Pds = 0.0 ; + Psl = Ps0 ; + } + + + +/*---------------------------------------------------* +* Evaluate derivatives of Psl. +* - note: Here, fsl1_dVbs and fsl2_dVbs are derivatives +* w.r.t. explicit Vbs. So, Psl in the fsl1 and fsl2 +* expressions is regarded as a constant. +*-----------------*/ + + Chi = beta * ( Psl - Vbs ) ; + +/*-------------------------------------------* +* zone-D2. (Psl) +*-----------------*/ + + if ( Chi < znbd5 ) { + + fi = Chi * Chi * Chi + * ( cn_im53 + Chi * ( cn_im54 + Chi * cn_im55 ) ) ; + fi_dChi = Chi * Chi + * ( 3 * cn_im53 + + Chi * ( 4 * cn_im54 + Chi * 5 * cn_im55 ) ) ; + + + /*note: cfs1 = cnst1 * exp_bVbsVds */ + fsl1 = cfs1 * fi * fi ; + fsl1_dPsl = cfs1 * beta * 2 * fi * fi_dChi ; + fsl1_dVbs = cfs1 * beta * fi * ( fi - 2 * fi_dChi ) ; + fsl1_dVds = - cfs1 * beta * fi * fi ; + + + fb = Chi * ( cn_nc51 + Chi * ( cn_nc52 + + Chi * ( cn_nc53 + + Chi * ( cn_nc54 + Chi * cn_nc55 ) ) ) ) ; + fb_dChi = cn_nc51 + Chi * ( 2 * cn_nc52 + + Chi * ( 3 * cn_nc53 + + Chi * ( 4 * cn_nc54 + Chi * 5 * cn_nc55 ) ) ) ; + + fsl2 = sqrt( fb * fb + fsl1 ) ; + + T2 = 0.5 / fsl2 ; + + if ( fsl2 >= epsm10 ) { + fsl2_dPsl = ( beta * fb_dChi * 2 * fb + fsl1_dPsl ) * T2 ; + fsl2_dVbs = ( - beta * fb_dChi * 2 * fb + fsl1_dVbs ) * T2 ; + fsl2_dVds = fsl1_dVds * T2 ; + } else { + fsl2_dPsl = beta * fb_dChi ; + fsl2_dVbs = - beta * fb_dChi ; + fsl2_dVds = 0.0 ; + } + + /* memo: Fsl = Vgp - Psl - fac1 * fsl2 */ + + Fsl_dPsl = - 1.0e0 - fac1 * fsl2_dPsl ; + + Psl_dVbs = - ( Vgp_dVbs + - ( fac1 * fsl2_dVbs + fac1_dVbs * fsl2 ) + ) / Fsl_dPsl ; + Psl_dVds = - ( Vgp_dVds + - ( fac1 * fsl2_dVds + fac1_dVds * fsl2 ) + ) / Fsl_dPsl ; + Psl_dVgs = - ( Vgp_dVgs + - fac1_dVgs * fsl2 + ) / Fsl_dPsl ; + + Pds_dVbs = Psl_dVbs - Ps0_dVbs ; + Pds_dVds = Psl_dVds - Ps0_dVds ; + Pds_dVgs = Psl_dVgs - Ps0_dVgs ; + + Xil = Chi - 1.0e0 ; + + Xilp12 = sqrt( Xil ) ; + Xilp32 = Xil * Xilp12 ; + +/*-------------------------------------------* +* zone-D3. (Psl) +*-----------------*/ + } else { + + Rho = beta * ( Psl - Vds ) ; + + exp_Rho = exp( Rho ) ; + + fsl1 = cnst1 * ( exp_Rho - exp_bVbsVds ) ; + + fsl1_dPsl = cnst1 * beta * ( exp_Rho ) ; + + fsl1_dVbs = - cnst1 * beta * exp_bVbsVds ; + fsl1_dVds = - beta * fsl1 ; + + + if ( fsl1 < epsm10 * T1 ) { + fsl1 = 0.0 ; + fsl1_dPsl = 0.0 ; + fsl1_dVds = 0.0 ; + } + + + Xil = Chi - 1.0e0 ; + + Xilp12 = sqrt( Xil ) ; + Xilp32 = Xil * Xilp12 ; + + fsl2 = sqrt( Xil + fsl1 ) ; + + T2 = 0.5e0 / fsl2 ; + + fsl2_dPsl = ( beta + fsl1_dPsl ) * T2 ; + + fsl2_dVbs = ( - beta + fsl1_dVbs ) * T2 ; + fsl2_dVds = ( fsl1_dVds ) * T2 ; + + /* memo: Fsl = Vgp - Psl - fac1 * fsl2 */ + + T2 = 0.5e0 / Xilp12 ; + + Fsl_dPsl = - 1.0e0 - fac1 * fsl2_dPsl ; + + Psl_dVbs = - ( Vgp_dVbs + - ( fac1 * fsl2_dVbs + fac1_dVbs * fsl2 ) + ) / Fsl_dPsl ; + + Psl_dVds = - ( Vgp_dVds + - ( fac1 * fsl2_dVds + fac1_dVds * fsl2 ) + ) / Fsl_dPsl ; + Psl_dVgs = - ( Vgp_dVgs + - fac1_dVgs * fsl2 + ) / Fsl_dPsl ; + + Pds_dVbs = Psl_dVbs - Ps0_dVbs ; + Pds_dVds = Psl_dVds - Ps0_dVds ; + Pds_dVgs = Psl_dVgs - Ps0_dVgs ; + } + + if ( Pds < ps_conv ) { + Pds_dVbs = 0.0 ; + Pds_dVgs = 0.0 ; + Psl_dVbs = Ps0_dVbs ; + Psl_dVgs = Ps0_dVgs ; + } + + + +/*-----------------------------------------------------------* +* Evaluate Qb and Idd. +* - Eta : substantial variable of QB'/Pds and Idd/Pds. +* - note: Eta = 4 * GAMMA_{hisim_0} +*-----------------*/ + + Eta = beta * Pds / Xi0 ; + + Eta_dVbs = beta * ( Pds_dVbs - ( Ps0_dVbs - 1.0e0 ) * Eta ) + / Xi0 ; + Eta_dVds = beta * ( Pds_dVds - Ps0_dVds * Eta ) / Xi0 ; + Eta_dVgs = beta * ( Pds_dVgs - Ps0_dVgs * Eta ) / Xi0 ; + + + /* ( Eta + 1 )^n */ + Eta1 = Eta + 1.0e0 ; + Eta1p12 = sqrt( Eta1 ) ; + Eta1p32 = Eta1p12 * Eta1 ; + Eta1p52 = Eta1p32 * Eta1 ; + + /* 1 / ( ( Eta + 1 )^n + 1 ) */ + Zeta12 = 1.0e0 / ( Eta1p12 + 1.0e0 ) ; + Zeta32 = 1.0e0 / ( Eta1p32 + 1.0e0 ) ; + Zeta52 = 1.0e0 / ( Eta1p52 + 1.0e0 ) ; + +/*---------------------------------------------------* +* F00 := PS00/Pds (n=1/2) +*-----------------*/ + + F00 = Zeta12 / Xi0p12 ; + + T3 = - 0.5e0 / Xi0p32 ; + T4 = - 0.5e0 / Eta1p12 * F00 ; + + F00_dVbs = Zeta12 * ( Xi0_dVbs * T3 + Eta_dVbs * T4 ) ; + F00_dVds = Zeta12 * ( Xi0_dVds * T3 + Eta_dVds * T4 ) ; + F00_dVgs = Zeta12 * ( Xi0_dVgs * T3 + Eta_dVgs * T4 ) ; + + +/*---------------------------------------------------* +* F10 := PS10/Pds (n=3/2) +*-----------------*/ + + T1 = 3.0e0 + Eta * ( 3.0e0 + Eta ) ; + + F10 = C_2o3 * Xi0p12 * Zeta32 * T1 ; + + T2 = 3.0e0 + Eta * 2.0e0 ; + T3 = C_1o3 / Xi0p12 * T1 ; + T4 = - 1.5e0 * Eta1p12 * F10 + C_2o3 * Xi0p12 * T2 ; + + F10_dVbs = Zeta32 * ( Xi0_dVbs * T3 + Eta_dVbs * T4 ) ; + F10_dVds = Zeta32 * ( Xi0_dVds * T3 + Eta_dVds * T4 ) ; + F10_dVgs = Zeta32 * ( Xi0_dVgs * T3 + Eta_dVgs * T4 ) ; + +/*---------------------------------------------------* +* F30 := PS30/Pds (n=5/2) +*-----------------*/ + + T1 = 5e0 + + Eta * ( 10e0 + Eta * ( 10e0 + Eta * ( 5e0 + Eta ) ) ) ; + + F30 = 4e0 / ( 15e0 * beta ) * Xi0p32 * Zeta52 * T1 ; + + T2 = 10e0 + Eta * ( 20e0 + Eta * ( 15e0 + Eta * 4e0 ) ) ; + T3 = 2e0 / ( 5e0 * beta ) * Xi0p12 * T1 ; + T4 = - ( 5e0 / 2e0 ) * Eta1p32 * F30 + + 4e0 / ( 15e0 * beta ) * Xi0p32 * T2 ; + + F30_dVbs = Zeta52 * ( Xi0_dVbs * T3 + Eta_dVbs * T4 ) ; + F30_dVds = Zeta52 * ( Xi0_dVds * T3 + Eta_dVds * T4 ) ; + F30_dVgs = Zeta52 * ( Xi0_dVgs * T3 + Eta_dVgs * T4 ) ; + +/*---------------------------------------------------* +* F11 := PS11/Pds. +*-----------------*/ + + F11 = Ps0 * F10 + C_2o3 / beta * Xilp32 - F30 ; + + F11_dVbs = Ps0_dVbs * F10 + Ps0 * F10_dVbs + + ( Xi0_dVbs / beta + Pds_dVbs ) * Xilp12 + - F30_dVbs ; + F11_dVds = Ps0_dVds * F10 + Ps0 * F10_dVds + + ( Xi0_dVds / beta + Pds_dVds ) * Xilp12 + - F30_dVds ; + F11_dVgs = Ps0_dVgs * F10 + Ps0 * F10_dVgs + + ( Xi0_dVgs / beta + Pds_dVgs ) * Xilp12 + - F30_dVgs ; + +/*---------------------------------------------------* +* Fdd := Idd/Pds. +*-----------------*/ + + T1 = Vgp + 1.0e0 / beta - 0.5e0 * ( 2.0e0 * Ps0 + Pds ) ; + T2 = - F10 + F00 ; + T3 = beta * Cox ; + T4 = beta * cnst0 ; + + Fdd = T3 * T1 + T4 * T2 ; + + Fdd_dVbs = T3 * ( Vgp_dVbs - Ps0_dVbs - 0.5e0 * Pds_dVbs ) + + beta * Cox_dVbs * T1 + + T4 * ( - F10_dVbs + F00_dVbs ) ; + Fdd_dVds = T3 * ( Vgp_dVds - Ps0_dVds - 0.5e0 * Pds_dVds ) + + beta * Cox_dVds * T1 + + T4 * ( - F10_dVds + F00_dVds ) ; + Fdd_dVgs = T3 * ( Vgp_dVgs - Ps0_dVgs - 0.5e0 * Pds_dVgs ) + + beta * Cox_dVgs * T1 + + T4 * ( - F10_dVgs + F00_dVgs ) ; + +/*---------------------------------------------------* +* Q_B : bulk charge. +*-----------------*/ + + T1 = Vgp + 1.0e0 / beta ; + T2 = T1 * F10 - F11 ; + + Qbnm = cnst0 + * ( cnst0 * ( 1.5e0 - ( Xi0 + 1.0e0 ) - 0.5e0 * beta * Pds ) + + Cox * T2 ) ; + + Qbnm_dVbs = cnst0 + * ( cnst0 * ( - Xi0_dVbs - 0.5e0 * beta * Pds_dVbs ) + + Cox * ( Vgp_dVbs * F10 + T1 * F10_dVbs - F11_dVbs ) + + Cox_dVbs * T2 ) ; + Qbnm_dVds = cnst0 + * ( cnst0 * ( - Xi0_dVds - 0.5e0 * beta * Pds_dVds ) + + Cox * ( Vgp_dVds * F10 + T1 * F10_dVds - F11_dVds ) + + Cox_dVds * T2 ) ; + Qbnm_dVgs = cnst0 + * ( cnst0 * ( - Xi0_dVgs - 0.5e0 * beta * Pds_dVgs ) + + Cox * ( Vgp_dVgs * F10 + T1 * F10_dVgs - F11_dVgs ) + + Cox_dVgs * T2 ) ; + + T1 = - Weff * beta * Leff ; + + Qb = T1 * Qbnm / Fdd ; + + T2 = T1 / ( Fdd * Fdd ) ; + + Qb_dVbs = T2 * ( Fdd * Qbnm_dVbs - Qbnm * Fdd_dVbs ) ; + Qb_dVds = T2 * ( Fdd * Qbnm_dVds - Qbnm * Fdd_dVds ) ; + Qb_dVgs = T2 * ( Fdd * Qbnm_dVgs - Qbnm * Fdd_dVgs ) ; + +/*---------------------------------------------------* +* Breaking point for Qi=Qd=0. +*-----------------*/ + + if ( flg_noqi != 0 ) { + goto end_of_part_1 ; + } + +/*---------------------------------------------------* +* Idd: +*-----------------*/ + + Idd = Pds * Fdd ; + + Idd_dVbs = Pds_dVbs * Fdd + Pds * Fdd_dVbs ; + Idd_dVds = Pds_dVds * Fdd + Pds * Fdd_dVds ; + Idd_dVgs = Pds_dVgs * Fdd + Pds * Fdd_dVgs ; + + + +/*-----------------------------------------------------------* +* Channel Length Modulation. Lred: \Delta L +*-----------------*/ + + if( sIN.clm2 < epsm10 && sIN.clm3 < epsm10 ) { + + Lred = 0.0e0 ; + Lred_dVbs = 0.0e0 ; + Lred_dVds = 0.0e0 ; + Lred_dVgs = 0.0e0 ; + + Psdl = Psl ; + Psdl_dVbs = Psl_dVbs ; + Psdl_dVds = Psl_dVds ; + Psdl_dVgs = Psl_dVgs ; + + if ( Psdl > Ps0 + Vds - epsm10 ) { + Psdl = Ps0 + Vds - epsm10 ; + } + + goto end_of_CLM ; + } + + + Ec = Idd / beta / Qn0 / Leff ; + Ec_dVbs = 1.0e0 / beta / Leff + * ( Idd_dVbs / Qn0 - Idd * Qn0_dVbs / Qn0 / Qn0 ) ; + Ec_dVds = ( Idd_dVds / Qn0 - Idd * Qn0_dVds / Qn0 / Qn0 ) + / beta / Leff ; + Ec_dVgs = 1.0e0 / beta / Leff + * ( Idd_dVgs / Qn0 - Idd * Qn0_dVgs / Qn0 / Qn0 ) ; + + T2 = Vds + Ps0 ; + T2_dVbs = Ps0_dVbs ; + T2_dVds = 1.0 + Ps0_dVds ; + T2_dVgs = Ps0_dVgs ; + Aclm = sIN.clm1 ; + + Psdl = Aclm * T2 + ( 1.0e0 - Aclm ) * Psl ; + Psdl_dVbs = Aclm * T2_dVbs + ( 1.0e0 - Aclm ) * Psl_dVbs ; + Psdl_dVds = Aclm * T2_dVds + ( 1.0e0 - Aclm ) * Psl_dVds ; + Psdl_dVgs = Aclm * T2_dVgs + ( 1.0e0 - Aclm ) * Psl_dVgs ; + + if ( Psdl > Ps0 + Vds - epsm10 ) { + Psdl = Ps0 + Vds - epsm10 ; + } + T1 = sqrt( 2.0e0 * C_ESI / q_Nsub ) ; + T9 = sqrt( Psl - Vbs ) ; + Wd = T1 * T9 ; + Wd_dVbs = 0.5e0 * T1 / T9 * ( Psl_dVbs - 1.0e0 ) ; + Wd_dVds = 0.5e0 * T1 / T9 * Psl_dVds ; + Wd_dVgs = 0.5e0 * T1 / T9 * Psl_dVgs ; + + T7 = Qn0 / Wd ; + T7_dVbs = ( Qn0_dVbs / Wd - Qn0 / Wd / Wd * Wd_dVbs ) ; + T7_dVds = ( Qn0_dVds / Wd - Qn0 / Wd / Wd * Wd_dVds ) ; + T7_dVgs = ( Qn0_dVgs / Wd - Qn0 / Wd / Wd * Wd_dVgs ) ; + + T8 = Ec * Ec + 2.0e0 / C_ESI * q_Nsub * ( Psdl - Psl ) + 1.0e5 ; + T8_dVbs = 2.0e0 * Ec * Ec_dVbs + + 2.0e0 / C_ESI * q_Nsub * ( Psdl_dVbs - Psl_dVbs ) ; + T8_dVds = 2.0e0 * Ec * Ec_dVds + + 2.0e0 / C_ESI * q_Nsub * ( Psdl_dVds - Psl_dVds ) ; + T8_dVgs = 2.0e0 * Ec * Ec_dVgs + + 2.0e0 / C_ESI * q_Nsub * ( Psdl_dVgs - Psl_dVgs ) ; + + Ed = sqrt( T8 ) ; + Ed_dVbs = 0.5e0 / Ed * T8_dVbs ; + Ed_dVds = 0.5e0 / Ed * T8_dVds ; + Ed_dVgs = 0.5e0 / Ed * T8_dVgs ; + + + Lred = ( Ed - Ec ) + / ( sIN.clm2 * q_Nsub + sIN.clm3 * T7 ) * C_ESI ; + T1 = 1.0 / ( sIN.clm2 * q_Nsub + sIN.clm3 * T7 ) ; + T2 = T1 * T1 ; + Lred_dVbs = ( ( Ed_dVbs - Ec_dVbs ) * T1 + - ( Ed - Ec ) * T2 * sIN.clm3 * T7_dVbs ) * C_ESI ; + Lred_dVds = ( ( Ed_dVds - Ec_dVds ) * T1 + - ( Ed - Ec ) * T2 * sIN.clm3 * T7_dVds ) * C_ESI ; + Lred_dVgs = ( ( Ed_dVgs - Ec_dVgs ) * T1 + - ( Ed - Ec ) * T2 * sIN.clm3 * T7_dVgs ) * C_ESI ; + +/*---------------------------------------------------* +* Modify Lred for symmetry. +*-----------------*/ + + end_of_CLM2: ; + + TX = Vds / cclmmdf ; + T2 = TX * TX ; + T5 = 1.0 + T2 ; + + FMD = 1.0 - 1.0 / T5 ; + FMD_dVds = 2.0 * Vds / ( T5 * T5 * cclmmdf * cclmmdf ) ; + + T6 = Lred ; + + Lred = FMD * T6 ; + Lred_dVbs *= FMD ; + Lred_dVds = FMD_dVds * ( T6 ) + FMD * Lred_dVds ; + Lred_dVgs *= FMD ; + +/*-------------------------------------------* +* End point of CLM. (label) +*-----------------*/ +end_of_CLM: ; + + +/*---------------------------------------------------* +* preparation for Qi and Qd. +*-----------------*/ + + T1 = 2.0e0 * fac1 ; + + DtPds = T1 * ( F10 - Xi0p12 ) ; + + T2 = 2.0 * ( F10 - Xi0p12 ) ; + + DtPds_dVbs = T1 * ( F10_dVbs + - 0.5 * beta * ( Ps0_dVbs - 1.0e0 ) / Xi0p12 ) + + T2 * fac1_dVbs ; + DtPds_dVds = T1 * ( F10_dVds + - 0.5 * beta * Ps0_dVds / Xi0p12 ) + + T2 * fac1_dVds ; + DtPds_dVgs = T1 * ( F10_dVgs + - 0.5 * beta * Ps0_dVgs / Xi0p12 ) + + T2 * fac1_dVgs ; + + + Achi = Pds + DtPds ; + Achi_dVbs = Pds_dVbs + DtPds_dVbs ; + Achi_dVds = Pds_dVds + DtPds_dVds ; + Achi_dVgs = Pds_dVgs + DtPds_dVgs ; + + +/*-----------------------------------------------------------* +* Alpha : parameter to evaluate charges. +* - cramped to 0 if Alpha < 0. +*-----------------*/ + + Alpha = 1.0e0 - Achi / VgVt ; + + if ( Alpha >= 0.0e0 ) { + + Alpha_dVbs = - Achi_dVbs / VgVt + ( Achi / VgVt ) + * ( VgVt_dVbs / VgVt ) ; + Alpha_dVds = - Achi_dVds / VgVt + ( Achi / VgVt ) + * ( VgVt_dVds / VgVt ) ; + Alpha_dVgs = - Achi_dVgs / VgVt + ( Achi / VgVt ) + * ( VgVt_dVgs / VgVt ) ; + + } else { + + Alpha = 0.0e0 ; + Alpha_dVbs = 0.0e0 ; + Alpha_dVds = 0.0e0 ; + Alpha_dVgs = 0.0e0 ; + } + +/*-----------------------------------------------------------* +* Q_I : inversion charge. +*-----------------*/ + + Qinm = 1.0e0 + Alpha * ( 1.0e0 + Alpha ) ; + Qinm_dVbs = Alpha_dVbs * ( 1.0e0 + Alpha + Alpha ) ; + Qinm_dVds = Alpha_dVds * ( 1.0e0 + Alpha + Alpha ) ; + Qinm_dVgs = Alpha_dVgs * ( 1.0e0 + Alpha + Alpha ) ; + + Qidn = Fn_Max( 1.0e0 + Alpha , epsm10 ) ; + Qidn_dVbs = Alpha_dVbs ; + Qidn_dVds = Alpha_dVds ; + Qidn_dVgs = Alpha_dVgs ; + + T1 = - Weff * ( Leff - Lred ) * C_2o3 * VgVt * Qinm / Qidn ; + + Qi = T1 * Cox ; + + Qi_dVbs = Qi * ( VgVt_dVbs / VgVt + + Qinm_dVbs / Qinm - Qidn_dVbs / Qidn + - Lred_dVbs/ ( Leff - Lred ) ) + + T1 * Cox_dVbs ; + Qi_dVds = Qi * ( VgVt_dVds / VgVt + + Qinm_dVds / Qinm - Qidn_dVds / Qidn + - Lred_dVds/ ( Leff - Lred ) ) + + T1 * Cox_dVds ; + Qi_dVgs = Qi * ( VgVt_dVgs / VgVt + + Qinm_dVgs / Qinm - Qidn_dVgs / Qidn + - Lred_dVgs/ ( Leff - Lred ) ) + + T1 * Cox_dVgs ; + +/*-----------------------------------------------------------* +* Q_D : drain charge. +*-----------------*/ + + Qdnm = 0.5e0 + Alpha ; + Qdnm_dVbs = Alpha_dVbs ; + Qdnm_dVds = Alpha_dVds ; + Qdnm_dVgs = Alpha_dVgs ; + + Qddn = Qidn * Qinm ; + Qddn_dVbs = Qidn_dVbs * Qinm + Qidn * Qinm_dVbs ; + Qddn_dVds = Qidn_dVds * Qinm + Qidn * Qinm_dVds ; + Qddn_dVgs = Qidn_dVgs * Qinm + Qidn * Qinm_dVgs ; + + Quot = 0.4e0 * Qdnm / Qddn ; + Qdrat = 0.6e0 - Quot ; + + if ( Qdrat <= 0.5e0 ) { + Qdrat_dVbs = Quot * ( Qddn_dVbs / Qddn - Qdnm_dVbs / Qdnm ) ; + Qdrat_dVds = Quot * ( Qddn_dVds / Qddn - Qdnm_dVds / Qdnm ) ; + Qdrat_dVgs = Quot * ( Qddn_dVgs / Qddn - Qdnm_dVgs / Qdnm ) ; + } else { + Qdrat = 0.5e0 ; + Qdrat_dVbs = 0.0e0 ; + Qdrat_dVds = 0.0e0 ; + Qdrat_dVgs = 0.0e0 ; + } + + Qd = Qi * Qdrat ; + Qd_dVbs = Qi_dVbs * Qdrat + Qi * Qdrat_dVbs ; + Qd_dVds = Qi_dVds * Qdrat + Qi * Qdrat_dVds ; + Qd_dVgs = Qi_dVgs * Qdrat + Qi * Qdrat_dVgs ; + +/*-----------------------------------------------------------* +* Modify charges for zone-D2. +* - FD2 must be defined previously. +*-----------------*/ + + Chi = beta * ( Ps0 - Vbs ) ; + + if ( Chi < znbd5 ) { + + T1 = 1.0 / ( znbd5 - znbd3 ) ; + + TX = T1 * ( Chi - znbd3 ) ; + TX_dVbs = beta * T1 * ( Ps0_dVbs - 1.0 ) ; + TX_dVds = beta * T1 * Ps0_dVds ; + TX_dVgs = beta * T1 * Ps0_dVgs ; + + T5 = - Leff * Weff ; + + Qb_dVbs = FD2 * Qb_dVbs + FD2_dVbs * Qb + + ( 1.0 - FD2 ) * T5 * Qb0_dVbs - FD2_dVbs * T5 * Qb0 ; + Qb_dVds = FD2 * Qb_dVds + FD2_dVds * Qb + + ( 1.0 - FD2 ) * T5 * Qb0_dVds - FD2_dVds * T5 * Qb0 ; + Qb_dVgs = FD2 * Qb_dVgs + FD2_dVgs * Qb + + ( 1.0 - FD2 ) * T5 * Qb0_dVgs - FD2_dVgs * T5 * Qb0 ; + + Qb = FD2 * Qb + ( 1.0 - FD2 ) * T5 * Qb0 ; + + if ( Qb > 0.0 ) { + Qb = 0.0 ; + Qb_dVbs = 0.0 ; + Qb_dVds = 0.0 ; + Qb_dVgs = 0.0 ; + } + + Qi_dVbs = FD2 * Qi_dVbs + FD2_dVbs * Qi + + ( 1.0 - FD2 ) * T5 * Qn0_dVbs - FD2_dVbs * T5 * Qn0 ; + Qi_dVds = FD2 * Qi_dVds + FD2_dVds * Qi + + ( 1.0 - FD2 ) * T5 * Qn0_dVds - FD2_dVds * T5 * Qn0 ; + Qi_dVgs = FD2 * Qi_dVgs + FD2_dVgs * Qi + + ( 1.0 - FD2 ) * T5 * Qn0_dVgs - FD2_dVgs * T5 * Qn0 ; + + Qi = FD2 * Qi + ( 1.0 - FD2 ) * T5 * Qn0 ; + + if ( Qi > 0.0 ) { + Qi = 0.0 ; + Qi_dVbs = 0.0 ; + Qi_dVds = 0.0 ; + Qi_dVgs = 0.0 ; + } + + Qd_dVbs = FD2 * Qd_dVbs + FD2_dVbs * Qd + + ( 1.0 - FD2 ) * T5 * Qi_dVbs / 2 + - FD2_dVbs * T5 * Qi / 2 ; + Qd_dVds = FD2 * Qd_dVds + FD2_dVds * Qd + + ( 1.0 - FD2 ) * T5 * Qi_dVds / 2 + - FD2_dVds * T5 * Qi / 2 ; + Qd_dVgs = FD2 * Qd_dVgs + FD2_dVgs * Qd + + ( 1.0 - FD2 ) * T5 * Qi_dVgs / 2 + - FD2_dVgs * T5 * Qi / 2 ; + + Qd = FD2 * Qd + ( 1.0 - FD2 ) * T5 * Qi / 2 ; + + if ( Qd > 0.0 ) { + Qd = 0.0 ; + Qd_dVbs = 0.0 ; + Qd_dVds = 0.0 ; + Qd_dVgs = 0.0 ; + } + + } + + + +/*-----------------------------------------------------------* +* Modified potential for symmetry. +*-----------------*/ + + T1 = exp( - ( Vds - Pds ) / ( 2.0 * sIN.pzadd0 ) ) ; + + Pzadd = sIN.pzadd0 * T1 ; + + T2 = - 0.5 * T1 ; + + Pzadd_dVbs = T2 * ( - Pds_dVbs ) ; + Pzadd_dVds = T2 * ( 1.0 - Pds_dVds ) ; + Pzadd_dVgs = T2 * ( - Pds_dVgs ) ; + + if ( fabs ( Pzadd ) < epsm10 ) { + Pzadd = 0.0 ; + Pzadd_dVbs = 0.0 ; + Pzadd_dVds = 0.0 ; + Pzadd_dVgs = 0.0 ; + } + + + Ps0z = Ps0 + Pzadd ; + Ps0z_dVbs = Ps0_dVbs + Pzadd_dVbs ; + Ps0z_dVds = Ps0_dVds + Pzadd_dVds ; + Ps0z_dVgs = Ps0_dVgs + Pzadd_dVgs ; + + +/*-----------------------------------------------------------* +* Evaluate universal mobility. +*-----------------*/ + + Ps0Vbsz = Ps0z - Vbsz ; + Ps0Vbsz_dVbs = Ps0z_dVbs - Vbsz_dVbs ; + Ps0Vbsz_dVds = Ps0z_dVds - Vbsz_dVds ; + Ps0Vbsz_dVgs = Ps0z_dVgs ; + + +/*-------------------------------------------* +* Qbm +*-----------------*/ + + T1 = cnst0 ; + T2 = sqrt( beta * Ps0Vbsz - 1.0 ) ; + + Qbm = T1 * T2 ; + + T3 = 0.5 * beta * T1 / T2 ; + + Qbm_dVbs = T3 * Ps0Vbsz_dVbs ; + Qbm_dVds = T3 * Ps0Vbsz_dVds ; + Qbm_dVgs = T3 * Ps0Vbsz_dVgs ; + +/*-------------------------------------------* +* Qnm +*-----------------*/ + + Chi = beta * Ps0Vbsz ; + + exp_Chi = exp( Chi ) ; + + exp_bVbs = exp( beta * Vbsz ) ; + + cfs1 = cnst1 * exp_bVbs ; + + fs01 = cfs1 * ( exp_Chi - 1.0 ) ; + + /* regard fs01 as a function of Chi and Vbs */ + fs01_dChi = cfs1 * ( exp_Chi ) ; + fs01_dVbs = beta * fs01 ; + + + if ( fs01 < epsm10 * cfs1 ) { + fs01 = 0.0 ; + fs01_dPs0 = 0.0 ; + fs01_dVbs = 0.0 ; + } + + Xi0z = Chi - 1.0e0 ; + + Xi0z_dVbs = beta * Ps0Vbsz_dVbs ; + Xi0z_dVds = beta * Ps0Vbsz_dVds ; + Xi0z_dVgs = beta * Ps0Vbsz_dVgs ; + + fs02 = sqrt( Xi0z + fs01 ) ; + + T2 = 0.5e0 / fs02 ; + + /* regard fs01 as a function of Chi and Vbs */ + fs02_dChi = ( 1.0 + fs01_dChi ) * T2 ; + fs02_dVbs = fs01_dVbs * T2 ; + + Xi0zp12 = sqrt( Xi0z ) ; + + Xi0zp12_dVbs = 0.5e0 * Xi0z_dVbs / Xi0zp12 ; + Xi0zp12_dVds = 0.5e0 * Xi0z_dVds / Xi0zp12 ; + Xi0zp12_dVgs = 0.5e0 * Xi0z_dVgs / Xi0zp12 ; + + T1 = 1.0 / ( fs02 + Xi0zp12 ) ; + + Qnm = cnst0 * fs01 * T1 ; + + fs01_dVds = beta * Ps0Vbsz_dVds * fs01_dChi + + fs01_dVbs * Vbsz_dVds ; + fs01_dVbs = beta * Ps0Vbsz_dVbs * fs01_dChi + fs01_dVbs ; + fs01_dVgs = beta * Ps0Vbsz_dVgs * fs01_dChi ; + + fs02_dVds = beta * Ps0Vbsz_dVds * fs02_dChi + + fs02_dVbs * Vbsz_dVds ; + fs02_dVbs = beta * Ps0Vbsz_dVbs * fs02_dChi + fs02_dVbs ; + fs02_dVgs = beta * Ps0Vbsz_dVgs * fs02_dChi ; + + Qnm_dVbs = Qnm + * ( fs01_dVbs / fs01 + - ( fs02_dVbs + Xi0zp12_dVbs ) * T1 ) ; + Qnm_dVds = Qnm + * ( fs01_dVds / fs01 + - ( fs02_dVds + Xi0zp12_dVds ) * T1 ) ; + Qnm_dVgs = Qnm + * ( fs01_dVgs / fs01 + - ( fs02_dVgs + Xi0zp12_dVgs ) * T1 ) ; + + if ( Qbm < 0.0 ) { + Qbm = 0.0 ; + } + if ( Qnm < 0.0 ) { + Qnm = 0.0 ; + } + + + +/*---------------------------------------------------* +* Muun : universal mobility. +*-----------------*/ + + /* removed Eqs. "Qbm = Qb0", "Qnm = Qn0", ... (4/Dec/01) */ + + T1 = sIN.ninv - sIN.ninvd * Vdsz ; + T1_dVds = - sIN.ninvd * Vdsz_dVds ; + + Eeff = ( sIN.ndep * Qbm + T1 * Qnm ) / C_ESI ; + Eeff_dVbs = ( sIN.ndep * Qbm_dVbs + T1 * Qnm_dVbs ) + / C_ESI ; + Eeff_dVds = ( sIN.ndep * Qbm_dVds + T1 * Qnm_dVds + + T1_dVds * Qnm ) + / C_ESI ; + Eeff_dVgs = ( sIN.ndep * Qbm_dVgs + T1 * Qnm_dVgs ) + / C_ESI ; + + Rns = Qnm / C_QE ; + + T10 = pow( sIN.temp / C_T300 , sIN.muetmp ) ; + T21 = pow( Eeff , sIN.mueph0 - 1.0e0 ) ; + T20 = T21 * Eeff ; + T31 = pow( Eeff , sIN.muesr0 - 1.0e0 ) ; + T30 = T31 * Eeff ; + + T1 = 1e0 / ( sIN.muecb0 + sIN.muecb1 * Rns / 1e11 ) + + T10 + * T20 / mueph + + T30 / sIN.muesr1 ; + + Muun = 1e0 / T1 ; + + T1 = 1e0 / ( T1 * T1 ) ; + T2 = sIN.muecb0 + sIN.muecb1 * Rns / 1e11 ; + T2 = 1e0 / ( T2 * T2 ) ; + T3 = T10 * sIN.mueph0 * T21 / mueph ; + T4 = sIN.muesr0 * T31 / sIN.muesr1 ; + + Muun_dVbs = - 1 * ( - 1e-11 * sIN.muecb1 * Qnm_dVbs / C_QE * T2 + + Eeff_dVbs * T3 + + Eeff_dVbs * T4 ) + * T1 ; + Muun_dVds = - 1 * ( - 1e-11 * sIN.muecb1 * Qnm_dVds / C_QE * T2 + + Eeff_dVds * T3 + + Eeff_dVds * T4 ) + * T1 ; + Muun_dVgs = - 1 * ( - 1e-11 * sIN.muecb1 * Qnm_dVgs / C_QE * T2 + + Eeff_dVgs * T3 + + Eeff_dVgs * T4 ) + * T1 ; + + +/*-----------------------------------------------------------* +* Mu : mobility +*-----------------*/ + + T1 = 1.0e0 / beta / ( Qn0 + small ) / ( Leff - Lred ) ; + T1_dVbs = 1.0e0 / beta * ( - Qn0_dVbs / ( Qn0 + small ) + / ( Qn0 + small ) / ( Leff - Lred ) + + Lred_dVbs / ( Qn0 + small ) / ( Leff - Lred ) + / ( Leff - Lred ) ) ; + T1_dVds = 1.0e0 / beta * ( - Qn0_dVds / ( Qn0 + small ) + / ( Qn0 + small ) / ( Leff - Lred ) + + Lred_dVds / ( Qn0 + small ) / ( Leff - Lred ) + / ( Leff - Lred ) ) ; + T1_dVgs = 1.0e0 / beta * ( - Qn0_dVgs / ( Qn0 + small ) + / ( Qn0 + small ) / ( Leff - Lred ) + + Lred_dVgs / ( Qn0 + small ) / ( Leff - Lred ) + / ( Leff - Lred ) ) ; + + Ey = Idd * T1 ; + Ey_dVbs = Idd_dVbs * T1 + Idd * T1_dVbs ; + Ey_dVds = Idd_dVds * T1 + Idd * T1_dVds ; + Ey_dVgs = Idd_dVgs * T1 + Idd * T1_dVgs ; + + + Em = Muun * Ey ; + Em_dVbs = Muun_dVbs * Ey + Muun * Ey_dVbs ; + Em_dVds = Muun_dVds * Ey + Muun * Ey_dVds ; + Em_dVgs = Muun_dVgs * Ey + Muun * Ey_dVgs ; + + T1 = sIN.temp / C_T300 ; + + Vmax = sIN.vmax / ( 1.8 + 0.4 * T1 + 0.1 * T1 * T1 ) ; + + T2 = 1.0 - sIN.vover / pow( Lgate , sIN.voverp ) ; + + if ( T2 < 0.01 ) { + fprintf( stderr , + "*** warning(HiSIM): Overshoot is too big.\n" ) ; + T2 = 0.01 ; + } + + Vmax = Vmax / T2 ; + + T1 = Em / Vmax ; + + /* note: sIN.bb = 2 (electron) ;1 (hole) */ + if ( 1.0e0 - epsm10 <= sIN.bb && sIN.bb <= 1.0e0 + epsm10 ) { + T3 = 1.0e0 ; + } else if ( 2.0e0 - epsm10 <= sIN.bb + && sIN.bb <= 2.0e0 + epsm10 ) { + T3 = T1 ; + } else { + T3 = pow( T1 , sIN.bb - 1.0e0 ) ; + } + T2 = T1 * T3 ; + T4 = 1.0e0 + T2 ; + T6 = pow( T4 , ( - 1.0e0 / sIN.bb - 1.0e0 ) ) ; + T5 = T4 * T6 ; + + Mu = Muun * T5 ; + Mu_dVbs = Muun_dVbs * T5 - Muun / Vmax * T6 * T3 * Em_dVbs ; + Mu_dVds = Muun_dVds * T5 - Muun / Vmax * T6 * T3 * Em_dVds ; + Mu_dVgs = Muun_dVgs * T5 - Muun / Vmax * T6 * T3 * Em_dVgs ; + + +end_of_mobility : ; + +/*-----------------------------------------------------------* +* Ids: channel current. +*-----------------*/ + + + T1 = Weff / beta / ( Leff - Lred ) ; + T1_dVbs = T1 / ( Leff - Lred ) * Lred_dVbs ; + T1_dVds = T1 / ( Leff - Lred ) * Lred_dVds ; + T1_dVgs = T1 / ( Leff - Lred ) * Lred_dVgs ; + + Ids0 = T1 * Idd * Mu ; + Ids0_dVbs = T1 * ( Mu * Idd_dVbs + Idd * Mu_dVbs ) + + T1_dVbs * Mu * Idd ; + Ids0_dVds = T1 * ( Mu * Idd_dVds + Idd * Mu_dVds ) + + T1_dVds * Mu * Idd ; + Ids0_dVgs = T1 * ( Mu * Idd_dVgs + Idd * Mu_dVgs ) + + T1_dVgs * Mu * Idd ; + + T1 = Vdsz + sIN.rpock2 ; + T2 = T1 * T1 + small ; + T2_dVbs = 0.0e0 ; + T2_dVds = 2.0 * T1 * Vdsz_dVds ; + T2_dVgs = 0.0e0 ; + + rp1 = FMD * sIN.rpock1 ; + rp1_dVds = FMD_dVds * sIN.rpock1 ; + + TX = pow( Ids0, sIN.rpocp1 ) * pow( Leff / 1.0e-4 , sIN.rpocp2 ) / Weff ; + T3 = rp1 * TX ; + T4 = ( T3 + T2 ) * ( T3 + T2 ); + + Ids = Ids0 / ( 1.0 + T3 / T2 ) ; + + T5 = T2 * ( T2 - ( sIN.rpocp1 - 1.0 ) * T3 ) / T4 ; + T6 = Ids0 * T3 / T4 ; + + Ids_dVbs = T5 * Ids0_dVbs + T6 * T2_dVbs ; + Ids_dVds = T5 * Ids0_dVds + T6 * T2_dVds + - Ids0 * T2 / T4 * rp1_dVds * TX ; + Ids_dVgs = T5 * Ids0_dVgs + T6 * T2_dVgs ; + + if ( Pds < ps_conv ) { + Ids_dVbs = 0.0 ; + Ids_dVgs = 0.0 ; + } + + Ids += Gdsmin * Vds ; + Ids_dVds += Gdsmin ; + +/*-----------------------------------------------------------* +* STI +*-----------------*/ + if ( sIN.coisti == 0 ) { + goto end_of_STI ; + } + + Vth_dVbs = Vthp_dVbs - dVth_dVbs ; + Vth_dVds = Vthp_dVds - dVth_dVds ; + Vth_dVbs = Vthp_dVgs - dVth_dVgs ; + + Vgssti = Vgs - Vfb + Vth * sIN.wvthsc; + Vgssti_dVbs = Vth_dVbs * sIN.wvthsc; + Vgssti_dVds = Vth_dVds * sIN.wvthsc; + Vgssti_dVgs = 1.0e0 + Vth_dVgs * sIN.wvthsc; + + costi0 = sqrt (2.0e0 * C_QE * sIN.nsti * C_ESI / beta); + costi1 = Nin * Nin / sIN.nsti / sIN.nsti ; + costi3 = costi0 * costi0 / Cox / Cox ; + costi4 = costi3 * beta / 2.0e0 ; + costi5 = costi4 * beta * 2.0e0 ; + costi6 = sqrt(1.0e0 + + 4.0e0 * (beta * (Vgssti - Vbs)-1.0e0) /costi5) ; + + Psasti = Vgssti + costi4 * (1.0e0 - costi6) ; + + Psasti_dVbs = Vgssti_dVbs - (Vgssti_dVbs - 1.0e0)/costi6 ; + Psasti_dVds = Vgssti_dVds - Vgssti_dVds/costi6 ; + Psasti_dVgs = Vgssti_dVgs - Vgssti_dVgs/costi6 ; + + Asti = 1.0e0 / costi1 / costi3 ; + Psbsti = log(Asti * (Vgssti*Vgssti)) / (beta + 2.0e0 / Vgssti) ; + + Psbsti_dVbs = 2.0e0 / (beta*Vgssti + 2.0e0) + * (1.0e0 + Psbsti/Vgssti) * Vgssti_dVbs ; + Psbsti_dVds = 2.0e0 / (beta*Vgssti + 2.0e0) + * (1.0e0 + Psbsti/Vgssti) * Vgssti_dVds ; + Psbsti_dVgs = 2.0e0 / (beta*Vgssti + 2.0e0) + * (1.0e0 + Psbsti/Vgssti) * Vgssti_dVgs ; + + Psab = Psbsti - Psasti - sti2_dlt ; + + Psab_dVbs = Psbsti_dVbs - Psasti_dVbs ; + Psab_dVds = Psbsti_dVds - Psasti_dVds ; + Psab_dVgs = Psbsti_dVgs - Psasti_dVgs ; + + Psti = Psbsti - 0.5e0 * (Psab + + sqrt(Psab * Psab + 4.0e0 * sti2_dlt * Psbsti)) ; + + Psti_dVbs = Psbsti_dVbs - 0.5e0 * Psab_dVbs + - (Psab * Psab_dVbs +2.0e0 * sti2_dlt * Psbsti_dVbs) + * 0.5e0 / sqrt(Psab * Psab + 4.0e0 * sti2_dlt * Psbsti) ; + Psti_dVds = Psbsti_dVds - 0.5e0 * Psab_dVds + - (Psab * Psab_dVds +2.0e0 * sti2_dlt * Psbsti_dVds) + * 0.5e0 / sqrt(Psab * Psab + 4.0e0 * sti2_dlt * Psbsti) ; + Psti_dVgs = Psbsti_dVgs - 0.5e0 * Psab_dVgs + - (Psab * Psab_dVgs +2.0e0 * sti2_dlt * Psbsti_dVgs) + * 0.5e0 / sqrt(Psab * Psab + 4.0e0 * sti2_dlt * Psbsti) ; + + expsti = exp(beta * Psti) ; + sq1sti = sqrt(beta * (Psti - Vbs) - 1.0e0 +costi1 * expsti) ; + + sq1sti_dVbs = 0.50e0 * (beta * (Psti_dVbs - 1.0e0) + + costi1 * beta * Psti_dVbs * expsti) / sq1sti ; + sq1sti_dVds = 0.50e0 * (beta * Psti_dVds + + costi1 * beta * Psti_dVds * expsti) / sq1sti ; + sq1sti_dVgs = 0.50e0 * (beta * Psti_dVgs + + costi1 * beta * Psti_dVgs * expsti) / sq1sti ; + + sq2sti = sqrt(beta * (Psti - Vbs) - 1.0e0) ; + + sq2sti_dVbs = 0.50e0 * beta *(Psti_dVbs - 1.0e0) / sq2sti ; + sq2sti_dVds = 0.50e0 * beta *Psti_dVds / sq2sti ; + sq2sti_dVgs = 0.50e0 * beta *Psti_dVgs / sq2sti ; + + Qn0sti = costi0 * (sq1sti - sq2sti) ; + Qn0sti_dVbs = costi0 * (sq1sti_dVbs-sq2sti_dVbs) ; + Qn0sti_dVds = costi0 * (sq1sti_dVds-sq2sti_dVds) ; + Qn0sti_dVgs = costi0 * (sq1sti_dVgs-sq2sti_dVgs) ; + + costi7 = 2.0e0 * sIN.wsti / beta ; + Idssti = costi7 * Mu * Qn0sti * (1.0e0 - exp(-beta * Vds)) + / (Leff - Lred) ; + + Idssti_dVbs = costi7 * (( Mu_dVbs * Qn0sti + Mu * Qn0sti_dVbs ) + * ( 1.0e0 - exp( - beta * Vds )) + + Lred_dVbs * Mu * Qn0sti * ( 1.0e0 - exp( - beta * Vds )) + / ( Leff - Lred )) ; + Idssti_dVds = costi7 * (( Mu_dVds * Qn0sti + Mu * Qn0sti_dVds + + beta * Mu * Qn0sti ) * ( 1.0e0 - exp( - beta * Vds )) + + Lred_dVds * Mu * Qn0sti * ( 1.0e0 - exp( - beta * Vds )) + / ( Leff - Lred )) ; + Idssti_dVgs = costi7 * (( Mu_dVgs * Qn0sti + Mu * Qn0sti_dVgs ) + * ( 1.0e0 - exp( - beta * Vds )) + + Lred_dVgs * Mu * Qn0sti * ( 1.0e0 - exp( - beta * Vds )) + / ( Leff - Lred )) ; + + Ids = Ids + Idssti ; + + Ids_dVbs = Ids_dVbs + Idssti_dVbs ; + Ids_dVds = Ids_dVds + Idssti_dVds ; + Ids_dVgs = Ids_dVgs + Idssti_dVgs ; + end_of_STI: ; + + +/*-----------------------------------------------------------* +* Break point for the case of Rs=Rd=0. +*-----------------*/ + + if ( flg_rsrd == 0 ) { + DJI = 1.0 ; + break ; + } + + + +/*-----------------------------------------------------------* +* calculate corrections of biases. +* - Fbs = 0, etc. are the small ciucuit equations. +* - DJ, Jacobian of the small circuit matrix, is g.t. 1 +* provided Rs, Rd and conductances are positive. +*-----------------*/ + + Fbs = Vbs - Vbsc + Ids * Rs ; + Fds = Vds - Vdsc + Ids * ( Rs + Rd ) ; + Fgs = Vgs - Vgsc + Ids * Rs ; + + DJ = 1.0 + Rs * Ids_dVbs + ( Rs + Rd ) * Ids_dVds + Rs * Ids_dVgs ; + DJI = 1.0 / DJ ; + + JI11 = 1 + ( Rs + Rd ) * Ids_dVds + Rs * Ids_dVgs ; + JI12 = - Rs * Ids_dVds ; + JI13 = - Rs * Ids_dVgs ; + JI21 = - ( Rs + Rd ) * Ids_dVbs ; + JI22 = 1 + Rs * Ids_dVbs + Rs * Ids_dVgs ; + JI23 = - ( Rs + Rd ) * Ids_dVgs ; + JI31 = - Rs * Ids_dVbs ; + JI32 = - Rs * Ids_dVds ; + JI33 = 1 + Rs * Ids_dVbs + ( Rs + Rd ) * Ids_dVds ; + + dVbs = - DJI * ( JI11 * Fbs + JI12 * Fds + JI13 * Fgs ) ; + dVds = - DJI * ( JI21 * Fbs + JI22 * Fds + JI23 * Fgs ) ; + dVgs = - DJI * ( JI31 * Fbs + JI32 * Fds + JI33 * Fgs ) ; + + dV_sum = fabs( dVbs ) + fabs( dVds ) + fabs( dVgs ) ; + + +/*-----------------------------------------------------------* +* Break point for converged case. +* - Exit from the bias loop. +* - NOTE: Update of internal biases is avoided. +*-----------------*/ + + + if ( Ids_last * Ids_tol >= fabs( Ids_last - Ids ) || + dV_sum < ps_conv ) { + break ; + } + +/*-----------------------------------------------------------* +* Update the internal biases. +*-----------------*/ + + Vbs = Vbs + dVbs ; + Vds = Vds + dVds ; + Vgs = Vgs + dVgs ; + + if ( Vds < 0.0 ) { + Vds = 0.0 ; + dVds = 0.0 ; + } + +/*-----------------------------------------------------------* +* Bottom of bias loop. (label) +*-----------------*/ +bottom_of_bias_loop : ; + + + +/*-----------------------------------------------------------* +* Make initial guess flag of potential ON. +* - This effects for the 2nd and later iterations of bias loop. +*-----------------*/ + flg_pprv = 1 ; + + } /*++ End of the bias loop +++++++++++++++++++++++++++++*/ + + if ( lp_bs > lp_bs_max ) { lp_bs -- ; } + + +/*-----------------------------------------------------------* +* End of PART-1. (label) +*-----------------*/ +end_of_part_1: ; + + + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +* PART-2: Substrate / gate / leak currents +*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + +/*-----------------------------------------------------------* +* Isub : substrate current induced by impact ionization. +*-----------------*/ +/*-------------------------------------------* +* Accumulation zone or nonconductive case, in which Ids==0. +*-----------------*/ + + if ( Ids <= 0.0e0 || sIN.coisub == 0 ) { + Isub = 0.0e0 ; + Isub_dVbs = 0.0e0 ; + Isub_dVds = 0.0e0 ; + Isub_dVgs = 0.0e0 ; + goto end_of_Isub ; + } + +/*-------------------------------------------* +* Conductive case. +*-----------------*/ + + if ( sIN.sub1 > 0.0e0 && sIN.vmax > 0.0e0 ) { + + Vdep = Vds + Ps0 - sIN.sub3 * Psl ; + Vdep_dVbs = Ps0_dVbs - sIN.sub3 * Psl_dVbs ; + Vdep_dVds = 1.0e0 + Ps0_dVds - sIN.sub3 * Psl_dVds ; + Vdep_dVgs = Ps0_dVgs - sIN.sub3 * Psl_dVgs ; + + TX = - sIN.sub2 / Vdep ; + + Epkf = exp( TX ) ; + Epkf_dVbs = - TX * Vdep_dVbs / Vdep * Epkf ; + Epkf_dVds = - TX * Vdep_dVds / Vdep * Epkf ; + Epkf_dVgs = - TX * Vdep_dVgs / Vdep * Epkf ; + + T1 = Ids * Epkf ; + T1_dVbs = Ids_dVbs * Epkf + Ids * Epkf_dVbs ; + T1_dVds = Ids_dVds * Epkf + Ids * Epkf_dVds ; + T1_dVgs = Ids_dVgs * Epkf + Ids * Epkf_dVgs ; + + if( T1 < 1.0e-25 ){ + T1 = 1.0e-25 ; + T1_dVbs = 0.0e0 ; + T1_dVds = 0.0e0 ; + T1_dVgs = 0.0e0 ; + } + + Isub = sIN.sub1 * Vdep * T1 ; + Isub_dVbs = sIN.sub1 * ( Vdep_dVbs * T1 + Vdep * T1_dVbs ) ; + Isub_dVds = sIN.sub1 * ( Vdep_dVds * T1 + Vdep * T1_dVds ) ; + Isub_dVgs = sIN.sub1 * ( Vdep_dVgs * T1 + Vdep * T1_dVgs ) ; + + } else { + + Isub = 0.0e0 ; + Isub_dVbs = 0.0e0 ; + Isub_dVds = 0.0e0 ; + Isub_dVgs = 0.0e0 ; + + } /* end of if ( sIN.sub1 ... ) else block. */ + +/*-------------------------------------------* +* End of Isub. (label) +*-----------------*/ +end_of_Isub: ; + +/*-----------------------------------------------------------* +* Igs : Gate current induced by tunneling. +* - Vzadd is used for symmetrizing. +*-----------------*/ + + Egp12 = sqrt( Eg ) ; + Egp32 = Eg * Egp12 ; + + if ( sIN.coiigs == 0 ) { + Igs = 0.0e0 ; + Igs_dVbs = 0.0e0 ; + Igs_dVds = 0.0e0 ; + Igs_dVgs = 0.0e0 ; + goto end_of_Igs ; + } + + Vgpz = Vgp + Vzadd ; + + Vgpz_dVbs = Vgp_dVbs ; + Vgpz_dVds = Vgp_dVds + Vzadd_dVds ; + Vgpz_dVgs = Vgp_dVgs ; + + T1 = Vgpz - ( Psl + Ps0 + 2.0 * Vzadd ) * sIN.gleak3 ; + + E0 = 10.0 ; + + E2 = T1 / Tox ; + + E2_dVbs = E2 + * ( ( Vgpz_dVbs - ( Psl_dVbs + Ps0_dVbs ) * sIN.gleak3 ) + / T1 + - Tox_dVbs / Tox ) ; + E2_dVds = E2 + * ( ( Vgpz_dVds + - ( Psl_dVds + Ps0_dVds + 2.0 * Vzadd_dVds ) + * sIN.gleak3 + ) / T1 + - Tox_dVds / Tox ) ; + E2_dVgs = E2 + * ( ( Vgpz_dVgs - ( Psl_dVgs + Ps0_dVgs ) * sIN.gleak3 ) + / T1 + - Tox_dVgs / Tox ) ; + + T1 = E2 - E0 - eef_dlt ; + T2 = T1 * T1 ; + + T3 = sqrt( T2 + 4.0 * eef_dlt * E2 ) ; + + Etun = E2 - ( T1 - T3 ) / 2 ; + + T4 = 1.0 / ( 4.0 * T3 ) ; + T5 = 2.0 * T1 * T4 + 0.5 ; + + Etun_dVbs = T5 * E2_dVbs ; + Etun_dVds = T5 * E2_dVds ; + Etun_dVgs = T5 * E2_dVgs ; + + T1 = exp( - sIN.gleak2 * Egp32 / Etun ) ; + + T2 = sIN.gleak1 / Egp12 * C_QE * Weff * Leff ; + + Igs = T2 * Etun * Etun * T1 ; + + T3 = T2 * T1 * ( 2.0 * Etun + sIN.gleak2 * Egp32 ) ; + + Igs_dVbs = T3 * Etun_dVbs ; + Igs_dVds = T3 * Etun_dVds ; + Igs_dVgs = T3 * Etun_dVgs ; + + end_of_Igs: ; + +/*-----------------------------------------------------------* +* Ilg : GIDL +*-----------------*/ + + if ( sIN.cogidl == 0 ) { + Ilg = 0.0e0 ; + Ilg_dVbs = 0.0e0 ; + Ilg_dVds = 0.0e0 ; + Ilg_dVgs = 0.0e0 ; + goto end_of_IGIDL ; + } + + T1 = sIN.gidl3 * Vdsz - Vgsz + dVth ; + + E1 = T1 / Tox ; + + E1_dVbs = E1 * ( dVth_dVbs / T1 - Tox_dVbs / Tox ) ; + E1_dVds = E1 * ( ( sIN.gidl3 * Vdsz_dVds - Vgsz_dVds + dVth_dVds ) + / T1 + - Tox_dVds / Tox ) ; + E1_dVgs = E1 * ( ( -1.0 + dVth_dVgs ) / T1 - Tox_dVgs / Tox ) ; + + T1 = E0 - E1 - eef_dlt ; + T2 = T1 * T1 ; + + T3 = sqrt( T2 + 4.0 * eef_dlt * E0 ) ; + + Egidl = E0 - ( T1 - T3 ) / 2 ; + + T4 = 1.0 / ( 4.0 * T3 ) ; + T5 = - 2.0 * T1 * T4 + 0.5 ; + + Egidl_dVbs = T5 * E1_dVbs ; + Egidl_dVds = T5 * E1_dVds ; + Egidl_dVgs = T5 * E1_dVgs ; + + T1 = exp( - sIN.gidl2 * Egp32 / Egidl ) ; + + T2 = sIN.gidl1 / Egp12 * C_QE * Weff ; + + Ilg = T2 * Egidl * Egidl * T1 ; + + T3 = T2 * T1 * ( 2.0 * Egidl + sIN.gidl2 * Egp32 ) ; + + Ilg_dVbs = T3 * Egidl_dVbs ; + Ilg_dVds = T3 * Egidl_dVds ; + Ilg_dVgs = T3 * Egidl_dVgs ; + + end_of_IGIDL: ; + +/*-----------------------------------------------------------* +* End of PART-2. (label) +*-----------------*/ +end_of_part_2: ; + + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +* PART-3: Overlap charge +*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + + +/*-------------------------------------------* +* Calculation of Psdl for cases of flg_noqi==1. +*-----------------*/ + + if ( flg_noqi != 0 ) { + + T2 = Vds + Ps0 ; + T2_dVbs = Ps0_dVbs ; + T2_dVds = 1.0e0 + Ps0_dVds ; + T2_dVgs = Ps0_dVgs ; + + Aclm = sIN.clm1 ; + + Psdl = Aclm * T2 + ( 1.0e0 - Aclm ) * Psl ; + Psdl_dVbs = Aclm * T2_dVbs + ( 1.0e0 - Aclm ) * Psl_dVbs ; + Psdl_dVds = Aclm * T2_dVds + ( 1.0e0 - Aclm ) * Psl_dVds ; + Psdl_dVgs = Aclm * T2_dVgs + ( 1.0e0 - Aclm ) * Psl_dVgs ; + + Ec = 0.0e0 ; + Ec_dVbs =0.0e0 ; + Ec_dVds =0.0e0 ; + Ec_dVgs =0.0e0 ; + + T1 = sqrt( 2.0e0 * C_ESI / q_Nsub ) ; + + if ( Psl - Vbs > 0 ){ + T9 = sqrt( Psl - Vbs ) ; + Wd = T1 * T9 ; + Wd_dVbs = 0.5e0 * T1 / T9 * ( Psl_dVbs - 1.0e0 ) ; + Wd_dVds = 0.5e0 * T1 / T9 * Psl_dVds ; + Wd_dVgs = 0.5e0 * T1 / T9 * Psl_dVgs ; + }else{ + Wd = 0e0 ; + Wd_dVbs = 0e0 ; + Wd_dVds = 0e0 ; + Wd_dVgs = 0e0 ; + } + + if ( Psdl > Ps0 + Vds - epsm10 ) { + Psdl = Ps0 + Vds - epsm10 ; + } + } + + +/*-------------------------------------------* +* Overlap charge (simple, default, CLM1 < 1.0) <-- changed 04/Dec/01 +* (orig. "CLM1 must be 1.0") +*-----------------*/ + if ( sIN.coovlp == 0 ){ + + T1 = Cox * Weff ; + Lov = sIN.xld + sIN.xpolyd ; + Qgos = Vgs * Lov * T1 ; + Qgos_dVbs = 0.0e0 ; + Qgos_dVds = 0.0e0 ; + Qgos_dVgs = Lov * T1 ; + + T2 = - 1.0e+11 ; + yn = sqrt ( ( Psdl - Ps0 - Vds) / T2 ) ; + yn2 = yn * yn ; + yn3 = yn2 * yn ; + + + if ( yn <= Lov ){ + Qgod = ( ( Vgs - Vds ) * Lov - T2 * yn3 / 3.0e0 ) * T1 ; + Qgod_dVbs = ( (-0.5e0) * yn * ( Psdl_dVbs - Ps0_dVbs ) ) * T1 ; + Qgod_dVds = ( (-1.0e0) * Lov - 0.5e0 * yn + * ( Psdl_dVds - Ps0_dVds - 1.0e0 ) ) * T1 ; + Qgod_dVgs = ( Lov - 0.5e0 * yn * ( Psdl_dVgs - Ps0_dVgs ) ) * T1 ; + }else{ + T3 = 0.5e0 / yn / T2 ; + yn_dVbs = T3 * ( Psdl_dVbs - Ps0_dVbs ) ; + yn_dVds = T3 * ( Psdl_dVds - Ps0_dVds - 1.0e0 ) ; + yn_dVgs = T3 * ( Psdl_dVgs - Ps0_dVgs ) ; + + T4 = (Lov - yn ) * (Lov - yn ) ; + T5 = T4 * (Lov - yn ) ; + Qgod = ( ( Vgs - Vds ) * Lov - T2 / 3.0e0 * ( T5 + yn3 ) ) * T1 ; + Qgod_dVbs = ( (-1.0e0) * T2 * yn2 * yn_dVbs + + T2 * T4 * yn_dVbs ) * T1; + Qgod_dVds = ( (-1.0e0) * Lov - T2 * yn2 * yn_dVds + + T2 * T4 * yn_dVds ) * T1; + Qgod_dVgs = ( Lov - T2 * yn2 * yn_dVgs + + T2 * T4 * yn_dVgs ) * T1; + } + } +/*-------------------------------------------* +* Overlap charge (complete) +*-----------------*/ + + else if( sIN.coovlp > 0 ){ + + T1 = Cox * Weff ; + + Qgos = Vgs * ( sIN.xld + sIN.xpolyd ) * T1 ; + Qgos_dVbs = 0.0e0 ; + Qgos_dVds = 0.0e0 ; + Qgos_dVgs = ( sIN.xld + sIN.xpolyd ) * T1 ; + + T3 = 1e21 / pow( sIN.xld + sIN.xpolyd , 3e0) ; + T1 = C_QE * T3 / ( C_ESI * 4e0 ) ; + T2 = Cox * Weff ; + + Lov = sIN.xld + sIN.xpolyd ; + Lov2 = Lov * Lov ; + + yn = pow( C_ESI * 5e0 / ( C_QE * T3 ) + * ( Ps0 + Vds - Psdl ) + , 0.2e0 ) ; + yn2 = yn * yn ; + + if ( yn < Lov ) { + Qgod = ( ( Vgs - Vds ) * ( sIN.xld + sIN.xpolyd ) + + T1 / 3e0 * yn2 * yn2 * yn2 ) * T2 ; + Qgod_dVbs = ( yn / 2e0 * ( Ps0_dVbs - Psdl_dVbs ) ) * T2 ; + Qgod_dVds = ( - 1e0 * ( sIN.xld + sIN.xpolyd ) + + yn / 2e0 * ( Ps0_dVds + 1e0 - Psdl_dVds ) ) * T2 ; + Qgod_dVgs = ( 1e0 * ( sIN.xld + sIN.xpolyd ) + + yn / 2e0 * ( Ps0_dVgs - Psdl_dVgs ) ) * T2 ; + } else { + T3 = C_ESI * 5e0 / ( C_QE * T3 ) ; + + Qgod = ( ( Vgs + T1 * 4e0 / 5e0 * yn2 * yn2 * yn - Vds ) * Lov + + T1 / 30e0 * Lov2 * Lov2 * Lov2 + - T1 * yn2 * yn2 / 2e0 * Lov2 ) * T2 ; + Qgod_dVbs = ( ( T1 * 4e0 / 5e0 * T3 * ( Ps0_dVbs - Psdl_dVbs ) ) * Lov + - 2e0 * T1 / 5e0 * T3 / yn * ( Ps0_dVbs - Psdl_dVbs ) * Lov2 ) + * T2 ; + Qgod_dVds = ( ( T1 * 4e0 / 5e0 * T3 * ( Ps0_dVds + 1e0 - Psdl_dVds ) - 1e0 ) + * Lov + - 2e0 * T1 / 5e0 * T3 / yn * ( Ps0_dVds + 1e0 - Psdl_dVds ) + * Lov2 ) * T2 ; + Qgod_dVgs = ( ( 1e0 + T1 * 4e0 / 5e0 * T3 * ( Ps0_dVgs - Psdl_dVgs ) ) * Lov + - 2e0 * T1 / 5e0 * T3 / yn * ( Ps0_dVgs - Psdl_dVgs ) * Lov2 ) + * T2 ; + } + } + +/*-------------------------------------------* +* Overlap charge (off) +*-----------------*/ + + else if( sIN.coovlp < 0 ){ + + Qgos = 0.0e0 ; + Qgos_dVbs = 0.0e0 ; + Qgos_dVds = 0.0e0 ; + Qgos_dVgs = 0.0e0 ; + + Qgod = 0.0e0 ; + Qgod_dVbs = 0.0e0 ; + Qgod_dVds = 0.0e0 ; + Qgod_dVgs = 0.0e0 ; + + } + +/*-----------------------------------------------------------* +* End of PART-3. (label) +*-----------------*/ +end_of_part_3: ; + + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +* PART-4: Substrate-source/drain junction diode. +*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + + + +/*-----------------------------------------------------------* +* Cbsj, Cbdj: node-base S/D biases. +*-----------------*/ + + if (sIN.mode == HiSIM_NORMAL_MODE ){ + Vbdj = Vbde ; + Vbsj = Vbse ; + } else { + Vbdj = Vbse ; + Vbsj = Vbde ; + } + + /* Vbdc = Vbsc - Vdsc ;*/ + + js = sIN.js0 * exp( ( Eg300 * C_b300 - Eg * beta + + sIN.xti * log( sIN.temp / C_T300 ) ) / sIN.nj ) ; + jssw = sIN.js0sw * exp( ( Eg300 * C_b300 - Eg * beta + + sIN.xti * log( sIN.temp / C_T300 ) ) + / sIN.njsw ) ; + + Nvtm = sIN.nj / beta ; + + + /* ibd */ + isbd = sIN.ad * js + sIN.pd * jssw ; + + if ( Vbdj < 0.5 ) { + Ibd = isbd * ( exp( Vbdj / Nvtm ) - 1 ) ; + Gbd = isbd / Nvtm * exp( Vbdj / Nvtm ) ; + + } else { + Ibd = isbd * ( exp( 0.5 / Nvtm ) - 1 ) + + isbd / Nvtm * exp( 0.5 / Nvtm ) * ( Vbdj - 0.5 ) ; + Gbd = isbd / Nvtm * exp( 0.5 / Nvtm ) ; + } + + + /* ibs */ + isbs = sIN.as * js + sIN.ps * jssw ; + + if ( Vbsj < 0.5 ) { + Ibs = isbs * ( exp( Vbsj / Nvtm ) - 1 ) ; + Gbs = isbs / Nvtm * exp( Vbsj / Nvtm ) ; + + } else { + Ibs = isbs * ( exp( 0.5 / Nvtm ) - 1 ) + + isbs / Nvtm * exp( 0.5 / Nvtm ) * (Vbsj - 0.5 ) ; + Gbs = isbs / Nvtm * exp( 0.5 / Nvtm ) ; + } + +/*---------------------------------------------------* +* Add Gjmin. +*-----------------*/ + + Ibd += Gjmin * Vbdj ; + Ibs += Gjmin * Vbsj ; + + Gbd += Gjmin ; + Gbs += Gjmin ; + +/*-----------------------------------------------------------* +* Charges and Capacitances. +*-----------------*/ + /* charge storage elements + * bulk-drain and bulk-source depletion capacitances + * czbd : zero bias drain junction capacitance + * czbs : zero bias source junction capacitance + * czbdsw:zero bias drain junction sidewall capacitance + * czbssw:zero bias source junction sidewall capacitance + */ + + czbd = sIN.cj * sIN.ad ; + czbs = sIN.cj * sIN.as ; + + /* Source Bulk Junction */ + if (sIN.ps > Weff) { + czbssw = sIN.cjsw * ( sIN.ps - Weff ) ; + czbsswg = sIN.cjswg * Weff ; + if (Vbsj == 0.0) + { Qbs = 0.0 ; + Capbs = czbs + czbssw ; + } + else if (Vbsj < 0.0) + { if (czbs > 0.0) + { arg = 1.0 - Vbsj / sIN.pb ; + if (sIN.mj == 0.5) + sarg = 1.0 / sqrt(arg) ; + else + sarg = exp(-sIN.mj * log(arg)) ; + Qbs = sIN.pb * czbs + * (1.0 - arg * sarg) / (1.0 - sIN.mj) ; + Capbs = czbs * sarg ; + } + else + { Qbs = 0.0 ; + Capbs = 0.0; + } + if (czbssw > 0.0) + { arg = 1.0 - Vbsj / sIN.pbsw; + if (sIN.mjsw == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-sIN.mjsw * log(arg)); + Qbs += sIN.pbsw * czbssw + * (1.0 - arg * sarg) / (1.0 - sIN.mjsw); + Capbs += czbssw * sarg; + } + if (czbsswg > 0.0) + { arg = 1.0 - Vbsj / sIN.pbswg; + if (sIN.mjswg == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-sIN.mjswg * log(arg)); + Qbs += sIN.pbswg * czbsswg + * (1.0 - arg * sarg) / (1.0 - sIN.mjswg); + Capbs += czbsswg * sarg; + } + } + else + { Qbs = Vbsj * (czbs + czbssw + czbsswg) + + Vbsj * Vbsj * (czbs * sIN.mj * 0.5 / sIN.pb + + czbssw * sIN.mjsw * 0.5 / sIN.pbsw + + czbsswg * sIN.mjswg + * 0.5 / sIN.pbswg); + Capbs = czbs + + czbssw + czbsswg + Vbsj * (czbs * sIN.mj /sIN.pb + + czbssw * sIN.mjsw / sIN.pbsw + + czbsswg * sIN.mjswg / sIN.pbswg ); + } + + } else { + czbsswg = sIN.cjswg * sIN.ps ; + if (Vbsj == 0.0) + { Qbs = 0.0 ; + Capbs = czbs + czbsswg ; + } + else if (Vbsj < 0.0) + { if (czbs > 0.0) + { arg = 1.0 - Vbsj / sIN.pb ; + if (sIN.mj == 0.5) + sarg = 1.0 / sqrt(arg) ; + else + sarg = exp(-sIN.mj * log(arg)) ; + Qbs = sIN.pb * czbs + * (1.0 - arg * sarg) / (1.0 - sIN.mj) ; + Capbs = czbs * sarg ; + } + else + { Qbs = 0.0 ; + Capbs = 0.0; + } + if (czbsswg > 0.0) + { arg = 1.0 - Vbsj / sIN.pbswg; + if (sIN.mjswg == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-sIN.mjswg * log(arg)); + Qbs += sIN.pbswg * czbsswg + * (1.0 - arg * sarg) / (1.0 - sIN.mjswg); + Capbs += czbsswg * sarg; + } + } + else + { Qbs = Vbsj * (czbs + czbsswg) + + Vbsj * Vbsj * (czbs * sIN.mj * 0.5 / sIN.pb + + czbsswg * sIN.mjswg * 0.5 / sIN.pbswg); + Capbs = czbs + + czbsswg + Vbsj * (czbs * sIN.mj /sIN.pb + + czbsswg * sIN.mjswg / sIN.pbswg ); + } + } + + + /* Drain Bulk Junction */ + if (sIN.pd > Weff) { + czbdsw = sIN.cjsw * ( sIN.pd - Weff ) ; + czbdswg = sIN.cjswg * Weff ; + if (Vbdj == 0.0) + { Qbd = 0.0 ; + Capbd = czbd + czbdsw ; + } + else if (Vbdj < 0.0) + { if (czbd > 0.0) + { arg = 1.0 - Vbdj / sIN.pb ; + if (sIN.mj == 0.5) + sarg = 1.0 / sqrt(arg) ; + else + sarg = exp(-sIN.mj * log(arg)) ; + Qbd = sIN.pb * czbd + * (1.0 - arg * sarg) / (1.0 - sIN.mj) ; + Capbd = czbd * sarg ; + } + else + { Qbd = 0.0 ; + Capbd = 0.0; + } + if (czbdsw > 0.0) + { arg = 1.0 - Vbdj / sIN.pbsw; + if (sIN.mjsw == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-sIN.mjsw * log(arg)); + Qbd += sIN.pbsw * czbdsw + * (1.0 - arg * sarg) / (1.0 - sIN.mjsw); + Capbd += czbdsw * sarg; + } + if (czbdswg > 0.0) + { arg = 1.0 - Vbdj / sIN.pbswg; + if (sIN.mjswg == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-sIN.mjswg * log(arg)); + Qbd += sIN.pbswg * czbdswg + * (1.0 - arg * sarg) / (1.0 - sIN.mjswg); + Capbd += czbdswg * sarg; + } + } + else + { Qbd = Vbdj * (czbd + czbdsw + czbdswg) + + Vbdj * Vbdj * (czbd * sIN.mj * 0.5 / sIN.pb + + czbdsw * sIN.mjsw * 0.5 / sIN.pbsw + + czbdswg * sIN.mjswg + * 0.5 / sIN.pbswg); + Capbd = czbd + + czbdsw + czbdswg + Vbdj * (czbd * sIN.mj /sIN.pb + + czbdsw * sIN.mjsw / sIN.pbsw + + czbdswg * sIN.mjswg / sIN.pbswg ); + } + + } else { + czbdswg = sIN.cjswg * sIN.pd ; + if (Vbdj == 0.0) + { Qbd = 0.0 ; + Capbd = czbd + czbdswg ; + } + else if (Vbdj < 0.0) + { if (czbd > 0.0) + { arg = 1.0 - Vbdj / sIN.pb ; + if (sIN.mj == 0.5) + sarg = 1.0 / sqrt(arg) ; + else + sarg = exp(-sIN.mj * log(arg)) ; + Qbd = sIN.pb * czbd + * (1.0 - arg * sarg) / (1.0 - sIN.mj) ; + Capbd = czbd * sarg ; + } + else + { Qbd = 0.0 ; + Capbd = 0.0; + } + if (czbdswg > 0.0) + { arg = 1.0 - Vbdj / sIN.pbswg; + if (sIN.mjswg == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-sIN.mjswg * log(arg)); + Qbd += sIN.pbswg * czbdswg + * (1.0 - arg * sarg) / (1.0 - sIN.mjswg); + Capbd += czbdswg * sarg; + } + } + else + { Qbd = Vbdj * (czbd + czbdswg) + + Vbdj * Vbdj * (czbd * sIN.mj * 0.5 / sIN.pb + + czbdswg * sIN.mjswg * 0.5 / sIN.pbswg); + Capbd = czbd + + czbdswg + Vbdj * (czbd * sIN.mj /sIN.pb + + czbdswg * sIN.mjswg / sIN.pbswg ); + } + } + + + +/*-----------------------------------------------------------* +* End of PART-4. (label) +*-----------------*/ +end_of_part_4: ; + + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +* PART-5: Noise Calculation. +*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + + if ( sIN.conois != 0 ){ + + NFalp = sIN.nfalp ; + NFtrp = sIN.nftrp ; + Cit = sIN.cit ; + + T1 = Qn0 / C_QE ; + T2 = (Cox+Qn0/(Ps0-Vbs)+Cit)/beta/C_QE ; + T3 = 1.0E0/(T1+T2)+NFalp*Mu ; + Nflic = Ids*Ids*NFtrp/((Leff-Lred)*beta*Weff)*T3*T3 ; + + } else { + Nflic = 0.0 ; + } + + +/*-----------------------------------------------------------* +* End of PART-5. (label) +*-----------------*/ +end_of_part_5: ; + + + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +* PART-6: Evaluation of outputs. +*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + +/*-----------------------------------------------------------* +* Implicit quantities related to Alpha. +*-----------------*/ + + /* note: T1 = 1 + Delta */ + if ( flg_noqi == 0 && VgVt > VgVt_small && Pds > 0.0 ) { + T1 = Achi / Pds ; + Delta = T1 - 1.0e0 ; + Vdsat = VgVt / T1 ; + } else { + Alpha = 1.0 ; + Delta = 0.0 ; + Vdsat = 0.0 ; + Achi = 0.0 ; + } + +/*-----------------------------------------------------------* +* Evaluate the derivatives w.r.t. external biases. +* - All derivatives that influence outputs must be modified here. +*-----------------*/ + +/*---------------------------------------------------* +* Case ignoring Rs/Rd. +*-----------------*/ + if ( flg_rsrd == 0 || Ids <= 0.0 ) { + + Ids_dVbse = Ids_dVbs ; + Ids_dVdse = Ids_dVds ; + Ids_dVgse = Ids_dVgs ; + + Qb_dVbse = Qb_dVbs ; + Qb_dVdse = Qb_dVds ; + Qb_dVgse = Qb_dVgs ; + + Qi_dVbse = Qi_dVbs ; + Qi_dVdse = Qi_dVds ; + Qi_dVgse = Qi_dVgs ; + + Qd_dVbse = Qd_dVbs ; + Qd_dVdse = Qd_dVds ; + Qd_dVgse = Qd_dVgs ; + + Isub_dVbse = Isub_dVbs ; + Isub_dVdse = Isub_dVds ; + Isub_dVgse = Isub_dVgs ; + + Igs_dVbse = Igs_dVbs ; + Igs_dVdse = Igs_dVds ; + Igs_dVgse = Igs_dVgs ; + + Ilg_dVbse = Ilg_dVbs ; + Ilg_dVdse = Ilg_dVds ; + Ilg_dVgse = Ilg_dVgs ; + + Qgos_dVbse = Qgos_dVbs ; + Qgos_dVdse = Qgos_dVds ; + Qgos_dVgse = Qgos_dVgs ; + + Qgod_dVbse = Qgod_dVbs ; + Qgod_dVdse = Qgod_dVds ; + Qgod_dVgse = Qgod_dVgs ; + + +/*---------------------------------------------------* +* Case Rs>0 or Rd>0 +*-----------------*/ + } else { + +/*-------------------------------------------* +* Conductances w.r.t. confined biases. +*-----------------*/ + + Ids_dVbse = Ids_dVbs * DJI ; + Ids_dVdse = Ids_dVds * DJI ; + Ids_dVgse = Ids_dVgs * DJI ; + +/*-------------------------------------------* +* Derivatives of internal biases w.r.t. external biases. +*-----------------*/ + Vbs_dVbse = ( 1.0 - Rs * Ids_dVbse ) ; + Vbs_dVdse = - Rs * Ids_dVdse ; + Vbs_dVgse = - Rs * Ids_dVgse ; + + Vds_dVbse = - ( Rs + Rd ) * Ids_dVbse ; + Vds_dVdse = ( 1.0 - ( Rs + Rd ) * Ids_dVdse ) ; + Vds_dVgse = - ( Rs + Rd ) * Ids_dVgse ; + + Vgs_dVbse = - Rs * Ids_dVbse ; + Vgs_dVdse = - Rs * Ids_dVdse ; + Vgs_dVgse = ( 1.0 - Rs * Ids_dVgse ) ; + +/*-------------------------------------------* +* Derivatives of charges. +*-----------------*/ + + Qb_dVbse = Qb_dVbs * Vbs_dVbse + Qb_dVds * Vds_dVbse + + Qb_dVgs * Vgs_dVbse ; + Qb_dVdse = Qb_dVbs * Vbs_dVdse + Qb_dVds * Vds_dVdse + + Qb_dVgs * Vgs_dVdse ; + Qb_dVgse = Qb_dVbs * Vbs_dVgse + Qb_dVds * Vds_dVgse + + Qb_dVgs * Vgs_dVgse ; + + Qi_dVbse = Qi_dVbs * Vbs_dVbse + Qi_dVds * Vds_dVbse + + Qi_dVgs * Vgs_dVbse ; + Qi_dVdse = Qi_dVbs * Vbs_dVdse + Qi_dVds * Vds_dVdse + + Qi_dVgs * Vgs_dVdse ; + Qi_dVgse = Qi_dVbs * Vbs_dVgse + Qi_dVds * Vds_dVgse + + Qi_dVgs * Vgs_dVgse ; + + Qd_dVbse = Qd_dVbs * Vbs_dVbse + Qd_dVds * Vds_dVbse + + Qd_dVgs * Vgs_dVbse ; + Qd_dVdse = Qd_dVbs * Vbs_dVdse + Qd_dVds * Vds_dVdse + + Qd_dVgs * Vgs_dVdse ; + Qd_dVgse = Qd_dVbs * Vbs_dVgse + Qd_dVds * Vds_dVgse + + Qd_dVgs * Vgs_dVgse ; + +/*-------------------------------------------* +* Substrate/gate/leak conductances. +*-----------------*/ + + Isub_dVbse = Isub_dVbs * Vbs_dVbse + Isub_dVds * Vds_dVbse + + Isub_dVgs * Vgs_dVbse ; + Isub_dVdse = Isub_dVbs * Vbs_dVdse + Isub_dVds * Vds_dVdse + + Isub_dVgs * Vgs_dVdse ; + Isub_dVgse = Isub_dVbs * Vbs_dVgse + Isub_dVds * Vds_dVgse + + Isub_dVgs * Vgs_dVgse ; + + Igs_dVbse = Igs_dVbs * Vbs_dVbse + Igs_dVds * Vds_dVbse + + Igs_dVgs * Vgs_dVbse ; + Igs_dVdse = Igs_dVbs * Vbs_dVdse + Igs_dVds * Vds_dVdse + + Igs_dVgs * Vgs_dVdse ; + Igs_dVgse = Igs_dVbs * Vbs_dVgse + Igs_dVds * Vds_dVgse + + Igs_dVgs * Vgs_dVgse ; + + Ilg_dVbse = Ilg_dVbs * Vbs_dVbse + Ilg_dVds * Vds_dVbse + + Ilg_dVgs * Vgs_dVbse ; + Ilg_dVdse = Ilg_dVbs * Vbs_dVdse + Ilg_dVds * Vds_dVdse + + Ilg_dVgs * Vgs_dVdse ; + Ilg_dVgse = Ilg_dVbs * Vbs_dVgse + Ilg_dVds * Vds_dVgse + + Ilg_dVgs * Vgs_dVgse ; + +/*---------------------------------------------------* +* Derivatives of overlap charges. +*-----------------*/ + + Qgos_dVbse = Qgos_dVbs * Vbs_dVbse + Qgos_dVds * Vds_dVbse + + Qgos_dVgs * Vgs_dVbse ; + Qgos_dVdse = Qgos_dVbs * Vbs_dVdse + Qgos_dVds * Vds_dVdse + + Qgos_dVgs * Vgs_dVdse ; + Qgos_dVgse = Qgos_dVbs * Vbs_dVgse + Qgos_dVds * Vds_dVgse + + Qgos_dVgs * Vgs_dVgse ; + + Qgod_dVbse = Qgod_dVbs * Vbs_dVbse + Qgod_dVds * Vds_dVbse + + Qgod_dVgs * Vgs_dVbse ; + Qgod_dVdse = Qgod_dVbs * Vbs_dVdse + Qgod_dVds * Vds_dVdse + + Qgod_dVgs * Vgs_dVdse ; + Qgod_dVgse = Qgod_dVbs * Vbs_dVgse + Qgod_dVds * Vds_dVgse + + Qgod_dVgs * Vgs_dVgse ; + + } /* end of if ( flg_rsrd == 0 ) blocks */ + +/*---------------------------------------------------* +* Derivatives of junction diode currents and charges. +* - NOTE: These quantities are regarded as functions of +* external biases. +* - NOTE: node-base S/D +*-----------------*/ + Gbse = Gbs ; + Gbde = Gbd ; + Capbse = Capbs ; + Capbde = Capbd ; + +/*---------------------------------------------------* +* Extrapolate quantities if external biases are out of bounds. +*-----------------*/ + + if ( flg_vbsc == 1 ) { + Ids_dVbse *= Vbsc_dVbse ; + Qb_dVbse *= Vbsc_dVbse ; + Qi_dVbse *= Vbsc_dVbse ; + Qd_dVbse *= Vbsc_dVbse ; + Isub_dVbse *= Vbsc_dVbse ; + Igs_dVbse *= Vbsc_dVbse ; + Ilg_dVbse *= Vbsc_dVbse ; + Qgos_dVbse *= Vbsc_dVbse ; + Qgod_dVbse *= Vbsc_dVbse ; + } + + if ( flg_vxxc != 0 ) { + + if ( flg_vbsc == -1 ) { + T1 = Vbse - Vbsc ; + } else { + T1 = 0.0 ; + } + + + if ( flg_vdsc != 0 ) { + T2 = Vdse - Vdsc ; + } else { + T2 = 0.0 ; + } + + if ( flg_vgsc != 0 ) { + T3 = Vgse - Vgsc ; + } else { + T3 = 0.0 ; + } + + if ( flg_vbdc != 0 ) { + T4 = Vbde - Vbdc ; + } else { + T4 = 0.0 ; + } + + + TX = Ids + T1 * Ids_dVbse + T2 * Ids_dVdse + T3 * Ids_dVgse ; + if ( TX * Ids >= 0.0 ) { + Ids = TX ; + } else { + T7 = Ids / ( Ids - TX ) ; + Ids_dVbse *= T7 ; + Ids_dVdse *= T7 ; + Ids_dVgse *= T7 ; + Ids = 0.0 ; + } + + TX = Qb + T1 * Qb_dVbse + T2 * Qb_dVdse + T3 * Qb_dVgse ; + /*note: The sign of Qb can be changed.*/ + Qb = TX ; + + TX = Qd + T1 * Qd_dVbse + T2 * Qd_dVdse + T3 * Qd_dVgse ; + if ( TX * Qd >= 0.0 ) { + Qd = TX ; + } else { + T7 = Qd / ( Qd - TX ) ; + Qd_dVbse *= T7 ; + Qd_dVdse *= T7 ; + Qd_dVgse *= T7 ; + Qd = 0.0 ; + } + + TX = Qi + T1 * Qi_dVbse + T2 * Qi_dVdse + T3 * Qi_dVgse ; + if ( TX * Qi >= 0.0 ) { + Qi = TX ; + } else { + T7 = Qi / ( Qi - TX ) ; + Qi_dVbse *= T7 ; + Qi_dVdse *= T7 ; + Qi_dVgse *= T7 ; + Qi = 0.0 ; + } + + TX = Isub + T1 * Isub_dVbse + T2 * Isub_dVdse + T3 * Isub_dVgse ; + if ( TX * Isub >= 0.0 ) { + Isub = TX ; + } else { + T7 = Isub / ( Isub - TX ) ; + Isub_dVbse *= T7 ; + Isub_dVdse *= T7 ; + Isub_dVgse *= T7 ; + Isub = 0.0 ; + } + + TX = Igs + T1 * Igs_dVbse + T2 * Igs_dVdse + T3 * Igs_dVgse ; + if ( TX * Igs >= 0.0 ) { + Igs = TX ; + } else { + T7 = Igs / ( Igs - TX ) ; + Igs_dVbse *= T7 ; + Igs_dVdse *= T7 ; + Igs_dVgse *= T7 ; + Igs = 0.0 ; + } + + TX = Ilg + T1 * Ilg_dVbse + T2 * Ilg_dVdse + T3 * Ilg_dVgse ; + if ( TX * Ilg >= 0.0 ) { + Ilg = TX ; + } else { + T7 = Ilg / ( Ilg - TX ) ; + Ilg_dVbse *= T7 ; + Ilg_dVdse *= T7 ; + Ilg_dVgse *= T7 ; + Ilg = 0.0 ; + } + + TX = Qgod + T1 * Qgod_dVbse + T2 * Qgod_dVdse + T3 * Qgod_dVgse ; + if ( TX * Qgod >= 0.0 ) { + Qgod = TX ; + } else { + T7 = Qgod / ( Qgod - TX ) ; + Qgod_dVbse *= T7 ; + Qgod_dVdse *= T7 ; + Qgod_dVgse *= T7 ; + Qgod = 0.0 ; + } + + TX = Qgos + T1 * Qgos_dVbse + T2 * Qgos_dVdse + T3 * Qgos_dVgse ; + if ( TX * Qgos >= 0.0 ) { + Qgos = TX ; + } else { + T7 = Qgos / ( Qgos - TX ) ; + Qgos_dVbse *= T7 ; + Qgos_dVdse *= T7 ; + Qgos_dVgse *= T7 ; + Qgos = 0.0 ; + } + + + } + +/*-----------------------------------------------------------* +* Warn negative conductance. +* - T1 ( = d Ids / d Vds ) is the derivative w.r.t. circuit bias. +*-----------------*/ + + if ( sIN.mode == HiSIM_NORMAL_MODE ) { + T1 = Ids_dVdse ; + } else { + T1 = Ids_dVbse + Ids_dVdse + Ids_dVgse ; + } + + if ( Ids_dVbse < 0.0 || T1 < 0.0 || Ids_dVgse < 0.0 ) { + fprintf( stderr , + "*** warning(HiSIM): Negative Conductance\n" ) ; + fprintf( stderr , + " type = %d mode = %d\n" , sIN.type , sIN.mode ) ; + fprintf( stderr , + " Vbse = %12.5e Vdse = %12.5e Vgse = %12.5e\n" , + Vbse , Vdse , Vgse ) ; + if ( flg_info >= 1 ) { + printf( "*** warning(HiSIM): Negative Conductance\n" ) ; + printf( " type = %d mode = %d\n" , sIN.type , sIN.mode ) ; + printf( " Vbse = %12.5e Vdse = %12.5e Vgse = %12.5e\n" , + Vbse , Vdse , Vgse ) ; + printf( " Ids_dVbse = %12.5e\n" , Ids_dVbse ) ; + printf( " Ids_dVdse = %12.5e\n" , Ids_dVdse ) ; + printf( " Ids_dVgse = %12.5e\n" , Ids_dVgse ) ; + } + } + + if ( Ids_dVbse < 0.0e0 ) { + fprintf( stderr , " Ids_dVbse = %12.5e\n" , Ids_dVbse ) ; + flg_ncnv ++ ; + } + if ( T1 < 0.0e0 ) { + fprintf( stderr , " Ids_dVdse = %12.5e\n" , T1 ) ; + flg_ncnv ++ ; + } + if ( Ids_dVgse < 0.0e0 ) { + fprintf( stderr , " Ids_dVgse = %12.5e\n" , Ids_dVgse ) ; + flg_ncnv ++ ; + } + + + +/*-----------------------------------------------------------* +* Redefine overlap charges/capacitances. +*-----------------*/ + +/*---------------------------------------------------* +* Constant capacitance. +*-----------------*/ + + if ( sIN.cocgbo >= 1 ) { + Cgbo = sIN.cgbo * Lgate ; + } else { + Cgbo = 0.0 ; + } + + if ( sIN.cocgdo >= 1 ) { + Cgdo = - sIN.cgdo * Weff ; + Qgod = - Cgdo * ( Vgse - Vdse ) ; + Qgod_dVbse = 0.0 ; + Qgod_dVdse = Cgdo ; + Qgod_dVgse = - Qgod_dVdse ; + } else { + Cgdo = Qgos_dVdse + Qgod_dVdse ; + } + + if ( sIN.cocgso >= 1 ) { + Cgso = - sIN.cgso * Weff ; + Qgos = - Cgso * Vgse ; + Qgos_dVbse = 0.0 ; + Qgos_dVdse = 0.0 ; + Qgos_dVgse = - Cgso ; + } else { + Cgso = - ( Qgos_dVbse + Qgod_dVbse + + Qgos_dVdse + Qgod_dVdse + + Qgos_dVgse + Qgod_dVgse ) ; + } + + Cggo = Qgos_dVgse + Qgod_dVgse ; + +/*---------------------------------------------------* +* Fringing capacitance. +*-----------------*/ + + Cf = C_EOX / ( C_Pi / 2.0e0 ) * Weff + * log( 1.0e0 + sIN.tpoly / sIN. tox ) ; + + /* added 2 Eqs. below. (4/Dec/01) */ + + Qfd = Cf * ( Vgse - Vdse ) ; + Qfs = Cf * Vgse ; + + /* end of additional Eqs. */ + +/*---------------------------------------------------* +* Add fringing charge/capacitance to overlap. +*-----------------*/ + + /* added 2 Eqs. below. (4/Dec/01) */ + + Qgod += Qfd ; + Qgos += Qfs ; + + /* end of additional Eqs. */ + + Cggo += 2.0 * Cf ; + Cgdo += - Cf ; + Cgso += - Cf ; + +/*-----------------------------------------------------------* +* Assign outputs. +*-----------------*/ + +/*---------------------------------------------------* +* Channel current and conductances. +*-----------------*/ + + /* pOT->ids = sIN.type * Ids ; */ + pOT->ids = Ids ; + pOT->gmbs = Ids_dVbse ; + pOT->gds = Ids_dVdse ; + pOT->gm = Ids_dVgse ; + +/*---------------------------------------------------* +* Intrinsic charges/capacitances. +*-----------------*/ + + pOT->qg = - ( Qb + Qi ) ; + pOT->qd = Qd ; + pOT->qs = Qi - Qd ; + + pOT->cbgb = Qb_dVgse ; + pOT->cbdb = Qb_dVdse ; + pOT->cbsb = - ( Qb_dVbse + Qb_dVdse + Qb_dVgse ) ; + + pOT->cggb = - Qb_dVgse - Qi_dVgse ; + pOT->cgdb = - Qb_dVdse - Qi_dVdse ; + pOT->cgsb = Qb_dVbse + Qb_dVdse + Qb_dVgse + + Qi_dVbse + Qi_dVdse + Qi_dVgse ; + + pOT->cdgb = Qd_dVgse ; + pOT->cddb = Qd_dVdse ; + pOT->cdsb = - ( Qd_dVgse + Qd_dVdse + Qd_dVbse ) ; + + +/*---------------------------------------------------* +* Overlap capacitances. +*-----------------*/ + + pOT->cgdo = Cgdo ; + pOT->cgso = Cgso ; + pOT->cgbo = Cgbo ; + +/*------------------------------------ + * Lateral-field-induced capasitance +-----------------------------------*/ + + if ( sIN.xqy == 0 ){ + Qy = 0e0 ; + Cqyd = 0e0 ; + Cqyg = 0e0 ; + Cqyb = 0e0 ; + Cqys = 0e0 ; + } else { + Pslk = Ec * Leff + Ps0 ; + Pslk_dVbs = Ec_dVbs * Leff + Ps0_dVbs; + Pslk_dVds = Ec_dVds * Leff + Ps0_dVds; + Pslk_dVgs = Ec_dVgs * Leff + Ps0_dVgs; + if ( Pslk > Psdl ){ + Pslk = Psdl ; + Pslk_dVbs = Psdl_dVbs ; + Pslk_dVds = Psdl_dVds ; + Pslk_dVgs = Psdl_dVgs ; + } + + T1 = Aclm * ( Vds + Ps0 ) + ( 1.0e0 - Aclm ) * Pslk ; + T1_dVbs = Aclm * ( Ps0_dVbs ) + ( 1.0e0 - Aclm ) * Pslk_dVbs ; + T1_dVds = Aclm * ( 1.0 + Ps0_dVds ) + ( 1.0e0 - Aclm ) * Pslk_dVds ; + T1_dVgs = Aclm * ( Ps0_dVgs ) + ( 1.0e0 - Aclm ) * Pslk_dVgs ; + + T10 = sqrt( 2.0e0 * C_ESI / q_Nsub ) ; + + T3 = T10 * 1.3; + T2 = C_ESI * Weff * T3 ; + + Qy = ( ( Ps0 + Vds - T1 ) / sIN.xqy - Ec ) * T2 ; + + Cqyd = ( ( Ps0_dVds + 1.0e0 - T1_dVds ) / sIN.xqy - Ec_dVds ) * T2; + Cqyg = ( ( Ps0_dVgs - T1_dVgs ) / sIN.xqy - Ec_dVgs ) * T2; + Cqyb = ( ( Ps0_dVbs - T1_dVbs ) / sIN.xqy - Ec_dVbs ) * T2; + Cqys = - ( Cqyb + Cqyd + Cqyg ) ; + } + + +/*---------------------------------------------------* +* Add S/D overlap charges/capacitances to intrinsic ones. +* - NOTE: This function depends on coadov, a control option. +*-----------------*/ + + if ( sIN.coadov == 1 ) { + pOT->qg += Qgod + Qgos - Qy ; + pOT->qd += - Qgod + Qy ; + pOT->qs += - Qgos ; + + pOT->cggb += Cggo - Cqyg ; + pOT->cgdb = pOT->cgdb + Cgdo + (-1) * Cqyd ; + pOT->cgsb += Cgso + (-1) * Cqys ; + + pOT->cdgb += - Qgod_dVgse - Cf + Cqyg ; + pOT->cddb += - Qgod_dVdse + Cf + Cqyd ; + pOT->cdsb += Qgod_dVbse + Qgod_dVdse + Qgod_dVgse + Cqys ; + + pOT->cgdo = 0.0 ; + pOT->cgso = 0.0 ; + + if ( pOT->cgdb > -1e-27 ) { pOT->cgdb = 0e0 ; } + if ( pOT->cgsb > -1e-27 ) { pOT->cgsb = 0e0 ; } + } + + +/*---------------------------------------------------* +* Substrate/gate/leak currents. +*-----------------*/ + + pOT->isub = Isub ; + + pOT->gbbs = Isub_dVbse ; + pOT->gbds = Isub_dVdse ; + pOT->gbgs = Isub_dVgse ; + + pOT->igs = Igs ; + + pOT->ggbs = Igs_dVbse ; + pOT->ggds = Igs_dVdse ; + pOT->gggs = Igs_dVgse ; + + pOT->ilg = Ilg ; + + pOT->glbs = Ilg_dVbse ; + pOT->glds = Ilg_dVdse ; + pOT->glgs = Ilg_dVgse ; + +/*---------------------------------------------------* +* Meyer's capacitances. +*-----------------*/ + + pOT->capgs = - pOT->cgsb - Cgso ; + pOT->capgd = - pOT->cgdb - Cgdo ; + pOT->capgb = pOT->cggb + pOT->cgdb + pOT->cgbo ; + +/*---------------------------------------------------* +* Von, Vdsat, +*-----------------*/ + + /* + pOT->von = sIN.type * Vth ; + pOT->vdsat = sIN.type * Vdsat ; + */ + pOT->von = Vth ; + pOT->vdsat = Vdsat ; + +/*---------------------------------------------------* +* Parasitic conductances. +*-----------------*/ + +/*:org: +* pOT->gd = 1.0e+50 ; +* pOT->gs = 1.0e+50 ; +* modified according to CMIxxxeval.c. +* I don't know the reason why these can be zero. +*/ + pOT->gd = 0.0e0 ; + pOT->gs = 0.0e0 ; + +/*---------------------------------------------------* +* Junction diode. +*-----------------*/ + + /* + pOT->ibs = sIN.type * Ibs ; + pOT->ibd = sIN.type * Ibd ; + */ + pOT->ibs = Ibs ; + pOT->ibd = Ibd ; + pOT->gbs = Gbse ; + pOT->gbd = Gbde ; + + pOT->qbs = Qbs ; + pOT->qbd = Qbd ; + pOT->capbs = Capbse ; + pOT->capbd = Capbde ; + + + +/*-----------------------------------------------------------* +* Warn floating-point exceptions. +* - Function finite() in libm is called. +* - Go to start with info==5. +*-----------------*/ + + T1 = pOT->ids + pOT->gmbs + pOT->gds + pOT->gm ; + T1 = T1 + pOT->qd + pOT->cdsb ; + if ( ! finite( T1 ) ) { + flg_err = 1 ; + fprintf( stderr , + "*** warning(HiSIM): FP-exception (PART-1)\n" ) ; + if ( flg_info >= 1 ) { + printf( "*** warning(HiSIM): FP-exception\n" ) ; + printf( "pOT->ids = %12.5e\n" , pOT->ids ) ; + printf( "pOT->gmbs = %12.5e\n" , pOT->gmbs ) ; + printf( "pOT->gds = %12.5e\n" , pOT->gds ) ; + printf( "pOT->gm = %12.5e\n" , pOT->gm ) ; + printf( "pOT->qd = %12.5e\n" , pOT->qd ) ; + printf( "pOT->cdsb = %12.5e\n" , pOT->cdsb ) ; + } + } + + T1 = pOT->isub + pOT->gbbs + pOT->gbds + pOT->gbgs ; + if ( ! finite( T1 ) ) { + flg_err = 1 ; + fprintf( stderr , + "*** warning(HiSIM): FP-exception (PART-2)\n" ) ; + if ( flg_info >= 1 ) { + printf( "*** warning(HiSIM): FP-exception\n" ) ; + } + } + + T1 = pOT->cgbo + Cgdo + Cgso + Cggo ; + if ( ! finite( T1 ) ) { + flg_err = 1 ; + fprintf( stderr , + "*** warning(HiSIM): FP-exception (PART-3)\n" ) ; + if ( flg_info >= 1 ) { + printf( "*** warning(HiSIM): FP-exception\n" ) ; + } + } + + T1 = pOT->ibs + pOT->ibd + pOT->gbs + pOT->gbd ; + T1 = T1 + pOT->qbs + pOT->qbd + pOT->capbs + pOT->capbd ; + if ( ! finite( T1 ) ) { + flg_err = 1 ; + fprintf( stderr , + "*** warning(HiSIM): FP-exception (PART-4)\n" ) ; + if ( flg_info >= 1 ) { + printf( "*** warning(HiSIM): FP-exception\n" ) ; + } + } + + + +/*-----------------------------------------------------------* +* Exit for error case. +*-----------------*/ + if ( flg_err != 0 ) { + return( HiSIM_ERROR ) ; + } + +/*-----------------------------------------------------------* +* Restore values for next calculation. +*-----------------*/ + + /* Confined biases */ + pOT->vbsc = Vbsc ; + pOT->vdsc = Vdsc ; + pOT->vgsc = Vgsc ; + /* Surface potentials and derivatives w.r.t. internal biases */ + pOT->ps0 = Ps0 ; + pOT->ps0_dvbs = Ps0_dVbs ; + pOT->ps0_dvds = Ps0_dVds ; + pOT->ps0_dvgs = Ps0_dVgs ; + pOT->pds = Pds ; + pOT->pds_dvbs = Pds_dVbs ; + pOT->pds_dvds = Pds_dVds ; + pOT->pds_dvgs = Pds_dVgs ; + /* Derivatives of channel current w.r.t. internal biases */ + pOT->ids_dvbs = Ids_dVbs ; + pOT->ids_dvds = Ids_dVds ; + pOT->ids_dvgs = Ids_dVgs ; + + pOT->nf = Nflic ; + + /* mobility added by K.M. */ + pOT->mu = Mu; + +/*-----------------------------------------------------------* +* End of PART-6. (label) +*-----------------*/ +end_of_part_6: ; + + +/*-----------------------------------------------------------* +* Bottom of hsm1eval1_1. +*-----------------*/ + + + +return ( HiSIM_OK ) ; + +} /* end of hsm1eval1_1 */ diff --git a/src/spicelib/devices/hisim/hsm1evalenv.h b/src/spicelib/devices/hisim/hsm1evalenv.h new file mode 100644 index 000000000..44d59e0ff --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1evalenv.h @@ -0,0 +1,84 @@ +/*********************************************************************** + HiSIM v1.1.0 + File: hsm1evalenv.h of HiSIM v1.1.0 + + Copyright (C) 2002 STARC + + June 30, 2002: developed by Hiroshima University and STARC + June 30, 2002: posted by Keiichi MORIKAWA, STARC Physical Design Group +***********************************************************************/ + +/* + * Modified by Paolo Nenzi 2002 + * ngspice integration + */ + +#ifndef HSM1_EVAL_ENV_H +#define HSM1_EVAL_ENV_H + +/* macros and constants used in hsm1eval1_x.c */ + +/*---------------------------------------------------* +* Numerical constants. (macro) +*-----------------*/ + +/* machine epsilon */ +#if defined(_FLOAT_H) && defined(DBL_EPSILON) +#define C_EPS_M (DBL_EPSILON) +#else +#define C_EPS_M (2.2204460492503131e-16) +#endif + +/* sqrt(2) */ +#define C_SQRT_2 (1.414213562373095e+00) + +/* 1/3 */ +#define C_1o3 (3.333333333333333e-01) +/* 2/3 */ +#define C_2o3 (6.666666666666667e-01) +/* 2^(1/3) */ +#define C_2p_1o3 (1.259921049894873e+00) + +/* Pi */ +#define C_Pi (3.141592653589793) +#define C_Pio2 (1.570796326794897) + +/* Unit change */ +#define C_m2cm (1.0e2) +#define C_m2cm_p2 (1.0e4) +#define C_m2cm_p1o2 (1.0e1) + +/*---------------------------------------------------* +* Physical constants/properties. (macro) +*-----------------*/ +/* Elemental charge */ +#define C_QE (1.6021918e-19) + +/* Boltzmann constant */ +#define C_KB (1.3806226e-23) + +/* Permitivity of Si and SiO2 */ +#define C_ESI (1.034943e-12) +#define C_EOX (3.453133e-13) + +/* Room temperature constants */ +#define C_T300 (300e+00) +#define C_b300 (3.868283e+01) +#define C_Eg0 (1.1785e0) + +/* Build-in potential */ +#define C_Vbi (1.0e0) + +/* Intrinsic carrier density at 300K */ +#define C_Nin0 (1.04e+10) + + +/*---------------------------------------------------* +* Functions. (macro) Take care of the arguments. +*-----------------*/ +#define Fn_Sqr(x) ( (x)*(x) ) /* x^2 */ +#define Fn_Max(x,y) ( (x) >= (y) ? (x) : (y) ) /* max[x,y] */ +#define Fn_Min(x,y) ( (x) <= (y) ? (x) : (y) ) /* min[x,y] */ +#define Fn_Sgn(x) ( (x) >= 0 ? (1) : (-1) ) /* sign[x] */ + +#endif /* HSM1_EVAL_ENV_H */ diff --git a/src/spicelib/devices/hisim/hsm1ext.h b/src/spicelib/devices/hisim/hsm1ext.h new file mode 100644 index 000000000..28569a9fd --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1ext.h @@ -0,0 +1,37 @@ +/*********************************************************************** + HiSIM v1.1.0 + File: hsm1ext.c of HiSIM v1.1.0 + + Copyright (C) 2002 STARC + + June 30, 2002: developed by Hiroshima University and STARC + June 30, 2002: posted by Keiichi MORIKAWA, STARC Physical Design Group +***********************************************************************/ + +/* + * Modified by Paolo Nenzi 2002 + * ngspice integration + */ + +extern int HSM1acLoad(GENmodel *,CKTcircuit*); +extern int HSM1ask(CKTcircuit *,GENinstance*,int,IFvalue*,IFvalue*); +extern int HSM1convTest(GENmodel *,CKTcircuit*); +extern int HSM1delete(GENmodel*,IFuid,GENinstance**); +extern void HSM1destroy(GENmodel**); +extern int HSM1getic(GENmodel*,CKTcircuit*); +extern int HSM1load(GENmodel*,CKTcircuit*); +extern int HSM1mAsk(CKTcircuit*,GENmodel *,int, IFvalue*); +extern int HSM1mDelete(GENmodel**,IFuid,GENmodel*); +extern int HSM1mParam(int,IFvalue*,GENmodel*); +extern void HSM1mosCap(CKTcircuit*, double, double, double, double*, + double, double, double, double, double, double, + double*, double*, double*, double*, double*, double*, double*, double*, + double*, double*, double*, double*, double*, double*, double*, + double*); +extern int HSM1param(int,IFvalue*,GENinstance*,IFvalue*); +extern int HSM1pzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int HSM1setup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int HSM1unsetup(GENmodel*,CKTcircuit*); +extern int HSM1temp(GENmodel*,CKTcircuit*); +extern int HSM1trunc(GENmodel*,CKTcircuit*,double*); +extern int HSM1noise(int,int,GENmodel*,CKTcircuit*,Ndata*,double*); diff --git a/src/spicelib/devices/hisim/hsm1getic.c b/src/spicelib/devices/hisim/hsm1getic.c new file mode 100644 index 000000000..ec44945d5 --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1getic.c @@ -0,0 +1,56 @@ +/*********************************************************************** + HiSIM v1.1.0 + File: hsm1getic.c of HiSIM v1.1.0 + + Copyright (C) 2002 STARC + + June 30, 2002: developed by Hiroshima University and STARC + June 30, 2002: posted by Keiichi MORIKAWA, STARC Physical Design Group +***********************************************************************/ + +/* + * Modified by Paolo Nenzi 2002 + * ngspice integration + */ + +#include "ngspice.h" +#include "cktdefs.h" +#include "hsm1def.h" +#include "sperror.h" +#include "suffix.h" + +int HSM1getic(GENmodel *inModel, CKTcircuit *ckt) +{ + HSM1model *model = (HSM1model*)inModel; + HSM1instance *here; + /* + * grab initial conditions out of rhs array. User specified, so use + * external nodes to get values + */ + + for ( ;model ;model = model->HSM1nextModel ) { + for ( here = model->HSM1instances; here ;here = here->HSM1nextInstance ) { + + if (here->HSM1owner != ARCHme) + continue; + + if (!here->HSM1_icVBS_Given) { + here->HSM1_icVBS = + *(ckt->CKTrhs + here->HSM1bNode) - + *(ckt->CKTrhs + here->HSM1sNode); + } + if (!here->HSM1_icVDS_Given) { + here->HSM1_icVDS = + *(ckt->CKTrhs + here->HSM1dNode) - + *(ckt->CKTrhs + here->HSM1sNode); + } + if (!here->HSM1_icVGS_Given) { + here->HSM1_icVGS = + *(ckt->CKTrhs + here->HSM1gNode) - + *(ckt->CKTrhs + here->HSM1sNode); + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/hisim/hsm1init.c b/src/spicelib/devices/hisim/hsm1init.c new file mode 100644 index 000000000..5a7bf710c --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1init.c @@ -0,0 +1,82 @@ +#include + +#include + +#include "hsm1itf.h" +#include "hsm1ext.h" +#include "hsm1init.h" + + +SPICEdev HSM1info = { + { + "HiSIM1", + "Hiroshima-university STARC IGFET Model 1.1.0", + + &HSM1nSize, + &HSM1nSize, + HSM1names, + + &HSM1pTSize, + HSM1pTable, + + &HSM1mPTSize, + HSM1mPTable, +#ifdef XSPICE +/*---- Fixed by SDB 5.2.2003 to enable XSPICE/tclspice integration -----*/ + NULL, /* This is a SPICE device, it has no MIF info data */ + + 0, /* This is a SPICE device, it has no MIF info data */ + NULL, /* This is a SPICE device, it has no MIF info data */ + + 0, /* This is a SPICE device, it has no MIF info data */ + NULL, /* This is a SPICE device, it has no MIF info data */ + + 0, /* This is a SPICE device, it has no MIF info data */ + NULL, /* This is a SPICE device, it has no MIF info data */ +/*--------------------------- End of SDB fix -------------------------*/ +#endif + +DEV_DEFAULT + }, + + DEVparam : HSM1param, + DEVmodParam : HSM1mParam, + DEVload : HSM1load, + DEVsetup : HSM1setup, + DEVunsetup : HSM1unsetup, + DEVpzSetup : HSM1setup, + DEVtemperature: HSM1temp, + DEVtrunc : HSM1trunc, + DEVfindBranch : NULL, + DEVacLoad : HSM1acLoad, + DEVaccept : NULL, + DEVdestroy : HSM1destroy, + DEVmodDelete : HSM1mDelete, + DEVdelete : HSM1delete, + DEVsetic : HSM1getic, + DEVask : HSM1ask, + DEVmodAsk : HSM1mAsk, + DEVpzLoad : HSM1pzLoad, + DEVconvTest : HSM1convTest, + DEVsenSetup : NULL, + DEVsenLoad : NULL, + DEVsenUpdate : NULL, + DEVsenAcLoad : NULL, + DEVsenPrint : NULL, + DEVsenTrunc : NULL, + DEVdisto : NULL, + DEVnoise : HSM1noise, +#ifdef CIDER + DEVdump : NULL, + DEVacct : NULL, +#endif + DEVinstSize : &HSM1iSize, + DEVmodSize : &HSM1mSize +}; + + +SPICEdev * +get_hsm1_info(void) +{ + return &HSM1info; +} diff --git a/src/spicelib/devices/hisim/hsm1init.h b/src/spicelib/devices/hisim/hsm1init.h new file mode 100644 index 000000000..69d0d4682 --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1init.h @@ -0,0 +1,13 @@ +#ifndef _HISIM1INIT_H +#define _HISIM1INIT_H + +extern IFparm HSM1pTable[ ]; +extern IFparm HSM1mPTable[ ]; +extern char *HSM1names[ ]; +extern int HSM1pTSize; +extern int HSM1mPTSize; +extern int HSM1nSize; +extern int HSM1iSize; +extern int HSM1mSize; + +#endif diff --git a/src/spicelib/devices/hisim/hsm1itf.h b/src/spicelib/devices/hisim/hsm1itf.h new file mode 100644 index 000000000..7b8da29e7 --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1itf.h @@ -0,0 +1,13 @@ +/********** +Copyright 2001 Regents of the University of California. All rights reserved. +Author: 2000 Weidong Liu, Xiaodong Jin. +Author: 2001 Xuemei Xi +File: bsim4itf.h +**********/ + +#ifndef DEV_HISIM1 +#define DEV_HISIM1 + +SPICEdev *get_hsm1_info(void); + +#endif diff --git a/src/spicelib/devices/hisim/hsm1ld.c b/src/spicelib/devices/hisim/hsm1ld.c new file mode 100644 index 000000000..095f373c2 --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1ld.c @@ -0,0 +1,1036 @@ +/*********************************************************************** + HiSIM v1.1.0 + File: hsm1ld.c of HiSIM v1.1.0 + + Copyright (C) 2002 STARC + + June 30, 2002: developed by Hiroshima University and STARC + June 30, 2002: posted by Keiichi MORIKAWA, STARC Physical Design Group +***********************************************************************/ + +/* + * Modified by Paolo Nenzi 2002 + * ngspice integration + */ + +#include "ngspice.h" +#include "cktdefs.h" +#include "hsm1def.h" +#include "hisim.h" +#include "trandefs.h" +#include "const.h" +#include "sperror.h" +#include "devdefs.h" +#include "suffix.h" + +static void ShowPhysVals(HSM1instance *here, int flag, int isFirst, double vds, + double vgs, double vbs) +{ + switch (flag) { + case 1: + if (isFirst) printf("Vds Ids\n"); + printf("%e %e\n", vds, here->HSM1_ids); + break; + case 2: + if (isFirst) printf("Vgs Ids\n"); + printf("%e %e\n", vgs, here->HSM1_ids); + break; + case 3: + if (isFirst) printf("vgs ln(Ids)\n"); + printf("%e %e\n", vgs, log(here->HSM1_ids)); + break; + case 4: + if (isFirst) printf("ln(Ids) gm/Ids\n"); + if (here->HSM1_ids == 0.0) + printf("I can't show gm/Ids - ln(Ids), because Ids = 0.\n"); + else + printf("%e %e\n", log(here->HSM1_ids), here->HSM1_gm/here->HSM1_ids); + break; + case 5: + if (isFirst) printf("Vds gds\n"); + printf("%e %e\n", vds, here->HSM1_gds); + break; + case 6: + if (isFirst) printf("Vgs gm\n"); + printf("%e %e\n", vgs, here->HSM1_gm); + break; + case 7: + if (isFirst) printf("Vbs gbs\n"); + printf("%e %e\n", vbs, here->HSM1_gbs); + break; + case 8: + if (isFirst) printf("Vgs Cgg\n"); + printf("%e %e\n", vgs, here->HSM1_cggb); + break; + case 9: + if (isFirst) printf("Vgs Cgs\n"); + printf("%e %e\n", vgs, here->HSM1_cgsb); + break; + case 10: + if (isFirst) printf("Vgs Cgd\n"); + printf("%e %e\n", vgs, here->HSM1_cgdb); + break; + case 11: + if (isFirst) printf("Vgs Cgb\n"); + printf("%e %e\n", vgs, -(here->HSM1_cggb+here->HSM1_cgsb+here->HSM1_cgdb)); + break; + case 12: + if (isFirst) printf("Vds Csg\n"); + printf("%e %e\n", vds, -(here->HSM1_cggb+here->HSM1_cbgb+here->HSM1_cdgb)); + break; + case 13: + if (isFirst) printf("Vds Cdg\n"); + printf("%e %e\n", vds, here->HSM1_cdgb); + break; + case 14: + if (isFirst) printf("Vds Cbg\n"); + printf("%e %e\n", vds, here->HSM1_cbgb); + break; + deafult: + /* + printf("There is no physical vaule corrsponding to %d\n", flag); + */ + break; + } +} + +int HSM1load(GENmodel *inModel, CKTcircuit *ckt) + /* actually load the current value into the + * sparse matrix previously provided + */ +{ + HSM1model *model = (HSM1model*)inModel; + HSM1instance *here; + HiSIM_input sIN; + HiSIM_output sOT; + HiSIM_messenger sMS; + double cbhat, cdrain, cdhat, cdreq; + double Ibtot, Idtot; + double ceq, ceqbd, ceqbs, ceqqb, ceqqd, ceqqg; + double delvbd, delvbs, delvds, delvgd, delvgs; + double gcbdb, gcbgb, gcbsb, gcddb, gcdgb, gcdsb; + double gcgdb, gcggb, gcgsb, gcsdb, gcsgb, gcssb; + double geq, tol, xfact; + double vbd, vbs, vcrit, vds, vgb, vgd, vgdo, vgs, von; + double qgd, qgs, qgb; + double gbbdp, gbbsp, gbspg, gbspdp, gbspb, gbspsp; + double qgate, qbulk, qdrn, qsrc; + double cqgate, cqbulk, cqdrn; + double gbdpdp, gbdpg, gbdpb, gbdpsp; + double cgdo, cgso, cgbo; + double gm, gmbs, FwdSum, RevSum; + double vt0, ag0; + int ByPass, Check, error; +#ifndef NOBYPASS + double tempv; +#endif /*NOBYPASS*/ + double tmp; + int ChargeComputationNeeded = + ((ckt->CKTmode & (MODEAC | MODETRAN | MODEINITSMSIG)) || + ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC))) + ? 1 : 0; + int showPhysVal; + + double m; + + /* loop through all the HSM1 device models */ + for ( ; model != NULL; model = model->HSM1nextModel ) { + /* loop through all the instances of the model */ + for (here = model->HSM1instances; here != NULL ; + here = here->HSM1nextInstance) { + + if (here->HSM1owner != ARCHme) + continue; + + + showPhysVal = 0; + Check=1; + ByPass = 0; + if ( ckt->CKTmode & MODEINITSMSIG ) { + vbs= *(ckt->CKTstate0 + here->HSM1vbs); + vgs= *(ckt->CKTstate0 + here->HSM1vgs); + vds= *(ckt->CKTstate0 + here->HSM1vds); + } + else if ( ckt->CKTmode & MODEINITTRAN ) { + vbs= *(ckt->CKTstate1 + here->HSM1vbs); + vgs= *(ckt->CKTstate1 + here->HSM1vgs); + vds= *(ckt->CKTstate1 + here->HSM1vds); + } + else if ( (ckt->CKTmode & MODEINITJCT) && !here->HSM1_off ) { + vds= model->HSM1_type * here->HSM1_icVDS; + vgs= model->HSM1_type * here->HSM1_icVGS; + vbs= model->HSM1_type * here->HSM1_icVBS; + if ( (vds == 0.0) && (vgs == 0.0) && (vbs == 0.0) && + ( (ckt->CKTmode & (MODETRAN|MODEAC|MODEDCOP|MODEDCTRANCURVE)) || + !(ckt->CKTmode & MODEUIC) ) ) { + /* set biases for starting analysis (same as BSIM3)*/ + vbs = 0.0; + /* vt0 = model->HSM1_type * (-1.0 * model->HSM1_vfbc);*/ + vt0 = model->HSM1_type * model->HSM1_vfbc; + vgs = vt0 + 0.1; + vds = 0.1; + } + } + else if ( ( ckt->CKTmode & (MODEINITJCT | MODEINITFIX) ) && + here->HSM1_off ) { + vbs = vgs = vds = 0.0; + } + else { +#ifndef PREDICTOR /* BSIM3 style */ + if(ckt->CKTmode & MODEINITPRED) { + xfact = ckt->CKTdelta / ckt->CKTdeltaOld[1]; + *(ckt->CKTstate0 + here->HSM1vbs) = + *(ckt->CKTstate1 + here->HSM1vbs); + vbs = (1.0 + xfact)* (*(ckt->CKTstate1 + here->HSM1vbs)) + -(xfact * (*(ckt->CKTstate2 + here->HSM1vbs))); + *(ckt->CKTstate0 + here->HSM1vgs) = + *(ckt->CKTstate1 + here->HSM1vgs); + vgs = (1.0 + xfact)* (*(ckt->CKTstate1 + here->HSM1vgs)) + -(xfact * (*(ckt->CKTstate2 + here->HSM1vgs))); + *(ckt->CKTstate0 + here->HSM1vds) = + *(ckt->CKTstate1 + here->HSM1vds); + vds = (1.0 + xfact)* (*(ckt->CKTstate1 + here->HSM1vds)) + -(xfact * (*(ckt->CKTstate2 + here->HSM1vds))); + *(ckt->CKTstate0 + here->HSM1vbd) = + *(ckt->CKTstate0 + here->HSM1vbs)- + *(ckt->CKTstate0 + here->HSM1vds); + showPhysVal = 1; + } + else { +#endif /* PREDICTOR */ + /* get biases from CKT */ + vbs = model->HSM1_type * + (*(ckt->CKTrhsOld+here->HSM1bNode) - + *(ckt->CKTrhsOld+here->HSM1sNodePrime)); + vgs = model->HSM1_type * + (*(ckt->CKTrhsOld+here->HSM1gNode) - + *(ckt->CKTrhsOld+here->HSM1sNodePrime)); + vds = model->HSM1_type * + (*(ckt->CKTrhsOld+here->HSM1dNodePrime) - + *(ckt->CKTrhsOld+here->HSM1sNodePrime)); + showPhysVal = 1; +#ifndef PREDICTOR + } +#endif /* PREDICTOR */ + vbd = vbs - vds; + vgd = vgs - vds; + vgdo = *(ckt->CKTstate0 + here->HSM1vgs) - + *(ckt->CKTstate0 + here->HSM1vds); + delvbs = vbs - *(ckt->CKTstate0 + here->HSM1vbs); + delvbd = vbd - *(ckt->CKTstate0 + here->HSM1vbd); + delvgs = vgs - *(ckt->CKTstate0 + here->HSM1vgs); + delvds = vds - *(ckt->CKTstate0 + here->HSM1vds); + delvgd = vgd - vgdo; + + if (here->HSM1_mode >= 0) { + Idtot = here->HSM1_ids + here->HSM1_isub - here->HSM1_ibd; + cdhat = Idtot - here->HSM1_gbd * delvbd + + (here->HSM1_gmbs + here->HSM1_gbbs) * delvbs + + (here->HSM1_gm + here->HSM1_gbgs) * delvgs + + (here->HSM1_gds + here->HSM1_gbds) * delvds; + Ibtot = here->HSM1_ibs + here->HSM1_ibd - here->HSM1_isub; + cbhat = Ibtot + here->HSM1_gbd * delvbd + + (here->HSM1_gbs - here->HSM1_gbbs) * delvbs + - here->HSM1_gbgs * delvgs + - here->HSM1_gbds * delvds; + } + else { + Idtot = here->HSM1_ids - here->HSM1_ibd; + cdhat = Idtot - (here->HSM1_gbd - here->HSM1_gmbs) * delvbd + + here->HSM1_gm * delvgd + - here->HSM1_gds * delvds; + Ibtot = here->HSM1_ibs + here->HSM1_ibd - here->HSM1_isub; + cbhat = Ibtot + here->HSM1_gbs * delvbs + + (here->HSM1_gbd - here->HSM1_gbbs) * delvbd + - here->HSM1_gbgs * delvgd + + here->HSM1_gbds * delvds; + } + +#ifndef NOBYPASS /* BSIM3 style */ + /* now lets see if we can bypass (ugh) */ + + /* following should be one big if connected by && all over + * the place, but some C compilers can't handle that, so + * we split it up here to let them digest it in stages + */ + if ( !(ckt->CKTmode & MODEINITPRED) && ckt->CKTbypass ) + if ( fabs(delvbs) < + ( ckt->CKTreltol * + MAX(fabs(vbs), fabs(*(ckt->CKTstate0+here->HSM1vbs))) + + ckt->CKTvoltTol ) ) + if ( fabs(delvbd) < + ( ckt->CKTreltol * + MAX(fabs(vbd), fabs(*(ckt->CKTstate0+here->HSM1vbd))) + + ckt->CKTvoltTol ) ) + if ( fabs(delvgs) < + ( ckt->CKTreltol * + MAX(fabs(vgs), fabs(*(ckt->CKTstate0+here->HSM1vgs))) + + ckt->CKTvoltTol ) ) + if ( fabs(delvds) < + ( ckt->CKTreltol * + MAX(fabs(vds), fabs(*(ckt->CKTstate0+here->HSM1vds))) + + ckt->CKTvoltTol ) ) + if ( fabs(cdhat - Idtot) < + ( ckt->CKTreltol * + MAX(fabs(cdhat),fabs(Idtot)) + ckt->CKTabstol ) ) { + tempv = MAX(fabs(cbhat),fabs(Ibtot)) + ckt->CKTabstol; + if ((fabs(cbhat - Ibtot)) < ckt->CKTreltol * tempv) { + /* bypass code */ + vbs = *(ckt->CKTstate0 + here->HSM1vbs); + vbd = *(ckt->CKTstate0 + here->HSM1vbd); + vgs = *(ckt->CKTstate0 + here->HSM1vgs); + vds = *(ckt->CKTstate0 + here->HSM1vds); + + vgd = vgs - vds; + vgb = vgs - vbs; + + cdrain = here->HSM1_ids; + if ((ckt->CKTmode & (MODETRAN | MODEAC)) || + ((ckt->CKTmode & MODETRANOP) && + (ckt->CKTmode & MODEUIC))) { + ByPass = 1; + qgate = here->HSM1_qg; + qbulk = here->HSM1_qb; + qdrn = here->HSM1_qd; + goto line755; + } + else + goto line850; + } + } +#endif /*NOBYPASS*/ + + /* von = model->HSM1_type * here->HSM1_von;*/ + von = here->HSM1_von; + if(*(ckt->CKTstate0 + here->HSM1vds) >= 0.0) { + vgs = DEVfetlim(vgs, *(ckt->CKTstate0 + here->HSM1vgs), von); + vds = vgs - vgd; + vds = DEVlimvds(vds, *(ckt->CKTstate0 + here->HSM1vds)); + vgd = vgs - vds; + } + else { + vgd = DEVfetlim(vgd, vgdo, von); + vds = vgs - vgd; + vds = -DEVlimvds(-vds, -(*(ckt->CKTstate0 + here->HSM1vds))); + vgs = vgd + vds; + } + if (vds >= 0.0) { + vcrit = CONSTvt0 * log( CONSTvt0 / (CONSTroot2 * 1.0e-14) ); + /* SourceSatCurrent = 1.0e-14 */ + vbs = DEVpnjlim(vbs,*(ckt->CKTstate0 + here->HSM1vbs), + CONSTvt0,vcrit,&Check); + vbd = vbs - vds; + } + else { + vcrit = CONSTvt0 * log( CONSTvt0 / (CONSTroot2 * 1.0e-14) ); + /* DrainSatCurrent = 1.0e-14 */ + vbd = DEVpnjlim(vbd,*(ckt->CKTstate0 + here->HSM1vbd), + CONSTvt0,vcrit,&Check); + vbs = vbd + vds; + } + } + + vbd = vbs - vds; + vgd = vgs - vds; + vgb = vgs - vbs; + + /* Input data for HiSIM evaluation part */ + sIN.gmin = ckt->CKTgmin; /* minimal conductance */ + + if (vds >= 0) { /* normal mode */ + here->HSM1_mode = 1; + sIN.vds = vds; + sIN.vgs = vgs; + sIN.vbs = vbs; + } + else { /* inverse mode */ + here->HSM1_mode = -1; + sIN.vds = -vds; + sIN.vgs = vgd; + sIN.vbs = vbd; + } + + sIN.type = model->HSM1_type; + sIN.mode = here->HSM1_mode; + /* sIN.qflag = ChargeComputationNeeded; no use */ + sIN.info = model->HSM1_info; + + sIN.xl = here->HSM1_l; + sIN.xw = here->HSM1_w; + + sIN.ad = here->HSM1_ad; + sIN.as = here->HSM1_as; + + sIN.pd = here->HSM1_pd; + sIN.ps = here->HSM1_ps; + + sIN.nrd = here->HSM1_nrd; + sIN.nrs = here->HSM1_nrs; + + sIN.temp = ckt->CKTtemp; + if ( here->HSM1_temp_Given ) sIN.temp = here->HSM1_temp; + if ( here->HSM1_dtemp_Given ) sIN.temp = ckt->CKTtemp + here->HSM1_dtemp; + + sIN.tox = model->HSM1_tox; + sIN.xld = model->HSM1_dl; + sIN.xwd = model->HSM1_dw; + + if (model->HSM1_version == 100) { /* HiSIM 1.0.0 */ + sIN.xj = model->HSM1_xj; + } + else if (model->HSM1_version == 110) { /* HiSIM 1.1.0 */ + sIN.xqy = model->HSM1_xqy; + } + sIN.vmax = model->HSM1_vmax; + sIN.bgtmp1 = model->HSM1_bgtmp1; + sIN.bgtmp2 = model->HSM1_bgtmp2; + sIN.rs = model->HSM1_rs; + sIN.rd = model->HSM1_rd; + sIN.vfbc = model->HSM1_vfbc; + sIN.nsubc = model->HSM1_nsubc; + sIN.lp = model->HSM1_lp; + sIN.nsubp = model->HSM1_nsubp; + sIN.scp1 = model->HSM1_scp1; + sIN.scp2 = model->HSM1_scp2; + sIN.scp3 = model->HSM1_scp3; + sIN.parl1 = model->HSM1_parl1; + sIN.parl2 = model->HSM1_parl2; + sIN.sc1 = model->HSM1_sc1; + sIN.sc2 = model->HSM1_sc2; + sIN.sc3 = model->HSM1_sc3; + sIN.pgd1 = model->HSM1_pgd1; + sIN.pgd2 = model->HSM1_pgd2; + sIN.pgd3 = model->HSM1_pgd3; + sIN.ndep = model->HSM1_ndep; + sIN.ninv = model->HSM1_ninv; + sIN.ninvd = model->HSM1_ninvd; + sIN.muecb0 = model->HSM1_muecb0; + sIN.muecb1 = model->HSM1_muecb1; + sIN.mueph1 = model->HSM1_mueph1; + sIN.mueph0 = model->HSM1_mueph0; + sIN.mueph2 = model->HSM1_mueph2; + sIN.w0 = model->HSM1_w0; + sIN.muesr1 = model->HSM1_muesr1; + sIN.muesr0 = model->HSM1_muesr0; + sIN.muetmp = model->HSM1_muetmp; + if (model->HSM1_version == 110) { /* HiSIM 1.1.0 */ + sIN.wvthsc = model->HSM1_wvthsc; + sIN.nsti = model->HSM1_nsti; + sIN.wsti = model->HSM1_wsti; + } + + if ( model->HSM1_bb_Given ) sIN.bb = model->HSM1_bb; + else + if ( model->HSM1_type == NMOS ) sIN.bb = 2.0e0; + else sIN.bb = 1.0e0; + + sIN.vds0 = model->HSM1_vds0; + sIN.bc0 = model->HSM1_bc0; + sIN.bc1 = model->HSM1_bc1; + sIN.sub1 = model->HSM1_sub1; + sIN.sub2 = model->HSM1_sub2; + sIN.sub3 = model->HSM1_sub3; + + if ( model->HSM1_cgso_Given ) sIN.cocgso = 1; + else sIN.cocgso = 0; + + if ( model->HSM1_cgdo_Given ) sIN.cocgdo = 1; + else sIN.cocgdo = 0; + + if ( model->HSM1_cgbo_Given ) sIN.cocgbo = 1; + else sIN.cocgbo = 0; + + if ( here->HSM1_mode == 1 ) { + sIN.cgso = model->HSM1_cgso; + sIN.cgdo = model->HSM1_cgdo; + } + else { + tmp = sIN.cocgso; + sIN.cocgso = sIN.cocgdo; + sIN.cocgdo = tmp; + sIN.cgso = model->HSM1_cgdo; + sIN.cgdo = model->HSM1_cgso; + } + + sIN.cgbo = model->HSM1_cgbo; + sIN.tpoly = model->HSM1_tpoly; + sIN.js0 = model->HSM1_js0; + sIN.js0sw = model->HSM1_js0sw; + sIN.nj = model->HSM1_nj; + sIN.njsw = model->HSM1_njsw; + sIN.xti = model->HSM1_xti; + sIN.cj = model->HSM1_cj; + sIN.cjsw = model->HSM1_cjsw; + sIN.cjswg = model->HSM1_cjswg; + sIN.mj = model->HSM1_mj; + sIN.mjsw = model->HSM1_mjsw; + sIN.mjswg = model->HSM1_mjswg; + sIN.pb = model->HSM1_pb; + sIN.pbsw = model->HSM1_pbsw; + sIN.pbswg = model->HSM1_pbswg; + sIN.xpolyd = model->HSM1_xpolyd; + sIN.clm1 = model->HSM1_clm1; + sIN.clm2 = model->HSM1_clm2; + sIN.clm3 = model->HSM1_clm3; + sIN.rpock1 = model->HSM1_rpock1; + sIN.rpock2 = model->HSM1_rpock2; + if (model->HSM1_version == 110) { /* HiSIM 1.1.0 */ + sIN.rpocp1 = model->HSM1_rpocp1; + sIN.rpocp2 = model->HSM1_rpocp2; + } + sIN.vover = model->HSM1_vover; + sIN.voverp = model->HSM1_voverp; + sIN.wfc = model->HSM1_wfc; + sIN.qme1 = model->HSM1_qme1; + sIN.qme2 = model->HSM1_qme2; + sIN.qme3 = model->HSM1_qme3; + sIN.gidl1 = model->HSM1_gidl1; + sIN.gidl2 = model->HSM1_gidl2; + sIN.gidl3 = model->HSM1_gidl3; + sIN.gleak1 = model->HSM1_gleak1; + sIN.gleak2 = model->HSM1_gleak2; + sIN.gleak3 = model->HSM1_gleak3; + sIN.vzadd0 = model->HSM1_vzadd0; + sIN.pzadd0 = model->HSM1_pzadd0; + + /* no use in SPICE3f5 */ + /* + sMS.ims[0] = 0; + sMS.dms[0] = 0.0e0; + sMS.ims[1] = 0; */ + /* sMS.dms[1] = pslot->timepoint; I don't know + * no use in SPICE3f5 */ + + if ( ! strcmp(here->HSM1_called, "yes" ) ) { + sIN.has_prv = 1; + } + else { + sIN.has_prv = 0; + strcpy( here->HSM1_called , "yes" ) ; + } + + sIN.corsrd = model->HSM1_corsrd; + sIN.coiprv = model->HSM1_coiprv; + sIN.copprv = model->HSM1_copprv; + sIN.cocgbo = model->HSM1_cocgbo; + sIN.coadov = model->HSM1_coadov; + sIN.coxx08 = model->HSM1_coxx08; + sIN.coxx09 = model->HSM1_coxx09; + sIN.coisub = model->HSM1_coisub; + sIN.coiigs = model->HSM1_coiigs; + sIN.cogidl = model->HSM1_cogidl; + sIN.coovlp = model->HSM1_coovlp; + sIN.conois = model->HSM1_conois; + if (model->HSM1_version == 110) { /* HiSIM 1.1.0 */ + sIN.coisti = model->HSM1_coisti; + } + + sIN.vbsc_prv = here->HSM1_vbsc_prv; + sIN.vdsc_prv = here->HSM1_vdsc_prv; + sIN.vgsc_prv = here->HSM1_vgsc_prv; + sIN.ps0_prv = here->HSM1_ps0_prv; + sIN.ps0_dvbs_prv = here->HSM1_ps0_dvbs_prv; + sIN.ps0_dvds_prv = here->HSM1_ps0_dvds_prv; + sIN.ps0_dvgs_prv = here->HSM1_ps0_dvgs_prv; + sIN.pds_prv = here->HSM1_pds_prv; + sIN.pds_dvbs_prv = here->HSM1_pds_dvbs_prv; + sIN.pds_dvds_prv = here->HSM1_pds_dvds_prv; + sIN.pds_dvgs_prv = here->HSM1_pds_dvgs_prv; + sIN.ids_prv = here->HSM1_ids_prv; + sIN.ids_dvbs_prv = here->HSM1_ids_dvbs_prv; + sIN.ids_dvds_prv = here->HSM1_ids_dvds_prv; + sIN.ids_dvgs_prv = here->HSM1_ids_dvgs_prv; + + sIN.nftrp = model->HSM1_nftrp; + sIN.nfalp = model->HSM1_nfalp; + sIN.cit = model->HSM1_cit; + + if ( sIN.info >= 5 ) { /* mode, bias conditions ... */ + printf( "--- variables given to HSM1evaluate() ----\n" ); + printf( "type = %s\n" , (sIN.type>0) ? "NMOS" : "PMOS" ); + printf( "mode = %s\n" , (sIN.mode>0) ? "NORMAL" : "REVERSE" ); + + printf( "vbs = %12.5e\n" , sIN.vbs ); + printf( "vds = %12.5e\n" , sIN.vds ); + printf( "vgs = %12.5e\n" , sIN.vgs ); + } + if ( sIN.info >= 6 ) { /* input flags */ + printf( "corsrd = %s\n" , (sIN.corsrd) ? "true" : "false" ) ; + printf( "coiprv = %s\n" , (sIN.coiprv) ? "true" : "false" ) ; + printf( "copprv = %s\n" , (sIN.copprv) ? "true" : "false" ) ; + printf( "cocgso = %s\n" , (sIN.cocgso) ? "true" : "false" ) ; + printf( "cocgdo = %s\n" , (sIN.cocgdo) ? "true" : "false" ) ; + printf( "cocgbo = %s\n" , (sIN.cocgbo) ? "true" : "false" ) ; + printf( "coadov = %s\n" , (sIN.coadov) ? "true" : "false" ) ; + printf( "coisub = %s\n" , (sIN.coisub) ? "true" : "false" ) ; + printf( "coiigs = %s\n" , (sIN.coiigs) ? "true" : "false" ) ; + printf( "cogidl = %s\n" , (sIN.cogidl) ? "true" : "false" ) ; + printf( "coovlp = %s\n" , (sIN.coovlp) ? "true" : "false" ) ; + printf( "conois = %s\n" , (sIN.conois) ? "true" : "false" ) ; + if (model->HSM1_version == 110) { /* HiSIM 1.1.0 */ + printf( "coisti = %s\n" , (sIN.coisti) ? "true" : "false" ) ; + } + } + /* print inputs ------------AA */ + + /* call model evaluation */ + if (model->HSM1_version == 100) { /* HiSIM 1.0.0 */ + if ( HSM1evaluate1_0(sIN, &sOT, &sMS) == HiSIM_ERROR ) + return (HiSIM_ERROR); + } + else if (model->HSM1_version == 110) { /* HiSIM 1.1.0 */ + if ( HSM1evaluate1_1(sIN, &sOT, &sMS) == HiSIM_ERROR ) + return (HiSIM_ERROR); + } + + /* store values for next calculation */ + /* note: derivatives are ones w.r.t. internal biases */ + here->HSM1_vbsc_prv = sOT.vbsc ; + here->HSM1_vdsc_prv = sOT.vdsc ; + here->HSM1_vgsc_prv = sOT.vgsc ; + here->HSM1_ps0_prv = sOT.ps0 ; + here->HSM1_ps0_dvbs_prv = sOT.ps0_dvbs ; + here->HSM1_ps0_dvds_prv = sOT.ps0_dvds ; + here->HSM1_ps0_dvgs_prv = sOT.ps0_dvgs ; + here->HSM1_pds_prv = sOT.pds ; + here->HSM1_pds_dvbs_prv = sOT.pds_dvbs ; + here->HSM1_pds_dvds_prv = sOT.pds_dvds ; + here->HSM1_pds_dvgs_prv = sOT.pds_dvgs ; + here->HSM1_ids_prv = sOT.ids ; + here->HSM1_ids_dvbs_prv = sOT.ids_dvbs ; + here->HSM1_ids_dvds_prv = sOT.ids_dvds ; + here->HSM1_ids_dvgs_prv = sOT.ids_dvgs ; + + /* for noise calc */ + here->HSM1_nfc = sOT.nf ; + + /* outputs */ + here->HSM1_gd = sOT.gd ; /* drain conductance */ + here->HSM1_gs = sOT.gs ; /* source conductance */ + + here->HSM1_von = model->HSM1_type * sOT.von; + here->HSM1_vdsat = model->HSM1_type * sOT.vdsat; + /* + here->HSM1_von = sOT.von; + here->HSM1_vdsat = sOT.vdsat; + */ + cdrain = here->HSM1_ids = sOT.ids ; /* cdrain */ + + here->HSM1_gds = sOT.gds ; + here->HSM1_gm = sOT.gm ; + here->HSM1_gmbs = sOT.gmbs ; + + /* overlap capacitances */ + here->HSM1_cgso = sOT.cgso ; /* G-S */ + here->HSM1_cgdo = sOT.cgdo ; /* G-D */ + here->HSM1_cgbo = sOT.cgbo ; /* G-B */ + + /* capop */ + /* pslot->capop = 13 ; capacitor selector ??? + * no use in SPICE3f5 */ + + /* Meyer's capacitances */ + /* + here->HSM1_capgs = sOT.capgs ; + here->HSM1_capgd = sOT.capgd ; + here->HSM1_capgb = sOT.capgb ; may be not necessary */ + + /* intrinsic charge ONLY */ + qgate = here->HSM1_qg = sOT.qg ; /* gate */ + qdrn = here->HSM1_qd = sOT.qd ; /* drain */ + /* here->HSM1_qs = sOT.qs ; source */ + qbulk = here->HSM1_qb = -1.0 * ( sOT.qg + sOT.qd + sOT.qs ); /* bulk */ + + /* charge caps (intrisic ONLY) */ + here->HSM1_cggb = sOT.cggb ; + here->HSM1_cgsb = sOT.cgsb ; + here->HSM1_cgdb = sOT.cgdb ; + here->HSM1_cbgb = sOT.cbgb ; + here->HSM1_cbsb = sOT.cbsb ; + here->HSM1_cbdb = sOT.cbdb ; + here->HSM1_cdgb = sOT.cdgb ; + here->HSM1_cdsb = sOT.cdsb ; + here->HSM1_cddb = sOT.cddb ; + + /* substrate diode */ + here->HSM1_ibd = sOT.ibd ; + here->HSM1_ibs = sOT.ibs ; + /* + here->HSM1_ibd = model->HSM1_type * sOT.ibd ; + here->HSM1_ibs = model->HSM1_type * sOT.ibs ; + */ + here->HSM1_gbd = sOT.gbd ; + here->HSM1_gbs = sOT.gbs ; + here->HSM1_capbd = sOT.capbd ; + here->HSM1_capbs = sOT.capbs ; + *(ckt->CKTstate0 + here->HSM1qbd) = sOT.qbd ; + *(ckt->CKTstate0 + here->HSM1qbs) = sOT.qbs ; + + /* substrate impact ionization current */ + here->HSM1_isub = sOT.isub ; + here->HSM1_gbgs = sOT.gbgs ; + here->HSM1_gbds = sOT.gbds ; + here->HSM1_gbbs = sOT.gbbs ; + + /* 1/f noise */ + /* here->HSM1_nois_idsfl = sOT.nois_idsfl ;*/ + + /* mobility added by K.M. */ + here->HSM1_mu = sOT.mu; + + /* print all outputs ------------VV */ + if ( sIN.info >= 4 ) { + printf( "--- variables returned from HSM1evaluate() ----\n" ) ; + printf( "gd = %12.5e\n" , sOT.gd ) ; + printf( "gs = %12.5e\n" , sOT.gs ) ; + + printf( "von = %12.5e\n" , sOT.von ) ; + printf( "vdsat = %12.5e\n" , sOT.vdsat ) ; + printf( "ids = %12.5e\n" , sOT.ids ) ; + + printf( "gds = %12.5e\n" , sOT.gds ) ; + printf( "gm = %12.5e\n" , sOT.gm ) ; + printf( "gmbs = %12.5e\n" , sOT.gmbs ) ; + + printf( "cgbo = %12.5e\n" , sOT.cgbo ) ; + + printf( "capgs = %12.5e\n" , sOT.capgs ) ; + printf( "capgd = %12.5e\n" , sOT.capgd ) ; + printf( "capgb = %12.5e\n" , sOT.capgb ) ; + + printf( "qg = %12.5e\n" , sOT.qg ) ; + printf( "qd = %12.5e\n" , sOT.qd ) ; + printf( "qs = %12.5e\n" , sOT.qs ) ; + + printf( "cggb = %12.5e\n" , sOT.cggb ) ; + printf( "cgsb = %12.5e\n" , sOT.cgsb ) ; + printf( "cgdb = %12.5e\n" , sOT.cgdb ) ; + printf( "cbgb = %12.5e\n" , sOT.cbgb ) ; + printf( "cbsb = %12.5e\n" , sOT.cbsb ) ; + printf( "cbdb = %12.5e\n" , sOT.cbdb ) ; + printf( "cdgb = %12.5e\n" , sOT.cdgb ) ; + printf( "cdsb = %12.5e\n" , sOT.cdsb ) ; + printf( "cddb = %12.5e\n" , sOT.cddb ) ; + + printf( "ibd = %12.5e\n" , sOT.ibd ) ; + printf( "ibs = %12.5e\n" , sOT.ibs ) ; + printf( "gbd = %12.5e\n" , sOT.gbd ) ; + printf( "gbs = %12.5e\n" , sOT.gbs ) ; + printf( "capbd = %12.5e\n" , sOT.capbd ) ; + printf( "capbs = %12.5e\n" , sOT.capbs ) ; + printf( "qbd = %12.5e\n" , sOT.qbd ) ; + printf( "qbs = %12.5e\n" , sOT.qbs ) ; + + printf( "isub = %12.5e\n" , sOT.isub ) ; + printf( "gbgs = %12.5e\n" , sOT.gbgs ) ; + printf( "gbds = %12.5e\n" , sOT.gbds ) ; + printf( "gbbs = %12.5e\n" , sOT.gbbs ) ; + + /* printf( "flicker noise = %12.5e\n" , sOT.nois_idsfl ) ;*/ + printf( "flicker noise = %12.5e\n" , sOT.nf ) ; + } + /* print all outputs ------------AA */ + + if ( sIN.info >= 3 ) { /* physical valiables vs bias */ + static int isFirst = 1; + if (isFirst) { + printf("# vbs vds vgs cggb cgdb cgsb cbgb cbdb cbsb cdgb cddb cdsb, Ps0 Psl\n"); + isFirst = 0; + } + printf("%12.5e %12.5e %12.5e %12.5e %12.5e %12.5e %12.5e %12.5e %12.5e %12.5e %12.5e %12.5e %12.5e %12.5e\n", + vbs, vds, vgs , + sOT.cggb, sOT.cgdb, sOT.cgsb, + sOT.cbgb, sOT.cbdb, sOT.cbsb, + sOT.cdgb, sOT.cddb, sOT.cdsb, + sOT.ps0, sOT.ps0 + sOT.pds); + + } + + /* + * check convergence + */ + if ( (here->HSM1_off == 0) || !(ckt->CKTmode & MODEINITFIX) ) { + if (Check == 1) { + ckt->CKTnoncon++; + } + } + *(ckt->CKTstate0 + here->HSM1vbs) = vbs; + *(ckt->CKTstate0 + here->HSM1vbd) = vbd; + *(ckt->CKTstate0 + here->HSM1vgs) = vgs; + *(ckt->CKTstate0 + here->HSM1vds) = vds; + + if (model->HSM1_show_Given && showPhysVal) { + static int isFirst = 1; + ShowPhysVals(here, model->HSM1_show, isFirst, vds, vgs, vbs); + if (isFirst) isFirst = 0; + } + + /* bulk and channel charge plus overlaps */ + + if (!ChargeComputationNeeded) goto line850; + + line755: + cgdo = here->HSM1_cgdo; + cgso = here->HSM1_cgso; + cgbo = here->HSM1_cgbo; + + ag0 = ckt->CKTag[0]; + if (here->HSM1_mode > 0) { /* NORAMAL mode */ + gcggb = (here->HSM1_cggb + cgdo + cgso + cgbo ) * ag0; + gcgdb = (here->HSM1_cgdb - cgdo) * ag0; + gcgsb = (here->HSM1_cgsb - cgso) * ag0; + + gcdgb = (here->HSM1_cdgb - cgdo) * ag0; + gcddb = (here->HSM1_cddb + here->HSM1_capbd + cgdo) * ag0; + gcdsb = here->HSM1_cdsb * ag0; + + gcsgb = -(here->HSM1_cggb + here->HSM1_cbgb + + here->HSM1_cdgb + cgso) * ag0; + gcsdb = -(here->HSM1_cgdb + here->HSM1_cbdb + + here->HSM1_cddb) * ag0; + gcssb = (here->HSM1_capbs + cgso - + (here->HSM1_cgsb + here->HSM1_cbsb + here->HSM1_cdsb)) * ag0; + + gcbgb = (here->HSM1_cbgb - cgbo) * ag0; + gcbdb = (here->HSM1_cbdb - here->HSM1_capbd) * ag0; + gcbsb = (here->HSM1_cbsb - here->HSM1_capbs) * ag0; + + if (sIN.coadov != 1) { + qgd = cgdo * vgd; + qgs = cgso * vgs; + qgb = cgbo * vgb; + qgate += qgd + qgs + qgb; + qbulk -= qgb; + qdrn -= qgd; + /* qsrc = -(qgate + qbulk + qdrn); */ + } + } + else { /* REVERSE mode */ + gcggb = (here->HSM1_cggb + cgdo + cgso + cgbo ) * ag0; + gcgdb = (here->HSM1_cgsb - cgdo) * ag0; + gcgsb = (here->HSM1_cgdb - cgso) * ag0; + + gcdgb = -(here->HSM1_cggb + + here->HSM1_cbgb + here->HSM1_cdgb + cgdo) * ag0; + gcddb = (here->HSM1_capbd + cgdo - + (here->HSM1_cgsb + here->HSM1_cbsb + here->HSM1_cdsb)) * ag0; + gcdsb = -(here->HSM1_cgdb + here->HSM1_cbdb + here->HSM1_cddb) * ag0; + + gcsgb = (here->HSM1_cdgb - cgso) * ag0; + gcsdb = here->HSM1_cdsb * ag0; + gcssb = (here->HSM1_cddb + here->HSM1_capbs + cgso) * ag0; + + gcbgb = (here->HSM1_cbgb - cgbo) * ag0; + gcbdb = (here->HSM1_cbsb - here->HSM1_capbd) * ag0; + gcbsb = (here->HSM1_cbdb - here->HSM1_capbs) * ag0; + + if (sIN.coadov != 1) { + qgd = cgdo * vgd; + qgs = cgso * vgs; + qgb = cgbo * vgb; + qgate += qgd + qgs + qgb; + qbulk -= qgb; + qsrc = qdrn - qgs; + qdrn = -(qgate + qbulk + qsrc); + } + else { + qdrn = -(qgate + qbulk + qdrn); + } + } + + if (ByPass) goto line860; + + *(ckt->CKTstate0 + here->HSM1qg) = qgate; + *(ckt->CKTstate0 + here->HSM1qd) = qdrn - *(ckt->CKTstate0 + here->HSM1qbd); + *(ckt->CKTstate0 + here->HSM1qb) = + qbulk + *(ckt->CKTstate0 + here->HSM1qbd) + *(ckt->CKTstate0 + here->HSM1qbs); + + /* + printf( "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\n" ) ; + printf( "HSM1qg = %12.5e\n" , *(ckt->CKTstate0 + here->HSM1qg) ) ; + printf( "HSM1qd = %12.5e\n" , *(ckt->CKTstate0 + here->HSM1qd) ) ; + printf( "HSM1qb = %12.5e\n" , *(ckt->CKTstate0 + here->HSM1qb) ) ; + printf( "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\n" ) ; + */ + + /* store small signal parameters */ + if (ckt->CKTmode & MODEINITSMSIG) goto line1000; + if (!ChargeComputationNeeded) goto line850; + + if (ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->HSM1qb) = *(ckt->CKTstate0 + here->HSM1qb); + *(ckt->CKTstate1 + here->HSM1qg) = *(ckt->CKTstate0 + here->HSM1qg); + *(ckt->CKTstate1 + here->HSM1qd) = *(ckt->CKTstate0 + here->HSM1qd); + } + + if ((error = NIintegrate(ckt, &geq, &ceq, 0.0, here->HSM1qb))) return(error); + if ((error = NIintegrate(ckt, &geq, &ceq, 0.0, here->HSM1qg))) return(error); + if ((error = NIintegrate(ckt, &geq, &ceq, 0.0, here->HSM1qd))) return(error); + + goto line860; + + line850: + /* initialize to zero charge conductance and current */ + ceqqg = ceqqb = ceqqd = 0.0; + + gcdgb = gcddb = gcdsb = 0.0; + gcsgb = gcsdb = gcssb = 0.0; + gcggb = gcgdb = gcgsb = 0.0; + gcbgb = gcbdb = gcbsb = 0.0; + + goto line900; + + line860: + /* evaluate equivalent charge current */ + + cqgate = *(ckt->CKTstate0 + here->HSM1cqg); + cqbulk = *(ckt->CKTstate0 + here->HSM1cqb); + cqdrn = *(ckt->CKTstate0 + here->HSM1cqd); + + /* + printf( "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\n" ) ; + printf( "cqgate = %12.5e\n" , cqgate ) ; + printf( "cqbulk = %12.5e\n" , cqbulk ) ; + printf( "cqdrn = %12.5e\n" , cqdrn ) ; + printf( "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\n" ) ; + */ + + ceqqg = cqgate - gcggb * vgb + gcgdb * vbd + gcgsb * vbs; + ceqqb = cqbulk - gcbgb * vgb + gcbdb * vbd + gcbsb * vbs; + ceqqd = cqdrn - gcdgb * vgb + gcddb * vbd + gcdsb * vbs; + + if (ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->HSM1cqb) = *(ckt->CKTstate0 + here->HSM1cqb); + *(ckt->CKTstate1 + here->HSM1cqg) = *(ckt->CKTstate0 + here->HSM1cqg); + *(ckt->CKTstate1 + here->HSM1cqd) = *(ckt->CKTstate0 + here->HSM1cqd); + } + + /* + * load current vector + */ + line900: + + m = here->HSM1_m; + + if (here->HSM1_mode >= 0) { /* NORMAL mode */ + gm = here->HSM1_gm; + gmbs = here->HSM1_gmbs; + FwdSum = gm + gmbs; + RevSum = 0.0; + + cdreq = model->HSM1_type * + (cdrain - here->HSM1_gds * vds - gm * vgs - gmbs * vbs); + ceqbd = -model->HSM1_type * + (here->HSM1_isub - here->HSM1_gbds * vds - here->HSM1_gbgs * vgs + - here->HSM1_gbbs * vbs); + ceqbs = 0.0; + + gbbdp = -here->HSM1_gbds; + gbbsp = here->HSM1_gbds + here->HSM1_gbgs + here->HSM1_gbbs; + + gbdpg = here->HSM1_gbgs; + gbdpdp = here->HSM1_gbds; + gbdpb = here->HSM1_gbbs; + gbdpsp = -(gbdpg + gbdpdp + gbdpb); + + gbspg = 0.0; + gbspdp = 0.0; + gbspb = 0.0; + gbspsp = 0.0; + } + else { /* REVERSE mode */ + gm = -here->HSM1_gm; + gmbs = -here->HSM1_gmbs; + FwdSum = 0.0; + RevSum = -(gm + gmbs); + + cdreq = -model->HSM1_type * + (cdrain + here->HSM1_gds * vds + gm * vgd + gmbs * vbd); + ceqbs = -model->HSM1_type * + (here->HSM1_isub + here->HSM1_gbds * vds - here->HSM1_gbgs * vgd + - here->HSM1_gbbs * vbd); + ceqbd = 0.0; + + gbbsp = -here->HSM1_gbds; + gbbdp = here->HSM1_gbds + here->HSM1_gbgs + here->HSM1_gbbs; + + gbdpg = 0.0; + gbdpsp = 0.0; + gbdpb = 0.0; + gbdpdp = 0.0; + + gbspg = here->HSM1_gbgs; + gbspsp = here->HSM1_gbds; + gbspb = here->HSM1_gbbs; + gbspdp = -(gbspg + gbspsp + gbspb); + } + + if (model->HSM1_type > 0) { + ceqbs += here->HSM1_ibs - here->HSM1_gbs * vbs; + ceqbd += here->HSM1_ibd - here->HSM1_gbd * vbd; + } + else { + ceqbs -= here->HSM1_ibs - here->HSM1_gbs * vbs; + ceqbd -= here->HSM1_ibd - here->HSM1_gbd * vbd; + ceqqg = -ceqqg; + ceqqb = -ceqqb; + ceqqd = -ceqqd; + } + + /* + printf( "----------------------------------------------------\n" ) ; + printf( "ceqqg = %12.5e\n" , ceqqg ) ; + printf( "....................................................\n" ) ; + printf( "ceqbs = %12.5e\n" , ceqbs ) ; + printf( "ceqbd = %12.5e\n" , ceqbd ) ; + printf( "ceqqb = %12.5e\n" , ceqqb ) ; + printf( "....................................................\n" ) ; + printf( "ceqbd = %12.5e\n" , ceqbd ) ; + printf( "cdreq = %12.5e\n" , cdreq ) ; + printf( "ceqqd = %12.5e\n" , ceqqd ) ; + printf( "----------------------------------------------------\n" ) ; + */ + + *(ckt->CKTrhs + here->HSM1gNode) -= m * ceqqg; + *(ckt->CKTrhs + here->HSM1bNode) -= m * (ceqbs + ceqbd + ceqqb); + *(ckt->CKTrhs + here->HSM1dNodePrime) += m * (ceqbd - cdreq - ceqqd); + *(ckt->CKTrhs + here->HSM1sNodePrime) += m * (cdreq + + ceqbs + ceqqg + ceqqb + ceqqd); + + /* + * load y matrix + */ + + *(here->HSM1DdPtr) += m * here->HSM1drainConductance; + *(here->HSM1GgPtr) += m * gcggb; + *(here->HSM1SsPtr) += m * here->HSM1sourceConductance; + *(here->HSM1BbPtr) += m * (here->HSM1_gbd + here->HSM1_gbs + - gcbgb - gcbdb - gcbsb - here->HSM1_gbbs); + *(here->HSM1DPdpPtr) += m * (here->HSM1drainConductance + + here->HSM1_gds + here->HSM1_gbd + RevSum + gcddb + gbdpdp); + *(here->HSM1SPspPtr) += m * (here->HSM1sourceConductance + + here->HSM1_gds + here->HSM1_gbs + FwdSum + gcssb + gbspsp); + *(here->HSM1DdpPtr) -= m * here->HSM1drainConductance; + *(here->HSM1GbPtr) -= m * (gcggb + gcgdb + gcgsb); + *(here->HSM1GdpPtr) += m * gcgdb; + *(here->HSM1GspPtr) += m * gcgsb; + *(here->HSM1SspPtr) -= m * here->HSM1sourceConductance; + *(here->HSM1BgPtr) += m * (gcbgb - here->HSM1_gbgs); + *(here->HSM1BdpPtr) += m * (gcbdb - here->HSM1_gbd + gbbdp); + *(here->HSM1BspPtr) += m * (gcbsb - here->HSM1_gbs + gbbsp); + *(here->HSM1DPdPtr) -= m * here->HSM1drainConductance; + *(here->HSM1DPgPtr) += m * (gm + gcdgb + gbdpg); + *(here->HSM1DPbPtr) -= m * (here->HSM1_gbd - gmbs + gcdgb + gcddb + gcdsb - gbdpb); + *(here->HSM1DPspPtr) -= m * (here->HSM1_gds + FwdSum - gcdsb - gbdpsp); + *(here->HSM1SPgPtr) += m * (gcsgb - gm + gbspg); + *(here->HSM1SPsPtr) -= m * here->HSM1sourceConductance; + *(here->HSM1SPbPtr) -= m * (here->HSM1_gbs + gmbs + gcsgb + gcsdb + gcssb - gbspb); + *(here->HSM1SPdpPtr) -= m * (here->HSM1_gds + RevSum - gcsdb - gbspdp); + + line1000: + ; + + } /* End of MOSFET Instance */ + } /* End of Model Instance */ + return(OK); +} diff --git a/src/spicelib/devices/hisim/hsm1mask.c b/src/spicelib/devices/hisim/hsm1mask.c new file mode 100644 index 000000000..e54592b19 --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1mask.c @@ -0,0 +1,379 @@ +/*********************************************************************** + HiSIM v1.1.0 + File: hsm1mask.c of HiSIM v1.1.0 + + Copyright (C) 2002 STARC + + June 30, 2002: developed by Hiroshima University and STARC + June 30, 2002: posted by Keiichi MORIKAWA, STARC Physical Design Group +***********************************************************************/ + +/* + * Modified by Paolo Nenzi 2002 + * ngspice integration + */ + +#include "ngspice.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "hsm1def.h" +#include "sperror.h" +#include "suffix.h" + +int HSM1mAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value) +{ + HSM1model *model = (HSM1model *)inst; + switch (which) { + case HSM1_MOD_NMOS: + value->iValue = model->HSM1_type; + return(OK); + case HSM1_MOD_PMOS: + value->iValue = model->HSM1_type; + return(OK); + case HSM1_MOD_LEVEL: + value->iValue = model->HSM1_level; + return(OK); + case HSM1_MOD_INFO: + value->iValue = model->HSM1_info; + return(OK); + case HSM1_MOD_NOISE: + value->iValue = model->HSM1_noise; + return(OK); + case HSM1_MOD_VERSION: + value->iValue = model->HSM1_version; + return(OK); + case HSM1_MOD_SHOW: + value->iValue = model->HSM1_show; + return(OK); + case HSM1_MOD_CORSRD: + value->iValue = model->HSM1_corsrd; + return(OK); + case HSM1_MOD_COIPRV: + value->iValue = model->HSM1_coiprv; + return(OK); + case HSM1_MOD_COPPRV: + value->iValue = model->HSM1_copprv; + return(OK); + case HSM1_MOD_COCGSO: + value->iValue = model->HSM1_cocgso; + return(OK); + case HSM1_MOD_COCGDO: + value->iValue = model->HSM1_cocgdo; + return(OK); + case HSM1_MOD_COCGBO: + value->rValue = model->HSM1_cocgbo; + return(OK); + case HSM1_MOD_COADOV: + value->iValue = model->HSM1_coadov; + return(OK); + case HSM1_MOD_COXX08: + value->iValue = model->HSM1_coxx08; + return(OK); + case HSM1_MOD_COXX09: + value->iValue = model->HSM1_coxx09; + return(OK); + case HSM1_MOD_COISUB: + value->iValue = model->HSM1_coisub; + return(OK); + case HSM1_MOD_COIIGS: + value->iValue = model->HSM1_coiigs; + return(OK); + case HSM1_MOD_COGIDL: + value->iValue = model->HSM1_cogidl; + return(OK); + case HSM1_MOD_COOVLP: + value->iValue = model->HSM1_coovlp; + return(OK); + case HSM1_MOD_CONOIS: + value->iValue = model->HSM1_conois; + return(OK); + case HSM1_MOD_COISTI: /* HiSIM1.1 */ + value->iValue = model->HSM1_coisti; + return(OK); + case HSM1_MOD_VMAX: + value->rValue = model->HSM1_vmax; + return(OK); + case HSM1_MOD_BGTMP1: + value->rValue = model->HSM1_bgtmp1; + return(OK); + case HSM1_MOD_BGTMP2: + value->rValue = model->HSM1_bgtmp2; + return(OK); + case HSM1_MOD_TOX: + value->rValue = model->HSM1_tox; + return(OK); + case HSM1_MOD_DL: + value->rValue = model->HSM1_dl; + return(OK); + case HSM1_MOD_DW: + value->rValue = model->HSM1_dw; + return(OK); + case HSM1_MOD_XJ: /* HiSIM1.0 */ + value->rValue = model->HSM1_xj; + return(OK); + case HSM1_MOD_XQY: /* HiSIM1.1 */ + value->rValue = model->HSM1_xqy; + return(OK); + case HSM1_MOD_RS: + value->rValue = model->HSM1_rs; + return(OK); + case HSM1_MOD_RD: + value->rValue = model->HSM1_rd; + return(OK); + case HSM1_MOD_VFBC: + value->rValue = model->HSM1_vfbc; + return(OK); + case HSM1_MOD_NSUBC: + value->rValue = model->HSM1_nsubc; + return(OK); + case HSM1_MOD_PARL1: + value->rValue = model->HSM1_parl1; + return(OK); + case HSM1_MOD_PARL2: + value->rValue = model->HSM1_parl2; + return(OK); + case HSM1_MOD_LP: + value->rValue = model->HSM1_lp; + return(OK); + case HSM1_MOD_NSUBP: + value->rValue = model->HSM1_nsubp; + return(OK); + case HSM1_MOD_SCP1: + value->rValue = model->HSM1_scp1; + return(OK); + case HSM1_MOD_SCP2: + value->rValue = model->HSM1_scp2; + return(OK); + case HSM1_MOD_SCP3: + value->rValue = model->HSM1_scp3; + return(OK); + case HSM1_MOD_SC1: + value->rValue = model->HSM1_sc1; + return(OK); + case HSM1_MOD_SC2: + value->rValue = model->HSM1_sc2; + return(OK); + case HSM1_MOD_SC3: + value->rValue = model->HSM1_sc3; + return(OK); + case HSM1_MOD_PGD1: + value->rValue = model->HSM1_pgd1; + return(OK); + case HSM1_MOD_PGD2: + value->rValue = model->HSM1_pgd2; + return(OK); + case HSM1_MOD_PGD3: + value->rValue = model->HSM1_pgd3; + return(OK); + case HSM1_MOD_NDEP: + value->rValue = model->HSM1_ndep; + return(OK); + case HSM1_MOD_NINV: + value->rValue = model->HSM1_ninv; + return(OK); + case HSM1_MOD_NINVD: + value->rValue = model->HSM1_ninvd; + return(OK); + case HSM1_MOD_MUECB0: + value->rValue = model->HSM1_muecb0; + return(OK); + case HSM1_MOD_MUECB1: + value->rValue = model->HSM1_muecb1; + return(OK); + case HSM1_MOD_MUEPH1: + value->rValue = model->HSM1_mueph1; + return(OK); + case HSM1_MOD_MUEPH0: + value->rValue = model->HSM1_mueph0; + return(OK); + case HSM1_MOD_MUEPH2: + value->rValue = model->HSM1_mueph2; + return(OK); + case HSM1_MOD_W0: + value->rValue = model->HSM1_w0; + return(OK); + case HSM1_MOD_MUESR1: + value->rValue = model->HSM1_muesr1; + return(OK); + case HSM1_MOD_MUESR0: + value->rValue = model->HSM1_muesr0; + return(OK); + case HSM1_MOD_BB: + value->rValue = model->HSM1_bb; + return(OK); + case HSM1_MOD_VDS0: + value->rValue = model->HSM1_vds0; + return(OK); + case HSM1_MOD_BC0: + value->rValue = model->HSM1_bc0; + return(OK); + case HSM1_MOD_BC1: + value->rValue = model->HSM1_bc1; + return(OK); + case HSM1_MOD_SUB1: + value->rValue = model->HSM1_sub1; + return(OK); + case HSM1_MOD_SUB2: + value->rValue = model->HSM1_sub2; + return(OK); + case HSM1_MOD_SUB3: + value->rValue = model->HSM1_sub3; + return(OK); + case HSM1_MOD_WVTHSC: /* HiSIM1.1 */ + value->rValue = model->HSM1_wvthsc; + return(OK); + case HSM1_MOD_NSTI: /* HiSIM1.1 */ + value->rValue = model->HSM1_nsti; + return(OK); + case HSM1_MOD_WSTI: /* HiSIM1.1 */ + value->rValue = model->HSM1_wsti; + return(OK); + case HSM1_MOD_CGSO: + value->rValue = model->HSM1_cgso; + return(OK); + case HSM1_MOD_CGDO: + value->rValue = model->HSM1_cgdo; + return(OK); + case HSM1_MOD_CGBO: + value->rValue = model->HSM1_cgbo; + return(OK); + case HSM1_MOD_TPOLY: + value->rValue = model->HSM1_tpoly; + return(OK); + case HSM1_MOD_JS0: + value->rValue = model->HSM1_js0; + return(OK); + case HSM1_MOD_JS0SW: + value->rValue = model->HSM1_js0sw; + return(OK); + case HSM1_MOD_NJ: + value->rValue = model->HSM1_nj; + return(OK); + case HSM1_MOD_NJSW: + value->rValue = model->HSM1_njsw; + return(OK); + case HSM1_MOD_XTI: + value->rValue = model->HSM1_xti; + return(OK); + case HSM1_MOD_CJ: + value->rValue = model->HSM1_cj; + return(OK); + case HSM1_MOD_CJSW: + value->rValue = model->HSM1_cjsw; + return(OK); + case HSM1_MOD_CJSWG: + value->rValue = model->HSM1_cjswg; + return(OK); + case HSM1_MOD_MJ: + value->rValue = model->HSM1_mj; + return(OK); + case HSM1_MOD_MJSW: + value->rValue = model->HSM1_mjsw; + return(OK); + case HSM1_MOD_MJSWG: + value->rValue = model->HSM1_mjswg; + return(OK); + case HSM1_MOD_PB: + value->rValue = model->HSM1_pbsw; + return(OK); + case HSM1_MOD_PBSW: + value->rValue = model->HSM1_pbsw; + return(OK); + case HSM1_MOD_PBSWG: + value->rValue = model->HSM1_pbswg; + return(OK); + case HSM1_MOD_XPOLYD: + value->rValue = model->HSM1_xpolyd; + return(OK); + case HSM1_MOD_CLM1: + value->rValue = model->HSM1_clm1; + return(OK); + case HSM1_MOD_CLM2: + value->rValue = model->HSM1_clm2; + return(OK); + case HSM1_MOD_CLM3: + value->rValue = model->HSM1_clm3; + return(OK); + case HSM1_MOD_MUETMP: + value->rValue = model->HSM1_muetmp; + return(OK); + case HSM1_MOD_RPOCK1: + value->rValue = model->HSM1_rpock1; + return(OK); + case HSM1_MOD_RPOCK2: + value->rValue = model->HSM1_rpock2; + return(OK); + case HSM1_MOD_RPOCP1: /* HiSIM1.1 */ + value->rValue = model->HSM1_rpocp1; + return(OK); + case HSM1_MOD_RPOCP2: /* HiSIM1.1 */ + value->rValue = model->HSM1_rpocp2; + return(OK); + case HSM1_MOD_VOVER: + value->rValue = model->HSM1_vover; + return(OK); + case HSM1_MOD_VOVERP: + value->rValue = model->HSM1_voverp; + return(OK); + case HSM1_MOD_WFC: + value->rValue = model->HSM1_wfc; + return(OK); + case HSM1_MOD_QME1: + value->rValue = model->HSM1_qme1; + return(OK); + case HSM1_MOD_QME2: + value->rValue = model->HSM1_qme2; + return(OK); + case HSM1_MOD_QME3: + value->rValue = model->HSM1_qme3; + return(OK); + case HSM1_MOD_GIDL1: + value->rValue = model->HSM1_gidl1; + return(OK); + case HSM1_MOD_GIDL2: + value->rValue = model->HSM1_gidl2; + return(OK); + case HSM1_MOD_GIDL3: + value->rValue = model->HSM1_gidl3; + return(OK); + case HSM1_MOD_GLEAK1: + value->rValue = model->HSM1_gleak1; + return(OK); + case HSM1_MOD_GLEAK2: + value->rValue = model->HSM1_gleak2; + return(OK); + case HSM1_MOD_GLEAK3: + value->rValue = model->HSM1_gleak3; + return(OK); + case HSM1_MOD_VZADD0: + value->rValue = model->HSM1_vzadd0; + return(OK); + case HSM1_MOD_PZADD0: + value->rValue = model->HSM1_pzadd0; + return(OK); + case HSM1_MOD_NFTRP: + value->rValue = model->HSM1_nftrp; + return(OK); + case HSM1_MOD_NFALP: + value->rValue = model->HSM1_nfalp; + return(OK); + case HSM1_MOD_CIT: + value->rValue = model->HSM1_cit; + return(OK); + case HSM1_MOD_KF: + value->rValue = model->HSM1_kf; + return(OK); + case HSM1_MOD_AF: + value->rValue = model->HSM1_af; + return(OK); + case HSM1_MOD_EF: + value->rValue = model->HSM1_ef; + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + + diff --git a/src/spicelib/devices/hisim/hsm1mdel.c b/src/spicelib/devices/hisim/hsm1mdel.c new file mode 100644 index 000000000..7b099d224 --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1mdel.c @@ -0,0 +1,48 @@ +/*********************************************************************** + HiSIM v1.1.0 + File: hsm1mdel.c of HiSIM v1.1.0 + + Copyright (C) 2002 STARC + + June 30, 2002: developed by Hiroshima University and STARC + June 30, 2002: posted by Keiichi MORIKAWA, STARC Physical Design Group +***********************************************************************/ + +/* + * Modified by Paolo Nenzi 2002 + * ngspice integration + */ + +#include "ngspice.h" +#include "hsm1def.h" +#include "sperror.h" +#include "suffix.h" + +int HSM1mDelete(GENmodel **inModel, IFuid modname, GENmodel *kill) +{ + HSM1model **model = (HSM1model**)inModel; + HSM1model *modfast = (HSM1model*)kill; + HSM1instance *here; + HSM1instance *prev = NULL; + HSM1model **oldmod; + + oldmod = model; + for ( ;*model ;model = &((*model)->HSM1nextModel) ) { + if ( (*model)->HSM1modName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + + delgot: + *oldmod = (*model)->HSM1nextModel; /* cut deleted device out of list */ + for ( here = (*model)->HSM1instances ; + here ;here = here->HSM1nextInstance ) { + if (prev) FREE(prev); + prev = here; + } + if (prev) FREE(prev); + FREE(*model); + return(OK); +} + diff --git a/src/spicelib/devices/hisim/hsm1mpar.c b/src/spicelib/devices/hisim/hsm1mpar.c new file mode 100644 index 000000000..05310421a --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1mpar.c @@ -0,0 +1,495 @@ +/*********************************************************************** + HiSIM v1.1.0 + File: hsm1mpar.c of HiSIM v1.1.0 + + Copyright (C) 2002 STARC + + June 30, 2002: developed by Hiroshima University and STARC + June 30, 2002: posted by Keiichi MORIKAWA, STARC Physical Design Group +***********************************************************************/ + +/* + * Modified by Paolo Nenzi 2002 + * ngspice integration + */ + +#include "ngspice.h" +#include "hsm1def.h" +#include "ifsim.h" +#include "sperror.h" +#include "suffix.h" + +int HSM1mParam(int param, IFvalue *value, GENmodel *inMod) +{ + HSM1model *mod = (HSM1model*)inMod; + switch (param) { + case HSM1_MOD_NMOS : + if (value->iValue) { + mod->HSM1_type = 1; + mod->HSM1_type_Given = TRUE; + } + break; + case HSM1_MOD_PMOS : + if (value->iValue) { + mod->HSM1_type = - 1; + mod->HSM1_type_Given = TRUE; + } + break; + case HSM1_MOD_LEVEL: + mod->HSM1_level = value->iValue; + mod->HSM1_level_Given = TRUE; + break; + case HSM1_MOD_INFO: + mod->HSM1_info = value->iValue; + mod->HSM1_info_Given = TRUE; + break; + case HSM1_MOD_NOISE: + mod->HSM1_noise = value->iValue; + mod->HSM1_noise_Given = TRUE; + break; + case HSM1_MOD_VERSION: + mod->HSM1_version = value->iValue; + mod->HSM1_version_Given = TRUE; + break; + case HSM1_MOD_SHOW: + mod->HSM1_show = value->iValue; + mod->HSM1_show_Given = TRUE; + break; + case HSM1_MOD_CORSRD: + mod->HSM1_corsrd = value->iValue; + mod->HSM1_corsrd_Given = TRUE; + break; + case HSM1_MOD_COIPRV: + mod->HSM1_coiprv = value->iValue; + mod->HSM1_coiprv_Given = TRUE; + break; + case HSM1_MOD_COPPRV: + mod->HSM1_copprv = value->iValue; + mod->HSM1_copprv_Given = TRUE; + break; + case HSM1_MOD_COCGSO: + mod->HSM1_cocgso = value->iValue; + mod->HSM1_cocgso_Given = TRUE; + break; + case HSM1_MOD_COCGDO: + mod->HSM1_cocgdo = value->iValue; + mod->HSM1_cocgdo_Given = TRUE; + break; + case HSM1_MOD_COCGBO: + mod->HSM1_cocgbo = value->iValue; + mod->HSM1_cocgbo_Given = TRUE; + break; + case HSM1_MOD_COADOV: + mod->HSM1_coadov = value->iValue; + mod->HSM1_coadov_Given = TRUE; + break; + case HSM1_MOD_COXX08: + mod->HSM1_coxx08 = value->iValue; + mod->HSM1_coxx08_Given = TRUE; + break; + case HSM1_MOD_COXX09: + mod->HSM1_coxx09 = value->iValue; + mod->HSM1_coxx09_Given = TRUE; + break; + case HSM1_MOD_COISUB: + mod->HSM1_coisub = value->iValue; + mod->HSM1_coisub_Given = TRUE; + break; + case HSM1_MOD_COIIGS: + mod->HSM1_coiigs = value->iValue; + mod->HSM1_coiigs_Given = TRUE; + break; + case HSM1_MOD_COGIDL: + mod->HSM1_cogidl = value->iValue; + mod->HSM1_cogidl_Given = TRUE; + break; + case HSM1_MOD_COOVLP: + mod->HSM1_coovlp = value->iValue; + mod->HSM1_coovlp_Given = TRUE; + break; + case HSM1_MOD_CONOIS: /* HiSIM1.1 */ + mod->HSM1_conois = value->iValue; + mod->HSM1_conois_Given = TRUE; + break; + case HSM1_MOD_COISTI: + mod->HSM1_coisti = value->iValue; + mod->HSM1_coisti_Given = TRUE; + break; + case HSM1_MOD_VMAX: + mod->HSM1_vmax = value->rValue; + mod->HSM1_vmax_Given = TRUE; + break; + case HSM1_MOD_BGTMP1: + mod->HSM1_bgtmp1 = value->rValue; + mod->HSM1_bgtmp1_Given = TRUE; + break; + case HSM1_MOD_BGTMP2: + mod->HSM1_bgtmp2 = value->rValue; + mod->HSM1_bgtmp2_Given = TRUE; + break; + case HSM1_MOD_TOX: + mod->HSM1_tox = value->rValue; + mod->HSM1_tox_Given = TRUE; + break; + case HSM1_MOD_DL: + mod->HSM1_dl = value->rValue; + mod->HSM1_dl_Given = TRUE; + break; + case HSM1_MOD_DW: + mod->HSM1_dw = value->rValue; + mod->HSM1_dw_Given = TRUE; + break; + case HSM1_MOD_XJ: /* HiSIM1.0 */ + mod->HSM1_xj = value->rValue; + mod->HSM1_xj_Given = TRUE; + break; + case HSM1_MOD_XQY: /* HiSIM1.1 */ + mod->HSM1_xqy = value->rValue; + mod->HSM1_xqy_Given = TRUE; + break; + case HSM1_MOD_RS: + mod->HSM1_rs = value->rValue; + mod->HSM1_rs_Given = TRUE; + break; + case HSM1_MOD_RD: + mod->HSM1_rd = value->rValue; + mod->HSM1_rd_Given = TRUE; + break; + case HSM1_MOD_VFBC: + mod->HSM1_vfbc = value->rValue; + mod->HSM1_vfbc_Given = TRUE; + break; + case HSM1_MOD_NSUBC: + mod->HSM1_nsubc = value->rValue; + mod->HSM1_nsubc_Given = TRUE; + break; + case HSM1_MOD_PARL1: + mod->HSM1_parl1 = value->rValue; + mod->HSM1_parl1_Given = TRUE; + break; + case HSM1_MOD_PARL2: + mod->HSM1_parl2 = value->rValue; + mod->HSM1_parl2_Given = TRUE; + break; + case HSM1_MOD_LP: + mod->HSM1_lp = value->rValue; + mod->HSM1_lp_Given = TRUE; + break; + case HSM1_MOD_NSUBP: + mod->HSM1_nsubp = value->rValue; + mod->HSM1_nsubp_Given = TRUE; + break; + case HSM1_MOD_SCP1: + mod->HSM1_scp1 = value->rValue; + mod->HSM1_scp1_Given = TRUE; + break; + case HSM1_MOD_SCP2: + mod->HSM1_scp2 = value->rValue; + mod->HSM1_scp2_Given = TRUE; + break; + case HSM1_MOD_SCP3: + mod->HSM1_scp3 = value->rValue; + mod->HSM1_scp3_Given = TRUE; + break; + case HSM1_MOD_SC1: + mod->HSM1_sc1 = value->rValue; + mod->HSM1_sc1_Given = TRUE; + break; + case HSM1_MOD_SC2: + mod->HSM1_sc2 = value->rValue; + mod->HSM1_sc2_Given = TRUE; + break; + case HSM1_MOD_SC3: + mod->HSM1_sc3 = value->rValue; + mod->HSM1_sc3_Given = TRUE; + break; + case HSM1_MOD_PGD1: + mod->HSM1_pgd1 = value->rValue; + mod->HSM1_pgd1_Given = TRUE; + break; + case HSM1_MOD_PGD2: + mod->HSM1_pgd2 = value->rValue; + mod->HSM1_pgd2_Given = TRUE; + break; + case HSM1_MOD_PGD3: + mod->HSM1_pgd3 = value->rValue; + mod->HSM1_pgd3_Given = TRUE; + break; + case HSM1_MOD_NDEP: + mod->HSM1_ndep = value->rValue; + mod->HSM1_ndep_Given = TRUE; + break; + case HSM1_MOD_NINV: + mod->HSM1_ninv = value->rValue; + mod->HSM1_ninv_Given = TRUE; + break; + case HSM1_MOD_NINVD: + mod->HSM1_ninvd = value->rValue; + mod->HSM1_ninvd_Given = TRUE; + break; + case HSM1_MOD_MUECB0: + mod->HSM1_muecb0 = value->rValue; + mod->HSM1_muecb0_Given = TRUE; + break; + case HSM1_MOD_MUECB1: + mod->HSM1_muecb1 = value->rValue; + mod->HSM1_muecb1_Given = TRUE; + break; + case HSM1_MOD_MUEPH1: + mod->HSM1_mueph1 = value->rValue; + mod->HSM1_mueph1_Given = TRUE; + break; + case HSM1_MOD_MUEPH0: + mod->HSM1_mueph0 = value->rValue; + mod->HSM1_mueph0_Given = TRUE; + break; + case HSM1_MOD_MUEPH2: + mod->HSM1_mueph2 = value->rValue; + mod->HSM1_mueph2_Given = TRUE; + break; + case HSM1_MOD_W0: + mod->HSM1_w0 = value->rValue; + mod->HSM1_w0_Given = TRUE; + break; + case HSM1_MOD_MUESR1: + mod->HSM1_muesr1 = value->rValue; + mod->HSM1_muesr1_Given = TRUE; + break; + case HSM1_MOD_MUESR0: + mod->HSM1_muesr0 = value->rValue; + mod->HSM1_muesr0_Given = TRUE; + break; + case HSM1_MOD_BB: + mod->HSM1_bb = value->rValue; + mod->HSM1_bb_Given = TRUE; + break; + case HSM1_MOD_VDS0: + mod->HSM1_vds0 = value->rValue; + mod->HSM1_vds0_Given = TRUE; + break; + case HSM1_MOD_BC0: + mod->HSM1_bc0 = value->rValue; + mod->HSM1_bc0_Given = TRUE; + break; + case HSM1_MOD_BC1: + mod->HSM1_bc1 = value->rValue; + mod->HSM1_bc1_Given = TRUE; + break; + case HSM1_MOD_SUB1: + mod->HSM1_sub1 = value->rValue; + mod->HSM1_sub1_Given = TRUE; + break; + case HSM1_MOD_SUB2: + mod->HSM1_sub2 = value->rValue; + mod->HSM1_sub2_Given = TRUE; + break; + case HSM1_MOD_SUB3: + mod->HSM1_sub3 = value->rValue; + mod->HSM1_sub3_Given = TRUE; + break; + case HSM1_MOD_WVTHSC: /* HiSIM1.1 */ + mod->HSM1_wvthsc = value->rValue; + mod->HSM1_wvthsc_Given = TRUE; + break; + case HSM1_MOD_NSTI: /* HiSIM1.1 */ + mod->HSM1_nsti = value->rValue; + mod->HSM1_nsti_Given = TRUE; + break; + case HSM1_MOD_WSTI: /* HiSIM1.1 */ + mod->HSM1_wsti = value->rValue; + mod->HSM1_wsti_Given = TRUE; + break; + case HSM1_MOD_CGSO: + mod->HSM1_cgso = value->rValue; + mod->HSM1_cgso_Given = TRUE; + break; + case HSM1_MOD_CGDO: + mod->HSM1_cgdo = value->rValue; + mod->HSM1_cgdo_Given = TRUE; + break; + case HSM1_MOD_CGBO: + mod->HSM1_cgbo = value->rValue; + mod->HSM1_cgbo_Given = TRUE; + break; + case HSM1_MOD_TPOLY: + mod->HSM1_tpoly = value->rValue; + mod->HSM1_tpoly_Given = TRUE; + break; + case HSM1_MOD_JS0: + mod->HSM1_js0 = value->rValue; + mod->HSM1_js0_Given = TRUE; + break; + case HSM1_MOD_JS0SW: + mod->HSM1_js0sw = value->rValue; + mod->HSM1_js0sw_Given = TRUE; + break; + case HSM1_MOD_NJ: + mod->HSM1_nj = value->rValue; + mod->HSM1_nj_Given = TRUE; + break; + case HSM1_MOD_NJSW: + mod->HSM1_njsw = value->rValue; + mod->HSM1_njsw_Given = TRUE; + break; + case HSM1_MOD_XTI: + mod->HSM1_xti = value->rValue; + mod->HSM1_xti_Given = TRUE; + break; + case HSM1_MOD_CJ: + mod->HSM1_cj = value->rValue; + mod->HSM1_cj_Given = TRUE; + break; + case HSM1_MOD_CJSW: + mod->HSM1_cjsw = value->rValue; + mod->HSM1_cjsw_Given = TRUE; + break; + case HSM1_MOD_CJSWG: + mod->HSM1_cjswg = value->rValue; + mod->HSM1_cjswg_Given = TRUE; + break; + case HSM1_MOD_MJ: + mod->HSM1_mj = value->rValue; + mod->HSM1_mj_Given = TRUE; + break; + case HSM1_MOD_MJSW: + mod->HSM1_mjsw = value->rValue; + mod->HSM1_mjsw_Given = TRUE; + break; + case HSM1_MOD_MJSWG: + mod->HSM1_mjswg = value->rValue; + mod->HSM1_mjswg_Given = TRUE; + break; + case HSM1_MOD_PB: + mod->HSM1_pb = value->rValue; + mod->HSM1_pb_Given = TRUE; + break; + case HSM1_MOD_PBSW: + mod->HSM1_pbsw = value->rValue; + mod->HSM1_pbsw_Given = TRUE; + break; + case HSM1_MOD_PBSWG: + mod->HSM1_pbswg = value->rValue; + mod->HSM1_pbswg_Given = TRUE; + break; + case HSM1_MOD_XPOLYD: + mod->HSM1_xpolyd = value->rValue; + mod->HSM1_xpolyd_Given = TRUE; + break; + case HSM1_MOD_CLM1: + mod->HSM1_clm1 = value->rValue; + mod->HSM1_clm1_Given = TRUE; + break; + case HSM1_MOD_CLM2: + mod->HSM1_clm2 = value->rValue; + mod->HSM1_clm2_Given = TRUE; + break; + case HSM1_MOD_CLM3: + mod->HSM1_clm3 = value->rValue; + mod->HSM1_clm3_Given = TRUE; + break; + case HSM1_MOD_MUETMP: + mod->HSM1_muetmp = value->rValue; + mod->HSM1_muetmp_Given = TRUE; + break; + case HSM1_MOD_RPOCK1: + mod->HSM1_rpock1 = value->rValue; + mod->HSM1_rpock1_Given = TRUE; + break; + case HSM1_MOD_RPOCK2: + mod->HSM1_rpock2 = value->rValue; + mod->HSM1_rpock2_Given = TRUE; + break; + case HSM1_MOD_RPOCP1: /* HiSIM1.1 */ + mod->HSM1_rpocp1 = value->rValue; + mod->HSM1_rpocp1_Given = TRUE; + break; + case HSM1_MOD_RPOCP2: /* HiSIM1.1 */ + mod->HSM1_rpocp2 = value->rValue; + mod->HSM1_rpocp2_Given = TRUE; + break; + case HSM1_MOD_VOVER: + mod->HSM1_vover = value->rValue; + mod->HSM1_vover_Given = TRUE; + break; + case HSM1_MOD_VOVERP: + mod->HSM1_voverp = value->rValue; + mod->HSM1_voverp_Given = TRUE; + break; + case HSM1_MOD_WFC: + mod->HSM1_wfc = value->rValue; + mod->HSM1_wfc_Given = TRUE; + break; + case HSM1_MOD_QME1: + mod->HSM1_qme1 = value->rValue; + mod->HSM1_qme1_Given = TRUE; + break; + case HSM1_MOD_QME2: + mod->HSM1_qme2 = value->rValue; + mod->HSM1_qme2_Given = TRUE; + break; + case HSM1_MOD_QME3: + mod->HSM1_qme3 = value->rValue; + mod->HSM1_qme3_Given = TRUE; + break; + case HSM1_MOD_GIDL1: + mod->HSM1_gidl1 = value->rValue; + mod->HSM1_gidl1_Given = TRUE; + break; + case HSM1_MOD_GIDL2: + mod->HSM1_gidl2 = value->rValue; + mod->HSM1_gidl2_Given = TRUE; + break; + case HSM1_MOD_GIDL3: + mod->HSM1_gidl3 = value->rValue; + mod->HSM1_gidl3_Given = TRUE; + break; + case HSM1_MOD_GLEAK1: + mod->HSM1_gleak1 = value->rValue; + mod->HSM1_gleak1_Given = TRUE; + break; + case HSM1_MOD_GLEAK2: + mod->HSM1_gleak2 = value->rValue; + mod->HSM1_gleak2_Given = TRUE; + break; + case HSM1_MOD_GLEAK3: + mod->HSM1_gleak3 = value->rValue; + mod->HSM1_gleak3_Given = TRUE; + break; + case HSM1_MOD_VZADD0: + mod->HSM1_vzadd0 = value->rValue; + mod->HSM1_vzadd0_Given = TRUE; + break; + case HSM1_MOD_PZADD0: + mod->HSM1_pzadd0 = value->rValue; + mod->HSM1_pzadd0_Given = TRUE; + break; + case HSM1_MOD_NFTRP: + mod->HSM1_nftrp = value->rValue; + mod->HSM1_nftrp_Given = TRUE; + break; + case HSM1_MOD_NFALP: + mod->HSM1_nfalp = value->rValue; + mod->HSM1_nfalp_Given = TRUE; + break; + case HSM1_MOD_CIT: + mod->HSM1_cit = value->rValue; + mod->HSM1_cit_Given = TRUE; + break; + case HSM1_MOD_KF: + mod->HSM1_kf = value->rValue; + mod->HSM1_kf_Given = TRUE; + break; + case HSM1_MOD_AF: + mod->HSM1_af = value->rValue; + mod->HSM1_af_Given = TRUE; + break; + case HSM1_MOD_EF: + mod->HSM1_ef = value->rValue; + mod->HSM1_ef_Given = TRUE; + break; + default: + return(E_BADPARM); + } + return(OK); +} + diff --git a/src/spicelib/devices/hisim/hsm1noi.c b/src/spicelib/devices/hisim/hsm1noi.c new file mode 100644 index 000000000..46ee1eb6f --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1noi.c @@ -0,0 +1,284 @@ +/*********************************************************************** + HiSIM v1.1.0 + File: hsm1noi.c of HiSIM v1.1.0 + + Copyright (C) 2002 STARC + + June 30, 2002: developed by Hiroshima University and STARC + June 30, 2002: posted by Keiichi MORIKAWA, STARC Physical Design Group +***********************************************************************/ + +/* + * Modified by Paolo Nenzi 2002 + * ngspice integration + */ + +#include "ngspice.h" +#include "hsm1def.h" +#include "cktdefs.h" +#include "iferrmsg.h" +#include "noisedef.h" +#include "suffix.h" +#include "const.h" /* jwan */ + +/* + * HSM1noise (mode, operation, firstModel, ckt, data, OnDens) + * This routine names and evaluates all of the noise sources + * associated with MOSFET's. It starts with the model *firstModel and + * traverses all of its insts. It then proceeds to any other models + * on the linked list. The total output noise density generated by + * all of the MOSFET's is summed with the variable "OnDens". + */ + +/* + Channel thermal and flicker noises are calculated based on the value + of model->HSM1_noise. + If model->HSM1_noise = 1, + Channel thermal noise = SPICE2 model + Flicker noise = SPICE2 model + If model->HSM1_noise = 2, + Channel thermal noise = HiSIM1 model corresponding to BSIM3 model + Flicker noise = HiSIM1 model + If model->HSM1_noise = 3, + Channel thermal noise = SPICE2 model + Flicker noise = HiSIM1 model + If model->HSM1_noise = 4, + Channel thermal noise = HiSIM1 model corresponding to BSIM3 model + Flicker noise = SPICE2 model + If model->HSM1_noise = 5, + Channel thermal noise = NONE + Flicker noise = HiSIM1 model + */ + +extern void NevalSrc(); +extern double Nintegrate(); + +int HSM1noise (int mode, int operation, GENmodel *inModel, CKTcircuit *ckt, + Ndata *data, double *OnDens) +{ + HSM1model *model = (HSM1model *)inModel; + HSM1instance *here; + char name[N_MXVLNTH]; + double tempOnoise; + double tempInoise; + double noizDens[HSM1NSRCS]; + double lnNdens[HSM1NSRCS]; + register int error, i; + + /* define the names of the noise sources */ + static char * HSM1nNames[HSM1NSRCS] = { + /* Note that we have to keep the order + consistent with the index definitions + in hsm1defs.h */ + ".rd", /* noise due to rd */ + ".rs", /* noise due to rs */ + ".id", /* noise due to id */ + ".1ovf", /* flicker (1/f) noise */ + "" /* total transistor noise */ + }; + + for ( ;model != NULL; model = model->HSM1nextModel ) { + for ( here = model->HSM1instances; here != NULL; + here = here->HSM1nextInstance ) { + + if (here->HSM1owner != ARCHme) + continue; + + switch (operation) { + case N_OPEN: + /* see if we have to to produce a summary report */ + /* if so, name all the noise generators */ + + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + switch (mode) { + case N_DENS: + for ( i = 0; i < HSM1NSRCS; i++ ) { + (void) sprintf(name, "onoise.%s%s", + (char *)here->HSM1name, HSM1nNames[i]); + data->namelist = + (IFuid *) xrealloc((char *) data->namelist, + (data->numPlots + 1) * sizeof(IFuid)); + if (!data->namelist) + return(E_NOMEM); + (*(SPfrontEnd->IFnewUid)) + (ckt, &(data->namelist[data->numPlots++]), + (IFuid) NULL, name, UID_OTHER, (void **) NULL); + } + break; + case INT_NOIZ: + for ( i = 0; i < HSM1NSRCS; i++ ) { + (void) sprintf(name, "onoise_total.%s%s", + (char *)here->HSM1name, HSM1nNames[i]); + data->namelist = + (IFuid *) xrealloc((char *) data->namelist, + (data->numPlots + 1) * sizeof(IFuid)); + if (!data->namelist) + return(E_NOMEM); + (*(SPfrontEnd->IFnewUid)) + (ckt, &(data->namelist[data->numPlots++]), + (IFuid) NULL, name, UID_OTHER, (void **) NULL); + + (void) sprintf(name, "inoise_total.%s%s", + (char *)here->HSM1name, HSM1nNames[i]); + data->namelist = + (IFuid *) xrealloc((char *) data->namelist, + (data->numPlots + 1) * sizeof(IFuid)); + if (!data->namelist) + return(E_NOMEM); + (*(SPfrontEnd->IFnewUid)) + (ckt, &(data->namelist[data->numPlots++]), + (IFuid) NULL, name, UID_OTHER, (void **)NULL); + } + break; + } + } + break; + case N_CALC: + switch (mode) { + case N_DENS: + NevalSrc(&noizDens[HSM1RDNOIZ], &lnNdens[HSM1RDNOIZ], + ckt, THERMNOISE, + here->HSM1dNodePrime, here->HSM1dNode, + here->HSM1drainConductance * here->HSM1_m); + + NevalSrc(&noizDens[HSM1RSNOIZ], &lnNdens[HSM1RSNOIZ], + ckt, THERMNOISE, + here->HSM1sNodePrime, here->HSM1sNode, + here->HSM1sourceConductance * here->HSM1_m); + + switch( model->HSM1_noise ) { + double I; + case 1: + case 3: + I = here->HSM1_gm + here->HSM1_gds + here->HSM1_gmbs; + I *= (I < 0.0) ? -1.0 : 1.0; + I *= 2.0/3.0; + I *= here->HSM1_m; /* PN */ + NevalSrc(&noizDens[HSM1IDNOIZ], &lnNdens[HSM1IDNOIZ], + ckt, THERMNOISE, + here->HSM1dNodePrime, here->HSM1sNodePrime, I); + break; + case 2: + case 4: + I = -1.0 * (here->HSM1_qg + here->HSM1_qb) + / (here->HSM1_weff * here->HSM1_leff); + I *= (I < 0.0) ? -1.0 : 1.0; + I *= here->HSM1_mu; + I *= here->HSM1_m; /* PN */ + NevalSrc(&noizDens[HSM1IDNOIZ], &lnNdens[HSM1IDNOIZ], + ckt, THERMNOISE, + here->HSM1dNodePrime, here->HSM1sNodePrime, I); + break; + case 5: + NevalSrc(&noizDens[HSM1IDNOIZ], &lnNdens[HSM1IDNOIZ], + ckt, THERMNOISE, + here->HSM1dNodePrime, here->HSM1sNodePrime, 0.0); + break; + } + NevalSrc(&noizDens[HSM1FLNOIZ], (double*) NULL, + ckt, N_GAIN, + here->HSM1dNodePrime, here->HSM1sNodePrime, + (double) 0.0); + + /* flicker noise */ + switch ( model->HSM1_noise ) { + case 1: + case 4: /* SPICE2 model */ + noizDens[HSM1FLNOIZ] *= model->HSM1_kf + * exp(model->HSM1_af * log(MAX(fabs(here->HSM1_ids * here->HSM1_m), N_MINLOG))) + / (pow(data->freq, model->HSM1_ef) * here->HSM1_leff + * here->HSM1_leff * (3.453133e-11 / model->HSM1_tox)); + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~cox */ + break; + case 2: + case 3: + case 5: + /* from HiSIM */ + noizDens[HSM1FLNOIZ] *= here->HSM1_nfc / data->freq; + break; + } + + lnNdens[HSM1FLNOIZ] = log(MAX(noizDens[HSM1FLNOIZ], N_MINLOG)); + + noizDens[HSM1TOTNOIZ] = noizDens[HSM1RDNOIZ] + noizDens[HSM1RSNOIZ] + + noizDens[HSM1IDNOIZ] + noizDens[HSM1FLNOIZ]; + lnNdens[HSM1TOTNOIZ] = log(MAX(noizDens[HSM1TOTNOIZ], N_MINLOG)); + + *OnDens += noizDens[HSM1TOTNOIZ]; + + if ( data->delFreq == 0.0 ) { + /* if we haven't done any previous + integration, we need to initialize our + "history" variables. + */ + + for ( i = 0; i < HSM1NSRCS; i++ ) + here->HSM1nVar[LNLSTDENS][i] = lnNdens[i]; + + /* clear out our integration variables + if it's the first pass + */ + if (data->freq == ((NOISEAN*) ckt->CKTcurJob)->NstartFreq) { + for (i = 0; i < HSM1NSRCS; i++) { + here->HSM1nVar[OUTNOIZ][i] = 0.0; + here->HSM1nVar[INNOIZ][i] = 0.0; + } + } + } + else { + /* data->delFreq != 0.0, + we have to integrate. + */ + for ( i = 0; i < HSM1NSRCS; i++ ) { + if ( i != HSM1TOTNOIZ ) { + tempOnoise = + Nintegrate(noizDens[i], lnNdens[i], + here->HSM1nVar[LNLSTDENS][i], data); + tempInoise = + Nintegrate(noizDens[i] * data->GainSqInv, + lnNdens[i] + data->lnGainInv, + here->HSM1nVar[LNLSTDENS][i] + data->lnGainInv, + data); + here->HSM1nVar[LNLSTDENS][i] = lnNdens[i]; + data->outNoiz += tempOnoise; + data->inNoise += tempInoise; + if ( ((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0 ) { + here->HSM1nVar[OUTNOIZ][i] += tempOnoise; + here->HSM1nVar[OUTNOIZ][HSM1TOTNOIZ] += tempOnoise; + here->HSM1nVar[INNOIZ][i] += tempInoise; + here->HSM1nVar[INNOIZ][HSM1TOTNOIZ] += tempInoise; + } + } + } + } + if ( data->prtSummary ) { + for (i = 0; i < HSM1NSRCS; i++) { + /* print a summary report */ + data->outpVector[data->outNumber++] = noizDens[i]; + } + } + break; + case INT_NOIZ: + /* already calculated, just output */ + if ( ((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0 ) { + for ( i = 0; i < HSM1NSRCS; i++ ) { + data->outpVector[data->outNumber++] = here->HSM1nVar[OUTNOIZ][i]; + data->outpVector[data->outNumber++] = here->HSM1nVar[INNOIZ][i]; + } + } + break; + } + break; + case N_CLOSE: + /* do nothing, the main calling routine will close */ + return (OK); + break; /* the plots */ + } /* switch (operation) */ + } /* for here */ + } /* for model */ + + return(OK); +} + + + diff --git a/src/spicelib/devices/hisim/hsm1par.c b/src/spicelib/devices/hisim/hsm1par.c new file mode 100644 index 000000000..c4367c5e4 --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1par.c @@ -0,0 +1,105 @@ +/*********************************************************************** + HiSIM v1.1.0 + File: hsm1par.c of HiSIM v1.1.0 + + Copyright (C) 2002 STARC + + June 30, 2002: developed by Hiroshima University and STARC + June 30, 2002: posted by Keiichi MORIKAWA, STARC Physical Design Group +***********************************************************************/ + +/* + * Modified by Paolo Nenzi 2002 + * ngspice integration + */ + +#include "ngspice.h" +#include "ifsim.h" +#include "hsm1def.h" +#include "sperror.h" +#include "suffix.h" + +int HSM1param(int param, IFvalue *value, GENinstance *inst, IFvalue *select) +{ + HSM1instance *here = (HSM1instance*)inst; + switch (param) { + case HSM1_W: + here->HSM1_w = value->rValue; + here->HSM1_w_Given = TRUE; + break; + case HSM1_L: + here->HSM1_l = value->rValue; + here->HSM1_l_Given = TRUE; + break; + case HSM1_M: + here->HSM1_m = value->rValue; + here->HSM1_m_Given = TRUE; + break; + case HSM1_AS: + here->HSM1_as = value->rValue; + here->HSM1_as_Given = TRUE; + break; + case HSM1_AD: + here->HSM1_ad = value->rValue; + here->HSM1_ad_Given = TRUE; + break; + case HSM1_PS: + here->HSM1_ps = value->rValue; + here->HSM1_ps_Given = TRUE; + break; + case HSM1_PD: + here->HSM1_pd = value->rValue; + here->HSM1_pd_Given = TRUE; + break; + case HSM1_NRS: + here->HSM1_nrs = value->rValue; + here->HSM1_nrs_Given = TRUE; + break; + case HSM1_NRD: + here->HSM1_nrd = value->rValue; + here->HSM1_nrd_Given = TRUE; + break; + case HSM1_TEMP: + here->HSM1_temp = value->rValue; + here->HSM1_temp_Given = TRUE; + break; + case HSM1_DTEMP: + here->HSM1_dtemp = value->rValue; + here->HSM1_dtemp_Given = TRUE; + break; + case HSM1_OFF: + here->HSM1_off = value->iValue; + break; + case HSM1_IC_VBS: + here->HSM1_icVBS = value->rValue; + here->HSM1_icVBS_Given = TRUE; + break; + case HSM1_IC_VDS: + here->HSM1_icVDS = value->rValue; + here->HSM1_icVDS_Given = TRUE; + break; + case HSM1_IC_VGS: + here->HSM1_icVGS = value->rValue; + here->HSM1_icVGS_Given = TRUE; + break; + case HSM1_IC: + switch (value->v.numValue) { + case 3: + here->HSM1_icVBS = *(value->v.vec.rVec + 2); + here->HSM1_icVBS_Given = TRUE; + case 2: + here->HSM1_icVGS = *(value->v.vec.rVec + 1); + here->HSM1_icVGS_Given = TRUE; + case 1: + here->HSM1_icVDS = *(value->v.vec.rVec); + here->HSM1_icVDS_Given = TRUE; + break; + default: + return(E_BADPARM); + } + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/hisim/hsm1pzld.c b/src/spicelib/devices/hisim/hsm1pzld.c new file mode 100644 index 000000000..c65cbde4a --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1pzld.c @@ -0,0 +1,211 @@ +/*********************************************************************** + HiSIM v1.1.0 + File: hsm1pzld.c of HiSIM v1.1.0 + + Copyright (C) 2002 STARC + + June 30, 2002: developed by Hiroshima University and STARC + June 30, 2002: posted by Keiichi MORIKAWA, STARC Physical Design Group +***********************************************************************/ + +/* + * Modified by Paolo Nenzi 2002 + * ngspice integration + */ + +#include "ngspice.h" +#include "cktdefs.h" +#include "complex.h" +#include "sperror.h" +#include "hsm1def.h" +#include "suffix.h" + +int HSM1pzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s) +{ + HSM1model *model = (HSM1model*)inModel; + HSM1instance *here; + double xcggb, xcgdb, xcgsb, xcgbb, xcbgb, xcbdb, xcbsb, xcbbb; + double xcdgb, xcddb, xcdsb, xcdbb, xcsgb, xcsdb, xcssb, xcsbb; + double gdpr, gspr, gds, gbd, gbs, capbd, capbs, FwdSum, RevSum, gm, gmbs; + double cggb, cgdb, cgsb, cbgb, cbdb, cbsb, cddb, cdgb, cdsb; + double cgso, cgdo, cgbo; + double gbspsp, gbbdp, gbbsp, gbspg, gbspb; + double gbspdp, gbdpdp, gbdpg, gbdpb, gbdpsp; + + double m; + + for ( ;model != NULL ;model = model->HSM1nextModel ) { + for ( here = model->HSM1instances ;here!= NULL ; + here = here->HSM1nextInstance ) { + + if (here->HSM1owner != ARCHme) + continue; + + if ( here->HSM1_mode >= 0 ) { + gm = here->HSM1_gm; + gmbs = here->HSM1_gmbs; + FwdSum = gm + gmbs; + RevSum = 0.0; + + gbbdp = -here->HSM1_gbds; + gbbsp = here->HSM1_gbds + here->HSM1_gbgs + here->HSM1_gbbs; + + gbdpg = here->HSM1_gbgs; + gbdpdp = here->HSM1_gbds; + gbdpb = here->HSM1_gbbs; + gbdpsp = -(gbdpg + gbdpdp + gbdpb); + + gbspg = 0.0; + gbspdp = 0.0; + gbspb = 0.0; + gbspsp = 0.0; + + cggb = here->HSM1_cggb; + cgsb = here->HSM1_cgsb; + cgdb = here->HSM1_cgdb; + + cbgb = here->HSM1_cbgb; + cbsb = here->HSM1_cbsb; + cbdb = here->HSM1_cbdb; + + cdgb = here->HSM1_cdgb; + cdsb = here->HSM1_cdsb; + cddb = here->HSM1_cddb; + + } + else { + gm = -here->HSM1_gm; + gmbs = -here->HSM1_gmbs; + FwdSum = 0.0; + RevSum = -(gm + gmbs); + + gbbsp = -here->HSM1_gbds; + gbbdp = here->HSM1_gbds + here->HSM1_gbgs + here->HSM1_gbbs; + + gbdpg = 0.0; + gbdpsp = 0.0; + gbdpb = 0.0; + gbdpdp = 0.0; + + gbspg = here->HSM1_gbgs; + gbspsp = here->HSM1_gbds; + gbspb = here->HSM1_gbbs; + gbspdp = -(gbspg + gbspsp + gbspb); + + cggb = here->HSM1_cggb; + cgsb = here->HSM1_cgdb; + cgdb = here->HSM1_cgsb; + + cbgb = here->HSM1_cbgb; + cbsb = here->HSM1_cbdb; + cbdb = here->HSM1_cbsb; + + cdgb = -(here->HSM1_cdgb + cggb + cbgb); + cdsb = -(here->HSM1_cddb + cgsb + cbsb); + cddb = -(here->HSM1_cdsb + cgdb + cbdb); + } + + gdpr = here->HSM1drainConductance; + gspr = here->HSM1sourceConductance; + gds = here->HSM1_gds; + gbd = here->HSM1_gbd; + gbs = here->HSM1_gbs; + capbd = here->HSM1_capbd; + capbs = here->HSM1_capbs; + + cgso = here->HSM1_cgso; + cgdo = here->HSM1_cgdo; + cgbo = here->HSM1_cgbo; + + m = here->HSM1_m; + + xcdgb = (cdgb - cgdo); + xcddb = (cddb + capbd + cgdo); + xcdsb = cdsb; + xcdbb = -(xcdgb + xcddb + xcdsb); + xcsgb = -(cggb + cbgb + cdgb + cgso); + xcsdb = -(cgdb + cbdb + cddb); + xcssb = (capbs + cgso - (cgsb + cbsb + cdsb)); + xcsbb = -(xcsgb + xcsdb + xcssb); + xcggb = (cggb + cgdo + cgso + cgbo); + xcgdb = (cgdb - cgdo); + xcgsb = (cgsb - cgso); + xcgbb = -(xcggb + xcgdb + xcgsb); + xcbgb = (cbgb - cgbo); + xcbdb = (cbdb - capbd); + xcbsb = (cbsb - capbs); + xcbbb = -(xcbgb + xcbdb + xcbsb); + + *(here->HSM1GgPtr ) += m * xcggb * s->real; + *(here->HSM1GgPtr +1) += m * xcggb * s->imag; + *(here->HSM1BbPtr ) += m * xcbbb * s->real; + *(here->HSM1BbPtr +1) += m * xcbbb * s->imag; + *(here->HSM1DPdpPtr ) += m * xcddb * s->real; + *(here->HSM1DPdpPtr +1) += m * xcddb * s->imag; + *(here->HSM1SPspPtr ) += m * xcssb * s->real; + *(here->HSM1SPspPtr +1) += m * xcssb * s->imag; + + *(here->HSM1GbPtr ) += m * xcgbb * s->real; + *(here->HSM1GbPtr +1) += m * xcgbb * s->imag; + *(here->HSM1GdpPtr ) += m * xcgdb * s->real; + *(here->HSM1GdpPtr +1) += m * xcgdb * s->imag; + *(here->HSM1GspPtr ) += m * xcgsb * s->real; + *(here->HSM1GspPtr +1) += m * xcgsb * s->imag; + + *(here->HSM1BgPtr ) += m * xcbgb * s->real; + *(here->HSM1BgPtr +1) += m * xcbgb * s->imag; + *(here->HSM1BdpPtr ) += m * xcbdb * s->real; + *(here->HSM1BdpPtr +1) += m * xcbdb * s->imag; + *(here->HSM1BspPtr ) += m * xcbsb * s->real; + *(here->HSM1BspPtr +1) += m * xcbsb * s->imag; + + *(here->HSM1DPgPtr ) += m * xcdgb * s->real; + *(here->HSM1DPgPtr +1) += m * xcdgb * s->imag; + *(here->HSM1DPbPtr ) += m * xcdbb * s->real; + *(here->HSM1DPbPtr +1) += m * xcdbb * s->imag; + *(here->HSM1DPspPtr ) += m * xcdsb * s->real; + *(here->HSM1DPspPtr +1) += m * xcdsb * s->imag; + + *(here->HSM1SPgPtr ) += m * xcsgb * s->real; + *(here->HSM1SPgPtr +1) += m * xcsgb * s->imag; + *(here->HSM1SPbPtr ) += m * xcsbb * s->real; + *(here->HSM1SPbPtr +1) += m * xcsbb * s->imag; + *(here->HSM1SPdpPtr ) += m * xcsdb * s->real; + *(here->HSM1SPdpPtr +1) += m * xcsdb * s->imag; + + *(here->HSM1DdPtr) += m * gdpr; + *(here->HSM1DdpPtr) -= m * gdpr; + *(here->HSM1DPdPtr) -= m * gdpr; + + *(here->HSM1SsPtr) += m * gspr; + *(here->HSM1SspPtr) -= m * gspr; + *(here->HSM1SPsPtr) -= m * gspr; + + *(here->HSM1BgPtr) -= m * here->HSM1_gbgs; + *(here->HSM1BbPtr) += m * (gbd + gbs - here->HSM1_gbbs); + *(here->HSM1BdpPtr) -= m * (gbd - gbbdp); + *(here->HSM1BspPtr) -= m * (gbs - gbbsp); + + *(here->HSM1DPgPtr) += m * (gm + gbdpg); + *(here->HSM1DPdpPtr) += m * (gdpr + gds + gbd + RevSum + gbdpdp); + *(here->HSM1DPspPtr) -= m * (gds + FwdSum - gbdpsp); + *(here->HSM1DPbPtr) -= m * (gbd - gmbs - gbdpb); + + *(here->HSM1SPgPtr) -= m * (gm - gbspg); + *(here->HSM1SPspPtr) += m * (gspr + gds + gbs + FwdSum + gbspsp); + *(here->HSM1SPbPtr) -= m * (gbs + gmbs - gbspb); + *(here->HSM1SPdpPtr) -= m * (gds + RevSum - gbspdp); + + /* + ... may nedeed in the future ... + *(here->HSM1GgPtr) -= m * xgtg; + *(here->HSM1GbPtr) -= m * xgtb; + *(here->HSM1GdpPtr) -= m * xgtd; + *(here->HSM1GspPtr) -= m * xgts; + */ + + } + } + return(OK); +} + diff --git a/src/spicelib/devices/hisim/hsm1set.c b/src/spicelib/devices/hisim/hsm1set.c new file mode 100644 index 000000000..300f41ac6 --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1set.c @@ -0,0 +1,347 @@ +/*********************************************************************** + HiSIM v1.1.0 + File: hsm1set.c of HiSIM v1.1.0 + + Copyright (C) 2002 STARC + + June 30, 2002: developed by Hiroshima University and STARC + June 30, 2002: posted by Keiichi MORIKAWA, STARC Physical Design Group +***********************************************************************/ + +/* + * Modified by Paolo Nenzi 2002 + * ngspice integration + */ + +#include "ngspice.h" +#include "smpdefs.h" +#include "cktdefs.h" +#include "hsm1def.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +int HSM1setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, + int *states) + /* load the HSM1 device structure with those pointers needed later + * for fast matrix loading + */ +{ + HSM1model *model = (HSM1model*)inModel; + HSM1instance *here; + int error; + CKTnode *tmp; + + CKTnode *tmpNode; + IFuid tmpName; + + /* loop through all the HSM1 device models */ + for ( ;model != NULL ;model = model->HSM1nextModel ) { + /* Default value Processing for HSM1 MOSFET Models */ + if ( !model->HSM1_type_Given ) + model->HSM1_type = NMOS ; + /***/ + if ( !model->HSM1_info_Given ) model->HSM1_info = 0 ; + if ( !model->HSM1_noise_Given) model->HSM1_noise = 5; /* select noise model 5 */ + if ( !model->HSM1_version_Given) model->HSM1_version = 100; /* default 100 */ + if ( !model->HSM1_corsrd_Given ) model->HSM1_corsrd = 0 ; + if ( !model->HSM1_coiprv_Given ) model->HSM1_coiprv = 1 ; + if ( !model->HSM1_copprv_Given ) model->HSM1_copprv = 1 ; + if ( !model->HSM1_cocgso_Given ) model->HSM1_cocgso = 0 ; + if ( !model->HSM1_cocgdo_Given ) model->HSM1_cocgdo = 0 ; + if ( !model->HSM1_cocgbo_Given ) model->HSM1_cocgbo = 0 ; + if ( !model->HSM1_coadov_Given ) model->HSM1_coadov = 1 ; + if ( !model->HSM1_coxx08_Given ) model->HSM1_coxx08 = 0 ; + if ( !model->HSM1_coxx09_Given ) model->HSM1_coxx09 = 0 ; + if ( !model->HSM1_coisub_Given ) model->HSM1_coisub = 0 ; + if ( !model->HSM1_coiigs_Given ) model->HSM1_coiigs = 0 ; + if ( !model->HSM1_cogidl_Given ) model->HSM1_cogidl = 0 ; + if ( !model->HSM1_coovlp_Given ) model->HSM1_coovlp = 0 ; + if ( !model->HSM1_conois_Given ) model->HSM1_conois = 0 ; + if ( model->HSM1_version == 110 ) {/* HiSIM1.1 */ + if ( !model->HSM1_coisti_Given ) model->HSM1_coisti = 0 ; + } + /***/ + if ( !model->HSM1_vmax_Given ) model->HSM1_vmax = 1.00e+7 ; + if ( !model->HSM1_bgtmp1_Given ) model->HSM1_bgtmp1 = 9.03e-5 ; + if ( !model->HSM1_bgtmp2_Given ) model->HSM1_bgtmp2 = 3.05e-7 ; + if ( !model->HSM1_tox_Given ) model->HSM1_tox = 3.60e-9 ; + if ( !model->HSM1_dl_Given ) model->HSM1_dl = 0.0 ; + if ( !model->HSM1_dw_Given ) model->HSM1_dw = 0.0 ; + if ( model->HSM1_version == 100 ) { /* HiSIM1.0 */ + if ( !model->HSM1_xj_Given ) model->HSM1_xj = 0.0 ; + if ( model->HSM1_xqy_Given ) { + printf("warning(HiSIM): the model parameter XQY is only available in VERSION = 110.\n"); + printf(" XQY = %f - ignored\n", model->HSM1_xqy); + } + } + else if ( model->HSM1_version == 110 ) { /* HiSIM1.1 */ + if ( !model->HSM1_xqy_Given ) model->HSM1_xqy = 0.0; + if ( model->HSM1_xj_Given ) { + printf("warning(HiSIM): the model parameter XJ is only available in VERSION = 100.\n"); + printf(" XJ = %f - ignored\n", model->HSM1_xj); + } + } + if ( !model->HSM1_rs_Given ) model->HSM1_rs = 0.0 ; + if ( !model->HSM1_rd_Given ) model->HSM1_rd = 0.0 ; + if ( !model->HSM1_vfbc_Given ) model->HSM1_vfbc = -0.722729 ; + if ( !model->HSM1_nsubc_Given ) model->HSM1_nsubc = 5.94e+17 ; + if ( !model->HSM1_parl1_Given ) model->HSM1_parl1 = 1.0 ; + if ( !model->HSM1_parl2_Given ) model->HSM1_parl2 = 2.20e-8 ; + if ( !model->HSM1_lp_Given ) model->HSM1_lp = 0.0 ; + if ( !model->HSM1_nsubp_Given ) model->HSM1_nsubp = 5.94e+17 ; + if ( !model->HSM1_scp1_Given ) model->HSM1_scp1 = 0.0 ; + if ( !model->HSM1_scp2_Given ) model->HSM1_scp2 = 0.0 ; + if ( !model->HSM1_scp3_Given ) model->HSM1_scp3 = 0.0 ; + if ( !model->HSM1_sc1_Given ) model->HSM1_sc1 = 13.5 ; + if ( !model->HSM1_sc2_Given ) model->HSM1_sc2 = 1.8 ; + if ( !model->HSM1_sc3_Given ) model->HSM1_sc3 = 0.0 ; + if ( !model->HSM1_pgd1_Given ) model->HSM1_pgd1 = 0.0 ; + if ( !model->HSM1_pgd2_Given ) model->HSM1_pgd2 = 0.0 ; + if ( !model->HSM1_pgd3_Given ) model->HSM1_pgd3 = 0.0 ; + if ( !model->HSM1_ndep_Given ) model->HSM1_ndep = 1.0 ; + if ( !model->HSM1_ninv_Given ) model->HSM1_ninv = 0.5 ; + if ( !model->HSM1_ninvd_Given ) model->HSM1_ninvd = 0.0 ; + if ( !model->HSM1_muecb0_Given ) model->HSM1_muecb0 = 300.0 ; + if ( !model->HSM1_muecb1_Given ) model->HSM1_muecb1 = 30.0 ; + if ( !model->HSM1_mueph1_Given ) model->HSM1_mueph1 = 1.00e+7 ; + if ( !model->HSM1_mueph0_Given ) model->HSM1_mueph0 = 0.295 ; + if ( !model->HSM1_mueph2_Given ) model->HSM1_mueph2 = 0.0 ; + if ( !model->HSM1_w0_Given ) model->HSM1_w0 = 0.0 ; + if ( !model->HSM1_muesr1_Given ) model->HSM1_muesr1 = 7.00e+8 ; + if ( !model->HSM1_muesr0_Given ) model->HSM1_muesr0 = 1.0 ; + if ( !model->HSM1_muetmp_Given ) model->HSM1_muetmp = 0.0 ; + /***/ + if ( !model->HSM1_bb_Given ) { + if (model->HSM1_type == NMOS) model->HSM1_bb = 2.0 ; + else model->HSM1_bb = 1.0 ; + } + /***/ + if ( !model->HSM1_vds0_Given ) model->HSM1_vds0 = 0.05 ; + if ( !model->HSM1_bc0_Given ) model->HSM1_bc0 = 0.0 ; + if ( !model->HSM1_bc1_Given ) model->HSM1_bc1 = 0.0 ; + if ( !model->HSM1_sub1_Given ) model->HSM1_sub1 = 0.0 ; + if ( !model->HSM1_sub2_Given ) model->HSM1_sub2 = -70.0 ; + if ( !model->HSM1_sub3_Given ) model->HSM1_sub3 = 1.0 ; + if ( model->HSM1_version == 110) { /* HiSIM1.1 */ + if ( !model->HSM1_wvthsc_Given ) model->HSM1_wvthsc = 0.0 ; + if ( !model->HSM1_nsti_Given ) model->HSM1_nsti = 1.0e17 ; + if ( !model->HSM1_wsti_Given ) model->HSM1_wsti = 0.0 ; + } + if ( !model->HSM1_tpoly_Given ) model->HSM1_tpoly = 0.0 ; + if ( !model->HSM1_js0_Given ) model->HSM1_js0 = 1.0e-4 ; + if ( !model->HSM1_js0sw_Given ) model->HSM1_js0sw = 0.0 ; + if ( !model->HSM1_nj_Given ) model->HSM1_nj = 1.0 ; + if ( !model->HSM1_njsw_Given ) model->HSM1_njsw = 1.0 ; + if ( !model->HSM1_xti_Given ) model->HSM1_xti = 3.0 ; + if ( !model->HSM1_cj_Given ) model->HSM1_cj = 8.397247e-04; + if ( !model->HSM1_cjsw_Given ) model->HSM1_cjsw = 5.0e-10 ; + if ( !model->HSM1_cjswg_Given ) model->HSM1_cjswg = 5.0e-10 ; + if ( !model->HSM1_mj_Given ) model->HSM1_mj = 0.5 ; + if ( !model->HSM1_mjsw_Given ) model->HSM1_mjsw = 0.33 ; + if ( !model->HSM1_mjswg_Given ) model->HSM1_mjswg = 0.33 ; + if ( !model->HSM1_pb_Given ) model->HSM1_pb = 1.0 ; + if ( !model->HSM1_pbsw_Given ) model->HSM1_pbsw = 1.0 ; + if ( !model->HSM1_pbswg_Given ) model->HSM1_pbswg = 1.0 ; + if ( !model->HSM1_xpolyd_Given ) model->HSM1_xpolyd = 0.0 ; + if ( !model->HSM1_clm1_Given ) model->HSM1_clm1 = 0.3e0 ; + if ( !model->HSM1_clm2_Given ) model->HSM1_clm2 = 0.0 ; + if ( !model->HSM1_clm3_Given ) model->HSM1_clm3 = 0.0 ; + if ( !model->HSM1_rpock1_Given ) model->HSM1_rpock1 = 0.0 ; + if ( !model->HSM1_rpock2_Given ) model->HSM1_rpock2 = 0.0 ; + if ( model->HSM1_version == 110 ) { /* HiSIM1.1 */ + if ( !model->HSM1_rpocp1_Given ) model->HSM1_rpocp1 = 0.0 ; + if ( !model->HSM1_rpocp2_Given ) model->HSM1_rpocp2 = 0.0 ; + } + if ( !model->HSM1_vover_Given ) model->HSM1_vover = 0.0 ; + if ( !model->HSM1_voverp_Given ) model->HSM1_voverp = 0.0 ; + if ( !model->HSM1_wfc_Given ) model->HSM1_wfc = 0.0 ; + if ( !model->HSM1_qme1_Given ) model->HSM1_qme1 = 0.0 ; + if ( !model->HSM1_qme2_Given ) model->HSM1_qme2 = 0.0 ; + if ( !model->HSM1_qme3_Given ) model->HSM1_qme3 = 0.0 ; + if ( !model->HSM1_gidl1_Given ) model->HSM1_gidl1 = 0.0 ; + if ( !model->HSM1_gidl2_Given ) model->HSM1_gidl2 = 0.0 ; + if ( !model->HSM1_gidl3_Given ) model->HSM1_gidl3 = 0.0 ; + if ( !model->HSM1_gleak1_Given ) model->HSM1_gleak1 = 0.0 ; + if ( !model->HSM1_gleak2_Given ) model->HSM1_gleak2 = 0.0 ; + if ( !model->HSM1_gleak3_Given ) model->HSM1_gleak3 = 0.0 ; + if ( !model->HSM1_vzadd0_Given ) model->HSM1_vzadd0 = 1.0e-2 ; + if ( !model->HSM1_pzadd0_Given ) model->HSM1_pzadd0 = 1.0e-3 ; + if ( !model->HSM1_nftrp_Given ) model->HSM1_nftrp = 100e9 ; + if ( !model->HSM1_nfalp_Given ) model->HSM1_nfalp = 2.00e-15 ; + if ( !model->HSM1_cit_Given ) model->HSM1_cit = 0.0 ; + + /* for flicker noise the same as BSIM3 */ + if ( !model->HSM1_ef_Given ) model->HSM1_ef = 0.0; + if ( !model->HSM1_af_Given ) model->HSM1_af = 1.0; + if ( !model->HSM1_kf_Given ) model->HSM1_kf = 0.0; + + /* loop through all the instances of the model */ + for ( here = model->HSM1instances ;here != NULL ; + here = here->HSM1nextInstance ) { + + if (here->HSM1owner == ARCHme) + { + /* allocate a chunk of the state vector */ + here->HSM1states = *states; + *states += HSM1numStates; + } + + /* perform the parameter defaulting */ + /* + if ( !here->HSM1_l_Given ) here->HSM1_l = 1.50e-4 ; + if ( !here->HSM1_w_Given ) here->HSM1_w = 5.55e-4 ; + */ + if ( !here->HSM1_l_Given ) here->HSM1_l = 5.0e-6 ; + if ( !here->HSM1_w_Given ) here->HSM1_w = 5.0e-6 ; + if ( !here->HSM1_m_Given ) here->HSM1_m = 1; + if ( !here->HSM1_ad_Given ) here->HSM1_ad = 0.0 ; + if ( !here->HSM1_as_Given ) here->HSM1_as = 0.0 ; + if ( !here->HSM1_pd_Given ) here->HSM1_pd = 0.0 ; + if ( !here->HSM1_ps_Given ) here->HSM1_ps = 0.0 ; + if ( !here->HSM1_nrd_Given ) here->HSM1_nrd = 0.0 ; + if ( !here->HSM1_nrs_Given ) here->HSM1_nrs = 0.0 ; + if ( !here->HSM1_temp_Given ) here->HSM1_temp = 300.15 ; + if ( !here->HSM1_dtemp_Given ) here->HSM1_dtemp = 0.0 ; + + if ( !here->HSM1_icVBS_Given ) here->HSM1_icVBS = 0.0; + if ( !here->HSM1_icVDS_Given ) here->HSM1_icVDS = 0.0; + if ( !here->HSM1_icVGS_Given ) here->HSM1_icVGS = 0.0; + + /* added by K.M. */ + here->HSM1_weff = here->HSM1_w - 2.0e0 * model->HSM1_dw; + here->HSM1_leff = here->HSM1_l - 2.0e0 * model->HSM1_dl; + + /* process source/drain series resistance added by K.M. */ + /* Drain and source conductances are always zero, + because there is no sheet resistance in HSM1 model param. + if ( model->HSM1_corsrd ) + here->HSM1drainConductance = 0.0; + else + here->HSM1drainConductance = model->HSM1_rs / here->HSM1_weff; + + if ( here->HSM1drainConductance > 0.0 ) + here->HSM1drainConductance = 1.0 / here->HSM1drainConductance; + else + here->HSM1drainConductance = 0.0; + + if ( model->HSM1_corsrd ) + here->HSM1sourceConductance = 0.0; + else + here->HSM1sourceConductance = model->HSM1_rd / here->HSM1_weff; + + if ( here->HSM1sourceConductance > 0.0 ) + here->HSM1sourceConductance = 1.0 / here->HSM1sourceConductance; + else + here->HSM1sourceConductance = 0.0; + */ + here->HSM1drainConductance = 0.0; + here->HSM1sourceConductance = 0.0; + + /* process drain series resistance */ + if( here->HSM1drainConductance > 0.0 && here->HSM1dNodePrime == 0 ) { + error = CKTmkVolt(ckt, &tmp, here->HSM1name, "drain"); + if (error) return(error); + here->HSM1dNodePrime = tmp->number; + + if (ckt->CKTcopyNodesets) { + if (CKTinst2Node(ckt,here,1,&tmpNode,&tmpName)==OK) { + if (tmpNode->nsGiven) { + tmp->nodeset=tmpNode->nodeset; + tmp->nsGiven=tmpNode->nsGiven; + } + } + } + + } + else { + here->HSM1dNodePrime = here->HSM1dNode; + } + + /* process source series resistance */ + if( here->HSM1sourceConductance > 0.0 && here->HSM1sNodePrime == 0 ) { + if ( here->HSM1sNodePrime == 0 ) { + error = CKTmkVolt(ckt, &tmp, here->HSM1name, "source"); + if (error) return(error); + here->HSM1sNodePrime = tmp->number; + + if (ckt->CKTcopyNodesets) { + if (CKTinst2Node(ckt,here,3,&tmpNode,&tmpName)==OK) { + if (tmpNode->nsGiven) { + tmp->nodeset=tmpNode->nodeset; + tmp->nsGiven=tmpNode->nsGiven; + } + } + } + + } + } + else { + here->HSM1sNodePrime = here->HSM1sNode; + } + + /* set Sparse Matrix Pointers */ + + /* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(HSM1DdPtr, HSM1dNode, HSM1dNode) + TSTALLOC(HSM1GgPtr, HSM1gNode, HSM1gNode) + TSTALLOC(HSM1SsPtr, HSM1sNode, HSM1sNode) + TSTALLOC(HSM1BbPtr, HSM1bNode, HSM1bNode) + TSTALLOC(HSM1DPdpPtr, HSM1dNodePrime, HSM1dNodePrime) + TSTALLOC(HSM1SPspPtr, HSM1sNodePrime, HSM1sNodePrime) + TSTALLOC(HSM1DdpPtr, HSM1dNode, HSM1dNodePrime) + TSTALLOC(HSM1GbPtr, HSM1gNode, HSM1bNode) + TSTALLOC(HSM1GdpPtr, HSM1gNode, HSM1dNodePrime) + TSTALLOC(HSM1GspPtr, HSM1gNode, HSM1sNodePrime) + TSTALLOC(HSM1SspPtr, HSM1sNode, HSM1sNodePrime) + TSTALLOC(HSM1BdpPtr, HSM1bNode, HSM1dNodePrime) + TSTALLOC(HSM1BspPtr, HSM1bNode, HSM1sNodePrime) + TSTALLOC(HSM1DPspPtr, HSM1dNodePrime, HSM1sNodePrime) + TSTALLOC(HSM1DPdPtr, HSM1dNodePrime, HSM1dNode) + TSTALLOC(HSM1BgPtr, HSM1bNode, HSM1gNode) + TSTALLOC(HSM1DPgPtr, HSM1dNodePrime, HSM1gNode) + TSTALLOC(HSM1SPgPtr, HSM1sNodePrime, HSM1gNode) + TSTALLOC(HSM1SPsPtr, HSM1sNodePrime, HSM1sNode) + TSTALLOC(HSM1DPbPtr, HSM1dNodePrime, HSM1bNode) + TSTALLOC(HSM1SPbPtr, HSM1sNodePrime, HSM1bNode) + TSTALLOC(HSM1SPdpPtr, HSM1sNodePrime, HSM1dNodePrime) + + } + } + return(OK); +} + + +int +HSM1unsetup (GENmodel *inModel, CKTcircuit *ckt) +{ + HSM1model *model; + HSM1instance *here; + + for (model = (HSM1model *) inModel; model != NULL; + model = model->HSM1nextModel) + { + for (here = model->HSM1instances; here != NULL; + here = here->HSM1nextInstance) + { + if (here->HSM1dNodePrime + && here->HSM1dNodePrime != here->HSM1dNode) + { + CKTdltNNum (ckt, here->HSM1dNodePrime); + here->HSM1dNodePrime = 0; + } + if (here->HSM1sNodePrime + && here->HSM1sNodePrime != here->HSM1sNode) + { + CKTdltNNum (ckt, here->HSM1sNodePrime); + here->HSM1sNodePrime = 0; + } + } + } + return OK; +} diff --git a/src/spicelib/devices/hisim/hsm1temp.c b/src/spicelib/devices/hisim/hsm1temp.c new file mode 100644 index 000000000..8966334e7 --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1temp.c @@ -0,0 +1,35 @@ +/*********************************************************************** + HiSIM v1.1.0 + File: hsm1temp.c of HiSIM v1.1.0 + + Copyright (C) 2002 STARC + + June 30, 2002: developed by Hiroshima University and STARC + June 30, 2002: posted by Keiichi MORIKAWA, STARC Physical Design Group +***********************************************************************/ + +/* + * Modified by Paolo Nenzi 2002 + * ngspice integration + */ + +#include "ngspice.h" +#include "smpdefs.h" +#include "cktdefs.h" +#include "hsm1def.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +int HSM1temp(GENmodel *inModel, CKTcircuit *ckt) +{ + /* "ckt->CKTtemp" dependence of HiSIM parameters is treated all in + * HSM1evaluate1_0/1_1(). So there is no task in HSM1temp(). + */ + + /* + if (here->HSM1owner != ARCHme) + continue; + */ + return(OK); +} diff --git a/src/spicelib/devices/hisim/hsm1trunc.c b/src/spicelib/devices/hisim/hsm1trunc.c new file mode 100644 index 000000000..bcaf388dd --- /dev/null +++ b/src/spicelib/devices/hisim/hsm1trunc.c @@ -0,0 +1,53 @@ +/*********************************************************************** + HiSIM v1.1.0 + File: hsm1trunc.c of HiSIM v1.1.0 + + Copyright (C) 2002 STARC + + June 30, 2002: developed by Hiroshima University and STARC + June 30, 2002: posted by Keiichi MORIKAWA, STARC Physical Design Group +***********************************************************************/ + +/* + * Modified by Paolo Nenzi 2002 + * ngspice integration + */ + +#include "ngspice.h" +#include "cktdefs.h" +#include "hsm1def.h" +#include "sperror.h" +#include "suffix.h" + +int HSM1trunc(GENmodel *inModel, CKTcircuit *ckt, double *timeStep) +{ +HSM1model *model = (HSM1model*)inModel; +HSM1instance *here; +#ifdef STEPDEBUG + double debugtemp; +#endif /* STEPDEBUG */ + + for ( ;model != NULL ;model = model->HSM1nextModel ) { + for ( here=model->HSM1instances ;here!=NULL ; + here = here->HSM1nextInstance ) { + + if (here->HSM1owner != ARCHme) + continue; + +#ifdef STEPDEBUG + debugtemp = *timeStep; +#endif /* STEPDEBUG */ + CKTterr(here->HSM1qb,ckt,timeStep); + CKTterr(here->HSM1qg,ckt,timeStep); + CKTterr(here->HSM1qd,ckt,timeStep); +#ifdef STEPDEBUG + if ( debugtemp != *timeStep ) + printf("device %s reduces step from %g to %g\n", + here->HSM1name, debugtemp, *timeStep); +#endif /* STEPDEBUG */ + } + } + return(OK); +} + +