//======================================================================================
//======================================================================================
// Filename: PSP102_macrodefs.include
//======================================================================================
//======================================================================================
//
//  (c) Copyright 2007, All Rights Reserved, NXP Semiconductors
//
//
//  Version: 102.1, April 2007 (Simkit 2.5)
//
//======================================================================================
//======================================================================================
//
// Further information can be found in the file readme.txt
//


/////////////////////////////////////////////
//
// Macros and constants used in PSP 
//
/////////////////////////////////////////////

// Explicit Gmin
`define GMIN 1E-15

`define PMOS                 -1
`define NMOS                 +1

// Some functions
`define MINA(x,y,a)           0.5*((x)+(y)-sqrt(((x)-(y))*((x)-(y))+(a)))
`define MAXA(x,y,a)           0.5*((x)+(y)+sqrt(((x)-(y))*((x)-(y))+(a)))

// Physical constants
`define EPSOX                 3.453E-11
`define QMN                   5.951993
`define QMP                   7.448711

// Other constants (PSP-mos)
`define DELTA1                0.02
`define invSqrt2              7.0710678118654746e-01
`define oneSixth              1.6666666666666667e-01
`define exp80                 5.5406223843935098e+34
`define exp160                3.0698496406442424e+69

`ifdef NQSmodel
    `define Gint GP
    `define Bint BP
    `define Bjs  BS
    `define Bjd  BD
`else // NQSmodel
    `define Gint G
    `define Bint B
    `define Bjs  B
    `define Bjd  B
`endif // NQSModel

/////////////////////////////////////////////////////////////////////////////
//
//  Macro definitions.
//
//  Note that because at present locally scoped variables
//  can only be in named blocks, the intermediate variables
//  used in the macros below must be explicitly declared
//  as variables in the main code.
//
/////////////////////////////////////////////////////////////////////////////


//  sigma    function used in surface potential and other calculations
//           (one call uses expressions for arguments so parentheses
//           around the arguments in the expressions are necessary)
`define sigma(a,c,tau,eta,y) \
nu         =  (a) + (c); \
mu         =  nu * nu / (tau) + 0.5 * ((c) * (c)) - (a); \
y          =  (eta) + (a) * nu / (mu + (nu / mu) * (c) * ((c) * (c) * `oneThird - (a)));


// modified version of sigma, which takes 4 arguments
`define sigma2(a,b,c,tau,eta,y) \
nu = (a) + (c); \
if (abs(tau) < 1e-120) begin /*sometimes tau is extremely small...*/\
    y              =  (eta); \
end else begin \
    mu             =  (nu) * (nu) / (tau) + 0.5 * ((c) * (c)) - (a) * (b); \
    y              =  (eta) + (a) * nu / (mu + (nu / mu) * (c) * ((c) * (c) * `oneThird - (a) * (b))); \
end
 
//
//  sp_s     surface potential calculation
//
`define sp_s(sp,xg,xn,delta) \
if (abs(xg) <= margin) begin \
    SP_S_temp1 =  inv_xi * inv_xi * `oneSixth * `invSqrt2; \
    sp         =  xg * inv_xi * (1.0 + xg * (1.0 - (delta)) * Gf * SP_S_temp1); \
end else begin \
    if (xg < -margin) begin \
        SP_S_yg     = -xg; \
        SP_S_ysub   = 1.25 * (SP_S_yg * inv_xi); \
        SP_S_eta    = 0.5 * (SP_S_ysub + 10 - sqrt((SP_S_ysub - 6.0) * (SP_S_ysub - 6.0) + 64.0)); \
        SP_S_temp   = SP_S_yg - SP_S_eta; \
        SP_S_a      = SP_S_temp * SP_S_temp + Gf2*(SP_S_eta + 1.0);\
        SP_S_c      = 2.0 * SP_S_temp - Gf2; \
        SP_S_tau    = -SP_S_eta + ln(SP_S_a * inv_Gf2); \
        `sigma(SP_S_a, SP_S_c, SP_S_tau, SP_S_eta, SP_S_y0) \
        `expl_high(SP_S_y0, SP_S_delta0) \
        SP_S_delta1 = 1.0 / SP_S_delta0; \
        SP_S_temp   = 1.0 / (2.0 + SP_S_y0 * SP_S_y0); \
        SP_S_xi0    = SP_S_y0 * SP_S_y0 * SP_S_temp; \
        SP_S_xi1    = 4.0 * (SP_S_y0 * SP_S_temp * SP_S_temp); \
        SP_S_xi2    = (8.0 * SP_S_temp - 12.0 * SP_S_xi0) * SP_S_temp * SP_S_temp; \
        SP_S_temp   = SP_S_yg - SP_S_y0; \
        SP_S_temp1  = (delta) * SP_S_delta1; \
        SP_S_pC     = 2.0 * SP_S_temp + Gf2 * (SP_S_delta0 - 1.0 - SP_S_temp1 + (delta) * (1.0 - SP_S_xi1)); \
        SP_S_qC     = SP_S_temp * SP_S_temp - Gf2 * (SP_S_delta0 - SP_S_y0 - 1.0 + SP_S_temp1 + (delta) * (SP_S_y0 - 1.0 - SP_S_xi0)); \
        SP_S_temp   = 2.0 - Gf2 * (SP_S_delta0 + SP_S_temp1 - (delta) * SP_S_xi2); \
        SP_S_temp   = SP_S_pC * SP_S_pC - 2.0 * (SP_S_qC * SP_S_temp); \
        sp          = -SP_S_y0 - 2.0 * (SP_S_qC / (SP_S_pC + sqrt(SP_S_temp))); \
    end else begin \
        SP_xg1    = 1.0 / (x1 + Gf * 7.324648775608221e-001); \
        SP_S_A_fac= (xi * x1 * SP_xg1 - 1.0) * SP_xg1; \
        SP_S_xbar = xg * inv_xi * (1.0 + SP_S_A_fac * xg); \
        `expl_low(-SP_S_xbar, SP_S_temp) \
        SP_S_w    = 1.0 - SP_S_temp; \
        SP_S_x1   = xg + Gf2 * 0.5 - Gf * sqrt(xg + Gf2 * 0.25 - SP_S_w); \
        SP_S_bx   = (xn) + 3.0; \
        SP_S_eta  = `MINA(SP_S_x1, SP_S_bx, 5.0) - 0.5 * (SP_S_bx - sqrt(SP_S_bx * SP_S_bx + 5.0)); \
        SP_S_temp = xg - SP_S_eta; \
        SP_S_temp1= exp(-SP_S_eta); \
        SP_S_temp2= 1.0 / (2.0 + SP_S_eta * SP_S_eta); \
        SP_S_xi0  = SP_S_eta * SP_S_eta * SP_S_temp2; \
        SP_S_xi1  = 4.0 * (SP_S_eta * SP_S_temp2 * SP_S_temp2); \
        SP_S_xi2  = (8.0 * SP_S_temp2 - 12.0 * SP_S_xi0) * SP_S_temp2 * SP_S_temp2; \
        SP_S_a    = max(1.0e-40, SP_S_temp * SP_S_temp - Gf2 * (SP_S_temp1 + SP_S_eta - 1.0 - (delta) * (SP_S_eta + 1.0 + SP_S_xi0))); \
        SP_S_b    = 1.0 - 0.5 * (Gf2 * (SP_S_temp1 - (delta) * SP_S_xi2)); \
        SP_S_c    = 2.0 * SP_S_temp + Gf2 * (1.0 - SP_S_temp1 - (delta) * (1.0 + SP_S_xi1)); \
        SP_S_tau  = (xn) - SP_S_eta + ln(SP_S_a / Gf2); \
        `sigma2(SP_S_a, SP_S_b, SP_S_c, SP_S_tau, SP_S_eta, SP_S_x0) \
        if (SP_S_x0 < `se05) begin \
            SP_S_delta0 = exp(SP_S_x0); \
            SP_S_delta1 = 1.0 / SP_S_delta0; \
            SP_S_delta0 = (delta) * SP_S_delta0; \
        end else begin \
            if (SP_S_x0 > (xn) - `se05) begin \
                SP_S_delta0 = exp(SP_S_x0 - (xn)); \
                SP_S_delta1 = (delta) / SP_S_delta0; \
            end else begin \
                SP_S_delta0 = `ke05 / `P3((xn) - SP_S_x0 - `se05); \
                SP_S_delta1 = `ke05 / `P3(SP_S_x0 - `se05); \
            end \
        end \
        SP_S_temp   = 1.0 / (2.0 + SP_S_x0 * SP_S_x0); \
        SP_S_xi0    = SP_S_x0 * SP_S_x0 * SP_S_temp; \
        SP_S_xi1    = 4.0 * (SP_S_x0 * SP_S_temp * SP_S_temp); \
        SP_S_xi2    = (8.0 * SP_S_temp - 12.0 * SP_S_xi0) * SP_S_temp * SP_S_temp; \
        SP_S_temp   = xg - SP_S_x0; \
        SP_S_pC     = 2.0 * SP_S_temp + Gf2 * (1.0 - SP_S_delta1 + SP_S_delta0 - (delta) * (1.0 + SP_S_xi1)); \
        SP_S_qC     = SP_S_temp * SP_S_temp - Gf2 * (SP_S_delta1 + SP_S_x0 - 1.0 + SP_S_delta0 - (delta) * (SP_S_x0 + 1.0 + SP_S_xi0)); \
        SP_S_temp   = 2.0 - Gf2 * (SP_S_delta1 + SP_S_delta0 - (delta) * SP_S_xi2); \
        SP_S_temp   = SP_S_pC * SP_S_pC - 2.0 * (SP_S_qC * SP_S_temp); \
        sp          = SP_S_x0 + 2.0 * (SP_S_qC / (SP_S_pC + sqrt(SP_S_temp))); \
    end \
end

//
//  sp_s_d     surface potential calculation at drain (subset of function sp_s)
//
`define sp_s_d(sp,xg,xn,delta) \
if (abs(xg) <= margin) begin \
    SP_S_temp1 =  inv_xi * inv_xi * `oneSixth * `invSqrt2; \
    sp         =  xg * inv_xi * (1.0 + xg * (1.0 - (delta)) * Gf * SP_S_temp1); \
end else begin \
    SP_S_bx   = (xn) + 3; \
    SP_S_eta  = `MINA(SP_S_x1, SP_S_bx, 5.0) - 0.5 * (SP_S_bx - sqrt(SP_S_bx * SP_S_bx + 5.0)); \
    SP_S_temp = xg - SP_S_eta; \
    SP_S_temp1= exp(-SP_S_eta); \
    SP_S_temp2= 1.0 / (2.0 + SP_S_eta * SP_S_eta); \
    SP_S_xi0  = SP_S_eta * SP_S_eta * SP_S_temp2; \
    SP_S_xi1  = 4.0 * (SP_S_eta * SP_S_temp2 * SP_S_temp2); \
    SP_S_xi2  = (8.0 * SP_S_temp2 - 12.0 * SP_S_xi0) * SP_S_temp2 * SP_S_temp2; \
    SP_S_a    = max(1.0e-40, SP_S_temp * SP_S_temp - Gf2 * (SP_S_temp1 + SP_S_eta - 1.0 - (delta) * (SP_S_eta + 1.0 + SP_S_xi0))); \
    SP_S_b    = 1.0 - 0.5 * (Gf2 * (SP_S_temp1 - (delta) * SP_S_xi2)); \
    SP_S_c    = 2.0 * SP_S_temp + Gf2 * (1.0 - SP_S_temp1 - (delta) * (1.0 + SP_S_xi1)); \
    SP_S_tau  = (xn) - SP_S_eta + ln(SP_S_a / Gf2); \
    `sigma2(SP_S_a, SP_S_b, SP_S_c, SP_S_tau, SP_S_eta, SP_S_x0) \
    if (SP_S_x0 < `se05) begin \
        SP_S_delta0 = exp(SP_S_x0); \
        SP_S_delta1 = 1.0 / SP_S_delta0; \
        SP_S_delta0 = (delta) * SP_S_delta0; \
    end else begin \
        if (SP_S_x0 > (xn) - `se05) begin \
            SP_S_delta0 = exp(SP_S_x0 - (xn)); \
            SP_S_delta1 = (delta) / SP_S_delta0; \
        end else begin \
            SP_S_delta0 = `ke05 / `P3((xn) - SP_S_x0 - `se05); \
            SP_S_delta1 = `ke05 / `P3(SP_S_x0 - `se05); \
        end \
    end \
    SP_S_temp   = 1.0 / (2.0 + SP_S_x0 * SP_S_x0); \
    SP_S_xi0    = SP_S_x0 * SP_S_x0 * SP_S_temp; \
    SP_S_xi1    = 4.0 * (SP_S_x0 * SP_S_temp * SP_S_temp); \
    SP_S_xi2    = (8.0 * SP_S_temp-12.0 * SP_S_xi0) * SP_S_temp * SP_S_temp; \
    SP_S_temp   = xg - SP_S_x0; \
    SP_S_pC     = 2.0 * SP_S_temp + Gf2 * (1.0 - SP_S_delta1 + SP_S_delta0 - (delta) * (1.0 + SP_S_xi1)); \
    SP_S_qC     = SP_S_temp * SP_S_temp - Gf2 * (SP_S_delta1 + SP_S_x0 - 1.0 + SP_S_delta0 - (delta) * (SP_S_x0 + 1.0 + SP_S_xi0)); \
    SP_S_temp   = 2.0 - Gf2*(SP_S_delta1+SP_S_delta0-(delta)*SP_S_xi2); \
    SP_S_temp   = SP_S_pC * SP_S_pC - 2.0 * (SP_S_qC * SP_S_temp); \
    sp          = SP_S_x0 + 2.0 * (SP_S_qC / (SP_S_pC + sqrt(SP_S_temp)));\
end

//
//  sp_ov    surface potential calculation for the overlap regions
//
`define sp_ov(sp,xg) \
if (abs(xg) <= x_mrg_ov) begin \
    sp         =  (-(xg) * inv_xi_ov); \
end else begin \
    if (xg < -x_mrg_ov) begin \
        SP_OV_yg   = -xg; \
        SP_OV_z    =  x1 * SP_OV_yg * inv_xi_ov; \
        SP_OV_eta  =  0.5 * (SP_OV_z + 10.0 - sqrt((SP_OV_z - 6.0) * (SP_OV_z - 6.0) + 64.0)); \
        SP_OV_a    =  (SP_OV_yg - SP_OV_eta) * (SP_OV_yg - SP_OV_eta) + GOV2 * (SP_OV_eta + 1.0); \
        SP_OV_c    =  2.0 * (SP_OV_yg - SP_OV_eta) - GOV2; \
        SP_OV_tau  =  ln(SP_OV_a / GOV2) - SP_OV_eta; \
        `sigma(SP_OV_a, SP_OV_c, SP_OV_tau, SP_OV_eta, SP_OV_y0) \
        SP_OV_D0   =  exp(SP_OV_y0); \
        SP_OV_temp =  SP_OV_yg - SP_OV_y0; \
        SP_OV_p    =  2.0 * SP_OV_temp + GOV2 * (SP_OV_D0 - 1.0); \
        SP_OV_q    =  SP_OV_temp * SP_OV_temp + GOV2 * (SP_OV_y0 + 1.0 - SP_OV_D0); \
        SP_OV_xi   =  1.0 - GOV2 * 0.5 * SP_OV_D0; \
        SP_OV_temp =  SP_OV_p * SP_OV_p - 4.0 * (SP_OV_xi * SP_OV_q); \
        SP_OV_w    =  2.0 * (SP_OV_q / (SP_OV_p + sqrt(SP_OV_temp))); \
        sp         = -(SP_OV_y0 + SP_OV_w); \
    end else begin \
        SP_OV_Afac =  (xi_ov * x1 * inv_xg1 - 1.0) * inv_xg1; \
        SP_OV_xbar =  xg * inv_xi_ov * (1.0 + SP_OV_Afac * xg); \
        `expl_low(-SP_OV_xbar, SP_OV_temp) \
        SP_OV_w    =  1.0 - SP_OV_temp; \
        SP_OV_x0   =  xg + GOV2 * 0.5 - GOV * sqrt(xg + GOV2 * 0.25 - SP_OV_w); \
        `expl_low(-SP_OV_x0, SP_OV_D0) \
        SP_OV_p    =  2.0 * (xg - SP_OV_x0) + GOV2 * (1 - SP_OV_D0); \
        SP_OV_q    =  (xg - SP_OV_x0) * (xg - SP_OV_x0) - GOV2 * (SP_OV_x0 - 1.0 + SP_OV_D0); \
        SP_OV_xi   =  1.0 - GOV2 * 0.5 * SP_OV_D0; \
        SP_OV_temp =  SP_OV_p * SP_OV_p - 4.0 * (SP_OV_xi * SP_OV_q); \
        SP_OV_u    =  2.0 * (SP_OV_q / (SP_OV_p + sqrt(SP_OV_temp))); \
        sp         =  SP_OV_x0 + SP_OV_u; \
    end \
    sp         = -sp; \
end
