// 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-44-549-ga4ff5a204
// Origin       : https://sourceforge.net/u/arpadbuermen/ngspice/ci/vadng-pre-48/tree/
// Date         : 2026-08-18 12:19:02 UTC
// Module name  : sp_mos3
// Model variant: default
// 
// 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 NMOS (1) or PMOS (-1). 
//   
//   Output variables rs and rd were removed due to a conflict with model 
//   parameters. Their inverses are available as sourceconductance and 
//   drainconductance output variables. 
//   
//   Output variables cbd, cbs, ig, id, is, and ib were renamed to c_bd, 
//   c_bs, i_g, i_d, i_s, i_b due to conflicts with model parameters. 
//   
//   Meyer charge is not computed and therefore not available. 
//   Output variables qgs, qgd, and qgb were removed. 
//   
//   Parameters ic, icvds, icvgs, and icvbs were removed. Initial conditions 
//   should be set via the simulator's initial conditions mechanism. 
//   
//   Noise model excludes Meyer capacitance currents from the drain 
//   current that is used for computing noise. This is a SPICE3 feature. 
//   Simplified noise model also excludes the capacitive current of the 
//   B-D diode. Due to the way OpenVAF handles c(v)*ddt(v) the implicit 
//   equations do not go away even if simplified noise model is used.
//
//   Full noise model used (appropriate for all noise analyses).
//   OpenVAF may create implicit equations.
//
// SPICE variable mapping
//   scale -> $simparam("scale", 1)
//
// CKTcircuit member mapping
//        CKTbadMos3 -> ('badmos3', '$simparam("badmos3", 0)', 'const')
//   CKTdefaultMosAD -> ('defad', '$simparam("defad", 0)', 'const')
//   CKTdefaultMosAS -> ('defas', '$simparam("defas", 0)', 'const')
//    CKTdefaultMosL -> ('defl', '$simparam("defl", 1e-4)', 'const')
//    CKTdefaultMosW -> ('defw', '$simparam("defw", 1e-4)', 'const')
//       CKTfixLimit -> ('oldlimit', '$simparam("oldlimit", 0)', 'const')
//           CKTgmin -> ('gmin', '$simparam("gmin", 1e-12)')
//        CKTnomTemp -> ('tnom', '($simparam("tnom", 27)+273.15)')
//           CKTtemp -> (None, '$temperature')
//
// Source files and copyright information:
//   devsup.c
//     Copyright 1990 Regents of the University of California.  All rights reserved.
//     Author: 1985 Thomas L. Quarles
//     Modified: 2000 AlansFixes
//   mos3/mos3defs.h
//     Copyright 1990 Regents of the University of California.  All rights reserved.
//     Author: 1985 Thomas L. Quarles
//     Modified: 2000 AlanFixes
//   mos3/mos3.c
//     Copyright 1990 Regents of the University of California.  All rights reserved.
//     Author: 1987 Thomas L. Quarles
//     Modified: 2000 AlansFixes
//   mos3/mos3par.c
//   mos3/mos3mpar.c
//     Copyright 1990 Regents of the University of California.  All rights reserved.
//     Author: 1985 Thomas L. Quarles
//     Modified: 2000 AlansFixes
//   mos3/mos3ask.c
//     Copyright 1990 Regents of the University of California.  All rights reserved.
//     Author: 1987 Mathew Lew and Thomas L. Quarles
//     Modified: 2000 AlansFixes
//   mos3/mos3mask.c
//     Copyright 1990 Regents of the University of California.  All rights reserved.
//     Author: 1987 Thomas L. Quarles
//     Modified: 2000 AlansFixes
//   mos3/mos3set.c
//     Copyright 1990 Regents of the University of California.  All rights reserved.
//     Author: 1985 Thomas L. Quarlesù
//     Modified: 2000 AlansFixes
//   mos3/mos3temp.c
//   mos3/mos3load.c
//     Copyright 1990 Regents of the University of California.  All rights reserved.
//     Author: 1985 Thomas L. Quarles
//     Modified: 2000 AlansFixes
//   mos3/mos3noi.c
//     Copyright 1990 Regents of the University of California.  All rights reserved.
//     Author: 1987 Gary W. Ng
//     Modified: 2000 AlansFixes

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

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

  // Instance parameters
  (* desc = "Length", type = "instance" *) parameter real l = 0;
  (* desc = "Width", type = "instance" *) parameter real w = 0;
  (* desc = "Drain area", type = "instance" *) parameter real ad = 0;
  (* desc = "Source area", type = "instance" *) parameter real as = 0;
  (* desc = "Drain perimeter", type = "instance" *) parameter real pd = 0;
  (* desc = "Source perimeter", type = "instance" *) parameter real ps = 0;
  (* desc = "Drain squares", type = "instance" *) parameter real nrd = 1;
  (* desc = "Source squares", type = "instance" *) parameter real nrs = 1;
  (* desc = "Instance operating temperature", type = "instance" *) parameter real temp = 0;
  (* desc = "Instance temperature difference", type = "instance" *) parameter real dtemp = 0.0;

  // Model parameters
  (* desc = "NMOS (1) or PMOS (-1)" *) parameter integer type = 1;
  (* desc = "Threshold voltage" *) parameter real vto = 0;
  aliasparam vt0 = vto;
  (* desc = "Transconductance parameter" *) parameter real kp = 2e-05;
  (* desc = "Bulk threshold parameter" *) parameter real gamma = 0;
  (* desc = "Surface potential" *) parameter real phi = 0.6;
  (* desc = "Drain ohmic resistance" *) parameter real rd = 0;
  (* desc = "Source ohmic resistance" *) parameter real rs = 0;
  (* desc = "B-D junction capacitance" *) parameter real cbd = 0;
  (* desc = "B-S junction capacitance" *) parameter real cbs = 0;
  (* desc = "Bulk junction sat. current" *) parameter real is = 1e-14;
  (* desc = "Bulk junction potential" *) parameter real pb = 0.8;
  (* desc = "Gate-source overlap cap." *) parameter real cgso = 0;
  (* desc = "Gate-drain overlap cap." *) parameter real cgdo = 0;
  (* desc = "Gate-bulk overlap cap." *) parameter real cgbo = 0;
  (* desc = "Sheet resistance" *) parameter real rsh = 0;
  (* desc = "Bottom junction cap per area" *) parameter real cj = 0;
  (* desc = "Bottom grading coefficient" *) parameter real mj = 0.5;
  (* desc = "Side junction cap per area" *) parameter real cjsw = 0;
  (* desc = "Side grading coefficient" *) parameter real mjsw = 0.33;
  (* desc = "Bulk jct. sat. current density" *) parameter real js = 0;
  (* desc = "Oxide thickness" *) parameter real tox = 1e-07;
  (* desc = "Lateral diffusion" *) parameter real ld = 0;
  (* desc = "Length mask adjustment" *) parameter real xl = 0;
  (* desc = "Width Narrowing (Diffusion)" *) parameter real wd = 0;
  (* desc = "Width mask adjustment" *) parameter real xw = 0;
  (* desc = "Threshold voltage Adjust" *) parameter real delvto = 0;
  aliasparam delvt0 = delvto;
  (* desc = "Surface mobility" *) parameter real u0 = 600;
  aliasparam uo = u0;
  (* desc = "Forward bias jct. fit parm." *) parameter real fc = 0.5;
  (* desc = "Substrate doping" *) parameter real nsub = 0;
  (* desc = "Gate type" *) parameter integer tpg = 1;
  (* desc = "Surface state density" *) parameter real nss = 0;
  (* desc = "Maximum carrier drift velocity" *) parameter real vmax = 0;
  (* desc = "Junction depth" *) parameter real xj = 0;
  (* desc = "Fast surface state density" *) parameter real nfs = 0;
  (* desc = "Vds dependence of threshold voltage" *) parameter real eta = 0;
  (* desc = "Width effect on threshold" *) parameter real delta = 0;
  (* desc = "Vgs dependence on mobility" *) parameter real theta = 0;
  (* desc = "Kappa" *) parameter real kappa = 0.2;
  (* desc = "Parameter measurement temperature" *) parameter real tnom = 0;
  (* desc = "Flicker noise coefficient" *) parameter real kf = 0;
  (* desc = "Flicker noise exponent" *) parameter real af = 1;
  (* desc = "Noise model selection" *) parameter integer nlev = 2;
  (* desc = "Channel shot noise coefficient" *) parameter real gdsnoi = 1;

  // Instance output variables
  (* desc = "Drain current" *) real i_d;
  (* desc = "B-D junction current" *) real ibd;
  (* desc = "B-S junction current" *) real ibs;
  (* desc = "Source current" *) real i_s;
  (* desc = "Gate current" *) real i_g;
  (* desc = "Bulk current" *) real i_b;
  (* desc = "Gate-Source voltage" *) real vgs;
  (* desc = "Drain-Source voltage" *) real vds;
  (* desc = "Bulk-Source voltage" *) real vbs;
  (* desc = "Bulk-Drain voltage" *) real vbd;
  (* desc = "Turn-on voltage" *) real von;
  (* desc = "Saturation drain voltage" *) real vdsat;
  (* desc = "Critical source voltage" *) real sourcevcrit;
  (* desc = "Critical drain voltage" *) real drainvcrit;
  (* desc = "Source conductance" *) real sourceconductance;
  (* desc = "Drain conductance" *) real drainconductance;
  (* desc = "Transconductance" *) real gm;
  (* desc = "Drain-Source conductance" *) real gds;
  (* desc = "Bulk-Source transconductance" *) real gmb;
  (* desc = "Bulk-Drain conductance" *) real gbd;
  (* desc = "Bulk-Source conductance" *) real gbs;
  (* desc = "Bulk-Drain capacitance" *) real c_bd;
  (* desc = "Bulk-Source capacitance" *) real c_bs;
  (* desc = "Gate-Source capacitance" *) real cgs;
  (* desc = "Gate-Drain capacitance" *) real cgd;
  (* desc = "Gate-Bulk capacitance" *) real cgb;
  (* desc = "Capacitance due to gate-source charge storage" *) real cqgs;
  (* desc = "Capacitance due to gate-drain charge storage" *) real cqgd;
  (* desc = "Capacitance due to gate-bulk charge storage" *) real cqgb;
  (* desc = "Capacitance due to bulk-drain charge storage" *) real cqbd;
  (* desc = "Capacitance due to bulk-source charge storage" *) real cqbs;
  (* desc = "Zero-Bias B-D junction capacitance" *) real cbd0;
  (* desc = "Zero-Bias B-D sidewall capacitance" *) real cbdsw0;
  (* desc = "Zero-Bias B-S junction capacitance" *) real cbs0;
  (* desc = "Zero-Bias B-S sidewall capacitance" *) real cbssw0;
  (* desc = "Bulk-Source charge storage" *) real qbs;
  (* desc = "Bulk-Drain charge storage" *) real qbd;

  // Model output variables
  (* desc = "Depletion layer width" *) real xd;
  (* desc = "Alpha" *) real alpha;
  (* desc = "" *) real input_delta;

  // Instance fields
  real MOS3l = 0;
  real MOS3w = 0;
  real MOS3drainArea = 0;
  real MOS3sourceArea = 0;
  real MOS3drainPerimiter = 0;
  real MOS3sourcePerimiter = 0;
  real MOS3sourceConductance = 0;
  real MOS3drainConductance = 0;
  real MOS3temp = 0;
  real MOS3tTransconductance = 0;
  real MOS3tSurfMob = 0;
  real MOS3tPhi = 0;
  real MOS3tVto = 0;
  real MOS3tSatCur = 0;
  real MOS3tSatCurDens = 0;
  real MOS3tCbd = 0;
  real MOS3tCbs = 0;
  real MOS3tCj = 0;
  real MOS3tCjsw = 0;
  real MOS3tBulkPot = 0;
  real MOS3tDepCap = 0;
  real MOS3tVbi = 0;
  real MOS3von = 0;
  real MOS3vdsat = 0;
  real MOS3sourceVcrit = 0;
  real MOS3drainVcrit = 0;
  real MOS3cd = 0;
  real MOS3cbs = 0;
  real MOS3cbd = 0;
  real MOS3gmbs = 0;
  real MOS3gm = 0;
  real MOS3gds = 0;
  real MOS3gbd = 0;
  real MOS3gbs = 0;
  real MOS3capbd = 0;
  real MOS3capbs = 0;
  real MOS3Cbd = 0;
  real MOS3Cbdsw = 0;
  real MOS3Cbs = 0;
  real MOS3Cbssw = 0;
  real MOS3f2d = 0;
  real MOS3f3d = 0;
  real MOS3f4d = 0;
  real MOS3f2s = 0;
  real MOS3f3s = 0;
  real MOS3f4s = 0;
  integer MOS3mode = 0;
  real MOS3cgs = 0;
  real MOS3cgd = 0;
  real MOS3cgb = 0;
  real MOS3dcCurrent = 0;
  real meyer_scale = 0;
  real meyer_unscale = 0;
  integer MOS3lGiven = 0;
  integer MOS3wGiven = 0;
  integer MOS3drainAreaGiven = 0;
  integer MOS3sourceAreaGiven = 0;
  integer MOS3drainPerimiterGiven = 0;
  integer MOS3sourcePerimiterGiven = 0;
  integer MOS3tempGiven = 0;

  // Model fields
  real MOS3tnom = 0;
  real MOS3transconductance = 0;
  real MOS3oxideCapFactor = 0;
  real MOS3vt0 = 0;
  real MOS3phi = 0;
  real MOS3gamma = 0;
  real MOS3substrateDoping = 0;
  real MOS3coeffDepLayWidth = 0;
  real MOS3narrowFactor = 0;
  real MOS3alpha = 0;
  integer MOS3type = 0;
  integer MOS3tnomGiven = 0;

  // States
  real MOS3vbd = 0;
  real MOS3vbs = 0;
  real MOS3vgs = 0;
  real MOS3vds = 0;
  real MOS3capgs = 0;
  real MOS3qgs = 0;
  real MOS3cqgs = 0;
  real MOS3capgd = 0;
  real MOS3qgd = 0;
  real MOS3cqgd = 0;
  real MOS3capgb = 0;
  real MOS3qgb = 0;
  real MOS3cqgb = 0;
  real MOS3qbd = 0;
  real MOS3cqbd = 0;
  real MOS3qbs = 0;
  real MOS3cqbs = 0;

  // Model parameter access locals

  // Instance parameter access locals

  // Device setup locals

  // Device temperature dependence locals
  real wkfngs = 0;
  real wkfng = 0;
  real fermig = 0;
  real fermis = 0;
  real vfb = 0;
  real fact1 = 0;
  real fact2 = 0;
  real vt = 0;
  real vtnom = 0;
  real kt = 0;
  real kt1 = 0;
  real ratio = 0;
  real ratio4 = 0;
  real egfet = 0;
  real egfet1 = 0;
  real pbfact = 0;
  real pbfact1 = 0;
  real pbo = 0;
  real phio = 0;
  real arg1 = 0;
  real capfact = 0;
  real gmanew = 0;
  real gmaold = 0;
  real ni_temp = 0;
  real nifact = 0;
  real czbd = 0;
  real czbdsw = 0;
  real czbs = 0;
  real czbssw = 0;
  real arg = 0;
  real sarg = 0;
  real sargsw = 0;

  // Device load locals
  integer limited = 0;
  real Beta = 0;
  real DrainSatCur = 0;
  real EffectiveLength = 0;
  real EffectiveWidth = 0;
  real GateBulkOverlapCap = 0;
  real GateDrainOverlapCap = 0;
  real GateSourceOverlapCap = 0;
  real OxideCap = 0;
  real SourceSatCur = 0;
  real load_arg = 0;
  real cdrain = 0;
  real cdreq = 0;
  real ceq = 0;
  real ceqbd = 0;
  real ceqbs = 0;
  real ceqgb = 0;
  real ceqgd = 0;
  real ceqgs = 0;
  real evbd = 0;
  real evbs = 0;
  real gcgb = 0;
  real gcgd = 0;
  real gcgs = 0;
  real geq = 0;
  real load_sarg = 0;
  real load_sargsw = 0;
  real load_vbd = 0;
  real load_vbs = 0;
  real load_vds = 0;
  real load_vdsat = 0;
  real vgb = 0;
  real vgd = 0;
  real vgdo = 0;
  real load_vgs = 0;
  real load_von = 0;
  real xfact = 0;
  integer xnrm = 0;
  integer xrev = 0;
  real capgs = 0;
  real capgd = 0;
  real capgb = 0;
  real load_vt = 0;
  real coeff0 = 0;
  real coeff1 = 0;
  real coeff2 = 0;
  real oneoverxl = 0;
  real load_eta = 0;
  real phibs = 0;
  real sqphbs = 0;
  real dsqdvb = 0;
  real sqphis = 0;
  real sqphs3 = 0;
  real wps = 0;
  real oneoverxj = 0;
  real xjonxl = 0;
  real djonxj = 0;
  real wponxj = 0;
  real arga = 0;
  real argb = 0;
  real argc = 0;
  real dwpdvb = 0;
  real dadvb = 0;
  real dbdvb = 0;
  real gammas = 0;
  real fbodys = 0;
  real fbody = 0;
  real onfbdy = 0;
  real qbonco = 0;
  real vbix = 0;
  real wconxj = 0;
  real dfsdvb = 0;
  real dfbdvb = 0;
  real dqbdvb = 0;
  real vth = 0;
  real dvtdvb = 0;
  real csonco = 0;
  real cdonco = 0;
  real dxndvb = 0;
  real dvodvb = 0;
  real dvodvd = 0;
  real vgsx = 0;
  real dvtdvd = 0;
  real onfg = 0;
  real fgate = 0;
  real us = 0;
  real dfgdvg = 0;
  real dfgdvd = 0;
  real dfgdvb = 0;
  real dvsdvg = 0;
  real dvsdvb = 0;
  real dvsdvd = 0;
  real xn = 0;
  real vdsc = 0;
  real onvdsc = 0;
  real dvsdga = 0;
  real vdsx = 0;
  real dcodvb = 0;
  real cdnorm = 0;
  real cdo = 0;
  real cd1 = 0;
  real fdrain = 0;
  real fd2 = 0;
  real dfddvg = 0;
  real dfddvb = 0;
  real dfddvd = 0;
  real gdsat = 0;
  real cdsat = 0;
  real gdoncd = 0;
  real gdonfd = 0;
  real gdonfg = 0;
  real dgdvg = 0;
  real dgdvd = 0;
  real dgdvb = 0;
  real emax = 0;
  real emongd = 0;
  real demdvg = 0;
  real demdvd = 0;
  real demdvb = 0;
  real delxl = 0;
  real dldvd = 0;
  real dldem = 0;
  real ddldvg = 0;
  real ddldvd = 0;
  real ddldvb = 0;
  real dlonxl = 0;
  real xlfact = 0;
  real diddl = 0;
  real gds0 = 0;
  real emoncd = 0;
  real ondvt = 0;
  real onxn = 0;
  real wfact = 0;
  real gms = 0;
  real gmw = 0;
  real fshort = 0;
  integer innerline1000 = 0;
  integer line900 = 1;
  integer line700 = 2;
  integer line520 = 3;
  integer line510 = 4;
  integer goto_destination = -1;

  // Device noise locals
  real noise_vgs = 0;
  real noise_vds = 0;
  real noise_vgd = 0;
  real vgst = 0;
  real noise_alpha = 0;
  real beta = 0;
  real Sid = 0;
  real noise_dtemp = 0;
  real flicker_psd = 0;
  real flicker_exp = 1;

  // 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;
  real badmos3 = $simparam("badmos3", 0);
  real defad = $simparam("defad", 0);
  real defas = $simparam("defas", 0);
  real defl = $simparam("defl", 1e-4);
  real defw = $simparam("defw", 1e-4);
  real oldlimit = $simparam("oldlimit", 0);
  real VACONST_tnom = ($simparam("tnom", 27)+273.15);
  real cpscale = $simparam("scale", 1);

  // Evaluation constants
  real lc_gmin = 0;

  // Translated function definitions
  analog function real DEVqmeyer;
    input vgs, vgd, vgb, von, _vdsat;
    inout capgs, capgd, capgb;
    input phi, cox;
    real vgs;
    real vgd;
    real vgb;
    real von;
    real _vdsat;
    real capgs;
    real capgd;
    real capgb;
    real phi;
    real cox;
    real vdsat;
    real vds;
    real vddif;
    real vddif1;
    real vddif2;
    real vgst;
    begin
      DEVqmeyer = 0;
      vdsat = _vdsat;
      vgst = vgs-von;
      vdsat = ((vdsat>0.025) ? (vdsat) : (0.025));
      if (vgst<=-phi) begin
        capgb = cox/2;
        capgs = 0;
        capgd = 0;
      end else if (vgst<=-phi/2) begin
        capgb = -vgst*cox/(2*phi);
        capgs = 0;
        capgd = 0;
      end else if (vgst<=0) begin
        capgb = -vgst*cox/(2*phi);
        capgs = vgst*cox/(1.5*phi)+cox/3;
        vds = vgs-vgd;
        if (vds>=vdsat) begin
          capgd = 0;
        end else begin
          vddif = 2.0*vdsat-vds;
          vddif1 = vdsat-vds;
          vddif2 = vddif*vddif;
          capgd = capgs*(1.0-vdsat*vdsat/vddif2);
          capgs = capgs*(1.0-vddif1*vddif1/vddif2);
        end
      end else begin
        vds = vgs-vgd;
        vdsat = ((vdsat>0.025) ? (vdsat) : (0.025));
        if (vdsat<=vds) begin
          capgs = cox/3;
          capgd = 0;
          capgb = 0;
        end else begin
          vddif = 2.0*vdsat-vds;
          vddif1 = vdsat-vds;
          vddif2 = vddif*vddif;
          capgd = cox*(1.0-vdsat*vdsat/vddif2)/3;
          capgs = cox*(1.0-vddif1*vddif1/vddif2)/3;
          capgb = 0;
        end
      end
    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 function real DEVlimvds;
    input vnew, vold;
    inout limiting_applied;
    real vnew, vold, vlimited;
    integer limiting_applied;
    begin
      if (vold >= 3.5) begin
        if(vnew > vold) begin
          vlimited = min(vnew, (3 * vold) + 2);
        end else begin
          if (vnew < 3.5) begin
            vlimited = max(vnew, 2);
          end else begin
            vlimited = vnew;
          end
        end
      end else begin
        if(vnew > vold) begin
          vlimited = min(vnew, 4);
        end else begin
          vlimited = max(vnew, -0.5);
        end
      end
      DEVlimvds = vlimited;
      if (vlimited!=vnew) begin
        limiting_applied = 1;
      end
    end
  endfunction

  // Analog block
  analog begin

    // Instance field assignments
    if ($param_given(l)) begin
      MOS3l = l*cpscale;
      MOS3lGiven = 1;
    end
    if ($param_given(w)) begin
      MOS3w = w*cpscale;
      MOS3wGiven = 1;
    end
    if ($param_given(ad)) begin
      MOS3drainArea = ad*cpscale*cpscale;
      MOS3drainAreaGiven = 1;
    end
    if ($param_given(as)) begin
      MOS3sourceArea = as*cpscale*cpscale;
      MOS3sourceAreaGiven = 1;
    end
    if ($param_given(pd)) begin
      MOS3drainPerimiter = pd*cpscale;
      MOS3drainPerimiterGiven = 1;
    end
    if ($param_given(ps)) begin
      MOS3sourcePerimiter = ps*cpscale;
      MOS3sourcePerimiterGiven = 1;
    end
    if ($param_given(temp)) begin
      MOS3temp = temp+273.15;
      MOS3tempGiven = 1;
    end

    // Model field assignments
    MOS3type = type;
    if ($param_given(vto)) begin
      MOS3vt0 = vto;
    end
    if ($param_given(kp)) begin
      MOS3transconductance = kp;
    end
    if ($param_given(gamma)) begin
      MOS3gamma = gamma;
    end
    if ($param_given(phi)) begin
      MOS3phi = phi;
    end
    if ($param_given(nsub)) begin
      MOS3substrateDoping = nsub;
    end
    if ($param_given(tnom)) begin
      MOS3tnom = tnom+273.15;
      MOS3tnomGiven = 1;
    end

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

    // Tag: setup, function: MOS3setup
    if (!$param_given(kp)) begin
      MOS3transconductance = 2e-5;
    end
    if (!$param_given(vto)) begin
      MOS3vt0 = 0;
    end
    if (!$param_given(phi)) begin
      MOS3phi = 0.6;
    end
    if (!$param_given(gamma)) begin
      MOS3gamma = 0;
    end
    if (!MOS3drainAreaGiven) begin
      MOS3drainArea = defad;
    end
    if (!MOS3drainPerimiterGiven) begin
      MOS3drainPerimiter = 0;
    end
    if (!MOS3sourcePerimiterGiven) begin
      MOS3sourcePerimiter = 0;
    end
    MOS3vdsat = 0;
    MOS3von = 0;
    MOS3mode = 1;
    if (!(rd!=0||rsh!=0&&nrd!=0)) begin
      V(d_int, d) <+ 0;
    end
    if (!(rs!=0||rsh!=0&&nrs!=0)) begin
      V(s_int, s) <+ 0;
    end

    // Tag: temp, function: MOS3temp
    if (!MOS3tnomGiven) begin
      MOS3tnom = VACONST_tnom;
    end
    fact1 = MOS3tnom/(27.0+273.15);
    vtnom = MOS3tnom*CONSTKoverQ;
    kt1 = 1.38064852e-23*MOS3tnom;
    egfet1 = 1.16-7.02e-4*MOS3tnom*MOS3tnom/(MOS3tnom+1108);
    arg1 = -egfet1/(kt1+kt1)+1.1150877/(1.38064852e-23*(27.0+273.15+(27.0+273.15)));
    pbfact1 = -2*vtnom*(1.5*ln(fact1)+1.6021766208e-19*arg1);
    nifact = MOS3tnom/300*sqrt(MOS3tnom/300);
    nifact = nifact * (exp(0.5*egfet1*(1.0/300.0-1/MOS3tnom)/CONSTKoverQ));
    ni_temp = 1.45e16*nifact;
    if (MOS3phi<=0.0) begin
      $fatal(0, "Phi is not positive.");
    end
    MOS3oxideCapFactor = 3.9*8.854214871e-12/tox;
    if (!$param_given(kp)) begin
      MOS3transconductance = u0*MOS3oxideCapFactor*1e-4;
    end
    if ($param_given(nsub)) begin
      if (MOS3substrateDoping*1e6>ni_temp) begin
        if (!$param_given(phi)) begin
          MOS3phi = 2*vtnom*ln(MOS3substrateDoping*1e6/ni_temp);
          MOS3phi = ((0.1>MOS3phi) ? (0.1) : (MOS3phi));
        end
        fermis = MOS3type*0.5*MOS3phi;
        wkfng = 3.2;
        if (tpg!=0) begin
          fermig = MOS3type*tpg*0.5*egfet1;
          wkfng = 3.25+0.5*egfet1-fermig;
        end
        wkfngs = wkfng-(3.25+0.5*egfet1+fermis);
        if (!$param_given(gamma)) begin
          MOS3gamma = sqrt(2*(11.7*8.854214871e-12)*1.6021766208e-19*MOS3substrateDoping*1e6)/MOS3oxideCapFactor;
        end
        if (!$param_given(vto)) begin
          vfb = wkfngs-nss*1e4*1.6021766208e-19/MOS3oxideCapFactor;
          MOS3vt0 = vfb+MOS3type*(MOS3gamma*sqrt(MOS3phi)+MOS3phi);
        end else begin
          vfb = MOS3vt0-MOS3type*(MOS3gamma*sqrt(MOS3phi)+MOS3phi);
        end
        MOS3alpha = (11.7*8.854214871e-12+11.7*8.854214871e-12)/(1.6021766208e-19*MOS3substrateDoping*1e6);
        MOS3coeffDepLayWidth = sqrt(MOS3alpha);
      end else begin
        MOS3substrateDoping = 0;
        $fatal(0, "Nsub < Ni ");
      end
    end
    MOS3narrowFactor = delta*0.5*3.1415926535897932384626433832795*(11.7*8.854214871e-12)/MOS3oxideCapFactor;
    if (!MOS3tempGiven) begin
      MOS3temp = $temperature+dtemp;
    end
    vt = MOS3temp*CONSTKoverQ;
    ratio = MOS3temp/MOS3tnom;
    fact2 = MOS3temp/(27.0+273.15);
    kt = MOS3temp*1.38064852e-23;
    egfet = 1.16-7.02e-4*MOS3temp*MOS3temp/(MOS3temp+1108);
    arg = -egfet/(kt+kt)+1.1150877/(1.38064852e-23*(27.0+273.15+(27.0+273.15)));
    pbfact = -2*vt*(1.5*ln(fact2)+1.6021766208e-19*arg);
    if (!MOS3lGiven) begin
      MOS3l = defl;
    end
    if (!MOS3sourceAreaGiven) begin
      MOS3sourceArea = defas;
    end
    if (!MOS3wGiven) begin
      MOS3w = defw;
    end
    if ($param_given(rd)) begin
      if (rd!=0) begin
        MOS3drainConductance = 1.0/rd;
      end else begin
        MOS3drainConductance = 0;
      end
    end else if ($param_given(rsh)) begin
      if (rsh!=0&&nrd!=0) begin
        MOS3drainConductance = 1.0/(rsh*nrd);
      end else begin
        MOS3drainConductance = 0;
      end
    end else begin
      MOS3drainConductance = 0;
    end
    if ($param_given(rs)) begin
      if (rs!=0) begin
        MOS3sourceConductance = 1.0/rs;
      end else begin
        MOS3sourceConductance = 0;
      end
    end else if ($param_given(rsh)) begin
      if (rsh!=0&&nrs!=0) begin
        MOS3sourceConductance = 1.0/(rsh*nrs);
      end else begin
        MOS3sourceConductance = 0;
      end
    end else begin
      MOS3sourceConductance = 0;
    end
    if (MOS3l-2*ld+xl<=0) begin
      $fatal(0, "effective channel length less than zero");
    end
    if (MOS3w-2*wd+xw<=0) begin
      $fatal(0, "effective channel width less than zero");
    end
    ratio4 = ratio*sqrt(ratio);
    MOS3tTransconductance = MOS3transconductance/ratio4;
    MOS3tSurfMob = u0/ratio4;
    phio = (MOS3phi-pbfact1)/fact1;
    MOS3tPhi = fact2*phio+pbfact;
    MOS3tVbi = delvto+MOS3vt0-MOS3type*(MOS3gamma*sqrt(MOS3phi))+0.5*(egfet1-egfet)+MOS3type*0.5*(MOS3tPhi-MOS3phi);
    MOS3tVto = MOS3tVbi+MOS3type*MOS3gamma*sqrt(MOS3tPhi);
    MOS3tSatCur = is*exp(-egfet/vt+egfet1/vtnom);
    MOS3tSatCurDens = js*exp(-egfet/vt+egfet1/vtnom);
    pbo = (pb-pbfact1)/fact1;
    gmaold = (pb-pbo)/pbo;
    capfact = 1/(1+mj*(4e-4*(MOS3tnom-(27.0+273.15))-gmaold));
    MOS3tCbd = cbd*capfact;
    MOS3tCbs = cbs*capfact;
    MOS3tCj = cj*capfact;
    capfact = 1/(1+mjsw*(4e-4*(MOS3tnom-(27.0+273.15))-gmaold));
    MOS3tCjsw = cjsw*capfact;
    MOS3tBulkPot = fact2*pbo+pbfact;
    gmanew = (MOS3tBulkPot-pbo)/pbo;
    capfact = 1+mj*(4e-4*(MOS3temp-(27.0+273.15))-gmanew);
    MOS3tCbd = MOS3tCbd * (capfact);
    MOS3tCbs = MOS3tCbs * (capfact);
    MOS3tCj = MOS3tCj * (capfact);
    capfact = 1+mjsw*(4e-4*(MOS3temp-(27.0+273.15))-gmanew);
    MOS3tCjsw = MOS3tCjsw * (capfact);
    MOS3tDepCap = fc*MOS3tBulkPot;
    if (js==0||MOS3drainArea==0||MOS3sourceArea==0) begin
      MOS3drainVcrit = vt*ln(vt/(CONSTroot2*MOS3tSatCur));
      MOS3sourceVcrit = MOS3drainVcrit;
    end else begin
      MOS3drainVcrit = vt*ln(vt/(CONSTroot2*MOS3tSatCurDens*MOS3drainArea));
      MOS3sourceVcrit = vt*ln(vt/(CONSTroot2*MOS3tSatCurDens*MOS3sourceArea));
    end
    if ($param_given(cbd)) begin
      czbd = MOS3tCbd;
    end else if ($param_given(cj)) begin
      czbd = MOS3tCj*MOS3drainArea;
    end else begin
      czbd = 0;
    end
    if ($param_given(cjsw)) begin
      czbdsw = MOS3tCjsw*MOS3drainPerimiter;
    end else begin
      czbdsw = 0;
    end
    arg = 1-fc;
    sarg = exp(-mj*ln(arg));
    sargsw = exp(-mjsw*ln(arg));
    MOS3Cbd = czbd;
    MOS3Cbdsw = czbdsw;
    MOS3f2d = czbd*(1-fc*(1+mj))*sarg/arg+czbdsw*(1-fc*(1+mjsw))*sargsw/arg;
    MOS3f3d = czbd*mj*sarg/arg/MOS3tBulkPot+czbdsw*mjsw*sargsw/arg/MOS3tBulkPot;
    MOS3f4d = czbd*MOS3tBulkPot*(1-arg*sarg)/(1-mj)+czbdsw*MOS3tBulkPot*(1-arg*sargsw)/(1-mjsw)-MOS3f3d/2*(MOS3tDepCap*MOS3tDepCap)-MOS3tDepCap*MOS3f2d;
    if ($param_given(cbs)) begin
      czbs = MOS3tCbs;
    end else if ($param_given(cj)) begin
      czbs = MOS3tCj*MOS3sourceArea;
    end else begin
      czbs = 0;
    end
    if ($param_given(cjsw)) begin
      czbssw = MOS3tCjsw*MOS3sourcePerimiter;
    end else begin
      czbssw = 0;
    end
    arg = 1-fc;
    sarg = exp(-mj*ln(arg));
    sargsw = exp(-mjsw*ln(arg));
    MOS3Cbs = czbs;
    MOS3Cbssw = czbssw;
    MOS3f2s = czbs*(1-fc*(1+mj))*sarg/arg+czbssw*(1-fc*(1+mjsw))*sargsw/arg;
    MOS3f3s = czbs*mj*sarg/arg/MOS3tBulkPot+czbssw*mjsw*sargsw/arg/MOS3tBulkPot;
    MOS3f4s = czbs*MOS3tBulkPot*(1-arg*sarg)/(1-mj)+czbssw*MOS3tBulkPot*(1-arg*sargsw)/(1-mjsw)-MOS3f3s/2*(MOS3tDepCap*MOS3tDepCap)-MOS3tDepCap*MOS3f2s;

    // Tag: load, function: MOS3load
    xfact = 0.0;
    capgs = 0.0;
    capgd = 0.0;
    capgb = 0.0;
    load_vt = CONSTKoverQ*MOS3temp;
    EffectiveWidth = MOS3w-2*wd+xw;
    EffectiveLength = MOS3l-2*ld+xl;
    if (MOS3tSatCurDens==0||MOS3drainArea==0||MOS3sourceArea==0) begin
      DrainSatCur = MOS3tSatCur;
      SourceSatCur = MOS3tSatCur;
    end else begin
      DrainSatCur = MOS3tSatCurDens*MOS3drainArea;
      SourceSatCur = MOS3tSatCurDens*MOS3sourceArea;
    end
    GateSourceOverlapCap = cgso*EffectiveWidth;
    GateDrainOverlapCap = cgdo*EffectiveWidth;
    GateBulkOverlapCap = cgbo*EffectiveLength;
    Beta = MOS3tTransconductance*EffectiveWidth/EffectiveLength;
    OxideCap = MOS3oxideCapFactor*EffectiveLength*EffectiveWidth;
    limited = 0;
    /* Previous vgs, vds, vbs, and vbd */
    MOS3vgs = MOS3type * $limit(V(g, s_int), DEVlimitOldGet);
    MOS3vds = MOS3type * $limit(V(d_int, s_int), DEVlimitOldGet);
    MOS3vbs = MOS3type * $limit(V(b, s_int), DEVlimitOldGet);
    MOS3vbd = MOS3type * $limit(V(b, d_int), DEVlimitOldGet);
    
    /* Simplified von value used in limiting, does not require introduction of a hidden state */
    load_von = MOS3type*MOS3tVbi;
    MOS3von = MOS3type*load_von;
    load_vbs = MOS3type*V(b, s_int);
    load_vgs = MOS3type*V(g, s_int);
    load_vds = MOS3type*V(d_int, s_int);
    load_vbd = load_vbs-load_vds;
    vgd = load_vgs-load_vds;
    vgdo = MOS3vgs-MOS3vds;
    load_von = MOS3type*MOS3von;
    if (MOS3vds>=0) begin
      load_vgs = DEVfetlim(load_vgs, MOS3vgs, load_von, limited);
      load_vds = load_vgs-vgd;
      load_vds = DEVlimvds(load_vds, MOS3vds, limited);
      vgd = load_vgs-load_vds;
    end else begin
      vgd = DEVfetlim(vgd, vgdo, load_von, limited);
      load_vds = load_vgs-vgd;
      if (!oldlimit) begin
        load_vds = -DEVlimvds(-load_vds, -MOS3vds, limited);
      end
      load_vgs = vgd+load_vds;
    end
    if (load_vds>=0) begin
      load_vbs = DEVpnjlim(load_vbs, MOS3vbs, load_vt, MOS3sourceVcrit, limited);
      load_vbd = load_vbs-load_vds;
    end else begin
      load_vbd = DEVpnjlim(load_vbd, MOS3vbd, load_vt, MOS3drainVcrit, limited);
      load_vbs = load_vbd+load_vds;
    end
    if (initialize_limiting()) begin
        load_vbs = -1;
        load_vgs = MOS3type * MOS3tVto;
        load_vds = 0;
        load_vbd = load_vbs - load_vds;
    end
    
    load_vgs = MOS3type * $limit(V(g, s_int), DEVlimitNewSet, MOS3type * load_vgs, limited);
    load_vds = MOS3type * $limit(V(d_int, s_int), DEVlimitNewSet, MOS3type * load_vds, limited);
    load_vbs = MOS3type * $limit(V(b, s_int), DEVlimitNewSet, MOS3type * load_vbs, limited);
    load_vbd = MOS3type * $limit(V(b, d_int), DEVlimitNewSet, MOS3type * load_vbd, limited);
    load_vbd = load_vbs-load_vds;
    vgd = load_vgs-load_vds;
    vgb = load_vgs-load_vbs;
    if (load_vbs<=-3*load_vt) begin
      load_arg = 3*load_vt/(load_vbs*CONSTe);
      load_arg = load_arg*load_arg*load_arg;
      MOS3cbs = -SourceSatCur*(1+load_arg)+lc_gmin/$mfactor*load_vbs;
      MOS3gbs = SourceSatCur*3*load_arg/load_vbs+lc_gmin/$mfactor;
    end else begin
      evbs = exp(((709.0<load_vbs/load_vt) ? (709.0) : (load_vbs/load_vt)));
      MOS3gbs = SourceSatCur*evbs/load_vt+lc_gmin/$mfactor;
      MOS3cbs = SourceSatCur*(evbs-1)+lc_gmin/$mfactor*load_vbs;
    end
    if (load_vbd<=-3*load_vt) begin
      load_arg = 3*load_vt/(load_vbd*CONSTe);
      load_arg = load_arg*load_arg*load_arg;
      MOS3cbd = -DrainSatCur*(1+load_arg)+lc_gmin/$mfactor*load_vbd;
      MOS3gbd = DrainSatCur*3*load_arg/load_vbd+lc_gmin/$mfactor;
    end else begin
      evbd = exp(((709.0<load_vbd/load_vt) ? (709.0) : (load_vbd/load_vt)));
      MOS3gbd = DrainSatCur*evbd/load_vt+lc_gmin/$mfactor;
      MOS3cbd = DrainSatCur*(evbd-1)+lc_gmin/$mfactor*load_vbd;
    end
    if (load_vds>=0) begin
      MOS3mode = 1;
    end else begin
      MOS3mode = -1;
    end
    coeff0 = 0.0631353e0;
    coeff1 = 0.8013292e0;
    coeff2 = -0.01110777e0;
    dxndvb = 0.0;
    dvodvb = 0.0;
    dvodvd = 0.0;
    xn = 0.0;
    onvdsc = 0.0;
    fdrain = 0.0;
    dfddvg = 0.0;
    dfddvb = 0.0;
    dfddvd = 0.0;
    gds0 = 0.0;
    load_vdsat = 0.0;
    oneoverxl = 1.0/EffectiveLength;
    load_eta = eta*8.15e-22/(MOS3oxideCapFactor*EffectiveLength*EffectiveLength*EffectiveLength);
    if (((MOS3mode==1) ? (load_vbs) : (load_vbd))<=0.0) begin
      phibs = MOS3tPhi-((MOS3mode==1) ? (load_vbs) : (load_vbd));
      sqphbs = sqrt(phibs);
      dsqdvb = -0.5/sqphbs;
    end else begin
      sqphis = sqrt(MOS3tPhi);
      sqphs3 = MOS3tPhi*sqphis;
      sqphbs = sqphis/(1.0+((MOS3mode==1) ? (load_vbs) : (load_vbd))/(MOS3tPhi+MOS3tPhi));
      phibs = sqphbs*sqphbs;
      dsqdvb = -phibs/(sqphs3+sqphs3);
    end
    if (xj!=0.0&&MOS3coeffDepLayWidth!=0.0) begin
      wps = MOS3coeffDepLayWidth*sqphbs;
      oneoverxj = 1.0/xj;
      xjonxl = xj*oneoverxl;
      djonxj = ld*oneoverxj;
      wponxj = wps*oneoverxj;
      wconxj = coeff0+coeff1*wponxj+coeff2*wponxj*wponxj;
      arga = wconxj+djonxj;
      argc = wponxj/(1.0+wponxj);
      argb = sqrt(1.0-argc*argc);
      fshort = 1.0-xjonxl*(arga*argb-djonxj);
      dwpdvb = MOS3coeffDepLayWidth*dsqdvb;
      dadvb = (coeff1+coeff2*(wponxj+wponxj))*dwpdvb*oneoverxj;
      dbdvb = -argc*argc*(1.0-argc)*dwpdvb/(argb*wps);
      dfsdvb = -xjonxl*(dadvb*argb+arga*dbdvb);
    end else begin
      fshort = 1.0;
      dfsdvb = 0.0;
    end
    gammas = MOS3gamma*fshort;
    fbodys = 0.5*gammas/(sqphbs+sqphbs);
    fbody = fbodys+MOS3narrowFactor/EffectiveWidth;
    onfbdy = 1.0/(1.0+fbody);
    dfbdvb = -fbodys*dsqdvb/sqphbs+fbodys*dfsdvb/fshort;
    qbonco = gammas*sqphbs+MOS3narrowFactor*phibs/EffectiveWidth;
    dqbdvb = gammas*dsqdvb+MOS3gamma*dfsdvb*sqphbs-MOS3narrowFactor/EffectiveWidth;
    vbix = MOS3tVbi*MOS3type-load_eta*(MOS3mode*load_vds);
    vth = vbix+qbonco;
    dvtdvd = -load_eta;
    dvtdvb = dqbdvb;
    load_von = vth;
    if (nfs!=0.0) begin
      csonco = 1.6021766208e-19*nfs*1e4*EffectiveLength*EffectiveWidth/OxideCap;
      cdonco = qbonco/(phibs+phibs);
      xn = 1.0+csonco+cdonco;
      load_von = vth+load_vt*xn;
      dxndvb = dqbdvb/(phibs+phibs)-qbonco*dsqdvb/(phibs*sqphbs);
      dvodvd = dvtdvd;
      dvodvb = dvtdvb+load_vt*dxndvb;
    end else if (((MOS3mode==1) ? (load_vgs) : (vgd))<=load_von) begin
      cdrain = 0.0;
      MOS3gm = 0.0;
      MOS3gds = 0.0;
      MOS3gmbs = 0.0;
      goto_destination = innerline1000;
    end
    if (goto_destination<0) begin
      vgsx = ((((MOS3mode==1) ? (load_vgs) : (vgd))>load_von) ? (((MOS3mode==1) ? (load_vgs) : (vgd))) : (load_von));
      onfg = 1.0+theta*(vgsx-vth);
      fgate = 1.0/onfg;
      us = MOS3tSurfMob*1e-4*fgate;
      dfgdvg = -theta*fgate*fgate;
      dfgdvd = -dfgdvg*dvtdvd;
      dfgdvb = -dfgdvg*dvtdvb;
      load_vdsat = (vgsx-vth)*onfbdy;
      if (vmax<=0.0) begin
        dvsdvg = onfbdy;
        dvsdvd = -dvsdvg*dvtdvd;
        dvsdvb = -dvsdvg*dvtdvb-load_vdsat*dfbdvb*onfbdy;
      end else begin
        vdsc = EffectiveLength*vmax/us;
        onvdsc = 1.0/vdsc;
        arga = (vgsx-vth)*onfbdy;
        argb = sqrt(arga*arga+vdsc*vdsc);
        load_vdsat = arga+vdsc-argb;
        dvsdga = (1.0-arga/argb)*onfbdy;
        dvsdvg = dvsdga-(1.0-vdsc/argb)*vdsc*dfgdvg*onfg;
        dvsdvd = -dvsdvg*dvtdvd;
        dvsdvb = -dvsdvg*dvtdvb-arga*dvsdga*dfbdvb;
      end
      vdsx = ((MOS3mode*load_vds<load_vdsat) ? (MOS3mode*load_vds) : (load_vdsat));
      if (vdsx==0.0) begin
        goto_destination = line900;
      end
      if (goto_destination<0) begin
        cdo = vgsx-vth-0.5*(1.0+fbody)*vdsx;
        dcodvb = -dvtdvb-0.5*dfbdvb*vdsx;
        cdnorm = cdo*vdsx;
        MOS3gm = vdsx;
        if (MOS3mode*load_vds>load_vdsat) begin
          MOS3gds = -dvtdvd*vdsx;
        end else begin
          MOS3gds = vgsx-vth-(1.0+fbody+dvtdvd)*vdsx;
        end
        MOS3gmbs = dcodvb*vdsx;
        cd1 = Beta*cdnorm;
        Beta = Beta*fgate;
        cdrain = Beta*cdnorm;
        MOS3gm = Beta*MOS3gm+dfgdvg*cd1;
        MOS3gds = Beta*MOS3gds+dfgdvd*cd1;
        MOS3gmbs = Beta*MOS3gmbs+dfgdvb*cd1;
        if (vmax>0.0) begin
          fdrain = 1.0/(1.0+vdsx*onvdsc);
          fd2 = fdrain*fdrain;
          arga = fd2*vdsx*onvdsc*onfg;
          dfddvg = -dfgdvg*arga;
          if (MOS3mode*load_vds>load_vdsat) begin
            dfddvd = -dfgdvd*arga;
          end else begin
            dfddvd = -dfgdvd*arga-fd2*onvdsc;
          end
          dfddvb = -dfgdvb*arga;
          MOS3gm = fdrain*MOS3gm+dfddvg*cdrain;
          MOS3gds = fdrain*MOS3gds+dfddvd*cdrain;
          MOS3gmbs = fdrain*MOS3gmbs+dfddvb*cdrain;
          cdrain = fdrain*cdrain;
          Beta = Beta*fdrain;
        end
        if (MOS3mode*load_vds<=load_vdsat) begin
          if (vmax>0.0||MOS3alpha==0.0||badmos3) begin
            goto_destination = line700;
          end else begin
            arga = MOS3mode*load_vds/load_vdsat;
            delxl = sqrt(kappa*MOS3alpha*load_vdsat/8);
            dldvd = 4*delxl*arga*arga*arga/load_vdsat;
            arga = arga * (arga);
            arga = arga * (arga);
            delxl = delxl * (arga);
            ddldvg = 0.0;
            ddldvd = -dldvd;
            ddldvb = 0.0;
            goto_destination = line520;
          end
        end
        if (goto_destination<0) begin
          if (vmax<=0.0) begin
            goto_destination = line510;
          end
          if (goto_destination<0) begin
            if (MOS3alpha==0.0) begin
              goto_destination = line700;
            end
            if (goto_destination<0) begin
              cdsat = cdrain;
              gdsat = cdsat*(1.0-fdrain)*onvdsc;
              gdsat = ((1.0e-12>gdsat) ? (1.0e-12) : (gdsat));
              gdoncd = gdsat/cdsat;
              gdonfd = gdsat/(1.0-fdrain);
              gdonfg = gdsat*onfg;
              dgdvg = gdoncd*MOS3gm-gdonfd*dfddvg+gdonfg*dfgdvg;
              dgdvd = gdoncd*MOS3gds-gdonfd*dfddvd+gdonfg*dfgdvd;
              dgdvb = gdoncd*MOS3gmbs-gdonfd*dfddvb+gdonfg*dfgdvb;
              if (badmos3) begin
                emax = cdsat*oneoverxl/gdsat;
              end else begin
                emax = kappa*cdsat*oneoverxl/gdsat;
              end
              emoncd = emax/cdsat;
              emongd = emax/gdsat;
              demdvg = emoncd*MOS3gm-emongd*dgdvg;
              demdvd = emoncd*MOS3gds-emongd*dgdvd;
              demdvb = emoncd*MOS3gmbs-emongd*dgdvb;
              arga = 0.5*emax*MOS3alpha;
              argc = kappa*MOS3alpha;
              argb = sqrt(arga*arga+argc*(MOS3mode*load_vds-load_vdsat));
              delxl = argb-arga;
              if (argb!=0.0) begin
                dldvd = argc/(argb+argb);
                dldem = 0.5*(arga/argb-1.0)*MOS3alpha;
              end else begin
                dldvd = 0.0;
                dldem = 0.0;
              end
              ddldvg = dldem*demdvg;
              ddldvd = dldem*demdvd-dldvd;
              ddldvb = dldem*demdvb;
              goto_destination = line520;
            end
          end
        end
      end
    end
    if (goto_destination<0||goto_destination==line510) begin
      goto_destination = -1;
      if (badmos3) begin
        delxl = sqrt(kappa*(MOS3mode*load_vds-load_vdsat)*MOS3alpha);
        dldvd = 0.5*delxl/(MOS3mode*load_vds-load_vdsat);
      end else begin
        delxl = sqrt(kappa*MOS3alpha*(MOS3mode*load_vds-load_vdsat+load_vdsat/8));
        dldvd = 0.5*delxl/(MOS3mode*load_vds-load_vdsat+load_vdsat/8);
      end
      ddldvg = 0.0;
      ddldvd = -dldvd;
      ddldvb = 0.0;
    end
    if (goto_destination<0||goto_destination==line520) begin
      goto_destination = -1;
      if (delxl>0.5*EffectiveLength) begin
        delxl = EffectiveLength-EffectiveLength*EffectiveLength/(4.0*delxl);
        arga = 4.0*(EffectiveLength-delxl)*(EffectiveLength-delxl)/(EffectiveLength*EffectiveLength);
        ddldvg = ddldvg*arga;
        ddldvd = ddldvd*arga;
        ddldvb = ddldvb*arga;
        dldvd = dldvd*arga;
      end
      dlonxl = delxl*oneoverxl;
      xlfact = 1.0/(1.0-dlonxl);
      cd1 = cdrain;
      cdrain = cdrain*xlfact;
      diddl = cdrain/(EffectiveLength-delxl);
      MOS3gm = MOS3gm*xlfact+diddl*ddldvg;
      MOS3gmbs = MOS3gmbs*xlfact+diddl*ddldvb;
      gds0 = diddl*ddldvd;
      MOS3gm = MOS3gm+gds0*dvsdvg;
      MOS3gmbs = MOS3gmbs+gds0*dvsdvb;
      MOS3gds = MOS3gds*xlfact+diddl*dldvd+gds0*dvsdvd;
    end
    if (goto_destination<0||goto_destination==line700) begin
      goto_destination = -1;
      if (((MOS3mode==1) ? (load_vgs) : (vgd))<load_von) begin
        onxn = 1.0/xn;
        ondvt = onxn/load_vt;
        wfact = exp((((MOS3mode==1) ? (load_vgs) : (vgd))-load_von)*ondvt);
        cdrain = cdrain*wfact;
        gms = MOS3gm*wfact;
        gmw = cdrain*ondvt;
        MOS3gm = gmw;
        if (MOS3mode*load_vds>load_vdsat) begin
          MOS3gm = MOS3gm+gds0*dvsdvg*wfact;
        end
        MOS3gds = MOS3gds*wfact+(gms-gmw)*dvodvd;
        MOS3gmbs = MOS3gmbs*wfact+(gms-gmw)*dvodvb-gmw*(((MOS3mode==1) ? (load_vgs) : (vgd))-load_von)*onxn*dxndvb;
      end
      goto_destination = innerline1000;
    end
    if (goto_destination<0||goto_destination==line900) begin
      goto_destination = -1;
      Beta = Beta*fgate;
      cdrain = 0.0;
      MOS3gm = 0.0;
      MOS3gds = Beta*(vgsx-vth);
      MOS3gmbs = 0.0;
      if (nfs!=0.0&&((MOS3mode==1) ? (load_vgs) : (vgd))<load_von) begin
        MOS3gds = MOS3gds * (exp((((MOS3mode==1) ? (load_vgs) : (vgd))-load_von)/(load_vt*xn)));
      end
    end
    goto_destination = -1;
    MOS3von = MOS3type*load_von;
    MOS3vdsat = MOS3type*load_vdsat;
    MOS3dcCurrent = MOS3mode*cdrain-MOS3cbd;
    MOS3cd = MOS3dcCurrent;
    if (OxideCap==0) begin
        meyer_scale = 0;
        meyer_unscale = 1;
    end else begin
        meyer_scale = OxideCap;
        meyer_unscale = OxideCap;
    end
    if (MOS3Cbs!=0||MOS3Cbssw!=0) begin
      if (load_vbs<MOS3tDepCap) begin
        load_arg = 1-load_vbs/MOS3tBulkPot;
        if (mj==mjsw) begin
          if (mj==0.5) begin
            load_sargsw = 1/sqrt(load_arg);
            load_sarg = load_sargsw;
          end else begin
            load_sargsw = exp(-mj*ln(load_arg));
            load_sarg = load_sargsw;
          end
        end else begin
          if (mj==0.5) begin
            load_sarg = 1/sqrt(load_arg);
          end else begin
            load_sarg = exp(-mj*ln(load_arg));
          end
          if (mjsw==0.5) begin
            load_sargsw = 1/sqrt(load_arg);
          end else begin
            load_sargsw = exp(-mjsw*ln(load_arg));
          end
        end
        MOS3qbs = MOS3tBulkPot*(MOS3Cbs*(1-load_arg*load_sarg)/(1-mj)+MOS3Cbssw*(1-load_arg*load_sargsw)/(1-mjsw));
        MOS3capbs = MOS3Cbs*load_sarg+MOS3Cbssw*load_sargsw;
      end else begin
        MOS3qbs = MOS3f4s+load_vbs*(MOS3f2s+load_vbs*(MOS3f3s/2));
        MOS3capbs = MOS3f2s+MOS3f3s*load_vbs;
      end
    end else begin
      MOS3qbs = 0;
      MOS3capbs = 0;
    end
    if (MOS3Cbd!=0||MOS3Cbdsw!=0) begin
      if (load_vbd<MOS3tDepCap) begin
        load_arg = 1-load_vbd/MOS3tBulkPot;
        if (mj==0.5&&mjsw==0.5) begin
          load_sargsw = 1/sqrt(load_arg);
          load_sarg = load_sargsw;
        end else begin
          if (mj==0.5) begin
            load_sarg = 1/sqrt(load_arg);
          end else begin
            load_sarg = exp(-mj*ln(load_arg));
          end
          if (mjsw==0.5) begin
            load_sargsw = 1/sqrt(load_arg);
          end else begin
            load_sargsw = exp(-mjsw*ln(load_arg));
          end
        end
        MOS3qbd = MOS3tBulkPot*(MOS3Cbd*(1-load_arg*load_sarg)/(1-mj)+MOS3Cbdsw*(1-load_arg*load_sargsw)/(1-mjsw));
        MOS3capbd = MOS3Cbd*load_sarg+MOS3Cbdsw*load_sargsw;
      end else begin
        MOS3qbd = MOS3f4d+load_vbd*(MOS3f2d+load_vbd*MOS3f3d/2);
        MOS3capbd = MOS3f2d+load_vbd*MOS3f3d;
      end
    end else begin
      MOS3qbd = 0;
      MOS3capbd = 0;
    end
    geq = 0;
    MOS3cqbd = ddt(MOS3qbd);
    ceq = MOS3cqbd;
    MOS3gbd = MOS3gbd + (geq);
    MOS3cbd = MOS3cbd + (MOS3cqbd);
    MOS3cd = MOS3cd - (MOS3cqbd);
    geq = 0;
    MOS3cqbs = ddt(MOS3qbs);
    ceq = MOS3cqbs;
    MOS3gbs = MOS3gbs + (geq);
    MOS3cbs = MOS3cbs + (MOS3cqbs);
    MOS3vbs = load_vbs;
    MOS3vbd = load_vbd;
    MOS3vgs = load_vgs;
    MOS3vds = load_vds;
    if (MOS3mode>0) begin
      DEVqmeyer(load_vgs, vgd, vgb, load_von, load_vdsat, MOS3capgs, MOS3capgd, MOS3capgb, MOS3tPhi, OxideCap);
    end else begin
      DEVqmeyer(vgd, load_vgs, vgb, load_von, load_vdsat, MOS3capgd, MOS3capgs, MOS3capgb, MOS3tPhi, OxideCap);
    end
    capgs = MOS3capgs+MOS3capgs+GateSourceOverlapCap;
    capgd = MOS3capgd+MOS3capgd+GateDrainOverlapCap;
    capgb = MOS3capgb+MOS3capgb+GateBulkOverlapCap;
    if (capgs==0) begin
      MOS3cqgs = 0;
    end
    if (capgd==0) begin
      MOS3cqgd = 0;
    end
    if (capgb==0) begin
      MOS3cqgb = 0;
    end
    gcgs = 0;
    ceqgs = capgs*(ddt(meyer_scale*load_vgs)/meyer_unscale);
    MOS3cqgs = ceqgs;
    gcgd = 0;
    ceqgd = capgd*(ddt(meyer_scale*vgd)/meyer_unscale);
    MOS3cqgd = ceqgd;
    gcgb = 0;
    ceqgb = capgb*(ddt(meyer_scale*vgb)/meyer_unscale);
    MOS3cqgb = ceqgb;
    ceqbs = MOS3type*MOS3cbs;
    ceqbd = MOS3type*MOS3cbd;
    if (MOS3mode>=0) begin
      xnrm = 1;
      xrev = 0;
      cdreq = MOS3type*cdrain;
    end else begin
      xnrm = 0;
      xrev = 1;
      cdreq = -MOS3type*cdrain;
    end
    
    // Residuals
    I(d) <+ MOS3drainConductance*V(d, d_int);
    I(g) <+ gcgb*V(g, b)+gcgd*V(g, d_int)+gcgs*V(g, s_int)+MOS3type*(ceqgs+ceqgb+ceqgd);
    I(s) <+ MOS3sourceConductance*V(s, s_int);
    I(b) <+ gcgb*V(b, g)+(ceqbs+ceqbd-MOS3type*ceqgb);
    I(d_int) <+ MOS3drainConductance*V(d_int, d)+gcgd*V(d_int, g)+-(ceqbd-cdreq+MOS3type*ceqgd);
    I(s_int) <+ MOS3sourceConductance*V(s_int, s)+gcgs*V(s_int, g)+-(cdreq+ceqbs+MOS3type*ceqgs);

    // Tag: noise, function: MOS3noise
    if (MOS3tempGiven) begin
      noise_dtemp = MOS3temp-$temperature;
    end else begin
      noise_dtemp = dtemp;
    end
    I(d_int, d) <+ white_noise(4*(VACONSTboltz*(($temperature+noise_dtemp)*MOS3drainConductance)), "rd");
    I(s_int, s) <+ white_noise(4*(VACONSTboltz*(($temperature+noise_dtemp)*MOS3sourceConductance)), "rs");
    if (nlev<3) begin
      Sid = 2.0/3.0*abs(MOS3gm);
    end else begin
      noise_vds = MOS3vds;
      noise_vgs = MOS3vgs;
      noise_vgd = noise_vgs-noise_vds;
      vgst = ((MOS3mode==1) ? (noise_vgs) : (noise_vgd))-MOS3type*MOS3von;
      if (vgst>0) begin
        if (vgst<=noise_vds*MOS3mode) begin
          noise_alpha = 0.0;
        end else begin
          noise_alpha = 1.0-noise_vds*MOS3mode/(MOS3type*MOS3vdsat);
        end
        beta = MOS3tTransconductance*MOS3w/(MOS3l-2*ld);
        Sid = 2.0/3.0*beta*vgst*(1.0+noise_alpha+noise_alpha*noise_alpha)/(1.0+noise_alpha)*gdsnoi;
      end else begin
        Sid = 0.0;
      end
    end
    I(d_int, s_int) <+ white_noise(4*(VACONSTboltz*(($temperature+noise_dtemp)*Sid)), "id");
    case (nlev)
      0: begin
        flicker_psd = ((MOS3cd>=0) ? (1) : (-1))*(kf*exp(af*ln(((abs(MOS3cd)>1E-38) ? (abs(MOS3cd)) : (1E-38))))/((MOS3l-2*ld)*(MOS3l-2*ld)*MOS3oxideCapFactor));
        flicker_exp = 1;
      end
      1: begin
        flicker_psd = ((MOS3cd>=0) ? (1) : (-1))*(kf*exp(af*ln(((abs(MOS3cd)>1E-38) ? (abs(MOS3cd)) : (1E-38))))/((MOS3w-2*wd)*(MOS3l-2*ld)*MOS3oxideCapFactor));
        flicker_exp = 1;
      end
      2, 
      3: begin
        flicker_psd = ((MOS3cd>=0) ? (1) : (-1))*(kf*MOS3gm*MOS3gm/((MOS3w-2*wd)*(MOS3l-2*ld)*MOS3oxideCapFactor));
        flicker_exp = af;
      end
    endcase

    I(d_int, s_int) <+ flicker_noise(flicker_psd, flicker_exp, "flicker");

    // Instance output variable computation
    i_d = MOS3cd;
    ibd = MOS3cbd;
    ibs = MOS3cbs;
    i_s = -MOS3cd;
    i_s = i_s - (MOS3cbd+MOS3cbs-MOS3cqgb);
    i_s = i_s - (MOS3cqgb+MOS3cqgd+MOS3cqgs);
    i_g = MOS3cqgb+MOS3cqgd+MOS3cqgs;
    i_b = MOS3cbd+MOS3cbs-MOS3cqgb;
    vgs = MOS3vgs;
    vds = MOS3vds;
    vbs = MOS3vbs;
    vbd = MOS3vbd;
    von = MOS3von;
    vdsat = MOS3vdsat;
    sourcevcrit = MOS3sourceVcrit;
    drainvcrit = MOS3drainVcrit;
    sourceconductance = MOS3sourceConductance;
    drainconductance = MOS3drainConductance;
    gm = MOS3gm;
    gds = MOS3gds;
    gmb = MOS3gmbs;
    gbd = MOS3gbd;
    gbs = MOS3gbs;
    c_bd = MOS3capbd;
    c_bs = MOS3capbs;
    cgs = 2*MOS3capgs;
    cgs = cgs + (cgso*(MOS3w+xw-2*wd));
    cgd = 2*MOS3capgd;
    cgd = cgd + (cgdo*(MOS3w+xw-2*wd));
    cgb = 2*MOS3capgb;
    cgb = cgb + (cgbo*(MOS3l+xl-2*ld));
    cqgs = MOS3cqgs;
    cqgd = MOS3cqgd;
    cqgb = MOS3cqgb;
    cqbd = MOS3cqbd;
    cqbs = MOS3cqbs;
    cbd0 = MOS3Cbd;
    cbdsw0 = MOS3Cbdsw;
    cbs0 = MOS3Cbs;
    cbssw0 = MOS3Cbssw;
    qbs = MOS3qbs;
    qbd = MOS3qbd;

    // Model output variable computation

  end
endmodule
