summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--nl_examples/congoBongo.c51
-rw-r--r--nl_examples/opamp.c21
-rw-r--r--src/emu/netlist/analog/nld_fourterm.c51
-rw-r--r--src/emu/netlist/analog/nld_fourterm.h41
-rw-r--r--src/emu/netlist/analog/nld_opamps.c118
-rw-r--r--src/emu/netlist/analog/nld_opamps.h29
-rw-r--r--src/emu/netlist/analog/nld_twoterm.c9
-rw-r--r--src/emu/netlist/analog/nld_twoterm.h38
-rw-r--r--src/emu/netlist/devices/net_lib.c2
-rw-r--r--src/emu/netlist/nl_base.c24
-rw-r--r--src/emu/netlist/nl_base.h3
-rw-r--r--src/emu/netlist/nl_setup.c1
-rw-r--r--src/emu/netlist/solver/nld_ms_direct.h104
-rw-r--r--src/emu/netlist/solver/nld_ms_sor_mat.h2
-rw-r--r--src/emu/netlist/solver/nld_solver.c4
15 files changed, 405 insertions, 93 deletions
diff --git a/nl_examples/congoBongo.c b/nl_examples/congoBongo.c
index 9584de39b88..1a04c0a2ad3 100644
--- a/nl_examples/congoBongo.c
+++ b/nl_examples/congoBongo.c
@@ -49,9 +49,9 @@ NETLIST_START(dummy)
// .END
SOLVER(Solver, 24000)
- PARAM(Solver.ACCURACY, 1e-8)
+ PARAM(Solver.ACCURACY, 1e-7)
PARAM(Solver.NR_LOOPS, 90)
- PARAM(Solver.SOR_FACTOR, 0.00001)
+ PARAM(Solver.SOR_FACTOR, 0.001)
PARAM(Solver.GS_LOOPS, 1)
//PARAM(Solver.GS_THRESHOLD, 99)
PARAM(Solver.ITERATIVE, "SOR")
@@ -334,7 +334,7 @@ NETLIST_START(CongoBongo_schematics)
NET_C(C61.1, R94.2)
NETLIST_END()
-NETLIST_START(opamp)
+NETLIST_START(opamp_mod)
/* Opamp model from
*
@@ -374,13 +374,18 @@ NETLIST_START(opamp)
NET_C(EBUF.ON, fVREF)
/* The opamp model */
- VCCS(G1)
+ LVCCS(G1)
PARAM(G1.RI, RES_K(1000))
-
+#if 0
PARAM(G1.G, 0.0022)
RES(RP1, 1e6)
CAP(CP1, 0.0318e-6)
-
+#else
+ PARAM(G1.G, 0.0002)
+ PARAM(G1.CURLIM, 0.002)
+ RES(RP1, 9.5e6)
+ CAP(CP1, 0.0033e-6)
+#endif
VCVS(EBUF)
PARAM(EBUF.RO, 50)
PARAM(EBUF.G, 1)
@@ -395,21 +400,43 @@ NETLIST_START(opamp)
DIODE(DP,".model tt D(IS=1e-15 N=1)")
DIODE(DN,".model tt D(IS=1e-15 N=1)")
-
+#if 1
NET_C(DP.K, fUH.Q)
NET_C(fUL.Q, DN.A)
NET_C(DP.A, DN.K, RP1.1)
+#else
+ /*
+ * This doesn't add any performance by decreasing iteration loops.
+ * To the contrary, it significantly decreases iterations
+ */
+ RES(RH1, 0.1)
+ RES(RL1, 0.1)
+ NET_C(DP.K, RH1.1)
+ NET_C(RH1.2, fUH.Q)
+ NET_C(fUL.Q, RL1.1)
+ NET_C(RL1.2, DN.A)
+ NET_C(DP.A, DN.K, RP1.1)
+#endif
NET_C(EBUF.IP, RP1.1)
NETLIST_END()
NETLIST_START(MB3614_DIP)
- SUBMODEL(opamp, op1)
- SUBMODEL(opamp, op2)
- SUBMODEL(opamp, op3)
- SUBMODEL(opamp, op4)
-
+#if 1
+ SUBMODEL(opamp_mod, op1)
+ SUBMODEL(opamp_mod, op2)
+ SUBMODEL(opamp_mod, op3)
+ SUBMODEL(opamp_mod, op4)
+#else
+ /* The opamp actually has an FPF of about 500k. This doesn't work here and causes oscillations.
+ * FPF here therefore about half the Solver clock.
+ */
+ OPAMP(op1, ".model MB3614 OPAMP(TYPE=3 VLH=2.0 VLL=0.2 FPF=5 UGF=11k SLEW=0.6M RI=1000k RO=50 DAB=0.002)")
+ OPAMP(op2, ".model MB3614 OPAMP(TYPE=3 VLH=2.0 VLL=0.2 FPF=5 UGF=11k SLEW=0.6M RI=1000k RO=50 DAB=0.002)")
+ OPAMP(op3, ".model MB3614 OPAMP(TYPE=3 VLH=2.0 VLL=0.2 FPF=5 UGF=11k SLEW=0.6M RI=1000k RO=50 DAB=0.002)")
+ OPAMP(op4, ".model MB3614 OPAMP(TYPE=3 VLH=2.0 VLL=0.2 FPF=5 UGF=11k SLEW=0.6M RI=1000k RO=50 DAB=0.002)")
+#endif
ALIAS( 1, op1.OUT)
ALIAS( 2, op1.MINUS)
ALIAS( 3, op1.PLUS)
diff --git a/nl_examples/opamp.c b/nl_examples/opamp.c
index 01db8fb4383..ce347c21c64 100644
--- a/nl_examples/opamp.c
+++ b/nl_examples/opamp.c
@@ -11,10 +11,12 @@ NETLIST_START(main)
/* Standard stuff */
CLOCK(clk, 1000) // 1000 Hz
- SOLVER(Solver, 48000)
- //PARAM(Solver.ACCURACY, 1e-3)
+ SOLVER(Solver, 480000)
+ PARAM(Solver.ACCURACY, 1e-10)
+ PARAM(Solver.NR_LOOPS, 30000 )
//PARAM(Solver.CONVERG, 1.0)
- //PARAM(Solver.GS_LOOPS, 30)
+ PARAM(Solver.GS_LOOPS, 30)
+ PARAM(Solver.GS_THRESHOLD, 99)
// Tie up +5 to opamps thought it's not currently needed
// Stay compatible
@@ -47,8 +49,8 @@ NETLIST_START(main)
NET_C(RL.2, GND)
NET_C(RL.1, op1.OUT)
- //LOG(logX, op1.OUT)
- //LOG(logY, clk)
+ LOG(logX, op1.OUT)
+ LOG(logY, clk)
NETLIST_END()
NETLIST_START(opamp)
@@ -73,10 +75,11 @@ NETLIST_START(opamp)
/* The opamp model */
- VCCS(G1)
- PARAM(G1.G, 100) // typical OP-AMP amplification 100 * 1000 = 100000
- RES(RP1, 1000)
- CAP(CP1, 1.59e-6) // <== change to 1.59e-3 for 10Khz bandwidth
+ LVCCS(G1)
+ PARAM(G1.G, 0.0021)
+ PARAM(G1.CURLIM, 0.002)
+ RES(RP1, 1e7)
+ CAP(CP1, 0.00333e-6)
VCVS(EBUF)
PARAM(EBUF.RO, 50)
PARAM(EBUF.G, 1)
diff --git a/src/emu/netlist/analog/nld_fourterm.c b/src/emu/netlist/analog/nld_fourterm.c
index 211c60ff3eb..58d173e6554 100644
--- a/src/emu/netlist/analog/nld_fourterm.c
+++ b/src/emu/netlist/analog/nld_fourterm.c
@@ -65,6 +65,7 @@ NETLIB_RESET(VCCS)
NETLIB_UPDATE_PARAM(VCCS)
{
+ NETLIB_NAME(VCCS)::reset();
}
NETLIB_UPDATE(VCCS)
@@ -81,6 +82,56 @@ NETLIB_UPDATE(VCCS)
}
// ----------------------------------------------------------------------------------------
+// nld_LVCCS
+// ----------------------------------------------------------------------------------------
+
+NETLIB_START(LVCCS)
+{
+ NETLIB_NAME(VCCS)::start();
+ register_param("CURLIM", m_cur_limit, 1000.0);
+}
+
+NETLIB_RESET(LVCCS)
+{
+ NETLIB_NAME(VCCS)::reset();
+}
+
+NETLIB_UPDATE_PARAM(LVCCS)
+{
+ NETLIB_NAME(VCCS)::update_param();
+}
+
+NETLIB_UPDATE(LVCCS)
+{
+ NETLIB_NAME(VCCS)::update();
+}
+
+NETLIB_UPDATE_TERMINALS(LVCCS)
+{
+ const nl_double m_mult = m_G.Value() * m_gfac; // 1.0 ==> 1V ==> 1A
+ const nl_double vi = m_IP.net().m_cur_Analog - m_IN.net().m_cur_Analog;
+
+ if (std::abs(m_mult / m_cur_limit * vi) > 0.5)
+ m_vi = m_vi + 0.2*std::tanh((vi - m_vi)/0.2);
+ else
+ m_vi = vi;
+
+ const nl_double x = m_mult / m_cur_limit * m_vi;
+ const nl_double X = std::tanh(x);
+
+ const nl_double beta = m_mult * (1.0 - X*X);
+ const nl_double I = m_cur_limit * X - beta * m_vi;
+
+ m_OP.set(beta, NL_FCONST(0.0), I);
+ m_OP1.set(-beta, NL_FCONST(0.0));
+
+ m_ON.set(-beta, NL_FCONST(0.0), -I);
+ m_ON1.set(beta, NL_FCONST(0.0));
+ //printf("vi %f beta %f I %f\n", vi, beta, I);
+
+}
+
+// ----------------------------------------------------------------------------------------
// nld_CCCS
// ----------------------------------------------------------------------------------------
diff --git a/src/emu/netlist/analog/nld_fourterm.h b/src/emu/netlist/analog/nld_fourterm.h
index ecc37f33388..7ed6965a393 100644
--- a/src/emu/netlist/analog/nld_fourterm.h
+++ b/src/emu/netlist/analog/nld_fourterm.h
@@ -16,15 +16,17 @@
// Macros
// ----------------------------------------------------------------------------------------
-#define VCCS(_name) \
+#define VCCS(_name) \
NET_REGISTER_DEV(VCCS, _name)
-#define CCCS(_name) \
+#define CCCS(_name) \
NET_REGISTER_DEV(CCCS, _name)
-#define VCVS(_name) \
+#define VCVS(_name) \
NET_REGISTER_DEV(VCVS, _name)
+#define LVCCS(_name) \
+ NET_REGISTER_DEV(LVCCS, _name)
NETLIB_NAMESPACE_DEVICES_START()
@@ -57,11 +59,14 @@ public:
ATTR_COLD NETLIB_NAME(VCCS)(const family_t afamily)
: device_t(afamily), m_gfac(1.0) { }
+ param_double_t m_G;
+ param_double_t m_RI;
+
protected:
virtual void start();
virtual void reset();
virtual void update_param();
- ATTR_HOT void update();
+ ATTR_HOT virtual void update();
ATTR_COLD void start_internal(const nl_double def_RI);
@@ -74,12 +79,31 @@ protected:
terminal_t m_OP1;
terminal_t m_ON1;
- param_double_t m_G;
- param_double_t m_RI;
-
nl_double m_gfac;
};
+/* Limited Current source*/
+
+class NETLIB_NAME(LVCCS) : public NETLIB_NAME(VCCS)
+{
+public:
+ ATTR_COLD NETLIB_NAME(LVCCS)()
+ : NETLIB_NAME(VCCS)(LVCCS), m_vi(0.0) { }
+ ATTR_COLD NETLIB_NAME(LVCCS)(const family_t afamily)
+ : NETLIB_NAME(VCCS)(afamily), m_vi(0.0) { }
+
+ param_double_t m_cur_limit; /* current limit */
+
+protected:
+ virtual void start();
+ virtual void reset();
+ virtual void update_param();
+ ATTR_HOT virtual void update();
+ NETLIB_UPDATE_TERMINALSI();
+
+ nl_double m_vi;
+};
+
// ----------------------------------------------------------------------------------------
// nld_CCCS
// ----------------------------------------------------------------------------------------
@@ -153,6 +177,8 @@ public:
ATTR_COLD NETLIB_NAME(VCVS)()
: NETLIB_NAME(VCCS)(VCVS) { }
+ param_double_t m_RO;
+
protected:
virtual void start();
virtual void reset();
@@ -162,7 +188,6 @@ protected:
terminal_t m_OP2;
terminal_t m_ON2;
- param_double_t m_RO;
};
NETLIB_NAMESPACE_DEVICES_END()
diff --git a/src/emu/netlist/analog/nld_opamps.c b/src/emu/netlist/analog/nld_opamps.c
index 7e88aece9bb..b20989f9645 100644
--- a/src/emu/netlist/analog/nld_opamps.c
+++ b/src/emu/netlist/analog/nld_opamps.c
@@ -37,3 +37,121 @@ NETLIST_START(opamp_lm3900)
PARAM(G1.RO, RES_K(8))
NETLIST_END()
+
+NETLIB_NAMESPACE_DEVICES_START()
+
+/*
+ * Type = 0: Impedance changer
+ * 1; Ideal opamp
+ * 2; opamp with first pole
+ * 3: opamp with first pole + output limit
+ * 4: opamp with input stage, first pole + output limit
+ */
+
+NETLIB_START(OPAMP)
+{
+ register_sub("RP1", m_RP);
+ register_sub("CP1", m_CP);
+ register_sub("G1", m_G1);
+ register_sub("EBUF", m_EBUF);
+ register_sub("DN", m_DN);
+ register_sub("DP", m_DP);
+
+ register_input("VCC", m_VCC);
+ register_input("GND", m_GND);
+
+ register_output("VL", m_VL);
+ register_output("VH", m_VH);
+ register_output("VREF", m_VREF);
+
+ register_param("model", m_model, "");
+
+ m_type = m_model.model_value("TYPE");
+
+ if (m_type == 3)
+ {
+ register_subalias("PLUS", "G1.IP");
+ register_subalias("MINUS", "G1.IN");
+ register_subalias("OUT", "EBUF.OP");
+
+ connect_late("EBUF.ON", "VREF");
+
+ connect_late("G1.ON", "VREF");
+ connect_late("RP1.2", "VREF");
+ connect_late("CP1.2", "VREF");
+ connect_late("EBUF.IN", "VREF");
+
+ connect_late("RP1.1", "G1.OP");
+ connect_late("CP1.1", "RP1.1");
+
+ connect_late("DP.K", "VH");
+ connect_late("VL", "DN.A");
+ connect_late("DP.A", "DN.K");
+ connect_late("DN.K", "RP1.1");
+ connect_late("EBUF.IP", "RP1.1");
+ }
+ else
+ netlist().error("Unknown opamp type: %d", m_type);
+}
+
+/* .model abc OPAMP(VLH=2.0 VLL=0.2 FPF=5 UGF=10k SLEW=0.6u RI=1000k RO=50 DAB=0.002)
+ *
+ * Differential Amp Bias ~ op amp's total quiescent current.
+ * */
+
+NETLIB_UPDATE(OPAMP)
+{
+ const double cVt = 0.0258 * 1.0; // * m_n;
+ const double cId = m_model.model_value("DAB"); // 3 mA
+ const double cVd = cVt * nl_math::log(cId / 1e-15 + 1.0);
+ m_VH.set_Q(INPANALOG(m_VCC) - m_model.model_value("VLH") - cVd);
+ m_VL.set_Q(INPANALOG(m_GND) + m_model.model_value("VLL") + cVd);
+ m_VREF.set_Q((INPANALOG(m_VCC) + INPANALOG(m_GND)) / 2.0);
+}
+
+NETLIB_RESET(OPAMP)
+{
+ m_EBUF.do_reset();
+ m_G1.do_reset();
+ m_DP.do_reset();
+ m_DN.do_reset();
+ m_CP.do_reset();
+ m_RP.do_reset();
+
+ m_EBUF.m_G.setTo(1.0);
+ m_G1.m_RI.setTo(m_model.model_value("RI"));
+ m_EBUF.m_RO.setTo(m_model.model_value("RO"));
+ m_DP.m_model.setTo(".model tt D(IS=1e-15 N=1)");
+ m_DN.m_model.setTo(".model tt D(IS=1e-15 N=1)");
+
+ double CP = m_model.model_value("DAB") / m_model.model_value("SLEW");
+ double RP = 0.5 / 3.1459 / CP / m_model.model_value("FPF");
+ double G = m_model.model_value("UGF") / m_model.model_value("FPF") / RP;
+
+ //printf("CP=%e RP=%f G=%f\n", CP, RP, G);
+ m_CP.m_C.setTo(CP);
+ m_RP.set_R(RP);
+ m_G1.m_G.setTo(G);
+
+}
+
+NETLIB_UPDATE_PARAM(OPAMP)
+{
+}
+
+/*
+NETLIB_DEVICE_WITH_PARAMS(OPAMPx,
+ NETLIB_NAME(R) m_RP;
+ NETLIB_NAME(C) m_CP;
+ NETLIB_NAME(VCCS) m_G1;
+ NETLIB_NAME(VCVS) m_EBUF;
+
+ param_model_t m_model;
+ analog_input_t m_VH;
+ analog_input_t m_VL;
+ analog_input_t m_VREF;
+);
+*/
+
+NETLIB_NAMESPACE_DEVICES_END()
+
diff --git a/src/emu/netlist/analog/nld_opamps.h b/src/emu/netlist/analog/nld_opamps.h
index caf8ff57650..28628797ab3 100644
--- a/src/emu/netlist/analog/nld_opamps.h
+++ b/src/emu/netlist/analog/nld_opamps.h
@@ -5,7 +5,7 @@
*
*/
-#pragma once
+//#pragma once
#ifndef NLD_OPAMPS_H_
#define NLD_OPAMPS_H_
@@ -13,11 +13,16 @@
#include "../nl_base.h"
#include "../nl_setup.h"
#include "nld_twoterm.h"
+#include "nld_fourterm.h"
// ----------------------------------------------------------------------------------------
// Macros
// ----------------------------------------------------------------------------------------
+#define OPAMP(_name, _model) \
+ NET_REGISTER_DEV(OPAMP, _name) \
+ NETDEV_PARAMI(_name, model, _model)
+
#define LM3900(_name) \
SUBMODEL(opamp_lm3900, name)
@@ -27,6 +32,28 @@
NETLIST_EXTERNAL(opamp_lm3900)
+NETLIB_NAMESPACE_DEVICES_START()
+
+NETLIB_DEVICE_WITH_PARAMS(OPAMP,
+ NETLIB_NAME(R) m_RP;
+ NETLIB_NAME(C) m_CP;
+ NETLIB_NAME(VCCS) m_G1;
+ NETLIB_NAME(VCVS) m_EBUF;
+ NETLIB_NAME(D) m_DP;
+ NETLIB_NAME(D) m_DN;
+
+ analog_input_t m_VCC;
+ analog_input_t m_GND;
+
+ param_model_t m_model;
+ analog_output_t m_VH;
+ analog_output_t m_VL;
+ analog_output_t m_VREF;
+
+ /* state */
+ unsigned m_type;
+);
+NETLIB_NAMESPACE_DEVICES_END()
#endif /* NLD_OPAMPS_H_ */
diff --git a/src/emu/netlist/analog/nld_twoterm.c b/src/emu/netlist/analog/nld_twoterm.c
index 64e9ef042ba..1a99dcaf90a 100644
--- a/src/emu/netlist/analog/nld_twoterm.c
+++ b/src/emu/netlist/analog/nld_twoterm.c
@@ -240,6 +240,7 @@ NETLIB_RESET(C)
NETLIB_UPDATE_PARAM(C)
{
//step_time(1.0/48000.0);
+ m_GParallel = netlist().gmin() * m_C.Value();
}
NETLIB_UPDATE(C)
@@ -247,6 +248,14 @@ NETLIB_UPDATE(C)
NETLIB_NAME(twoterm)::update();
}
+ATTR_HOT void NETLIB_NAME(C)::step_time(const nl_double st)
+{
+ /* Gpar should support convergence */
+ const nl_double G = m_C.Value() / st + m_GParallel;
+ const nl_double I = -G * deltaV();
+ set(G, 0.0, I);
+}
+
// ----------------------------------------------------------------------------------------
// nld_D
// ----------------------------------------------------------------------------------------
diff --git a/src/emu/netlist/analog/nld_twoterm.h b/src/emu/netlist/analog/nld_twoterm.h
index 9969c65830e..0bc08241658 100644
--- a/src/emu/netlist/analog/nld_twoterm.h
+++ b/src/emu/netlist/analog/nld_twoterm.h
@@ -194,14 +194,11 @@ NETLIB_DEVICE_WITH_PARAMS(POT2,
class NETLIB_NAME(C) : public NETLIB_NAME(twoterm)
{
public:
- ATTR_COLD NETLIB_NAME(C)() : NETLIB_NAME(twoterm)(CAPACITOR) { }
+ ATTR_COLD NETLIB_NAME(C)() : NETLIB_NAME(twoterm)(CAPACITOR), m_GParallel(0.0) { }
- ATTR_HOT void step_time(const nl_double st)
- {
- const nl_double G = m_C.Value() / st;
- const nl_double I = -G * deltaV();
- set(G, 0.0, I);
- }
+ ATTR_HOT void step_time(const nl_double st);
+
+ param_double_t m_C;
protected:
virtual void start();
@@ -209,7 +206,8 @@ protected:
virtual void update_param();
ATTR_HOT void update();
- param_double_t m_C;
+private:
+ nl_double m_GParallel;
};
@@ -225,6 +223,7 @@ public:
ATTR_HOT inline void update_diode(const nl_double nVd)
{
+#if 1
if (nVd < NL_FCONST(-5.0) * m_Vt)
{
m_Vd = nVd;
@@ -233,23 +232,32 @@ public:
}
else if (nVd < m_Vcrit)
{
- const nl_double eVDVt = nl_math::exp(nVd * m_VtInv);
m_Vd = nVd;
+ //m_Vd = m_Vd + 10.0 * m_Vt * std::tanh((nVd - m_Vd) / 10.0 / m_Vt);
+ const nl_double eVDVt = nl_math::exp(m_Vd * m_VtInv);
m_Id = m_Is * (eVDVt - NL_FCONST(1.0));
m_G = m_Is * m_VtInv * eVDVt + m_gmin;
}
else
{
- const nl_double a = std::max((nVd - m_Vd) * m_VtInv, NL_FCONST(1e-12) - NL_FCONST(1.0));
+#if 1
+ const nl_double a = std::max((nVd - m_Vd) * m_VtInv, NL_FCONST(1e-1) - NL_FCONST(1.0));
m_Vd = m_Vd + nl_math::e_log1p(a) * m_Vt;
-
+#else
+ m_Vd = m_Vd + 10.0 * m_Vt * std::tanh((nVd - m_Vd) / 10.0 / m_Vt);
+#endif
const nl_double eVDVt = nl_math::exp(m_Vd * m_VtInv);
m_Id = m_Is * (eVDVt - NL_FCONST(1.0));
m_G = m_Is * m_VtInv * eVDVt + m_gmin;
}
-
- //printf("nVd %f m_Vd %f Vcrit %f\n", nVd, m_Vd, m_Vcrit);
+#else
+ m_Vd = m_Vd + 20.0 * m_Vt * std::tanh((nVd - m_Vd) / 20.0 / m_Vt);
+ const nl_double eVDVt = nl_math::exp(m_Vd * m_VtInv);
+ m_Id = m_Is * (eVDVt - NL_FCONST(1.0));
+ m_G = m_Is * m_VtInv * eVDVt + m_gmin;
+#endif
+ //printf("%p nVd %f m_Vd %f Vcrit %f\n", this, nVd, m_Vd, m_Vcrit);
}
ATTR_COLD void set_param(const nl_double Is, const nl_double n, nl_double gmin);
@@ -288,13 +296,13 @@ public:
NETLIB_UPDATE_TERMINALSI();
+ param_model_t m_model;
+
protected:
virtual void start();
virtual void update_param();
ATTR_HOT void update();
- param_model_t m_model;
-
generic_diode m_D;
};
diff --git a/src/emu/netlist/devices/net_lib.c b/src/emu/netlist/devices/net_lib.c
index 832e3989902..bd65e11ed92 100644
--- a/src/emu/netlist/devices/net_lib.c
+++ b/src/emu/netlist/devices/net_lib.c
@@ -58,8 +58,10 @@ void initialize_factory(factory_list_t &factory)
ENTRY(VCVS, VCVS, "-")
ENTRY(VCCS, VCCS, "-")
ENTRY(CCCS, CCCS, "-")
+ ENTRY(LVCCS, LVCCS, "-")
ENTRY(VS, VS, "V")
ENTRY(CS, CS, "I")
+ ENTRY(OPAMP, OPAMP, "model")
ENTRY(dummy_input, DUMMY_INPUT, "-")
ENTRY(frontier, FRONTIER_DEV, "+I,G,Q") // not intended to be used directly
ENTRY(function, AFUNC, "N,FUNC") // only for macro devices - NO FEEDBACK loops
diff --git a/src/emu/netlist/nl_base.c b/src/emu/netlist/nl_base.c
index 12fd82edbdb..d9dd4f10178 100644
--- a/src/emu/netlist/nl_base.c
+++ b/src/emu/netlist/nl_base.c
@@ -555,6 +555,19 @@ ATTR_COLD void device_t::register_subalias(const pstring &name, core_terminal_t
m_terminals.add(alias);
}
+ATTR_COLD void device_t::register_subalias(const pstring &name, const pstring &aliased)
+{
+ pstring alias = this->name() + "." + name;
+ pstring aliased_fqn = this->name() + "." + aliased;
+
+ // everything already fully qualified
+ setup().register_alias_nofqn(alias, aliased_fqn);
+
+ // FIXME: make this working again
+ //if (term.isType(terminal_t::INPUT) || term.isType(terminal_t::TERMINAL))
+ // m_terminals.add(name);
+}
+
ATTR_COLD void device_t::register_terminal(const pstring &name, terminal_t &port)
{
setup().register_object(*this, name, port);
@@ -588,13 +601,12 @@ ATTR_COLD void device_t::register_input(const pstring &name, analog_input_t &inp
ATTR_COLD void device_t::connect_late(core_terminal_t &t1, core_terminal_t &t2)
{
-#if 1
- //printf("device %s: connect %s to %s\n", name().cstr(), t1.name().cstr(), t2.name().cstr());
setup().register_link_fqn(t1.name(), t2.name());
-#else
- if (!setup().connect(t1, t2))
- netlist().error("Error connecting %s to %s\n", t1.name().cstr(), t2.name().cstr());
-#endif
+}
+
+ATTR_COLD void device_t::connect_late(const pstring &t1, const pstring &t2)
+{
+ setup().register_link_fqn(name() + "." + t1, name() + "." + t2);
}
ATTR_COLD void device_t::connect_direct(core_terminal_t &t1, core_terminal_t &t2)
diff --git a/src/emu/netlist/nl_base.h b/src/emu/netlist/nl_base.h
index fff7fedf204..ff852c7f6f4 100644
--- a/src/emu/netlist/nl_base.h
+++ b/src/emu/netlist/nl_base.h
@@ -388,6 +388,7 @@ namespace netlist
BJT_SWITCH, // BJT(Switch)
VCVS, // Voltage controlled voltage source
VCCS, // Voltage controlled current source
+ LVCCS, // Voltage controlled current source (Current limited)
CCCS, // Current controlled current source
VS, // Voltage Source
CS, // Current Source
@@ -1087,12 +1088,14 @@ namespace netlist
ATTR_COLD void register_sub(const pstring &name, device_t &dev);
ATTR_COLD void register_subalias(const pstring &name, core_terminal_t &term);
+ ATTR_COLD void register_subalias(const pstring &name, const pstring &aliased);
ATTR_COLD void register_terminal(const pstring &name, terminal_t &port);
ATTR_COLD void register_output(const pstring &name, analog_output_t &out);
ATTR_COLD void register_output(const pstring &name, logic_output_t &out);
ATTR_COLD void register_input(const pstring &name, analog_input_t &in);
ATTR_COLD void register_input(const pstring &name, logic_input_t &in);
+ ATTR_COLD void connect_late(const pstring &t1, const pstring &t2);
ATTR_COLD void connect_late(core_terminal_t &t1, core_terminal_t &t2);
ATTR_COLD void connect_direct(core_terminal_t &t1, core_terminal_t &t2);
diff --git a/src/emu/netlist/nl_setup.c b/src/emu/netlist/nl_setup.c
index 47f5abca724..81bcf9c0c03 100644
--- a/src/emu/netlist/nl_setup.c
+++ b/src/emu/netlist/nl_setup.c
@@ -919,6 +919,7 @@ nl_double setup_t::model_value(const pstring &model_str, const pstring &entity,
char numfac = *(tmp.right(1).cstr());
switch (numfac)
{
+ case 'M': factor = 1e6; break;
case 'k': factor = 1e3; break;
case 'm': factor = 1e-3; break;
case 'u': factor = 1e-6; break;
diff --git a/src/emu/netlist/solver/nld_ms_direct.h b/src/emu/netlist/solver/nld_ms_direct.h
index 4e2da2af9cf..f64514a1c7c 100644
--- a/src/emu/netlist/solver/nld_ms_direct.h
+++ b/src/emu/netlist/solver/nld_ms_direct.h
@@ -14,6 +14,10 @@
NETLIB_NAMESPACE_DEVICES_START()
+//#define nl_ext_double __float128 // slow, very slow
+//#define nl_ext_double long double // slightly slower
+#define nl_ext_double double
+
template <unsigned m_N, unsigned _storage_N>
class matrix_solver_direct_t: public matrix_solver_t
{
@@ -50,7 +54,8 @@ protected:
*/
ATTR_HOT nl_double compute_next_timestep();
- ATTR_ALIGN nl_double m_A[_storage_N][((_storage_N + 7) / 8) * 8];
+ ATTR_ALIGN nl_ext_double m_A[_storage_N][((_storage_N + 7) / 8) * 8];
+ //ATTR_ALIGN nl_double m_A[_storage_N][((_storage_N + 7) / 8) * 8];
ATTR_ALIGN nl_double m_RHS[_storage_N];
ATTR_ALIGN nl_double m_last_RHS[_storage_N]; // right hand side - contains currents
ATTR_ALIGN nl_double m_last_V[_storage_N];
@@ -356,7 +361,8 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_solve()
unsigned maxrow = i;
for (unsigned j = i + 1; j < kN; j++)
{
- if (nl_math::abs(m_A[j][i]) > nl_math::abs(m_A[maxrow][i]))
+ //if (std::abs(m_A[j][i]) > std::abs(m_A[maxrow][i]))
+ if (m_A[j][i] * m_A[j][i] > m_A[maxrow][i] * m_A[maxrow][i])
maxrow = j;
}
@@ -368,43 +374,63 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_solve()
}
std::swap(m_RHS[i], m_RHS[maxrow]);
}
- }
-
- /* FIXME: Singular matrix? */
- const nl_double f = 1.0 / m_A[i][i];
- const double * RESTRICT s = &m_A[i][0];
- const unsigned *p = m_terms[i]->m_nzrd.data();
- const unsigned e = m_terms[i]->m_nzrd.size();
+ /* FIXME: Singular matrix? */
+ const nl_double f = 1.0 / m_A[i][i];
+ const nl_ext_double * RESTRICT s = &m_A[i][i+1];
- /* Eliminate column i from row j */
+ /* Eliminate column i from row j */
- for (unsigned j = i + 1; j < kN; j++)
+ for (unsigned j = i + 1; j < kN; j++)
+ {
+ nl_ext_double * RESTRICT d = &m_A[j][i+1];
+ const nl_double f1 = - m_A[j][i] * f;
+ if (f1 != NL_FCONST(0.0))
+ {
+ const unsigned e = kN - i - 1;
+ for (unsigned k = 0; k < e; k++)
+ d[k] = d[k] + s[k] * f1;
+ m_RHS[j] += m_RHS[i] * f1;
+ }
+ }
+ }
+ else
{
- double * RESTRICT d = &m_A[j][0];
- const nl_double f1 = - d[i] * f;
- if (f1 != NL_FCONST(0.0))
+ /* FIXME: Singular matrix? */
+ const nl_double f = 1.0 / m_A[i][i];
+ const nl_ext_double * RESTRICT s = &m_A[i][0];
+ const unsigned *p = m_terms[i]->m_nzrd.data();
+ const unsigned e = m_terms[i]->m_nzrd.size();
+
+ /* Eliminate column i from row j */
+
+ for (unsigned j = i + 1; j < kN; j++)
{
-#if 0
- /* The code below is 30% faster than the original
- * implementation which is given here for reference.
- *
- * for (unsigned k = i + 1; k < kN; k++)
- * m_A[j][k] = m_A[j][k] + m_A[i][k] * f1;
- */
- double * RESTRICT d = &m_A[j][i+1];
- const double * RESTRICT s = &m_A[i][i+1];
- const int e = kN - i - 1;
-
- for (int k = 0; k < e; k++)
- d[k] = d[k] + s[k] * f1;
-#else
- for (unsigned k = 0; k < e; k++)
+ nl_ext_double * RESTRICT d = &m_A[j][0];
+ const nl_double f1 = - d[i] * f;
+ if (f1 != NL_FCONST(0.0))
{
- const unsigned pk = p[k];
- d[pk] += s[pk] * f1;
+ #if 0
+ /* The code below is 30% faster than the original
+ * implementation which is given here for reference.
+ *
+ * for (unsigned k = i + 1; k < kN; k++)
+ * m_A[j][k] = m_A[j][k] + m_A[i][k] * f1;
+ */
+ double * RESTRICT d = &m_A[j][i+1];
+ const double * RESTRICT s = &m_A[i][i+1];
+ const int e = kN - i - 1;
+
+ for (int k = 0; k < e; k++)
+ d[k] = d[k] + s[k] * f1;
+ #else
+ for (unsigned k = 0; k < e; k++)
+ {
+ const unsigned pk = p[k];
+ d[pk] += s[pk] * f1;
+ }
+ #endif
+ m_RHS[j] += m_RHS[i] * f1;
}
-#endif
- m_RHS[j] += m_RHS[i] * f1;
}
}
}
@@ -422,14 +448,14 @@ ATTR_HOT void matrix_solver_direct_t<m_N, _storage_N>::LE_back_subst(
nl_double tmp = 0;
#if 1
-#if 0
- const double * RESTRICT A = &m_A[j][j+1];
- const double * RESTRICT xp = &x[j+1];
- const int e = kN - j - 1;
- for (int k = 0; k < e; k++)
+#if (USE_PIVOT_SEARCH)
+ const nl_ext_double * RESTRICT A = &m_A[j][j+1];
+ const nl_double * RESTRICT xp = &x[j+1];
+ const unsigned e = kN - j - 1;
+ for (unsigned k = 0; k < e; k++)
tmp += A[k] * xp[k];
#else
- const double * RESTRICT A = &m_A[j][0];
+ const nl_ext_double * RESTRICT A = &m_A[j][0];
const unsigned *p = m_terms[j]->m_nzrd.data();
const unsigned e = m_terms[j]->m_nzrd.size();
diff --git a/src/emu/netlist/solver/nld_ms_sor_mat.h b/src/emu/netlist/solver/nld_ms_sor_mat.h
index d55f2872585..d5ce05ef8b1 100644
--- a/src/emu/netlist/solver/nld_ms_sor_mat.h
+++ b/src/emu/netlist/solver/nld_ms_sor_mat.h
@@ -199,7 +199,7 @@ ATTR_HOT inline int matrix_solver_SOR_mat_t<m_N, _storage_N>::vsolve_non_dynamic
{
nl_double Idrive = 0;
- const double * RESTRICT A = &this->m_A[k][0];
+ const nl_ext_double * RESTRICT A = &this->m_A[k][0];
const unsigned *p = this->m_terms[k]->m_nz.data();
const unsigned e = this->m_terms[k]->m_nz.size();
diff --git a/src/emu/netlist/solver/nld_solver.c b/src/emu/netlist/solver/nld_solver.c
index 03e3c819c38..acf9a6fdaae 100644
--- a/src/emu/netlist/solver/nld_solver.c
+++ b/src/emu/netlist/solver/nld_solver.c
@@ -134,9 +134,9 @@ ATTR_COLD void matrix_solver_t::setup(analog_net_t::list_t &nets)
break;
case device_t::BJT_EB:
case device_t::DIODE:
- //case device_t::VCVS:
+ case device_t::LVCCS:
case device_t::BJT_SWITCH:
- NL_VERBOSE_OUT(("found BJT/Diode\n"));
+ NL_VERBOSE_OUT(("found BJT/Diode/LVCCS\n"));
if (!m_dynamic_devices.contains(&p->device()))
m_dynamic_devices.add(&p->device());
break;