summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist/analog/nld_mosfet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/netlist/analog/nld_mosfet.cpp')
-rw-r--r--src/lib/netlist/analog/nld_mosfet.cpp865
1 files changed, 464 insertions, 401 deletions
diff --git a/src/lib/netlist/analog/nld_mosfet.cpp b/src/lib/netlist/analog/nld_mosfet.cpp
index c66cec291f6..63911ceb02f 100644
--- a/src/lib/netlist/analog/nld_mosfet.cpp
+++ b/src/lib/netlist/analog/nld_mosfet.cpp
@@ -1,193 +1,168 @@
-// license:GPL-2.0+
+// license:BSD-3-Clause
// copyright-holders:Couriersud
-/*
- * nld_mosfet.cpp
- *
- * Formulas in here based on the following Sources:
- *
- * https://www.imperial.ac.uk/pls/portallive/docs/1/7292573.PDF
- * http://www3.imperial.ac.uk/pls/portallive/docs/1/56133736.PDF
- * https://people.rit.edu/lffeee/SPICE_MOSFET_Model_Intro.pdf
- * https://people.rit.edu/lffeee/SPICE.pdf
- * http://web.mit.edu/course/6/6.012/SPR98/www/lectures/S98_Lecture10.pdf
- * http://homepages.rpi.edu/~sawyes/Models_review.pdf
- * http://jaco.ec.t.kanazawa-u.ac.jp/edu/mix/pdf/3.pdf
- *
- * Farid N. Naim, Circuit Simulation (Wiley-IEEE Press, 2010).
- * Stefan Jahn, Michael Margraf, Vincent Habchi and Raimund Jacob, "Qucs Technical Papers" (2007)
- *
- */
-
-#include "netlist/solver/nld_solver.h"
-#include "netlist/nl_setup.h"
+
+// Names
+// spell-checker: words Farid, Naim, Jahn, Margraf, Habchi, Raimund, Qucs
+//
+// Specific technical terms
+// spell-checker: words Cgso, Cgdo, Cgbo, Cjsw, Mjsw, Ucrit, Uexp, Utra, Neff, Tnom, capval, Udsat, Utst
+
+///
+/// \file nld_mosfet.cpp
+///
+/// Formulas in here based on the following Sources:
+///
+/// https:///www.imperial.ac.uk/pls/portallive/docs/1/7292573.PDF
+/// http://www3.imperial.ac.uk/pls/portallive/docs/1/56133736.PDF
+/// https://people.rit.edu/lffeee/SPICE_MOSFET_Model_Intro.pdf
+/// https://people.rit.edu/lffeee/SPICE.pdf
+/// http://web.mit.edu/course/6/6.012/SPR98/www/lectures/S98_Lecture10.pdf
+/// http://homepages.rpi.edu/~sawyes/Models_review.pdf
+/// http://jaco.ec.t.kanazawa-u.ac.jp/edu/mix/pdf/3.pdf
+///
+/// Farid N. Naim, Circuit Simulation (Wiley-IEEE Press, 2010).
+/// Stefan Jahn, Michael Margraf, Vincent Habchi and Raimund Jacob, "Qucs
+/// Technical Papers" (2007)
+///
+
+#include "../nl_setup.h"
#include "nlid_twoterm.h"
-#include <cmath>
+#include "solver/nld_solver.h"
-#define BODY_CONNECTED_TO_SOURCE (1)
+#define BODY_CONNECTED_TO_SOURCE (1)
-namespace netlist
-{
-namespace analog
+namespace netlist::analog
{
- using constants = plib::constants<nl_double>;
-
- // -----------------------------------------------------------------------------
- // nld_FET - Base classes
- // -----------------------------------------------------------------------------
-
- /*! Class representing the nmos/pmos model paramers.
- *
- * This is the model representation of the nmos model.
- *
- * Netlist has an additional parameter caller CAPMOD:
- *
- * CAPMOD=0: Capacitance model disabled
- * CAPMOD=2: Meyer capacitance model
- *
- * Typically, SPICE uses the following parameters. A "Y" in the first
- * column indicates that the parameter is actually used in netlist.
- *
- * | NL? |Name | Description|Units |Default |Example |
- * |:---:|------|-----------------------------------------------------------------------|-------|---------:|----------------:|
- * | Y |Vto | Zero-bias threshold voltage | V | 0 | 1 |
- * | Y |Kp | Transconductance parameter | A/V² | 0.00002 | 0.00003 |
- * | Y |Gamma | Bulk threshold parameter | V^½ | 0 | 0.37 |
- * | Y |Phi | Surface inversion potential | V | 0.6 | 0.65 |
- * | Y |Lambda| Channel-length modulation (level 1 and 2 only) | 1/V | 0 | 0.02 |
- * | |Rd | Drain ohmic resistance |W|0|1|
- * | |Rs | Source ohmic resistance |W|0|1|
- * | |Cbd | Zero-bias B-D junction capacitance |F|0|20f|
- * | |Cbs | Zero-bias B-S junction capacitance |F|0|20f|
- * | Y |Is | Bulk junction saturation current |A|0.00000000000001|1E-015|
- * | Y |N | Bulk diode emission coefficient |-|1|*
- * | |Pb | Bulk junction potential |V|0.8|0.87|8|
- * | Y |Cgso | Gate-source overlap capacitance per meter channel width |F/m|0|0.00000000004|
- * | Y |Cgdo | Gate-drain overlap capacitance per meter channel width |F/m|0|0.00000000004|*
- * | Y |Cgbo | Gate-bulk overlap capacitance per meter channel width |F/m|0|0.0000000002|*
- * | |Rsh | Drain and source diffusion sheet resistance |W|0|10|*
- * | |Cj | Zero-bias bulk junction bottom capacitance per square meter of junction area|F/m²|0|0.0002|*
- * | |Mj | Bulk junction bottom grading coefficient |-|0.5|0.5|*
- * | |Cjsw | Zero-bias bulk junction sidewall capacitance per meter of junction perimeter|F/m|0|1p|*
- * | |Mjsw | Bulk junction sidewall grading coefficient |-|.50 level 1 .33 level 2,3||
- * | |Js | Bulk junction saturation current per square-meter of junction area|A/m|0|0.00000001|
- * | Y |Tox | Oxide thickness |m|0.0000001|0.0000001|
- * | Y |Nsub | Substrate doping |1/cm³|0|4000000000000000|
- * | |Nss | Surface state density |1/cm²|0|10000000000|
- * | |Nfs | Fast surface state |1/cm²|0|10000000000|*
- * | |TPG | Type of gate material: +1 opp. to substrate -1 same as substrate 0 Al gate|-|1|
- * | |Xj | Metallurgical junction depth |m|0|1µ|*
- * | Y |Ld | Lateral diffusion |m|0|0.8µ|
- * | Y |Uo | Surface mobility |cm²/V/s|600|700|
- * | |Ucrit | Critical field for mobility degradation (level 2 only) |V/cm|10000|10000|
- * | |Uexp | Critical field exponent in mobility degradation (level 2 only) |-|0|0.1|
- * | |Utra | Transverse field coefficient (level 2 only) |-|0|0.3|*
- * | |Vmax | Maximum carrier drift velocity (levels 2 & 3 only) |m/s|0|50000|
- * | |Neff | Total channel-charge exponent (level 2 only) |-|1|5|
- * | |Kf | Flicker noise coefficient |-|0|1E-026|
- * | |Af | Flicker noise exponent |-|1|1.2|
- * | |Fc | Coefficient for forward-bias depletion capacitance formula |-|0.5|
- * | |Delta | Width effect on threshold voltage(levels 2 and 3) |-|0|1|
- * | |Theta | Mobility modulation (level 3 only) |-|0|0.1|
- * | |Eta | Static feedback (level 3 only) |-|0|1|
- * | |Kappa | Saturation field (level 3 only) |0.2|0.5|
- * | |Tnom | Parameter measurement temperature |ºC|27|50||
- * | Y |L | Length scaling |-|100e-6||
- * | Y |W | Width scaling |-|100e-6||
- * */
-
- class fet_model_t : public param_model_t
+ using constants = plib::constants<nl_fptype>;
+
+ /// \brief Class representing the nmos/pmos model parameters.
+ ///
+ /// This is the model representation of the nmos model.
+ ///
+ /// Netlist has an additional parameter caller CAPMOD:
+ ///
+ /// CAPMOD=0: Capacitance model disabled
+ /// CAPMOD=2: Meyer capacitance model
+ ///
+ /// Typically, SPICE uses the following parameters. A "Y" in the first
+ /// column indicates that the parameter is actually used in netlist.
+ ///
+ /// |NL? |Name | Description|Units |Default |Example |
+ /// |:---:|------|-----------------------------------------------------------------------|-------|---------:|----------------:|
+ /// | Y |Vto | Zero-bias threshold voltage | V | 0 | 1 |
+ /// | Y |Kp | Transconductance parameter | A/V² | 0.00002 | 0.00003 |
+ /// | Y |Gamma | Bulk threshold parameter | V^½ | 0 | 0.37 |
+ /// | Y |Phi | Surface inversion potential | V | 0.6 | 0.65 |
+ /// | Y |Lambda| Channel-length modulation (level 1 and 2 only) | 1/V | 0 | 0.02 |
+ /// | |Rd | Drain ohmic resistance |W|0|1|
+ /// | |Rs | Source ohmic resistance |W|0|1|
+ /// | |Cbd | Zero-bias B-D junction capacitance |F|0|20f|
+ /// | |Cbs | Zero-bias B-S junction capacitance |F|0|20f|
+ /// | Y |Is | Bulk junction saturation current |A|0.00000000000001|1E-015|
+ /// | Y |N | Bulk diode emission coefficient |-|1|*|
+ /// | |Pb | Bulk junction potential |V|0.8|0.87|
+ /// | Y |Cgso | Gate-source overlap capacitance per meter channel width |F/m|0|0.00000000004|
+ /// | Y |Cgdo | Gate-drain overlap capacitance per meter channel width |F/m|0|0.00000000004*|
+ /// | Y |Cgbo | Gate-bulk overlap capacitance per meter channel width |F/m|0|0.0000000002*|
+ /// | |Rsh | Drain and source diffusion sheet resistance |W|0|10*|
+ /// | |Cj | Zero-bias bulk junction bottom capacitance per square meter of junction area|F/m²|0|0.0002*|
+ /// | |Mj | Bulk junction bottom grading coefficient |-|0.5|0.5*|
+ /// | |Cjsw | Zero-bias bulk junction sidewall capacitance per meter of junction perimeter|F/m|0|1p*|
+ /// | |Mjsw | Bulk junction sidewall grading coefficient |-|.50 level 1 .33 level 2,3||
+ /// | |Js | Bulk junction saturation current per square-meter of junction area|A/m|0|0.00000001|
+ /// | Y |Tox | Oxide thickness |m|0.0000001|0.0000001|
+ /// | Y |Nsub | Substrate doping |1/cm³|0|4000000000000000|
+ /// | |Nss | Surface state density |1/cm²|0|10000000000|
+ /// | |Nfs | Fast surface state |1/cm²|0|10000000000*|
+ /// | |TPG | Type of gate material: +1 opp. to substrate -1 same as substrate |Al gate|-|1|
+ /// | |Xj | Metallurgical junction depth |m|0|1µ*|
+ /// | Y |Ld | Lateral diffusion |m|0|0.8µ|
+ /// | Y |Uo | Surface mobility |cm²/V/s|600|700|
+ /// | |Ucrit | Critical field for mobility degradation (level 2 only) |V/cm|10000|10000|
+ /// | |Uexp | Critical field exponent in mobility degradation (level 2 only) |-|0|0.1|
+ /// | |Utra | Transverse field coefficient (level 2 only) |-|0|0.3*|
+ /// | |Vmax | Maximum carrier drift velocity (levels 2 & 3 only) |m/s|0|50000|
+ /// | |Neff | Total channel-charge exponent (level 2 only) |-|1|5|
+ /// | |Kf | Flicker noise coefficient |-|0|1E-026|
+ /// | |Af | Flicker noise exponent |-|1|1.2|
+ /// | |Fc | Coefficient for forward-bias depletion capacitance formula |-|0.5||
+ /// | |Delta | Width effect on threshold voltage(levels 2 and 3) |-|0|1|
+ /// | |Theta | Mobility modulation (level 3 only) |-|0|0.1|
+ /// | |Eta | Static feedback (level 3 only) |-|0|1|
+ /// | |Kappa | Saturation field (level 3 only) |-|0.2|0.5|
+ /// | |Tnom | Parameter measurement temperature |ºC|27|50|
+ /// | Y |L | Length scaling |-|100e-6||
+ /// | Y |W | Width scaling |-|100e-6||
+ ///
+
+ class fet_model_t
{
public:
- fet_model_t(device_t &device, const pstring &name, const pstring &val)
- : param_model_t(device, name, val)
- , m_VTO(*this, "VTO")
- , m_N(*this, "N")
- , m_ISS(*this, "IS") // Haven't seen a model using ISS / ISD
- , m_ISD(*this, "IS")
- , m_LD(*this, "LD")
- , m_L(*this, "L")
- , m_W(*this, "W")
- , m_TOX(*this, "TOX")
- , m_KP(*this, "KP")
- , m_UO(*this, "UO")
- , m_PHI(*this, "PHI")
- , m_NSUB(*this, "NSUB")
- , m_GAMMA(*this, "GAMMA")
- , m_LAMBDA(*this, "LAMBDA")
- , m_RD(*this, "RD")
- , m_RS(*this, "RS")
- , m_CGSO(*this, "CGSO")
- , m_CGDO(*this, "CGDO")
- , m_CGBO(*this, "CGBO")
- , m_CAPMOD(*this, "CAPMOD")
- {}
-
- value_t m_VTO; //!< Threshold voltage [V]
- value_t m_N; //!< Bulk diode emission coefficient
- value_t m_ISS; //!< Body diode saturation current
- value_t m_ISD; //!< Body diode saturation current
- value_t m_LD; //!< Lateral diffusion [m]
- value_t m_L; //!< Length scaling
- value_t m_W; //!< Width scaling
- value_t m_TOX; //!< Oxide thickness
- value_t m_KP; //!< Transconductance parameter [A/V²]
- value_t m_UO; //!< Surface mobility [cm²/V/s]
- value_t m_PHI; //!< Surface inversion potential [V]
- value_t m_NSUB; //!< Substrate doping [1/cm³]
- value_t m_GAMMA; //!< Bulk threshold parameter [V^½]
- value_t m_LAMBDA; //!< Channel-length modulation [1/V]
- value_t m_RD; //!< Drain ohmic resistance
- value_t m_RS; //!< Source ohmic resistance
- value_t m_CGSO; //!< Gate-source overlap capacitance per meter channel width
- value_t m_CGDO; //!< Gate-drain overlap capacitance per meter channel width
- value_t m_CGBO; //!< Gate-bulk overlap capacitance per meter channel width
- value_base_t<int> m_CAPMOD; //!< Capacitance model (0=no model 2=Meyer)
- };
-
- // Have a common start for mosfets
-
- NETLIB_OBJECT(FET)
- {
- public:
- enum q_type {
- FET_NMOS,
- FET_PMOS
- };
-
- NETLIB_CONSTRUCTOR(FET)
- , m_model(*this, "MODEL", "NMOS")
- , m_qtype(FET_NMOS)
+ fet_model_t(param_model_t &model)
+ : m_VTO(model, "VTO")
+ , m_N(model, "N")
+ , m_ISS(model, "IS") // Haven't seen a model using ISS / ISD
+ , m_ISD(model, "IS")
+ , m_LD(model, "LD")
+ , m_L(model, "L")
+ , m_W(model, "W")
+ , m_TOX(model, "TOX")
+ , m_KP(model, "KP")
+ , m_UO(model, "UO")
+ , m_PHI(model, "PHI")
+ , m_NSUB(model, "NSUB")
+ , m_GAMMA(model, "GAMMA")
+ , m_LAMBDA(model, "LAMBDA")
+ , m_RD(model, "RD")
+ , m_RS(model, "RS")
+ , m_CGSO(model, "CGSO")
+ , m_CGDO(model, "CGDO")
+ , m_CGBO(model, "CGBO")
+ , m_CAPMOD(model, "CAPMOD")
{
}
- NETLIB_IS_DYNAMIC(true)
-
- //NETLIB_RESETI();
- NETLIB_UPDATEI() { }
-
- q_type qtype() const { return m_qtype; }
- bool is_qtype(q_type atype) const { return m_qtype == atype; }
- void set_qtype(q_type atype) { m_qtype = atype; }
- protected:
-
- fet_model_t m_model;
- private:
- q_type m_qtype;
+ param_model_t::value_t m_VTO; //!< Threshold voltage [V]
+ param_model_t::value_t m_N; //!< Bulk diode emission coefficient
+ param_model_t::value_t m_ISS; //!< Body diode saturation current
+ param_model_t::value_t m_ISD; //!< Body diode saturation current
+ param_model_t::value_t m_LD; //!< Lateral diffusion [m]
+ param_model_t::value_t m_L; //!< Length scaling
+ param_model_t::value_t m_W; //!< Width scaling
+ param_model_t::value_t m_TOX; //!< Oxide thickness
+ param_model_t::value_t m_KP; //!< Transconductance parameter [A/V²]
+ param_model_t::value_t m_UO; //!< Surface mobility [cm²/V/s]
+ param_model_t::value_t m_PHI; //!< Surface inversion potential [V]
+ param_model_t::value_t m_NSUB; //!< Substrate doping [1/cm³]
+ param_model_t::value_t m_GAMMA; //!< Bulk threshold parameter [V^½]
+ param_model_t::value_t m_LAMBDA; //!< Channel-length modulation [1/V]
+ param_model_t::value_t m_RD; //!< Drain ohmic resistance
+ param_model_t::value_t m_RS; //!< Source ohmic resistance
+ param_model_t::value_t m_CGSO; //!< Gate-source overlap capacitance per
+ //!< meter channel width
+ param_model_t::value_t m_CGDO; //!< Gate-drain overlap capacitance per
+ //!< meter channel width
+ param_model_t::value_t m_CGBO; //!< Gate-bulk overlap capacitance per
+ //!< meter channel width
+ param_model_t::value_base_t<int> m_CAPMOD; //!< Capacitance model (0=no
+ //!< model 2=Meyer)
};
// -----------------------------------------------------------------------------
- // nld_QBJT_EB
+ // nld_MOSFET
// -----------------------------------------------------------------------------
- NETLIB_OBJECT_DERIVED(MOSFET, FET)
+ class nld_MOSFET : public base_device_t
{
public:
- NETLIB_CONSTRUCTOR_DERIVED(MOSFET, FET)
- , m_DG(*this, "m_DG", true)
- , m_SG(*this, "m_SG", true)
- , m_SD(*this, "m_SD", true)
+ nld_MOSFET(constructor_param_t data)
+ : base_device_t(data)
+ , m_model(*this, "MODEL", "NMOS")
+ , m_DG(*this, "m_DG", NETLIB_DELEGATE(terminal_handler))
+ , m_SG(*this, "m_SG", NETLIB_DELEGATE(terminal_handler))
+ , m_SD(*this, "m_SD", NETLIB_DELEGATE(terminal_handler))
, m_D_BD(*this, "m_D_BD")
#if (!BODY_CONNECTED_TO_SOURCE)
, m_D_BS(*this, "m_D_BS")
@@ -195,144 +170,183 @@ namespace analog
, m_cap_gb(*this, "m_cap_gb")
, m_cap_gs(*this, "m_cap_gs")
, m_cap_gd(*this, "m_cap_gd")
- , m_phi(0.0)
- , m_gamma(0.0)
- , m_vto(0.0)
- , m_beta(0.0)
- , m_lambda(0.0)
- , m_Leff(0.0)
- , m_CoxWL(0.0)
- , m_polarity(qtype() == FET_NMOS ? 1.0 : -1.0)
- , m_Cgb(0.0)
- , m_Cgs(0.0)
- , m_Cgd(0.0)
- , m_capmod(2)
- , m_Vgs(*this, "m_Vgs", 0.0)
- , m_Vgd(*this, "m_Vgd", 0.0)
- {
- register_subalias("S", m_SG.m_P); // Source
- register_subalias("G", m_SG.m_N); // Gate
+ , m_phi(nlconst::zero())
+ , m_gamma(nlconst::zero())
+ , m_vto(nlconst::zero())
+ , m_beta(nlconst::zero())
+ , m_lambda(nlconst::zero())
+ , m_Leff(nlconst::zero())
+ , m_CoxWL(nlconst::zero())
+ // S, m_polarity(qtype() == FET_NMOS ? nlconst::one() : -nlconst::one())
+ , m_Cgb(nlconst::zero())
+ , m_Cgs(nlconst::zero())
+ , m_Cgd(nlconst::zero())
+ , m_capacitor_model(2)
+ , m_Vgs(*this, "m_Vgs", nlconst::zero())
+ , m_Vgd(*this, "m_Vgd", nlconst::zero())
+ , m_model_acc(m_model)
+ {
+ register_sub_alias("S", m_SG.P()); // Source
+ register_sub_alias("G", m_SG.N()); // Gate
- register_subalias("D", m_DG.m_P); // Drain
+ register_sub_alias("D", m_DG.P()); // Drain
- connect(m_SG.m_P, m_SD.m_P);
- connect(m_SG.m_N, m_DG.m_N);
- connect(m_DG.m_P, m_SD.m_N);
+ connect(m_SG.P(), m_SD.P());
+ connect(m_SG.N(), m_DG.N());
+ connect(m_DG.P(), m_SD.N());
- set_qtype((m_model.type() == "NMOS_DEFAULT") ? FET_NMOS : FET_PMOS);
- m_polarity = qtype() == FET_NMOS ? 1.0 : -1.0;
+ m_polarity = (m_model.type() == "NMOS_DEFAULT" ? nlconst::one()
+ : -nlconst::one());
- m_capmod = m_model.m_CAPMOD;
- // printf("capmod %d %g %g\n", m_capmod, (double)m_model.m_VTO, m_polarity);
- nl_assert_always(m_capmod == 0 || m_capmod == 2, "Error: CAPMODEL invalid value for " + m_model.name());
+ m_capacitor_model = m_model_acc.m_CAPMOD;
+ //# printf("capmod %d %g %g\n", m_capacitor_model, (nl_fptype)m_model_acc.m_VTO, m_polarity);
+ nl_assert_always(m_capacitor_model == 0 || m_capacitor_model == 2,
+ "Error: CAPMODEL invalid value");
- /*
- * From http://ltwiki.org/LTspiceHelp/LTspiceHelp/M_MOSFET.htm :
- *
- * VTO, KP, LAMBDA, PHI and GAMMA. These parameters are computed
- * if the process parameters(NSUB, TOX,...) are given, but
- * user-specified values always override.
- *
- * But couldn't find a formula for lambda anywhere
- *
- */
+ //
+ // From http://ltwiki.org/LTspiceHelp/LTspiceHelp/M_MOSFET.htm :
+ //
+ // VTO, KP, LAMBDA, PHI and GAMMA. These parameters are
+ // computed if the process parameters(NSUB, TOX,...) are given,
+ // but user-specified values always override.
+ //
+ // But couldn't find a formula for lambda anywhere
+ //
- m_lambda = m_model.m_LAMBDA; // FIXME: m_lambda only set once
+ m_lambda = m_model_acc.m_LAMBDA; // FIXME: m_lambda only set once
// calculate effective channel length
- m_Leff = m_model.m_L - 2 * m_model.m_LD;
- nl_assert_always(m_Leff > 0.0, "Effective Lateral diffusion would be negative for model " + m_model.name());
+ m_Leff = m_model_acc.m_L - 2 * m_model_acc.m_LD;
+ nl_assert_always(
+ m_Leff > nlconst::zero(),
+ "Effective Lateral diffusion would be negative for model");
- nl_double Cox = (m_model.m_TOX > 0.0) ? (constants::eps_SiO2() * constants::eps_0() / m_model.m_TOX) : 0.0;
+ nl_fptype Cox = (m_model_acc.m_TOX > nlconst::zero())
+ ? (constants::eps_SiO2() * constants::eps_0()
+ / m_model_acc.m_TOX)
+ : nlconst::zero();
// calculate DC transconductance coefficient
- if (m_model.m_KP > 0)
- m_beta = m_model.m_KP * m_model.m_W / m_Leff;
- else if (Cox > 0 && m_model.m_UO > 0)
- m_beta = m_model.m_UO * 1e-4 * Cox * m_model.m_W / m_Leff;
+ if (m_model_acc.m_KP > nlconst::zero())
+ m_beta = m_model_acc.m_KP * m_model_acc.m_W / m_Leff;
+ else if (Cox > nlconst::zero()
+ && m_model_acc.m_UO > nlconst::zero())
+ m_beta = m_model_acc.m_UO * nlconst::magic(1e-4) * Cox
+ * m_model_acc.m_W / m_Leff;
else
- m_beta = 2e-5 * m_model.m_W / m_Leff;
+ m_beta = nlconst::magic(2e-5) * m_model_acc.m_W / m_Leff;
- //FIXME::UT can disappear
- const double Vt = constants::T0() * constants::k_b() / constants::Q_e();
+ // FIXME::UT can disappear
+ const nl_fptype Vt = constants::T0() * constants::k_b()
+ / constants::Q_e();
// calculate surface potential if not given
- if (m_model.m_PHI > 0.0)
- m_phi = m_model.m_PHI;
- else if (m_model.m_NSUB > 0.0)
+ if (m_model_acc.m_PHI > nlconst::zero())
+ m_phi = m_model_acc.m_PHI;
+ else if (m_model_acc.m_NSUB > nlconst::zero())
{
- nl_assert_always(m_model.m_NSUB * 1e6 >= constants::NiSi(), "Error calculating phi for model " + m_model.name());
- m_phi = 2 * Vt * std::log (m_model.m_NSUB * 1e6 / constants::NiSi());
+ nl_assert_always(m_model_acc.m_NSUB * nlconst::magic(1e6)
+ >= constants::NiSi(),
+ "Error calculating phi for model");
+ m_phi = nlconst::two() * Vt
+ * plib::log(m_model_acc.m_NSUB * nlconst::magic(1e6)
+ / constants::NiSi());
}
else
- m_phi = 0.6;
+ m_phi = nlconst::magic(0.6);
// calculate bulk threshold if not given
- if (m_model.m_GAMMA > 0.0)
- m_gamma = m_model.m_GAMMA;
+ if (m_model_acc.m_GAMMA > nlconst::zero())
+ m_gamma = m_model_acc.m_GAMMA;
else
{
- if (Cox > 0.0 && m_model.m_NSUB > 0)
- m_gamma = std::sqrt (2.0 * constants::Q_e() * constants::eps_Si() * constants::eps_0() * m_model.m_NSUB * 1e6) / Cox;
+ if (Cox > nlconst::zero()
+ && m_model_acc.m_NSUB > nlconst::zero())
+ m_gamma = plib::sqrt(
+ nlconst::two() * constants::Q_e()
+ * constants::eps_Si() * constants::eps_0()
+ * m_model_acc.m_NSUB * nlconst::magic(1e6))
+ / Cox;
else
- m_gamma = 0.0;
+ m_gamma = nlconst::zero();
}
- m_vto = m_model.m_VTO;
- if(m_vto != 0.0)
+ m_vto = m_model_acc.m_VTO;
+ // FIXME zero conversion
+ if (m_vto == nlconst::zero())
log().warning(MW_MOSFET_THRESHOLD_VOLTAGE(m_model.name()));
- /* FIXME: VTO if missing may be calculated from TPG, NSS and temperature. Usually models
- * specify VTO so skip this here.
- */
+ // FIXME: VTO if missing may be calculated from TPG, NSS and
+ // temperature. Usually models specify VTO so skip this here.
- m_CoxWL = Cox * m_model.m_W * m_Leff;
+ m_CoxWL = Cox * m_model_acc.m_W * m_Leff;
- //printf("Cox: %g\n", m_Cox);
+ //#printf("Cox: %g\n", m_Cox);
}
- NETLIB_IS_TIMESTEP(true || m_capmod != 0)
+ NETLIB_IS_DYNAMIC(true)
+ NETLIB_IS_TIMESTEP(true || m_capacitor_model != 0)
NETLIB_TIMESTEPI()
{
- if (m_capmod != 0)
+ if (m_capacitor_model != 0)
{
- //const nl_double Ugd = -m_DG.deltaV() * m_polarity; // Gate - Drain
- //const nl_double Ugs = -m_SG.deltaV() * m_polarity; // Gate - Source
- const nl_double Ugd = m_Vgd; // Gate - Drain
- const nl_double Ugs = m_Vgs; // Gate - Source
- const nl_double Ubs = 0.0; // Bulk - Source == 0 if connected
- const nl_double Ugb = Ugs - Ubs;
-
- m_cap_gb.timestep(m_Cgb, Ugb, step);
- m_cap_gs.timestep(m_Cgs, Ugs, step);
- m_cap_gd.timestep(m_Cgd, Ugd, step);
+ if (ts_type == detail::time_step_type::FORWARD)
+ {
+ //#const nl_nl_fptype Ugd = -m_DG.deltaV() * m_polarity; // Gate - Drain
+ //#const nl_nl_fptype Ugs = -m_SG.deltaV() * m_polarity; // Gate - Source
+ const nl_fptype Ugd = m_Vgd; // Gate - Drain
+ const nl_fptype Ugs = m_Vgs; // Gate - Source
+ const nl_fptype Ubs = nlconst::zero(); // Bulk - Source == 0
+ // if connected
+ const nl_fptype Ugb = Ugs - Ubs;
+
+ m_cap_gb.time_step(m_Cgb, Ugb, step);
+ m_cap_gs.time_step(m_Cgs, Ugs, step);
+ m_cap_gd.time_step(m_Cgd, Ugd, step);
+ }
+ else
+ {
+ m_cap_gb.restore_state();
+ m_cap_gs.restore_state();
+ m_cap_gd.restore_state();
+ }
}
}
protected:
-
NETLIB_RESETI()
{
- NETLIB_NAME(FET)::reset();
// Bulk diodes
- m_D_BD.set_param(m_model.m_ISD, m_model.m_N, exec().gmin(), constants::T0());
- #if (!BODY_CONNECTED_TO_SOURCE)
- m_D_BS.set_param(m_model.m_ISS, m_model.m_N, exec().gmin(), constants::T0());
- #endif
+ m_D_BD.set_param(m_model_acc.m_ISD, m_model_acc.m_N, exec().gmin(),
+ constants::T0());
+#if (!BODY_CONNECTED_TO_SOURCE)
+ m_D_BS.set_param(m_model_acc.m_ISS, m_model_acc.m_N, exec().gmin(),
+ constants::T0());
+#endif
}
- NETLIB_UPDATEI();
+ NETLIB_HANDLERI(terminal_handler)
+ {
+ // only called if connected to a rail net ==> notify the solver to
+ // recalculate
+ auto *solv(m_SG.solver());
+ if (solv != nullptr)
+ solv->solve_now();
+ else
+ m_DG.solver()->solve_now();
+ }
NETLIB_UPDATE_PARAMI();
NETLIB_UPDATE_TERMINALSI();
private:
+ param_model_t m_model;
- nld_twoterm m_DG;
- nld_twoterm m_SG;
- nld_twoterm m_SD;
+ NETLIB_NAME(two_terminal) m_DG;
+ NETLIB_NAME(two_terminal) m_SG;
+ NETLIB_NAME(two_terminal) m_SD;
generic_diode<diode_e::MOS> m_D_BD;
#if (!BODY_CONNECTED_TO_SOURCE)
@@ -343,83 +357,94 @@ namespace analog
generic_capacitor<capacitor_e::VARIABLE_CAPACITY> m_cap_gs;
generic_capacitor<capacitor_e::VARIABLE_CAPACITY> m_cap_gd;
- nl_double m_phi;
- nl_double m_gamma;
- nl_double m_vto;
- nl_double m_beta;
- nl_double m_lambda;
+ nl_fptype m_phi;
+ nl_fptype m_gamma;
+ nl_fptype m_vto;
+ nl_fptype m_beta;
+ nl_fptype m_lambda;
- /* used in capacitance calculation */
- nl_double m_Leff;
- nl_double m_CoxWL;
- nl_double m_polarity;
+ // used in capacitance calculation
+ nl_fptype m_Leff;
+ nl_fptype m_CoxWL;
+ nl_fptype m_polarity;
- /* capacitance values */
+ // capacitance values
- nl_double m_Cgb;
- nl_double m_Cgs;
- nl_double m_Cgd;
+ nl_fptype m_Cgb;
+ nl_fptype m_Cgs;
+ nl_fptype m_Cgd;
- int m_capmod;
- state_var<nl_double> m_Vgs;
- state_var<nl_double> m_Vgd;
+ int m_capacitor_model;
+ state_var<nl_fptype> m_Vgs;
+ state_var<nl_fptype> m_Vgd;
+ fet_model_t m_model_acc;
- void set_cap(generic_capacitor<capacitor_e::VARIABLE_CAPACITY> cap,
- nl_double capval, nl_double V,
- nl_double &g11, nl_double &g12, nl_double &g21, nl_double &g22,
- nl_double &I1, nl_double &I2)
+ void set_cap(generic_capacitor<capacitor_e::VARIABLE_CAPACITY> &cap,
+ nl_fptype capval, nl_fptype V, nl_fptype &g11,
+ nl_fptype &g12, nl_fptype &g21, nl_fptype &g22,
+ nl_fptype &I1, nl_fptype &I2) const
{
- const nl_double I = cap.Ieq(capval, V) * m_polarity;
- const nl_double G = cap.G(capval);
- g11 += G; g12 -= G; g21 -= G; g22 += G;
- I1 -= I; I2 += I;
- //printf("Cap: %g\n", capval);
+ const nl_fptype I = cap.Ieq(capval, V) * m_polarity;
+ const nl_fptype G = cap.G(capval);
+ g11 += G;
+ g12 -= G;
+ g21 -= G;
+ g22 += G;
+ I1 -= I;
+ I2 += I;
+ // printf("Cap: %g\n", capval);
}
- void calculate_caps(nl_double Vgs, nl_double Vgd, nl_double Vth,
- nl_double &Cgs, nl_double &Cgd, nl_double &Cgb)
+ void
+ calculate_caps(nl_fptype Vgs, nl_fptype Vgd, nl_fptype Vth,
+ nl_fptype &Cgs, nl_fptype &Cgd, nl_fptype &Cgb) const
{
- nl_double Vctrl = Vgs - Vth * m_polarity;
+ nl_fptype Vctrl = Vgs - Vth * m_polarity;
// Cut off - now further differentiated into 3 different formulas
// Accumulation
if (Vctrl <= -m_phi)
{
Cgb = m_CoxWL;
- Cgs = 0.0;
- Cgd = 0.0;
+ Cgs = nlconst::zero();
+ Cgd = nlconst::zero();
}
- else if (Vctrl <= -m_phi / 2.0)
+ else if (Vctrl <= -m_phi / nlconst::two())
{
Cgb = -Vctrl * m_CoxWL / m_phi;
- Cgs = 0.0;
- Cgd = 0.0;
+ Cgs = nlconst::zero();
+ Cgd = nlconst::zero();
}
// Depletion
else if (Vctrl <= 0)
{
Cgb = -Vctrl * m_CoxWL / m_phi;
- Cgs = Vctrl * m_CoxWL * (4.0 / 3.0) / m_phi + (2.0 / 3.0) * m_CoxWL;
- Cgd = 0.0;
+ Cgs = Vctrl * m_CoxWL * nlconst::fraction(4.0, 3.0) / m_phi
+ + nlconst::two_thirds() * m_CoxWL;
+ Cgd = nlconst::zero();
}
else
{
- const nl_double Vdsat = Vctrl;
- const nl_double Vds = Vgs - Vgd;
+ const nl_fptype Vdsat = Vctrl;
+ const nl_fptype Vds = Vgs - Vgd;
// saturation
if (Vdsat <= Vds)
{
- Cgb = 0;
- Cgs = (2.0 / 3.0) * m_CoxWL;
- Cgd = 0;
+ Cgb = nlconst::zero();
+ Cgs = nlconst::two_thirds() * m_CoxWL;
+ Cgd = nlconst::zero();
}
else
{
// linear
- const nl_double Sqr1 = std::pow(Vdsat - Vds, 2);
- const nl_double Sqr2 = std::pow(2.0 * Vdsat - Vds, 2);
+ const auto Sqr1(plib::narrow_cast<nl_fptype>(
+ plib::pow(Vdsat - Vds, 2)));
+ const auto Sqr2(plib::narrow_cast<nl_fptype>(
+ plib::pow(nlconst::two() * Vdsat - Vds, 2)));
Cgb = 0;
- Cgs = m_CoxWL * (1.0 - Sqr1 / Sqr2) * (2.0 / 3.0);
- Cgd = m_CoxWL * (1.0 - Vdsat * Vdsat / Sqr2) * (2.0 / 3.0);
+ Cgs = m_CoxWL * (nlconst::one() - Sqr1 / Sqr2)
+ * nlconst::two_thirds();
+ Cgd = m_CoxWL * (nlconst::one() - Vdsat * Vdsat / Sqr2)
+ * nlconst::two_thirds();
}
}
}
@@ -429,36 +454,33 @@ namespace analog
// MOSFET
// ----------------------------------------------------------------------------------------
- NETLIB_UPDATE(MOSFET)
- {
- if (!m_SG.m_P.net().isRailNet())
- m_SG.m_P.solve_now(); // Basis
- else if (!m_SG.m_N.net().isRailNet())
- m_SG.m_N.solve_now(); // Emitter
- else
- m_DG.m_N.solve_now(); // Collector
- }
-
NETLIB_UPDATE_TERMINALS(MOSFET)
{
- nl_double Vgd = -m_DG.deltaV() * m_polarity; // Gate - Drain
- nl_double Vgs = -m_SG.deltaV() * m_polarity; // Gate - Source
+ nl_fptype Vgd = -m_DG.deltaV() * m_polarity; // Gate - Drain
+ nl_fptype Vgs = -m_SG.deltaV() * m_polarity; // Gate - Source
// limit step sizes
- const nl_double k = 3.5; // see "Circuit Simulation", page 185
- nl_double d = (Vgs - m_Vgs);
- Vgs = m_Vgs + 1.0/k * (d < 0 ? -1.0 : 1.0) * std::log1p(k * std::abs(d));
+ const nl_fptype k = nlconst::magic(3.5); // see "Circuit Simulation",
+ // page 185
+ nl_fptype d = (Vgs - m_Vgs);
+ Vgs = m_Vgs
+ + plib::reciprocal(k) * plib::signum(d)
+ * plib::log1p(k * plib::abs(d));
d = (Vgd - m_Vgd);
- Vgd = m_Vgd + 1.0/k * (d < 0 ? -1.0 : 1.0) * std::log1p(k * std::abs(d));
+ Vgd = m_Vgd
+ + plib::reciprocal(k) * plib::signum(d)
+ * plib::log1p(k * plib::abs(d));
m_Vgs = Vgs;
m_Vgd = Vgd;
- const nl_double Vbs = 0.0; // Bulk - Source == 0 if connected
- //const nl_double Vbd = m_SD.deltaV() * m_polarity; // Bulk - Drain = Source - Drain
- const nl_double Vds = Vgs - Vgd;
- const nl_double Vbd = -Vds; // Bulk - Drain = Source - Drain
+ const nl_fptype Vbs = nlconst::zero(); // Bulk - Source == 0 if
+ // connected
+ // const nl_nl_fptype Vbd = m_SD.deltaV() * m_polarity; // Bulk - Drain
+ // = Source - Drain
+ const nl_fptype Vds = Vgs - Vgd;
+ const nl_fptype Vbd = -Vds; // Bulk - Drain = Source - Drain
#if (!BODY_CONNECTED_TO_SOURCE)
m_D_BS.update_diode(Vbs);
@@ -467,135 +489,176 @@ namespace analog
// Are we in forward mode ?
// in backward mode, just swap source and drain
- const bool is_forward = Vds >= 0;
+ const bool is_forward = Vds >= nlconst::zero();
// calculate Vth
- const nl_double Vbulk = is_forward ? Vbs : Vbd;
- const nl_double phi_m_Vbulk = (m_phi > Vbulk) ? std::sqrt(m_phi - Vbulk) : 0.0;
- const nl_double Vth = m_vto * m_polarity + m_gamma * (phi_m_Vbulk - std::sqrt(m_phi));
+ const nl_fptype Vbulk = is_forward ? Vbs : Vbd;
+ const nl_fptype phi_m_Vbulk = (m_phi > Vbulk)
+ ? plib::sqrt(m_phi - Vbulk)
+ : nlconst::zero();
+ const nl_fptype Vth = m_vto * m_polarity
+ + m_gamma * (phi_m_Vbulk - plib::sqrt(m_phi));
+
+ const nl_fptype Vctrl = (is_forward ? Vgs : Vgd) - Vth;
- const nl_double Vctrl = (is_forward ? Vgs : Vgd) - Vth;
+ nl_fptype Ids(0);
+ nl_fptype gm(0);
+ nl_fptype gds(0);
+ nl_fptype gmb(0);
- nl_double Ids, gm, gds, gmb;
- const nl_double absVds = std::abs(Vds);
+ const nl_fptype absVds = plib::abs(Vds);
- if (Vctrl <= 0.0)
+ if (Vctrl <= nlconst::zero())
{
// cutoff region
- Ids = 0.0;
- gm = 0.0;
- gds = 0.0;
- gmb = 0.0;
+ Ids = nlconst::zero();
+ gm = nlconst::zero();
+ gds = nlconst::zero();
+ gmb = nlconst::zero();
}
else
{
- const nl_double beta = m_beta * (1.0 + m_lambda * absVds);
+ const nl_fptype beta = m_beta
+ * (nlconst::one() + m_lambda * absVds);
if (Vctrl <= absVds)
{
// saturation region
- Ids = beta * Vctrl * Vctrl / 2.0;
- gm = beta * Vctrl;
- gds = m_lambda * m_beta * Vctrl * Vctrl / 2.0;
+ Ids = beta * Vctrl * Vctrl / nlconst::two();
+ gm = beta * Vctrl;
+ gds = m_lambda * m_beta * Vctrl * Vctrl / nlconst::two();
}
else
{
// linear region
- Ids = beta * absVds * (Vctrl - absVds / 2);
- gm = beta * absVds;
- gds = beta * (Vctrl - absVds) + m_lambda * m_beta * absVds * (Vctrl - absVds / 2.0);
+ Ids = beta * absVds * (Vctrl - absVds / nlconst::two());
+ gm = beta * absVds;
+ gds = beta * (Vctrl - absVds)
+ + m_lambda * m_beta * absVds
+ * (Vctrl - absVds / nlconst::two());
}
- // backgate transconductance
- const nl_double bgtc = (phi_m_Vbulk != 0.0) ? (m_gamma / phi_m_Vbulk / 2.0) : 0.0;
+ // back gate transconductance
+ const nl_fptype bgtc = (phi_m_Vbulk != nlconst::zero())
+ ? (m_gamma / phi_m_Vbulk
+ / nlconst::two())
+ : nlconst::zero();
gmb = gm * bgtc;
}
// FIXME: these are needed to compute capacitance
- // nl_double Udsat = pol * std::max (Utst, 0.0);
+ // nl_fptype Udsat = pol * std::max (Utst, 0.0);
// Uon = pol * Vth;
// compute bulk diode equivalent currents
- const nl_double IeqBD = m_D_BD.Ieq();
- const nl_double gbd = m_D_BD.G();
+ const nl_fptype IeqBD = m_D_BD.Ieq();
+ const nl_fptype gbd = m_D_BD.G();
#if (!BODY_CONNECTED_TO_SOURCE)
- const nl_double IeqBS = m_D_BS.Ieq();
- const nl_double gbs = m_D_BS.G();
+ const nl_fptype IeqBS = m_D_BS.Ieq();
+ const nl_fptype gbs = m_D_BS.G();
#else
- const nl_double IeqBS = 0.0;
- const nl_double gbs = 0.0;
+ const nl_fptype IeqBS = nlconst::zero();
+ const nl_fptype gbs = nlconst::zero();
#endif
// exchange controlling nodes if necessary
- const nl_double gsource = is_forward ? (gm + gmb) : 0;
- const nl_double gdrain = is_forward ? 0.0 : (gm + gmb);
+ const nl_fptype gate_source = is_forward ? (gm + gmb) : nlconst::zero();
+ const nl_fptype gate_drain = is_forward ? nlconst::zero() : (gm + gmb);
- const nl_double IeqDS = (is_forward) ?
- Ids - gm * Vgs - gmb * Vbs - gds * Vds
- : -Ids - gm * Vgd - gmb * Vbd - gds * Vds;
+ const nl_fptype IeqDS = (is_forward)
+ ? Ids - gm * Vgs - gmb * Vbs - gds * Vds
+ : -Ids - gm * Vgd - gmb * Vbd - gds * Vds;
// IG = 0
- nl_double IG = 0.0;
- nl_double ID = (+IeqBD - IeqDS) * m_polarity;
- nl_double IS = (+IeqBS + IeqDS) * m_polarity;
- nl_double IB = (-IeqBD - IeqBS) * m_polarity;
-
- nl_double gGG = 0.0;
- nl_double gGD = 0.0;
- nl_double gGS = 0.0;
- nl_double gGB = 0.0;
-
- nl_double gDG = gm;
- nl_double gDD = gds + gbd - gdrain;
- const nl_double gDS = -gds - gsource;
- const nl_double gDB = gmb - gbd;
-
- nl_double gSG = -gm;
- const nl_double gSD = -gds + gdrain;
- nl_double gSS = gbs + gds + gsource;
- const nl_double gSB = -gbs - gmb;
-
- nl_double gBG = 0.0;
- const nl_double gBD = -gbd;
- const nl_double gBS = -gbs;
- nl_double gBB = gbs + gbd;
-
- if (m_capmod != 0)
+ nl_fptype IG = nlconst::zero();
+ nl_fptype ID = (+IeqBD - IeqDS) * m_polarity;
+ nl_fptype IS = (+IeqBS + IeqDS) * m_polarity;
+ nl_fptype IB = (-IeqBD - IeqBS) * m_polarity;
+
+ nl_fptype gGG = nlconst::zero();
+ nl_fptype gGD = nlconst::zero();
+ nl_fptype gGS = nlconst::zero();
+ nl_fptype gGB = nlconst::zero();
+
+ nl_fptype gDG = gm;
+ nl_fptype gDD = gds + gbd - gate_drain;
+ const nl_fptype gDS = -gds - gate_source;
+ const nl_fptype gDB = gmb - gbd;
+
+ nl_fptype gSG = -gm;
+ const nl_fptype gSD = -gds + gate_drain;
+ nl_fptype gSS = gbs + gds + gate_source;
+ const nl_fptype gSB = -gbs - gmb;
+
+ nl_fptype gBG = nlconst::zero();
+ const nl_fptype gBD = -gbd;
+ const nl_fptype gBS = -gbs;
+ nl_fptype gBB = gbs + gbd;
+
+ if (m_capacitor_model != 0)
{
- const nl_double Vgb = Vgs - Vbs;
+ const nl_fptype Vgb = Vgs - Vbs;
if (is_forward)
calculate_caps(Vgs, Vgd, Vth, m_Cgs, m_Cgd, m_Cgb);
else
calculate_caps(Vgd, Vgs, Vth, m_Cgd, m_Cgs, m_Cgb);
- set_cap(m_cap_gb, m_Cgb + m_model.m_CGBO * m_Leff, Vgb, gGG, gGB, gBG, gBB, IG, IB);
- set_cap(m_cap_gs, m_Cgs + m_model.m_CGSO * m_model.m_W, Vgs, gGG, gGS, gSG, gSS, IG, IS);
- set_cap(m_cap_gd, m_Cgd + m_model.m_CGDO * m_model.m_W, Vgd, gGG, gGD, gDG, gDD, IG, ID);
+ set_cap(m_cap_gb, m_Cgb + m_model_acc.m_CGBO * m_Leff, Vgb, gGG,
+ gGB, gBG, gBB, IG, IB);
+ set_cap(m_cap_gs, m_Cgs + m_model_acc.m_CGSO * m_model_acc.m_W, Vgs,
+ gGG, gGS, gSG, gSS, IG, IS);
+ set_cap(m_cap_gd, m_Cgd + m_model_acc.m_CGDO * m_model_acc.m_W, Vgd,
+ gGG, gGD, gDG, gDD, IG, ID);
}
// Source connected to body, Diode S-B shorted!
- const nl_double gSSBB = gSS + gBB + gBS + gSB;
-
+ const nl_fptype gSSBB = gSS + gBB + gBS + gSB;
+ const auto zero(nlconst::zero());
// S G
- m_SG.set_mat( gSSBB, gSG + gBG, +(IS + IB), // S
- gGS + gGB, gGG, IG ); // G
+ m_SG.set_mat(gSSBB, gSG + gBG, +(IS + IB), // S
+ gGS + gGB, gGG, IG); // G
// D G
- m_DG.set_mat( gDD, gDG, +ID, // D
- gGD, 0.0, 0.0 ); // G
+ m_DG.set_mat(gDD, gDG, +ID, // D
+ gGD, zero, zero); // G
// S D
- m_SD.set_mat( 0.0, gSD + gBD, 0.0, // S
- gDS + gDB, 0.0, 0.0); // D
+ m_SD.set_mat(zero, gSD + gBD, zero, // S
+ gDS + gDB, zero, zero); // D
+
+ /// |
+ /// | D S G I
+ /// |
+ /// | D gDD gDS + gDB gDG ID
+ ///
+ /// | S gSD + gBD gSSBB gSG + gBG IS+IB
+ ///
+ /// | G gGD gGS + gGB gGG IG
+ /// |
+ /// | forward=yes, bulk diode=no, backgate transconductance=no
+ /// | IG = 0, gGG = 0, gGS, gGB =0, gGD=0l
+ /// gDD=gds + gbd=gds
+ /// gSD+gBD=-gds + gmb - gbd = -gds
+ ///
+ /// | D S G I
+ /// |
+ /// | D gDD gDS + gDB gDG ID
+ ///
+ /// | S gSD + gBD gSSBB gSG + gBG IS+IB
+ ///
+ /// | G 0 0 0 0
+ /// |
+ /// |
+ /// |
+ /// |
+ /// |
+ /// |
}
- NETLIB_UPDATE_PARAM(MOSFET)
- {
- }
+ NETLIB_UPDATE_PARAM(MOSFET) {}
-} // namespace analog
+} // namespace netlist::analog
-namespace devices {
+namespace netlist::devices
+{
NETLIB_DEVICE_IMPL_NS(analog, MOSFET, "MOSFET", "MODEL")
-} // namespace devices
-
-} // namespace netlist
+} // namespace netlist::devices