// Model generated by Verilog-A Distiller.
// (c)2026 Arpad Buermen. All rights reserved.
// SPDX-License-Identifier: AGPL-3.0-or-later
// 
// SPICE flavour: ngspice
// Version      : ngspice-45-116-gf11f4594e
// Origin       : https://sourceforge.net/u/arpadbuermen/ngspice/ci/vadng-pre-46/tree/
// Date         : 2026-02-02 07:38:34 UTC
// Module name  : sp_mes1
// Model variant: sn
// 
// Notes:
//   Parameter m was replaced with builtin Verilog-A parameter $mfactor.
//
//   All parameters and output variables refer to a single parallel instance,
//   even if $mfactor>1.
//
//   Parameter off was removed. Bypassing is not available in Verilog-A. 
//   
//   Device type is set by the type parameter to NJF (1) or PJF (-1). 
//   
//   Output variables cg, cd, cgd, and is were renamed to i_g, i_d, i_gd, 
//   and i_s due to a conflict of cgd and is with model parameters. 
//   To keep names consistent all current output variables were renamed. 
//   
//   Parameters ic, ic-vds, and ic-vgs were removed. Initial conditions 
//   should be set via the simulator's initial conditions mechanism.
//
//   Simplified noise model used (ignores capacitive current).
//   Appropriate only for small-signal noise analysis.
//
// CKTcircuit member mapping
//   CKTgmin -> ('gmin', '$simparam("gmin", 1e-12)')
//
// Source files and copyright information:
//   mes/mesdefs.h
//     Copyright 1990 Regents of the University of California.  All rights reserved.
//     Author: 1985 S. Hwang
//   mes/mes.c
//     Copyright 1990 Regents of the University of California.  All rights reserved.
//     Author: 1987 Thomas L. Quarles
//   mes/mesparam.c
//   mes/mesmpar.c
//     Copyright 1990 Regents of the University of California.  All rights reserved.
//     Author: 1985 S. Hwang
//   mes/mesask.c
//   mes/mesmask.c
//     Copyright 1990 Regents of the University of California.  All rights reserved.
//     Author: 1987 Thomas L. Quarles
//   mes/messetup.c
//     Copyright 1990 Regents of the University of California.  All rights reserved.
//     Author: 1985 S. Hwang
//     Modified: 2000 AlansFixes
//   mes/mestemp.c
//     Copyright 1990 Regents of the University of California.  All rights reserved.
//     Author: 1985 S. Hwang
//   mes/mesload.c
//     Copyright 1990 Regents of the University of California.  All rights reserved.
//     Author: 1985 S. Hwang
//     Modified: 2000 AlansFixes
//   mes/mesnoise.c
//     Copyright 1990 Regents of the University of California.  All rights reserved.
//     Author: 1987 Gary W. Ng

`include "constants.vams"
`include "disciplines.vams"

module sp_mes1(d, g, s);
  inout d, g, s;
  electrical d, g, s, d_int, s_int;

  // Instance parameters
  (* desc = "Area factor", type = "instance" *) parameter real area = 1.0;

  // Model parameters
  (* desc = "N-type (1) or P-type (-1)" *) parameter integer type = 1;
  (* desc = "Pinch-off voltage" *) parameter real vt0 = 0;
  aliasparam vto = vt0;
  (* desc = "Saturation voltage parameter" *) parameter real alpha = 2;
  (* desc = "Transconductance parameter" *) parameter real beta = 0.0025;
  (* desc = "Channel length modulation parm." *) parameter real lambda = 0;
  (* desc = "Doping tail extending parameter" *) parameter real b = 0.3;
  (* desc = "Drain ohmic resistance" *) parameter real rd = 0;
  (* desc = "Source ohmic resistance" *) parameter real rs = 0;
  (* desc = "G-S junction capacitance" *) parameter real cgs = 0;
  (* desc = "G-D junction capacitance" *) parameter real cgd = 0;
  (* desc = "Gate junction potential" *) parameter real pb = 1;
  (* desc = "Junction saturation current" *) parameter real is = 1e-14;
  (* desc = "Forward bias junction fit parm." *) parameter real fc = 0.5;
  (* desc = "Flicker noise coefficient" *) parameter real kf = 0;
  (* desc = "Flicker noise exponent" *) parameter real af = 1;

  // Instance output variables
  (* desc = "Gate-Source voltage" *) real vgs;
  (* desc = "Gate-Drain voltage" *) real vgd;
  (* desc = "Transconductance" *) real gm;
  (* desc = "Drain-Source conductance" *) real gds;
  (* desc = "Gate-Source conductance" *) real ggs;
  (* desc = "Gate-Drain conductance" *) real ggd;
  (* desc = "Capacitance due to gate-source charge storage" *) real cqgs;
  (* desc = "Capacitance due to gate-drain charge storage" *) real cqgd;
  (* desc = "Gate-Source charge storage" *) real qgs;
  (* desc = "Gate-Drain charge storage" *) real qgd;

  // Model output variables
  (* desc = "Drain conductance" *) real gd;
  (* desc = "Source conductance" *) real gs;
  (* desc = "Depletion capacitance" *) real depl_cap;
  (* desc = "Critical voltage" *) real vcrit;

  // Instance fields
  integer MESmode = 0;
  real MESdcCurrent = 0;

  // Model fields
  real MESthreshold = 0;
  real MESdrainConduct = 0;
  real MESsourceConduct = 0;
  real MESdepletionCap = 0;
  real MESf1 = 0;
  real MESf2 = 0;
  real MESf3 = 0;
  real MESvcrit = 0;
  integer MEStype = 0;

  // States
  real MESvgs = 0;
  real MESvgd = 0;
  real MEScg = 0;
  real MEScd = 0;
  real MEScgd = 0;
  real MESgm = 0;
  real MESgds = 0;
  real MESggs = 0;
  real MESggd = 0;
  real MESqgs = 0;
  real MEScqgs = 0;
  real MESqgd = 0;
  real MEScqgd = 0;

  // Model parameter access locals

  // Instance parameter access locals

  // Device setup locals

  // Device temperature dependence locals
  real xfc = 0;
  real temp = 0;

  // Device load locals
  integer limited = 0;
  real afact = 0;
  real load_beta = 0;
  real betap = 0;
  real capgd = 0;
  real capgs = 0;
  real cd = 0;
  real cdrain = 0;
  real cdreq = 0;
  real ceq = 0;
  real ceqgd = 0;
  real ceqgs = 0;
  real cg = 0;
  real load_cgd = 0;
  real cgdna = 0;
  real cgsna = 0;
  real csat = 0;
  real czgd = 0;
  real czgs = 0;
  real denom = 0;
  real evgd = 0;
  real evgs = 0;
  real gdpr = 0;
  real load_gds = 0;
  real geq = 0;
  real load_ggd = 0;
  real load_ggs = 0;
  real load_gm = 0;
  real gspr = 0;
  real invdenom = 0;
  real lfact = 0;
  real phib = 0;
  real prod = 0;
  real qgga = 0;
  real vcap = 0;
  real load_vcrit = 0;
  real vds = 0;
  real load_vgd = 0;
  real vgdt = 0;
  real load_vgs = 0;
  real vgst = 0;
  real load_vto = 0;
  real arg = 0;
  real vcnorm = 0;

  // Device noise locals

  // Global constants
  real CONSTroot2 = sqrt(2.0);
  real CONSTvt0 = 1.38064852e-23*(27+273.15)/1.6021766208e-19;
  real CONSTKoverQ = 1.38064852e-23/1.6021766208e-19;
  real CONSTe = exp(1.0);
  real VACONSTcharge = 1.6021766208e-19;
  real VACONSTboltz = 1.38064852e-23;

  // Evaluation constants
  real lc_gmin = 0;

  // Translated function definitions
  analog function real qggnew;
    input vgs, vgd, phib, vcap, vto, cgs, cgd;
    inout cgsnew, cgdnew;
    real vgs;
    real vgd;
    real phib;
    real vcap;
    real vto;
    real cgs;
    real cgd;
    real cgsnew;
    real cgdnew;
    real veroot;
    real veff1;
    real veff2;
    real del;
    real vnroot;
    real vnew1;
    real vnew3;
    real vmax;
    real ext;
    real qroot;
    real qggval;
    real par1;
    real cfact;
    real cplus;
    real cminus;
    begin
      veroot = sqrt((vgs-vgd)*(vgs-vgd)+vcap*vcap);
      veff1 = 0.5*(vgs+vgd+veroot);
      veff2 = veff1-veroot;
      del = 0.2;
      vnroot = sqrt((veff1-vto)*(veff1-vto)+del*del);
      vnew1 = 0.5*(veff1+vto+vnroot);
      vnew3 = vnew1;
      vmax = 0.5;
      if (vnew1<vmax) begin
        ext = 0;
      end else begin
        vnew1 = vmax;
        ext = (vnew3-vmax)/sqrt(1-vmax/phib);
      end
      qroot = sqrt(1-vnew1/phib);
      qggval = cgs*(2*phib*(1-qroot)+ext)+cgd*veff2;
      par1 = 0.5*(1+(veff1-vto)/vnroot);
      cfact = (vgs-vgd)/veroot;
      cplus = 0.5*(1+cfact);
      cminus = cplus-cfact;
      cgsnew = cgs/qroot*par1*cplus+cgd*cminus;
      cgdnew = cgs/qroot*par1*cminus+cgd*cplus;
      qggnew = qggval;
    end
  endfunction

  // Verbatim analog functions
  analog function integer initialize_limiting;
    integer il;
    begin
      il = $simparam("iniLim", -1);
      if (il<0) begin
        // iniLim not available, use heuristics
        initialize_limiting = 
          $simparam("iteration", 10)==1 && 
          (analysis("dc") || analysis("static")) && 
          analysis("nodeset");
      end else begin
        initialize_limiting = il;
      end
    end
  endfunction

  analog function real DEVlimitOldGet;
    input vnew, vold;
    real vnew, vold, result;
    begin
      DEVlimitOldGet = vold;
    end
  endfunction

  analog function real DEVlimitNewSet;
    input vnew, vold, new_value, limited;
    real vnew, vold, new_value;
    integer limited;
    begin
      DEVlimitNewSet = new_value;
      if (limited) begin
        $discontinuity(-1);
      end
    end
  endfunction

  analog function real DEVpnjlim;
    input vnew, vold, vt, vcrit;
    inout limiting_applied;
    real vnew, vold, vt, vcrit, limited, arg;
    integer limiting_applied;
    
    begin
      limited = vnew;
      if ((vnew > vcrit) && (abs(vnew - vold) > (vt + vt))) begin
        // Positive vnew above vcrit, change greater than 2*vt
        if(vold > 0) begin
          arg = (vnew - vold) / vt;
          if(arg > 0) begin
            limited = vold + vt * ln(1+arg);
            limiting_applied = 1;
          end else begin
            limited = vold - vt * ln(1-arg);
            limiting_applied = 1;
          end
        end else begin
          limited = vt *ln(vnew/vt);
          limiting_applied = 1;
        end
      end else if (vnew<0) begin
        // Negative vnew, use ngspice limiting
        if (vold > 0) begin
          arg = -1*vold-1; 
        end else begin
          arg = 2*vold-1;
        end
        if (vnew<arg) begin
          limited = arg;
          limiting_applied = 1;
        end
      end 
      DEVpnjlim = limited;
    end
  endfunction

  analog function real DEVfetlim;
    input vnew, vold, vto;
    inout limiting_applied;
    real vnew, vold, vto, vlimited;
    real vtsthi, vtstlo, vtox, delv, vtemp;
    integer limiting_applied;  
    begin
      vlimited = vnew;
      vtsthi = abs(2*(vold-vto))+2;
      // vtstlo = vtsthi/2 +2;
      vtstlo = abs(vold-vto)+1;
      vtox = vto + 3.5;
      delv = vnew-vold;
      
      if (vold >= vto) begin
        if(vold >= vtox) begin
          if(delv <= 0) begin
            /* going off */
            if(vlimited >= vtox) begin
                if(-delv > vtstlo) begin
                vlimited =  vold - vtstlo;
                end
            end else begin
              vlimited = max(vnew,vto+2);
            end
          end else begin
            /* staying on */
            if(delv >= vtsthi) begin
              vlimited = vold + vtsthi;
            end
          end
        end else begin
          /* middle region */
          if(delv <= 0) begin
            /* decreasing */
            vlimited = max(vnew,vto-0.5);
          end else begin
            /* increasing */
            vlimited = min(vnew,vto+4);
          end
        end
      end else begin
        /* off */
        if(delv <= 0) begin
          if(-delv >vtsthi) begin
            vlimited = vold - vtsthi;
          end
        end else begin
          vtemp = vto + 0.5;
          if(vnew <= vtemp) begin
            if(delv > vtstlo) begin
              vlimited = vold + vtstlo;
            end
          end else begin
            vlimited = vtemp;
          end
        end
      end
      if (vlimited!=vnew) begin
        limiting_applied = 1;
      end
      DEVfetlim = vlimited;
    end
  endfunction

  // Analog block
  analog begin

    // Instance field assignments

    // Model field assignments
    MEStype = type;
    if ($param_given(vt0)) begin
      MESthreshold = vt0;
    end

    // Evaluation constants
    lc_gmin = $simparam("gmin", 1e-12);

    // Tag: setup, function: MESsetup
    if (MEStype!=1&&MEStype!=-1) begin
      MEStype = 1;
    end
    if (!$param_given(vt0)) begin
      MESthreshold = -2;
    end
    if (!(rs!=0)) begin
      V(s_int, s) <+ 0;
    end
    if (!(rd!=0)) begin
      V(d_int, d) <+ 0;
    end

    // Tag: temp, function: MEStemp
    if (rd!=0) begin
      MESdrainConduct = 1/rd;
    end else begin
      MESdrainConduct = 0;
    end
    if (rs!=0) begin
      MESsourceConduct = 1/rs;
    end else begin
      MESsourceConduct = 0;
    end
    MESdepletionCap = fc*pb;
    xfc = 1-fc;
    temp = sqrt(xfc);
    MESf1 = pb*(1-temp)/(1-0.5);
    MESf2 = temp*temp*temp;
    MESf3 = 1-fc*(1+0.5);
    MESvcrit = CONSTvt0*ln(CONSTvt0/(CONSTroot2*is));

    // Tag: load, function: MESload
    load_beta = beta*area;
    gdpr = MESdrainConduct*area;
    gspr = MESsourceConduct*area;
    csat = is*area;
    load_vcrit = MESvcrit;
    load_vto = MESthreshold;
    limited = 0;
    MESvgs = MEStype * $limit(V(g, s_int), DEVlimitOldGet);
    MESvgd = MEStype * $limit(V(g, d_int), DEVlimitOldGet);
    load_vgs = MEStype*V(g, s_int);
    load_vgd = MEStype*V(g, d_int);
    load_vgs = DEVpnjlim(load_vgs, MESvgs, CONSTvt0, load_vcrit, limited);
    load_vgd = DEVpnjlim(load_vgd, MESvgd, CONSTvt0, load_vcrit, limited);
    load_vgs = DEVfetlim(load_vgs, MESvgs, MESthreshold, limited);
    load_vgd = DEVfetlim(load_vgd, MESvgd, MESthreshold, limited);
    if (initialize_limiting()) begin
        load_vgs = -1;
        load_vgd = -1;
    end
    load_vgs = MEStype * $limit(V(g, s_int), DEVlimitNewSet, MEStype * load_vgs, limited);
    load_vgd = MEStype * $limit(V(g, d_int), DEVlimitNewSet, MEStype * load_vgd, limited);
    vds = load_vgs-load_vgd;
    if (load_vgs<=-3*CONSTvt0) begin
      arg = 3*CONSTvt0/(load_vgs*CONSTe);
      arg = arg*arg*arg;
      cg = -csat*(1+arg)+lc_gmin*load_vgs;
      load_ggs = csat*3*arg/load_vgs+lc_gmin;
    end else begin
      evgs = exp(load_vgs/CONSTvt0);
      load_ggs = csat*evgs/CONSTvt0+lc_gmin;
      cg = csat*(evgs-1)+lc_gmin*load_vgs;
    end
    if (load_vgd<=-3*CONSTvt0) begin
      arg = 3*CONSTvt0/(load_vgd*CONSTe);
      arg = arg*arg*arg;
      load_cgd = -csat*(1+arg)+lc_gmin*load_vgd;
      load_ggd = csat*3*arg/load_vgd+lc_gmin;
    end else begin
      evgd = exp(load_vgd/CONSTvt0);
      load_ggd = csat*evgd/CONSTvt0+lc_gmin;
      load_cgd = csat*(evgd-1)+lc_gmin*load_vgd;
    end
    cg = cg+load_cgd;
    if (vds>=0) begin
      vgst = load_vgs-MESthreshold;
      if (vgst<=0) begin
        cdrain = 0;
        load_gm = 0;
        load_gds = 0;
      end else begin
        prod = 1+lambda*vds;
        betap = load_beta*prod;
        denom = 1+b*vgst;
        invdenom = 1/denom;
        if (vds>=3/alpha) begin
          cdrain = betap*vgst*vgst*invdenom;
          load_gm = betap*vgst*(1+denom)*invdenom*invdenom;
          load_gds = lambda*load_beta*vgst*vgst*invdenom;
        end else begin
          afact = 1-alpha*vds/3;
          lfact = 1-afact*afact*afact;
          cdrain = betap*vgst*vgst*invdenom*lfact;
          load_gm = betap*vgst*(1+denom)*invdenom*invdenom*lfact;
          load_gds = load_beta*vgst*vgst*invdenom*(alpha*afact*afact*prod+lfact*lambda);
        end
      end
    end else begin
      vgdt = load_vgd-MESthreshold;
      if (vgdt<=0) begin
        cdrain = 0;
        load_gm = 0;
        load_gds = 0;
      end else begin
        prod = 1-lambda*vds;
        betap = load_beta*prod;
        denom = 1+b*vgdt;
        invdenom = 1/denom;
        if (-vds>=3/alpha) begin
          cdrain = -betap*vgdt*vgdt*invdenom;
          load_gm = -betap*vgdt*(1+denom)*invdenom*invdenom;
          load_gds = lambda*load_beta*vgdt*vgdt*invdenom-load_gm;
        end else begin
          afact = 1+alpha*vds/3;
          lfact = 1-afact*afact*afact;
          cdrain = -betap*vgdt*vgdt*invdenom*lfact;
          load_gm = -betap*vgdt*(1+denom)*invdenom*invdenom*lfact;
          load_gds = load_beta*vgdt*vgdt*invdenom*(alpha*afact*afact*prod+lfact*lambda)-load_gm;
        end
      end
    end
    cd = cdrain-load_cgd;
    vcnorm = cgs * area;
    if (vcnorm<=0) begin
        vcnorm = cgd * area;
    end
    if (vcnorm<=0) begin
        vcnorm = 1;
    end
    czgs = cgs*area;
    czgd = cgd*area;
    phib = pb;
    vcap = 1/alpha;
    qgga = qggnew(load_vgs, load_vgd, phib, vcap, load_vto, czgs, czgd, cgsna, cgdna);
    capgs = cgsna;
    capgd = cgdna;
    geq = 0;
    ceq = capgs*(ddt(vcnorm*load_vgs)/vcnorm);
    MEScqgs = ceq;
    load_ggs = load_ggs+geq;
    cg = cg+MEScqgs;
    geq = 0;
    ceq = capgd*(ddt(vcnorm*load_vgd)/vcnorm);
    MEScqgd = ceq;
    load_ggd = load_ggd+geq;
    cg = cg+MEScqgd;
    MESdcCurrent = cd;
    cd = cd-MEScqgd;
    load_cgd = load_cgd+MEScqgd;
    MESvgs = load_vgs;
    MESvgd = load_vgd;
    MEScg = cg;
    MEScd = cd;
    MEScgd = load_cgd;
    MESgm = load_gm;
    MESgds = load_gds;
    MESggs = load_ggs;
    MESggd = load_ggd;
    ceqgd = MEStype*load_cgd;
    ceqgs = MEStype*(cg-load_cgd);
    cdreq = MEStype*(cd+load_cgd);
    
    // Residuals
    I(d) <+ gdpr*V(d, d_int);
    I(g) <+ -(-ceqgs-ceqgd);
    I(s) <+ gspr*V(s, s_int);
    I(s_int) <+ gspr*V(s_int, s)+-(cdreq+ceqgs);
    I(d_int) <+ gdpr*V(d_int, d)+-(-cdreq+ceqgd);

    // Tag: noise, function: MESnoise
    I(d_int, d) <+ white_noise(4*(VACONSTboltz*($temperature*(MESdrainConduct*area))), "rd");
    I(s_int, s) <+ white_noise(4*(VACONSTboltz*($temperature*(MESsourceConduct*area))), "rs");
    I(d_int, s_int) <+ white_noise(4*(VACONSTboltz*($temperature*(2.0/3.0*abs(MESgm)))), "id");
    I(d_int, s_int) <+ flicker_noise(((MESdcCurrent>=0) ? (1) : (-1))*(kf*exp(af*ln(((abs(MESdcCurrent)>1E-38) ? (abs(MESdcCurrent)) : (1E-38))))), 1, "flicker");

    // Instance output variable computation
    vgs = MESvgs;
    vgd = MESvgd;
    gm = MESgm;
    gds = MESgds;
    ggs = MESggs;
    ggd = MESggd;
    cqgs = capgs;
    cqgd = capgd;
    qgs = MESqgs;
    qgd = MESqgd;

    // Model output variable computation

  end
endmodule
