//  HICUM Level_0 Version_1.12: A Verilog-A description
//  (A simplified version of HICUM Level2 model for BJT) 
//  ## It is modified after the first version of HICUM/L0 code    ##

//  12/08: Modifications for ngspice and adms2.2.7 DW 
//  Changed VT0 in Vt0 to prevent conflict in compiled C version.
//  Made a temporary variable cjei_i for cjei output purpose only.

// Minor code related changes
// 03/08: Quick Fix: Default value of TFH has been changed from infinity to zero and modified the default value limits to [0, inf) to include zero
// 12/06: Upper limit of FGEO is changed to infinity
//  06/06:  Thermal node "tnode" set as external
//  Flag FLSH introduced for controlling Self-heating calculation
//  all if-else blocks marked with begin-end
//  all series resistors and RTH are allowed to have a minimum value MIN_R
//  07/06: QCJMOD deleted, QJMODF introduced along with with HICJQ
//  ddx() operator used with QJMOD and QJMODF wherever needed
//  aj is kept at 2.4 except BE depletion charge
//  Substrate transistor transfer current added.
//  Gmin added to (bi,ei) and (bi,ci) branches.
//  hyperbolic smoothing used in rbi computation to avoid devide-by-zero.

// *********************************************************************************
// 06/06: Comment on NODE COLLAPSING:
// Presently this verilog code permits a minimum of 1 milli-Ohm resistance for any
// series resistance as well as for thermal resistance RTH. If any of the resistance
// values drops below this minimum value, the corresponding nodes are shorted with
// zero voltage contribution. We want the model compilers/simulators deal this 
// situation in such a manner that the corresponding node is COLLAPSED.
// We expect that the simulators should permit current contribution statement
// for any branch with resistance value more than (or equal to) 1 milli-Ohm without
// any convergence problem. In fact, we wish NOT to have to use a voltage contribution
// statement in our Verilog code, except as an indication for the model compiler/simulator
// to interprete a zero branch voltage as NODE-COLLAPSING action.
// **********************************************************************************


//Default simulator: Spectre

`ifdef insideADMS
 `define P(p) (*p*)
 `define PGIVEN(p)		$given(p)
 `define INITIAL_MODEL		@(initial_model)
`else
 `define P(p)
 `define PGIVEN(p)		p
 `define INITIAL_MODEL		@(initial_step)
`endif


//ADS
//`include "constants.vams"
//`include "disciplines.vams"
//`include "compact.vams"

//Spectre
`include "constants.h"
`include "discipline.h"


`define	NPN	+1
`define	PNP	-1

`define VPT_thresh   	1.0e2
`define EXPLIM		80.0
`define INF		1.0e6
`define TMAX		326.85
`define TMIN		-100.0
`define MIN_R		0.001
//`define Gmin 		1.0e-12

`define QCMODF(vj,cj0,vd,z,aj,cjf)\
  if(cj0 > 0.0) begin\
      vf	= vd*(1.0-exp(-ln(aj)/z));\
      xvf	= (vf-vj)/VT;\
      xvf2	= sqrt(xvf*xvf+1.921812);\
      v_j	= vf-VT*(xvf+xvf2)*0.5;\
      dvj	= 0.5*(xvf+xvf2)/xvf2;\
      cjf	= cj0*exp(-z*ln(1-v_j/vd))*dvj+aj*cj0*(1-dvj);\
  end else begin\
      cjf	= 0.0;\
  end

// DEPLETION CHARGE CALCULATION
// Hyperbolic smoothing used; no punch-through
`define QJMODF(vj,cj0,vd,z,aj,qjf)\
  if(cj0 > 0.0) begin\
      vf	= vd*(1.0-exp(-ln(aj)/z));\
      xvf	= (vf-vj)/VT;\
      xvf2	= sqrt(xvf*xvf+1.921812);\
      v_j	= vf-VT*(xvf+xvf2)*0.5;\
      x		= 1.0-z;\
      y		= 1.0-exp(x*ln(1.0-v_j/vd));\
      qjf	= cj0*vd*y/x+aj*cj0*(vj-v_j);\
  end else begin\
      qjf	= 0.0;\
  end


// Depletion Charge : with punch through
`define QJMOD(vj,cj0,vd,z,vpt,aj,qjf)\
  if(cj0 > 0.0) begin\
	zr	= z/4.0;\
	vp	= vpt-vd;\
	vf	= vd*(1.0-exp(-ln(aj)/z));\
	cmax	= aj*cj0;\
	cr	= cj0*exp((z-zr)*ln(vd/vpt));\
	a	= VT;\
	ve	= (vf-vj)/a;\
	if (ve <= `EXPLIM) begin\
		ex1	= exp(ve);\
		ee1	= 1.0+ex1;\
		vj1	= vf-a*ln(ee1);\
	end else begin\
		vj1	= vj;\
	end\
	a	= 0.1*vp+4.0*VT;\
	vr	= (vp+vj1)/a;\
	if (vr <= `EXPLIM) begin\
		ex1	= exp(vr);\
		ee1	= 1.0+ex1;\
		vj2	= -vp+a*ln(ee1);\
	end else begin\
		vj2	= vj1;\
	end\
	vj4	= vj-vj1;\
	ez	= 1.0-z;\
	ezr	= 1.0-zr;\
	vdj1	= ln(1.0-vj1/vd);\
	vdj2	= ln(1.0-vj2/vd);\
	qj1	= cj0*(1.0-exp(vdj2*ez))/ez;\
	qj2	= cr*(1.0-exp(vdj1*ezr))/ezr;\
	qj3	= cr*(1.0-exp(vdj2*ezr))/ezr;\
	qjf	= (qj1+qj2-qj3)*vd+cmax*vj4;\
  end else begin\
  	qjf	= 0.0;\
  end


// DEPLETION CHARGE CALCULATION SELECTOR:
// Dependent on junction punch-through voltage
// Important for collector related junctions
`define HICJQ(vj,cj0,vd,z,vpt,qjf)\
    if(vpt < `VPT_thresh) begin\
        `QJMOD(vj,cj0,vd,z,vpt,2.4,qjf)\
    end else begin\
        `QJMODF(vj,cj0,vd,z,2.4,qjf)\
    end
    
//Temperature dependence of depletion capacitance parameters
`define TMPHICJ(cj0,vd,z,vg,cj0_t,vd_t)\
	arg	= 0.5*vd/Vt0;\
	vdj0	= 2*Vt0*ln(exp(arg)-exp(-arg));\
	vdjt	= vdj0*qtt0+vg*(1-qtt0)-mg*VT*ln_qtt0;\
	vd_t	= vdjt+2*VT*ln(0.5*(1+sqrt(1+4*exp(-vdjt/VT))));\
	cj0_t	= cj0*exp(z*ln(vd/vd_t));


//Limiting exponential
`define LIN_EXP(le, arg)\
  if(arg > 80) begin\
	le = (1 + ((arg) - 80));\
        arg = 80;\
  end else begin\
	le=1;\
  end\
  le = le*limexp(arg);

// IDEAL DIODE (WITHOUT CAPACITANCE): 
// conductance not calculated
// INPUT:
//  IS, IST	: saturation currents (model parameter related)
//  UM1		: ideality factor
//  U		: branch voltage
// IMPLICIT INPUT:
//  VT		: thermal voltage
// OUTPUT:
//  Iz		: diode current
`define HICDIO(IS,IST,UM1,U,Iz)\
	DIOY	= U/(UM1*VT);\
	if (IS > 0.0) begin\
		if (DIOY > 80) begin\
			le 	= (1 + ((DIOY) - 80));\
			DIOY	= 80;\
		end else begin\
			le	= 1;\
		end\
  		le 	= le*limexp(DIOY);\
		Iz	= IST*(le-1.0);\
		if(DIOY <= -14.0) begin\
			Iz	= -IST;\
		end\
	end else begin\
		Iz	= 0.0;\
        end
        

module hic0_full (c,b,e,s,tnode);                    
                                               
                                            
//Node definitions 
                      
	inout		c,b,e,s,tnode;                                                  
	electrical 	c     `P(info="external collector node");
	electrical 	b     `P(info="external base node");
	electrical 	e     `P(info="external emitter node");
	electrical 	s     `P(info="external substrate node");
	electrical 	ci    `P(info="internal collector node");
	electrical 	bi    `P(info="internal base node");
	electrical 	ei    `P(info="internal emitter node");
	electrical 	tnode `P(info="local temperature rise node");
	
	
	//Branch definitions
	branch 		(ci,c) 		br_cic_i;
	branch 		(ci,c) 		br_cic_v;
	branch 		(ei,e) 		br_eie_i;
	branch 		(ei,e) 		br_eie_v;
	branch		(bi,ei)		br_biei;
	branch		(bi,ci)		br_bici;
	branch		(ci,ei)		br_ciei;
	branch 		(b,bi)  	br_bbi_i;  
	branch 		(b,bi)  	br_bbi_v; 	
	branch		(b,e)		br_be;
	branch		(b,ci)		br_bci;
	branch		(b,s)		br_bs;
	branch		(s,ci)		br_sci;
	branch		(tnode )	br_sht;                          
                                        
//                                             
// Parameter initialization with default values            
                                               
// Collector current                         
	parameter real is     		= 1.0e-16	from [0:1]	`P(spice:name="is"  info="(Modified) saturation current" m:factor="yes" unit="A");                  
	parameter real mcf    		= 1.00		from (0:10]	`P(spice:name="mcf" info="Non-ideality coefficient of forward collector current");                  
	parameter real mcr    		= 1.00		from (0:10]	`P(spice:name="mcr" info="Non-ideality coefficient of reverse collector current");                
	parameter real vef   		= `INF		from (0:`INF]	`P(spice:name="vef" info="forward Early voltage (normalization volt.)"  unit="V" default:value="infinity");                  
	parameter real iqf    		= `INF		from (0:`INF]	`P(spice:name="iqf" info="forward d.c. high-injection toll-off current" unit="A" m:factor="yes" default:value="infinity");        
	parameter real iqr    		= `INF		from (0:`INF]	`P(spice:name="iqr" info="inverse d.c. high-injection roll-off current" unit="A" m:factor="yes" default:value="infinity");               
	parameter real iqfh   		= `INF		from (0:`INF]	`P(spice:name="iqfh" info="high-injection correction current" unit="A" m:factor="yes");              
	parameter real tfh    		= 0.0		from [0:`INF)	`P(spice:name="tfh" info="high-injection correction factor" test:value="2e-9" m:factor="yes");                
                                               
// Base current                              
	parameter real ibes   		= 1e-18		from [0:1]	`P(spice:name="ibes" info="BE saturation current" unit="A" m:factor="yes");                 
	parameter real mbe    		= 1.0		from (0:10]	`P(spice:name="mbe"  info="BE non-ideality factor");                 
	parameter real ires   		= 0.0		from [0:1]	`P(spice:name="ires" info="BE recombination saturation current" test:value="1e-16" unit="A" m:factor="yes");               
	parameter real mre    		= 2.0		from (0:10]	`P(spice:name="mre"  info="BE recombination non-ideality factor");        
	parameter real ibcs  		= 0.0		from [0:1]	`P(spice:name="ibcs" info="BC saturation current" test:value="1e-16" unit="A" m:factor="yes");   
	parameter real mbc    		= 1.0		from (0:10]	`P(spice:name="mbc"  info="BC non-ideality factor");
                                               
// BE depletion cap                          
	parameter real cje0   		= 1.0e-20 	from (0:`INF)	`P(spice:name="cje0" info="Zero-bias BE depletion capacitance" unit="F" test:value="2e-14" m:factor="yes");
	parameter real vde    		= 0.9		from (0:10]	`P(spice:name="vde"  info="BE built-in voltage" unit="V");
	parameter real ze     		= 0.5		from (0:1]	`P(spice:name="ze"   info="BE exponent factor"); 
	parameter real aje    		= 2.5		from [1:`INF)	`P(spice:name="aje"  info="Ratio of maximum to zero-bias value");
                                               
// Transit time                              
	parameter real t0     		= 0.0		from [0:`INF)	`P(spice:name="t0"    info="low current transit time at Vbici=0" test:value="5e-12" unit="s");
	parameter real dt0h   		= 0.0;		// from [0:`INF)	`P(spice:name="dt0h"  info="Base width modulation contribution" test:value="2e-12" unit="s");
	parameter real tbvl   		= 0.0		from [0:`INF)	`P(spice:name="tbvl"  info="SCR width modulation contribution" test:value="4e-12" unit="s");
	parameter real tef0   		= 0.0		from [0:`INF)	`P(spice:name="tef0"  info="Storage time in neutral emitter" test:value="1e-12" unit="s"); 
	parameter real gte    		= 1.0		from (0:10]	`P(spice:name="gte"   info="Exponent factor for emmiter transit time");                  
	parameter real thcs   		= 0.0		from [0:`INF)	`P(spice:name="thcs"  info="Saturation time at high current densities" test:value="3e-11" unit="s");
	parameter real ahc    		= 0.1		from (0:10]	`P(spice:name="ahc"   info="Smoothing facor for current dependence");
	parameter real tr     		= 0.0		from [0:`INF)	`P(spice:name="tr"    info="Storage time at inverse operation" unit="s"); 
	                                             
// Critical current                          
	parameter real rci0   		= 150		from (0:`INF)	`P(spice:name="rci0"  info="Low-field collector resistance under emitter" test:value="50" unit="Ohm" m:inverse_factor="yes");
	parameter real vlim   		= 0.5		from (0:10]	`P(spice:name="vlim"  info="Voltage dividing ohmic and satur.region" unit="V");                  
	parameter real vpt    		= 100		from (0:100]	`P(spice:name="vpt"   info="Punch-through voltage" test:value="10" unit="V" default="infinity");
	parameter real vces  		= 0.1		from [0:1]	`P(spice:name="vces"  info="Saturation voltage" unit="V");
                                               
// BC depletion cap intern                   
	parameter real cjci0  		= 1.0e-20	from (0:`INF)	`P(spice:name="cjci0" info="Total zero-bias BC depletion capacitance" test:value="1e-15" unit="F" m:factor="yes");     
	parameter real vdci   		= 0.7		from (0:10]	`P(spice:name="vdci"  info="BC built-in voltage" test:value="0.7" unit="V");
	parameter real zci    		= 0.333		from (0:1]	`P(spice:name="zci"   info="BC exponent factor" test:value="0.4"); 
	parameter real vptci  		= 100		from (0:100]	`P(spice:name="vptci" info="Punch-through voltage of BC junction" test:value="50" unit="V");       
                                               
// BC depletion cap extern                   
	parameter real cjcx0  		= 1.0e-20	from [0:`INF)	`P(spice:name="cjcx0" info="Zero-bias external BC depletion capacitance" unit="F" test:value="1e-15" m:factor="yes");     
	parameter real vdcx   		= 0.7		from (0:10]	`P(spice:name="vdcx"  info="External BC built-in voltage" unit="V");  
	parameter real zcx    		= 0.333		from (0:1]	`P(spice:name="zcx"   info="External BC exponent factor");   
	parameter real vptcx  		= 100		from (0:100]	`P(spice:name="vptcx" info="Punch-through voltage" unit="V" test:value="5.0" default="infinity");  
	parameter real fbc    		= 1.0		from [0:1]	`P(spice:name="fbc"   info="Split factor = Cjci0/Cjc0" test:value="0.5");  
                                               
// Base resistance                           
	parameter real rbi0   		= 0.0		from [0:`INF)	`P(spice:name="rbi0"  info="Internal base resistance at zero-bias" test:value="100" unit="Ohm" m:inverse_factor="yes");   
	parameter real vr0e   		= 2.5		from (0:`INF]	`P(spice:name="vr0e"  info="forward Early voltage (normalization volt.)" unit="V");                 
	parameter real vr0c   		= `INF		from (0:`INF]	`P(spice:name="vr0c" info="forward Early voltage (normalization volt.)" unit="V" default="infinity" test:value="25.0");                  
	parameter real fgeo   		= 0.656		from [0:`INF]	`P(spice:name="fgeo"  info="Geometry factor" test:value="0.73"); 
                                               
// Series resistances                        
	parameter real rbx    		= 0.0		from [0:`INF)	`P(spice:name="rbx"   info="External base series resistance" test:value="8.8" unit="Ohm" m:inverse_factor="yes"); 
	parameter real rcx    		= 0.0		from [0:`INF)	`P(spice:name="rcx"   info="Emitter series resistance" test:value="12.5" unit="Ohm" m:inverse_factor="yes");        
	parameter real re     		= 0.0		from [0:`INF)	`P(spice:name="re"    info="External collector series resistance" test:value="9.16" unit="Ohm" m:inverse_factor="yes");      
                                               
// Substrate transfer current, diode current and cap                   
	parameter real itss   		= 0.0		from [0:1.0]	`P(spice:name="itss" info="Substrate transistor transfer saturation current" unit="A" test:value="1e-17" m:factor="yes");    
	parameter real msf    		= 1.0		from (0:10]	`P(spice:name="msf"  info="Substrate transistor transfer current non-ideality factor");   
	parameter real iscs   		= 0.0		from [0:1.0]	`P(spice:name="iscs" info="SC saturation current" unit="A" test:value="1e-17" m:factor="yes");    
	parameter real msc    		= 1.0		from (0:10]	`P(spice:name="msc"  info="SC non-ideality factor");   
	parameter real cjs0   		= 1.0e-20	from [0:`INF)	`P(spice:name="cjs0" info="Zero-bias SC depletion capacitance" unit="F" test:value="1e-15" m:factor="yes");    
	parameter real vds    		= 0.3		from (0:10]	`P(spice:name="vds"  info="SC built-in voltage" unit="V");     
	parameter real zs     		= 0.3		from (0:1]	`P(spice:name="zs"   info="External SC exponent factor");
	parameter real vpts   		= 100		from (0:100]	`P(spice:name="vpts" info="SC punch-through voltage" unit="V" test:value="5.0" default="infinity");     
                                               
// Parasitic caps                            
	parameter real cbcpar 		= 0.0		from [0:`INF)	`P(spice:name="cbcpar" info="Collector-base isolation (overlap) capacitance" unit="F" m:factor="yes" test:value="1e-15"); 
	parameter real cbepar 		= 0.0		from [0:`INF)	`P(spice:name="cbepar" info="Emitter-base oxide capacitance" unit="F" m:factor="yes" test:value="2e-15");  
                                               
// BC avalanche current                      
	parameter real eavl   		= 0.0		from [0:inf)	`P(spice:name="eavl" info="Exponent factor" test:value="1e-14");    
	parameter real kavl   		= 0.0		from [0:`INF)	`P(spice:name="kavl" info="Prefactor" test:value="1.19");                  
                                               
// Flicker noise                             
	parameter real kf     		= 0.0		from [0:`INF)	`P(spice:name="kf" info="flicker noise coefficient" unit="M^(1-AF)");         
	parameter real af     		= 2.0		from (0:10]	`P(spice:name="af" info="flicker noise exponent factor");  
                                               
// Temperature dependance                    
	parameter real vgb    		= 1.2		from (0:10]	`P(spice:name="vgb"     info="Bandgap-voltage" unit="V" test:value="1.17"); 
	parameter real vge    		= 1.17		from (0:10]	`P(spice:name="vge"     info="Effective emitter bandgap-voltage" unit="V" test:value="1.07");  
	parameter real vgc    		= 1.17		from (0:10]	`P(spice:name="vgc"     info="Effective collector bandgap-voltage" unit="V" test:value="1.14");         
	parameter real vgs    		= 1.17		from (0:10]	`P(spice:name="vgs"     info="Effective substrate bandgap-voltage" unit="V" test:value="1.17"); 
	parameter real f1vg   		=-1.02377e-4			`P(spice:name="f1vg" info="Coefficient K1 in T-dependent bandgap equation" unit="V/K");
	parameter real f2vg   		= 4.3215e-4			`P(spice:name="f2vg" info="Coefficient K2 in T-dependent bandgap equation" unit="V/K");
	parameter real alt0   		= 0.0				`P(spice:name="alt0"    info="Frist-order TC of tf0" unit="1/K");
	parameter real kt0    		= 0.0				`P(spice:name="kt0"     info="Second-order TC of tf0" unit="1/K^2");                   
	parameter real zetact 		= 3.0				`P(spice:name="zetact"  info="Exponent coefficient in transfer current temperature dependence" test:value="3.5");        
	parameter real zetabet		= 3.5				`P(spice:name="zetabet" info="Exponent coefficient in BE junction current temperature dependence" test:value="4.0");         
	parameter real zetaci 		= 0.0				`P(spice:name="zetaci"  info="TC of epi-collector diffusivity" test:value="1.6"); 
	parameter real alvs   		= 0.0				`P(spice:name="alvs"    info="Relative TC of satur.drift velocity" unit="1/K" test:value="1e-3");
	parameter real alces  		= 0.0				`P(spice:name="alces"   info="Relative TC of vces" unit="1/K" test:value="4e-4"); 
	parameter real zetarbi		= 0.0				`P(spice:name="zetarbi" info="TC of internal base resistance" test:value="0.6"); 
	parameter real zetarbx		= 0.0				`P(spice:name="zetarbx" info="TC of external base resistance" test:value="0.2"); 
	parameter real zetarcx		= 0.0				`P(spice:name="zetarcx" info="TC of external collector resistance" test:value="0.2");
	parameter real zetare		= 0.0				`P(spice:name="zetare"  info="TC of emitter resistances"); 
	parameter real alkav		= 0.0				`P(spice:name="alkav" info="TC of avalanche prefactor" unit="1/K"); 
	parameter real aleav		= 0.0				`P(spice:name="aleav" info="TC of avalanche exponential factor" unit="1/K");
	
// Self-heating                              
 	parameter integer flsh		= 0		from [0:2]	`P(spice:name="flsh"  info="Flag for self-heating calculation" test:value="2");            
 	parameter real rth		= 0.0		from [0:`INF)	`P(spice:name="rth"  info="Thermal resistance" test:value="200.0" unit="K/W" m:inverse_factor="yes");            
	parameter real cth		= 0.0		from [0:`INF)	`P(spice:name="cth"  info="Thermal capacitance" test:value="0.1" unit="Ws/K" m:factor="yes");
	
// Transistor type
	parameter integer npn		= 1		from [0:1]	`P(spice:isflag="yes" info="model type flag  for npn" );
	parameter integer pnp		= 0		from [0:1]	`P(info="model type flag  for pnp" );

//Circuit simulator specific parameters
	parameter real tnom		= 27				`P(spice:name="tnom" info="Temperature for which parameters are valid" unit="C");
	parameter real dt		= 0.0				`P(spice:name="dt" type="instance" info="Temperature change for particular transistor" unit="K");                   


// Declaration of the variables: begin

        real _circuit_gmin;

	real HICUMtype `P(spice:name="type" info="Device type from npn or pnp flags" unit="no" ask="yes");

	// QCJMOD
	real cj0,vd,z,aj;
	real zr,vp;
	real cmax,cr,ve;
	real ee1,ez,ezr,vdj1,vdj2,ex1,vr,vj1,vj2,vj4;
	real qj1,qj2,qj3,qjf;
	
	
	//Cjfun		*** VT, removed: BA
	real cj1,cj2,cj3,cjf;
	
	
	//cjtfun 	*** tnom,VT,mg,Vt0, removed: BA
	real	vg;
	real	vdj0,vdjt,cj0_t,vd_t,aj_t;
	
	
	// temperature and drift
	real VT,Tamb,Tdev,Tnom,dT,qtt0,ln_qtt0;
	real vde_t,vdci_t,vdcx_t,vds_t;
	real is_t,ires_t,ibes_t,ibcs_t;
	real itss_t,iscs_t,cje0_t,cjci0_t,cjcx0_t;
	real cjs0_t,rci0_t,vlim_t;
	real vces_t,thcs_t,tef0_t,rbi0_t;
	real rbx_t,rcx_t,re_t,t0_t,eavl_t,kavl_t;
	real aje_t;

	// bc charge and cap
	real qjci `P(ask="yes" info="B-C internal junction charge" unit="C");
	real qjcx,qjcii,cjcii,qjcxi,qjciii; //cjcx
	real cjci0_t_ii,cjcx0_t_ii,cjcx0_t_i,v_j;

	// be junction
	real qjei `P(ask="yes" info="B-E internal junction charge" unit="C");
	real cjei_i `P(ask="yes" info="B-E internal junction capacitance" unit="F"); // dw: adms2.2.7 problem
	real cjei,vf,vj,x,y,e1,e2;  
	 
	// transfer and internal base current
	real cc,qj_2,facl;
	real tf0,ickf,ickr,itfi,itri,qm;
	real qpt,itf,itr;
	real it `P(ask="yes" info="Transfer Current" unit="A");
	real ibe,ire,ibi;
	real itfl,itrl,al,s3l,wl,d_qfh;
	
	// be diffusion charge
	real qf,qf0,dqfh,dqef;
	real dtef,dtfh,tf,ick;
	real vc,vceff,s3,w,a,tww;

	// bc diffusion charge
	real qr;

	// avalanche current source
	real v_bord,a_iavl,lncc;
	
	// base resistance
	real rb,eta,rbi,qje,Qz_nom,fQz; 

	// substrate transistor, diode and cap
	real qjs,HSa,HSb,HSI_Tsu,HSUM;

	// self heating
	real pterm;
	
	// new for temperature dependence
  	real mg,zetabci,zetasct,zetatef,avs;
  	real k1,k2,vgbe,vgbc,vgsc,dvg;	
  	real xvf,xvf2,dvj,uvc,Vt0;

  	// noise
  	real flicker_Pwr,fourkt,twoq;
  	
  	// LIN_EXP
  	real	le,arg,le1,arg1,le2,arg2;
  	
  	//HICDIO
  	real	IS,IST,UM1,U,Iz,DIOY;
  	
  	// branch voltages
  	real   Vbci,Vbici,Vbiei,Vciei,Vsci,Veie,Vbbi,Vcic,Vbe,Vrth;
	
	//Output to be seen
	real	ijbc `P(ask="yes" info="Base-collector diode current" unit="A");
	real	iavl `P(ask="yes" info="Avalanche current" unit="A");
	real	ijsc `P(ask="yes" info="Substrate-collector diode current" unit="A");
	real	Ieei `P(ask="yes" info="Current through external to internal emitter node" unit="A");
	real	Icci `P(ask="yes" info="Current through external to internal collector node" unit="A");
	real	Ibbi `P(ask="yes" info="Current through external to internal base node" unit="A");
	real	Ibici `P(ask="yes" info="Base-collector diode current minus the avalanche current" unit="A");
	real	ijbe `P(ask="yes" info="Base-emitter diode current" unit="A");

  	real	Qbci,Qbe,Qbici,Qbiei;
//Declaration of the variables: end

  
//
//======================== calculation of the transistor =================== 
//

analog begin

// assign voltages with regard to transistor type

	`INITIAL_MODEL
	 begin
	  if (`PGIVEN(npn))
	     HICUMtype	=  `NPN;
	  else if (`PGIVEN(pnp))
	     HICUMtype	=  `PNP;
	  else
	     HICUMtype	=  `NPN;
         end

	Vbci  = HICUMtype*V(br_bci);
	Vbici = HICUMtype*V(br_bici);
	Vbiei = HICUMtype*V(br_biei);
	Vciei = HICUMtype*V(br_ciei);
	Vsci  = HICUMtype*V(br_sci);
	Veie  = V(br_eie_v);
	Vcic  = V(br_cic_v);
	Vbbi  = V(br_bbi_v);
	Vbe   = HICUMtype*V(br_be);
	Vrth  = V(br_sht);



//
// temperature and resulting parameter drift
//

	Tnom	= tnom+273.15;
	Tamb	= $temperature;
	Tdev	= Tamb+dt+Vrth;
	
// Limit temperature to avoid FPE's in equations
	if(Tdev < `TMIN + 273.15) begin
	   Tdev = `TMIN + 273.15;
	end else begin
 	if (Tdev > `TMAX + 273.15) begin
	   Tdev = `TMAX + 273.15;
	end
	end

	Vt0     = `P_K*Tnom /`P_Q;
	VT      = `P_K*Tdev /`P_Q;
	dT      = Tdev-Tnom;  
	qtt0    = Tdev/Tnom;
	ln_qtt0 = ln(qtt0);
	k1      = f1vg*Tnom;
	k2      = f2vg*Tnom+k1*ln(Tnom);
	avs     = alvs*Tnom;
	vgbe    = (vgb+vge)/2;   
	vgbc    = (vgb+vgc)/2;   
	vgsc    = (vgs+vgc)/2;   
	mg      = 3-`P_Q*f1vg/`P_K;
	zetabci = mg+1-zetaci;
	zetasct = mg-1.5;  //+1-m_upS with m_upS=2.5
	is_t    = is*exp(zetact*ln_qtt0+vgb/VT*(qtt0-1));
	ibes_t  = ibes*exp(zetabet*ln_qtt0+vge/VT*(qtt0-1));
	ires_t  = ires*exp(0.5*mg*ln_qtt0+0.5*vgbe/VT*(qtt0-1));
	ibcs_t  = ibcs*exp(zetabci*ln_qtt0+vgc/VT*(qtt0-1));
	itss_t	= itss*exp(zetasct*ln_qtt0+vgc/VT*(qtt0-1));
	iscs_t  = iscs*exp(zetasct*ln_qtt0+vgs/VT*(qtt0-1));
	`TMPHICJ(cje0,vde,ze,vgbe,cje0_t,vde_t)
	aje_t	= aje*vde_t/vde;
	`TMPHICJ(cjci0,vdci,zci,vgbc,cjci0_t,vdci_t)
	`TMPHICJ(cjcx0,vdcx,zcx,vgbc,cjcx0_t,vdcx_t)
	`TMPHICJ(cjs0,vds,zs,vgsc,cjs0_t,vds_t)
	rci0_t  = rci0*exp(zetaci*ln_qtt0);
	vlim_t  = vlim*exp((zetaci-avs)*ln_qtt0);
	vces_t  = vces*(1+alces*dT);
	t0_t    = t0*(1+alt0*dT+kt0*dT*dT);
	thcs_t  = thcs*exp((zetaci-1)*ln_qtt0);
	zetatef = zetabet-zetact-0.5;
	dvg     = vgb-vge;
	tef0_t  = tef0*exp(zetatef*ln_qtt0-dvg/VT*(qtt0-1));
	rbx_t   = rbx*exp(zetarbx*ln_qtt0);
	rcx_t   = rcx*exp(zetarcx*ln_qtt0);
	rbi0_t  = rbi0*exp(zetarbi*ln_qtt0);
	re_t    = re*exp(zetare*ln_qtt0);
	eavl_t  = eavl*exp(aleav*dT);
	kavl_t  = kavl*exp(alkav*dT);


//
// Calculation of intrinsic transistor elements
//

// BC charge and cap (internal and external)

// The cjcx0 value is used to switch between one (cjcx0=0) and two bc parameter sets
// 1. For one parameter set only the internal bc set is partitioned by fbc
// 2. For two independent sets only the external set is partitioned by fbc
	 
	if (cjcx0_t==0) begin 
		cjci0_t_ii	= cjci0_t*fbc;             // zero bias internal portion
		qjcxi		= 0;
		cjcx0_t_i	= cjci0_t*(1-fbc);         // zero bias external portion
		`HICJQ(Vbci,cjcx0_t_i,vdci_t,zci,vptci,qjcx)
	end else begin  
		cjci0_t_ii	= cjci0_t;                 // zero bias internal portion
		cjcx0_t_ii	= cjcx0_t*fbc;
		`HICJQ(Vbici,cjcx0_t_ii,vdcx_t,zcx,vptcx,qjcxi)
		cjcx0_t_i	= cjcx0_t*(1-fbc);         // zero bias external portion
		`HICJQ(Vbci,cjcx0_t_i,vdcx_t,zcx,vptcx,qjcx)
	end
	`HICJQ(Vbici,cjci0_t_ii,vdci_t,zci,vptci,qjci)
	qjcii	= qjci+qjcxi;
		
//Internal bc cap without punch through for cc
 
	//`HICJQ(Vbici,cjci0_t_ii,vdci_t,zci,100,qjciii)
	`QCMODF(Vbici,cjci0_t_ii,vdci_t,zci,2.4,cjcii)
	//cjcii	= ddx(qjciii,V(bi));

//Internal be cap and charge

	`QJMODF(Vbiei,cje0_t,vde_t,ze,aje_t,qjei)
	cjei	= ddx(qjei,V(bi));
	cjei_i	= cjei; // dw: adms2.2.7 problem

// Critical current: ick
	vc	= Vciei-vces_t;
	uvc	= vc/VT-1;
	vceff	= VT*(1+0.5*(uvc+sqrt(uvc*uvc+1.921812)));	
	x	= (vceff-vlim_t)/vpt;
	ick	= vceff*(1+0.5*(x+sqrt(x*x+1e-3)))/rci0_t/sqrt(1+vceff*vceff/vlim_t/vlim_t);

// Transfer current

// Normalized BC cap and carge
	cc	= cjci0_t_ii/cjcii;
	qjci	= qjci/cjci0_t_ii; 
	qj_2	= (1+qjci/vef)/2;

// Minority charge transit time
	tf0	= t0_t+dt0h*(cc-1)+tbvl*(1/cc-1);

// DC critical currents
	ickf	= iqf;
	ickr	= iqr;

// Ideal transfer currents
	arg1 = Vbiei/(mcf*VT);
	`LIN_EXP(le1,arg1)
	itfi=is_t*le1;
	
	arg2 = Vbici/(mcr*VT);
	`LIN_EXP(le2,arg2)
	itri=is_t*le2;


// Normalized minority charge
	qm	= (itfi/ickf+itri/ickr);

// Normalized total hole charge
	qpt	= qj_2+sqrt((qj_2)*(qj_2)+qm);
	if (qpt<=1e-20) begin
		qpt=1e-20;
	end	

// Low transfer current
	itfl	= itfi/qpt; 
	itrl	= itri/qpt;

// Normalized injection width with low transfer current
// and normalized charge component
	if (itfl<=1e-20) begin
		itfl	= 1e-20;
	end
	al	= 1-ick/itfl;
	s3l	= sqrt(al*al+ahc);
	wl	= (al+s3l)/(1+sqrt(1+ahc));
	d_qfh	= (wl*wl+tfh*itfl/ick)*itfl/iqfh;
	
// Transfer current
	facl	= 1/(1+d_qfh/qpt);
	itf	= itfl*facl;
	itr	= itrl*facl;
	if (itf<=1e-20) begin
		itf	= 1e-20;
	end
	it	= itf-itr;

// BE diffusion charge

// Calculation of low-current portion
	qf0	= tf0*itf;

// Current dependent component
	a	= 1-ick/itf;
	s3	= sqrt(a*a+ahc);
	w	= (a+s3)/(1+sqrt(1+ahc));
	tww	= thcs_t*w*w;
	dqfh	= tww*itf;
	dtfh	= tww*(1+2*ick/itf/s3);
 
// Emitter component
	dtef	= tef0_t*exp(gte*ln(itf/ick));
	dqef	= dtef*itf/(gte+1.0);
 
// Total minority charge and transit time 
	qf	= qf0+dqef+dqfh;
	tf	= tf0+dtfh+dtef;
 
// BC diffusion charge
	qr	= tr*itr;

// Internal base current

// BE diode
	`HICDIO(ibes,ibes_t,mbe,Vbiei,ibe)
	`HICDIO(ires,ires_t,mre,Vbiei,ire)
	ijbe	= ibe+ire;

// BC diode
	`HICDIO(ibcs,ibcs_t,mbc,Vbici,ijbc)

// Total base current
	ibi	= ijbe+ijbc;

// Avalanche current	

	if (Vbici < 0) begin : HICAVL
		v_bord	= eavl_t*vdci_t;
		if (vdci_t-Vbici>v_bord) begin
			a_iavl	= kavl_t/vdci_t*exp(-cc);
			iavl	= itf*a_iavl*(v_bord+(1+cc)*(vdci_t-Vbici-v_bord));
		end else begin
			lncc	= ln(1/cc);	      
			iavl	= kavl_t*itf*exp(-1/zci*lncc-eavl_t*exp((1/zci-1)*lncc));
		end
	end else begin
		iavl	= 0;
	end

//
// Additional elements for external transistor
//

// Base resistance
	if(rbi0_t > 0.0) begin : HICRBI
		// Conductivity modulation with hyperbolic smoothing
		qje	= qjei/cje0_t;
		Qz_nom	= 1+qje/vr0e+qjci/vr0c+itf/ickf+itr/ickr;
		fQz	= 0.5*(Qz_nom+sqrt(Qz_nom*Qz_nom+0.01));;
		rbi	= rbi0_t/fQz;
		// Emitter current crowding
		if (ibi > 0.0) begin
			eta	= fgeo*rbi*ibi/VT;
			if (eta < 1e-6) begin
				rbi	= rbi*(1-0.5*eta);
			end else begin
				rbi	= rbi*ln(eta+1)/eta;
			end
		end
	end else begin
		rbi	= 0.0;
	end
	// Total base resistance 
	rb	= rbi+rbx_t;

// Parasitic substrate transistor transfer current
 	if(itss > 0.0) begin : Sub_Transfer
 		HSUM	= msf*VT;
        	HSa	= limexp(Vbci/HSUM);
        	HSb	= limexp(Vsci/HSUM);
        	HSI_Tsu	= itss_t*(HSa-HSb);
      	end else begin
        	HSI_Tsu	= 0.0;
      	end

// Substrate diode and cap and charge

	`HICDIO(iscs,iscs_t,msc,Vsci,ijsc)

	`HICJQ(Vsci,cjs0_t,vds_t,zs,vpts,qjs)

// Self heating

	if (flsh == 1 && rth >= `MIN_R) begin
		pterm	= it*Vciei+iavl*(vdci_t-Vbici); 
	end else if (flsh == 2 && rth >= `MIN_R) begin
		pterm	=  Vciei*it + (vdci_t-Vbici)*iavl + ijbe*Vbiei + ijbc*Vbici + ijsc*Vsci;
		if (rb >= `MIN_R) begin
		pterm	= pterm + Vbbi*Vbbi/rb;
		end
		if (re_t >= `MIN_R) begin
		pterm	= pterm + Veie*Veie/re_t;
		end
		if (rcx_t >= `MIN_R) begin
		pterm	= pterm + Vcic*Vcic/rcx_t;
		end
	end

//
// Compute branch sources
//
	
	Ibici = ijbc - iavl;

	Qbci  = cbcpar*Vbci;
	Qbe   = cbepar*Vbe;
	Qbici = qjcii+qr;
	Qbiei = qjei+qf;

	ijsc  = HICUMtype*ijsc;
	qjs   = HICUMtype*qjs;
	qjcx  = HICUMtype*qjcx; 
	Qbci  = HICUMtype*Qbci;
	Qbe   = HICUMtype*Qbe;
	
	Ibici = HICUMtype*Ibici;
	Qbici = HICUMtype*Qbici;
	ijbe  = HICUMtype*ijbe;
	Qbiei = HICUMtype*Qbiei; 
	it    = HICUMtype*it;
	
//
// Define branch sources
//
	I(br_biei)	<+ _circuit_gmin*V(br_biei);
	I(br_bici)	<+ _circuit_gmin*V(br_bici);
		
	I(br_bs) 		<+ HSI_Tsu;
	I(br_sci)		<+ ijsc	+ _circuit_gmin*V(br_sci);	//`P(spectre:gmin="add" spectre:pwl_passive="1e10");
	I(br_sci)		<+ ddt(qjs);
	I(br_bci)		<+ ddt(qjcx);
	I(br_bci)	  	<+ ddt(Qbci);
	I(br_be)		<+ ddt(Qbe);
	if (re >= `MIN_R) begin
	I(br_eie_i)	  	<+ Veie/re_t + _circuit_gmin*V(br_eie_i);//`P(spectre:gmin="add");
	end else begin
	V(br_eie_v)		<+ 0.0;
	end
	if (rcx >= `MIN_R) begin
	I(br_cic_i)	  	<+ Vcic/rcx_t + _circuit_gmin*V(br_cic_i);//`P(spectre:gmin="add");
	end else begin
	V(br_cic_v)		<+ 0.0;
	end
	if (rbi0 >= `MIN_R || rbx >= `MIN_R) begin
	I(br_bbi_i)	  	<+ Vbbi/rb + _circuit_gmin*V(br_bbi_i);	//`P(spectre:gmin="add");
	end else begin
	V(br_bbi_v)		<+ 0.0;
	end
	I(br_bici)	<+ Ibici + _circuit_gmin*V(br_bici);		//`P(spectre:gmin="add" spectre:pwl_sat_current="IMAX" spectre:pwl_sat_cond="imax/0.025" spectre:pwl_rev_current="imax" spectre:pwl_rev_cond="IMAX/0.025");
	I(br_bici)	<+ ddt(Qbici);
	I(br_biei)	<+ ijbe + _circuit_gmin*V(br_biei);		//`P(spectre:gmin="add" spectre:pwl_fwd_current="IBEIS*exp(25.0)" spectre:pwl_fwd_node="bi" spectre:pwl_fwd_cond="IBEIS*exp(25.0)/0.025" spectre:pwl_sat_current="IMAX" spectre:pwl_sat_cond="IMAX/0.025" spectre:pwl_passive="1e10");
	I(br_biei)	<+ ddt(Qbiei);
	I(br_ciei)	<+ it					`P(spectre:pwl_fwd_current="IS*exp(25.0)" spectre:pwl_fwd_node="bi" spectre:pwl_fwd_cond="IS*exp(25.0)/0.025"   spectre:pwl_rev_current="IMAX" spectre:pwl_rev_cond="IMAX/0.025" spectre:pwl_passive="1e10");
	
	// Following code is an intermediate solution:
	// ******************************************
	if(flsh == 0 || rth < `MIN_R) begin
		I(br_sht) 	<+ Vrth/`MIN_R;
	end else begin
		I(br_sht) 	<+ Vrth/rth-pterm + _circuit_gmin*V(br_sht);//`P(spectre:gmin="add");
		I(br_sht) 	<+ ddt(cth*Vrth);
	end
	// ******************************************
	// For simulators having no problem with V(br_sht) <+ 0.0 
	// with external thermal node, follwing code may be used.
	// This external thermal node should remain accessible.
	// ********************************************
	//if(flsh == 0 || rth < `MIN_R) begin
	//	V(br_sht)	<+ 0.0;
	//end else begin
	//	I(br_sht) 	<+ Vrth/rth-pterm		`P(spectre:gmin="add");
	//	I(br_sht) 	<+ ddt(cth*Vrth);
	//end
	// ********************************************
	
// Noise sources
// Thermal noise
	fourkt 	= 4.0 * `P_K * Tdev;
	if(rbx >= `MIN_R || rbi0 >= `MIN_R) begin
		I(br_bbi_i)		<+ white_noise(fourkt/rb);
	end
	if(rcx >= `MIN_R) begin
		I(br_cic_i)		<+ white_noise(fourkt/rcx_t);
	end
	if(re >= `MIN_R) begin
		I(br_eie_i)		<+ white_noise(fourkt/re_t);
	end

// Shot noise
	twoq	= 2.0 * `P_Q;
	I(br_biei)	<+ white_noise(twoq*ijbe);
	I(br_ciei)	<+ white_noise(twoq*it);
   
// Flicker noise   
	flicker_Pwr	= kf*pow(ijbe,af);
	I(br_biei)	<+ flicker_noise(flicker_Pwr,1.0);

end  // analog
endmodule
