summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author couriersud <couriersud@gmx.org>2019-03-29 19:40:39 +0100
committer couriersud <couriersud@gmx.org>2019-03-29 19:40:39 +0100
commite4ff0d3322b1da0c747fd98d3100e4bea840bada (patch)
tree217daaab5b24b294322b0b25f3c6e5bed369d6ac
parenta0d2c0c25cf6802f73189ad45724dfbceee2ba23 (diff)
netlist: Improved MOS transistor model. [Couriersud]
This is a significant improvement to the MOS transistor model. It adds modelling of the Meyer capacitance model. This is a somewhat academic addition since the effects occur on a nanosecond time scale and have a huge impact on performance. I plan to make the capacitance model selectable. Both on a model level as well as by introducing a global solver parameter. The model delivers comparable results to LTSpice.
-rw-r--r--nl_examples/nmos_fet.cpp10
-rw-r--r--src/lib/netlist/analog/nld_mosfet.cpp282
-rw-r--r--src/lib/netlist/analog/nlid_twoterm.h76
-rw-r--r--src/lib/netlist/build/makefile3
-rw-r--r--src/lib/netlist/devices/nlid_proxy.cpp4
-rw-r--r--src/lib/netlist/macro/nlm_base.cpp4
-rw-r--r--src/lib/netlist/nl_base.h2
-rw-r--r--src/lib/netlist/nl_config.h1
-rw-r--r--src/lib/netlist/nl_setup.cpp1
-rw-r--r--src/lib/netlist/solver/nld_matrix_solver.cpp2
-rw-r--r--src/lib/netlist/solver/nld_solver.h2
11 files changed, 266 insertions, 121 deletions
diff --git a/nl_examples/nmos_fet.cpp b/nl_examples/nmos_fet.cpp
index ffa67c1bf00..8a096af59ac 100644
--- a/nl_examples/nmos_fet.cpp
+++ b/nl_examples/nmos_fet.cpp
@@ -9,13 +9,15 @@
#include "netlist/devices/net_lib.h"
#include "netlist/analog/nld_twoterm.h"
-NETLIST_START(bjt)
+NETLIST_START(nmos)
/* Standard stuff */
CLOCK(clk, 100) // 100 Hz
SOLVER(Solver, 48000)
- PARAM(Solver.ACCURACY, 1e-7)
- PARAM(Solver.NR_LOOPS, 5000)
+ PARAM(Solver.ACCURACY, 1e-9)
+ PARAM(Solver.NR_LOOPS, 50000)
+ PARAM(Solver.DYNAMIC_TS, 1)
+ PARAM(Solver.DYNAMIC_MIN_TIMESTEP, 1e-9)
ANALOG_INPUT(V5, 5)
ANALOG_INPUT(V3, 3.5)
@@ -40,7 +42,7 @@ NETLIST_START(bjt)
NET_C(RCE.1, M.D)
NET_C(RCE.2, GND)
- // capacitance over D - S
+ // capacitance over G - S
CAP(C, CAP_N(1))
NET_C(M.D, C.1)
diff --git a/src/lib/netlist/analog/nld_mosfet.cpp b/src/lib/netlist/analog/nld_mosfet.cpp
index ea717fdefee..f941d06076a 100644
--- a/src/lib/netlist/analog/nld_mosfet.cpp
+++ b/src/lib/netlist/analog/nld_mosfet.cpp
@@ -57,9 +57,9 @@ namespace analog
* | 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|
- * | |Cgso | Gate-source overlap capacitance per meter channel width |F/m|0|0.00000000004|
- * | |Cgdo | Gate-drain overlap capacitance per meter channel width |F/m|0|0.00000000004|*
- * | |Cgbo | Gate-bulk overlap capacitance per meter channel width |F/m|0|0.0000000002|*
+ * | 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|*
@@ -87,8 +87,8 @@ namespace analog
* | |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 |-|1.0||
- * | Y |W | Width scaling |-|1.0||
+ * | Y |L | Length scaling |-|100e-6||
+ * | Y |W | Width scaling |-|100e-6||
* */
class fet_model_t : public param_model_t
@@ -112,24 +112,30 @@ namespace analog
, m_LAMBDA(*this, "LAMBDA")
, m_RD(*this, "RD")
, m_RS(*this, "RS")
+ , m_CGSO(*this, "CGSO")
+ , m_CGDO(*this, "CGDO")
+ , m_CGBO(*this, "CGBO")
{}
- 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_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
};
// Have a common start for mosfets
@@ -167,7 +173,6 @@ namespace analog
// nld_QBJT_EB
// -----------------------------------------------------------------------------
-
NETLIB_OBJECT_DERIVED(MOSFET, FET)
{
public:
@@ -179,13 +184,21 @@ namespace analog
#if (!BODY_CONNECTED_TO_SOURCE)
, m_D_BS(*this, "m_D_BS")
#endif
+ , 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_Cox(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)
+
{
register_subalias("S", m_SG.m_P); // Source
register_subalias("G", m_SG.m_N); // Gate
@@ -212,6 +225,20 @@ namespace analog
#endif
}
+ NETLIB_IS_TIMESTEP(true)
+
+ NETLIB_TIMESTEPI()
+ {
+ 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 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);
+ }
+
protected:
NETLIB_RESETI();
@@ -230,6 +257,11 @@ namespace analog
generic_diode<diode_e::MOS> m_D_BS;
#endif
+ generic_capacitor<capacitor_e::VARIABLE_CAPACITY> m_cap_gb;
+ 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;
@@ -238,19 +270,80 @@ namespace analog
/* used in capacitance calculation */
nl_double m_Leff;
- nl_double m_Cox;
+ nl_double m_CoxWL;
+ nl_double m_polarity;
- //NETLIB_SUBXX(analog, C) m_CJE;
- //NETLIB_SUBXX(analog, C) m_CJC;
- };
+ /* capacitance values */
+ nl_double m_Cgb;
+ nl_double m_Cgs;
+ nl_double m_Cgd;
+ 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)
+ {
+ 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);
+ }
+
+ void calculate_caps(nl_double Vgs, nl_double Vgd, nl_double Vth,
+ nl_double &Cgs, nl_double &Cgd, nl_double &Cgb)
+ {
+ nl_double 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;
+ }
+ else if (Vctrl <= -m_phi / 2.0)
+ {
+ Cgb = -Vctrl * m_CoxWL / m_phi;
+ Cgs = 0.0;
+ Cgd = 0.0;
+ }
+ // 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;
+ }
+ else
+ {
+ const nl_double Vdsat = Vctrl;
+ const nl_double Vds = Vgs - Vgd;
+ // saturation
+ if (Vdsat <= Vds)
+ {
+ Cgb = 0;
+ Cgs = (2.0 / 3.0) * m_CoxWL;
+ Cgd = 0;
+ }
+ else
+ {
+ // linear
+ const nl_double Sqr1 = std::pow(Vdsat - Vds, 2);
+ const nl_double Sqr2 = std::pow(2.0 * 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);
+ }
+ }
+ }
+ };
// ----------------------------------------------------------------------------------------
// nld_Q - Ebers Moll
// ----------------------------------------------------------------------------------------
-
NETLIB_UPDATE(MOSFET)
{
if (!m_SG.m_P.net().isRailNet())
@@ -264,46 +357,34 @@ namespace analog
NETLIB_RESET(MOSFET)
{
NETLIB_NAME(FET)::reset();
-#if 0
- if (m_CJE)
- {
- m_CJE->reset();
- m_CJE->m_C.setTo(m_model.m_CJE);
- }
- if (m_CJC)
- {
- m_CJC->reset();
- m_CJC->m_C.setTo(m_model.m_CJC);
- }
-#endif
}
NETLIB_UPDATE_TERMINALS(MOSFET)
{
- const nl_double polarity = (qtype() == FET_NMOS ? 1.0 : -1.0);
-
- const nl_double Ugd = -m_DG.deltaV() * polarity; // Gate - Drain
- const nl_double Ugs = -m_SG.deltaV() * polarity; // Gate - Source
- const nl_double Ubs = 0.0; // Bulk - Source == 0 if connected
- const nl_double Ubd = m_SD.deltaV() * polarity; // Bulk - Drain = Source - Drain
- const nl_double Uds = Ugs - Ugd;
+ const nl_double Vgd = -m_DG.deltaV() * m_polarity; // Gate - Drain
+ const nl_double Vgs = -m_SG.deltaV() * m_polarity; // Gate - Source
+ 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;
#if (!BODY_CONNECTED_TO_SOURCE)
- m_D_BS.update_diode(Ubs);
+ m_D_BS.update_diode(Vbs);
#endif
- m_D_BD.update_diode(Ubd);
+ m_D_BD.update_diode(Vbd);
// Are we in forward mode ?
- const bool is_forward = Uds >= 0;
+ // in backward mode, just swap source and drain
+ const bool is_forward = Vds >= 0;
// calculate Vth
- const nl_double Vbulk = is_forward ? Ubs : Ubd;
+ 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 * polarity + m_gamma * (phi_m_Vbulk - std::sqrt(m_phi));
+ const nl_double Vth = m_vto * m_polarity + m_gamma * (phi_m_Vbulk - std::sqrt(m_phi));
- const nl_double Vctrl = (is_forward ? Ugs : Ugd) - Vth;
+ const nl_double Vctrl = (is_forward ? Vgs : Vgd) - Vth;
nl_double Ids, gm, gds, gmb;
+ const nl_double absVds = std::abs(Vds);
if (Vctrl <= 0.0)
{
@@ -315,21 +396,20 @@ namespace analog
}
else
{
- const nl_double Vds = std::abs(Uds);
- const nl_double b = m_beta * (1.0 + m_lambda * Vds);
- if (Vctrl <= Vds)
+ const nl_double beta = m_beta * (1.0 + m_lambda * absVds);
+ if (Vctrl <= absVds)
{
// saturation region
- Ids = b * Vctrl * Vctrl / 2.0;
- gm = b * Vctrl;
+ Ids = beta * Vctrl * Vctrl / 2.0;
+ gm = beta * Vctrl;
gds = m_lambda * m_beta * Vctrl * Vctrl / 2.0;
}
else
{
// linear region
- Ids = b * Vds * (Vctrl - Vds / 2);
- gm = b * Vds;
- gds = b * (Vctrl - Vds) + m_lambda * m_beta * Vds * (Vctrl - Vds / 2.0);
+ Ids = beta * absVds * (Vctrl - absVds / 2);
+ gm = beta * absVds;
+ gds = beta * (Vctrl - absVds) + m_lambda * m_beta * absVds * (Vctrl - absVds / 2.0);
}
// backgate transconductance
@@ -345,7 +425,7 @@ namespace analog
const nl_double IeqBD = m_D_BD.Ieq();
const nl_double gbd = m_D_BD.G();
-#if 0
+#if (!BODY_CONNECTED_TO_SOURCE)
const nl_double IeqBS = m_D_BS.Ieq();
const nl_double gbs = m_D_BS.G();
#else
@@ -357,34 +437,45 @@ namespace analog
const nl_double gdrain = is_forward ? 0.0 : (gm + gmb);
const nl_double IeqDS = (is_forward) ?
- Ids - gm * Ugs - gmb * Ubs - gds * Uds
- : -Ids - gm * Ugd - gmb * Ubd - gds * Uds;
+ Ids - gm * Vgs - gmb * Vbs - gds * Vds
+ : -Ids - gm * Vgd - gmb * Vbd - gds * Vds;
// IG = 0
- const nl_double IG = 0.0;
- const nl_double ID = (+IeqBD - IeqDS) * polarity;
- const nl_double IS = (+IeqBS + IeqDS) * polarity;
- const nl_double IB = (-IeqBD - IeqBS) * polarity;
-
- const nl_double gGG = 0.0; // ok
- const nl_double gGD = 0.0; // ok
- const nl_double gGS = 0.0; // ok
- const nl_double gGB = 0.0; // ok
-
- const nl_double gDG = gm; // ok
- const nl_double gDD = gds + gbd - gdrain; // ok
- const nl_double gDS = -gds - gsource; // ok
- const nl_double gDB = gmb - gbd; // ok
-
- const nl_double gSG = -gm; // ok
- const nl_double gSD = -gds + gdrain; // ok
- const nl_double gSS = gbs + gds + gsource; // ok
+ 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;
- const nl_double gBG = 0.0; // ok
- const nl_double gBD = -gbd; // ok
+ nl_double gBG = 0.0;
+ const nl_double gBD = -gbd;
const nl_double gBS = -gbs;
- const nl_double gBB = gbs + gbd; // ok
+ nl_double gBB = gbs + gbd;
+
+ const nl_double 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);
// Source connected to body, Diode S-B shorted!
const nl_double gSSBB = gSS + gBB + gBS + gSB;
@@ -398,13 +489,12 @@ namespace analog
// S D
m_SD.set_mat( 0.0, gSD + gBD, 0.0, // S
gDS + gDB, 0.0, 0.0); // D
-
}
-
NETLIB_UPDATE_PARAM(MOSFET)
{
set_qtype((m_model.model_type() == "NMOS") ? FET_NMOS : FET_PMOS);
+ m_polarity = qtype() == FET_NMOS ? 1.0 : -1.0;
/*
* From http://ltwiki.org/LTspiceHelp/LTspiceHelp/M_MOSFET.htm :
@@ -422,16 +512,14 @@ namespace analog
// 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());
- if (m_model.m_TOX > 0.0)
- m_Cox = (constants::eps_SiO2() * constants::eps_0() / m_model.m_TOX);
- else
- m_Cox = 0.0;
+
+ nl_double Cox = (m_model.m_TOX > 0.0) ? (constants::eps_SiO2() * constants::eps_0() / m_model.m_TOX) : 0.0;
// calculate DC transconductance coefficient
if (m_model.m_KP > 0)
m_beta = m_model.m_KP * m_model.m_W / m_Leff;
- else if (m_Cox > 0 && m_model.m_UO > 0)
- m_beta = m_model.m_UO * 1e-4 * m_Cox * 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;
else
m_beta = 2e-5 * m_model.m_W / m_Leff;
@@ -462,8 +550,8 @@ namespace analog
m_gamma = m_model.m_GAMMA;
else
{
- if (m_Cox > 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) / m_Cox;
+ 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;
else
m_gamma = 0.0;
}
@@ -475,7 +563,9 @@ namespace analog
* specify VTO so skip this here.
*/
- m_Cox = m_Cox * m_model.m_W * m_Leff;
+ m_CoxWL = Cox * m_model.m_W * m_Leff;
+
+ //printf("Cox: %g\n", m_Cox);
}
diff --git a/src/lib/netlist/analog/nlid_twoterm.h b/src/lib/netlist/analog/nlid_twoterm.h
index 470fb35c96e..aaf35fe9e28 100644
--- a/src/lib/netlist/analog/nlid_twoterm.h
+++ b/src/lib/netlist/analog/nlid_twoterm.h
@@ -87,7 +87,7 @@ public:
void solve_now();
- void solve_later(netlist_time delay = netlist_time::from_nsec(1));
+ void solve_later(netlist_time delay = netlist_time::quantum());
void set_G_V_I(const nl_double G, const nl_double V, const nl_double I)
{
@@ -226,7 +226,7 @@ private:
enum class capacitor_e
{
- CHARGE_CONSERVING,
+ VARIABLE_CAPACITY,
CONSTANT_CAPACITY
};
@@ -235,19 +235,63 @@ class generic_capacitor
{
};
+#if 1
+template <>
+class generic_capacitor<capacitor_e::VARIABLE_CAPACITY>
+{
+public:
+ generic_capacitor(device_t &dev, const pstring &name)
+ : m_h(dev, name + ".m_h", 0.0)
+ , m_c(dev, name + ".m_c", 0.0)
+ , m_v(dev, name + ".m_v", 0.0)
+ , m_gmin(0.0)
+ {
+ }
+
+ capacitor_e type() const { return capacitor_e::VARIABLE_CAPACITY; }
+ nl_double G(nl_double cap) const
+ {
+ //return m_h * (2.0 * cap - m_c) + m_gmin;
+ return m_h * 0.5 * (cap + m_c) + m_gmin;
+ }
+
+ nl_double Ieq(nl_double cap, nl_double v) const
+ {
+ plib::unused_var(v);
+// return m_h * (cap * v - m_charge) - G(cap) * v;
+ return -m_h * 0.5 * (cap + m_c) * m_v;
+ }
+
+ void timestep(nl_double cap, nl_double v, nl_double step)
+ {
+ m_h = 1.0 / step;
+ m_c = cap;
+ m_v = v;
+ }
+
+ void setparams(nl_double gmin) { m_gmin = gmin; }
+
+private:
+ state_var<double> m_h;
+ state_var<double> m_c;
+ state_var<double> m_v;
+ nl_double m_gmin;
+};
+#else
template <>
-class generic_capacitor<capacitor_e::CHARGE_CONSERVING>
+class generic_capacitor<capacitor_e::VARIABLE_CAPACITY>
{
public:
generic_capacitor(device_t &dev, const pstring &name)
: m_h(dev, name + ".m_h", 0.0)
, m_charge(dev, name + ".m_charge", 0.0)
+ , m_v(dev, name + ".m_v", 0.0)
, m_gmin(0.0)
{
}
- constexpr capacitor_e type() const { return capacitor_e::CHARGE_CONSERVING; }
+ constexpr capacitor_e type() const { return capacitor_e::VARIABLE_CAPACITY; }
constexpr nl_double G(nl_double cap) const
{
@@ -256,13 +300,16 @@ public:
constexpr nl_double Ieq(nl_double cap, nl_double v) const
{
- return m_h * (cap * v - m_charge) - G(cap) * v;
+// return m_h * (cap * v - m_charge) - G(cap) * v;
+// return m_h * (cap * (v - m_v)) - G(cap) * v;
+ return -m_h * cap * m_v;
}
void timestep(nl_double cap, nl_double v, nl_double step)
{
m_h = 1.0 / step;
- m_charge = cap * v;
+ m_charge = m_charge + cap * (v - m_v);
+ m_v = v;
}
void setparams(nl_double gmin) { m_gmin = gmin; }
@@ -270,9 +317,10 @@ public:
private:
state_var<double> m_h;
state_var<double> m_charge;
+ state_var<double> m_v;
nl_double m_gmin;
};
-
+#endif
template <>
class generic_capacitor<capacitor_e::CONSTANT_CAPACITY>
{
@@ -283,9 +331,9 @@ public:
{
}
- constexpr capacitor_e type() const { return capacitor_e::CONSTANT_CAPACITY; }
- constexpr nl_double G(nl_double cap) const { return cap * m_h + m_gmin; }
- constexpr nl_double Ieq(nl_double cap, nl_double v) const { return - G(cap) * v; }
+ capacitor_e type() const { return capacitor_e::CONSTANT_CAPACITY; }
+ nl_double G(nl_double cap) const { return cap * m_h + m_gmin; }
+ nl_double Ieq(nl_double cap, nl_double v) const { return - G(cap) * v; }
void timestep(nl_double cap, nl_double v, nl_double step)
{
@@ -324,7 +372,7 @@ public:
}
}
- NETLIB_IS_DYNAMIC(m_cap.type() == capacitor_e::CHARGE_CONSERVING)
+ NETLIB_IS_DYNAMIC(m_cap.type() == capacitor_e::VARIABLE_CAPACITY)
NETLIB_UPDATE_TERMINALSI()
{
const nl_double I = m_cap.Ieq(m_C(), deltaV());
@@ -344,8 +392,8 @@ protected:
NETLIB_UPDATE_PARAMI() { }
private:
- generic_capacitor<capacitor_e::CHARGE_CONSERVING> m_cap;
- //generic_capacitor<capacitor_e::CONSTANT_CAPACITY> m_cap;
+ //generic_capacitor<capacitor_e::VARIABLE_CAPACITY> m_cap;
+ generic_capacitor<capacitor_e::CONSTANT_CAPACITY> m_cap;
};
// -----------------------------------------------------------------------------
@@ -429,7 +477,7 @@ public:
else if (TYPE == diode_e::MOS || nVd < m_Vcrit)
{
m_Vd = nVd;
- const double IseVDVt = std::exp(std::min(700.0, m_logIs + m_Vd * m_VtInv));
+ const double IseVDVt = std::exp(std::min(300.0, m_logIs + m_Vd * m_VtInv));
m_Id = IseVDVt - m_Is;
m_G = IseVDVt * m_VtInv + m_gmin;
}
diff --git a/src/lib/netlist/build/makefile b/src/lib/netlist/build/makefile
index 647c7df6f12..6179a0e5932 100644
--- a/src/lib/netlist/build/makefile
+++ b/src/lib/netlist/build/makefile
@@ -230,6 +230,9 @@ maketree: $(sort $(OBJDIRS))
native:
$(MAKE) CEXTRAFLAGS="-march=native -msse4.2 -Wall -Wpedantic -Wsign-compare -Wextra "
+gcc5:
+ $(MAKE) CC=g++-5 LD=g++-5 CEXTRAFLAGS="-march=native -msse4.2 -Wall -Wpedantic -Wsign-compare -Wextra "
+
clang:
$(MAKE) CC=clang++-9 LD=clang++-9 CEXTRAFLAGS="-march=native -Weverything -Werror -Wno-padded -Wno-weak-vtables -Wno-unused-template -Wno-missing-variable-declarations -Wno-float-equal -Wconversion -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-format-nonliteral -Wno-exit-time-destructors"
diff --git a/src/lib/netlist/devices/nlid_proxy.cpp b/src/lib/netlist/devices/nlid_proxy.cpp
index a2fd18e85a7..e40d3506cff 100644
--- a/src/lib/netlist/devices/nlid_proxy.cpp
+++ b/src/lib/netlist/devices/nlid_proxy.cpp
@@ -58,9 +58,9 @@ namespace netlist
if (supply_V == 0.0) supply_V = 5.0;
if (m_I.Q_Analog() > logic_family()->high_thresh_V(0.0, supply_V))
- out().push(1, NLTIME_FROM_NS(1));
+ out().push(1, netlist_time::quantum());
else if (m_I.Q_Analog() < logic_family()->low_thresh_V(0.0, supply_V))
- out().push(0, NLTIME_FROM_NS(1));
+ out().push(0, netlist_time::quantum());
else
{
// do nothing
diff --git a/src/lib/netlist/macro/nlm_base.cpp b/src/lib/netlist/macro/nlm_base.cpp
index 86f2450d301..2e4542de4b6 100644
--- a/src/lib/netlist/macro/nlm_base.cpp
+++ b/src/lib/netlist/macro/nlm_base.cpp
@@ -34,8 +34,8 @@ NETLIST_END()
static NETLIST_START(mosfet_models)
//NET_MODEL("NMOS _(VTO=0.0 N=1.0 IS=1E-14 KP=2E-5 UO=600 PHI=0.6 LD=0.0 L=1.0 TOX=1E-7 W=1.0 NSUB=0.0 GAMMA=0.0 RD=0.0 RS=0.0 LAMBDA=0.0)")
//NET_MODEL("PMOS _(VTO=0.0 N=1.0 IS=1E-14 KP=2E-5 UO=600 PHI=0.6 LD=0.0 L=1.0 TOX=1E-7 W=1.0 NSUB=0.0 GAMMA=0.0 RD=0.0 RS=0.0 LAMBDA=0.0)")
- NET_MODEL("NMOS _(VTO=0.0 N=1.0 IS=1E-14 KP=0.0 UO=600 PHI=0.0 LD=0.0 L=1.0 TOX=1E-7 W=1.0 NSUB=0.0 GAMMA=0.0 RD=0.0 RS=0.0 LAMBDA=0.0)")
- NET_MODEL("PMOS _(VTO=0.0 N=1.0 IS=1E-14 KP=0.0 UO=600 PHI=0.0 LD=0.0 L=1.0 TOX=1E-7 W=1.0 NSUB=0.0 GAMMA=0.0 RD=0.0 RS=0.0 LAMBDA=0.0)")
+ NET_MODEL("NMOS _(VTO=0.0 N=1.0 IS=1E-14 KP=0.0 UO=600 PHI=0.0 LD=0.0 L=100e-6 TOX=1E-7 W=100e-6 NSUB=0.0 GAMMA=0.0 RD=0.0 RS=0.0 LAMBDA=0.0 CGSO=0 CGDO=0 CGBO=0)")
+ NET_MODEL("PMOS _(VTO=0.0 N=1.0 IS=1E-14 KP=0.0 UO=600 PHI=0.0 LD=0.0 L=100e-6 TOX=1E-7 W=100e-6 NSUB=0.0 GAMMA=0.0 RD=0.0 RS=0.0 LAMBDA=0.0 CGSO=0 CGDO=0 CGBO=0)")
NETLIST_END()
static NETLIST_START(bjt_models)
diff --git a/src/lib/netlist/nl_base.h b/src/lib/netlist/nl_base.h
index 9d0eed869e0..c1f07a55af2 100644
--- a/src/lib/netlist/nl_base.h
+++ b/src/lib/netlist/nl_base.h
@@ -1710,7 +1710,7 @@ namespace netlist
if (newQ != m_my_net.Q_Analog())
{
m_my_net.set_Q_Analog(newQ);
- m_my_net.toggle_and_push_to_queue(NLTIME_FROM_NS(1));
+ m_my_net.toggle_and_push_to_queue(netlist_time::quantum());
}
}
diff --git a/src/lib/netlist/nl_config.h b/src/lib/netlist/nl_config.h
index faa5008ff56..98ca0e27370 100644
--- a/src/lib/netlist/nl_config.h
+++ b/src/lib/netlist/nl_config.h
@@ -89,6 +89,7 @@
// Use nano-second resolution - Sufficient for now
static constexpr const auto NETLIST_INTERNAL_RES = 1000000000;
+//static constexpr const auto NETLIST_INTERNAL_RES = 1000000000000;
static constexpr const auto NETLIST_CLOCK = NETLIST_INTERNAL_RES;
//#define NETLIST_INTERNAL_RES (UINT64_C(1000000000))
diff --git a/src/lib/netlist/nl_setup.cpp b/src/lib/netlist/nl_setup.cpp
index b9300f5ad9c..3ae73b50f6f 100644
--- a/src/lib/netlist/nl_setup.cpp
+++ b/src/lib/netlist/nl_setup.cpp
@@ -737,6 +737,7 @@ void setup_t::resolve_inputs()
detail::core_terminal_t *t1 = find_terminal(t1s);
detail::core_terminal_t *t2 = find_terminal(t2s);
+ //printf("%s %s\n", t1s.c_str(), t2s.c_str());
if (connect(*t1, *t2))
li = m_links.erase(li);
else
diff --git a/src/lib/netlist/solver/nld_matrix_solver.cpp b/src/lib/netlist/solver/nld_matrix_solver.cpp
index 1fe14b0f5e1..0a7bf5ef3c3 100644
--- a/src/lib/netlist/solver/nld_matrix_solver.cpp
+++ b/src/lib/netlist/solver/nld_matrix_solver.cpp
@@ -19,7 +19,7 @@ namespace devices
: m_railstart(0)
, m_last_V(0.0)
, m_DD_n_m_1(0.0)
- , m_h_n_m_1(1e-9)
+ , m_h_n_m_1(1e-12)
{
}
diff --git a/src/lib/netlist/solver/nld_solver.h b/src/lib/netlist/solver/nld_solver.h
index c9ec967a72a..3580ca94996 100644
--- a/src/lib/netlist/solver/nld_solver.h
+++ b/src/lib/netlist/solver/nld_solver.h
@@ -48,7 +48,7 @@ namespace devices
, m_gmin(*this, "GMIN", 1e-9)
, m_pivot(*this, "PIVOT", false) // use pivoting - on supported solvers
, m_nr_loops(*this, "NR_LOOPS", 250) // Newton-Raphson loops
- , m_nr_recalc_delay(*this, "NR_RECALC_DELAY", NLTIME_FROM_NS(10).as_double()) // Delay to next solve attempt if nr loops exceeded
+ , m_nr_recalc_delay(*this, "NR_RECALC_DELAY", netlist_time::quantum().as_double()) // Delay to next solve attempt if nr loops exceeded
, m_parallel(*this, "PARALLEL", 0)
/* automatic time step */